diff --git a/rostests/copying b/rostests/COPYING similarity index 95% rename from rostests/copying rename to rostests/COPYING index dc63aaca038..d159169d105 100644 --- a/rostests/copying +++ b/rostests/COPYING @@ -1,13 +1,12 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -16,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -56,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -111,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -169,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -226,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -256,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -278,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -292,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) 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 @@ -304,16 +303,16 @@ the "copyright" line and a pointer to where the full notice is found. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names: This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff --git a/rostests/apitests/apitest.c b/rostests/apitests/apitest.c index bd3abecb1b8..40453d919fe 100644 --- a/rostests/apitests/apitest.c +++ b/rostests/apitests/apitest.c @@ -80,6 +80,36 @@ WriteRow(HANDLE hFile, LPDWORD lpdwBytesWritten, LPWSTR pszFunction, PTESTINFO p return TRUE; } +static CHAR +GetDisplayChar(CHAR c) +{ + if (c < 32) return '.'; + return c; +} + +VOID +DumpMem(PVOID pData, ULONG cbSize, ULONG nWidth) +{ + ULONG cLines = (cbSize + nWidth - 1) / nWidth; + ULONG cbLastLine = cbSize % nWidth; + INT i,j; + + for (i = 0; i <= cLines; i++) + { + printf("%08lx: ", i*nWidth); + for (j = 0; j < (i == cLines? cbLastLine : nWidth); j++) + { + printf("%02x ", ((BYTE*)pData)[i*nWidth + j]); + } + printf(" "); + for (j = 0; j < (i == cLines? cbLastLine : nWidth); j++) + { + printf("%c", GetDisplayChar(((CHAR*)pData)[i*nWidth + j])); + } + printf("\n"); + } +} + int TestMain(LPWSTR pszName, LPWSTR pszModule) { diff --git a/rostests/apitests/apitest.h b/rostests/apitests/apitest.h index 6900789c9a3..e3e08e0609f 100644 --- a/rostests/apitests/apitest.h +++ b/rostests/apitests/apitest.h @@ -40,7 +40,7 @@ typedef struct tagTEST if (x)\ {\ (pti->passed)++;\ - printf("non-rtest succeeded in %s:%d (%s)\n", __FILE__, __LINE__, #x);\ + printf("%s:%d: non-rtest succeeded (%s)\n", __FILE__, __LINE__, #x);\ } else {\ (pti->failed)++;\ } \ @@ -52,7 +52,30 @@ typedef struct tagTEST (pti->passed)++;\ } else {\ (pti->failed)++;\ - printf("test failed in %s:%d (%s)\n", __FILE__, __LINE__, #x);\ + printf("%s:%d: test failed (%s)\n", __FILE__, __LINE__, #x);\ + } \ + } + +#define TESTX(x, format, ...) \ + if (pti->bRegress) \ + { \ + if (x)\ + {\ + (pti->passed)++;\ + printf("%s:%d: non-rtest succeeded (%s)\n", __FILE__, __LINE__, #x);\ + } else {\ + (pti->failed)++;\ + } \ + } \ + else \ + { \ + if (x)\ + {\ + (pti->passed)++;\ + } else {\ + (pti->failed)++;\ + printf("%s:%d: test failed (%s) ", __FILE__, __LINE__, #x);\ + printf(format, __VA_ARGS__); \ } \ } @@ -91,5 +114,6 @@ int TestMain(LPWSTR pszExe, LPWSTR pszModule); extern TESTENTRY TestList[]; INT NumTests(void); BOOL IsFunctionPresent(LPWSTR lpszFunction); +VOID DumpMem(PVOID pData, ULONG cbSize, ULONG nWidth); #endif /* _APITEST_H */ diff --git a/rostests/apitests/dciman32api/dciman32api.rbuild b/rostests/apitests/dciman32api/dciman32api.rbuild index f333e806aa0..7e6687be3f8 100644 --- a/rostests/apitests/dciman32api/dciman32api.rbuild +++ b/rostests/apitests/dciman32api/dciman32api.rbuild @@ -1,9 +1,6 @@ . - - 0x0501 apitest - kernel32 user32 gdi32 shell32 diff --git a/rostests/apitests/directory.rbuild b/rostests/apitests/directory.rbuild index 64c7c035739..a55d9bacc0d 100644 --- a/rostests/apitests/directory.rbuild +++ b/rostests/apitests/directory.rbuild @@ -3,8 +3,6 @@ . - - 0x0501 apitest.c diff --git a/rostests/apitests/gdi32api/gdi.h b/rostests/apitests/gdi32api/gdi.h index 72fd7a126de..0e484dc6c5b 100644 --- a/rostests/apitests/gdi32api/gdi.h +++ b/rostests/apitests/gdi32api/gdi.h @@ -38,15 +38,6 @@ typedef PGDI_TABLE_ENTRY (CALLBACK * GDIQUERYPROC) (void); /** Not really an object type. Forces GDI_FreeObj to be silent. */ #define GDI_OBJECT_TYPE_SILENT 0x80000000 - - -/* Number Representation */ - -typedef LONG FIX; - - - - HDC WINAPI GdiConvertBitmap(HDC hdc); HBRUSH WINAPI GdiConvertBrush(HBRUSH hbr); HDC WINAPI GdiConvertDC(HDC hdc); diff --git a/rostests/apitests/gdi32api/gdi32api.rbuild b/rostests/apitests/gdi32api/gdi32api.rbuild index a045a7965ff..562db78c830 100644 --- a/rostests/apitests/gdi32api/gdi32api.rbuild +++ b/rostests/apitests/gdi32api/gdi32api.rbuild @@ -1,9 +1,6 @@ . - - 0x0501 apitest - kernel32 user32 gdi32 shell32 diff --git a/rostests/apitests/gdi32api/testlist.c b/rostests/apitests/gdi32api/testlist.c index d38c267773c..9631f29bc97 100644 --- a/rostests/apitests/gdi32api/testlist.c +++ b/rostests/apitests/gdi32api/testlist.c @@ -6,8 +6,10 @@ /* include the tests */ #include "tests/AddFontResource.c" #include "tests/AddFontResourceEx.c" +#include "tests/BeginPath.c" #include "tests/CreateBitmapIndirect.c" #include "tests/CreateCompatibleDC.c" +#include "tests/CreateFontIndirect.c" #include "tests/CreateFont.c" #include "tests/CreatePen.c" #include "tests/CreateRectRgn.c" @@ -33,27 +35,24 @@ #include "tests/GetDIBits.c" #include "tests/GetObject.c" #include "tests/GetStockObject.c" +#include "tests/GetTextFace.c" #include "tests/SelectObject.c" #include "tests/SetDCPenColor.c" +#include "tests/SetMapMode.c" #include "tests/SetSysColors.c" +#include "tests/SetWindowExtEx.c" #include "tests/SetWorldTransform.c" - - - - - - - - /* The List of tests */ TESTENTRY TestList[] = { { L"AddFontResourceA", Test_AddFontResourceA }, { L"AddFontResourceEx", Test_AddFontResourceEx }, + { L"BeginPath", Test_BeginPath }, { L"CreateBitmapIndirect", Test_CreateBitmapIndirect }, { L"CreateCompatibleDC", Test_CreateCompatibleDC }, + { L"CreateFontIndirect", Test_CreateFontIndirect }, { L"CreateFont", Test_CreateFont }, { L"CreatePen", Test_CreatePen }, { L"EngCreateSemaphore", Test_EngCreateSemaphore }, @@ -79,9 +78,12 @@ TESTENTRY TestList[] = { L"GetDIBits", Test_GetDIBits }, { L"GetObject", Test_GetObject }, { L"GetStockObject", Test_GetStockObject }, + { L"GetTextFace", Test_GetTextFace }, { L"SelectObject", Test_SelectObject }, { L"SetDCPenColor", Test_SetDCPenColor }, + { L"SetMapMode", Test_SetMapMode }, { L"SetSysColors", Test_SetSysColors }, + { L"SetWindowExtEx", Test_SetWindowExtEx }, { L"SetWorldTransform", Test_SetWorldTransform }, }; diff --git a/rostests/apitests/gdi32api/tests/BeginPath.c b/rostests/apitests/gdi32api/tests/BeginPath.c new file mode 100644 index 00000000000..f4671207dfe --- /dev/null +++ b/rostests/apitests/gdi32api/tests/BeginPath.c @@ -0,0 +1,24 @@ + + +INT +Test_BeginPath(PTESTINFO pti) +{ + HDC hDC; + BOOL ret; + + SetLastError(0); + ret = BeginPath(0); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + hDC = CreateCompatibleDC(NULL); + + SetLastError(0); + ret = BeginPath(hDC); + TEST(ret == 1); + TEST(GetLastError() == 0); + + DeleteDC(hDC); + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/gdi32api/tests/CreateCompatibleDC.c b/rostests/apitests/gdi32api/tests/CreateCompatibleDC.c index 2cbae85b0b7..2cfb508f778 100644 --- a/rostests/apitests/gdi32api/tests/CreateCompatibleDC.c +++ b/rostests/apitests/gdi32api/tests/CreateCompatibleDC.c @@ -39,6 +39,12 @@ Test_CreateCompatibleDC(PTESTINFO pti) RTEST(hDC2 == NULL); if (hDC2 != NULL) DeleteDC(hDC2); + /* Check map mode */ + hDC = CreateCompatibleDC(hDCScreen); + SetMapMode(hDC, MM_ISOTROPIC); + hDC2 = CreateCompatibleDC(hDC); + TEST(GetMapMode(hDC2) == MM_TEXT); + // cleanup DeleteDC(hDC); diff --git a/rostests/apitests/gdi32api/tests/CreateFontIndirect.c b/rostests/apitests/gdi32api/tests/CreateFontIndirect.c new file mode 100644 index 00000000000..0202c3c703d --- /dev/null +++ b/rostests/apitests/gdi32api/tests/CreateFontIndirect.c @@ -0,0 +1,180 @@ + +INT +Test_CreateFontIndirectA(PTESTINFO pti) +{ + LOGFONTA logfont; + HFONT hFont; + ULONG ret; + ENUMLOGFONTEXDVW elfedv2; + + logfont.lfHeight = 12; + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfWeight = FW_NORMAL; + logfont.lfItalic = 0; + logfont.lfUnderline = 0; + logfont.lfStrikeOut = 0; + logfont.lfCharSet = DEFAULT_CHARSET; + logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logfont.lfQuality = PROOF_QUALITY; + logfont.lfPitchAndFamily = DEFAULT_PITCH; + memset(logfont.lfFaceName, 'A', LF_FACESIZE); + hFont = CreateFontIndirectA(&logfont); + TEST(hFont != 0); + + memset(&elfedv2, 0, sizeof(elfedv2)); + ret = GetObjectW(hFont, sizeof(elfedv2), &elfedv2); + TEST(ret == sizeof(ENUMLOGFONTEXW) + 2*sizeof(DWORD)); + TEST(elfedv2.elfEnumLogfontEx.elfLogFont.lfFaceName[LF_FACESIZE-1] == 0); + TEST(elfedv2.elfEnumLogfontEx.elfFullName[0] == 0); + + return APISTATUS_NORMAL; +} + +INT +Test_CreateFontIndirectW(PTESTINFO pti) +{ + LOGFONTW logfont; + HFONT hFont; + ULONG ret; + ENUMLOGFONTEXDVW elfedv2; + + logfont.lfHeight = 12; + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfWeight = FW_NORMAL; + logfont.lfItalic = 0; + logfont.lfUnderline = 0; + logfont.lfStrikeOut = 0; + logfont.lfCharSet = DEFAULT_CHARSET; + logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logfont.lfQuality = PROOF_QUALITY; + logfont.lfPitchAndFamily = DEFAULT_PITCH; + memset(logfont.lfFaceName, 'A', LF_FACESIZE * 2); + hFont = CreateFontIndirectW(&logfont); + TEST(hFont != 0); + + memset(&elfedv2, 0, sizeof(elfedv2)); + ret = GetObjectW(hFont, sizeof(elfedv2), &elfedv2); + TEST(ret == sizeof(ENUMLOGFONTEXW) + 2*sizeof(DWORD)); + TEST(elfedv2.elfEnumLogfontEx.elfLogFont.lfFaceName[LF_FACESIZE-1] == ((WCHAR)'A' << 8) + 'A'); + TEST(elfedv2.elfEnumLogfontEx.elfFullName[0] == 0); + /* Theres a bunch of data in elfFullName ... */ + + return APISTATUS_NORMAL; +} + +INT +Test_CreateFontIndirectExA(PTESTINFO pti) +{ + ENUMLOGFONTEXDVA elfedva, elfedva2; + ENUMLOGFONTEXDVW elfedvw; + ENUMLOGFONTEXA *penumlfa; + LOGFONTA *plogfonta; + HFONT hFont; + ULONG ret; + + memset(&elfedva, 0, sizeof(elfedva)); + penumlfa = &elfedva.elfEnumLogfontEx; + plogfonta = &elfedva.elfEnumLogfontEx.elfLogFont; + + plogfonta->lfHeight = 12; + plogfonta->lfWidth = 0; + plogfonta->lfEscapement = 0; + plogfonta->lfOrientation = 0; + plogfonta->lfWeight = FW_NORMAL; + plogfonta->lfItalic = 0; + plogfonta->lfUnderline = 0; + plogfonta->lfStrikeOut = 0; + plogfonta->lfCharSet = DEFAULT_CHARSET; + plogfonta->lfOutPrecision = OUT_DEFAULT_PRECIS; + plogfonta->lfClipPrecision = CLIP_DEFAULT_PRECIS; + plogfonta->lfQuality = PROOF_QUALITY; + plogfonta->lfPitchAndFamily = DEFAULT_PITCH; + + memset(plogfonta->lfFaceName, 'A', LF_FACESIZE * sizeof(WCHAR)); + memset(penumlfa->elfFullName, 'B', LF_FULLFACESIZE * sizeof(WCHAR)); + + hFont = CreateFontIndirectExA(&elfedva); + TEST(hFont != 0); + + ret = GetObjectW(hFont, sizeof(elfedvw), &elfedvw); + TEST(ret == sizeof(ENUMLOGFONTEXW) + 2*sizeof(DWORD)); + TEST(elfedvw.elfEnumLogfontEx.elfLogFont.lfFaceName[LF_FACESIZE-1] == 0); + TEST(elfedvw.elfEnumLogfontEx.elfFullName[LF_FULLFACESIZE-1] == 0); + + memset(&elfedva2, 0, sizeof(elfedva2)); + ret = GetObjectA(hFont, sizeof(elfedva2), &elfedva2); + TEST(ret == sizeof(ENUMLOGFONTEXDVA)); + TEST(elfedva2.elfEnumLogfontEx.elfLogFont.lfFaceName[LF_FACESIZE-1] == 0); + TEST(elfedva2.elfEnumLogfontEx.elfFullName[LF_FULLFACESIZE-1] == 0); + + return APISTATUS_NORMAL; +} + +INT +Test_CreateFontIndirectExW(PTESTINFO pti) +{ + ENUMLOGFONTEXDVW elfedv, elfedv2; + ENUMLOGFONTEXDVA elfedva; + ENUMLOGFONTEXW *penumlfw; + LOGFONTW *plogfontw; + HFONT hFont; + ULONG ret; + + memset(&elfedv, 0, sizeof(elfedv)); + penumlfw = &elfedv.elfEnumLogfontEx; + plogfontw = &elfedv.elfEnumLogfontEx.elfLogFont; + + plogfontw->lfHeight = 12; + plogfontw->lfWidth = 0; + plogfontw->lfEscapement = 0; + plogfontw->lfOrientation = 0; + plogfontw->lfWeight = FW_NORMAL; + plogfontw->lfItalic = 0; + plogfontw->lfUnderline = 0; + plogfontw->lfStrikeOut = 0; + plogfontw->lfCharSet = DEFAULT_CHARSET; + plogfontw->lfOutPrecision = OUT_DEFAULT_PRECIS; + plogfontw->lfClipPrecision = CLIP_DEFAULT_PRECIS; + plogfontw->lfQuality = PROOF_QUALITY; + plogfontw->lfPitchAndFamily = DEFAULT_PITCH; + + memset(plogfontw->lfFaceName, 'A', LF_FACESIZE * sizeof(WCHAR)); + memset(penumlfw->elfFullName, 'B', LF_FULLFACESIZE * sizeof(WCHAR)); + + hFont = CreateFontIndirectExW(&elfedv); + TEST(hFont != 0); + + memset(&elfedv2, 0, sizeof(elfedv2)); + ret = GetObjectW(hFont, sizeof(elfedv2), &elfedv2); + TEST(ret == sizeof(ENUMLOGFONTEXW) + 2*sizeof(DWORD)); + TEST(elfedv2.elfEnumLogfontEx.elfLogFont.lfFaceName[LF_FACESIZE-1] == ((WCHAR)'A' << 8) + 'A'); + TEST(elfedv2.elfEnumLogfontEx.elfFullName[LF_FULLFACESIZE-1] == ((WCHAR)'B' << 8) + 'B'); + + memset(&elfedva, 0, sizeof(elfedva)); + ret = GetObjectA(hFont, sizeof(elfedva), &elfedva); + TEST(ret == sizeof(ENUMLOGFONTEXDVA)); + TEST(elfedva.elfEnumLogfontEx.elfLogFont.lfFaceName[LF_FACESIZE-1] == '?'); + TEST(elfedva.elfEnumLogfontEx.elfFullName[LF_FULLFACESIZE-1] == 0); + + return APISTATUS_NORMAL; +} + + +INT +Test_CreateFontIndirect(PTESTINFO pti) +{ + + Test_CreateFontIndirectA(pti); + Test_CreateFontIndirectW(pti); + Test_CreateFontIndirectExA(pti); + Test_CreateFontIndirectExW(pti); + + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/gdi32api/tests/GdiGetCharDimensions.c b/rostests/apitests/gdi32api/tests/GdiGetCharDimensions.c index 6a8856eaad5..f5874f49903 100644 --- a/rostests/apitests/gdi32api/tests/GdiGetCharDimensions.c +++ b/rostests/apitests/gdi32api/tests/GdiGetCharDimensions.c @@ -1,4 +1,4 @@ -LONG STDCALL GdiGetCharDimensions(HDC, LPTEXTMETRICW, LONG *); +LONG WINAPI GdiGetCharDimensions(HDC, LPTEXTMETRICW, LONG *); INT Test_GdiGetCharDimensions(PTESTINFO pti) diff --git a/rostests/apitests/gdi32api/tests/GetCurrentObject.c b/rostests/apitests/gdi32api/tests/GetCurrentObject.c index e41a46897f4..b49f15cc7d7 100644 --- a/rostests/apitests/gdi32api/tests/GetCurrentObject.c +++ b/rostests/apitests/gdi32api/tests/GetCurrentObject.c @@ -4,6 +4,7 @@ Test_GetCurrentObject(PTESTINFO pti) { HWND hWnd; HDC hDC; + HBITMAP hBmp; /* Create a window */ hWnd = CreateWindowW(L"BUTTON", L"TestWindow", WS_OVERLAPPEDWINDOW | WS_VISIBLE, @@ -70,7 +71,6 @@ Test_GetCurrentObject(PTESTINFO pti) /* Default bitmap */ SetLastError(ERROR_SUCCESS); - HBITMAP hBmp; hBmp = GetCurrentObject(hDC, OBJ_BITMAP); RTEST(GDI_HANDLE_GET_TYPE(hBmp) == GDI_OBJECT_TYPE_BITMAP); RTEST(GetLastError() == ERROR_SUCCESS); diff --git a/rostests/apitests/gdi32api/tests/GetObject.c b/rostests/apitests/gdi32api/tests/GetObject.c index c295e1c6612..ae5d5560440 100644 --- a/rostests/apitests/gdi32api/tests/GetObject.c +++ b/rostests/apitests/gdi32api/tests/GetObject.c @@ -98,15 +98,17 @@ Test_Bitmap(PTESTINFO pti) static INT Test_Dibsection(PTESTINFO pti) { - BITMAPINFO bmi = {{sizeof(BITMAPINFOHEADER), 10, 10, 1, 8, BI_RGB, 0, 10, 10, 0,0}}; + BITMAPINFO bmi = {{sizeof(BITMAPINFOHEADER), 10, 9, 1, 8, BI_RGB, 0, 10, 10, 0,0}}; HBITMAP hBitmap; + BITMAP bitmap; DIBSECTION dibsection; PVOID pData; + HDC hDC; FillMemory(&dibsection, sizeof(DIBSECTION), 0x77); - HDC hDC = GetDC(0); + hDC = GetDC(0); hBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &pData, NULL, 0); - if(!hBitmap) return FALSE; + ASSERT(hBitmap); SetLastError(ERROR_SUCCESS); RTEST(GetObject(hBitmap, sizeof(DIBSECTION), NULL) == sizeof(BITMAP)); @@ -115,8 +117,15 @@ Test_Dibsection(PTESTINFO pti) RTEST(GetObject(hBitmap, -5, NULL) == sizeof(BITMAP)); RTEST(GetObject(hBitmap, 0, &dibsection) == 0); RTEST(GetObject(hBitmap, 5, &dibsection) == 0); - RTEST(GetObject(hBitmap, sizeof(BITMAP), &dibsection) == sizeof(BITMAP)); - RTEST(GetObject(hBitmap, sizeof(BITMAP)+2, &dibsection) == sizeof(BITMAP)); + RTEST(GetObject(hBitmap, sizeof(BITMAP), &bitmap) == sizeof(BITMAP)); + RTEST(GetObject(hBitmap, sizeof(BITMAP)+2, &bitmap) == sizeof(BITMAP)); + TEST(bitmap.bmType == 0); + TEST(bitmap.bmWidth == 10); + TEST(bitmap.bmHeight == 9); + TEST(bitmap.bmWidthBytes == 12); + TEST(bitmap.bmPlanes == 1); + TEST(bitmap.bmBitsPixel == 8); + TEST(bitmap.bmBits == pData); RTEST(GetObject(hBitmap, sizeof(DIBSECTION), &dibsection) == sizeof(DIBSECTION)); RTEST(GetObject(hBitmap, sizeof(DIBSECTION)+2, &dibsection) == sizeof(DIBSECTION)); RTEST(GetObject(hBitmap, -5, &dibsection) == sizeof(DIBSECTION)); diff --git a/rostests/apitests/gdi32api/tests/GetTextFace.c b/rostests/apitests/gdi32api/tests/GetTextFace.c new file mode 100644 index 00000000000..4063784fac7 --- /dev/null +++ b/rostests/apitests/gdi32api/tests/GetTextFace.c @@ -0,0 +1,68 @@ + +INT +Test_GetTextFace(PTESTINFO pti) +{ + HDC hDC; + INT ret; + INT ret2; + WCHAR Buffer[20]; + + hDC = CreateCompatibleDC(NULL); + ASSERT(hDC); + + /* Whether asking for the string size (NULL buffer) ignores the size argument */ + SetLastError(0xE000BEEF); + ret = GetTextFaceW(hDC, 0, NULL); + TEST(ret != 0); + TEST(GetLastError() == 0xE000BEEF); + ret2 = ret; + + SetLastError(0xE000BEEF); + ret = GetTextFaceW(hDC, -1, NULL); + TEST(ret != 0); + TEST(ret == ret2); + TEST(GetLastError() == 0xE000BEEF); + ret2 = ret; + + SetLastError(0xE000BEEF); + ret = GetTextFaceW(hDC, 10000, NULL); + TEST(ret != 0); + TEST(ret == ret2); + TEST(GetLastError() == 0xE000BEEF); + ret2 = ret; + + /* Whether the buffer is correctly filled */ + SetLastError(0xE000BEEF); + ret = GetTextFaceW(hDC, 20, Buffer); + TEST(ret != 0); + TEST(ret <= 20); + TEST(Buffer[ret - 1] == 0); + TEST(GetLastError() == 0xE000BEEF); + + SetLastError(0xE000BEEF); + ret = GetTextFaceW(hDC, 1, Buffer); + TEST(ret == 1); + TEST(Buffer[ret - 1] == 0); + TEST(GetLastError() == 0xE000BEEF); + + SetLastError(0xE000BEEF); + ret = GetTextFaceW(hDC, 2, Buffer); + TEST(ret == 2); + TEST(Buffer[ret - 1] == 0); + TEST(GetLastError() == 0xE000BEEF); + + /* Whether invalid buffer sizes are correctly ignored */ + SetLastError(0xE000BEEF); + ret = GetTextFaceW(hDC, 0, Buffer); + TEST(ret == 0); + TEST(GetLastError() == 0xE000BEEF); + + SetLastError(0xE000BEEF); + ret = GetTextFaceW(hDC, -1, Buffer); + TEST(ret == 0); + TEST(GetLastError() == 0xE000BEEF); + + DeleteDC(hDC); + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/gdi32api/tests/SetDCPenColor.c b/rostests/apitests/gdi32api/tests/SetDCPenColor.c index 32cc26a124c..d69b3dffa0c 100644 --- a/rostests/apitests/gdi32api/tests/SetDCPenColor.c +++ b/rostests/apitests/gdi32api/tests/SetDCPenColor.c @@ -2,6 +2,7 @@ INT Test_SetDCPenColor(PTESTINFO pti) { HDC hScreenDC, hDC; + HBITMAP hbmp; // Test an incorrect DC SetLastError(ERROR_SUCCESS); @@ -33,6 +34,16 @@ Test_SetDCPenColor(PTESTINFO pti) SetDCPenColor(hDC, CLR_INVALID); RTEST(SetDCPenColor(hDC, RGB(0,0,0)) == CLR_INVALID); + hbmp = CreateBitmap(10, 10, 1, 32, NULL); + ASSERT(hbmp); + + SelectObject(hDC, hbmp); + SelectObject(hDC, GetStockObject(DC_PEN)); + SetDCPenColor(hDC, 0x123456); + MoveToEx(hDC, 0, 0, NULL); + LineTo(hDC, 10, 0); + TEST(GetPixel(hDC, 5, 0) == 0x123456); + // Delete the DC DeleteDC(hDC); diff --git a/rostests/apitests/gdi32api/tests/SetMapMode.c b/rostests/apitests/gdi32api/tests/SetMapMode.c new file mode 100644 index 00000000000..9d8c66deea2 --- /dev/null +++ b/rostests/apitests/gdi32api/tests/SetMapMode.c @@ -0,0 +1,181 @@ + + + +INT +Test_SetMapMode(PTESTINFO pti) +{ + HDC hDC; + SIZE WindowExt, ViewportExt; + ULONG ulMapMode; + + hDC = CreateCompatibleDC(NULL); + ASSERT(hDC); + + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + + ulMapMode = SetMapMode(hDC, MM_ISOTROPIC); + TEST(ulMapMode == MM_TEXT); + TEST(WindowExt.cx == 1); + TEST(WindowExt.cy == 1); + TEST(ViewportExt.cx == 1); + TEST(ViewportExt.cy == 1); + + SetLastError(0); + ulMapMode = SetMapMode(hDC, 0); + TEST(GetLastError() == 0); + TEST(ulMapMode == 0); + + /* Go through all valid values */ + ulMapMode = SetMapMode(hDC, 1); + TEST(ulMapMode == MM_ISOTROPIC); + ulMapMode = SetMapMode(hDC, 2); + TEST(ulMapMode == 1); + ulMapMode = SetMapMode(hDC, 3); + TEST(ulMapMode == 2); + ulMapMode = SetMapMode(hDC, 4); + TEST(ulMapMode == 3); + ulMapMode = SetMapMode(hDC, 5); + TEST(ulMapMode == 4); + ulMapMode = SetMapMode(hDC, 6); + TEST(ulMapMode == 5); + ulMapMode = SetMapMode(hDC, 7); + TEST(ulMapMode == 6); + ulMapMode = SetMapMode(hDC, 8); + TEST(ulMapMode == 7); + + /* Test invalid value */ + ulMapMode = SetMapMode(hDC, 9); + TEST(ulMapMode == 0); + ulMapMode = SetMapMode(hDC, 10); + TEST(ulMapMode == 0); + + TEST(GetLastError() == 0); + + /* Test NULL DC */ + ulMapMode = SetMapMode((HDC)0, 2); + TEST(ulMapMode == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + /* Test NULL DC and invalid mode */ + ulMapMode = SetMapMode((HDC)0, 10); + TEST(ulMapMode == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + /* Test invalid DC */ + ulMapMode = SetMapMode((HDC)0x12345, 2); + TEST(ulMapMode == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + /* Test invalid DC and invalid mode */ + ulMapMode = SetMapMode((HDC)0x12345, 10); + TEST(ulMapMode == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + DeleteDC(hDC); + + /* Test a deleted DC */ + ulMapMode = SetMapMode(hDC, 2); + TEST(ulMapMode == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + /* Test MM_TEXT */ + hDC = CreateCompatibleDC(NULL); + SetMapMode(hDC, MM_TEXT); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 1); + TEST(WindowExt.cy == 1); + TEST(ViewportExt.cx == 1); + TEST(ViewportExt.cy == 1); + DeleteDC(hDC); + + /* Test MM_ISOTROPIC */ + hDC = CreateCompatibleDC(NULL); + SetMapMode(hDC, MM_ISOTROPIC); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 3600); + TEST(WindowExt.cy == 2700); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + DeleteDC(hDC); + + /* Test MM_ANISOTROPIC */ + hDC = CreateCompatibleDC(NULL); + SetMapMode(hDC, MM_ANISOTROPIC); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 1); + TEST(WindowExt.cy == 1); + TEST(ViewportExt.cx == 1); + TEST(ViewportExt.cy == 1); + + /* set MM_ISOTROPIC first, the values will be kept */ + SetMapMode(hDC, MM_ISOTROPIC); + SetMapMode(hDC, MM_ANISOTROPIC); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 3600); + TEST(WindowExt.cy == 2700); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + DeleteDC(hDC); + + /* Test MM_LOMETRIC */ + hDC = CreateCompatibleDC(NULL); + SetMapMode(hDC, MM_LOMETRIC); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 3600); + TEST(WindowExt.cy == 2700); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + DeleteDC(hDC); + + /* Test MM_HIMETRIC */ + hDC = CreateCompatibleDC(NULL); + SetMapMode(hDC, MM_HIMETRIC); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 36000); + TEST(WindowExt.cy == 27000); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + DeleteDC(hDC); + + /* Test MM_LOENGLISH */ + hDC = CreateCompatibleDC(NULL); + SetMapMode(hDC, MM_LOENGLISH); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 1417); + TEST(WindowExt.cy == 1063); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + DeleteDC(hDC); + + /* Test MM_HIENGLISH */ + hDC = CreateCompatibleDC(NULL); + SetMapMode(hDC, MM_HIENGLISH); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 14173); + TEST(WindowExt.cy == 10630); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + DeleteDC(hDC); + + /* Test MM_TWIPS */ + hDC = CreateCompatibleDC(NULL); + SetMapMode(hDC, MM_TWIPS); + GetWindowExtEx(hDC, &WindowExt); + GetViewportExtEx(hDC, &ViewportExt); + TEST(WindowExt.cx == 20409); + TEST(WindowExt.cy == 15307); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + DeleteDC(hDC); + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/gdi32api/tests/SetWindowExtEx.c b/rostests/apitests/gdi32api/tests/SetWindowExtEx.c new file mode 100644 index 00000000000..9b12a580afd --- /dev/null +++ b/rostests/apitests/gdi32api/tests/SetWindowExtEx.c @@ -0,0 +1,275 @@ + + +INT +Test_SetWindowExtEx(PTESTINFO pti) +{ + HDC hDC; + BOOL ret; + SIZE WindowExt, ViewportExt; + PGDI_TABLE_ENTRY pEntry; + DC_ATTR* pDC_Attr; + + hDC = CreateCompatibleDC(0); + ASSERT(hDC); + + SetLastError(0); + ret = SetWindowExtEx(0, 0, 0, NULL); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + TEST(ret == 0); + + SetLastError(0); + ret = SetWindowExtEx((HDC)0x1234, 0, 0, NULL); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + TEST(ret == 0); + + SetLastError(0); + ret = SetWindowExtEx(hDC, 0, 0, NULL); + TEST(GetLastError() == 0); + TEST(ret == 1); + + WindowExt.cx = 1234; + WindowExt.cy = 6789; + SetLastError(0); + ret = SetWindowExtEx(0, 0, 0, &WindowExt); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + TEST(ret == 0); + TEST(WindowExt.cx == 1234); + TEST(WindowExt.cy == 6789); + + DeleteDC(hDC); + + /* Test with a deleted DC */ + SetLastError(0); + ret = SetWindowExtEx(hDC, 0, 0, NULL); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + TEST(ret == 0); + + hDC = CreateCompatibleDC(0); + ASSERT(hDC); + + pEntry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hDC); + ASSERT(pEntry); + pDC_Attr = pEntry->UserData; + ASSERT(pDC_Attr); + + /* Test setting it without changing the map mode (MM_TEXT) */ + ret = SetWindowExtEx(hDC, 10, 20, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 1); + TEST(WindowExt.cy == 1); + + /* Values should not be changed */ + WindowExt.cx = WindowExt.cy = 0; + ret = SetWindowExtEx(hDC, 40, 30, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 1); + TEST(WindowExt.cy == 1); + + /* Check the viewport */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == 1); + TEST(ViewportExt.cy == 1); + + /* Test setting in isotropic mode with 0 extents */ + SetMapMode(hDC, MM_ISOTROPIC); + WindowExt.cx = WindowExt.cy = 0; + ret = SetWindowExtEx(hDC, 0, 0, &WindowExt); + TEST(ret == 0); + TEST(WindowExt.cx == 3600); + TEST(WindowExt.cy == 2700); + ret = SetWindowExtEx(hDC, 100, 0, &WindowExt); + TEST(ret == 0); + ret = SetWindowExtEx(hDC, 0, 100, &WindowExt); + TEST(ret == 0); + + /* Test setting in isotropic mode */ + ret = SetWindowExtEx(hDC, 21224, 35114, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 3600); + TEST(WindowExt.cy == 2700); + + /* Values should be changed */ + ret = SetWindowExtEx(hDC, + 4 * GetDeviceCaps(GetDC(0), HORZRES), + -4 * GetDeviceCaps(GetDC(0), VERTRES), + &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 21224); + TEST(WindowExt.cy == 35114); + + /* Check the viewport, should be the same */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + + /* again isotropic mode with 1:1 res */ + ret = SetWindowExtEx(hDC, 123, 123, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 4 * GetDeviceCaps(GetDC(0), HORZRES)); + TEST(WindowExt.cy == -4 * GetDeviceCaps(GetDC(0), VERTRES)); + + /* Test flXform */ + TEST(pDC_Attr->flXform & PAGE_EXTENTS_CHANGED); + + /* Check the viewport from the dcattr, without going through gdi */ + TEST(pDC_Attr->szlViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(pDC_Attr->szlViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + + /* Check the viewport with gdi, should not be the same */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), VERTRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + + /* Test flXform */ + TEST(pDC_Attr->flXform & PAGE_EXTENTS_CHANGED); + + /* again isotropic mode with 3:1 res */ + ret = SetWindowExtEx(hDC, 300, 100, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 123); + TEST(WindowExt.cy == 123); + + /* Check the viewport now, should not be the same */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), VERTRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES) / 3); + + /* again isotropic mode with 1:3 res */ + SetViewportExtEx(hDC, 6000, 3000, 0); + ret = SetWindowExtEx(hDC, 200, 600, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 300); + TEST(WindowExt.cy == 100); + + /* Check the viewport now, should not be the same */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == 1000); + TEST(ViewportExt.cy == 3000); + + /* Test setting in anisotropic mode */ + SetMapMode(hDC, MM_ANISOTROPIC); + ret = SetWindowExtEx(hDC, 80, 60, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 200); + TEST(WindowExt.cy == 600); + + /* Values should be changed */ + ret = SetWindowExtEx(hDC, 500, 500, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 80); + TEST(WindowExt.cy == 60); + + /* Check the viewport */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == 1000); + TEST(ViewportExt.cy == 3000); + + /* Test setting in low metric mode */ + SetMapMode(hDC, MM_LOMETRIC); + ret = SetWindowExtEx(hDC, 120, 90, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 3600); + TEST(WindowExt.cy == 2700); + + /* Values should not be changed */ + WindowExt.cx = WindowExt.cy = 0; + ret = SetWindowExtEx(hDC, 900, 700, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 3600); + TEST(WindowExt.cy == 2700); + + /* Check the viewport */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + + /* Test setting in high metric mode */ + SetMapMode(hDC, MM_HIMETRIC); + ret = SetWindowExtEx(hDC, 120, 90, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 36000); + TEST(WindowExt.cy == 27000); + + /* Values should not be changed */ + WindowExt.cx = WindowExt.cy = 0; + ret = SetWindowExtEx(hDC, 500, 300, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 36000); + TEST(WindowExt.cy == 27000); + + /* Check the viewport */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + + /* Test setting in low english mode */ + SetMapMode(hDC, MM_LOENGLISH); + ret = SetWindowExtEx(hDC, 320, 290, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 1417); + TEST(WindowExt.cy == 1063); + + /* Values should not be changed */ + WindowExt.cx = WindowExt.cy = 0; + ret = SetWindowExtEx(hDC, 560, 140, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 1417); + TEST(WindowExt.cy == 1063); + + /* Check the viewport */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + + /* Test setting in high english mode */ + SetMapMode(hDC, MM_HIENGLISH); + ret = SetWindowExtEx(hDC, 320, 290, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 14173); + TEST(WindowExt.cy == 10630); + + /* Values should not be changed */ + WindowExt.cx = WindowExt.cy = 0; + ret = SetWindowExtEx(hDC, 1560, 1140, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 14173); + TEST(WindowExt.cy == 10630); + + /* Check the viewport */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + + /* Test setting in twips mode */ + SetMapMode(hDC, MM_TWIPS); + ret = SetWindowExtEx(hDC, 3320, 3290, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 20409); + TEST(WindowExt.cy == 15307); + + /* Values should not be changed */ + WindowExt.cx = WindowExt.cy = 0; + ret = SetWindowExtEx(hDC, 4560, 4140, &WindowExt); + TEST(ret == 1); + TEST(WindowExt.cx == 20409); + TEST(WindowExt.cy == 15307); + + /* Check the viewport */ + GetViewportExtEx(hDC, &ViewportExt); + TEST(ViewportExt.cx == GetDeviceCaps(GetDC(0), HORZRES)); + TEST(ViewportExt.cy == -GetDeviceCaps(GetDC(0), VERTRES)); + + /* test manually modifying the dcattr, should go to tests for GetViewportExtEx */ + SetMapMode(hDC, MM_ISOTROPIC); + ret = SetWindowExtEx(hDC, 420, 4140, &WindowExt); + pDC_Attr->szlWindowExt.cx = 0; + GetViewportExtEx(hDC, &ViewportExt); + TEST(pDC_Attr->szlWindowExt.cx == 0); + TEST(ViewportExt.cx == 0); + + DeleteDC(hDC); + + return APISTATUS_NORMAL; + + +} diff --git a/rostests/apitests/user32api/testlist.c b/rostests/apitests/user32api/testlist.c index a76a7d361b8..0dc05131500 100644 --- a/rostests/apitests/user32api/testlist.c +++ b/rostests/apitests/user32api/testlist.c @@ -6,6 +6,7 @@ #include "user32api.h" /* include the tests */ +#include "tests/GetSystemMetrics.c" #include "tests/InitializeLpkHooks.c" #include "tests/ScrollDC.c" #include "tests/ScrollWindowEx.c" @@ -14,6 +15,7 @@ /* The List of tests */ TESTENTRY TestList[] = { + { L"GetSystemMetrics", Test_GetSystemMetrics }, { L"InitializeLpkHooks", Test_InitializeLpkHooks }, { L"ScrollDC", Test_ScrollDC }, { L"ScrollWindowEx", Test_ScrollWindowEx }, diff --git a/rostests/apitests/user32api/tests/GetSystemMetrics.c b/rostests/apitests/user32api/tests/GetSystemMetrics.c new file mode 100644 index 00000000000..720f0f7a91d --- /dev/null +++ b/rostests/apitests/user32api/tests/GetSystemMetrics.c @@ -0,0 +1,396 @@ + +INT +Test_GetSystemMetrics(PTESTINFO pti) +{ + INT ret; + HDC hDC; + BOOL BoolVal; + UINT UintVal; + RECT rect; + + SetLastError(0); + hDC = GetDC(0); + + ret = GetSystemMetrics(0); + TEST(ret > 0); + + ret = GetSystemMetrics(64); + TEST(ret == 0); + ret = GetSystemMetrics(65); + TEST(ret == 0); + ret = GetSystemMetrics(66); + TEST(ret == 0); + + + ret = GetSystemMetrics(SM_CXSCREEN); + TEST(ret == GetDeviceCaps(hDC, HORZRES)); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYSCREEN); + TEST(ret == GetDeviceCaps(hDC, VERTRES)); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXVSCROLL); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYHSCROLL); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYCAPTION); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXBORDER); + SystemParametersInfoW(SPI_GETFOCUSBORDERWIDTH, 0, &UintVal, 0); + TEST(ret == UintVal); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYBORDER); + SystemParametersInfoW(SPI_GETFOCUSBORDERHEIGHT, 0, &UintVal, 0); + TEST(ret == UintVal); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXDLGFRAME); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYDLGFRAME); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYVTHUMB); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXHTHUMB); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXICON); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYICON); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXCURSOR); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYCURSOR); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMENU); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + SystemParametersInfoW(SPI_GETWORKAREA, 0, &rect, 0); + ret = GetSystemMetrics(SM_CXFULLSCREEN); + TEST(ret == rect.right); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYFULLSCREEN); + TEST(ret == rect.bottom - rect.top - GetSystemMetrics(SM_CYCAPTION)); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYKANJIWINDOW); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_MOUSEPRESENT); + TEST(ret == 1); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYVSCROLL); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXHSCROLL); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_DEBUG); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_SWAPBUTTON); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_RESERVED1); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_RESERVED2); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_RESERVED3); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_RESERVED4); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXMIN); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMIN); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXSIZE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYSIZE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXFRAME); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYFRAME); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXMINTRACK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMINTRACK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXDOUBLECLK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYDOUBLECLK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXICONSPACING); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYICONSPACING); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_MENUDROPALIGNMENT); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_PENWINDOWS); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_DBCSENABLED); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CMOUSEBUTTONS); +// TEST(ret == 0); + TEST(GetLastError() == 0); + +#if(WINVER >= 0x0400) + ret = GetSystemMetrics(SM_SECURE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXEDGE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYEDGE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXMINSPACING); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMINSPACING); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXSMICON); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYSMICON); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYSMCAPTION); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXSMSIZE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYSMSIZE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXMENUSIZE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMENUSIZE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_ARRANGE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXMINIMIZED); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMINIMIZED); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXMAXTRACK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMAXTRACK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXMAXIMIZED); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMAXIMIZED); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_NETWORK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CLEANBOOT); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXDRAG); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYDRAG); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_SHOWSOUNDS); + SystemParametersInfoW(SPI_GETSHOWSOUNDS, 0, &BoolVal, 0); + TEST(ret == BoolVal); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXMENUCHECK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYMENUCHECK); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_SLOWMACHINE); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_MIDEASTENABLED); +// TEST(ret == 0); + TEST(GetLastError() == 0); +#endif + +#if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400) + ret = GetSystemMetrics(SM_MOUSEWHEELPRESENT); +// TEST(ret == 0); + TEST(GetLastError() == 0); +#endif + +#if(WINVER >= 0x0500) + ret = GetSystemMetrics(SM_XVIRTUALSCREEN); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_YVIRTUALSCREEN); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXVIRTUALSCREEN); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYVIRTUALSCREEN); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CMONITORS); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_SAMEDISPLAYFORMAT); +// TEST(ret == 0); + TEST(GetLastError() == 0); +#endif + +#if(_WIN32_WINNT >= 0x0500) + ret = GetSystemMetrics(SM_IMMENABLED); + TEST(ret == 0); + TEST(GetLastError() == 0); +#endif + +#if(_WIN32_WINNT >= 0x0501) + ret = GetSystemMetrics(SM_CXFOCUSBORDER); + SystemParametersInfoW(SPI_GETFOCUSBORDERWIDTH, 0, &UintVal, 0); + TEST(ret == UintVal); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CYFOCUSBORDER); + SystemParametersInfoW(SPI_GETFOCUSBORDERHEIGHT, 0, &UintVal, 0); + TEST(ret == UintVal); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_TABLETPC); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_MEDIACENTER); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_STARTER); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_SERVERR2); +// TEST(ret == 0); + TEST(GetLastError() == 0); +#endif + +#if(_WIN32_WINNT >= 0x0600) + ret = GetSystemMetrics(SM_MOUSEHORIZONTALWHEELPRESENT); +// TEST(ret == 0); + TEST(GetLastError() == 0); + + ret = GetSystemMetrics(SM_CXPADDEDBORDER); +// TEST(ret == 0); + TEST(GetLastError() == 0); +#endif + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/user32api/tests/InitializeLpkHooks.c b/rostests/apitests/user32api/tests/InitializeLpkHooks.c index bdfe900cdce..85e6d7a4667 100644 --- a/rostests/apitests/user32api/tests/InitializeLpkHooks.c +++ b/rostests/apitests/user32api/tests/InitializeLpkHooks.c @@ -27,7 +27,7 @@ int Count_myLpkTabbedTextOut = 0; int Count_myLpkPSMTextOut = 0; int Count_myLpkDrawTextEx = 0; -DWORD STDCALL myLpkTabbedTextOut (LPVOID x1,LPVOID x2,LPVOID x3, LPVOID x4, LPVOID x5, LPVOID x6, LPVOID x7, LPVOID x8, +DWORD WINAPI myLpkTabbedTextOut (LPVOID x1,LPVOID x2,LPVOID x3, LPVOID x4, LPVOID x5, LPVOID x6, LPVOID x7, LPVOID x8, LPVOID x9, LPVOID x10, LPVOID x11, LPVOID x12) { Count_myLpkTabbedTextOut++; @@ -55,7 +55,7 @@ typedef struct _USER32_INTERN_INITALIZEHOOKS PLPK_LPEDITCONTROL_LIST fpListLpkEditControl; } USER32_INTERN_INITALIZEHOOKS, *PUSER32_INTERN_INITALIZEHOOKS; -VOID STDCALL InitializeLpkHooks (PUSER32_INTERN_INITALIZEHOOKS); +VOID WINAPI InitializeLpkHooks (PUSER32_INTERN_INITALIZEHOOKS); INT Test_InitializeLpkHooks(PTESTINFO pti) diff --git a/rostests/apitests/user32api/user32api.rbuild b/rostests/apitests/user32api/user32api.rbuild index 646eeda53c5..ea33d4e33ea 100644 --- a/rostests/apitests/user32api/user32api.rbuild +++ b/rostests/apitests/user32api/user32api.rbuild @@ -1,9 +1,6 @@ . - - 0x0501 apitest - kernel32 user32 gdi32 shell32 diff --git a/rostests/apitests/w32kdll/w32kdll_2k3sp2/w32kdll_2k3sp2.rbuild b/rostests/apitests/w32kdll/w32kdll_2k3sp2/w32kdll_2k3sp2.rbuild index 2c08116d2ec..5876d07b0e4 100644 --- a/rostests/apitests/w32kdll/w32kdll_2k3sp2/w32kdll_2k3sp2.rbuild +++ b/rostests/apitests/w32kdll/w32kdll_2k3sp2/w32kdll_2k3sp2.rbuild @@ -1,7 +1,5 @@ - - 0x0502 w32kdll_2k3sp2.S main.c diff --git a/rostests/apitests/w32kdll/w32kdll_2ksp4/w32kdll_2ksp4.rbuild b/rostests/apitests/w32kdll/w32kdll_2ksp4/w32kdll_2ksp4.rbuild index 2531c46ca48..2083f95151b 100644 --- a/rostests/apitests/w32kdll/w32kdll_2ksp4/w32kdll_2ksp4.rbuild +++ b/rostests/apitests/w32kdll/w32kdll_2ksp4/w32kdll_2ksp4.rbuild @@ -1,7 +1,5 @@ - - 0x0502 w32kdll_2ksp4.S main.c diff --git a/rostests/apitests/w32kdll/w32kdll_ros/w32kdll_ros.def b/rostests/apitests/w32kdll/w32kdll_ros/w32kdll_ros.def index ec3c7cc0805..490e9d3588b 100644 --- a/rostests/apitests/w32kdll/w32kdll_ros/w32kdll_ros.def +++ b/rostests/apitests/w32kdll/w32kdll_ros/w32kdll_ros.def @@ -241,7 +241,7 @@ NtGdiMonoBitmap@4 NtGdiMoveTo@16 NtGdiOffsetClipRgn@12 NtGdiOffsetRgn@12 -NtGdiOpenDCW@28 +NtGdiOpenDCW@32 NtGdiPatBlt@24 NtGdiPolyPatBlt@20 NtGdiPathToRegion@4 @@ -497,7 +497,7 @@ NtUserRealInternalGetMessage@24 NtUserRealWaitMessageEx@8 NtUserRedrawWindow@16 NtUserRegisterClassExWOW@28 -NtUserRegisterUserApiHook@8 +NtUserRegisterUserApiHook@16 NtUserRegisterHotKey@16 NtUserRegisterRawInputDevices@12 NtUserRegisterTasklist@4 @@ -587,7 +587,7 @@ NtUserUnregisterUserApiHook@0 NtUserUnregisterHotKey@8 NtUserUpdateInputContext@12 NtUserUpdateInstance@12 -NtUserUpdateLayeredWindow@36 +NtUserUpdateLayeredWindow@40 NtUserGetLayeredWindowAttributes@16 NtUserSetLayeredWindowAttributes@16 NtUserUpdatePerUserSystemParameters@8 diff --git a/rostests/apitests/w32kdll/w32kdll_ros/w32kdll_ros.rbuild b/rostests/apitests/w32kdll/w32kdll_ros/w32kdll_ros.rbuild index 1cd91ce10a9..b81ecad236c 100644 --- a/rostests/apitests/w32kdll/w32kdll_ros/w32kdll_ros.rbuild +++ b/rostests/apitests/w32kdll/w32kdll_ros/w32kdll_ros.rbuild @@ -1,7 +1,5 @@ - - 0x0502 win32ksys main.c diff --git a/rostests/apitests/w32kdll/w32kdll_vista/w32kdll_vista.rbuild b/rostests/apitests/w32kdll/w32kdll_vista/w32kdll_vista.rbuild index a504093c201..68c9b18d23b 100644 --- a/rostests/apitests/w32kdll/w32kdll_vista/w32kdll_vista.rbuild +++ b/rostests/apitests/w32kdll/w32kdll_vista/w32kdll_vista.rbuild @@ -1,7 +1,5 @@ - - 0x0502 w32kdll_vista.S main.c diff --git a/rostests/apitests/w32kdll/w32kdll_xpsp2/w32kdll_xpsp2.rbuild b/rostests/apitests/w32kdll/w32kdll_xpsp2/w32kdll_xpsp2.rbuild index 06798204580..d3467c48582 100644 --- a/rostests/apitests/w32kdll/w32kdll_xpsp2/w32kdll_xpsp2.rbuild +++ b/rostests/apitests/w32kdll/w32kdll_xpsp2/w32kdll_xpsp2.rbuild @@ -1,7 +1,5 @@ - - 0x0502 w32kdll_xpsp2.S main.c diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiCombineRgn.c b/rostests/apitests/w32knapi/ntgdi/NtGdiCombineRgn.c new file mode 100644 index 00000000000..0b267d33065 --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiCombineRgn.c @@ -0,0 +1,49 @@ + +INT +Test_NtGdiCombineRgn(PTESTINFO pti) +{ + HRGN hRgnDest, hRgn1, hRgn2; +// test what params are accepted for what operations +// 0? invalid? are params maybe ignored in some cases? +// LastError + + /* Preparation */ + hRgnDest = CreateRectRgn(0,0,1,1); + hRgn1 = CreateRectRgn(1,1,4,4); + hRgn2 = CreateRectRgn(2,2,6,3); + + /* RGN_AND = 1, RGN_OR = 2, RGN_XOR = 3, RGN_DIFF = 4, RGN_COPY = 5 */ + + TEST(NtGdiCombineRgn(hRgnDest, hRgn1, hRgn2, 0) == ERROR); + TEST(NtGdiCombineRgn(hRgnDest, hRgn1, hRgn2, 6) == ERROR); + + SetLastError(ERROR_SUCCESS); + TEST(NtGdiCombineRgn(hRgnDest, 0, 0, RGN_AND) == ERROR); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + SetLastError(ERROR_SUCCESS); + TEST(NtGdiCombineRgn(hRgnDest, hRgn1, 0, RGN_AND) == ERROR); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + SetLastError(ERROR_SUCCESS); + TEST(NtGdiCombineRgn(hRgnDest, 0, hRgn1, RGN_AND) == ERROR); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + SetLastError(ERROR_SUCCESS); + TEST(NtGdiCombineRgn(0, hRgn1, hRgn2, RGN_AND) == ERROR); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + /* Create intersection */ + TEST(NtGdiCombineRgn(hRgnDest, hRgn1, hRgn2, RGN_AND) == SIMPLEREGION); + SetRectRgn(hRgn1, 2, 2, 4, 3); + TEST(NtGdiCombineRgn(hRgnDest, hRgnDest, hRgn1, RGN_XOR) == NULLREGION); + + /* Create intersection with itself */ + SetRectRgn(hRgnDest, 2, 2, 4, 3); + TEST(NtGdiCombineRgn(hRgnDest, hRgnDest, hRgnDest, RGN_AND) == SIMPLEREGION); + SetRectRgn(hRgn1, 2, 2, 4, 3); + TEST(NtGdiCombineRgn(hRgnDest, hRgnDest, hRgn1, RGN_XOR) == NULLREGION); + + + /* What if 2 regions are the same */ + + return APISTATUS_NORMAL; +} + diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiCreateCompatibleDC.c b/rostests/apitests/w32knapi/ntgdi/NtGdiCreateCompatibleDC.c new file mode 100644 index 00000000000..a53821b5889 --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiCreateCompatibleDC.c @@ -0,0 +1,27 @@ + +INT +Test_NtGdiCreateCompatibleDC(PTESTINFO pti) +{ + HDC hDC; + HGDIOBJ hObj; + + /* Test if aa NULL DC is accepted */ + hDC = NtGdiCreateCompatibleDC(NULL); + TEST(hDC != NULL); + + /* We select a nwe palette. Note: SelectObject doesn't work with palettes! */ + hObj = SelectPalette(hDC, GetStockObject(DEFAULT_PALETTE), 0); + /* The old palette should be GetStockObject(DEFAULT_PALETTE) */ + TEST(hObj == GetStockObject(DEFAULT_PALETTE)); + + /* The default bitmap should be GetStockObject(21) */ + hObj = SelectObject(hDC, GetStockObject(21)); + TEST(hObj == GetStockObject(21)); + + /* The default pen should be GetStockObject(BLACK_PEN) */ + hObj = SelectObject(hDC, GetStockObject(WHITE_PEN)); + TEST(hObj == GetStockObject(BLACK_PEN)); + + return APISTATUS_NORMAL; +} + diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiCreateDIBSection.c b/rostests/apitests/w32knapi/ntgdi/NtGdiCreateDIBSection.c new file mode 100644 index 00000000000..9375ef2300f --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiCreateDIBSection.c @@ -0,0 +1,475 @@ + +/* +HBITMAP +APIENTRY +NtGdiCreateDIBSection( + IN HDC hDC, + IN OPTIONAL HANDLE hSection, + IN DWORD dwOffset, + IN LPBITMAPINFO pbmi, + IN DWORD iUsage, + IN UINT cjHeader, + IN FLONG fl, + IN ULONG_PTR dwColorSpace, + OUT PVOID *ppvBits) +*/ + +ULONG +GetBitmapSize(BITMAPINFOHEADER *pbih) +{ + ULONG WidthBits, WidthBytes; + + WidthBits = pbih->biWidth * pbih->biBitCount * pbih->biPlanes; + WidthBytes = ((WidthBits + 31) & ~ 31) >> 3; + + return pbih->biHeight * WidthBytes; +} + + +INT +Test_NtGdiCreateDIBSection(PTESTINFO pti) +{ + HBITMAP hbmp; + HDC hDC; + ULONG cjHeader; + PVOID pvBits = NULL; + ULONG cEntries; + DIBSECTION dibsection; + + struct + { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[100]; + } bmi; + PBITMAPINFO pbmi = (PBITMAPINFO)&bmi; + PBITMAPINFOHEADER pbih = (PBITMAPINFOHEADER)&bmi.bmiHeader; + PBITMAPV4HEADER pbV4h = (PBITMAPV4HEADER)&bmi.bmiHeader; + PBITMAPV5HEADER pbV5h = (PBITMAPV5HEADER)&bmi.bmiHeader; + + HANDLE hSection; + NTSTATUS Status; + LARGE_INTEGER MaximumSize; + + hDC = GetDC(0); + pbih->biSize = sizeof(BITMAPINFOHEADER); + pbih->biWidth = 2; + pbih->biHeight = 2; + pbih->biPlanes = 1; + pbih->biBitCount = 1; + pbih->biCompression = BI_RGB; + pbih->biSizeImage = 0; + pbih->biXPelsPerMeter = 100; + pbih->biYPelsPerMeter = 100; + pbih->biClrUsed = 2; + pbih->biClrImportant = 2; + + cEntries = 0; + +/** iUsage = 0 (DIB_RGB_COLORS) ***********************************************/ + + cjHeader = bmi.bmiHeader.biSize + cEntries * 4 + 8; + + /* Test something simple */ + SetLastError(0); + pvBits = 0; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits != NULL); + TEST(hbmp != 0); +// TEST(GetLastError() == 0); + TEST(GetObject(hbmp, sizeof(DIBSECTION), &dibsection) == sizeof(DIBSECTION)); + TEST(dibsection.dsBitfields[0] == 0); + TEST(dibsection.dsBitfields[1] == 0); + TEST(dibsection.dsBitfields[2] == 0); + TEST(dibsection.dshSection == 0); + TEST(dibsection.dsOffset == 0); + if (hbmp) DeleteObject(hbmp); + + + /* Test a 0 HDC */ + SetLastError(0); + pvBits = 0; + hbmp = NtGdiCreateDIBSection(0, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits != NULL); + TEST(hbmp != 0); + TEST(GetLastError() == ERROR_NOT_ENOUGH_MEMORY); + if (hbmp) DeleteObject(hbmp); + + /* Test a wrong HDC */ + SetLastError(0); + pvBits = 0; + hbmp = NtGdiCreateDIBSection((HDC)0xdeadbeef, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits != 0); + TEST(hbmp != 0); + TEST(GetLastError() == 8); + if (hbmp) DeleteObject(hbmp); + + /* Test pbmi = NULL */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, NULL, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + /* Test invalid pbmi */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, (PVOID)0x80001234, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + if (hbmp) DeleteObject(hbmp); + + /* Test invalid pbmi */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, (PVOID)1, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + if (hbmp) DeleteObject(hbmp); + + /* Test ppvBits = NULL */ + SetLastError(0); + hbmp = NtGdiCreateDIBSection(0, NULL, 0, pbmi, 0, cjHeader, 0, 0, NULL); + TEST(hbmp == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + if (hbmp) DeleteObject(hbmp); + + /* Test ppvBits = NULL and pbmi == 0*/ + SetLastError(0); + hbmp = NtGdiCreateDIBSection(0, NULL, 0, NULL, 0, cjHeader, 0, 0, NULL); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + /* Test ppvBits = NULL and wrong cjHeader */ + SetLastError(0); + hbmp = NtGdiCreateDIBSection(0, NULL, 0, pbmi, 0, cjHeader+4, 0, 0, NULL); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + /* Test ppvBits = NULL and cjHeader = 0 */ + SetLastError(0); + hbmp = NtGdiCreateDIBSection(0, NULL, 0, pbmi, 0, 0, 0, 0, NULL); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + /* Test wrong cjHeader */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader+4, 0, 0, &pvBits); + pvBits = (PVOID)-1; + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + /* Test different bitcount */ + pbih->biBitCount = 4; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(hbmp != 0); + if (hbmp) DeleteObject(hbmp); + + pbih->biBitCount = 8; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(hbmp != 0); + if (hbmp) DeleteObject(hbmp); + + cjHeader = pbih->biSize; + pbih->biBitCount = 16; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(hbmp != 0); + if (hbmp) DeleteObject(hbmp); + + pbih->biBitCount = 24; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(hbmp != 0); + if (hbmp) DeleteObject(hbmp); + + pbih->biBitCount = 32; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(hbmp != 0); + if (hbmp) DeleteObject(hbmp); + + /* Test BI_BITFIELDS */ + cEntries = 3; + cjHeader = pbih->biSize + cEntries * sizeof(DWORD); + pbih->biBitCount = 16; + pbih->biCompression = BI_BITFIELDS; + ((DWORD*)pbmi->bmiColors)[0] = 0x0007; + ((DWORD*)pbmi->bmiColors)[1] = 0x0038; + ((DWORD*)pbmi->bmiColors)[2] = 0x01C0; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(hbmp != 0); + TEST(GetObject(hbmp, sizeof(DIBSECTION), &dibsection) == sizeof(DIBSECTION)); + TEST(dibsection.dsBm.bmType == 0); + TEST(dibsection.dsBm.bmWidth == 2); + TEST(dibsection.dsBm.bmHeight == 2); + TEST(dibsection.dsBm.bmWidthBytes == 4); + TEST(dibsection.dsBm.bmPlanes == 1); + TEST(dibsection.dsBm.bmBitsPixel == 16); + TEST(dibsection.dsBm.bmBits == pvBits); + TEST(dibsection.dsBmih.biSize == sizeof(BITMAPINFOHEADER)); + TEST(dibsection.dsBmih.biWidth == 2); + TEST(dibsection.dsBmih.biHeight == 2); + TEST(dibsection.dsBmih.biPlanes == 1); + TEST(dibsection.dsBmih.biBitCount == 16); + TEST(dibsection.dsBmih.biCompression == BI_BITFIELDS); + TEST(dibsection.dsBmih.biSizeImage == 8); + TEST(dibsection.dsBmih.biXPelsPerMeter == 0); + TEST(dibsection.dsBmih.biYPelsPerMeter == 0); + TEST(dibsection.dsBmih.biClrUsed == 0); + TEST(dibsection.dsBmih.biClrImportant == 0); + TEST(dibsection.dsBitfields[0] == 0x0007); + TEST(dibsection.dsBitfields[1] == 0x0038); + TEST(dibsection.dsBitfields[2] == 0x01C0); + TEST(dibsection.dshSection == 0); + TEST(dibsection.dsOffset == 0); + +printf("dib with bitfileds: %p\n", hbmp); +//system("PAUSE"); + + if (hbmp) DeleteObject(hbmp); + + + /* Test BI_BITFIELDS */ + SetLastError(0); + pvBits = 0; + + pbih->biSize = sizeof(BITMAPINFOHEADER); + pbih->biWidth = 2; + pbih->biHeight = 2; + pbih->biPlanes = 1; + pbih->biBitCount = 4; + pbih->biCompression = BI_RGB; + pbih->biSizeImage = 0; + pbih->biXPelsPerMeter = 100; + pbih->biYPelsPerMeter = 100; + pbih->biClrUsed = 0; + pbih->biClrImportant = 0; + ((DWORD*)pbmi->bmiColors)[0] = 0xF800; + ((DWORD*)pbmi->bmiColors)[1] = 0x00ff00; + ((DWORD*)pbmi->bmiColors)[2] = 0x0000ff; + cEntries = 0; + cjHeader = bmi.bmiHeader.biSize + cEntries * 4 + 20; + + +/** iUsage = 1 (DIB_PAL_COLORS) ***********************************************/ + + pbmi->bmiHeader.biClrUsed = 2; + pbmi->bmiHeader.biClrImportant = 2; + + cEntries = 2; + cjHeader = bmi.bmiHeader.biSize + cEntries * 4 + 8; + + /* Test iUsage = 1 */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 1, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + + +/** iUsage = 2 (???) **********************************************************/ + + /* Test iUsage = 2 */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 2, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + +/** wrong iUsage **************************************************************/ + + cEntries = 0; + cjHeader = bmi.bmiHeader.biSize + cEntries * 4 + 8; + + /* Test iUsage = 3 */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 3, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + if (hbmp) DeleteObject(hbmp); + + /* Test iUsage = 3 */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 3, cjHeader+4, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + /* Test wrong iUsage */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, -55, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + if (hbmp) DeleteObject(hbmp); + + /* Test wrong iUsage and wrong cjHeader */ + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, -55, cjHeader+4, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + /* increased header size */ + pbih->biSize = sizeof(BITMAPINFOHEADER) + 4; + cjHeader = pbih->biSize + cEntries * 4 + 8; + SetLastError(0); + pvBits = 0; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits != NULL); + TEST(hbmp != 0); + TEST(GetLastError() == 8); + if (hbmp) DeleteObject(hbmp); + + /* increased header size */ + pbih->biSize = sizeof(BITMAPINFOHEADER) + 2; + cjHeader = pbih->biSize + cEntries * 4 + 8; + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + /* decreased header size */ + pbih->biSize = sizeof(BITMAPINFOHEADER) - 4; + cjHeader = pbih->biSize + cEntries * 4 + 8; + SetLastError(0); + pvBits = (PVOID)-1; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits == (PVOID)-1); + TEST(hbmp == 0); + TEST(GetLastError() == 0); + if (hbmp) DeleteObject(hbmp); + + +/** BITMAPV4HEADER ************************************************************/ + + pbV4h->bV4Size = sizeof(BITMAPV4HEADER); + pbV4h->bV4Width = 2; + pbV4h->bV4Height = 3; + pbV4h->bV4Planes = 1; + pbV4h->bV4BitCount = 1; + pbV4h->bV4V4Compression = BI_RGB; + pbV4h->bV4SizeImage = 0; + pbV4h->bV4XPelsPerMeter = 100; + pbV4h->bV4YPelsPerMeter = 100; + pbV4h->bV4ClrUsed = 0; + pbV4h->bV4ClrImportant = 0; + pbV4h->bV4RedMask = 0; + pbV4h->bV4GreenMask = 0; + pbV4h->bV4BlueMask = 0; + pbV4h->bV4AlphaMask = 0; + pbV4h->bV4CSType = 0; + memset(&pbV4h->bV4Endpoints, sizeof(CIEXYZTRIPLE), 0); + pbV4h->bV4GammaRed = 0; + pbV4h->bV4GammaGreen = 0; + pbV4h->bV4GammaBlue = 0; + + cEntries = 0; + cjHeader = bmi.bmiHeader.biSize + cEntries * 4 + 8; + + /* Test something simple */ + SetLastError(0); + pvBits = 0; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits != NULL); + TEST(hbmp != 0); + TEST(GetLastError() == 8); + if (hbmp) DeleteObject(hbmp); + + +/** BITMAPV5HEADER ************************************************************/ + + pbV5h->bV5Size = sizeof(BITMAPV5HEADER); + pbV5h->bV5Width = 2; + pbV5h->bV5Height = 3; + pbV5h->bV5Planes = 1; + pbV5h->bV5BitCount = 1; + pbV5h->bV5Compression = BI_RGB; + pbV5h->bV5SizeImage = 0; + pbV5h->bV5XPelsPerMeter = 100; + pbV5h->bV5YPelsPerMeter = 100; + pbV5h->bV5ClrUsed = 2; + pbV5h->bV5ClrImportant = 2; + pbV5h->bV5RedMask = 0; + pbV5h->bV5GreenMask = 0; + pbV5h->bV5BlueMask = 0; + pbV5h->bV5AlphaMask = 0; + pbV5h->bV5CSType = 0; + memset(&pbV5h->bV5Endpoints, sizeof(CIEXYZTRIPLE), 0); + pbV5h->bV5GammaRed = 0; + pbV5h->bV5GammaGreen = 0; + pbV5h->bV5GammaBlue = 0; + pbV5h->bV5Intent = 0; + pbV5h->bV5ProfileData = 0; + pbV5h->bV5ProfileSize = 0; + pbV5h->bV5Reserved = 0; + + cEntries = 0; + cjHeader = pbV5h->bV5Size + cEntries * 4 + 8; + + /* Test something simple */ + SetLastError(0); + pvBits = 0; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits != NULL); + TEST(hbmp != 0); + TEST(GetLastError() == 8); + if (hbmp) DeleteObject(hbmp); + + /* increased header size */ + pbV5h->bV5Size = sizeof(BITMAPV5HEADER) + 64; + cjHeader = pbV5h->bV5Size + cEntries * 4 + 8; + SetLastError(0); + pvBits = 0; + hbmp = NtGdiCreateDIBSection(hDC, NULL, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits != NULL); + TEST(hbmp != 0); + TEST(GetLastError() == 8); + if (hbmp) DeleteObject(hbmp); + + /* Test section */ + MaximumSize.QuadPart = 4096; + Status = ZwCreateSection(&hSection, + SECTION_ALL_ACCESS, + NULL, + &MaximumSize, + PAGE_READWRITE, + SEC_COMMIT, + NULL); + ASSERT(NT_SUCCESS(Status)); + + SetLastError(0); + pvBits = 0; + hbmp = NtGdiCreateDIBSection(hDC, hSection, 0, pbmi, 0, cjHeader, 0, 0, &pvBits); + TEST(pvBits != NULL); + TEST(hbmp != 0); +// TEST(GetLastError() == 0); + printf("hbmp = %p, pvBits = %p, hSection = %p\n", hbmp, pvBits, hSection); +//system("PAUSE"); + if (hbmp) DeleteObject(hbmp); + + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiDeleteObjectApp.c b/rostests/apitests/w32knapi/ntgdi/NtGdiDeleteObjectApp.c new file mode 100644 index 00000000000..ef4daa228bd --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiDeleteObjectApp.c @@ -0,0 +1,93 @@ + +INT +Test_NtGdiDeleteObjectApp(PTESTINFO pti) +{ + HDC hdc; + HBITMAP hbmp; + HBRUSH hbrush; + + /* Try to delete 0 */ + SetLastError(0); + TEST(NtGdiDeleteObjectApp(0) == 0); + TEST(GetLastError() == 0); + + /* Try to delete something with a stockbit */ + SetLastError(0); + TEST(NtGdiDeleteObjectApp((PVOID)(GDI_HANDLE_STOCK_MASK | 0x1234)) == 1); + TEST(GetLastError() == 0); + + /* Delete a DC */ + SetLastError(0); + hdc = CreateCompatibleDC(NULL); + ASSERT(IsHandleValid(hdc) == 1); + TEST(NtGdiDeleteObjectApp(hdc) == 1); + TEST(GetLastError() == 0); + TEST(IsHandleValid(hdc) == 0); + + /* Delete a brush */ + SetLastError(0); + hbrush = CreateSolidBrush(0x123456); + ASSERT(IsHandleValid(hbrush) == 1); + TEST(NtGdiDeleteObjectApp(hbrush) == 1); + TEST(GetLastError() == 0); + TEST(IsHandleValid(hbrush) == 0); + + /* Try to delete a stock brush */ + SetLastError(0); + hbrush = GetStockObject(BLACK_BRUSH); + ASSERT(IsHandleValid(hbrush) == 1); + TEST(NtGdiDeleteObjectApp(hbrush) == 1); + TEST(GetLastError() == 0); + TEST(IsHandleValid(hbrush) == 1); + + /* Delete a bitmap */ + SetLastError(0); + hbmp = CreateBitmap(10, 10, 1, 1, NULL); + ASSERT(IsHandleValid(hbmp) == 1); + TEST(NtGdiDeleteObjectApp(hbmp) == 1); + TEST(GetLastError() == 0); + TEST(IsHandleValid(hbmp) == 0); + + /* Create a DC for further use */ + hdc = CreateCompatibleDC(NULL); + ASSERT(hdc); + + /* Try to delete a brush that is selected into a DC */ + SetLastError(0); + hbrush = CreateSolidBrush(0x123456); + ASSERT(IsHandleValid(hbrush) == 1); + TEST(NtGdiSelectBrush(hdc, hbrush)); + TEST(NtGdiDeleteObjectApp(hbrush) == 1); + TEST(GetLastError() == 0); + TEST(IsHandleValid(hbrush) == 1); + + /* Try to delete a bitmap that is selected into a DC */ + SetLastError(0); + hbmp = CreateBitmap(10, 10, 1, 1, NULL); + ASSERT(IsHandleValid(hbmp) == 1); + TEST(NtGdiSelectBitmap(hdc, hbmp)); + + TEST(NtGdiDeleteObjectApp(hbmp) == 1); + TEST(GetLastError() == 0); + TEST(IsHandleValid(hbmp) == 1); + + /* Bitmap get's deleted as soon as we dereference it */ + NtGdiSelectBitmap(hdc, GetStockObject(DEFAULT_BITMAP)); + TEST(IsHandleValid(hbmp) == 0); + + TEST(NtGdiDeleteObjectApp(hbmp) == 1); + TEST(GetLastError() == 0); + TEST(IsHandleValid(hbmp) == 0); + + /* Try to delete a brush that is selected into a DC */ + SetLastError(0); + hbrush = CreateSolidBrush(123); + ASSERT(IsHandleValid(hbrush) == 1); + TEST(NtGdiSelectBrush(hdc, hbrush)); + + TEST(NtGdiDeleteObjectApp(hbrush) == 1); + TEST(GetLastError() == 0); + TEST(IsHandleValid(hbrush) == 1); + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiDoPalette.c b/rostests/apitests/w32knapi/ntgdi/NtGdiDoPalette.c index a172554b9c1..26ee94a848a 100644 --- a/rostests/apitests/w32knapi/ntgdi/NtGdiDoPalette.c +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiDoPalette.c @@ -102,7 +102,8 @@ Test_NtGdiDoPalette_GdiPalAnimate(PTESTINFO pti) INT Test_NtGdiDoPalette_GdiPalSetEntries(PTESTINFO pti) { - HPALETTE hPal; + HDC hDC; + HPALETTE hPal, hOldPal; PALETTEENTRY palEntries[5] = { {0,0,0,0}, {0xff,0xff,0xff,0}, @@ -156,6 +157,13 @@ Test_NtGdiDoPalette_GdiPalSetEntries(PTESTINFO pti) /* Test that the buffer was not changed */ + + /* Test with palette selected into dc */ + hDC = CreateCompatibleDC(NULL); + hOldPal = SelectPalette(hDC, hPal, 0); + RTEST(NtGdiDoPalette(hPal, 0, 4, palEntries, GdiPalSetEntries, TRUE) == 4); + SelectPalette(hDC, hOldPal, 0); + /* Test pEntries = NULL */ RTEST(NtGdiDoPalette(hPal, 0, 1, NULL, GdiPalGetEntries, TRUE) == 0); @@ -198,6 +206,69 @@ Test_NtGdiDoPalette_GetBIBColorTable(PTESTINFO pti) INT Test_NtGdiDoPalette_SetDIBColorTable(PTESTINFO pti) { + HDC hdc; + HBITMAP hbmp; + BYTE *pjBits; + + struct + { + BITMAPINFOHEADER bmiHeader; + ULONG bmiColors[10]; + } bmi; + + hdc = CreateCompatibleDC(0); + ASSERT(hdc); + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = 10; + bmi.bmiHeader.biHeight = 10; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 8; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 1; + bmi.bmiHeader.biYPelsPerMeter = 1; + bmi.bmiHeader.biClrUsed = 9; + bmi.bmiHeader.biClrImportant = 9; + bmi.bmiColors[0] = 0x000000; + bmi.bmiColors[1] = 0x202020; + bmi.bmiColors[2] = 0x404040; + bmi.bmiColors[3] = 0x606060; + bmi.bmiColors[4] = 0x808080; + bmi.bmiColors[5] = 0xA0A0A0; + bmi.bmiColors[6] = 0xC0C0C0; + bmi.bmiColors[7] = 0xE0E0E0; + bmi.bmiColors[8] = 0xffffff; + hbmp = CreateDIBSection(hdc, (BITMAPINFO*)&bmi, DIB_PAL_COLORS, (PVOID*)&pjBits, NULL, 0); + ASSERT(hbmp); + ASSERT(pjBits); + + SelectObject(hdc, hbmp); + + + pjBits[0] = 8; + pjBits[1] = 1; + pjBits[2] = 2; + pjBits[3] = 3; + + bmi.bmiColors[8] = 0x000000; + bmi.bmiColors[7] = 0x202020; + bmi.bmiColors[6] = 0x404040; + bmi.bmiColors[5] = 0x606060; + bmi.bmiColors[4] = 0x808080; + bmi.bmiColors[3] = 0xA0A0A0; + bmi.bmiColors[2] = 0xC0C0C0; + bmi.bmiColors[1] = 0xE0E0E0; + bmi.bmiColors[0] = 0xffffff; + TEST(NtGdiDoPalette(hdc, 0, 9, &bmi.bmiColors, GdiPalSetColorTable, FALSE) == 9); + + SetDCPenColor(hdc, 0xE0E0E0); + SetDCBrushColor(hdc, 0x202020); + Rectangle(hdc, 0, 0, 10, 10); + + DeleteDC(hdc); + DeleteObject(hbmp); + return APISTATUS_NORMAL; } diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiExtTextOutW.c b/rostests/apitests/w32knapi/ntgdi/NtGdiExtTextOutW.c new file mode 100644 index 00000000000..fa38b05436d --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiExtTextOutW.c @@ -0,0 +1,53 @@ + +/* +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) +*/ + +INT +Test_NtGdiExtTextOutW(PTESTINFO pti) +{ + HWND hWnd; + HDC hDC; + RECT rect; + LPWSTR lpstr; + BOOL ret; + ULONG len; + INT Dx[10] = {10, -5, 10, 5, 10, -10, 10, 5, 10, 5}; + + /* Create a window */ + hWnd = CreateWindowW(L"BUTTON", L"TestWindow", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, + NULL, NULL, g_hInstance, 0); + hDC = GetDC(hWnd); + + lpstr = L"Hallo"; + len = wcslen(lpstr); + + ret = NtGdiExtTextOutW(hDC, 0, 0, 0, &rect, lpstr, len, Dx, 0); + TEST(ret == 1); + + ret = NtGdiExtTextOutW(hDC, 0, 0, ETO_PDY, &rect, lpstr, len, Dx, 0); + TEST(ret == 1); + + /* Test invalid lpDx */ + ret = NtGdiExtTextOutW(hDC, 0, 0, 0, 0, lpstr, len, (INT*)((ULONG_PTR)-1), 0); + TEST(ret == 0); + + /* Test alignment requirement for lpDx */ + ret = NtGdiExtTextOutW(hDC, 0, 0, 0, 0, lpstr, len, (INT*)((ULONG_PTR)Dx + 1), 0); + TEST(ret == 1); + + return APISTATUS_NORMAL; +} + diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiFlushUserBatch.c b/rostests/apitests/w32knapi/ntgdi/NtGdiFlushUserBatch.c new file mode 100644 index 00000000000..4f4b5e6f6c7 --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiFlushUserBatch.c @@ -0,0 +1,35 @@ + +INT +Test_NtGdiFlushUserBatch(PTESTINFO pti) +{ + PVOID pRet; + PTEB pTeb; + + pTeb = NtCurrentTeb(); + ASSERT(pTeb); + + pRet = (PVOID)NtGdiFlushUserBatch(); + + TEST(pRet != 0); + TEST(pRet == &pTeb->RealClientId); + + TEST(pTeb->GdiBatchCount == 0); + TEST(pTeb->GdiTebBatch.Offset == 0); + TEST(pTeb->GdiTebBatch.HDC == 0); + + /* Set up some bullshit */ + pTeb->InDbgPrint = 1; + pTeb->GdiBatchCount = 12; + pTeb->GdiTebBatch.Offset = 21; + pTeb->GdiTebBatch.HDC = (HDC)123; + + pRet = (PVOID)NtGdiFlushUserBatch(); + TEST(pRet == &pTeb->RealClientId); + + TEST(pTeb->InDbgPrint == 0); + TEST(pTeb->GdiBatchCount == 12); + TEST(pTeb->GdiTebBatch.Offset == 0); + TEST(pTeb->GdiTebBatch.HDC == 0); + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiGetFontResourceInfoInternalW.c b/rostests/apitests/w32knapi/ntgdi/NtGdiGetFontResourceInfoInternalW.c index 0effcc8b247..ab6dd24fdcb 100644 --- a/rostests/apitests/w32knapi/ntgdi/NtGdiGetFontResourceInfoInternalW.c +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiGetFontResourceInfoInternalW.c @@ -2,18 +2,12 @@ INT Test_NtGdiGetFontResourceInfoInternalW(PTESTINFO pti) { - WCHAR szFullFileName[MAX_PATH+1]; BOOL bRet; DWORD dwBufSize; LOGFONTW logfont; UNICODE_STRING NtFileName; - GetCurrentDirectoryW(MAX_PATH, szFullFileName); - wcscat(szFullFileName, L"\\test.otf"); - - ASSERT(AddFontResourceW(szFullFileName) != 0); - - ASSERT(RtlDosPathNameToNtPathName_U(szFullFileName, + ASSERT(RtlDosPathNameToNtPathName_U(L".\\test.otf", &NtFileName, NULL, NULL)); @@ -36,7 +30,7 @@ Test_NtGdiGetFontResourceInfoInternalW(PTESTINFO pti) printf("lfWidth = %ld\n", logfont.lfWidth); printf("lfFaceName = %ls\n", logfont.lfFaceName); - RemoveFontResourceW(szFullFileName); +// RemoveFontResourceW(szFullFileName); return APISTATUS_NORMAL; } diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiPolyPolyDraw.c b/rostests/apitests/w32knapi/ntgdi/NtGdiPolyPolyDraw.c new file mode 100644 index 00000000000..1b2dbc408a0 --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiPolyPolyDraw.c @@ -0,0 +1,208 @@ + + +static +INT +Test_Params(PTESTINFO pti) +{ + ULONG_PTR ret; + ULONG Count1[4] = {3, 2, 4, 3}; + ULONG Count2[2] = {0, 3}; + ULONG Count3[2] = {0, 0}; + ULONG Count4[2] = {1, 3}; + ULONG Count5[2] = {0x80000001, 0x80000001}; + POINT Points[6] = {{0,0}, {1,1}, {3,-3}, {-2,2}, {4,2}, {2,4}}; + HDC hDC; + + SetLastError(0); + ret = NtGdiPolyPolyDraw(NULL, NULL, NULL, 0, 0); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(NULL, NULL, NULL, 0, 1); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(NULL, NULL, NULL, 0, 2); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(NULL, NULL, NULL, 0, 3); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(NULL, NULL, NULL, 0, 4); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(NULL, NULL, NULL, 0, 5); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(NULL, NULL, NULL, 0, 6); + TEST(ret == 0); + TEST(GetLastError() == 0); + +//////////////////////////////////////////////////////////////////////////////// + + /* Test with an invalid DC */ + + SetLastError(0); + ret = NtGdiPolyPolyDraw(0, Points, Count1, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + hDC = (HDC)0x12345; + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 0); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 2); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 3); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 4); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 5); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 6); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw((HDC)1, Points, Count1, 1, 6); + TEST((ret & GDI_HANDLE_BASETYPE_MASK) == GDI_OBJECT_TYPE_REGION); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw((HDC)0, Points, Count1, 1, 6); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 0, 1); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count2, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, NULL, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, (PVOID)0x81000000, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, NULL, Count1, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, (PVOID)0x81000000, Count1, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == 0); + + +//////////////////////////////////////////////////////////////////////////////// + + /* Test with a valid DC */ + + hDC = CreateCompatibleDC(NULL); + ASSERT(hDC); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 0); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 1); + TEST(ret == 1); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 2); + TEST(ret == 1); + TEST(GetLastError() == 0); + +#if 0 + SetLastError(0); + // better don't do this on win xp!!! (random crashes) +// ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 3); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + SetLastError(0); + // better don't do this on win xp!!! (random crashes) +// ret = NtGdiPolyPolyDraw(hDC, Points, Count1, 2, 4); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + +#endif + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count2, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count3, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == 0); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count4, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + SetLastError(0); + ret = NtGdiPolyPolyDraw(hDC, Points, Count5, 2, 1); + TEST(ret == 0); + TEST(GetLastError() == 87); + + return APISTATUS_NORMAL; +} + + + + +INT +Test_NtGdiPolyPolyDraw(PTESTINFO pti) +{ + Test_Params(pti); + + return APISTATUS_NORMAL; +} + diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiRestoreDC.c b/rostests/apitests/w32knapi/ntgdi/NtGdiRestoreDC.c new file mode 100644 index 00000000000..fd14a50c214 --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiRestoreDC.c @@ -0,0 +1,192 @@ + + +static HBRUSH hbrush; +static HBITMAP hbitmap; +static HPEN hpen; +static HFONT hfont; +static HRGN hrgn, hrgn2; + +static +void +SetSpecialDCState(HDC hdc) +{ + /* Select spcial Objects */ + SelectObject(hdc, hbrush); + SelectObject(hdc, hpen); + SelectObject(hdc, hbitmap); + SelectObject(hdc, hfont); + SelectObject(hdc, hrgn); + + /* Colors */ + SetDCBrushColor(hdc, RGB(12,34,56)); + SetDCPenColor(hdc, RGB(23,34,45)); + + /* Coordinates */ + SetMapMode(hdc, MM_ANISOTROPIC); + SetGraphicsMode(hdc, GM_ADVANCED); + SetWindowOrgEx(hdc, 12, 34, NULL); + SetViewportOrgEx(hdc, 56, 78, NULL); + SetWindowExtEx(hdc, 123, 456, NULL); + SetViewportExtEx(hdc, 234, 567, NULL); + + + +} + +static +void +SetSpecialDCState2(HDC hdc) +{ + /* Select spcial Objects */ + SelectObject(hdc, GetStockObject(DC_BRUSH)); + SelectObject(hdc, GetStockObject(DC_PEN)); + SelectObject(hdc, GetStockObject(DEFAULT_BITMAP)); + SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + SelectObject(hdc, hrgn2); + + /* Colors */ + SetDCBrushColor(hdc, RGB(65,43,21)); + SetDCPenColor(hdc, RGB(54,43,32)); + + /* Coordinates */ + SetMapMode(hdc, MM_ISOTROPIC); + SetGraphicsMode(hdc, GM_COMPATIBLE); + SetWindowOrgEx(hdc, 43, 21, NULL); + SetViewportOrgEx(hdc, 87, 65, NULL); + SetWindowExtEx(hdc, 654, 321, NULL); + SetViewportExtEx(hdc, 765, 432, NULL); + + +} + +static +void +Test_IsSpecialState(PTESTINFO pti, HDC hdc, BOOL bMemDC) +{ + POINT pt; + SIZE sz; + + /* Test Objects */ + TEST(SelectObject(hdc, GetStockObject(DC_BRUSH)) == hbrush); + TEST(SelectObject(hdc, GetStockObject(DC_PEN)) == hpen); + TEST(SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)) == hfont); + if (bMemDC) + { + TEST(SelectObject(hdc, GetStockObject(DEFAULT_BITMAP)) == hbitmap); + TEST(SelectObject(hdc, hrgn2) == (PVOID)1); + } + else + { + TEST(SelectObject(hdc, GetStockObject(DEFAULT_BITMAP)) == 0); + TEST(SelectObject(hdc, hrgn2) == (PVOID)2); + } + + /* Test colors */ + TEST(GetDCBrushColor(hdc) == RGB(12,34,56)); + TEST(GetDCPenColor(hdc) == RGB(23,34,45)); + + /* Test coordinates */ + TEST(GetMapMode(hdc) == MM_ANISOTROPIC); + TEST(GetGraphicsMode(hdc) == GM_ADVANCED); + GetWindowOrgEx(hdc, &pt); + TEST(pt.x == 12); + TEST(pt.y == 34); + GetViewportOrgEx(hdc, &pt); + TEST(pt.x == 56); + TEST(pt.y == 78); + GetWindowExtEx(hdc, &sz); + TESTX(sz.cx == 123, "sz.cx == %ld\n", sz.cx); + TESTX(sz.cy == 456, "sz.cy == %ld\n", sz.cy); + GetViewportExtEx(hdc, &sz); + TEST(sz.cx == 234); + TEST(sz.cy == 567); + + +} + + +static +void +Test_SaveRestore(PTESTINFO pti, HDC hdc, BOOL bMemDC) +{ + SetSpecialDCState(hdc); + NtGdiSaveDC(hdc); + SetSpecialDCState2(hdc); + + SetLastError(0); + TEST(NtGdiRestoreDC(hdc, 2) == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + SetLastError(0); + TEST(NtGdiRestoreDC(hdc, 0) == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + SetLastError(0); + TEST(NtGdiRestoreDC(hdc, -2) == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + SetLastError(0); + TEST(NtGdiRestoreDC(hdc, 1) == 1); + TEST(GetLastError() == 0); + + Test_IsSpecialState(pti, hdc, bMemDC); +} + + +INT +Test_NtGdiRestoreDC(PTESTINFO pti) +{ + HDC hdc; + + hdc = CreateCompatibleDC(0); + ASSERT(IsHandleValid(hdc)); + + SetLastError(0); + TEST(NtGdiRestoreDC(0, -10) == 0); + TEST(GetLastError() == ERROR_INVALID_HANDLE); + + SetLastError(0); + TEST(NtGdiRestoreDC(hdc, 0) == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + SetLastError(0); + TEST(NtGdiRestoreDC(hdc, 1) == 0); + TEST(GetLastError() == ERROR_INVALID_PARAMETER); + + /* Initialize objects */ + hbrush = CreateSolidBrush(12345); + ASSERT(IsHandleValid(hbrush)); + hpen = CreatePen(PS_SOLID, 4, RGB(10,12,32)); + ASSERT(IsHandleValid(hpen)); + hbitmap = CreateBitmap(10, 10, 1, 1, NULL); + ASSERT(IsHandleValid(hbitmap)); + hfont = CreateFont(10, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + DEFAULT_PITCH, "Arial"); + ASSERT(IsHandleValid(hfont)); + hrgn = CreateRectRgn(12, 14, 14, 17); + ASSERT(IsHandleValid(hrgn)); + hrgn2 = CreateRectRgn(1, 1, 2, 2); + ASSERT(IsHandleValid(hrgn2)); + + /* Test mem dc */ + Test_SaveRestore(pti, hdc, TRUE); + DeleteDC(hdc); + + /* Test screen DC */ + hdc = GetDC(0); + ASSERT(IsHandleValid(hdc)); + Test_SaveRestore(pti, hdc, FALSE); + ReleaseDC(0, hdc); + + /* Test info dc */ + hdc = CreateICW(L"DISPLAY", NULL, NULL, NULL); + ASSERT(IsHandleValid(hdc)); + Test_SaveRestore(pti, hdc, FALSE); + DeleteDC(hdc); + + + + return APISTATUS_NORMAL; +} + diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiSaveDC.c b/rostests/apitests/w32knapi/ntgdi/NtGdiSaveDC.c new file mode 100644 index 00000000000..2c27851f52c --- /dev/null +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiSaveDC.c @@ -0,0 +1,45 @@ + +INT +Test_NtGdiSaveDC(PTESTINFO pti) +{ + HDC hdc; + HWND hwnd; + + /* Test 0 hdc */ + TEST(NtGdiSaveDC(0) == 0); + + /* Test info dc */ + hdc = CreateICW(L"DISPLAY",NULL,NULL,NULL); + TEST(hdc); + TEST(NtGdiSaveDC(hdc) == 1); + TEST(NtGdiSaveDC(hdc) == 2); + DeleteDC(hdc); + + /* Test display dc */ + hdc = GetDC(0); + TEST(hdc); + TEST(NtGdiSaveDC(hdc) == 1); + TEST(NtGdiSaveDC(hdc) == 2); + ReleaseDC(0, hdc); + + /* Test a mem DC */ + hdc = CreateCompatibleDC(0); + TEST(hdc); + TEST(NtGdiSaveDC(hdc) == 1); + TEST(NtGdiSaveDC(hdc) == 2); + DeleteDC(hdc); + + /* Create a window */ + hwnd = CreateWindowW(L"BUTTON", L"TestWindow", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 10, 10, 100, 100, + NULL, NULL, g_hInstance, 0); + hdc = GetDC(hwnd); + TEST(hdc); + TEST(NtGdiSaveDC(hdc) == 1); + NtGdiRestoreDC(hdc, 1); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + + return APISTATUS_NORMAL; +} + diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiSelectBitmap.c b/rostests/apitests/w32knapi/ntgdi/NtGdiSelectBitmap.c index 2e99071dcf7..c45243e50e2 100644 --- a/rostests/apitests/w32knapi/ntgdi/NtGdiSelectBitmap.c +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiSelectBitmap.c @@ -1,13 +1,65 @@ + +INT +Test_SelectDIBSection(PTESTINFO pti) +{ + HDC hdc; + HBITMAP hbmp; + struct + { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[100]; + } bmi; + PBITMAPINFO pbmi = (PBITMAPINFO)&bmi; + PVOID pvBits; + + hdc = CreateCompatibleDC(0); + ASSERT(hdc); + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = 2; + bmi.bmiHeader.biHeight = 2; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 100; + bmi.bmiHeader.biYPelsPerMeter = 100; + bmi.bmiHeader.biClrUsed = 2; + bmi.bmiHeader.biClrImportant = 2; + + hbmp = CreateDIBSection(hdc, pbmi, DIB_PAL_COLORS, &pvBits, NULL, 0); + ASSERT(hbmp); + + TEST(NtGdiSelectBitmap(hdc, hbmp) != 0); + + return 0; +} + + INT Test_NtGdiSelectBitmap(PTESTINFO pti) { HDC hDC; HBITMAP hBmp, hOldBmp; + HPALETTE hOldPalette, hPalette; + LOGPALETTE logpal = {0x300, 1, {{12,13,14,15}}}; + + hBmp = CreateBitmap(2,2,1,1,NULL); + ASSERT(hBmp); + + /* We cannot select a bitmap into a display DC */ + hDC = GetDC(NULL); + ASSERT(hDC); + hOldBmp = NtGdiSelectBitmap(hDC, hBmp); + TEST(hOldBmp == NULL); hDC = CreateCompatibleDC(GetDC(NULL)); ASSERT(hDC); - hBmp = CreateBitmap(2,2,1,1,NULL); + /* Check the palette before we mess it up*/ + hPalette = CreatePalette(&logpal); + hOldPalette = SelectPalette(hDC, hPalette, 0); + TEST(hOldPalette == GetStockObject(DEFAULT_PALETTE)); /* Test NULL DC */ SetLastError(ERROR_SUCCESS); @@ -27,23 +79,35 @@ Test_NtGdiSelectBitmap(PTESTINFO pti) TEST(hOldBmp == NULL); TEST(GetLastError() == ERROR_SUCCESS); - /* Test NULL bitmap */ + /* Test bitmap with only index */ SetLastError(ERROR_SUCCESS); hOldBmp = NtGdiSelectBitmap(hDC, (HBITMAP)((ULONG_PTR)hBmp & 0x0000ffff)); TEST(hOldBmp == NULL); TEST(GetLastError() == ERROR_SUCCESS); - /* Test invalid bitmap */ + /* Test valid bitmap */ SetLastError(ERROR_SUCCESS); hOldBmp = NtGdiSelectBitmap(hDC, hBmp); TEST(hOldBmp != NULL); + /* The default bitmap should be GetStockObject(21) */ + TEST(hOldBmp == GetStockObject(21)); + + /* Check the palette */ + hOldPalette = SelectPalette(hDC, hOldPalette, 0); + TEST(hOldPalette == hPalette); + DeleteObject(hPalette); + + /* Select the old one again and check */ hOldBmp = NtGdiSelectBitmap(hDC, hOldBmp); TEST(hOldBmp == hBmp); TEST(GetLastError() == ERROR_SUCCESS); + /* cleanup */ DeleteObject(hBmp); DeleteDC(hDC); + Test_SelectDIBSection(pti); + return APISTATUS_NORMAL; } diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiSelectBrush.c b/rostests/apitests/w32knapi/ntgdi/NtGdiSelectBrush.c index d332e9af39f..ba39232165f 100644 --- a/rostests/apitests/w32knapi/ntgdi/NtGdiSelectBrush.c +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiSelectBrush.c @@ -3,6 +3,7 @@ Test_NtGdiSelectBrush(PTESTINFO pti) { HDC hDC; HBRUSH hBrush, hOldBrush; + DC_ATTR *pdcattr; hDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL); @@ -39,6 +40,25 @@ Test_NtGdiSelectBrush(PTESTINFO pti) TEST(hOldBrush == hBrush); TEST(GetLastError() == ERROR_SUCCESS); + /* Begin with a white brush */ + NtGdiSelectBrush(hDC, GetStockObject(WHITE_BRUSH)); + /* Select a brush in user mode */ + SelectObject(hDC, GetStockObject(BLACK_BRUSH)); + /* See what we get returned */ + hOldBrush = NtGdiSelectBrush(hDC, GetStockObject(WHITE_BRUSH)); + TEST(hOldBrush == GetStockObject(BLACK_BRUSH)); + + + /* Begin with a white brush */ + NtGdiSelectBrush(hDC, GetStockObject(WHITE_BRUSH)); + + pdcattr = GetHandleUserData(hDC); + /* Change the brush in user mode, without setting flags */ + pdcattr->hbrush = (HBRUSH)12345; + + hOldBrush = NtGdiSelectBrush(hDC, GetStockObject(BLACK_BRUSH)); + TEST(hOldBrush == (HBRUSH)12345); + DeleteDC(hDC); diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiSelectPen.c b/rostests/apitests/w32knapi/ntgdi/NtGdiSelectPen.c index 7731dc62b32..e9f67134549 100644 --- a/rostests/apitests/w32knapi/ntgdi/NtGdiSelectPen.c +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiSelectPen.c @@ -3,8 +3,10 @@ Test_NtGdiSelectPen(PTESTINFO pti) { HDC hDC; HPEN hPen, hOldPen; + LOGBRUSH logbrush; - hDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL); + hDC = GetDC(NULL); + ASSERT(hDC); hPen = GetStockObject(WHITE_PEN); @@ -26,19 +28,42 @@ Test_NtGdiSelectPen(PTESTINFO pti) TEST(hOldPen == NULL); TEST(GetLastError() == ERROR_SUCCESS); - /* Test NULL pen */ + /* Test invalid pen */ SetLastError(ERROR_SUCCESS); hOldPen = NtGdiSelectPen(hDC, (HPEN)((ULONG_PTR)hPen & 0x0000ffff)); TEST(hOldPen == NULL); TEST(GetLastError() == ERROR_SUCCESS); + /* Test valid pen */ + SelectObject(hDC, GetStockObject(BLACK_PEN)); SetLastError(ERROR_SUCCESS); hOldPen = NtGdiSelectPen(hDC, hPen); + TEST(hOldPen == GetStockObject(BLACK_PEN)); + hOldPen = NtGdiSelectPen(hDC, hOldPen); + TEST(hOldPen == hPen); + TEST(GetLastError() == ERROR_SUCCESS); + + /* Test extpen */ + SetLastError(ERROR_SUCCESS); + logbrush.lbStyle = BS_SOLID; + logbrush.lbColor = RGB(0x12,0x34,0x56); + hPen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &logbrush, 0, NULL); + ASSERT(hPen); + hOldPen = NtGdiSelectPen(hDC, hPen); TEST(hOldPen != NULL); hOldPen = NtGdiSelectPen(hDC, hOldPen); TEST(hOldPen == hPen); TEST(GetLastError() == ERROR_SUCCESS); + /* Test deleting pen */ + SetLastError(ERROR_SUCCESS); + hOldPen = NtGdiSelectPen(hDC, hPen); + TEST(DeleteObject(hPen) == 1); + hOldPen = NtGdiSelectPen(hDC, hOldPen); + TEST(hOldPen == hPen); + TEST(GetLastError() == ERROR_SUCCESS); + + /* Test that fallback pen is BLACK_PEN */ DeleteDC(hDC); diff --git a/rostests/apitests/w32knapi/ntgdi/NtGdiSetDIBitsToDeviceInternal.c b/rostests/apitests/w32knapi/ntgdi/NtGdiSetDIBitsToDeviceInternal.c index e172815437e..7ba68af96a2 100644 --- a/rostests/apitests/w32knapi/ntgdi/NtGdiSetDIBitsToDeviceInternal.c +++ b/rostests/apitests/w32knapi/ntgdi/NtGdiSetDIBitsToDeviceInternal.c @@ -1,8 +1,25 @@ + +void +ReadBits(HDC hDC, PDWORD OutBits) +{ + int x,y; + + for (y = 0; y < 8; y++) + { + DWORD Row = 0; + for (x = 0; x < 8; x++) + Row |= (0x80 & GetPixel(hDC, 2 + x, 3 + y)) >> x; + OutBits[y] = Row; + } +} + + INT Test_NtGdiSetDIBitsToDeviceInternal(PTESTINFO pti) { static const DWORD InBits[8] = { 0x81, 0x7E, 0x5A, 0x7E, 0x7E, 0x42, 0x7E, 0x81 }; DWORD OutBits[8]; + XFORM xform; HWND hWnd = CreateWindowW(L"Static", NULL, WS_VISIBLE, 100, 100, 200, 200, @@ -35,6 +52,27 @@ Test_NtGdiSetDIBitsToDeviceInternal(PTESTINFO pti) (PVOID)InBits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS, sizeof(InBits), sizeof(bmi), TRUE, NULL)); + /* Now get the data from the screen, and see if it matches */ + ReadBits(hDC, OutBits); + + TEST(memcmp(InBits, OutBits, sizeof(InBits)) == 0); + + /* Change transformation */ + GetWorldTransform(hDC, &xform); + xform.eM11 = 2; + xform.eM22 = 2; + xform.eDx = 10; + SetWorldTransform(hDC, &xform); + + TEST(NtGdiSetDIBitsToDeviceInternal(hDC, 2, 3, 8, 8, 0, 0, 0, 8, + (PVOID)InBits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS, + sizeof(InBits), sizeof(bmi), TRUE, NULL)); + + xform.eM11 = 1; + xform.eM22 = 1; + xform.eDx = 0; + SetWorldTransform(hDC, &xform); + /* Now get the data from the screen, and see if it matches */ for (y = 0; y < 8; y++) { @@ -43,8 +81,10 @@ Test_NtGdiSetDIBitsToDeviceInternal(PTESTINFO pti) Row |= (0x80 & GetPixel(hDC, 2 + x, 3 + y)) >> x; OutBits[y] = Row; } + TEST(memcmp(InBits, OutBits, sizeof(InBits)) == 0); + ReleaseDC(hWnd, hDC); DestroyWindow(hWnd); diff --git a/rostests/apitests/w32knapi/ntuser/NtUserCallOneParam.c b/rostests/apitests/w32knapi/ntuser/NtUserCallOneParam.c index 2e62315750b..72b83a07901 100644 --- a/rostests/apitests/w32knapi/ntuser/NtUserCallOneParam.c +++ b/rostests/apitests/w32knapi/ntuser/NtUserCallOneParam.c @@ -39,6 +39,7 @@ Test_OneParamRoutine_MapDesktopObject(PTESTINFO pti) /* 0x30 */ hMenu = CreateMenu(); pObject = NtUserCallOneParam((DWORD)hMenu, _ONEPARAM_ROUTINE_MAPDEKTOPOBJECT); + DestroyMenu(hMenu); TEST(pObject > 0); TEST(pObject < 0x80000000); diff --git a/rostests/apitests/w32knapi/ntuser/NtUserCountClipboardFormats.c b/rostests/apitests/w32knapi/ntuser/NtUserCountClipboardFormats.c index 98a45a44af4..7a51f87e940 100644 --- a/rostests/apitests/w32knapi/ntuser/NtUserCountClipboardFormats.c +++ b/rostests/apitests/w32knapi/ntuser/NtUserCountClipboardFormats.c @@ -1,5 +1,5 @@ /* First the call stub */ -DWORD STDCALL +DWORD WINAPI NtUserCountClipboardFormats(VOID) { DWORD p; diff --git a/rostests/apitests/w32knapi/ntuser/NtUserEnumDisplayMonitors.c b/rostests/apitests/w32knapi/ntuser/NtUserEnumDisplayMonitors.c new file mode 100644 index 00000000000..a250621d860 --- /dev/null +++ b/rostests/apitests/w32knapi/ntuser/NtUserEnumDisplayMonitors.c @@ -0,0 +1,52 @@ + +ULONG gMonitorCount = 0; +HDC ghdcMonitor = 0; +RECT grcMonitor = {0}; + +BOOL +NTAPI +NtUserEnumDisplayMonitors1( + HDC hDC, + LPCRECT lprcClip, + MONITORENUMPROC lpfnEnum, + LPARAM dwData) +{ + return (INT)Syscall(L"NtUserEnumDisplayMonitors", 4, &hDC); +} + +BOOL CALLBACK +MonitorEnumProc( + HMONITOR hMonitor, + HDC hdcMonitor, + LPRECT lprcMonitor, + LPARAM dwData) +{ + gMonitorCount++; + if (gMonitorCount == 1) + { + ghdcMonitor = hdcMonitor; + grcMonitor = *lprcMonitor; + } + return TRUE; +} + +INT +Test_NtUserEnumDisplayMonitors(PTESTINFO pti) +{ + BOOL ret; + + // WILL crash! +// TEST(NtUserEnumDisplayMonitors1(NULL, NULL, NULL, 0) == 0); + + ret = NtUserEnumDisplayMonitors1(0, NULL, MonitorEnumProc, 0); + TEST(ret == TRUE); + TEST(gMonitorCount > 0); + TEST(ghdcMonitor == 0); + TEST(grcMonitor.left == 0); + TEST(grcMonitor.right > 0); + TEST(grcMonitor.top == 0); + TEST(grcMonitor.bottom > 0); + + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/ntuser/NtUserGetClassInfo.c b/rostests/apitests/w32knapi/ntuser/NtUserGetClassInfo.c new file mode 100644 index 00000000000..11dad25c9ff --- /dev/null +++ b/rostests/apitests/w32knapi/ntuser/NtUserGetClassInfo.c @@ -0,0 +1,58 @@ +BOOL +NTAPI +NtUserGetClassInfo2( + HINSTANCE hInstance, + PUNICODE_STRING ClassName, + LPWNDCLASSEXW wcex, + LPWSTR *ppwstr, + BOOL Ansi) +{ + return (BOOL)Syscall(L"NtUserGetClassInfo", 5, &hInstance); +} + +INT +Test_NtUserGetClassInfo(PTESTINFO pti) +{ + WNDCLASSEXW wclex, wclex2 = {0}; + UNICODE_STRING us; + PWSTR pwstr; + + us.Length = 8; + us.MaximumLength = 8; + us.Buffer = L"test"; + + wclex.cbSize = sizeof(WNDCLASSEXW); + wclex.style = 0; + wclex.lpfnWndProc = NULL; + wclex.cbClsExtra = 2; + wclex.cbWndExtra = 4; + wclex.hInstance = g_hInstance; + wclex.hIcon = NULL; + wclex.hCursor = NULL; + wclex.hbrBackground = CreateSolidBrush(RGB(4,7,5)); + wclex.lpszMenuName = L"MyMenu"; + wclex.lpszClassName = us.Buffer; + wclex.hIconSm = NULL; + + ASSERT(RegisterClassExW(&wclex) != 0); + + TEST(GetClassInfoExW(g_hInstance, us.Buffer, &wclex) != 0); + wclex2.cbSize = sizeof(WNDCLASSEXW); + TEST(NtUserGetClassInfo2(g_hInstance, &us, &wclex2, &pwstr, 0) != 0); + + TEST(pwstr == wclex.lpszMenuName); + TEST(wclex2.cbSize == wclex.cbSize); + TEST(wclex2.style == wclex.style); + TEST(wclex2.lpfnWndProc == wclex.lpfnWndProc); + TEST(wclex2.cbClsExtra == wclex.cbClsExtra); + TEST(wclex2.cbWndExtra == wclex.cbWndExtra); + TEST(wclex2.hInstance == wclex.hInstance); + TEST(wclex2.hIcon == wclex.hIcon); + TEST(wclex2.hCursor == wclex.hCursor); + TEST(wclex2.hbrBackground == wclex.hbrBackground); + TEST(wclex2.lpszMenuName == 0); + TEST(wclex2.lpszClassName == 0); + TEST(wclex2.hIconSm == wclex.hIconSm); + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/ntuser/NtUserProcessConnect.c b/rostests/apitests/w32knapi/ntuser/NtUserProcessConnect.c new file mode 100644 index 00000000000..c870fd64907 --- /dev/null +++ b/rostests/apitests/w32knapi/ntuser/NtUserProcessConnect.c @@ -0,0 +1,24 @@ + +INT +Test_NtUserProcessConnect(PTESTINFO pti) +{ + HANDLE hProcess; + NTSTATUS Status; + USERCONNECT UserConnect = {0}; + + hProcess = GetCurrentProcess(); + + UserConnect.ulVersion = MAKELONG(0, 5); + Status = NtUserProcessConnect(hProcess, (USERCONNECT*)&UserConnect, sizeof(USERCONNECT)); + TEST(NT_SUCCESS(Status)); + + printf("UserConnect.ulVersion = 0x%lx\n", UserConnect.ulVersion); + printf("UserConnect.ulCurrentVersion = 0x%lx\n", UserConnect.ulCurrentVersion); + printf("UserConnect.dwDispatchCount = 0x%lx\n", UserConnect.dwDispatchCount); + printf("UserConnect.siClient.psi = 0x%p\n", UserConnect.siClient.psi); + printf("UserConnect.siClient.aheList = 0x%p\n", UserConnect.siClient.aheList); + printf("UserConnect.siClient.pDispInfo = 0x%p\n", UserConnect.siClient.pDispInfo); + printf("UserConnect.siClient.ulSharedDelta = 0x%lx\n", UserConnect.siClient.ulSharedDelta); + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/ntuser/NtUserSelectPalette.c b/rostests/apitests/w32knapi/ntuser/NtUserSelectPalette.c new file mode 100644 index 00000000000..dac693c39a0 --- /dev/null +++ b/rostests/apitests/w32knapi/ntuser/NtUserSelectPalette.c @@ -0,0 +1,148 @@ + + +FORCEINLINE +PALETTEENTRY +PALENTRY(BYTE r, BYTE g, BYTE b) +{ + PALETTEENTRY ret; + + ret.peRed = r; + ret.peGreen = g; + ret.peBlue = b; + ret.peFlags = 0; + return ret; +} + +INT +Test_NtUserSelectPalette(PTESTINFO pti) +{ + HPALETTE hPal, hOldPal; + HWND hWnd; + HDC hDC, hCompDC; + struct + { + LOGPALETTE logpal; + PALETTEENTRY entry[20]; + } pal; + + ZeroMemory(&pal, sizeof(pal)); + + pal.logpal.palVersion = 0x300; + pal.logpal.palNumEntries = 6; + pal.entry[0] = PALENTRY(0,0,0); + pal.entry[1] = PALENTRY(255,255,255); + pal.entry[2] = PALENTRY(128,128,128); + pal.entry[3] = PALENTRY(128,0,0); + pal.entry[4] = PALENTRY(0,128,0); + pal.entry[5] = PALENTRY(0,0,128); + + hPal = CreatePalette(&pal.logpal); + ASSERT(hPal); + TEST(DeletePalette(hPal) == 1); + hPal = CreatePalette(&pal.logpal); + ASSERT(hPal); + + /* Create a window */ + hWnd = CreateWindowW(L"BUTTON", L"TestWindow", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, + NULL, NULL, g_hInstance, 0); + hDC = GetDC(hWnd); + ASSERT(hDC); + hCompDC = CreateCompatibleDC(hDC); + ASSERT(hCompDC); + + /* Test NULL DC */ + SetLastError(ERROR_SUCCESS); + hOldPal = NtUserSelectPalette(NULL, hPal, 0); + TEST(hOldPal == 0); + TEST(GetLastError() == ERROR_SUCCESS); + + /* Test invalid DC */ + SetLastError(ERROR_SUCCESS); + hOldPal = NtUserSelectPalette((HDC)-1, hPal, 0); + TEST(hOldPal == 0); + TEST(GetLastError() == ERROR_SUCCESS); + + /* Test NULL palette */ + SetLastError(ERROR_SUCCESS); + hOldPal = NtUserSelectPalette(hDC, NULL, 0); + TEST(hOldPal == 0); + TEST(GetLastError() == ERROR_SUCCESS); + + /* Test invalid palette */ + SetLastError(ERROR_SUCCESS); + hOldPal = NtUserSelectPalette(hDC, (HPALETTE)-1, 0); + TEST(hOldPal == 0); + TEST(GetLastError() == ERROR_SUCCESS); + + /* Test valid palette */ + hOldPal = NtUserSelectPalette(hDC, hPal, 0); + TEST(hOldPal != 0); + TEST(hOldPal == GetStockObject(DEFAULT_PALETTE)); + + /* We cannot Delete the palette */ + TEST(DeletePalette(hPal) == 0); + + /* We can still select the Palette into a compatible DC */ + hOldPal = NtUserSelectPalette(hCompDC, hPal, 0); + TEST(hOldPal != 0); + + + +#if 0 + RealizePalette(hDC); + + GetClientRect(hWnd, &rect); + FillRect(hDC, &rect, GetSysColorBrush(COLOR_BTNSHADOW)); + + TEST(GetNearestColor(hDC, RGB(0,0,0)) == RGB(0,0,0)); + TEST(GetNearestColor(hDC, RGB(0,0,1)) == RGB(0,0,1)); + + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + RECT rect; + HBITMAP hBmp; + + + BITMAPINFOHEADER bmih = {sizeof(BITMAPINFOHEADER), // biSize + 3, // biWidth + 3, // biHeight + 1, // biPlanes + 8, // biBitCount + BI_RGB, // biCompression + 0, // biSizeImage + 92, // biXPelsPerMeter + 92, // biYPelsPerMeter + 6, // biClrUsed + 6}; // biClrImportant + BYTE bits[3][3] = {{0,1,2},{3,4,5},{6,1,2}}; + + struct + { + BITMAPINFOHEADER bmih; + RGBQUAD colors[6]; + } bmi = {{sizeof(BITMAPINFOHEADER),3,3,1,8,BI_RGB,0,92,92,6,6}, + {{0,0,0,0},{255,255,255,0},{255,0,0,0}, + {0,255,0,0},{0,0,255,0},{128,128,128,0}}}; + + hBmp = CreateDIBitmap(hCompDC, &bmih, CBM_INIT, &bits, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); + ASSERT(hBmp); + + SetLastError(0); + TEST(NtGdiSelectBitmap(hCompDC, hBmp)); + hOldPal = NtUserSelectPalette(hCompDC, hPal, 0); + TEST(hOldPal != NULL); + RealizePalette(hCompDC); + + TEST(GetNearestColor(hCompDC, RGB(0,0,0)) == RGB(0,0,0)); + TEST(GetNearestColor(hCompDC, RGB(0,0,1)) == RGB(0,0,0)); + TEST(GetNearestColor(hCompDC, RGB(100,0,0)) == RGB(0,0,0)); + TEST(GetNearestColor(hCompDC, RGB(250,250,250)) == RGB(255,255,255)); + TEST(GetNearestColor(hCompDC, RGB(120,100,110)) == RGB(128,128,128)); + +printf("nearest = 0x%x\n", GetNearestColor(hCompDC, RGB(120,100,110))); +#endif + + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/ntuser/NtUserSetTimer.c b/rostests/apitests/w32knapi/ntuser/NtUserSetTimer.c new file mode 100644 index 00000000000..380257947db --- /dev/null +++ b/rostests/apitests/w32knapi/ntuser/NtUserSetTimer.c @@ -0,0 +1,15 @@ + + + +INT +Test_NtUserSetTimer(PTESTINFO pti) +{ + + + // check valid argument + // check for replacement / new timers + // check when expiries are handled (msgs and calls) + + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/ntuser/NtUserSystemParametersInfo.c b/rostests/apitests/w32knapi/ntuser/NtUserSystemParametersInfo.c index 03c7af6350f..dd429b17995 100644 --- a/rostests/apitests/w32knapi/ntuser/NtUserSystemParametersInfo.c +++ b/rostests/apitests/w32knapi/ntuser/NtUserSystemParametersInfo.c @@ -1,6 +1,69 @@ +static const WCHAR* KEY_MOUSE = L"Control Panel\\Mouse"; +//static const WCHAR* VAL_MOUSE1 = L"MouseThreshold1"; +//static const WCHAR* VAL_MOUSE2 = L"MouseThreshold2"; +//static const WCHAR* VAL_MOUSE3 = L"MouseSpeed"; +//static const WCHAR* VAL_DBLCLKWIDTH = L"DoubleClickWidth"; +//static const WCHAR* VAL_DBLCLKHEIGHT = L"DoubleClickHeight"; +//static const WCHAR* VAL_DBLCLKTIME = L"DoubleClickSpeed"; +static const WCHAR* VAL_SWAP = L"SwapMouseButtons"; + +static const WCHAR* KEY_DESKTOP = L"Control Panel\\Desktop"; +//static const WCHAR* VAL_SCRTO = L"ScreenSaveTimeOut"; +//static const WCHAR* VAL_SCRACT = L"ScreenSaveActive"; +//static const WCHAR* VAL_GRID = L"GridGranularity"; +//static const WCHAR* VAL_DRAG = L"DragFullWindows"; +//static const WCHAR* VAL_DRAGHEIGHT = L"DragHeight"; +//static const WCHAR* VAL_DRAGWIDTH = L"DragWidth"; +//static const WCHAR* VAL_FNTSMOOTH = L"FontSmoothing"; +static const WCHAR* VAL_PREFMASK = L"UserPreferencesMask"; + +enum +{ + UPM_ACTIVEWINDOWTRACKING = 0x01, + UPM_MENUANIMATION = 0x02, + UPM_COMBOBOXANIMATION = 0x04, + UPM_LISTBOXSMOOTHSCROLLING = 0x08, + UPM_GRADIENTCAPTIONS = 0x10, + UPM_KEYBOARDCUES = 0x20, + UPM_ACTIVEWNDTRKZORDER = 0x40, + UPM_HOTTRACKING = 0x80, + UPM_RESERVED = 0x100, + UPM_MENUFADE = 0x200, + UPM_SELECTIONFADE = 0x400, + UPM_TOOLTIPANIMATION = 0x800, + UPM_TOOLTIPFADE = 0x1000, + UPM_CURSORSHADOW = 0x2000, + UPM_CLICKLOCK = 0x8000, + // room for more + UPM_UIEFFECTS = 0x80000000, + UPM_DEFAULT = 0x80003E9E +} USERPREFMASKS; + + +//static const WCHAR* KEY_MDALIGN = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"; +//static const WCHAR* VAL_MDALIGN = L"MenuDropAlignment"; + +static const WCHAR* KEY_METRIC = L"Control Panel\\Desktop\\WindowMetrics"; +//static const WCHAR* VAL_BORDER = L"BorderWidth"; +//static const WCHAR* VAL_ICONSPC = L"IconSpacing"; +//static const WCHAR* VAL_ICONVSPC = L"IconVerticalspacing"; +//static const WCHAR* VAL_ITWRAP = L"IconTitleWrap"; + +static const WCHAR* KEY_SOUND = L"Control Panel\\Sound"; +static const WCHAR* VAL_BEEP = L"Beep"; + +//static const WCHAR* KEY_KBD = L"Control Panel\\Keyboard"; +//static const WCHAR* VAL_KBDSPD = L"KeyboardSpeed"; +//static const WCHAR* VAL_KBDDELAY = L"KeyboardDelay"; + +//static const WCHAR* KEY_SHOWSNDS = L"Control Panel\\Accessibility\\ShowSounds"; +//static const WCHAR* KEY_KDBPREF = L"Control Panel\\Accessibility\\Keyboard Preference"; +//static const WCHAR* KEY_SCRREAD = L"Control Panel\\Accessibility\\Blind Access"; +//static const WCHAR* VAL_ON = L"On"; + LONG -QueryUserRegValueW(LPWSTR pszSubKey, LPWSTR pszValueName, PVOID pData, LPDWORD cbSize, LPDWORD pType) +QueryUserRegValueW(PCWSTR pszSubKey, PCWSTR pszValueName, PVOID pData, LPDWORD cbSize, LPDWORD pType) { HKEY hKey; LONG ret; @@ -40,24 +103,6 @@ CreateTestWindow() NULL, g_hInstance, 0); - -} - -void -Test_SPI_87_88(PTESTINFO pti) -{ - DWORD dwRet = 0xdeadbeef; - - TEST(NtUserSystemParametersInfo(87, 0, &dwRet, 0) == TRUE); - TEST(dwRet == 0xdeadbeef); - dwRet++; - TEST(NtUserSystemParametersInfo(87, 0, &dwRet, 0) == TRUE); - - - dwRet--; - TEST(NtUserSystemParametersInfo(87, 0, &dwRet, 0) == TRUE); - - } void @@ -66,7 +111,7 @@ Test_NtUserSystemParametersInfo_Params(PTESTINFO pti) // UINT uint; DWORD data[1000]; UINT i, uint; -#if 1 + ACCESSTIMEOUT ato; /* Test normal */ SetLastError(ERROR_SUCCESS); TEST(NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &uint, 0) == TRUE); @@ -78,47 +123,46 @@ Test_NtUserSystemParametersInfo_Params(PTESTINFO pti) TEST(GetLastError() == ERROR_INVALID_PARAMETER); /* Test wrong cbSize member */ - ACCESSTIMEOUT ato; ato.cbSize = 1; - SetLastError(ERROR_SUCCESS); + SetLastError(0xdeadbeef); TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, 0, &ato, 0) == FALSE); - TEST(GetLastError() == ERROR_SUCCESS); -#endif + TEST(GetLastError() == 0xdeadbeef); +#if 0 /* Test undocumented, but valid SPI codes */ for(i = 0; i < 1000; i++) data[i] = 0xdeadbeef; SetLastError(ERROR_SUCCESS); - TEST(NtUserSystemParametersInfo(4112, 0, &data, 0) == TRUE); + TEST(NtUserSystemParametersInfo(0x1010, 0, &data, 0) == TRUE); TEST(GetLastError() == ERROR_SUCCESS); TEST(data[0] <= 1); TEST(data[1] == 0xdeadbeef); for(i = 0; i < 1000; i++) data[i] = 0xbeefdead; SetLastError(ERROR_SUCCESS); - TEST(NtUserSystemParametersInfo(4113, 0, &data, 0) == TRUE); + TEST(NtUserSystemParametersInfo(0x1011, 0, &data, 0) == TRUE); TEST(GetLastError() == ERROR_SUCCESS); TEST(data[0] == 0xbeefdead); TEST(data[1] == 0xbeefdead); data[0] = 0; - NtUserSystemParametersInfo(4112, 0, &data, 0); + NtUserSystemParametersInfo(0x1010, 0, &data, 0); TEST(data[0] == 1); for(i = 0; i < 1000; i++) data[i] = 0xdeadbeef; SetLastError(ERROR_SUCCESS); - TEST(NtUserSystemParametersInfo(4136, 0, &data, 0) == TRUE); + TEST(NtUserSystemParametersInfo(0x1028, 0, &data, 0) == TRUE); TEST(GetLastError() == ERROR_SUCCESS); TEST(data[0] != 0xdeadbeef); TEST(data[1] == 0xdeadbeef); for(i = 0; i < 1000; i++) data[i] = 0xbeefdead; SetLastError(ERROR_SUCCESS); - TEST(NtUserSystemParametersInfo(4137, 0, &data, 0) == TRUE); + TEST(NtUserSystemParametersInfo(0x1029, 0, &data, 0) == TRUE); TEST(GetLastError() == ERROR_SUCCESS); TEST(data[0] == 0xbeefdead); TEST(data[1] == 0xbeefdead); for(i = 0; i < 1000; i++) data[i] = 0xdeadbeef; SetLastError(ERROR_SUCCESS); - TEST(NtUserSystemParametersInfo(4138, 0, &data, 0) == TRUE); + TEST(NtUserSystemParametersInfo(0x102A, 0, &data, 0) == TRUE); TEST(GetLastError() == ERROR_SUCCESS); TEST(data[0] != 0xdeadbeef); TEST(data[1] == 0xdeadbeef); @@ -255,7 +299,7 @@ Test_NtUserSystemParametersInfo_Params(PTESTINFO pti) TEST(GetLastError() == ERROR_SUCCESS); TEST(data[0] == 0xbeefdead); TEST(data[1] == 0xbeefdead); - +#endif /* Test invalid pointer */ SetLastError(ERROR_SUCCESS); TEST(NtUserSystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, (PVOID)0x80000000, 0) == FALSE); @@ -265,6 +309,53 @@ Test_NtUserSystemParametersInfo_Params(PTESTINFO pti) /* test wrong bools */ } +void +Test_NtUserSystemParametersInfo_Winsta(PTESTINFO pti) +{ + HWINSTA hwinsta, hwinstaOld; + INT ai[20]; + BOOL bRet; +// INT i; + + hwinstaOld = GetProcessWindowStation(); + hwinsta = CreateWindowStation(NULL, 0, READ_CONTROL, NULL); + SetProcessWindowStation(hwinsta); + printf("hwinstaOld=%p, hwinsta=%p\n", hwinstaOld, hwinsta); + +#if 1 // currently Winsta stuff is broken in ros + TEST(SystemParametersInfoA(SPI_GETBEEP, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_ACCESS_DENIED); + TEST(SystemParametersInfoA(SPI_SETBEEP, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION); + TEST(SystemParametersInfoA(SPI_GETMOUSE, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_ACCESS_DENIED); + TEST(SystemParametersInfoA(SPI_SETMOUSE, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION); + TEST(SystemParametersInfoA(SPI_GETBORDER, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_ACCESS_DENIED); + TEST(SystemParametersInfoA(SPI_SETBORDER, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION); + TEST(SystemParametersInfoA(SPI_GETKEYBOARDSPEED, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_ACCESS_DENIED); + TEST(SystemParametersInfoA(SPI_SETKEYBOARDSPEED, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION); + TEST(SystemParametersInfoA(SPI_ICONHORIZONTALSPACING, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_ACCESS_DENIED); + TEST(SystemParametersInfoA(SPI_ICONHORIZONTALSPACING, 32, 0, 0) == 0); + TEST(GetLastError() == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION); + TEST(SystemParametersInfoA(SPI_GETSCREENSAVETIMEOUT, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_ACCESS_DENIED); + TEST(SystemParametersInfoA(SPI_SETSCREENSAVETIMEOUT, 0, ai, 0) == 0); + TEST(GetLastError() == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION); + TEST(SystemParametersInfoA(SPI_GETKEYBOARDCUES, 0, &bRet, 0) == 0); + TEST(GetLastError() == ERROR_ACCESS_DENIED); + TEST(SystemParametersInfoA(SPI_SETKEYBOARDCUES, 0, (PVOID)1, 0) == 0); + TEST(GetLastError() == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION); +#endif + + SetProcessWindowStation(hwinstaOld); +} + void Test_NtUserSystemParametersInfo_fWinIni(PTESTINFO pti) { @@ -290,7 +381,76 @@ Test_NtUserSystemParametersInfo_fWinIni(PTESTINFO pti) } void -Test_SPI_GETSETBEEP(PTESTINFO pti) +Test_MetricKey(PTESTINFO pti, PCWSTR pwszVal, INT iVal) +{ + WCHAR szReg[10]; + DWORD cbSize; + + cbSize = sizeof(szReg); + TESTX(QueryUserRegValueW(KEY_METRIC, pwszVal, &szReg, &cbSize, NULL) == ERROR_SUCCESS, "Value=%S\n", pwszVal); + TESTX(_wcsicmp(szReg, L"1") == 0, "Value=%S\n", pwszVal); + +} + +INT +Test_UserPref(PTESTINFO pti, UINT uiGet, UINT uiSet, DWORD dwPrefMask) +{ + BOOL bOrig, bTemp = 0; + DWORD dwUserPref, dwUserPrefOrg; + DWORD cbSize; + + /* Get original values */ + NtUserSystemParametersInfo(uiGet, 0, &bOrig, 0); + cbSize = sizeof(dwUserPrefOrg); + QueryUserRegValueW(KEY_DESKTOP, VAL_PREFMASK, &dwUserPrefOrg, &cbSize, NULL); + + /* Value 0 */ + NtUserSystemParametersInfo(uiSet, 0, NULL, SPIF_UPDATEINIFILE); + NtUserSystemParametersInfo(uiGet, 0, &bTemp, 0); + TEST(bTemp == 0); + cbSize = sizeof(dwUserPref); + TEST(QueryUserRegValueW(KEY_DESKTOP, VAL_PREFMASK, &dwUserPref, &cbSize, NULL) == ERROR_SUCCESS); + TEST((dwUserPref & dwPrefMask) == 0); + TEST((dwUserPref & (~dwPrefMask)) == (dwUserPrefOrg & (~dwPrefMask))); + + /* Value 1 without Registry */ + NtUserSystemParametersInfo(uiSet, 0, (PVOID)1, 0); + NtUserSystemParametersInfo(uiGet, 0, &bTemp, 0); + TEST(bTemp == 1); + cbSize = sizeof(dwUserPref); + TEST(QueryUserRegValueW(KEY_DESKTOP, VAL_PREFMASK, &dwUserPref, &cbSize, NULL) == ERROR_SUCCESS); + TEST((dwUserPref & dwPrefMask) == 0); + TEST((dwUserPref & (~dwPrefMask)) == (dwUserPrefOrg & (~dwPrefMask))); + + /* Value 2 without Registry */ + NtUserSystemParametersInfo(uiSet, 0, (PVOID)2, 0); + NtUserSystemParametersInfo(uiGet, 0, &bTemp, 0); + TEST(bTemp == 1); + cbSize = sizeof(dwUserPref); + TEST(QueryUserRegValueW(KEY_DESKTOP, VAL_PREFMASK, &dwUserPref, &cbSize, NULL) == ERROR_SUCCESS); + TEST((dwUserPref & dwPrefMask) == 0); + TEST((dwUserPref & (~dwPrefMask)) == (dwUserPrefOrg & (~dwPrefMask))); + + /* Value 1 with Registry */ + NtUserSystemParametersInfo(uiSet, 0, (PVOID)1, SPIF_UPDATEINIFILE); + NtUserSystemParametersInfo(uiGet, 0, &bTemp, 0); + TEST(bTemp == 1); + cbSize = sizeof(dwUserPref); + TEST(QueryUserRegValueW(KEY_DESKTOP, VAL_PREFMASK, &dwUserPref, &cbSize, NULL) == ERROR_SUCCESS); + TEST((dwUserPref & dwPrefMask) == dwPrefMask); + TEST((dwUserPref & (~dwPrefMask)) == (dwUserPrefOrg & (~dwPrefMask))); + + /* Restore original value */ + NtUserSystemParametersInfo(uiSet, 0, (PVOID)bOrig, SPIF_UPDATEINIFILE); + + return APISTATUS_NORMAL; +} + + +/******************************************************************************/ + +void +Test_SPI_SETBEEP(PTESTINFO pti) { BOOL bOrig, bTemp = 0; WCHAR szReg[10]; @@ -304,54 +464,689 @@ Test_SPI_GETSETBEEP(PTESTINFO pti) NtUserSystemParametersInfo(SPI_GETBEEP, 0, &bTemp, 0); TEST(bTemp == 0); cbSize = sizeof(szReg); - TEST(QueryUserRegValueW(L"Control Panel\\Sound", L"Beep", &szReg, &cbSize, NULL) == ERROR_SUCCESS); - TEST(wcscmpi(szReg, L"No") == 0); + TEST(QueryUserRegValueW(KEY_SOUND, VAL_BEEP, &szReg, &cbSize, NULL) == ERROR_SUCCESS); + TEST(_wcsicmp(szReg, L"No") == 0); /* Value 1 */ NtUserSystemParametersInfo(SPI_SETBEEP, 1, NULL, SPIF_UPDATEINIFILE); NtUserSystemParametersInfo(SPI_GETBEEP, 0, &bTemp, 0); TEST(bTemp == 1); cbSize = sizeof(szReg); - TEST(QueryUserRegValueW(L"Control Panel\\Sound", L"Beep", &szReg, &cbSize, NULL) == ERROR_SUCCESS); - TEST(wcscmpi(szReg, L"Yes") == 0); + TEST(QueryUserRegValueW(KEY_SOUND, VAL_BEEP, &szReg, &cbSize, NULL) == ERROR_SUCCESS); + TEST(_wcsicmp(szReg, L"Yes") == 0); /* Value 2 */ NtUserSystemParametersInfo(SPI_SETBEEP, 2, NULL, SPIF_UPDATEINIFILE); NtUserSystemParametersInfo(SPI_GETBEEP, 0, &bTemp, 0); TEST(bTemp == 1); cbSize = sizeof(szReg); - TEST(QueryUserRegValueW(L"Control Panel\\Sound", L"Beep", &szReg, &cbSize, NULL) == ERROR_SUCCESS); - TEST(wcscmpi(szReg, L"Yes") == 0); + TEST(QueryUserRegValueW(KEY_SOUND, VAL_BEEP, &szReg, &cbSize, NULL) == ERROR_SUCCESS); + TEST(_wcsicmp(szReg, L"Yes") == 0); /* Restore original value */ NtUserSystemParametersInfo(SPI_SETBEEP, 0, &bOrig, SPIF_UPDATEINIFILE); } -INT +void +Test_SPI_SETMOUSE(PTESTINFO pti) +{ + INT aiOrig[3], aiTemp[3]; + + /* Get original value */ + NtUserSystemParametersInfo(SPI_GETMOUSE, 0, aiOrig, 0); + + /* Test uiParam value */ + TEST(NtUserSystemParametersInfo(SPI_GETMOUSE, 0, aiTemp, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETMOUSE, 1, aiTemp, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETMOUSE, -1, aiTemp, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETMOUSE, 0xdeadbeef, aiTemp, 0) == 1); + + /* Set modified values */ + aiTemp[0] = aiOrig[0] + 1; + aiTemp[1] = aiOrig[1] - 1; + aiTemp[2] = aiOrig[2] + 2; + NtUserSystemParametersInfo(SPI_SETMOUSE, 2, aiTemp, SPIF_UPDATEINIFILE); + aiTemp[0] = aiTemp[1] = aiTemp[2] = 0; + + /* Get new values */ + NtUserSystemParametersInfo(SPI_GETMOUSE, 0, aiTemp, 0); + + /* Test modified values */ + TEST(aiTemp[0] == aiOrig[0] + 1); + TEST(aiTemp[1] == aiOrig[1] - 1); + TEST(aiTemp[2] == aiOrig[2] + 2); + + // FIXME: Test registry values + + /* Restore original value */ + NtUserSystemParametersInfo(SPI_SETMOUSE, 0, aiOrig, SPIF_UPDATEINIFILE); +} + +void +Test_SPI_SETBORDER(PTESTINFO pti) +{ + INT iOrig, iTemp = 0; + + /* Get original value */ + NtUserSystemParametersInfo(SPI_GETBORDER, 0, &iOrig, 0); + + /* Value 0 */ + NtUserSystemParametersInfo(SPI_SETBORDER, 0, NULL, SPIF_UPDATEINIFILE); + NtUserSystemParametersInfo(SPI_GETBORDER, 0, &iTemp, 0); + TEST(iTemp == 1); + TEST(GetSystemMetrics(SM_CXBORDER) == 1); + + /* Value 1 */ + NtUserSystemParametersInfo(SPI_SETBORDER, 1, NULL, SPIF_UPDATEINIFILE); + NtUserSystemParametersInfo(SPI_GETBORDER, 0, &iTemp, 0); + TEST(iTemp == 1); +// Test_MetricKey(pti, VAL_BORDER, 1); + + /* Value 2 */ + NtUserSystemParametersInfo(SPI_SETBORDER, 2, NULL, SPIF_UPDATEINIFILE); + NtUserSystemParametersInfo(SPI_GETBORDER, 0, &iTemp, 0); + TEST(iTemp == 2); + TEST(GetSystemMetrics(SM_CXBORDER) == 1); + + /* Restore original value */ + NtUserSystemParametersInfo(SPI_SETBORDER, iOrig, NULL, SPIF_UPDATEINIFILE); + +} + +// Test_SPI_SETKEYBOARDSPEED(pti); +// Test_SPI_LANGDRIVER(pti); +// Test_SPI_ICONHORIZONTALSPACING(pti); +// Test_SPI_SETSCREENSAVETIMEOUT(pti); +// Test_SPI_SETSCREENSAVEACTIVE(pti); +// Test_SPI_SETGRIDGRANULARITY(pti); + +void Test_SPI_SETDESKWALLPAPER(PTESTINFO pti) { - /* Get old Wallpaper */ -// NtUserSystemParametersInfo(SPI_GET_DESKWALLPAPER, 0, + UNICODE_STRING ustrOld, ustrNew; + WCHAR szOld[MAX_PATH]; + WCHAR szNew[MAX_PATH]; + + /* Get old Wallpaper */ + TEST(NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, szOld, 0) == 1); + RtlInitUnicodeString(&ustrOld, szOld); + + /* Set no Wallpaper */ + TEST(NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, L"", 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, szNew, 0) == 1); + TEST(szNew[0] == 0); + + /* Set no Wallpaper 2 */ + RtlInitUnicodeString(&ustrNew, L""); + TEST(NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, &ustrNew, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, szNew, 0) == 1); + TEST(szNew[0] == 0); + + /* Reset Wallpaper */ + TEST(NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, szNew, 0) == 1); + TEST(wcscmp(szNew, szOld) == 0); + + /* Set new Wallpaper */ + RtlInitUnicodeString(&ustrNew, L"test.bmp"); + TEST(NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, &ustrNew, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, szNew, 0) == 1); + TEST(wcscmp(szNew, L"test.bmp") == 0); + + /* Get Wallpaper, too small buffer */ + szNew[0] = 0; szNew[1] = 0; szNew[2] = 0; + TEST(NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, 3, szNew, 0) == 1); + TEST(szNew[0] != 0); + TEST(szNew[1] != 0); + TEST(szNew[2] != 0); + + /* Set invalid Wallpaper */ + SetLastError(0xdeadbeef); + RtlInitUnicodeString(&ustrNew, L"*#!!-&"); + TEST(NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, &ustrNew, 0) == 0); + TEST(GetLastError() == ERROR_FILE_NOT_FOUND); + TEST(NtUserSystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, szNew, 0) == 1); + TEST(wcscmp(szNew, L"*#!!-&") == 0); + + /* Restore old Wallpaper */ + TEST(NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, MAX_PATH, &ustrOld, SPIF_UPDATEINIFILE) == 1); -// TEST(NtUserSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, &hNewWallPaper, 0) == 0); - return 0; } +// Test_SPI_SETDESKPATTERN(pti); +// Test_SPI_SETKEYBOARDDELAY(pti); +// Test_SPI_ICONVERTICALSPACING(pti); +// Test_SPI_SETICONTITLEWRAP(pti); +// Test_SPI_SETMENUDROPALIGNMENT(pti); +// Test_SPI_SETDOUBLECLKWIDTH(pti); +// Test_SPI_SETDOUBLECLKHEIGHT(pti); +// Test_SPI_SETDOUBLECLICKTIME(pti); + +INT +Test_SPI_SETMOUSEBUTTONSWAP(PTESTINFO pti) +{ + BOOL bOrig, bTemp = 0; + WCHAR szReg[10]; + DWORD cbSize; + + /* Get original value */ + bOrig = GetSystemMetrics(SM_SWAPBUTTON); + + /* Value 0 */ + NtUserSystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, 0, NULL, SPIF_UPDATEINIFILE); + bTemp = GetSystemMetrics(SM_SWAPBUTTON); + TEST(bTemp == 0); + cbSize = sizeof(szReg); + TEST(QueryUserRegValueW(KEY_MOUSE, VAL_SWAP, &szReg, &cbSize, NULL) == ERROR_SUCCESS); + TEST(_wcsicmp(szReg, L"0") == 0); + + /* Value 1 */ + NtUserSystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, 1, NULL, SPIF_UPDATEINIFILE); + bTemp = GetSystemMetrics(SM_SWAPBUTTON); + TEST(bTemp == 1); + cbSize = sizeof(szReg); + TEST(QueryUserRegValueW(KEY_MOUSE, VAL_SWAP, &szReg, &cbSize, NULL) == ERROR_SUCCESS); + TEST(_wcsicmp(szReg, L"1") == 0); + + /* Value 2 */ + NtUserSystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, 2, NULL, SPIF_UPDATEINIFILE); + bTemp = GetSystemMetrics(SM_SWAPBUTTON); + TEST(bTemp == 1); + cbSize = sizeof(szReg); + TEST(QueryUserRegValueW(KEY_MOUSE, VAL_SWAP, &szReg, &cbSize, NULL) == ERROR_SUCCESS); + TEST(_wcsicmp(szReg, L"2") == 0); + + /* Value -1 */ + NtUserSystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, -1, NULL, SPIF_UPDATEINIFILE); + bTemp = GetSystemMetrics(SM_SWAPBUTTON); + TEST(bTemp == 1); + cbSize = sizeof(szReg); + TEST(QueryUserRegValueW(KEY_MOUSE, VAL_SWAP, &szReg, &cbSize, NULL) == ERROR_SUCCESS); + TEST(_wcsicmp(szReg, L"-1") == 0); + + /* Restore original value */ + NtUserSystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, bOrig, 0, SPIF_UPDATEINIFILE); + + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETICONTITLELOGFONT(PTESTINFO pti) +{ + LOGFONTW lfOrig; + struct + { + LOGFONTW lf; + DWORD dwRedzone; + } buf; + + /* Get original value */ + ASSERT(NtUserSystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfOrig), &lfOrig, 0)); + + /* Test uiParam == 0 */ + memset(&buf, 0, sizeof(buf)); + buf.lf.lfFaceName[LF_FACESIZE-1] = 33; + buf.dwRedzone = 0xdeadbeef; + TEST(NtUserSystemParametersInfo(SPI_GETICONTITLELOGFONT, 0, &buf.lf, 0) == 1); + TEST(buf.lf.lfHeight != 0); + TEST(buf.lf.lfWeight != 0); + TEST(buf.lf.lfFaceName[0] != 0); + TEST(buf.lf.lfFaceName[LF_FACESIZE-1] == 0); + TEST(buf.dwRedzone == 0xdeadbeef); + + /* Test uiParam < sizeof(LOGFONTW) */ + memset(&buf, 0, sizeof(buf)); + buf.lf.lfFaceName[LF_FACESIZE-1] = 33; + buf.dwRedzone = 0xdeadbeef; + TEST(NtUserSystemParametersInfo(SPI_GETICONTITLELOGFONT, 8, &buf.lf, 0) == 1); + TEST(buf.lf.lfHeight != 0); + TEST(buf.lf.lfWeight != 0); + TEST(buf.lf.lfFaceName[0] != 0); + TEST(buf.lf.lfFaceName[LF_FACESIZE-1] == 0); + TEST(buf.dwRedzone == 0xdeadbeef); + + /* Test uiParam < 0 */ + TEST(NtUserSystemParametersInfo(SPI_GETICONTITLELOGFONT, -1, &buf.lf, 0) == 1); + + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETFASTTASKSWITCH(PTESTINFO pti) +{ + char buf[10]; + TEST(NtUserSystemParametersInfo(SPI_SETFASTTASKSWITCH, 0, 0, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_SETFASTTASKSWITCH, 0, buf, 0) == 1); + + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETDRAGFULLWINDOWS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETNONCLIENTMETRICS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETMINIMIZEDMETRICS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETICONMETRICS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETWORKAREA(PTESTINFO pti) +{ + RECT rcOrig, rc; + + /* Get the original value */ + ASSERT(NtUserSystemParametersInfo(SPI_GETWORKAREA, 0, &rcOrig, 0) == 1); + + /* Change value */ + rc = rcOrig; + rc.left += 1; + rc.top += 2; + rc.right -= 3; + rc.bottom -= 2; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 1, &rc, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, sizeof(RECT), &rc, 0) == 1); + + TEST(NtUserSystemParametersInfo(SPI_GETWORKAREA, 1, &rc, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETWORKAREA, -1, &rc, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETWORKAREA, 0xdeadbeef, &rc, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)0xdeadbeef, 0) == 0); + + /* Test values */ + rc = rcOrig; rc.left = -1; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 0); + rc = rcOrig; rc.top = -1; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 0); + rc = rcOrig; rc.top = 10; rc.bottom = 11; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 1); + rc = rcOrig; rc.top = 10; rc.bottom = 10; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 0); + rc = rcOrig; rc.top = 10; rc.bottom = 9; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 0); + rc = rcOrig; rc.left = 10; rc.right = 11; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 1); + rc = rcOrig; rc.left = 10; rc.right = 10; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 0); + rc = rcOrig; rc.left = 10; rc.right = 9; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 0); + rc = rcOrig; rc.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 1); + rc = rcOrig; rc.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN)+1; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 0); + rc = rcOrig; rc.right = GetSystemMetrics(SM_CXVIRTUALSCREEN); + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 1); + rc = rcOrig; rc.right = GetSystemMetrics(SM_CXVIRTUALSCREEN)+1; + TEST(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rc, 0) == 0); + + /* Restore original value */ + ASSERT(NtUserSystemParametersInfo(SPI_SETWORKAREA, 0, &rcOrig, 0) == 1); + + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETPENWINDOWS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETFILTERKEYS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETTOGGLEKEYS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETMOUSEKEYS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETSHOWSOUNDS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETSTICKYKEYS(PTESTINFO pti) +{ + STICKYKEYS skOrig, sk; + + /* Get original values */ + skOrig.cbSize = sizeof(STICKYKEYS); + ASSERT(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, 0, &skOrig, 0) == 1); + + sk.cbSize = sizeof(STICKYKEYS)+1; + TEST(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, 0, &sk, 0) == 0); + + sk.cbSize = sizeof(STICKYKEYS)-1; + TEST(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, 0, &sk, 0) == 0); + + sk.cbSize = sizeof(STICKYKEYS); + TEST(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, 1, &sk, 0) == 0); + TEST(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, -1, &sk, 0) == 0); + TEST(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, sk.cbSize, &sk, 0) == 1); + TEST(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, sk.cbSize-1, &sk, 0) == 0); + TEST(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, sk.cbSize+1, &sk, 0) == 0); + + sk = skOrig; + sk.dwFlags = (skOrig.dwFlags ^ 1); + TEST(NtUserSystemParametersInfo(SPI_SETSTICKYKEYS, sk.cbSize+1, &sk, 0) == 0); + TEST(NtUserSystemParametersInfo(SPI_SETSTICKYKEYS, sk.cbSize-1, &sk, 0) == 0); + TEST(NtUserSystemParametersInfo(SPI_SETSTICKYKEYS, sk.cbSize, &sk, 0) == 1); + + sk = skOrig; + TEST(NtUserSystemParametersInfo(SPI_GETSTICKYKEYS, 0, &sk, 0) == 1); + TEST(sk.dwFlags == (skOrig.dwFlags ^ 1)); + + /* Restore original values */ + skOrig.cbSize = sizeof(STICKYKEYS); + ASSERT(NtUserSystemParametersInfo(SPI_SETSTICKYKEYS, 0, &skOrig, 0) == 1); + + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETACCESSTIMEOUT(PTESTINFO pti) +{ + ACCESSTIMEOUT atoOrig, atoTmp; + + /* Get original values */ + atoOrig.cbSize = sizeof(ACCESSTIMEOUT); + ASSERT(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, 0, &atoOrig, 0) == 1); + + atoTmp.cbSize = sizeof(ACCESSTIMEOUT) - 1; + TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, 0, &atoTmp, 0) == 0); + atoTmp.cbSize = sizeof(ACCESSTIMEOUT) + 1; + TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, 0, &atoTmp, 0) == 0); + atoTmp.cbSize = sizeof(ACCESSTIMEOUT); + TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, 0, &atoTmp, 0) == 1); + atoTmp.cbSize = sizeof(ACCESSTIMEOUT); + TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, 1, &atoTmp, 0) == 0); + atoTmp.cbSize = sizeof(ACCESSTIMEOUT); + TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, -1, &atoTmp, 0) == 0); + atoTmp.cbSize = sizeof(ACCESSTIMEOUT); + TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, sizeof(ACCESSTIMEOUT), &atoTmp, 0) == 1); + atoTmp.cbSize = sizeof(ACCESSTIMEOUT); + TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, sizeof(ACCESSTIMEOUT)-1, &atoTmp, 0) == 0); + atoTmp.cbSize = sizeof(ACCESSTIMEOUT); + TEST(NtUserSystemParametersInfo(SPI_GETACCESSTIMEOUT, sizeof(ACCESSTIMEOUT)+1, &atoTmp, 0) == 0); + + /* Restore original values */ + ASSERT(NtUserSystemParametersInfo(SPI_SETACCESSTIMEOUT, sizeof(atoOrig), &atoOrig, 0) == 1); + + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETSERIALKEYS(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETSOUNDSENTRY(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETHIGHCONTRAST(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +INT +Test_SPI_SETKEYBOARDPREF(PTESTINFO pti) +{ + return APISTATUS_NORMAL; +} + +// Test_SPI_SETSCREENREADER(pti); +/// Test_SPI_SETANIMATION(pti); +// Test_SPI_SETFONTSMOOTHING(pti); +// Test_SPI_SETDRAGWIDTH(pti); +// Test_SPI_SETDRAGHEIGHT(pti); +// Test_SPI_SETHANDHELD(pti); +// Test_SPI_SETLOWPOWERTIMEOUT(pti); +// Test_SPI_SETPOWEROFFTIMEOUT(pti); +// Test_SPI_SETLOWPOWERACTIVE(pti); +// Test_SPI_SETPOWEROFFACTIVE(pti); +// Test_SPI_SETCURSORS(pti); +// Test_SPI_SETICONS(pti); +// Test_SPI_SETDEFAULTINPUTLANG(pti); +// Test_SPI_SETLANGTOGGLE(pti); +// Test_SPI_GETWINDOWSEXTENSION(pti); +// Test_SPI_SETMOUSETRAILS(pti); +// Test_SPI_SETSNAPTODEFBUTTON(pti); +// Test_SPI_GETSCREENSAVERRUNNING(pti); +// Test_SPI_SETMOUSEHOVERWIDTH(pti); +// Test_SPI_SETMOUSEHOVERHEIGHT(pti); +// Test_SPI_SETMOUSEHOVERTIME(pti); +// Test_SPI_SETWHEELSCROLLLINES(pti); +// Test_SPI_SETMENUSHOWDELAY(pti); +// Test_SPI_SETWHEELSCROLLCHARS(pti); +// Test_SPI_SETSHOWIMEUI(pti); +// Test_SPI_SETMOUSESPEED(pti); +// Test_SPI_GETSCREENSAVERRUNNING(pti); +// Test_SPI_SETAUDIODESCRIPTION(pti); +// Test_SPI_SETSCREENSAVESECURE(pti); +// Test_SPI_SETACTIVEWINDOWTRACKING(pti); + +INT +Test_SPI_SETMENUANIMATION(PTESTINFO pti) +{ + BOOL bOrig, bTemp = 0; + DWORD dwUserPrefMask; + DWORD cbSize; + + /* Get original values */ + NtUserSystemParametersInfo(SPI_GETMENUANIMATION, 0, &bOrig, 0); + + /* Value 0 */ + NtUserSystemParametersInfo(SPI_SETMENUANIMATION, 0, NULL, SPIF_UPDATEINIFILE); + NtUserSystemParametersInfo(SPI_GETMENUANIMATION, 0, &bTemp, 0); + TEST(bTemp == 0); + cbSize = sizeof(dwUserPrefMask); + TEST(QueryUserRegValueW(KEY_DESKTOP, VAL_PREFMASK, &dwUserPrefMask, &cbSize, NULL) == ERROR_SUCCESS); + TEST((dwUserPrefMask & UPM_MENUANIMATION) == 0); + + /* Value 1 */ + NtUserSystemParametersInfo(SPI_SETMENUANIMATION, 0, (PVOID)1, SPIF_UPDATEINIFILE); + NtUserSystemParametersInfo(SPI_GETMENUANIMATION, 0, &bTemp, 0); + TEST(bTemp == 1); + cbSize = sizeof(dwUserPrefMask); + TEST(QueryUserRegValueW(KEY_DESKTOP, VAL_PREFMASK, &dwUserPrefMask, &cbSize, NULL) == ERROR_SUCCESS); + TEST((dwUserPrefMask & UPM_MENUANIMATION) != 0); + + + /* Restore original values */ + NtUserSystemParametersInfo(SPI_SETMENUANIMATION, 0, (PVOID)bOrig, SPIF_UPDATEINIFILE); + + return APISTATUS_NORMAL; +} + +// Test_SPI_SETCOMBOBOXANIMATION(pti); +// Test_SPI_SETLISTBOXSMOOTHSCROLLING(pti); +// Test_SPI_SETGRADIENTCAPTIONS(pti); + +INT +Test_SPI_SETKEYBOARDCUES(PTESTINFO pti) +{ + return Test_UserPref(pti, SPI_GETKEYBOARDCUES, SPI_SETKEYBOARDCUES, UPM_KEYBOARDCUES); +} + +// Test_SPI_SETACTIVEWNDTRKZORDER(pti); +// Test_SPI_SETHOTTRACKING(pti); +// Test_SPI_SETMENUFADE(pti); +// Test_SPI_SETSELECTIONFADE(pti); +// Test_SPI_SETTOOLTIPANIMATION(pti); +// Test_SPI_SETTOOLTIPFADE(pti); +// Test_SPI_SETCURSORSHADOW(pti); +// Test_SPI_SETMOUSESONAR(pti); + +INT +Test_SPI_SETMOUSECLICKLOCK(PTESTINFO pti) +{ + return Test_UserPref(pti, SPI_GETMOUSECLICKLOCK, SPI_SETMOUSECLICKLOCK, UPM_CLICKLOCK); +} + +// Test_SPI_SETMOUSEVANISH(pti); +// Test_SPI_SETFLATMENU(pti); +// Test_SPI_SETDROPSHADOW(pti); +// Test_SPI_SETBLOCKSENDINPUTRESETS(pti); +// Test_SPI_GETSETUIEFFECTS(pti); +// Test_SPI_SETDISABLEOVERLAPPEDCONTENT(pti); +// Test_SPI_SETCLIENTAREAANIMATION(pti); +// Test_SPI_SETCLEARTYPE(pti); +// Test_SPI_SETSPEECHRECOGNITION(pti); +// Test_SPI_SETFOREGROUNDLOCKTIMEOUT(pti); +// Test_SPI_SETACTIVEWNDTRKTIMEOUT(pti); +// Test_SPI_SETFOREGROUNDFLASHCOUNT(pti); +// Test_SPI_SETCARETWIDTH(pti); +// Test_SPI_SETMOUSECLICKLOCKTIME(pti); +// Test_SPI_SETFONTSMOOTHINGTYPE(pti); +// Test_SPI_SETFONTSMOOTHINGCONTRAST(pti); +// Test_SPI_SETFOCUSBORDERWIDTH(pti); +// Test_SPI_SETFOCUSBORDERHEIGHT(pti); +// Test_SPI_SETFONTSMOOTHINGORIENTATION(pti); + + INT Test_NtUserSystemParametersInfo(PTESTINFO pti) { HWND hWnd; hWnd = CreateTestWindow(); -// ASSERT(hWnd); + ASSERT(hWnd); + Test_NtUserSystemParametersInfo_Params(pti); - Test_NtUserSystemParametersInfo_fWinIni(pti); + Test_NtUserSystemParametersInfo_Winsta(pti); - Test_SPI_GETSETBEEP(pti); + Test_SPI_SETBEEP(pti); + Test_SPI_SETMOUSE(pti); + Test_SPI_SETBORDER(pti); +// Test_SPI_SETKEYBOARDSPEED(pti); +// Test_SPI_LANGDRIVER(pti); +// Test_SPI_ICONHORIZONTALSPACING(pti); +// Test_SPI_SETSCREENSAVETIMEOUT(pti); +// Test_SPI_SETSCREENSAVEACTIVE(pti); +// Test_SPI_SETGRIDGRANULARITY(pti); Test_SPI_SETDESKWALLPAPER(pti); - - Test_SPI_87_88(pti); +// Test_SPI_SETDESKPATTERN(pti); +// Test_SPI_SETKEYBOARDDELAY(pti); +// Test_SPI_ICONVERTICALSPACING(pti); +// Test_SPI_SETICONTITLEWRAP(pti); +// Test_SPI_SETMENUDROPALIGNMENT(pti); +// Test_SPI_SETDOUBLECLKWIDTH(pti); +// Test_SPI_SETDOUBLECLKHEIGHT(pti); +// Test_SPI_SETDOUBLECLICKTIME(pti); + Test_SPI_SETMOUSEBUTTONSWAP(pti); + Test_SPI_SETICONTITLELOGFONT(pti); + Test_SPI_SETFASTTASKSWITCH(pti); + Test_SPI_SETDRAGFULLWINDOWS(pti); + Test_SPI_SETNONCLIENTMETRICS(pti); + Test_SPI_SETMINIMIZEDMETRICS(pti); + Test_SPI_SETICONMETRICS(pti); + Test_SPI_SETWORKAREA(pti); + Test_SPI_SETPENWINDOWS(pti); + Test_SPI_SETFILTERKEYS(pti); + Test_SPI_SETTOGGLEKEYS(pti); + Test_SPI_SETMOUSEKEYS(pti); + Test_SPI_SETSHOWSOUNDS(pti); + Test_SPI_SETSTICKYKEYS(pti); + Test_SPI_SETACCESSTIMEOUT(pti); + Test_SPI_SETSERIALKEYS(pti); + Test_SPI_SETSOUNDSENTRY(pti); + Test_SPI_SETHIGHCONTRAST(pti); + Test_SPI_SETKEYBOARDPREF(pti); +// Test_SPI_SETSCREENREADER(pti); +/// Test_SPI_SETANIMATION(pti); +// Test_SPI_SETFONTSMOOTHING(pti); +// Test_SPI_SETDRAGWIDTH(pti); +// Test_SPI_SETDRAGHEIGHT(pti); +// Test_SPI_SETHANDHELD(pti); +// Test_SPI_SETLOWPOWERTIMEOUT(pti); +// Test_SPI_SETPOWEROFFTIMEOUT(pti); +// Test_SPI_SETLOWPOWERACTIVE(pti); +// Test_SPI_SETPOWEROFFACTIVE(pti); +// Test_SPI_SETCURSORS(pti); +// Test_SPI_SETICONS(pti); +// Test_SPI_SETDEFAULTINPUTLANG(pti); +// Test_SPI_SETLANGTOGGLE(pti); +// Test_SPI_GETWINDOWSEXTENSION(pti); +// Test_SPI_SETMOUSETRAILS(pti); +// Test_SPI_SETSNAPTODEFBUTTON(pti); +// Test_SPI_GETSCREENSAVERRUNNING(pti); +// Test_SPI_SETMOUSEHOVERWIDTH(pti); +// Test_SPI_SETMOUSEHOVERHEIGHT(pti); +// Test_SPI_SETMOUSEHOVERTIME(pti); +// Test_SPI_SETWHEELSCROLLLINES(pti); +// Test_SPI_SETMENUSHOWDELAY(pti); +// Test_SPI_SETWHEELSCROLLCHARS(pti); +// Test_SPI_SETSHOWIMEUI(pti); +// Test_SPI_SETMOUSESPEED(pti); +// Test_SPI_GETSCREENSAVERRUNNING(pti); +// Test_SPI_SETAUDIODESCRIPTION(pti); +// Test_SPI_SETSCREENSAVESECURE(pti); +// Test_SPI_SETACTIVEWINDOWTRACKING(pti); + Test_SPI_SETMENUANIMATION(pti); +// Test_SPI_SETCOMBOBOXANIMATION(pti); +// Test_SPI_SETLISTBOXSMOOTHSCROLLING(pti); +// Test_SPI_SETGRADIENTCAPTIONS(pti); + Test_SPI_SETKEYBOARDCUES(pti); +// Test_SPI_SETACTIVEWNDTRKZORDER(pti); +// Test_SPI_SETHOTTRACKING(pti); +// Test_SPI_SETMENUFADE(pti); +// Test_SPI_SETSELECTIONFADE(pti); +// Test_SPI_SETTOOLTIPANIMATION(pti); +// Test_SPI_SETTOOLTIPFADE(pti); +// Test_SPI_SETCURSORSHADOW(pti); +// Test_SPI_SETMOUSESONAR(pti); + Test_SPI_SETMOUSECLICKLOCK(pti); +// Test_SPI_SETMOUSEVANISH(pti); +// Test_SPI_SETFLATMENU(pti); +// Test_SPI_SETDROPSHADOW(pti); +// Test_SPI_SETBLOCKSENDINPUTRESETS(pti); +// Test_SPI_GETSETUIEFFECTS(pti); +// Test_SPI_SETDISABLEOVERLAPPEDCONTENT(pti); +// Test_SPI_SETCLIENTAREAANIMATION(pti); +// Test_SPI_SETCLEARTYPE(pti); +// Test_SPI_SETSPEECHRECOGNITION(pti); +// Test_SPI_SETFOREGROUNDLOCKTIMEOUT(pti); +// Test_SPI_SETACTIVEWNDTRKTIMEOUT(pti); +// Test_SPI_SETFOREGROUNDFLASHCOUNT(pti); +// Test_SPI_SETCARETWIDTH(pti); +// Test_SPI_SETMOUSECLICKLOCKTIME(pti); +// Test_SPI_SETFONTSMOOTHINGTYPE(pti); +// Test_SPI_SETFONTSMOOTHINGCONTRAST(pti); +// Test_SPI_SETFOCUSBORDERWIDTH(pti); +// Test_SPI_SETFOCUSBORDERHEIGHT(pti); +// Test_SPI_SETFONTSMOOTHINGORIENTATION(pti); DestroyWindow(hWnd); diff --git a/rostests/apitests/w32knapi/ntuser/NtUserToUnicodeEx.c b/rostests/apitests/w32knapi/ntuser/NtUserToUnicodeEx.c index fd129dc61c2..921b660752e 100644 --- a/rostests/apitests/w32knapi/ntuser/NtUserToUnicodeEx.c +++ b/rostests/apitests/w32knapi/ntuser/NtUserToUnicodeEx.c @@ -139,7 +139,7 @@ Test_NtUserToUnicodeEx(PTESTINFO pti) TEST(NtUserToUnicodeEx(52, 5, KeyState, Buffer, 10, 0, hkl) == 1); TEST(Buffer[0] == '$'); TEST(NtUserToUnicodeEx(53, 6, KeyState, Buffer, 10, 0, hkl) == 1); - TEST(Buffer[0] == '\%'); + TEST(Buffer[0] == '%'); TEST(NtUserToUnicodeEx(54, 7, KeyState, Buffer, 10, 0, hkl) == 1); TEST(Buffer[0] == '^'); TEST(NtUserToUnicodeEx(55, 8, KeyState, Buffer, 10, 0, hkl) == 1); diff --git a/rostests/apitests/w32knapi/ntuser/NtUserUpdatePerUserSystemParameters.c b/rostests/apitests/w32knapi/ntuser/NtUserUpdatePerUserSystemParameters.c new file mode 100644 index 00000000000..d05b8b6b43e --- /dev/null +++ b/rostests/apitests/w32knapi/ntuser/NtUserUpdatePerUserSystemParameters.c @@ -0,0 +1,22 @@ + +DWORD WINAPI +UpdatePerUserSystemParameters(DWORD dw1, DWORD dw2); + +INT +Test_NtUserUpdatePerUserSystemParameters(PTESTINFO pti) +{ + BOOL bScrRd; + + TEST(NtUserUpdatePerUserSystemParameters(0, 0) == 0); + TEST(NtUserUpdatePerUserSystemParameters(0, 1) == 0); + TEST(NtUserUpdatePerUserSystemParameters(1, 0) == 0); + TEST(NtUserUpdatePerUserSystemParameters(1, 1) == 0); + TEST(NtUserUpdatePerUserSystemParameters(0, 2) == 0); + TEST(NtUserUpdatePerUserSystemParameters(0, -1) == 0); + +// NtUserSystemParametersInfo(SPI_SETSCREENREADER, 1, 0, 0); + NtUserSystemParametersInfo(SPI_GETSCREENREADER, 0, &bScrRd, 0); + printf("bScrRd = %d\n", bScrRd); + + return APISTATUS_NORMAL; +} diff --git a/rostests/apitests/w32knapi/testlist.c b/rostests/apitests/w32knapi/testlist.c index 987f90366ec..b38e66bf0b5 100644 --- a/rostests/apitests/w32knapi/testlist.c +++ b/rostests/apitests/w32knapi/testlist.c @@ -8,15 +8,25 @@ #include "ntgdi/NtGdiArcInternal.c" #include "ntgdi/NtGdiBitBlt.c" +#include "ntgdi/NtGdiCombineRgn.c" #include "ntgdi/NtGdiCreateBitmap.c" #include "ntgdi/NtGdiCreateCompatibleBitmap.c" +#include "ntgdi/NtGdiCreateCompatibleDC.c" +#include "ntgdi/NtGdiCreateDIBSection.c" +#include "ntgdi/NtGdiDeleteObjectApp.c" #include "ntgdi/NtGdiDoPalette.c" #include "ntgdi/NtGdiEngCreatePalette.c" //#include "ntgdi/NtGdiEnumFontChunk.c" #include "ntgdi/NtGdiEnumFontOpen.c" +//#include "ntgdi/NtGdiExtCreatePen.c" +#include "ntgdi/NtGdiExtTextOutW.c" +#include "ntgdi/NtGdiFlushUserBatch.c" #include "ntgdi/NtGdiGetBitmapBits.c" #include "ntgdi/NtGdiGetFontResourceInfoInternalW.c" #include "ntgdi/NtGdiGetRandomRgn.c" +#include "ntgdi/NtGdiPolyPolyDraw.c" +#include "ntgdi/NtGdiRestoreDC.c" +#include "ntgdi/NtGdiSaveDC.c" #include "ntgdi/NtGdiSelectBitmap.c" #include "ntgdi/NtGdiSelectBrush.c" #include "ntgdi/NtGdiSelectFont.c" @@ -36,13 +46,19 @@ #include "ntuser/NtUserCallOneParam.c" #include "ntuser/NtUserCountClipboardFormats.c" //#include "ntuser/NtUserCreateWindowEx.c" +#include "ntuser/NtUserEnumDisplayMonitors.c" #include "ntuser/NtUserEnumDisplaySettings.c" #include "ntuser/NtUserFindExistingCursorIcon.c" +#include "ntuser/NtUserGetClassInfo.c" +#include "ntuser/NtUserGetTitleBarInfo.c" +#include "ntuser/NtUserProcessConnect.c" #include "ntuser/NtUserRedrawWindow.c" #include "ntuser/NtUserScrollDC.c" +#include "ntuser/NtUserSelectPalette.c" +#include "ntuser/NtUserSetTimer.c" #include "ntuser/NtUserSystemParametersInfo.c" #include "ntuser/NtUserToUnicodeEx.c" -#include "ntuser/NtUserGetTitleBarInfo.c" +#include "ntuser/NtUserUpdatePerUserSystemParameters.c" /* The List of tests */ TESTENTRY TestList[] = @@ -55,15 +71,25 @@ TESTENTRY TestList[] = /* ntgdi */ { L"NtGdiArcInternal", Test_NtGdiArcInternal }, { L"NtGdiBitBlt", Test_NtGdiBitBlt }, + { L"NtGdiCombineRgn", Test_NtGdiCombineRgn }, { L"NtGdiCreateBitmap", Test_NtGdiCreateBitmap }, { L"NtGdiCreateCompatibleBitmap", Test_NtGdiCreateCompatibleBitmap }, + { L"NtGdiCreateCompatibleDC", Test_NtGdiCreateCompatibleDC }, + { L"NtGdiCreateDIBSection", Test_NtGdiCreateDIBSection }, + { L"NtGdiDeleteObjectApp", Test_NtGdiDeleteObjectApp }, { L"NtGdiDoPalette", Test_NtGdiDoPalette }, { L"NtGdiEngCreatePalette", Test_NtGdiEngCreatePalette }, // { L"NtGdiEnumFontChunk", Test_NtGdiEnumFontChunk }, { L"NtGdiEnumFontOpen", Test_NtGdiEnumFontOpen }, +// { L"NtGdiExtCreatePen", Test_NtGdiExtCreatePen }, + { L"NtGdiExtTextOutW", Test_NtGdiExtTextOutW }, + { L"NtGdiFlushUserBatch", Test_NtGdiFlushUserBatch }, { L"NtGdiGetBitmapBits", Test_NtGdiGetBitmapBits }, { L"NtGdiGetFontResourceInfoInternalW", Test_NtGdiGetFontResourceInfoInternalW }, { L"NtGdiGetRandomRgn", Test_NtGdiGetRandomRgn }, + { L"NtGdiPolyPolyDraw", Test_NtGdiPolyPolyDraw }, + { L"NtGdiRestoreDC", Test_NtGdiRestoreDC }, + { L"NtGdiSaveDC", Test_NtGdiSaveDC }, { L"NtGdiSetBitmapBits", Test_NtGdiSetBitmapBits }, { L"NtGdiSetDIBitsToDeviceInternal", Test_NtGdiSetDIBitsToDeviceInternal }, { L"NtGdiSelectBitmap", Test_NtGdiSelectBitmap }, @@ -84,13 +110,19 @@ TESTENTRY TestList[] = { L"NtUserCallOneParam", Test_NtUserCallOneParam }, { L"NtUserCountClipboardFormats", Test_NtUserCountClipboardFormats }, // { L"NtUserCreateWindowEx", Test_NtUserCreateWindowEx }, + { L"NtUserEnumDisplayMonitors", Test_NtUserEnumDisplayMonitors }, { L"NtUserEnumDisplaySettings", TEST_NtUserEnumDisplaySettings }, { L"NtUserFindExistingCursorIcon", Test_NtUserFindExistingCursoricon }, + { L"NtUserGetClassInfo", Test_NtUserGetClassInfo }, + { L"NtUserGetTitleBarInfo", Test_NtUserGetTitleBarInfo }, + { L"NtUserProcessConnect", Test_NtUserProcessConnect }, { L"NtUserRedrawWindow", Test_NtUserRedrawWindow }, { L"NtUserScrollDC", Test_NtUserScrollDC }, + { L"NtUserSelectPalette", Test_NtUserSelectPalette }, + { L"NtUserSetTimer", Test_NtUserSetTimer }, { L"NtUserSystemParametersInfo", Test_NtUserSystemParametersInfo }, { L"NtUserToUnicodeEx", Test_NtUserToUnicodeEx }, - { L"NtUserGetTitleBarInfo", Test_NtUserGetTitleBarInfo } + { L"NtUserUpdatePerUserSystemParameters", Test_NtUserUpdatePerUserSystemParameters }, }; /* The function that gives us the number of tests */ diff --git a/rostests/apitests/w32knapi/w32knapi.c b/rostests/apitests/w32knapi/w32knapi.c index fa20eefcde7..28240e210bb 100644 --- a/rostests/apitests/w32knapi/w32knapi.c +++ b/rostests/apitests/w32knapi/w32knapi.c @@ -13,11 +13,45 @@ MyGdiQueryTable() return pPeb->GdiSharedHandleTable; } -static DWORD STDCALL +BOOL +IsHandleValid(HGDIOBJ hobj) +{ + USHORT Index = (ULONG_PTR)hobj; + PGDI_TABLE_ENTRY pentry = &GdiHandleTable[Index]; + + if (pentry->KernelData == NULL || + pentry->KernelData < (PVOID)0x80000000 || + (USHORT)pentry->FullUnique != (USHORT)((ULONG_PTR)hobj >> 16)) + { + return FALSE; + } + + return TRUE; +} + +PVOID +GetHandleUserData(HGDIOBJ hobj) +{ + USHORT Index = (ULONG_PTR)hobj; + PGDI_TABLE_ENTRY pentry = &GdiHandleTable[Index]; + + if (pentry->KernelData == NULL || + pentry->KernelData < (PVOID)0x80000000 || + (USHORT)pentry->FullUnique != (USHORT)((ULONG_PTR)hobj >> 16)) + { + return NULL; + } + + return pentry->UserData; +} + + +static DWORD WINAPI IntSyscall(FARPROC proc, UINT cParams, PVOID pFirstParam) { - DWORD ret; + DWORD retval; +#ifdef __GNUC__ asm volatile ( "pushfl;" // Save flags @@ -29,21 +63,37 @@ IntSyscall(FARPROC proc, UINT cParams, PVOID pFirstParam) "rep movsd;" // Copy params to the stack "call *%%edx;" // Call function "popfl;" // Restore flags - : "=a" (ret) + : "=a" (retval) : "S" (pFirstParam), "c" (cParams), "d"(proc) : "%edi" ); +#else + __asm + { + pushf + mov eax, cParams + shl eax, 2 + sub esp, eax + mov edi, esp + cld + rep movsd + call proc + mov retval, eax + popf + }; +#endif - return ret; + return retval; } DWORD Syscall(LPWSTR pszFunction, int cParams, void* pParams) { char szFunctionName[MAX_PATH]; + FARPROC proc; sprintf(szFunctionName, "%ls", pszFunction); - FARPROC proc = (FARPROC)GetProcAddress(g_hModule, szFunctionName); + proc = (FARPROC)GetProcAddress(g_hModule, szFunctionName); if (!proc) { printf("Couldn't find proc: %s\n", szFunctionName); diff --git a/rostests/apitests/w32knapi/w32knapi.h b/rostests/apitests/w32knapi/w32knapi.h index 4463015e162..2821787814a 100644 --- a/rostests/apitests/w32knapi/w32knapi.h +++ b/rostests/apitests/w32knapi/w32knapi.h @@ -37,6 +37,8 @@ extern HINSTANCE g_hInstance; extern HMODULE g_hModule; extern PGDI_TABLE_ENTRY GdiHandleTable; +BOOL IsHandleValid(HGDIOBJ hobj); +PVOID GetHandleUserData(HGDIOBJ hobj); DWORD Syscall(LPWSTR lpszFunction, int cParams, void* pParams); BOOL InitOsVersion(); extern UINT g_OsIdx; diff --git a/rostests/apitests/w32knapi/w32knapi.rbuild b/rostests/apitests/w32knapi/w32knapi.rbuild index 948fedc33d2..4574c831e22 100644 --- a/rostests/apitests/w32knapi/w32knapi.rbuild +++ b/rostests/apitests/w32knapi/w32knapi.rbuild @@ -1,17 +1,14 @@ . - - 0x0501 - 0x501 apitest ntdll - kernel32 user32 gdi32 shell32 advapi32 w32kdll dbghelp + -fms-extensions w32knapi.c osver.c testlist.c diff --git a/rostests/apitests/ws2_32/ws2_32.rbuild b/rostests/apitests/ws2_32/ws2_32.rbuild index e86f3cc04f8..c00e7a2ddaf 100644 --- a/rostests/apitests/ws2_32/ws2_32.rbuild +++ b/rostests/apitests/ws2_32/ws2_32.rbuild @@ -1,7 +1,5 @@ - 0x0501 apitest - kernel32 user32 shell32 ws2_32 diff --git a/rostests/tests/alphablend/alphablend.c b/rostests/dibtests/alphablend/alphablend.c similarity index 100% rename from rostests/tests/alphablend/alphablend.c rename to rostests/dibtests/alphablend/alphablend.c diff --git a/rostests/tests/alphablend/alphablend.rbuild b/rostests/dibtests/alphablend/alphablend.rbuild similarity index 62% rename from rostests/tests/alphablend/alphablend.rbuild rename to rostests/dibtests/alphablend/alphablend.rbuild index 843a46ba97f..a24f9d3692b 100644 --- a/rostests/tests/alphablend/alphablend.rbuild +++ b/rostests/dibtests/alphablend/alphablend.rbuild @@ -1,9 +1,5 @@ - 0x0501 - 0x0501 - . - kernel32 user32 gdi32 alphablend.c diff --git a/rostests/tests/alphablend/alphablend.rc b/rostests/dibtests/alphablend/alphablend.rc similarity index 100% rename from rostests/tests/alphablend/alphablend.rc rename to rostests/dibtests/alphablend/alphablend.rc diff --git a/rostests/tests/alphablend/lena.bmp b/rostests/dibtests/alphablend/lena.bmp similarity index 100% rename from rostests/tests/alphablend/lena.bmp rename to rostests/dibtests/alphablend/lena.bmp diff --git a/rostests/tests/alphablend/lenaalpha.bmp b/rostests/dibtests/alphablend/lenaalpha.bmp similarity index 100% rename from rostests/tests/alphablend/lenaalpha.bmp rename to rostests/dibtests/alphablend/lenaalpha.bmp diff --git a/rostests/tests/bitblt/bitblt.c b/rostests/dibtests/bitblt/bitblt.c similarity index 100% rename from rostests/tests/bitblt/bitblt.c rename to rostests/dibtests/bitblt/bitblt.c diff --git a/rostests/tests/bitblt/bitblt.rbuild b/rostests/dibtests/bitblt/bitblt.rbuild similarity index 60% rename from rostests/tests/bitblt/bitblt.rbuild rename to rostests/dibtests/bitblt/bitblt.rbuild index f55909c5320..e7a04b0c711 100644 --- a/rostests/tests/bitblt/bitblt.rbuild +++ b/rostests/dibtests/bitblt/bitblt.rbuild @@ -1,9 +1,5 @@ - 0x0501 - 0x0501 - . - kernel32 user32 gdi32 bitblt.c diff --git a/rostests/tests/bitblt/bitblt.rc b/rostests/dibtests/bitblt/bitblt.rc similarity index 100% rename from rostests/tests/bitblt/bitblt.rc rename to rostests/dibtests/bitblt/bitblt.rc diff --git a/rostests/tests/bitblt/lena.bmp b/rostests/dibtests/bitblt/lena.bmp similarity index 100% rename from rostests/tests/bitblt/lena.bmp rename to rostests/dibtests/bitblt/lena.bmp diff --git a/rostests/dibtests/bltrop/bltrop.c b/rostests/dibtests/bltrop/bltrop.c new file mode 100644 index 00000000000..8b73cf9018a --- /dev/null +++ b/rostests/dibtests/bltrop/bltrop.c @@ -0,0 +1,221 @@ +/* + * Shows the 15 well known BitBlt raster operations + * using src, dest, pattern, a background brush and color. + * + * Created by Gregor Schneider , November 2008 +*/ + +#include +#include + +HINSTANCE hInst; +TCHAR szWindowClass[] = _T("testclass"); + +static LRESULT CALLBACK +WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HBITMAP hBmpTest; + + switch (message) + { + case WM_CREATE: + { + hBmpTest = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(100), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + break; + } + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc, hdcMem; + BITMAP bitmap; + HBRUSH brush, brush2; + INT l; + + hdc = BeginPaint(hWnd, &ps); + hdcMem = CreateCompatibleDC(hdc); + + GetObject(hBmpTest, sizeof(BITMAP), &bitmap); + + /* fill destination with brush */ + brush = CreateHatchBrush(HS_DIAGCROSS, RGB(255,0,0)); + SelectObject(hdc, brush); + PatBlt(hdc, 30, 0, 4*bitmap.bmWidth*2, 4*bitmap.bmHeight, PATCOPY); + + /* hatched brushes */ + l = 66; + brush = CreateHatchBrush(HS_DIAGCROSS, RGB(255,0,0)); + SelectObject(hdc, brush); + PatBlt(hdc, 0, 0, 30, l, PATCOPY); + DeleteObject(brush); + + brush = CreateHatchBrush(HS_CROSS, RGB(255,0,0)); + SelectObject(hdc, brush); + PatBlt(hdc, 0, 1*l, 30, l, PATCOPY); + DeleteObject(brush); + + brush = CreateHatchBrush(HS_FDIAGONAL, RGB(255,0,0)); + SelectObject(hdc, brush); + PatBlt(hdc, 0, 2*l, 30, l, PATCOPY); + DeleteObject(brush); + + brush = CreateHatchBrush(HS_BDIAGONAL, RGB(255,0,0)); + SelectObject(hdc, brush); + PatBlt(hdc, 0, 3*l, 30, l, PATCOPY); + DeleteObject(brush); + + brush = CreateHatchBrush(HS_VERTICAL, RGB(255,0,0)); + SelectObject(hdc, brush); + PatBlt(hdc, 0, 4*l, 30, l, PATCOPY); + DeleteObject(brush); + + brush = CreateHatchBrush(HS_HORIZONTAL, RGB(255,0,0)); + SelectObject(hdc, brush); + PatBlt(hdc, 0, 5*l, 30, l, PATCOPY); + DeleteObject(brush); + + /* set up a second brush */ + brush2 = CreateHatchBrush(HS_VERTICAL, RGB(127,127,127)); + + /* first select brush, then set bk color */ + SelectObject(hdc, brush2); + SetBkColor(hdc, RGB(0, 255, 0)); + + /* 15 blt op's with bitblt */ + SelectObject(hdcMem, hBmpTest); + /* offset coordinates */ + SetWindowOrgEx(hdc, -10, -10, NULL); + BitBlt(hdc, 30, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); + BitBlt(hdc, 130, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, DSTINVERT); + BitBlt(hdc, 230, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, MERGECOPY); + BitBlt(hdc, 330, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, MERGEPAINT); + + BitBlt(hdc, 30, 100, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, NOTSRCCOPY); + BitBlt(hdc, 130, 100, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, NOTSRCERASE); + BitBlt(hdc, 230, 100, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, PATCOPY); + BitBlt(hdc, 330, 100, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, PATINVERT); + + BitBlt(hdc, 30, 200, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, PATPAINT); + BitBlt(hdc, 130, 200, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCAND); + BitBlt(hdc, 230, 200, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCERASE); + BitBlt(hdc, 330, 200, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCINVERT); + + BitBlt(hdc, 30, 300, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, BLACKNESS); + BitBlt(hdc, 130, 300, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCPAINT); + BitBlt(hdc, 230, 300, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, WHITENESS); + + /* 15 blt op's with stretchblt */ + StretchBlt(hdc, 30+400, 0, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY); + StretchBlt(hdc, 130+400, 0, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, DSTINVERT); + StretchBlt(hdc, 230+400, 0, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, MERGECOPY); + StretchBlt(hdc, 330+400, 0, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, MERGEPAINT); + + StretchBlt(hdc, 30+400, 100, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, NOTSRCCOPY); + StretchBlt(hdc, 130+400, 100, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, NOTSRCERASE); + StretchBlt(hdc, 230+400, 100, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, PATCOPY); + StretchBlt(hdc, 330+400, 100, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, PATINVERT); + + StretchBlt(hdc, 30+400, 200, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, PATPAINT); + StretchBlt(hdc, 130+400, 200, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCAND); + StretchBlt(hdc, 230+400, 200, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCERASE); + StretchBlt(hdc, 330+400, 200, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCINVERT); + + StretchBlt(hdc, 30+400, 300, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, BLACKNESS); + StretchBlt(hdc, 130+400, 300, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCPAINT); + StretchBlt(hdc, 230+400, 300, bitmap.bmWidth/2, bitmap.bmHeight/2, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, WHITENESS); + + DeleteObject(brush); + DeleteObject(brush2); + DeleteDC(hdcMem); + EndPaint(hWnd, &ps); + break; + } + + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + + +static ATOM +MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = NULL; + + return RegisterClassEx(&wcex); +} + + +static BOOL +InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; + + hWnd = CreateWindowEx(0, + szWindowClass, + _T("BitBlt raster operation test"), + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 840, + 440, + NULL, + NULL, + hInstance, + NULL); + + if (!hWnd) + { + return FALSE; + } + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + return TRUE; +} + + +int WINAPI +_tWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + MSG msg; + + MyRegisterClass(hInstance); + + if (!InitInstance(hInstance, nCmdShow)) + { + return FALSE; + } + + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (int)msg.wParam; +} diff --git a/rostests/dibtests/bltrop/bltrop.rbuild b/rostests/dibtests/bltrop/bltrop.rbuild new file mode 100644 index 00000000000..f19491c61bb --- /dev/null +++ b/rostests/dibtests/bltrop/bltrop.rbuild @@ -0,0 +1,6 @@ + + . + gdi32 + user32 + bltrop.c + bltrop.rc diff --git a/rostests/dibtests/bltrop/bltrop.rc b/rostests/dibtests/bltrop/bltrop.rc new file mode 100644 index 00000000000..deb50ccf35c --- /dev/null +++ b/rostests/dibtests/bltrop/bltrop.rc @@ -0,0 +1 @@ +100 BITMAP "mars.bmp" diff --git a/rostests/dibtests/bltrop/mars.bmp b/rostests/dibtests/bltrop/mars.bmp new file mode 100644 index 00000000000..84a937c7ceb Binary files /dev/null and b/rostests/dibtests/bltrop/mars.bmp differ diff --git a/rostests/tests/dibtest/dibtest.c b/rostests/dibtests/dibtest/dibtest.c similarity index 100% rename from rostests/tests/dibtest/dibtest.c rename to rostests/dibtests/dibtest/dibtest.c diff --git a/rostests/tests/dibtest/dibtest.rbuild b/rostests/dibtests/dibtest/dibtest.rbuild similarity index 53% rename from rostests/tests/dibtest/dibtest.rbuild rename to rostests/dibtests/dibtest/dibtest.rbuild index 4b44f5fad73..de99253175b 100644 --- a/rostests/tests/dibtest/dibtest.rbuild +++ b/rostests/dibtests/dibtest/dibtest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 dibtest.c diff --git a/rostests/dibtests/directory.rbuild b/rostests/dibtests/directory.rbuild new file mode 100644 index 00000000000..68d3ef88186 --- /dev/null +++ b/rostests/dibtests/directory.rbuild @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rostests/tests/icontest/icon.ico b/rostests/dibtests/icontest/icon.ico similarity index 100% rename from rostests/tests/icontest/icon.ico rename to rostests/dibtests/icontest/icon.ico diff --git a/rostests/tests/icontest/icontest.c b/rostests/dibtests/icontest/icontest.c similarity index 99% rename from rostests/tests/icontest/icontest.c rename to rostests/dibtests/icontest/icontest.c index a5761bc3816..f48320dd569 100644 --- a/rostests/tests/icontest/icontest.c +++ b/rostests/dibtests/icontest/icontest.c @@ -9,7 +9,7 @@ const char titleDrwIco[] = "DrawIcon Output"; const char titleMask[] = "Mask(AND image)"; const char titleXor[] = "XOR(color image)"; const char file[] = "Icon from file:"; -const char res[] = "Icon from Resorce:"; +const char res[] = "Icon from Resource:"; const char cursor[] = "Current Cursor:"; const char cursormask[] = "Cursor Mask Bitmap"; const char cursorcolor[] = "Cursor Color Bitmap"; diff --git a/rostests/tests/icontest/icontest.rbuild b/rostests/dibtests/icontest/icontest.rbuild similarity index 64% rename from rostests/tests/icontest/icontest.rbuild rename to rostests/dibtests/icontest/icontest.rbuild index e61c3df6324..8936201e290 100644 --- a/rostests/tests/icontest/icontest.rbuild +++ b/rostests/dibtests/icontest/icontest.rbuild @@ -1,9 +1,5 @@ - 0x0501 - 0x0501 - . - kernel32 user32 gdi32 ntdll diff --git a/rostests/tests/icontest/icontest.rc b/rostests/dibtests/icontest/icontest.rc similarity index 100% rename from rostests/tests/icontest/icontest.rc rename to rostests/dibtests/icontest/icontest.rc diff --git a/rostests/tests/icontest/resource.h b/rostests/dibtests/icontest/resource.h similarity index 100% rename from rostests/tests/icontest/resource.h rename to rostests/dibtests/icontest/resource.h diff --git a/rostests/tests/palbitblt/pal.c b/rostests/dibtests/palbitblt/pal.c similarity index 99% rename from rostests/tests/palbitblt/pal.c rename to rostests/dibtests/palbitblt/pal.c index 786eb301872..b1af6a537d0 100644 --- a/rostests/tests/palbitblt/pal.c +++ b/rostests/dibtests/palbitblt/pal.c @@ -77,7 +77,7 @@ void UpdatePalette(HBITMAP hBM){ DoBlt(hBM); } -void InitBitmap(HANDLE *hBM){ +void InitBitmap(HBITMAP *hBM){ HPALETTE PalHan; HWND ActiveWindow; HDC hDC; diff --git a/rostests/dibtests/palbitblt/palbitblt.rbuild b/rostests/dibtests/palbitblt/palbitblt.rbuild new file mode 100644 index 00000000000..1d75d706d0d --- /dev/null +++ b/rostests/dibtests/palbitblt/palbitblt.rbuild @@ -0,0 +1,5 @@ + + user32 + gdi32 + pal.c + diff --git a/rostests/tests/patblt/Penguin.bmp b/rostests/dibtests/patblt/Penguin.bmp similarity index 100% rename from rostests/tests/patblt/Penguin.bmp rename to rostests/dibtests/patblt/Penguin.bmp diff --git a/rostests/tests/patblt/patblt.cpp b/rostests/dibtests/patblt/patblt.cpp similarity index 100% rename from rostests/tests/patblt/patblt.cpp rename to rostests/dibtests/patblt/patblt.cpp diff --git a/rostests/tests/patblt/patblt.rbuild b/rostests/dibtests/patblt/patblt.rbuild similarity index 58% rename from rostests/tests/patblt/patblt.rbuild rename to rostests/dibtests/patblt/patblt.rbuild index 56631d4c290..e7295167e0e 100644 --- a/rostests/tests/patblt/patblt.rbuild +++ b/rostests/dibtests/patblt/patblt.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 patblt.cpp diff --git a/rostests/tests/stretchblt/lena.bmp b/rostests/dibtests/stretchblt/lena.bmp similarity index 100% rename from rostests/tests/stretchblt/lena.bmp rename to rostests/dibtests/stretchblt/lena.bmp diff --git a/rostests/tests/stretchblt/stretchblt.cpp b/rostests/dibtests/stretchblt/stretchblt.cpp similarity index 100% rename from rostests/tests/stretchblt/stretchblt.cpp rename to rostests/dibtests/stretchblt/stretchblt.cpp diff --git a/rostests/tests/stretchblt/stretchblt.rbuild b/rostests/dibtests/stretchblt/stretchblt.rbuild similarity index 56% rename from rostests/tests/stretchblt/stretchblt.rbuild rename to rostests/dibtests/stretchblt/stretchblt.rbuild index 76a319dea9b..48626f7c20f 100644 --- a/rostests/tests/stretchblt/stretchblt.rbuild +++ b/rostests/dibtests/stretchblt/stretchblt.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 stretchblt.cpp diff --git a/rostests/dibtests/vbltest/test_inv01.bmp b/rostests/dibtests/vbltest/test_inv01.bmp new file mode 100644 index 00000000000..5858d285cf7 Binary files /dev/null and b/rostests/dibtests/vbltest/test_inv01.bmp differ diff --git a/rostests/dibtests/vbltest/test_inv04.bmp b/rostests/dibtests/vbltest/test_inv04.bmp new file mode 100644 index 00000000000..9d5b3592938 Binary files /dev/null and b/rostests/dibtests/vbltest/test_inv04.bmp differ diff --git a/rostests/dibtests/vbltest/test_inv08.bmp b/rostests/dibtests/vbltest/test_inv08.bmp new file mode 100644 index 00000000000..75a19196e3f Binary files /dev/null and b/rostests/dibtests/vbltest/test_inv08.bmp differ diff --git a/rostests/dibtests/vbltest/test_inv24.bmp b/rostests/dibtests/vbltest/test_inv24.bmp new file mode 100644 index 00000000000..77988e01475 Binary files /dev/null and b/rostests/dibtests/vbltest/test_inv24.bmp differ diff --git a/rostests/dibtests/vbltest/test_inv32.ico b/rostests/dibtests/vbltest/test_inv32.ico new file mode 100644 index 00000000000..2c32fdf0022 Binary files /dev/null and b/rostests/dibtests/vbltest/test_inv32.ico differ diff --git a/rostests/dibtests/vbltest/vbltest.c b/rostests/dibtests/vbltest/vbltest.c new file mode 100644 index 00000000000..0e2bb25fe27 --- /dev/null +++ b/rostests/dibtests/vbltest/vbltest.c @@ -0,0 +1,219 @@ +/* + * Tests various blit and blend operations with different src + * bit depths and scaling where possbile. + * + * Created by Gregor Schneider , November 2008 +*/ + +#include +#include + +BOOL WINAPI GdiAlphaBlend( + HDC hdcDst, int xDst, int yDst, int wDst, int hDst, + HDC hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc, + BLENDFUNCTION blendFunction); + +BOOL WINAPI GdiTransparentBlt( + HDC hdcDst, int xDst, int yDst, int wDst, int hDst, + HDC hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc, + UINT crTransparent); + +#define CURRENT_BMPS 4 +#define CURRENT_ICONS 1 +#define SCALE 1.5 +#define OFFSET 5 + +HINSTANCE hInst; +TCHAR szWindowClass[] = _T("testclass"); + +static LRESULT CALLBACK +WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HBITMAP hbmList[CURRENT_BMPS]; + static HICON hicList[CURRENT_ICONS]; + + switch (message) + { + case WM_CREATE: + { + hbmList[0] = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(100), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + hbmList[1] = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(400), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + hbmList[2] = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(800), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + hbmList[3] = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(2400), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + hicList[0] = (HICON)LoadIcon(hInst, MAKEINTRESOURCE(3200)); + break; + } + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc, hdcMem; + BITMAP bitmap; + BLENDFUNCTION bfunc; + int x = 0, y = 0, i; + hdc = BeginPaint(hWnd, &ps); + hdcMem = CreateCompatibleDC(hdc); + + bfunc.AlphaFormat = AC_SRC_ALPHA; + bfunc.BlendFlags = 0; + bfunc.BlendOp = AC_SRC_OVER; + bfunc.SourceConstantAlpha = 128; + + /* bitmaps */ + for(i = 0; i < CURRENT_BMPS; i++) + { + y = 0; + SelectObject(hdcMem, hbmList[i]); + GetObject(hbmList[i], sizeof(BITMAP), &bitmap); + + /* bit blt */ + BitBlt(hdc, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); + y += bitmap.bmHeight + OFFSET; + + /* stretch blt, org size */ + StretchBlt(hdc, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY); + y += bitmap.bmHeight + OFFSET; + + /* stretch blt, scaled */ + StretchBlt(hdc, x, y, bitmap.bmWidth*SCALE, bitmap.bmHeight*SCALE, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY); + y += bitmap.bmHeight*SCALE + OFFSET; + + /* transparent blt, transparency: grey */ + GdiTransparentBlt(hdc, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, 128*256*256+128*256+128); + y += bitmap.bmHeight + OFFSET; + + /* transparent blt, transparency: grey, scaled */ + GdiTransparentBlt(hdc, x, y, bitmap.bmWidth*SCALE, bitmap.bmHeight*SCALE, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, 128*256*256+128*256+128); + y += bitmap.bmHeight*SCALE + OFFSET; + + /* alpha blend, org size */ + GdiAlphaBlend(hdc, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, bfunc); + y += bitmap.bmHeight + OFFSET; + + /* alpha blend, scaled */ + GdiAlphaBlend(hdc, x, y, bitmap.bmWidth*SCALE, bitmap.bmHeight*SCALE, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, bfunc); + y += bitmap.bmHeight*SCALE + OFFSET; + + x += bitmap.bmWidth*SCALE + OFFSET; + } + + /* icons */ + for(i = 0; i < CURRENT_ICONS; i++) + { + y = 0; + /* pure icon */ + DrawIcon(hdc, x, y, hicList[i]); + y += bitmap.bmHeight + OFFSET; + + /* normal icon using Ex */ + DrawIconEx(hdc, x, y, hicList[i], 0, 0, 0, NULL, DI_NORMAL); + y += bitmap.bmHeight + OFFSET; + + /* normal icon using Ex with bigger size */ + DrawIconEx(hdc, x, y, hicList[i], bitmap.bmWidth, bitmap.bmHeight, 0, NULL, DI_NORMAL); + y += bitmap.bmHeight + OFFSET; + + /* only icon using Ex */ + DrawIconEx(hdc, x, y, hicList[i], 0, 0, 0, NULL, DI_IMAGE); + y += bitmap.bmHeight + OFFSET; + + /* mask using Ex */ + DrawIconEx(hdc, x, y, hicList[i], 0, 0, 0, NULL, DI_MASK); + y += bitmap.bmHeight + OFFSET; + + x += bitmap.bmWidth*SCALE + OFFSET; + } + + DeleteDC(hdcMem); + EndPaint(hWnd, &ps); + break; + } + + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + + +static ATOM +MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = NULL; + + return RegisterClassEx(&wcex); +} + + +static BOOL +InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; + + hWnd = CreateWindowEx(0, + szWindowClass, + _T("Various blit and blend operations"), + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 640, + 640, + NULL, + NULL, + hInstance, + NULL); + + if (!hWnd) + { + return FALSE; + } + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + return TRUE; +} + + +int WINAPI +_tWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + MSG msg; + + MyRegisterClass(hInstance); + + if (!InitInstance(hInstance, nCmdShow)) + { + return FALSE; + } + + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (int)msg.wParam; +} diff --git a/rostests/dibtests/vbltest/vbltest.rbuild b/rostests/dibtests/vbltest/vbltest.rbuild new file mode 100644 index 00000000000..d715469ba68 --- /dev/null +++ b/rostests/dibtests/vbltest/vbltest.rbuild @@ -0,0 +1,6 @@ + + . + user32 + gdi32 + vbltest.c + vbltest.rc diff --git a/rostests/dibtests/vbltest/vbltest.rc b/rostests/dibtests/vbltest/vbltest.rc new file mode 100644 index 00000000000..432bf1ce56b --- /dev/null +++ b/rostests/dibtests/vbltest/vbltest.rc @@ -0,0 +1,6 @@ +100 BITMAP "test_inv01.bmp" +400 BITMAP "test_inv04.bmp" +800 BITMAP "test_inv08.bmp" +2400 BITMAP "test_inv24.bmp" +3200 ICON "test_inv32.ico" + diff --git a/rostests/directory.rbuild b/rostests/directory.rbuild index 4ac30a12cf2..271e54152ae 100644 --- a/rostests/directory.rbuild +++ b/rostests/directory.rbuild @@ -4,11 +4,17 @@ + + + - - + + + + + diff --git a/rostests/drivers/csqtest/csqtest.rbuild b/rostests/drivers/csqtest/csqtest.rbuild index 4dd069c942c..222924a0ab0 100644 --- a/rostests/drivers/csqtest/csqtest.rbuild +++ b/rostests/drivers/csqtest/csqtest.rbuild @@ -1,6 +1,5 @@ - include/reactos/drivers ntoskrnl hal diff --git a/rostests/drivers/directory.rbuild b/rostests/drivers/directory.rbuild index f989e45510e..322935ee2f4 100644 --- a/rostests/drivers/directory.rbuild +++ b/rostests/drivers/directory.rbuild @@ -7,6 +7,9 @@ + + + diff --git a/rostests/drivers/kmtest/deviface_test.c b/rostests/drivers/kmtest/deviface_test.c index 3dcb580528a..4d92e06df24 100644 --- a/rostests/drivers/kmtest/deviface_test.c +++ b/rostests/drivers/kmtest/deviface_test.c @@ -31,8 +31,8 @@ /* PRIVATE FUNCTIONS **********************************************************/ -NTSTATUS NTAPI -(*IoGetDeviceInterfaces_Func)( +NTSTATUS +(NTAPI *IoGetDeviceInterfaces_Func)( IN CONST GUID *InterfaceClassGuid, IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL, IN ULONG Flags, diff --git a/rostests/drivers/kmtest/devobj_test.c b/rostests/drivers/kmtest/devobj_test.c new file mode 100644 index 00000000000..00e96cea36d --- /dev/null +++ b/rostests/drivers/kmtest/devobj_test.c @@ -0,0 +1,266 @@ +/* + * Driver Regression Tests + * + * Copyright 2009 Michael Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* INCLUDES *******************************************************************/ + +#include "kmtest.h" +#include +#include +#include "ntddser.h" +#include "ntndk.h" + +VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT DeviceObject, BOOLEAN UnLoading) +{ + PDEVICE_OBJECT RetObject; + + RetObject = IoGetLowerDeviceObject(DeviceObject); + + if (UnLoading) + { + ok(RetObject == 0, + "Expected no Lower DeviceObject, got %p", RetObject); + } + else + { + ok(RetObject == AttachDeviceObject, + "Expected an Attached DeviceObject %p, got %p", AttachDeviceObject, RetObject); + } + + if (RetObject) + { + ObDereferenceObject(RetObject); + } + + RetObject = IoGetDeviceAttachmentBaseRef(DeviceObject); + ok(RetObject == DeviceObject, + "Expected an Attached DeviceObject %p, got %p", DeviceObject, RetObject); + + if (RetObject) + { + ObDereferenceObject(RetObject); + } + +} +VOID DeviceCreatedTest(PDEVICE_OBJECT DeviceObject, BOOLEAN ExclusiveAccess) +{ + PEXTENDED_DEVOBJ_EXTENSION extdev; + + /*Check the device object members */ + ok(DeviceObject->Type==3, "Expected Type = 3, got %x", DeviceObject->Type); + ok(DeviceObject->Size = 0xb8, "Expected Size = 0xba, got %x", DeviceObject->Size); + ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu", + DeviceObject->ReferenceCount); + ok(DeviceObject->DriverObject == ThisDriverObject, + "Expected DriverObject member to match this DriverObject %p, got %p", + ThisDriverObject, DeviceObject->DriverObject); + ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p", DeviceObject->NextDevice); + ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p", DeviceObject->AttachedDevice); + ok(DeviceObject->Characteristics == 0, "Expected Characteristics to be 0"); + if (ExclusiveAccess) + { + ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING | DO_EXCLUSIVE)), + "Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING | DO_EXCLUSIVE, got %lu", DeviceObject->Flags); + } + else + { + ok((DeviceObject->Flags == (DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING)), + "Expected Flags DO_DEVICE_HAS_NAME | DO_DEVICE_INITIALIZING, got %lu", DeviceObject->Flags); + } + ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN, + "Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu", + DeviceObject->DeviceType); + ok(DeviceObject->ActiveThreadCount == 0, "Expected ActiveThreadCount = 0, got %lu\n", DeviceObject->ActiveThreadCount); + + /*Check the extended extension */ + extdev = (PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension; + ok(extdev->ExtensionFlags == 0, "Expected Extended ExtensionFlags to be 0, got %lu", extdev->ExtensionFlags); + ok (extdev->Type == 13, "Expected Type of 13, got %d", extdev->Type); + ok (extdev->Size == 0, "Expected Size of 0, got %d", extdev->Size); + ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p", + DeviceObject, extdev->DeviceObject); + ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p", extdev->AttachedTo); + ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu", extdev->StartIoCount); + ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu", extdev->StartIoKey); + ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu", extdev->StartIoFlags); +} + +VOID DeviceDeletionTest(PDEVICE_OBJECT DeviceObject, BOOLEAN Lower) +{ + PEXTENDED_DEVOBJ_EXTENSION extdev; + + /*Check the device object members */ + ok(DeviceObject->Type==3, "Expected Type = 3, got %d", DeviceObject->Type); + ok(DeviceObject->Size = 0xb8, "Expected Size = 0xba, got %d", DeviceObject->Size); + ok(DeviceObject->ReferenceCount == 0, "Expected ReferenceCount = 0, got %lu", + DeviceObject->ReferenceCount); + if (!Lower) + { + ok(DeviceObject->DriverObject == ThisDriverObject, + "Expected DriverObject member to match this DriverObject %p, got %p", + ThisDriverObject, DeviceObject->DriverObject); + } + ok(DeviceObject->NextDevice == NULL, "Expected NextDevice to be NULL, got %p", DeviceObject->NextDevice); + + if (Lower) + { + ok(DeviceObject->AttachedDevice == MainDeviceObject, + "Expected AttachDevice to be %p, got %p", MainDeviceObject, DeviceObject->AttachedDevice); + } + else + { + ok(DeviceObject->AttachedDevice == NULL, "Expected AttachDevice to be NULL, got %p", DeviceObject->AttachedDevice); + } + + ok(DeviceObject->Flags ==FILE_VIRTUAL_VOLUME, + "Expected Flags FILE_VIRTUAL_VOLUME, got %lu", DeviceObject->Flags); + ok(DeviceObject->DeviceType == FILE_DEVICE_UNKNOWN, + "Expected DeviceType to match creation parameter FILE_DEVICE_UNKNWOWN, got %lu", + DeviceObject->DeviceType); + ok(DeviceObject->ActiveThreadCount == 0, "Expected ActiveThreadCount = 0, got %lu\n", DeviceObject->ActiveThreadCount); + + /*Check the extended extension */ + extdev = (PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension; + ok(extdev->ExtensionFlags == DOE_UNLOAD_PENDING, + "Expected Extended ExtensionFlags to be DOE_UNLOAD_PENDING, got %lu", extdev->ExtensionFlags); + ok (extdev->Type == 13, "Expected Type of 13, got %d", extdev->Type); + ok (extdev->Size == 0, "Expected Size of 0, got %d", extdev->Size); + ok (extdev->DeviceObject == DeviceObject, "Expected DeviceOject to match newly created device %p, got %p", + DeviceObject, extdev->DeviceObject); + if (Lower) + { + /* Skip this for now */ + //ok(extdev->AttachedTo == MainDeviceObject, "Expected AttachTo to %p, got %p", MainDeviceObject, extdev->AttachedTo); + } + else + { + ok(extdev->AttachedTo == NULL, "Expected AttachTo to be NULL, got %p", extdev->AttachedTo); + } + ok(extdev->StartIoCount == 0, "Expected StartIoCount = 0, got %lu", extdev->StartIoCount); + ok(extdev->StartIoKey == 0, "Expected StartIoKey = 0, got %lu", extdev->StartIoKey); + ok(extdev->StartIoFlags == 0, "Expected StartIoFlags = 0, got %lu", extdev->StartIoFlags); +} + +VOID DeviceCreateDeleteTest(PDRIVER_OBJECT DriverObject) +{ + NTSTATUS Status; + UNICODE_STRING DeviceString; + UNICODE_STRING DosDeviceString; + PDEVICE_OBJECT DeviceObject; + + /* Create using wrong directory */ + RtlInitUnicodeString(&DeviceString, L"\\Device1\\Kmtest"); + Status = IoCreateDevice(DriverObject, + 0, + &DeviceString, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &DeviceObject); + ok(Status == STATUS_OBJECT_PATH_NOT_FOUND, "Expected STATUS_OBJECT_PATH_NOT_FOUND, got 0x%lX", Status); + + /* Create using correct params with exlusice access */ + RtlInitUnicodeString(&DeviceString, L"\\Device\\Kmtest"); + Status = IoCreateDevice(DriverObject, + 0, + &DeviceString, + FILE_DEVICE_UNKNOWN, + 0, + TRUE, + &DeviceObject); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + DeviceCreatedTest(DeviceObject, TRUE); + + /* Delete the device */ + if (NT_SUCCESS(Status)) + { + IoDeleteDevice(DeviceObject); + ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p", + DriverObject->DeviceObject); + } + + /* Create using correct params with exlusice access */ + Status = IoCreateDevice(DriverObject, + 0, + &DeviceString, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &DeviceObject); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + DeviceCreatedTest(DeviceObject, FALSE); + + /* Delete the device */ + if (NT_SUCCESS(Status)) + { + IoDeleteDevice(DeviceObject); + ok(DriverObject->DeviceObject == 0, "Expected DriverObject->DeviceObject to be NULL, got %p", + DriverObject->DeviceObject); + } + + /* Recreate device */ + Status = IoCreateDevice(DriverObject, + 0, + &DeviceString, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &DeviceObject); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + RtlInitUnicodeString(&DosDeviceString, L"\\DosDevices\\kmtest"); + Status = IoCreateSymbolicLink(&DosDeviceString, &DeviceString); + + if (!NT_SUCCESS(Status)) + { + /* Delete device object if not successful */ + IoDeleteDevice(DeviceObject); + return; + } + + MainDeviceObject = DeviceObject; + + return; +} + +BOOLEAN AttachDeviceTest(PDEVICE_OBJECT DeviceObject, PWCHAR NewDriverRegPath) +{ + NTSTATUS Status; + UNICODE_STRING LowerDeviceName; + + RtlInitUnicodeString(&LowerDeviceName, NewDriverRegPath); + Status = IoAttachDevice(DeviceObject, &LowerDeviceName, &AttachDeviceObject); + + /* TODO: Add more tests */ + + return TRUE; +} + +BOOLEAN DetachDeviceTest(PDEVICE_OBJECT AttachedDevice) +{ + + IoDetachDevice(AttachedDevice); + + /* TODO: Add more tests */ + + return TRUE; +} diff --git a/rostests/drivers/kmtest/drvobj_test.c b/rostests/drivers/kmtest/drvobj_test.c new file mode 100644 index 00000000000..ad3675a6c2a --- /dev/null +++ b/rostests/drivers/kmtest/drvobj_test.c @@ -0,0 +1,141 @@ +/* + * Driver Regression Tests + * + * Copyright 2009 Michael Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* INCLUDES *******************************************************************/ + +#include "kmtest.h" +#include +#include + +VOID DriverObjectTest(PDRIVER_OBJECT DriverObject, int DriverStatus) +{ + BOOLEAN CheckThisDispatchRoutine; + PVOID FirstMajorFunc; + int i; + + ok(DriverObject->Size == sizeof(DRIVER_OBJECT), "Size does not match, got %x",DriverObject->Size); + ok(DriverObject->Type == 4, "Type does not match 4. got %d",DriverObject->Type); + + if (DriverStatus == 0) + { + ok(DriverObject->DeviceObject == NULL, "Expected DeviceObject pointer to be 0, got %p", + DriverObject->DeviceObject); + ok (DriverObject->Flags == DRVO_LEGACY_DRIVER, + "Expected Flags to be DRVO_LEGACY_DRIVER, got %lu", + DriverObject->Flags); + } + else if (DriverStatus == 1) + { + ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null"); + ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED), + "Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED, got %lu", + DriverObject->Flags); + } + else + { + ok(DriverObject->DeviceObject != NULL, "Expected DeviceObject pointer to non null"); + ok (DriverObject->Flags == (DRVO_LEGACY_DRIVER | DRVO_INITIALIZED | DRVO_UNLOAD_INVOKED), + "Expected Flags to be DRVO_LEGACY_DRIVER | DRVO_INITIALIZED | DRVO_UNLOAD_INVOKED, got %lu", + DriverObject->Flags); + } + + /* Select a routine that was not changed */ + FirstMajorFunc = DriverObject->MajorFunction[1]; + ok(FirstMajorFunc != 0, "Expected MajorFunction[1] to be non NULL"); + + if (FirstMajorFunc) + { + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + { + if (DriverStatus > 0) CheckThisDispatchRoutine = (i > 3) && (i != 14); + else CheckThisDispatchRoutine = TRUE; + + if (CheckThisDispatchRoutine) + { + ok(DriverObject->MajorFunction[i] == FirstMajorFunc, "Expected MajorFunction[%d] to match %p", + i, FirstMajorFunc); + } + } + } + else + { + ok(TRUE, "Skipped testing for all MajorFunction"); + } +} + +BOOLEAN ZwLoadTest(PDRIVER_OBJECT DriverObject, PUNICODE_STRING DriverRegistryPath, PWCHAR NewDriverRegPath) +{ + UNICODE_STRING RegPath; + NTSTATUS Status; + + /* Try to load ourself */ + Status = ZwLoadDriver(DriverRegistryPath); + ok (Status == STATUS_IMAGE_ALREADY_LOADED, "Expected NTSTATUS STATUS_IMAGE_ALREADY_LOADED, got 0x%lX", Status); + + if (Status != STATUS_IMAGE_ALREADY_LOADED) + { + DbgPrint("WARNING: Loading this a second time will cause BUGCHECK!\n"); + } + + /* Try to load with a Registry Path that doesnt exist */ + RtlInitUnicodeString(&RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\deadbeef"); + Status = ZwLoadDriver(&RegPath); + ok (Status == STATUS_OBJECT_NAME_NOT_FOUND, "Expected NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND, got 0x%lX", Status); + + /* Load the driver */ + RtlInitUnicodeString(&RegPath, NewDriverRegPath); + Status = ZwLoadDriver(&RegPath); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + return TRUE; +} + +BOOLEAN ZwUnloadTest(PDRIVER_OBJECT DriverObject, PUNICODE_STRING DriverRegistryPath, PWCHAR NewDriverRegPath) +{ + UNICODE_STRING RegPath; + NTSTATUS Status; + + /* Try to unload ourself, which should fail as our Unload routine hasnt been set yet. */ + Status = ZwUnloadDriver(DriverRegistryPath); + ok (Status == STATUS_INVALID_DEVICE_REQUEST, "Expected NTSTATUS STATUS_INVALID_DEVICE_REQUEST, got 0x%lX", Status); + + /* Try to unload with a Registry Path that doesnt exist */ + RtlInitUnicodeString(&RegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\deadbeef"); + Status = ZwUnloadDriver(&RegPath); + ok (Status == STATUS_OBJECT_NAME_NOT_FOUND, "Expected NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND, got 0x%lX", Status); + + /* Unload the driver */ + RtlInitUnicodeString(&RegPath, NewDriverRegPath); + Status = ZwUnloadDriver(&RegPath); + ok(Status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got 0x%lX", Status); + + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + return TRUE; +} diff --git a/rostests/drivers/kmtest/kmtest.c b/rostests/drivers/kmtest/kmtest.c index 77fc9c093db..948797a3273 100644 --- a/rostests/drivers/kmtest/kmtest.c +++ b/rostests/drivers/kmtest/kmtest.c @@ -40,7 +40,7 @@ StartTest() VOID FinishTest(LPSTR TestName) { - DbgPrint("Test %s finished with %d succeses and %d failures\n", TestName, successes, failures); + DbgPrint("%s: %d test executed (0 marked as todo, %d failures), 0 skipped.\n", TestName, successes + failures, failures); } void kmtest_set_location(const char* file, int line) @@ -100,14 +100,99 @@ int kmtest_ok(int condition, const char *msg, ... ) /* PUBLIC FUNCTIONS ***********************************************************/ +PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriver); + /* * Test Declarations */ -VOID NtoskrnlIoMdlTest(); -VOID NtoskrnlIoDeviceInterface(); +VOID NtoskrnlIoTests(); VOID NtoskrnlObTest(); VOID NtoskrnlExecutiveTests(); VOID NtoskrnlPoolsTest(); +VOID DriverObjectTest(PDRIVER_OBJECT, int); +VOID DeviceCreateDeleteTest(PDRIVER_OBJECT); +VOID DeviceObjectTest(PDEVICE_OBJECT); +BOOLEAN ZwLoadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR); +BOOLEAN ZwUnloadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR); +BOOLEAN DetachDeviceTest(PDEVICE_OBJECT); +BOOLEAN AttachDeviceTest(PDEVICE_OBJECT, PWCHAR); +VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT, BOOLEAN); + +/* + * KmtestDispatch + */ +NTSTATUS +NTAPI +KmtestDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) + +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (AttachDeviceObject) + { + IoSkipCurrentIrpStackLocation(Irp); + Status = IoCallDriver(AttachDeviceObject, Irp); + return Status; + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +/* + * KmtestCreateClose + */ +NTSTATUS +NTAPI +KmtestCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (AttachDeviceObject) + { + IoSkipCurrentIrpStackLocation(Irp); + Status = IoCallDriver(AttachDeviceObject, Irp); + return Status; + } + + /* Do DriverObject Test with Driver Initialized */ + DriverObjectTest(DeviceObject->DriverObject, 1); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information=0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +/* + * KmtestUnload + */ +VOID +NTAPI +KmtestUnload(IN PDRIVER_OBJECT DriverObject) +{ + UNICODE_STRING DosDeviceString; + + if(AttachDeviceObject) + { + IoDetachDevice(AttachDeviceObject); + } + + /* Do DriverObject Test for Unload */ + DriverObjectTest(DriverObject, 2); + + if (MainDeviceObject) + { + RtlInitUnicodeString(&DosDeviceString, L"\\DosDevices\\Kmtest"); + IoDeleteSymbolicLink(&DosDeviceString); + + IoDeleteDevice(MainDeviceObject); + } + FinishTest("Driver Tests"); +} /* * DriverEntry @@ -117,13 +202,70 @@ NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { - DbgPrint("\n===============================================\nKernel Mode Regression Test driver starting...\n"); - //NtoskrnlExecutiveTests(); - //NtoskrnlIoDeviceInterface(); - //NtoskrnlIoMdlTest(); - //NtoskrnlObTest(); - //NtoskrnlObTest(); + int i; + PWCHAR LowerDriverRegPath; + + DbgPrint("\n===============================================\n"); + DbgPrint("Kernel Mode Regression Driver Test starting...\n"); + DbgPrint("===============================================\n"); + + MainDeviceObject = NULL; + AttachDeviceObject = NULL; + ThisDriverObject = DriverObject; + + NtoskrnlExecutiveTests(); + NtoskrnlIoTests(); + NtoskrnlObTest(); NtoskrnlPoolsTest(); + /* Start the tests for the driver routines */ + StartTest(); + + /* Do DriverObject Test for Driver Entry */ + DriverObjectTest(DriverObject, 0); + /* Create and delete device, on return MainDeviceObject has been created */ + DeviceCreateDeleteTest(DriverObject); + + /* Make sure a device object was created */ + if (MainDeviceObject) + { + LowerDriverRegPath = CreateLowerDeviceRegistryKey(RegistryPath, L"kmtestassist"); + + if (LowerDriverRegPath) + { + /* Load driver test and load the lower driver */ + if (ZwLoadTest(DriverObject, RegistryPath, LowerDriverRegPath)) + { + AttachDeviceTest(MainDeviceObject, L"kmtestassists"); + if (AttachDeviceObject) + { + LowerDeviceKernelAPITest(MainDeviceObject, FALSE); + } + + /* Unload lower driver without detaching from its device */ + ZwUnloadTest(DriverObject, RegistryPath, LowerDriverRegPath); + LowerDeviceKernelAPITest(MainDeviceObject, TRUE); + } + else + { + DbgPrint("Failed to load kmtestassist driver\n"); + } + } + } + else + { + return STATUS_UNSUCCESSFUL; + } + + /* Set all MajorFunctions to NULL to verify that kernel fixes them */ + for (i = 1; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + DriverObject->MajorFunction[i] = NULL; + + /* Set necessary routines */ + DriverObject->DriverUnload = KmtestUnload; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KmtestDispatch; + DriverObject->MajorFunction[IRP_MJ_CREATE] = KmtestCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = KmtestCreateClose; + return STATUS_SUCCESS; } diff --git a/rostests/drivers/kmtest/kmtest.h b/rostests/drivers/kmtest/kmtest.h index 658bf8b513b..a0f20d3405d 100644 --- a/rostests/drivers/kmtest/kmtest.h +++ b/rostests/drivers/kmtest/kmtest.h @@ -4,6 +4,8 @@ #include #include #include +#include "ntddk.h" + /* Some macros, structs, and vars are based or inspired from the great @@ -45,4 +47,8 @@ extern int kmtest_ok( int condition, const char *msg, ... ); #define ok_(file, line) (kmtest_set_location(file, line), 0) ? 0 : kmtest_ok #define ok ok_(__FILE__, __LINE__) +PDEVICE_OBJECT AttachDeviceObject; +PDEVICE_OBJECT MainDeviceObject; +PDRIVER_OBJECT ThisDriverObject; + #endif /* PNPTEST_H */ diff --git a/rostests/drivers/kmtest/kmtest.rbuild b/rostests/drivers/kmtest/kmtest.rbuild index 23a65549f62..e45f8a6baea 100644 --- a/rostests/drivers/kmtest/kmtest.rbuild +++ b/rostests/drivers/kmtest/kmtest.rbuild @@ -1,12 +1,15 @@ - include/reactos/drivers ntoskrnl hal + pseh kmtest.c deviface.c deviface_test.c + drvobj_test.c + devobj_test.c + reghelper.c ntos_ex.c ntos_io.c ntos_ob.c diff --git a/rostests/drivers/kmtest/kmtestassist.c b/rostests/drivers/kmtest/kmtestassist.c new file mode 100644 index 00000000000..eaa3bfc7e35 --- /dev/null +++ b/rostests/drivers/kmtest/kmtestassist.c @@ -0,0 +1,97 @@ +/* + * Driver Regression Tests + * + * Copyright 2009 Michael Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* INCLUDES *******************************************************************/ + +#include "ntddk.h" +#include "ntddser.h" + +NTSTATUS +NTAPI +DriverDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) +{ + DbgPrint(" ControlCode %x\n",IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode); + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information=0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +DriverCreateClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) +{ + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; +} + +VOID +NTAPI +DriverUnload(IN PDRIVER_OBJECT DriverObject) +{ + UNICODE_STRING DeviceString; + + RtlInitUnicodeString(&DeviceString, L"\\DosDevices\\kmtestassist"); + IoDeleteSymbolicLink(&DeviceString); + + IoDeleteDevice(DriverObject->DeviceObject); +} + +NTSTATUS +NTAPI +DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING path) +{ + PDEVICE_OBJECT pDeviceObject; + UNICODE_STRING DriverString; + UNICODE_STRING DeviceString; + + NTSTATUS Status= STATUS_DEVICE_CONFIGURATION_ERROR; + + RtlInitUnicodeString(&DriverString, L"\\Device\\kmtestassist"); + + Status = IoCreateDevice(DriverObject,0,&DriverString,FILE_DEVICE_UNKNOWN,0,FALSE,&pDeviceObject); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + RtlInitUnicodeString(&DeviceString, L"\\DosDevices\\kmtestassist"); + + Status = IoCreateSymbolicLink(&DeviceString, &DriverString); + if (!NT_SUCCESS(Status)) + { + // Delete device object if not successful + IoDeleteDevice(pDeviceObject); + return Status; + } + + DriverObject->DriverUnload = DriverUnload; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch; + DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose; + + return Status; +} diff --git a/rostests/drivers/kmtest/kmtestassist.rbuild b/rostests/drivers/kmtest/kmtestassist.rbuild new file mode 100644 index 00000000000..c50f7bf89e1 --- /dev/null +++ b/rostests/drivers/kmtest/kmtestassist.rbuild @@ -0,0 +1,7 @@ + + + include/reactos/drivers + ntoskrnl + hal + kmtestassist.c + diff --git a/rostests/drivers/kmtest/ntos_ex.c b/rostests/drivers/kmtest/ntos_ex.c index 73f47c65f66..84d6859ab51 100644 --- a/rostests/drivers/kmtest/ntos_ex.c +++ b/rostests/drivers/kmtest/ntos_ex.c @@ -39,8 +39,8 @@ TestTimerApcRoutine(IN PVOID TimerContext, IN LONG TimerHighValue) { - DPRINT("Timer Apc called!\n"); ULONG *ApcCount = (ULONG *)TimerContext; + DPRINT("Timer Apc called!\n"); (*ApcCount)++; } diff --git a/rostests/drivers/kmtest/ntos_io.c b/rostests/drivers/kmtest/ntos_io.c index 9a662d22992..986098edc7d 100644 --- a/rostests/drivers/kmtest/ntos_io.c +++ b/rostests/drivers/kmtest/ntos_io.c @@ -3,6 +3,7 @@ * ReactOS Kernel Mode Regression Testing framework * * Copyright 2006 Aleksey Bragin + * Copyright 2008 Etersoft (Alexander Morozov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,6 +29,9 @@ #define NDEBUG #include "debug.h" +VOID NtoskrnlIoDeviceInterface(); + + /* PUBLIC FUNCTIONS ***********************************************************/ VOID NtoskrnlIoMdlTest() @@ -44,7 +48,7 @@ VOID NtoskrnlIoMdlTest() ok(Mdl == NULL, "IoAllocateMdl should fail allocation of 2Gb or more, but got Mdl=0x%X", - (UINT)Mdl); + (UINT32)Mdl); if (Mdl) IoFreeMdl(Mdl); @@ -55,10 +59,10 @@ VOID NtoskrnlIoMdlTest() ok(Mdl != NULL, "Mdl allocation failed"); // Check fields of the allocated struct ok(Mdl->Next == NULL, "Mdl->Next should be NULL, but is 0x%X", - (UINT)Mdl->Next); + (UINT32)Mdl->Next); ok(Mdl->ByteCount == MdlSize, "Mdl->ByteCount should be equal to MdlSize, but is 0x%X", - (UINT)Mdl->ByteCount); + (UINT32)Mdl->ByteCount); // TODO: Check other fields of MDL struct IoFreeMdl(Mdl); @@ -68,7 +72,7 @@ VOID NtoskrnlIoMdlTest() Mdl = IoAllocateMdl(VirtualAddress, MdlSize, FALSE, FALSE, Irp); ok(Mdl != NULL, "Mdl allocation failed"); ok(Irp->MdlAddress == Mdl, "Irp->MdlAddress should be 0x%X, but is 0x%X", - (UINT)Mdl, (UINT)Irp->MdlAddress); + (UINT32)Mdl, (UINT32)Irp->MdlAddress); IoFreeMdl(Mdl); @@ -79,3 +83,95 @@ VOID NtoskrnlIoMdlTest() FinishTest("NTOSKRNL Io Mdl"); } + +VOID NtoskrnlIoIrpTest() +{ + USHORT size; + IRP *iorp; + + StartTest(); + + // 1st test + size = sizeof(IRP) + 5 * sizeof(IO_STACK_LOCATION); + iorp = ExAllocatePool(NonPagedPool, size); + + if (NULL != iorp) + { + IoInitializeIrp(iorp, size, 5); + + ok(6 == iorp->Type, "Irp type should be 6, but got %d\n", iorp->Type); + ok(iorp->Size == size, "Irp size should be %d, but got %d\n", + iorp->Size, size); + ok(5 == iorp->StackCount, "Irp StackCount should be 5, but got %d\n", + iorp->StackCount); + ok(6 == iorp->CurrentLocation, "Irp CurrentLocation should be 6, but got %d\n", + iorp->CurrentLocation); + ok(IsListEmpty(&iorp->ThreadListEntry), "IRP thread list is not empty\n"); + ok ((PIO_STACK_LOCATION)(iorp + 1) + 5 == + iorp->Tail.Overlay.CurrentStackLocation, + "CurrentStackLocation mismatch\n"); + + ExFreePool(iorp); + } + + // 2nd test + size = sizeof(IRP) + 2 * sizeof(IO_STACK_LOCATION); + iorp = IoAllocateIrp(2, FALSE); + + if (NULL != iorp) + { + ok(6 == iorp->Type, "Irp type should be 6, but got %d\n", iorp->Type); + ok(iorp->Size >= size, + "Irp size should be more or equal to %d, but got %d\n", + iorp->Size, size); + ok(2 == iorp->StackCount, "Irp StackCount should be 2, but got %d\n", + iorp->StackCount); + ok(3 == iorp->CurrentLocation, "Irp CurrentLocation should be 3, but got %d\n", + iorp->CurrentLocation); + ok(IsListEmpty(&iorp->ThreadListEntry), "IRP thread list is not empty\n"); + ok ((PIO_STACK_LOCATION)(iorp + 1) + 2 == + iorp->Tail.Overlay.CurrentStackLocation, + "CurrentStackLocation mismatch\n"); + ok((IRP_ALLOCATED_FIXED_SIZE & iorp->AllocationFlags), + "IRP Allocation flags lack fixed size attribute\n"); + ok(!(IRP_LOOKASIDE_ALLOCATION & iorp->AllocationFlags), + "IRP Allocation flags should not have lookaside allocation\n"); + + IoFreeIrp(iorp); + } + + // 3rd test + size = sizeof(IRP) + 2 * sizeof(IO_STACK_LOCATION); + iorp = IoAllocateIrp(2, TRUE); + + if (NULL != iorp) + { + ok(6 == iorp->Type, "Irp type should be 6, but got %d\n", iorp->Type); + ok(iorp->Size >= size, + "Irp size should be more or equal to %d, but got %d\n", + iorp->Size, size); + ok(2 == iorp->StackCount, "Irp StackCount should be 2, but got %d\n", + iorp->StackCount); + ok(3 == iorp->CurrentLocation, "Irp CurrentLocation should be 3, but got %d\n", + iorp->CurrentLocation); + ok(IsListEmpty(&iorp->ThreadListEntry), "IRP thread list is not empty\n"); + ok ((PIO_STACK_LOCATION)(iorp + 1) + 2 == + iorp->Tail.Overlay.CurrentStackLocation, + "CurrentStackLocation mismatch\n"); + ok((IRP_ALLOCATED_FIXED_SIZE & iorp->AllocationFlags), + "IRP Allocation flags lack fixed size attribute\n"); + ok((IRP_LOOKASIDE_ALLOCATION & iorp->AllocationFlags), + "IRP Allocation flags lack lookaside allocation\n"); + + IoFreeIrp(iorp); + } + + FinishTest("NTOSKRNL Io Irp"); +} + +VOID NtoskrnlIoTests() +{ + NtoskrnlIoMdlTest(); + NtoskrnlIoDeviceInterface(); + NtoskrnlIoIrpTest(); +} diff --git a/rostests/drivers/kmtest/ntos_pools.c b/rostests/drivers/kmtest/ntos_pools.c index e12fdbadd2c..816d7c325f3 100644 --- a/rostests/drivers/kmtest/ntos_pools.c +++ b/rostests/drivers/kmtest/ntos_pools.c @@ -25,12 +25,14 @@ #include #include #include +/* SEH support with PSEH */ +#include #include "kmtest.h" //#define NDEBUG #include "debug.h" -#define TAG_POOLTEST TAG('P','t','s','t') +#define TAG_POOLTEST 'tstP' /* PRIVATE FUNCTIONS ***********************************************************/ @@ -125,10 +127,61 @@ PoolsTest() FinishTest("NTOSKRNL Pools Tests"); } +VOID +PoolsCorruption() +{ + PULONG Ptr, TestPtr; + ULONG AllocSize; + NTSTATUS Status = STATUS_SUCCESS; + + StartTest(); + + // start with non-paged pool + AllocSize = 4096 + 0x10; + Ptr = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST); + + // touch all bytes, it shouldn't cause an exception + RtlZeroMemory(Ptr, AllocSize); + + // test buffer overrun, right after our allocation ends + _SEH2_TRY + { + TestPtr = (PULONG)((PUCHAR)Ptr + AllocSize); + //Ptr[4] = 0xd33dbeef; + *TestPtr = 0xd33dbeef; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Get the status */ + Status = _SEH2_GetExceptionCode(); + } _SEH2_END; + + ok(Status == STATUS_ACCESS_VIOLATION, "Exception should occur, but got Status 0x%08lX\n", Status); + + // test overrun in a distant byte range, but within 4096KB + _SEH2_TRY + { + Ptr[2020] = 0xdeadb33f; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Get the status */ + Status = _SEH2_GetExceptionCode(); + } _SEH2_END; + + ok(Status == STATUS_ACCESS_VIOLATION, "Exception should occur, but got Status 0x%08lX\n", Status); + + // free the pool + ExFreePoolWithTag(Ptr, TAG_POOLTEST); + + FinishTest("NTOSKRNL Pool Corruption"); +} + /* PUBLIC FUNCTIONS ***********************************************************/ VOID NtoskrnlPoolsTest() { PoolsTest(); + //PoolsCorruption(); } diff --git a/rostests/drivers/kmtest/reghelper.c b/rostests/drivers/kmtest/reghelper.c new file mode 100644 index 00000000000..c3a54d67ef3 --- /dev/null +++ b/rostests/drivers/kmtest/reghelper.c @@ -0,0 +1,219 @@ +/* + * Driver Regression Tests + * + * Copyright 2009 Michael Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* INCLUDES *******************************************************************/ + +#include "kmtest.h" + +/* + Adds a service registry entry for a driver + The driver must reside in the same path as this loaded driver + The caller is resposible for releasing memory +*/ +PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriver) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING Name; + UNICODE_STRING Value; + UNICODE_STRING NewDriverRegPath; + PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInfo = NULL; + HANDLE ServiceKey; + NTSTATUS Status; + ULONG Disposition; + ULONG ServiceDWordValue; + ULONG ResultLength = 0; + ULONG Length = 0; + PWCHAR ReturnPath = NULL; + /* Now lets find out where we were loaded from by using registry */ + InitializeObjectAttributes(&ObjectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = ZwOpenKey(&ServiceKey, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwOpenKey () failed (Status %x)\n", Status); + return NULL; + } + + RtlInitUnicodeString(&Name, L"ImagePath"); + + /* First query how much memory we need */ + Status = ZwQueryValueKey(ServiceKey, &Name, KeyValuePartialInformation, 0, 0, &ResultLength); + + ResultLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION); + ValuePartialInfo = ExAllocatePool(PagedPool, ResultLength); + if (!ValuePartialInfo) + { + DbgPrint("Out of memory!\n"); + goto cleanup; + } + + Length = ResultLength; + Status = ZwQueryValueKey(ServiceKey, &Name, KeyValuePartialInformation, (PVOID)ValuePartialInfo, Length, &ResultLength); + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwQueryValueKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + /* Remove the current driver name from the string */ + /* FIXME: Dont use hard coded driver name, determine it from the string returned from the above Query */ + Length = (wcslen((PWCHAR)ValuePartialInfo->Data) * 2) - (wcslen(L"kmtest.sys") * 2); + RtlZeroMemory((PVOID)((ULONG)ValuePartialInfo->Data + Length), + wcslen(L"drvtests.sys") * 2); + ZwClose(ServiceKey); + + /* Now add a registry entry for the driver */ + + NewDriverRegPath.Length = 0; + NewDriverRegPath.MaximumLength = (wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + + wcslen(NewDriver) + 1) * sizeof(WCHAR); + NewDriverRegPath.Buffer = ExAllocatePool(PagedPool, NewDriverRegPath.MaximumLength); + if (!NewDriverRegPath.Buffer) + { + DbgPrint("Out of memory!\n"); + ExFreePool(NewDriverRegPath.Buffer); + goto cleanup; + } + + RtlAppendUnicodeToString(&NewDriverRegPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); + RtlAppendUnicodeToString(&NewDriverRegPath, NewDriver); + + InitializeObjectAttributes(&ObjectAttributes, + &NewDriverRegPath, + OBJ_CASE_INSENSITIVE | OBJ_OPENIF, + 0, + NULL); + + Status = ZwCreateKey(&ServiceKey, + KEY_ALL_ACCESS, + &ObjectAttributes, + 0, + NULL, + REG_OPTION_VOLATILE, + &Disposition); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + ExFreePool(NewDriverRegPath.Buffer); + goto cleanup; + } + + ReturnPath = NewDriverRegPath.Buffer; + RtlInitUnicodeString(&Name, L"ImagePath"); + + Value.Length = 0; + Value.MaximumLength = (wcslen((PWCHAR)ValuePartialInfo->Data) + + wcslen(NewDriver) + 5) * sizeof(WCHAR); + Value.Buffer = ExAllocatePool(PagedPool, Value.MaximumLength); + + if (!Value.Buffer) + { + DbgPrint("Out of memory!\n"); + ExFreePool(Value.Buffer); + goto cleanup; + } + + RtlAppendUnicodeToString(&Value, (PWCHAR)ValuePartialInfo->Data); + RtlAppendUnicodeToString(&Value, NewDriver); + RtlAppendUnicodeToString(&Value, L".sys"); + + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_SZ, + Value.Buffer, + (wcslen(Value.Buffer)+1) * sizeof(WCHAR)); + ExFreePool(Value.Buffer); + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + RtlInitUnicodeString(&Name, L"DisplayName"); + RtlInitUnicodeString(&Value, NewDriver); + + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_SZ, + Value.Buffer, + (wcslen(Value.Buffer)+1) * sizeof(WCHAR)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + RtlInitUnicodeString(&Name, L"ErrorControl"); + ServiceDWordValue = 0; + + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_DWORD, + &ServiceDWordValue, + sizeof(ULONG)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + RtlInitUnicodeString(&Name, L"Start"); + ServiceDWordValue = 3; + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_DWORD, + &ServiceDWordValue, + sizeof(ULONG)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + + RtlInitUnicodeString(&Name, L"Type"); + ServiceDWordValue = 0; + Status = ZwSetValueKey(ServiceKey, + &Name, + 0, + REG_DWORD, + &ServiceDWordValue, + sizeof(ULONG)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint("ZwCreateKey() failed (Status %lx)\n", Status); + goto cleanup; + } + +cleanup: + ZwClose(ServiceKey); + if (ValuePartialInfo) ExFreePool(ValuePartialInfo); + + return ReturnPath; + +} diff --git a/rostests/drivers/memtest/memtest.c b/rostests/drivers/memtest/memtest.c index 823ce8cf24b..8d20747b75b 100644 --- a/rostests/drivers/memtest/memtest.c +++ b/rostests/drivers/memtest/memtest.c @@ -47,7 +47,7 @@ MonitorThread(PVOID Ignored) if (ZwQuerySystemInformation(SystemPerformanceInformation, (PVOID) &PerformanceInfo, sizeof(SYSTEM_PERFORMANCE_INFORMATION), - &Length) != NO_ERROR) + &Length) != STATUS_SUCCESS) { break; } diff --git a/rostests/drivers/memtest/memtest.rbuild b/rostests/drivers/memtest/memtest.rbuild index e2f9bef5347..61cb6fec55d 100644 --- a/rostests/drivers/memtest/memtest.rbuild +++ b/rostests/drivers/memtest/memtest.rbuild @@ -1,6 +1,5 @@ - include/reactos/drivers ntoskrnl hal diff --git a/rostests/dxtest/ddraw/DDraw/display_modes.cpp b/rostests/dxtest/ddraw/DDraw/display_modes.cpp index 9915af2e374..3143575dee0 100644 --- a/rostests/dxtest/ddraw/DDraw/display_modes.cpp +++ b/rostests/dxtest/ddraw/DDraw/display_modes.cpp @@ -24,8 +24,8 @@ HRESULT CALLBACK EnumDisplayModes( LPDDSURFACEDESC2 pDDSD, ENUMCONTEXT* Context DDSURFACEDESC2 DisplayMode = {0}; DisplayMode.dwSize = sizeof(DDSURFACEDESC2); - TEST ( pDDSD->dwFlags == DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT | DDSD_REFRESHRATE); - TEST ( pDDSD->ddpfPixelFormat.dwFlags == DDPF_RGB | DDPF_PALETTEINDEXED8 || pDDSD->ddpfPixelFormat.dwFlags == DDPF_RGB ); + TEST ( pDDSD->dwFlags == (DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT | DDSD_REFRESHRATE)); + TEST ( pDDSD->ddpfPixelFormat.dwFlags == (DDPF_RGB | DDPF_PALETTEINDEXED8) || pDDSD->ddpfPixelFormat.dwFlags == DDPF_RGB ); TEST ( Context->DirectDraw->SetDisplayMode (pDDSD->dwWidth, pDDSD->dwHeight, pDDSD->ddpfPixelFormat.dwRGBBitCount, pDDSD->dwRefreshRate, 0) == DD_OK); TEST ( Context->DirectDraw->GetMonitorFrequency (&lpdwFrequency) == DD_OK && lpdwFrequency == pDDSD->dwRefreshRate); TEST ( Context->DirectDraw->GetDisplayMode (&DisplayMode) == DD_OK @@ -33,7 +33,7 @@ HRESULT CALLBACK EnumDisplayModes( LPDDSURFACEDESC2 pDDSD, ENUMCONTEXT* Context && pDDSD->dwWidth == DisplayMode.dwWidth && pDDSD->dwRefreshRate == DisplayMode.dwRefreshRate && pDDSD->ddpfPixelFormat.dwRGBBitCount == DisplayMode.ddpfPixelFormat.dwRGBBitCount - && DisplayMode.dwFlags == DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT | DDSD_REFRESHRATE ); + && DisplayMode.dwFlags == (DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT | DDSD_REFRESHRATE) ); setcout++; return DDENUMRET_OK; @@ -124,4 +124,4 @@ BOOL Test_GetMonitorFrequency (INT* passed, INT* failed) DirectDraw->Release(); return TRUE; -} \ No newline at end of file +} diff --git a/rostests/dxtest/ddraw/Surface/blt.cpp b/rostests/dxtest/ddraw/Surface/blt.cpp index ed3024fc0f5..620641a4589 100644 --- a/rostests/dxtest/ddraw/Surface/blt.cpp +++ b/rostests/dxtest/ddraw/Surface/blt.cpp @@ -154,4 +154,4 @@ BOOL Test_Blt (INT* passed, INT* failed) Surface->Release(); return TRUE; -} \ No newline at end of file +} diff --git a/rostests/dxtest/ddraw/Surface/create.cpp b/rostests/dxtest/ddraw/Surface/create.cpp index 7ad5cb5068c..14c33346e93 100644 --- a/rostests/dxtest/ddraw/Surface/create.cpp +++ b/rostests/dxtest/ddraw/Surface/create.cpp @@ -2,7 +2,7 @@ HWND CreateBasicWindow (VOID); LPDIRECTDRAW7 DirectDraw; -BOOL TestCaps (char* dummy, DWORD Caps, HRESULT test1, HRESULT test2) +BOOL TestCaps (const char* dummy, DWORD Caps, HRESULT test1, HRESULT test2) { LPDIRECTDRAWSURFACE7 Surface = NULL; DDSURFACEDESC2 Desc = { 0 }; diff --git a/rostests/dxtest/ddraw/Surface/misc.cpp b/rostests/dxtest/ddraw/Surface/misc.cpp index 41c13c02f35..4ec8465ab3b 100644 --- a/rostests/dxtest/ddraw/Surface/misc.cpp +++ b/rostests/dxtest/ddraw/Surface/misc.cpp @@ -12,7 +12,7 @@ BOOL Test_Misc (INT* passed, INT* failed) DDSCAPS2 Caps; TEST (Surface->GetCaps((DDSCAPS2*)0xdeadbeef) == DDERR_INVALIDPARAMS); TEST (Surface->GetCaps(&Caps) == DD_OK && Caps.dwCaps == 0x10004040 - && Caps.dwCaps2 == Caps.dwCaps3 == Caps.dwCaps4 == 0); // FIXME: Replace 0x10004040 + && Caps.dwCaps2 == 0 && Caps.dwCaps3 == 0 && Caps.dwCaps4 == 0); // FIXME: Replace 0x10004040 // GetDC / ReleaseDC HDC hdc; diff --git a/rostests/dxtest/ddraw/ddraw.rbuild b/rostests/dxtest/ddraw/ddraw.rbuild index b15c6ebcb61..eca73152570 100644 --- a/rostests/dxtest/ddraw/ddraw.rbuild +++ b/rostests/dxtest/ddraw/ddraw.rbuild @@ -1,14 +1,11 @@ - - . - - 0x0501 - kernel32 - user32 - gdi32 - ole32 - ddraw - dxguid - ddraw_test.cpp - helper.cpp - testlist.cpp - + + . + user32 + gdi32 + ole32 + ddraw + dxguid + ddraw_test.cpp + helper.cpp + testlist.cpp + diff --git a/rostests/dxtest/ddraw/ddrawtest.h b/rostests/dxtest/ddraw/ddrawtest.h index 78f3190170f..35d4a27b304 100644 --- a/rostests/dxtest/ddraw/ddrawtest.h +++ b/rostests/dxtest/ddraw/ddrawtest.h @@ -1,8 +1,6 @@ #ifndef _DDRAWTEST_H #define _DDRAWTEST_H -#define WINVER 0x501 - #include #include #include @@ -26,7 +24,7 @@ typedef BOOL (*TESTPROC)(INT*, INT*); typedef struct tagTEST { - CHAR* Test; + const CHAR* Test; TESTPROC Proc; } TEST, *PTEST; diff --git a/rostests/dxtest/ddraw/debug.cpp b/rostests/dxtest/ddraw/debug.cpp index 8744547ca50..6feda229275 100644 --- a/rostests/dxtest/ddraw/debug.cpp +++ b/rostests/dxtest/ddraw/debug.cpp @@ -1,7 +1,7 @@ #define GetCode(X) printf("%s\n", DDErrorString(X)); -PCHAR DDErrorString (HRESULT hResult) +const CHAR* DDErrorString (HRESULT hResult) { switch (hResult) { diff --git a/rostests/dxtest/win32kdxtest/NtGdiDdCanCreateSurface.c b/rostests/dxtest/win32kdxtest/NtGdiDdCanCreateSurface.c index 0bc6e4c27eb..b183275f966 100644 --- a/rostests/dxtest/win32kdxtest/NtGdiDdCanCreateSurface.c +++ b/rostests/dxtest/win32kdxtest/NtGdiDdCanCreateSurface.c @@ -1,45 +1,45 @@ - -#include -/* SDK/DDK/NDK Headers. */ -#include -#include -#include -#include -#include -#include -#include "test.h" - -/* - * Test see if we can delete a DirectDrawObject from win32k - * - */ -void -test_NtGdiDdCanCreateSurface(HANDLE hDirectDrawLocal) -{ - int fails=0; - BOOL retValue=FALSE; - DDHAL_CANCREATESURFACEDATA pCanCreateSurface; - DDSURFACEDESC2 desc; - - RtlZeroMemory(&pCanCreateSurface,sizeof(DDHAL_CANCREATESURFACEDATA)); - RtlZeroMemory(&desc,sizeof(DDSURFACEDESC2)); - - /* crash in windows 2000 */ - retValue = OsThunkDdCanCreateSurface(NULL,NULL); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"1. NtGdiDdCanCreateSurface(NULL,NULL);\0"); - - retValue = OsThunkDdCanCreateSurface(hDirectDrawLocal,NULL); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"2. NtGdiDdCanCreateSurface(hDirectDrawLocal,NULL);\0"); - - retValue = OsThunkDdCanCreateSurface(hDirectDrawLocal,(PDD_CANCREATESURFACEDATA)&pCanCreateSurface); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"3. NtGdiDdCanCreateSurface(hDirectDrawLocal,pCanCreateSurface);\0"); - - pCanCreateSurface.lpDDSurfaceDesc = &desc; - desc.dwSize = sizeof(DDSURFACEDESC2); - - retValue = OsThunkDdCanCreateSurface(hDirectDrawLocal,(PDD_CANCREATESURFACEDATA)&pCanCreateSurface); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"4. NtGdiDdCanCreateSurface(hDirectDrawLocal,pCanCreateSurface);\0"); - -} - - + +#include +/* SDK/DDK/NDK Headers. */ +#include +#include +#include +#include +#include +#include +#include "test.h" + +/* + * Test see if we can delete a DirectDrawObject from win32k + * + */ +void +test_NtGdiDdCanCreateSurface(HANDLE hDirectDrawLocal) +{ + int fails=0; + BOOL retValue=FALSE; + DDHAL_CANCREATESURFACEDATA pCanCreateSurface; + DDSURFACEDESC2 desc; + + RtlZeroMemory(&pCanCreateSurface,sizeof(DDHAL_CANCREATESURFACEDATA)); + RtlZeroMemory(&desc,sizeof(DDSURFACEDESC2)); + + /* crash in windows 2000 */ + retValue = OsThunkDdCanCreateSurface(NULL,NULL); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"1. NtGdiDdCanCreateSurface(NULL,NULL);\0"); + + retValue = OsThunkDdCanCreateSurface(hDirectDrawLocal,NULL); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"2. NtGdiDdCanCreateSurface(hDirectDrawLocal,NULL);\0"); + + retValue = OsThunkDdCanCreateSurface(hDirectDrawLocal,(PDD_CANCREATESURFACEDATA)&pCanCreateSurface); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"3. NtGdiDdCanCreateSurface(hDirectDrawLocal,pCanCreateSurface);\0"); + + pCanCreateSurface.lpDDSurfaceDesc = (DDSURFACEDESC*)&desc; + desc.dwSize = sizeof(DDSURFACEDESC2); + + retValue = OsThunkDdCanCreateSurface(hDirectDrawLocal,(PDD_CANCREATESURFACEDATA)&pCanCreateSurface); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"4. NtGdiDdCanCreateSurface(hDirectDrawLocal,pCanCreateSurface);\0"); + +} + + diff --git a/rostests/dxtest/win32kdxtest/NtGdiDdGetScanLine.c b/rostests/dxtest/win32kdxtest/NtGdiDdGetScanLine.c index 3aea20f901d..b5367828b51 100644 --- a/rostests/dxtest/win32kdxtest/NtGdiDdGetScanLine.c +++ b/rostests/dxtest/win32kdxtest/NtGdiDdGetScanLine.c @@ -1,40 +1,40 @@ -#include -/* SDK/DDK/NDK Headers. */ -#include -#include -#include -#include -#include -#include "test.h" - -/* - * Test see if we can delete a DirectDrawObject from win32k - * - */ -void -test_NtGdiDdGetScanLine(HANDLE hDirectDrawLocal) -{ - int fails=0; - BOOL retValue=FALSE; - DD_GETSCANLINEDATA puGetScanLineData; - - printf("Start testing of NtGdiDdGetScanLine\n"); - RtlZeroMemory(&puGetScanLineData,sizeof(DD_GETSCANLINEDATA)); - - retValue = OsThunkDdGetScanLine(NULL,NULL); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"1. NtGdiDdGetScanLine(NULL,NULL);\0"); - - retValue = OsThunkDdGetScanLine(hDirectDrawLocal,NULL); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"2. NtGdiDdGetScanLine(hDirectDrawLocal,NULL);\0"); - - puGetScanLineData.ddRVal = DDERR_GENERIC; - retValue = OsThunkDdGetScanLine(hDirectDrawLocal,&puGetScanLineData); - testing_eq(retValue,DDHAL_DRIVER_NOTHANDLED,fails,"3. NtGdiDdGetScanLine(hDirectDrawLocal,puGetScanLineData);\0"); - testing_noteq(puGetScanLineData.ddRVal,DD_OK,fails,"4. NtGdiDdGetScanLine(hDirectDrawLocal,puGetScanLineData);\0"); - testing_eq(puGetScanLineData.dwScanLine,0,fails,"4. NtGdiDdGetScanLine(hDirectDrawLocal,puGetScanLineData);\0"); - - - /* FIXME DDERR_VERTICALBLANKINPROGRESS test */ - - show_status(fails, "NtGdiDdGetScanLine\0"); -} \ No newline at end of file +#include +/* SDK/DDK/NDK Headers. */ +#include +#include +#include +#include +#include +#include "test.h" + +/* + * Test see if we can delete a DirectDrawObject from win32k + * + */ +void +test_NtGdiDdGetScanLine(HANDLE hDirectDrawLocal) +{ + int fails=0; + BOOL retValue=FALSE; + DD_GETSCANLINEDATA puGetScanLineData; + + printf("Start testing of NtGdiDdGetScanLine\n"); + RtlZeroMemory(&puGetScanLineData,sizeof(DD_GETSCANLINEDATA)); + + retValue = OsThunkDdGetScanLine(NULL,NULL); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"1. NtGdiDdGetScanLine(NULL,NULL);\0"); + + retValue = OsThunkDdGetScanLine(hDirectDrawLocal,NULL); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"2. NtGdiDdGetScanLine(hDirectDrawLocal,NULL);\0"); + + puGetScanLineData.ddRVal = DDERR_GENERIC; + retValue = OsThunkDdGetScanLine(hDirectDrawLocal,&puGetScanLineData); + testing_eq(retValue,DDHAL_DRIVER_NOTHANDLED,fails,"3. NtGdiDdGetScanLine(hDirectDrawLocal,puGetScanLineData);\0"); + testing_noteq(puGetScanLineData.ddRVal,DD_OK,fails,"4. NtGdiDdGetScanLine(hDirectDrawLocal,puGetScanLineData);\0"); + testing_eq(puGetScanLineData.dwScanLine,0,fails,"4. NtGdiDdGetScanLine(hDirectDrawLocal,puGetScanLineData);\0"); + + + /* FIXME DDERR_VERTICALBLANKINPROGRESS test */ + + show_status(fails, "NtGdiDdGetScanLine\0"); +} diff --git a/rostests/dxtest/win32kdxtest/NtGdiDdQueryDirectDrawObject.c b/rostests/dxtest/win32kdxtest/NtGdiDdQueryDirectDrawObject.c index 1b6960890bd..c0e4886d745 100644 --- a/rostests/dxtest/win32kdxtest/NtGdiDdQueryDirectDrawObject.c +++ b/rostests/dxtest/win32kdxtest/NtGdiDdQueryDirectDrawObject.c @@ -54,10 +54,7 @@ test_NtGdiDdQueryDirectDrawObject( HANDLE hDirectDrawLocal) D3DNTHAL_GLOBALDRIVERDATA D3dDriverData; DD_D3DBUFCALLBACKS D3dBufferCallbacks; DDSURFACEDESC2 D3dTextureFormats[100]; - DWORD NumHeaps = 0; VIDEOMEMORY vmList; - DWORD NumFourCC = 0; - DWORD FourCC = 0; /* clear data */ memset(&vmList,0,sizeof(VIDEOMEMORY)); diff --git a/rostests/dxtest/win32kdxtest/NtGdiDdWaitForVerticalBlank.c b/rostests/dxtest/win32kdxtest/NtGdiDdWaitForVerticalBlank.c index 2f7eae7ace1..22b28967a4f 100644 --- a/rostests/dxtest/win32kdxtest/NtGdiDdWaitForVerticalBlank.c +++ b/rostests/dxtest/win32kdxtest/NtGdiDdWaitForVerticalBlank.c @@ -1,46 +1,46 @@ -#include -/* SDK/DDK/NDK Headers. */ -#include -#include -#include -#include -#include - -#include -#include "test.h" - -/* - * Test see if we can delete a DirectDrawObject from win32k - * - */ -void -test_NtGdiDdWaitForVerticalBlank(HANDLE hDirectDrawLocal) -{ - int fails=0; - BOOL retValue=FALSE; - DDHAL_WAITFORVERTICALBLANKDATA pDdWaitForVerticalBlankData; - - RtlZeroMemory(&pDdWaitForVerticalBlankData,sizeof(DDHAL_WAITFORVERTICALBLANKDATA)); - - retValue = OsThunkDdWaitForVerticalBlank(NULL,NULL); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"1. NtGdiDdWaitForVerticalBlank(NULL,NULL);\0"); - - retValue = OsThunkDdWaitForVerticalBlank(hDirectDrawLocal,NULL); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"2. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); - - retValue = OsThunkDdWaitForVerticalBlank(hDirectDrawLocal,(PDD_WAITFORVERTICALBLANKDATA)&pDdWaitForVerticalBlankData); - testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"3. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); - testing_eq(pDdWaitForVerticalBlankData.ddRVal, DD_OK,fails,"4. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); - - RtlZeroMemory(&pDdWaitForVerticalBlankData,sizeof(DDHAL_WAITFORVERTICALBLANKDATA)); - pDdWaitForVerticalBlankData.dwFlags = DDWAITVB_I_TESTVB; - retValue = OsThunkDdWaitForVerticalBlank(hDirectDrawLocal,(PDD_WAITFORVERTICALBLANKDATA)&pDdWaitForVerticalBlankData); - - testing_eq(retValue, DDHAL_DRIVER_NOTHANDLED,fails,"5. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); - testing_noteq(pDdWaitForVerticalBlankData.ddRVal, DD_OK,fails,"6. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); - - retValue = OsThunkDdWaitForVerticalBlank(hDirectDrawLocal,(PDD_WAITFORVERTICALBLANKDATA)&pDdWaitForVerticalBlankData); - - show_status(fails, "NtGdiDdWaitForVerticalBlank\0"); -} - +#include +/* SDK/DDK/NDK Headers. */ +#include +#include +#include +#include +#include + +#include +#include "test.h" + +/* + * Test see if we can delete a DirectDrawObject from win32k + * + */ +void +test_NtGdiDdWaitForVerticalBlank(HANDLE hDirectDrawLocal) +{ + int fails=0; + BOOL retValue=FALSE; + DDHAL_WAITFORVERTICALBLANKDATA pDdWaitForVerticalBlankData; + + RtlZeroMemory(&pDdWaitForVerticalBlankData,sizeof(DDHAL_WAITFORVERTICALBLANKDATA)); + + retValue = OsThunkDdWaitForVerticalBlank(NULL,NULL); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"1. NtGdiDdWaitForVerticalBlank(NULL,NULL);\0"); + + retValue = OsThunkDdWaitForVerticalBlank(hDirectDrawLocal,NULL); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"2. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); + + retValue = OsThunkDdWaitForVerticalBlank(hDirectDrawLocal,(PDD_WAITFORVERTICALBLANKDATA)&pDdWaitForVerticalBlankData); + testing_eq(retValue, DDHAL_DRIVER_HANDLED,fails,"3. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); + testing_eq(pDdWaitForVerticalBlankData.ddRVal, DD_OK,fails,"4. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); + + RtlZeroMemory(&pDdWaitForVerticalBlankData,sizeof(DDHAL_WAITFORVERTICALBLANKDATA)); + pDdWaitForVerticalBlankData.dwFlags = DDWAITVB_I_TESTVB; + retValue = OsThunkDdWaitForVerticalBlank(hDirectDrawLocal,(PDD_WAITFORVERTICALBLANKDATA)&pDdWaitForVerticalBlankData); + + testing_eq(retValue, DDHAL_DRIVER_NOTHANDLED,fails,"5. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); + testing_noteq(pDdWaitForVerticalBlankData.ddRVal, DD_OK,fails,"6. NtGdiDdWaitForVerticalBlank(hDirectDrawLocal,NULL);\0"); + + retValue = OsThunkDdWaitForVerticalBlank(hDirectDrawLocal,(PDD_WAITFORVERTICALBLANKDATA)&pDdWaitForVerticalBlankData); + + show_status(fails, "NtGdiDdWaitForVerticalBlank\0"); +} + diff --git a/rostests/dxtest/win32kdxtest/win32kdxtest.rbuild b/rostests/dxtest/win32kdxtest/win32kdxtest.rbuild index 9901aa007d4..ad0499a5d05 100644 --- a/rostests/dxtest/win32kdxtest/win32kdxtest.rbuild +++ b/rostests/dxtest/win32kdxtest/win32kdxtest.rbuild @@ -1,8 +1,5 @@ - + . - 0x0501 - 0x0501 - kernel32 user32 gdi32 d3d8thk @@ -14,4 +11,3 @@ NtGdiDdWaitForVerticalBlank.c NtGdiDdCanCreateSurface.c dump.c - \ No newline at end of file diff --git a/rostests/regtests/crt/crt_regtest.rbuild b/rostests/regtests/crt/crt_regtest.rbuild new file mode 100644 index 00000000000..4b297d5b1b8 --- /dev/null +++ b/rostests/regtests/crt/crt_regtest.rbuild @@ -0,0 +1,11 @@ + + + + + . + wine + iofuncs.c + testlist.c + time.c + + diff --git a/rostests/regtests/crt/iofuncs.c b/rostests/regtests/crt/iofuncs.c new file mode 100644 index 00000000000..cc64ac2c56a --- /dev/null +++ b/rostests/regtests/crt/iofuncs.c @@ -0,0 +1,100 @@ +/* + * PROJECT: ReactOS CRT regression tests + * LICENSE: GPL - See COPYING in the top level directory + * FILE: rostests/regtests/crt/iofuncs.c + * PURPOSE: Tests for input/output functions of the CRT + * PROGRAMMERS: Gregor Schneider + */ + +#include +#include + +#define _CRT_NON_CONFORMING_SWPRINTFS + +struct _testData +{ + double val; + int prec; + char* exp; + char* exp2; +} ECVTTESTDATA[] = +{ + { 45.0, 2, "+4.50E+001", "+4.5000E+001" }, /*0*/ + { 0.0001, 1, "+1.0E-004", "+1.000E-004" }, + { 0.0001, -10, "+1.000000E-004", "+1.000000E-004" }, + { 0.0001, 10, "+1.0000000000E-004", "+1.000000000000E-004" }, + { -111.0001, 5, "-1.11000E+002", "-1.1100010E+002" }, + { 111.0001, 5, "+1.11000E+002", "+1.1100010E+002" }, /*5*/ + { 3333.3, 2, "+3.33E+003", "+3.3333E+003" }, + { 999999999999.9, 3, "+1.000E+012", "+1.00000E+012" }, + { 0.0, 5, "+0.00000E+000", "+0.0000000E+000" }, + { 0.0, 0, "+0E+000", "+0.00E+000" }, + { 0.0, -1, "+0.000000E+000", "+0.0E+000" }, /*10*/ + { -123.0001, 0, "-1E+002", "-1.23E+002" }, + { -123.0001, -1, "-1.230001E+002", "-1.2E+002" }, + { -123.0001, -2, "-1.230001E+002", "-1E+002" }, + { -123.0001, -3, "-1.230001E+002", "-1.230001E+002" }, + { 99.99, 1, "+1.0E+002", "+9.999E+001" }, /*15*/ + { 0.0063, 2, "+6.30E-003", "+6.3000E-003" }, + { 0.0063, 3, "+6.300E-003", "+6.30000E-003" }, + { 0.09999999996, 2, "+1.00E-001", "+1.0000E-001" }, + { 0.6, 1, "+6.0E-001", "+6.000E-001" }, + { 0.6, 0, "+6E-001", "+6.00E-001" }, /*20*/ + { 0.4, 0, "+4E-001", "+4.00E-001" }, + { 0.49, 0, "+5E-001", "+4.90E-001" }, + { 0.51, 0, "+5E-001", "+5.10E-001" } +}; + +void Test_ofuncs() +{ + int i; + char* buf = NULL; + + /* Test exponential format */ + buf = malloc(30 * sizeof(char)); + if (buf == NULL) + { + printf("Memory full, exiting\n"); + return; + } + for (i = 0; i < sizeof(ECVTTESTDATA)/sizeof(ECVTTESTDATA[0]); i++) + { + sprintf(buf, "%-+.*E", ECVTTESTDATA[i].prec, ECVTTESTDATA[i].val); + ok(!strcmp(buf, ECVTTESTDATA[i].exp), + "sprintf exp test %d failed: got %s, expected %s\n", + i, buf, ECVTTESTDATA[i].exp); + } + for (i = 0; i < sizeof(ECVTTESTDATA)/sizeof(ECVTTESTDATA[0]); i++) + { + sprintf(buf, "%-+.*E", ECVTTESTDATA[i].prec + 2, ECVTTESTDATA[i].val); + ok(!strcmp(buf, ECVTTESTDATA[i].exp2), + "sprintf exp +2 prec test %d failed: got %s, expected %s\n", + i, buf, ECVTTESTDATA[i].exp2); + } + + /* Test with negative number to be rounded */ + sprintf(buf, "%-+.*E", ECVTTESTDATA[18].prec + 2, -ECVTTESTDATA[18].val); + ok(!strcmp(buf, "-1.0000E-001"), "Negative number sprintf rounding failed: got %s, expected %s\n", + buf, "-1.0000E-001"); + free(buf); +} + +void Test_ifuncs() +{ + double var; + char cnum[] = "12.3"; + wchar_t wnum[] = L"12.3"; + + /* Test sscanf behaviour */ + sscanf(cnum, "%lf", &var); + ok(var == 12.3, "sscanf double conversion failed: got %f\n", var); + swscanf(wnum, L"%lf", &var); + ok(var == 12.3, "swscanf double conversion failed: got %f\n", var); +} + +START_TEST(iofuncs) +{ + Test_ofuncs(); + Test_ifuncs(); +} + diff --git a/rostests/regtests/crt/testlist.c b/rostests/regtests/crt/testlist.c new file mode 100644 index 00000000000..6d720ebc33d --- /dev/null +++ b/rostests/regtests/crt/testlist.c @@ -0,0 +1,19 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#define __ROS_LONG64__ +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_iofuncs(void); +extern void func_time(void); + +const struct test winetest_testlist[] = +{ + { "iofuncs", func_iofuncs }, + { "time", func_time }, + { 0, 0 } +}; + diff --git a/rostests/regtests/crt/time.c b/rostests/regtests/crt/time.c new file mode 100644 index 00000000000..e9f4f74e6ce --- /dev/null +++ b/rostests/regtests/crt/time.c @@ -0,0 +1,48 @@ +/* + * PROJECT: ReactOS CRT regression tests + * LICENSE: GPL - See COPYING in the top level directory + * FILE: rostests/regtests/crt/time.c + * PURPOSE: Tests for time functions of the CRT + * PROGRAMMERS: Gregor Schneider + */ + +#include +#include +#include + +void Test_asctime() +{ + /* Test asctime */ + struct tm time; + char* timestr; + char explowtime[] = "Mon Jun 04 00:30:20 1909\n"; /* XP's crt returns new line after the string */ + + time.tm_hour = 0; + time.tm_mday = 4; + time.tm_min = 30; + time.tm_mon = 5; + time.tm_sec = 20; + time.tm_wday = 1; + time.tm_yday = 200; + time.tm_year = 9; + + timestr = asctime(&time); + ok(!strcmp(timestr, explowtime), "Wrong time returned, got %s\n", timestr); +} + +void Test_ctime() +{ + /* Test border ctime cases */ + time_t time; + time = -15; + ok(ctime(&time) == NULL, "ctime doesn't return NULL for invalid parameters\n"); + time = -5000000; + ok(ctime(&time) == NULL, "ctime doesn't return NULL for invalid parameters\n"); +} + +START_TEST(time) +{ + Test_asctime(); + Test_ctime(); +} + diff --git a/rostests/regtests_by_casper/directory.rbuild b/rostests/regtests/directory.rbuild similarity index 52% rename from rostests/regtests_by_casper/directory.rbuild rename to rostests/regtests/directory.rbuild index 55fd1e14efa..acbe991bc01 100644 --- a/rostests/regtests_by_casper/directory.rbuild +++ b/rostests/regtests/directory.rbuild @@ -1,10 +1,10 @@ - - + + - - + + diff --git a/rostests/regtests/gdi/gdi_regtest.rbuild b/rostests/regtests/gdi/gdi_regtest.rbuild new file mode 100644 index 00000000000..1c3c010e40e --- /dev/null +++ b/rostests/regtests/gdi/gdi_regtest.rbuild @@ -0,0 +1,14 @@ + + + + + . + wine + gdi32 + user32 + ntdll + + xlate.c + testlist.c + + diff --git a/rostests/regtests/gdi/testlist.c b/rostests/regtests/gdi/testlist.c new file mode 100644 index 00000000000..66d9dc0c2ae --- /dev/null +++ b/rostests/regtests/gdi/testlist.c @@ -0,0 +1,17 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#define __ROS_LONG64__ +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_xlate(void); + +const struct test winetest_testlist[] = +{ + { "xlate", func_xlate }, + { 0, 0 } +}; + diff --git a/rostests/regtests/gdi/xlate.c b/rostests/regtests/gdi/xlate.c new file mode 100644 index 00000000000..e981381cb53 --- /dev/null +++ b/rostests/regtests/gdi/xlate.c @@ -0,0 +1,544 @@ + +#include +#include +#include + +enum +{ + BMF_1BPP = 0, + BMF_4BPP = 1, + BMF_8BPP = 2, + BMF_16BPP_555 = 3, + BMF_16BPP_565 = 4, + BMF_24BPP_RGB = 5, + BMF_24BPP_BGR = 6, + BMF_32BPP_RGB = 7, + BMF_32BPP_BGR = 8 +}; + +ULONG bpp[] = {1, 4, 8, 15, 16, 24, 24, 32, 32}; + +static BYTE ajBits1[] = {0xAA, 0xAA, 0xAA, 0xAA, 0,0,0,0}; +static BYTE ajBits8[] = {0x00, 0xFF, 0x80, 0xCC, 0,0,0,0}; +static WORD ajBits16[] = {0x0000, 0xFFFF, 0x1000, 0x0C0C, 0,0,0,0}; +static DWORD ajBits24[] = {0x0000, 0xFFFF, 0x1000, 0x0C0C, 0,0,0,0}; +static DWORD ajBits32[] = {0x0000, 0xFFFF, 0x1000, 0x0C0C, 0,0,0,0}; +static HBITMAP hbmp1bpp_a, hbmp1bpp_b; +static HBITMAP hbmp8bpp_a, hbmp8bpp_b; +static HBITMAP hbmp16bpp_a, hbmp16bpp_b; +static HBITMAP hbmp24bpp_a, hbmp24bpp_b; +static HBITMAP hbmp32bpp_a, hbmp32bpp_b; +static HBITMAP hbmpCompat; +static HDC hdcSrc, hdcDst; +static ULONG iDcFormat; + +ULONG +GetRealColorDepth() +{ + HBITMAP hbmp; + HDC hdc; + struct + { + BITMAPINFOHEADER bmiHeader; + ULONG aulMasks[3]; + } bmi; + PBITMAPINFO pbmi = (PBITMAPINFO)&bmi; + ULONG ulColorDepth; + + /* Get the screen DC */ + hdc = GetDC(NULL); + + /* Create a compatible bitmap */ + hbmp = CreateCompatibleBitmap(hdc, 1, 1); + + /* Fill BITMAPINFOHEADER */ + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + GetDIBits(hdc, hbmp, 0, 1, NULL, pbmi, DIB_RGB_COLORS); + + /* Call again to fill in the bitfields */ + GetDIBits(hdc, hbmp, 0, 1, NULL, pbmi, DIB_RGB_COLORS); + + /* Get the basic color depth */ + ulColorDepth = bmi.bmiHeader.biBitCount; + + DeleteObject(hbmp); + + switch (ulColorDepth) + { + case 1: + return BMF_1BPP; + case 4: + return BMF_4BPP; + case 8: + return BMF_8BPP; + case 16: + /* Check the red mask */ + if (bmi.aulMasks[0] == 0x7c00) + return BMF_16BPP_555; + else + return BMF_16BPP_565; + case 24: + return BMF_4BPP; + case 32: + if (bmi.bmiHeader.biCompression == BI_BITFIELDS && + bmi.aulMasks[0] == 0xff) + return BMF_32BPP_RGB; + else + return BMF_32BPP_BGR; + } + + /* Cleanup and return */ + return BMF_32BPP_RGB; +} + +static +ULONG +iXlateFromRGB(ULONG iFormat, COLORREF crColor) +{ + ULONG ulRed, ulGreen, ulBlue; + + ulRed = GetRValue(crColor); + ulGreen = GetGValue(crColor); + ulBlue = GetBValue(crColor); + + switch (iFormat) + { + case BMF_1BPP: + return crColor ? 0xffffff : 0; + + case BMF_4BPP: + case BMF_8BPP: + case BMF_16BPP_555: + ulRed = (ulRed & 0xF8) >> 3; + ulGreen = (ulGreen & 0xF8) >> 3; + ulBlue = (ulBlue & 0xF8) >> 3; + return ulRed << 10 | ulGreen << 5 | ulBlue; + + case BMF_16BPP_565: + ulRed = (ulRed & 0xF8) >> 3; + ulGreen = (ulGreen & 0xFC) >> 2; + ulBlue = (ulBlue & 0xF8) >> 3; + return ulRed << 11 | ulGreen << 5 | ulBlue; + + case BMF_24BPP_RGB: + case BMF_32BPP_RGB: + return crColor; + + case BMF_24BPP_BGR: + case BMF_32BPP_BGR: + return RGB(ulBlue, ulGreen, ulRed); + } + return 0; +} + +static +COLORREF +iXlateToRGB(ULONG iFormat, ULONG ulColor) +{ + ULONG ulRed, ulGreen, ulBlue; + + switch (iFormat) + { + case BMF_1BPP: + return ulColor ? 0xffffff : 0; + + case BMF_4BPP: + case BMF_8BPP: + case BMF_16BPP_555: + ulRed = (ulColor & 0x7C00) >> 7; + ulRed |= ulRed >> 5; + ulGreen = (ulColor & 0x3E0) >> 2; + ulGreen |= ulGreen >> 5; + ulBlue = (ulColor & 0x1F) << 3; + ulBlue |= ulBlue >> 5; + return RGB(ulRed, ulGreen, ulBlue); + + case BMF_16BPP_565: + ulRed = (ulColor & 0xF800) >> 8; + ulRed |= ulRed >> 5; + ulGreen = (ulColor & 0x7E0) >> 3; + ulGreen |= ulGreen >> 6; + ulBlue = (ulColor & 0x1F) << 3; + ulBlue |= ulBlue >> 5; + return RGB(ulRed, ulGreen, ulBlue); + + case BMF_24BPP_RGB: + case BMF_32BPP_RGB: + return ulColor; + + case BMF_24BPP_BGR: + case BMF_32BPP_BGR: + ulRed = GetRValue(ulColor); + ulGreen = GetGValue(ulColor); + ulBlue = GetBValue(ulColor); + return RGB(ulBlue, ulGreen, ulRed); + } + return 0; +} + +static +ULONG +GetClosestColor(ULONG iFormat, COLORREF crColor, COLORREF crBackColor) +{ + if (iFormat == BMF_1BPP) + return crBackColor; + return iXlateToRGB(iFormat, iXlateFromRGB(iFormat, crColor)); +} + +ULONG +GetDIBPixel(ULONG iFormat, PVOID pvBits, ULONG x) +{ + switch (iFormat) + { + case BMF_1BPP: + // + case BMF_16BPP_555: + case BMF_16BPP_565: + return *(WORD*)((PCHAR)pvBits + x * sizeof(WORD)); + + case BMF_24BPP_RGB: + case BMF_24BPP_BGR: + return (*(DWORD*)((PCHAR)pvBits + x * 3)) & 0xffffff; + + case BMF_32BPP_RGB: + case BMF_32BPP_BGR: + return *(DWORD*)((PCHAR)pvBits + x * sizeof(DWORD)); + } + return 0; +} + +static +void +Initialize() +{ + hdcSrc = CreateCompatibleDC(0); + hdcDst = CreateCompatibleDC(0); + + hbmpCompat = CreateCompatibleBitmap(GetDC(0), 4, 2); + ok(hbmpCompat != 0, "CreateCompatibleBitmap failed\n"); + + iDcFormat = GetRealColorDepth(); + printf("got iDcFormat = %ld\n", iDcFormat); + + hbmp1bpp_a = CreateBitmap(4, 2, 1, 1, ajBits1); + ok(hbmp1bpp_a != 0, "CreateBitmap failed\n"); + + hbmp1bpp_b = CreateBitmap(4, 2, 1, 1, ajBits1); + ok(hbmp1bpp_b != 0, "CreateBitmap failed\n"); + + hbmp8bpp_a = CreateBitmap(4, 2, 1, 8, ajBits8); + ok(hbmp8bpp_a != 0, "CreateBitmap failed\n"); + + hbmp8bpp_b = CreateBitmap(4, 2, 1, 8, ajBits8); + ok(hbmp8bpp_b != 0, "CreateBitmap failed\n"); + + hbmp16bpp_a = CreateBitmap(4, 2, 1, 16, ajBits16); + ok(hbmp16bpp_a != 0, "CreateBitmap failed\n"); + + hbmp16bpp_b = CreateBitmap(4, 2, 1, 16, ajBits16); + ok(hbmp16bpp_b != 0, "CreateBitmap failed\n"); + + hbmp24bpp_a = CreateBitmap(4, 2, 1, 24, ajBits24); + ok(hbmp24bpp_a != 0, "CreateBitmap failed\n"); + + hbmp24bpp_b = CreateBitmap(4, 2, 1, 24, ajBits24); + ok(hbmp24bpp_b != 0, "CreateBitmap failed\n"); + + hbmp32bpp_a = CreateBitmap(4, 2, 1, 32, ajBits32); + ok(hbmp32bpp_a != 0, "CreateBitmap failed\n"); + + hbmp32bpp_b = CreateBitmap(4, 2, 1, 32, ajBits32); + ok(hbmp32bpp_b != 0, "CreateBitmap failed\n"); + +} + +void +Test_SrcMono1(ULONG iBmpFormat, HBITMAP hbmpDst, PVOID pvBits) +{ + COLORREF c, expected; + HBRUSH hbr; + RECT rect; + struct + { + BITMAPINFOHEADER bmiHeader; + ULONG bmiColors[2]; + BYTE aj[32]; + } bmi; + + SelectObject(hdcSrc, hbmp1bpp_a); + SelectObject(hdcDst, hbmpDst); + + /* Set default dc fore and back colors */ + SetTextColor(hdcSrc, 0x000000); + SetBkColor(hdcSrc, 0xffffff); + SetTextColor(hdcDst, 0x000000); + SetBkColor(hdcDst, 0xffffff); + + /* Do a bitblt operation */ + ok(BitBlt(hdcDst, 0, 0, 2, 2, hdcSrc, 0, 0, SRCCOPY), "(%ld): BitBlt failed", iBmpFormat); + + /* Test background color */ + c = GetPixel(hdcDst, 0, 0); + expected = 0xffffff; + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + /* Test foreground color */ + c = GetPixel(hdcDst, 1, 0); + expected = 0x000000; + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + if (pvBits) + { + c = GetDIBPixel(iBmpFormat, pvBits, 0); + expected = iXlateFromRGB(iBmpFormat, GetBkColor(hdcSrc)); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + c = GetDIBPixel(iBmpFormat, pvBits, 1); + expected = iXlateFromRGB(iBmpFormat, GetTextColor(hdcSrc)); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + } + + /* Set different dc fore and back colors */ + SetTextColor(hdcSrc, 0xf00f0f); + SetBkColor(hdcSrc, 0xf0ff0f); + SetTextColor(hdcDst, 0xefFee5); + SetBkColor(hdcDst, 0x100121); + + /* Make sure this alone didn't affect the resulting colors */ + c = GetPixel(hdcDst, 0, 0); + expected = 0xffffff; + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + c = GetPixel(hdcDst, 1, 0); + expected = 0x000000; + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + /* Repeat the bitblt operation */ + ok(BitBlt(hdcDst, 0, 0, 2, 2, hdcSrc, 0, 0, SRCCOPY), "(%ld): BitBlt failed", iBmpFormat); + + /* Test background color */ + c = GetPixel(hdcDst, 0, 0); + expected = GetClosestColor(iBmpFormat, GetBkColor(hdcDst), 0xffffff); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + /* Test foreground color */ + c = GetPixel(hdcDst, 1, 0); + expected = GetClosestColor(iBmpFormat, GetTextColor(hdcDst), 0); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + if (pvBits) + { + c = GetDIBPixel(iBmpFormat, pvBits, 0); + expected = iXlateFromRGB(iBmpFormat, GetBkColor(hdcDst)); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + c = GetDIBPixel(iBmpFormat, pvBits, 1); + expected = iXlateFromRGB(iBmpFormat, GetTextColor(hdcDst)); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + } + + /* Set inverted fore and back colors */ + SetTextColor(hdcSrc, 0); + SetBkColor(hdcSrc, 0xffffff); + SetTextColor(hdcDst, 0xffffff); + SetBkColor(hdcDst, 0x000000); + + /* Repeat the bitblt operation */ + ok(BitBlt(hdcDst, 0, 0, 2, 2, hdcSrc, 0, 0, SRCCOPY), "(%ld): BitBlt failed", iBmpFormat); + + /* Test background color */ + c = GetPixel(hdcDst, 0, 0); + expected = GetClosestColor(iBmpFormat, GetBkColor(hdcDst), 0xffffff); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + /* Test foreground color */ + c = GetPixel(hdcDst, 1, 0); + expected = GetClosestColor(iBmpFormat, GetTextColor(hdcDst), 0); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + if (pvBits) + { + c = GetDIBPixel(iBmpFormat, pvBits, 0); + expected = iXlateFromRGB(iBmpFormat, GetBkColor(hdcDst)); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + c = GetDIBPixel(iBmpFormat, pvBits, 1); + expected = iXlateFromRGB(iBmpFormat, GetTextColor(hdcDst)); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + } + + +/* Hatch brush ****************************************************************/ + + /* Set dc fore and back colors */ + SetTextColor(hdcDst, 0x102030); + SetBkColor(hdcDst, 0xeeccdd); + SetBkMode(hdcDst, OPAQUE); + + /* Create a hatch brush */ + hbr = CreateHatchBrush(HS_DIAGCROSS, 0x123456); + + /* Fill the destination bitmap */ + rect.left = rect.top = 0; + rect.bottom = rect.right = 4; + ok(FillRect(hdcDst, &rect, hbr), "FillRect failed\n"); + + /* Test the fore color of the hatch brush */ + c = GetPixel(hdcDst, 0, 0); + expected = GetClosestColor(iBmpFormat, 0x123456, 0); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + /* Test the back color of the hatch brush */ + c = GetPixel(hdcDst, 1, 0); + expected = GetClosestColor(iBmpFormat, GetBkColor(hdcDst), 0xffffff); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + if (pvBits) + { + c = GetDIBPixel(iBmpFormat, pvBits, 0); + expected = iXlateFromRGB(iBmpFormat, 0x123456); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + c = GetDIBPixel(iBmpFormat, pvBits, 1); + expected = iXlateFromRGB(iBmpFormat, GetBkColor(hdcDst)); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + } + + DeleteObject(hbr); + +/* DIB brush ******************************************************************/ + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = 8; + bmi.bmiHeader.biHeight = 8; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 1; + bmi.bmiHeader.biYPelsPerMeter = 1; + bmi.bmiHeader.biClrUsed = 2; + bmi.bmiHeader.biClrImportant = 2; + bmi.bmiColors[0] = 0xeeeeee; + bmi.bmiColors[1] = 0x111111; + memset(bmi.aj, 0xaaaa, sizeof(bmi.aj)); + hbr = CreateDIBPatternBrushPt(&bmi, DIB_RGB_COLORS); + ok(hbr != 0, "CreateDIBPatternBrushPt failed\n"); + + rect.left = rect.top = 0; + rect.bottom = rect.right = 4; + ok(FillRect(hdcDst, &rect, hbr),"FillRect failed\n"); + + /* Test color 1 of the dib brush */ + c = GetPixel(hdcDst, 0, 0); + expected = GetClosestColor(iBmpFormat, bmi.bmiColors[1], 0); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + /* Test color 0 of the dib brush */ + c = GetPixel(hdcDst, 1, 0); + expected = GetClosestColor(iBmpFormat, bmi.bmiColors[0], 0xffffff); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + if (pvBits) + { + c = GetDIBPixel(iBmpFormat, pvBits, 0); + expected = iXlateFromRGB(iBmpFormat, bmi.bmiColors[1]); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + + c = GetDIBPixel(iBmpFormat, pvBits, 1); + expected = iXlateFromRGB(iBmpFormat, bmi.bmiColors[0]); + ok(c == expected, "(%ld): wrong color, expected %lx, got %lx\n", iBmpFormat, expected, c); + } + + DeleteObject(hbr); + + +} + +void +Test_SrcMono() +{ + HBITMAP hbmp; + struct + { + BITMAPINFOHEADER bmiHeader; + ULONG bmiColors[3]; + } bmi; + PVOID pvBits; + ULONG c, expected; + + SelectObject(hdcSrc, hbmp1bpp_a); + + Test_SrcMono1(BMF_1BPP, hbmp1bpp_b, 0); + Test_SrcMono1(iDcFormat, hbmpCompat, 0); + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = 2; + bmi.bmiHeader.biHeight = -2; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 16; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = 1; + bmi.bmiHeader.biYPelsPerMeter = 1; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + hbmp = CreateDIBSection(hdcDst, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &pvBits, NULL, 0); + ok(hbmp != 0, "CreateDIBSection failed\n"); + memset(pvBits, 0x55555555, 8 * 8 * 2); + + SelectObject(hdcDst, hbmp); + + c = GetPixel(hdcDst, 0, 0); + expected = iXlateToRGB(BMF_16BPP_555, 0x5555); + ok(c == expected, "expected %lx, got %lx\n", expected, c); + + expected = 0x123456; + SetPixel(hdcDst, 0, 0, expected); + expected = iXlateFromRGB(BMF_16BPP_555, expected); + c = *(volatile WORD*)pvBits; + ok(c == expected, "expected %lx, got %lx\n", expected, c); + + Test_SrcMono1(BMF_16BPP_555, hbmp, pvBits); + + DeleteObject(hbmp); + + /* Create a 565 DIB section */ + bmi.bmiHeader.biCompression = BI_BITFIELDS; + bmi.bmiHeader.biClrUsed = 3; + bmi.bmiHeader.biClrImportant = 3; + bmi.bmiColors[0] = 0xF800; + bmi.bmiColors[1] = 0x7E0; + bmi.bmiColors[2] = 0x1F; + hbmp = CreateDIBSection(hdcDst, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &pvBits, NULL, 0); + ok(hbmp != 0, "CreateDIBSection failed\n"); + SelectObject(hdcDst, hbmp); + + Test_SrcMono1(BMF_16BPP_565, hbmp, pvBits); + + DeleteObject(hbmp); + + /* Create a 32 bpp DIB section */ + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + hbmp = CreateDIBSection(hdcDst, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &pvBits, NULL, 0); + ok(hbmp != 0, "CreateDIBSection failed\n"); + SelectObject(hdcDst, hbmp); + + Test_SrcMono1(BMF_32BPP_BGR, hbmp, pvBits); + + DeleteObject(hbmp); + +} + + +START_TEST(xlate) +{ + Initialize(); + + Test_SrcMono(); +} + +// trunk: 41 failures + diff --git a/rostests/regtests_by_casper/regtests/regtests.c b/rostests/regtests_by_casper/regtests/regtests.c deleted file mode 100644 index ccda2f93d66..00000000000 --- a/rostests/regtests_by_casper/regtests/regtests.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * PROJECT: ReactOS kernel - * FILE: regtests/regtests/regtests.c - * PURPOSE: Regression testing framework - * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) - * UPDATE HISTORY: - * 23-10-2004 CSH Created - */ -#include - -HMODULE STDCALL -_GetModuleHandleA(LPCSTR lpModuleName) -{ - return GetModuleHandleA(lpModuleName); -} - -FARPROC STDCALL -_GetProcAddress(HMODULE hModule, - LPCSTR lpProcName) -{ - return GetProcAddress(hModule, lpProcName); -} - -HINSTANCE STDCALL -_LoadLibraryA(LPCSTR lpLibFileName) -{ - return LoadLibraryA(lpLibFileName); -} - -VOID STDCALL -_ExitProcess(UINT uExitCode) -{ - ExitProcess(uExitCode); -} - -HANDLE STDCALL -_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, - DWORD dwCreationFlags, LPDWORD lpThreadId) -{ - return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, - lpParameter, dwCreationFlags, lpThreadId); -} - -WINBOOL STDCALL -_TerminateThread(HANDLE hThread, DWORD dwExitCode) -{ - return TerminateThread(hThread, dwExitCode); -} - -DWORD STDCALL -_WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) -{ - return WaitForSingleObject(hHandle, dwMilliseconds); -} - -DWORD STDCALL -_GetLastError() -{ - return GetLastError(); -} - -VOID STDCALL -_CloseHandle(HANDLE handle) -{ - CloseHandle (handle); -} - -BOOL STDCALL -_GetThreadTimes(HANDLE hThread, LPFILETIME lpCreationTime, - LPFILETIME lpExitTime, LPFILETIME lpKernelTime, - LPFILETIME lpUserTime) -{ - return GetThreadTimes(hThread, lpCreationTime, lpExitTime, - lpKernelTime, lpUserTime); -} - -BOOL STDCALL -_SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass) -{ - return SetPriorityClass(hProcess, dwPriorityClass); -} - -BOOL STDCALL -_SetThreadPriority(HANDLE hThread, int nPriority) -{ - return SetThreadPriority(hThread, nPriority); -} - -HANDLE STDCALL -_GetCurrentProcess() -{ - return GetCurrentProcess(); -} - -HANDLE STDCALL -_GetCurrentThread() -{ - return GetCurrentThread(); -} - -VOID STDCALL -_Sleep(DWORD dwMilliseconds) -{ - return Sleep(dwMilliseconds); -} diff --git a/rostests/regtests_by_casper/regtests/regtests.def b/rostests/regtests_by_casper/regtests/regtests.def deleted file mode 100644 index cd492c37c75..00000000000 --- a/rostests/regtests_by_casper/regtests/regtests.def +++ /dev/null @@ -1,17 +0,0 @@ -LIBRARY REGTESTS.DLL -EXPORTS -_ExitProcess@4 -_GetModuleHandleA@4 -_GetProcAddress@8 -_LoadLibraryA@4 -_CreateThread@24 -_TerminateThread@8 -_WaitForSingleObject@8 -_GetLastError@0 -_CloseHandle@4 -_GetThreadTimes@20 -_SetPriorityClass@8 -_SetThreadPriority@8 -_GetCurrentProcess@0 -_GetCurrentThread@0 -_Sleep@4 diff --git a/rostests/regtests_by_casper/regtests/regtests.rbuild b/rostests/regtests_by_casper/regtests/regtests.rbuild deleted file mode 100644 index 1822536009f..00000000000 --- a/rostests/regtests_by_casper/regtests/regtests.rbuild +++ /dev/null @@ -1,7 +0,0 @@ - - - . - - kernel32 - regtests.c - diff --git a/rostests/regtests_by_casper/shared/regtests.c b/rostests/regtests_by_casper/shared/regtests.c deleted file mode 100644 index 3513911b600..00000000000 --- a/rostests/regtests_by_casper/shared/regtests.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * PROJECT: ReactOS kernel - * FILE: regtests/shared/regtests.c - * PURPOSE: Regression testing framework - * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) - * UPDATE HISTORY: - * 06-07-2003 CSH Created - */ -#define WIN32_NO_STATUS -#include -#define NTOS_MODE_USER -#include -#include -#include "regtests.h" - -#define NDEBUG -#include - -typedef struct _PERFORM_TEST_ARGS -{ - TestOutputRoutine OutputRoutine; - _PTEST Test; - LPSTR TestName; - DWORD Result; - char Buffer[5000]; - DWORD Time; -} PERFORM_TEST_ARGS; - -int _Result; -char *_Buffer; - -static LIST_ENTRY AllTests; - -VOID -InitializeTests() -{ - InitializeListHead(&AllTests); -} - -char* -FormatExecutionTime(char *buffer, ULONG milliseconds) -{ - sprintf(buffer, - "%ldms", - milliseconds); - return buffer; -} - -DWORD WINAPI -PerformTest(PVOID _arg) -{ - PERFORM_TEST_ARGS *Args = (PERFORM_TEST_ARGS *)_arg; - _PTEST Test = Args->Test; - - _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_IDLE); - - memset(Args->Buffer, 0, sizeof(Args->Buffer)); - - _SEH_TRY { - _Result = TS_OK; - _Buffer = Args->Buffer; - (Test->Routine)(TESTCMD_RUN); - Args->Result = _Result; - } _SEH_HANDLE { - Args->Result = TS_FAILED; - sprintf(Args->Buffer, "due to exception 0x%lx", _SEH_GetExceptionCode()); - } _SEH_END; - return 1; -} - -VOID -ControlNormalTest(HANDLE hThread, - PERFORM_TEST_ARGS *Args, - DWORD TimeOut) -{ - _FILETIME time; - _FILETIME executionTime; - DWORD status; - - status = _WaitForSingleObject(hThread, TimeOut); - if (status == WAIT_TIMEOUT) - { - _TerminateThread(hThread, 0); - Args->Result = TS_TIMEDOUT; - } - status = _GetThreadTimes(hThread, - &time, - &time, - &time, - &executionTime); - Args->Time = executionTime.dwLowDateTime / 10000; -} - -VOID -DisplayResult(PERFORM_TEST_ARGS* Args, - LPSTR OutputBuffer) -{ - char Format[100]; - - if (Args->Result == TS_OK) - { - sprintf(OutputBuffer, - "[%s] Success [%s]\n", - Args->TestName, - FormatExecutionTime(Format, - Args->Time)); - } - else if (Args->Result == TS_TIMEDOUT) - { - sprintf(OutputBuffer, - "[%s] Timed out [%s]\n", - Args->TestName, - FormatExecutionTime(Format, - Args->Time)); - } - else - sprintf(OutputBuffer, "[%s] Failed (%s)\n", Args->TestName, Args->Buffer); - - if (Args->OutputRoutine != NULL) - (*Args->OutputRoutine)(OutputBuffer); - else - DbgPrint(OutputBuffer); -} - -VOID -ControlTest(HANDLE hThread, - PERFORM_TEST_ARGS *Args, - DWORD TestType, - DWORD TimeOut) -{ - switch (TestType) - { - case TT_NORMAL: - ControlNormalTest(hThread, Args, TimeOut); - break; - default: - printf("Unknown test type %ld\n", TestType); - break; - } -} - -VOID -PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName) -{ - PLIST_ENTRY CurrentEntry; - PLIST_ENTRY NextEntry; - _PTEST Current; - PERFORM_TEST_ARGS Args; - HANDLE hThread; - char OutputBuffer[1024]; - char Name[200]; - DWORD TestType; - DWORD TimeOut; - - Args.OutputRoutine = OutputRoutine; - Args.TestName = Name; - Args.Time = 0; - - CurrentEntry = AllTests.Flink; - for (; CurrentEntry != &AllTests; CurrentEntry = NextEntry) - { - NextEntry = CurrentEntry->Flink; - Current = CONTAINING_RECORD(CurrentEntry, _TEST, ListEntry); - Args.Test = Current; - - /* Get name of test */ - memset(Name, 0, sizeof(Name)); - - _Result = TS_OK; - _Buffer = Name; - (Current->Routine)(TESTCMD_TESTNAME); - if (_Result != TS_OK) - { - if (TestName != NULL) - continue; - strcpy(Name, "Unnamed"); - } - - if ((TestName != NULL) && (_stricmp(Name, TestName) != 0)) - continue; - - TestType = TT_NORMAL; - _Result = TS_OK; - _Buffer = (char *)&TestType; - (Current->Routine)(TESTCMD_TESTTYPE); - if (_Result != TS_OK) - TestType = TT_NORMAL; - - /* Get timeout for test */ - TimeOut = 0; - _Result = TS_OK; - _Buffer = (char *)&TimeOut; - (Current->Routine)(TESTCMD_TIMEOUT); - if (_Result != TS_OK || TimeOut == INFINITE) - TimeOut = 5000; - - /* Run test in a separate thread */ - hThread = _CreateThread(NULL, 0, PerformTest, (PVOID)&Args, 0, NULL); - if (hThread == NULL) - { - printf("[%s] Failed (CreateThread() failed: %ld)\n", - Name, - _GetLastError()); - Args.Result = TS_FAILED; - } - else - ControlTest(hThread, &Args, TestType, TimeOut); - - DisplayResult(&Args, OutputBuffer); - } -} - -VOID -AddTest(TestRoutine Routine) -{ - _PTEST Test; - - Test = (_PTEST) malloc(sizeof(_TEST)); - if (Test == NULL) - { - DbgPrint("Out of memory"); - return; - } - - Test->Routine = Routine; - - InsertTailList(&AllTests, &Test->ListEntry); -} - -PVOID STDCALL -FrameworkGetHook(ULONG index) -{ - return FrameworkGetHookInternal(index); -} diff --git a/rostests/regtests_by_casper/shared/regtests.h b/rostests/regtests_by_casper/shared/regtests.h deleted file mode 100644 index eeca12f68e1..00000000000 --- a/rostests/regtests_by_casper/shared/regtests.h +++ /dev/null @@ -1,384 +0,0 @@ -/* - * PROJECT: ReactOS kernel - * FILE: regtests/shared/regtests.h - * PURPOSE: Regression testing - * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) - * UPDATE HISTORY: - * 06-07-2003 CSH Created - */ -#ifndef __REGTESTS_H -#define __REGTESTS_H -#include -#include - -typedef DWORD (STDCALL _LPTHREAD_START_ROUTINE)(LPVOID lpParameter); - -typedef struct __FILETIME -{ - DWORD dwLowDateTime; - DWORD dwHighDateTime; -} _FILETIME, *_PFILETIME, *_LPFILETIME; - -extern void SetupOnce(); - -#define _SetupOnce() \ -void SetupOnce() - -/* Valid values for Command parameter of TestRoutine */ -#define TESTCMD_RUN 0 /* Buffer contains information about what failed */ -#define TESTCMD_TESTTYPE 1 /* Buffer contains type of test */ -#define TESTCMD_TESTNAME 2 /* Buffer contains description of test */ -#define TESTCMD_TIMEOUT 3 /* Buffer contains timeout for test (DWORD, default is 5000 ms) */ - -/* Test types */ -#define TT_NORMAL 0 - -/* Valid values for return values of TestRoutine */ -#define TS_TIMEDOUT ((DWORD)-2) -#define TS_EXCEPTION ((DWORD)-1) -#define TS_OK 0 -#define TS_FAILED 1 - -extern int _Result; -extern char *_Buffer; - -/* Macros to simplify tests */ -#define _DispatcherTypeTimeout(FunctionName, TestName, TestType, TimeOut) \ -void \ -FunctionName(int Command) \ -{ \ - switch (Command) \ - { \ - case TESTCMD_RUN: \ - RunTest(); \ - break; \ - case TESTCMD_TESTTYPE: \ - *(PDWORD)_Buffer = (DWORD)TestType; \ - break; \ - case TESTCMD_TESTNAME: \ - strcpy(_Buffer, TestName); \ - break; \ - case TESTCMD_TIMEOUT: \ - *(PDWORD)_Buffer = (DWORD)TimeOut; \ - break; \ - default: \ - _Result = TS_FAILED; \ - break; \ - } \ -} - -#define _DispatcherTimeout(FunctionName, TestName, TimeOut) \ - _DispatcherTypeTimeout(FunctionName, TestName, TT_NORMAL, TimeOut) - -#define _DispatcherType(FunctionName, TestName, TestType) \ - _DispatcherTypeTimeout(FunctionName, TestName, TestType, 5000) - -#define _Dispatcher(FunctionName, TestName) \ - _DispatcherTimeout(FunctionName, TestName, 5000) - -static __inline void -AppendAssertion(char *message) -{ - if (strlen(_Buffer) != 0) - strcat(_Buffer, "\n"); - strcat(_Buffer, message); - _Result = TS_FAILED; -} - -#define _AssertTrue(_Condition) \ -{ \ - if (!(_Condition)) \ - { \ - char _message[100]; \ - sprintf(_message, "Condition was not true at %s:%d", \ - __FILE__, __LINE__); \ - AppendAssertion(_message); \ - } \ -} - -#define _AssertFalse(_Condition) \ -{ \ - if (_Condition) \ - { \ - char _message[100]; \ - sprintf(_message, "Condition was not false at %s:%d", \ - __FILE__, __LINE__); \ - AppendAssertion(_message); \ - } \ -} - -#define _AssertEqualValue(_Expected, _Actual) \ -{ \ - ULONG __Expected = (ULONG) (_Expected); \ - ULONG __Actual = (ULONG) (_Actual); \ - if ((__Expected) != (__Actual)) \ - { \ - char _message[100]; \ - sprintf(_message, "Expected %ld/0x%.08lx was %ld/0x%.08lx at %s:%d", \ - (__Expected), (__Expected), (__Actual), (__Actual), __FILE__, __LINE__); \ - AppendAssertion(_message); \ - } \ -} - -#define _AssertEqualWideString(_Expected, _Actual) \ -{ \ - LPWSTR __Expected = (LPWSTR) (_Expected); \ - LPWSTR __Actual = (LPWSTR) (_Actual); \ - if (wcscmp((__Expected), (__Actual)) != 0) \ - { \ - char _message[100]; \ - sprintf(_message, "Expected %S was %S at %s:%d", \ - (__Expected), (__Actual), __FILE__, __LINE__); \ - AppendAssertion(_message); \ - } \ -} - -#define _AssertNotEqualValue(_Expected, _Actual) \ -{ \ - ULONG __Expected = (ULONG) (_Expected); \ - ULONG __Actual = (ULONG) (_Actual); \ - if ((__Expected) == (__Actual)) \ - { \ - char _message[100]; \ - sprintf(_message, "Actual value expected to be different from %ld/0x%.08lx at %s:%d", \ - (__Expected), (__Expected), __FILE__, __LINE__); \ - AppendAssertion(_message); \ - } \ -} - - -/* - * Test routine prototype - * Command - The command to process - */ -typedef void (*TestRoutine)(int Command); - -/* - * Test output routine prototype - * Buffer - Address of buffer with text to output - */ -typedef void (*TestOutputRoutine)(char *Buffer); - -/* - * Test driver entry routine. -* OutputRoutine - Output routine. - * TestName - If NULL all tests are run. If non-NULL specifies the test to be run - */ -typedef void (STDCALL *TestDriverMain)(TestOutputRoutine OutputRoutine, char *TestName); - -typedef struct __TEST -{ - LIST_ENTRY ListEntry; - TestRoutine Routine; -} _TEST, *_PTEST; - -extern VOID InitializeTests(); -extern VOID RegisterTests(); -extern VOID PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName); - - -typedef struct __API_DESCRIPTION -{ - PCHAR FileName; - PCHAR FunctionName; - PCHAR ForwardedFunctionName; - PVOID FunctionAddress; - PVOID MockFunctionAddress; -} _API_DESCRIPTION, *_PAPI_DESCRIPTION; - -extern _API_DESCRIPTION ExternalDependencies[]; -extern ULONG MaxExternalDependency; - -HANDLE STDCALL -_GetModuleHandleA(LPCSTR lpModuleName); - -PVOID STDCALL -_GetProcAddress(HANDLE hModule, - LPCSTR lpProcName); - -HANDLE STDCALL -_LoadLibraryA(LPCSTR lpLibFileName); - -VOID STDCALL -_ExitProcess(UINT uExitCode); - -HANDLE STDCALL -_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, - _LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, - DWORD dwCreationFlags, LPDWORD lpThreadId); - -BOOL STDCALL -_TerminateThread(HANDLE hThread, DWORD dwExitCode); - -DWORD STDCALL -_WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); - -DWORD STDCALL -_GetLastError(); - -VOID STDCALL -_CloseHandle(HANDLE handle); - -BOOL STDCALL -_GetThreadTimes(HANDLE hThread, - _LPFILETIME lpCreationTime, - _LPFILETIME lpExitTime, - _LPFILETIME lpKernelTime, - _LPFILETIME lpUserTime); - -BOOL STDCALL -_SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass); - -BOOL STDCALL -_SetThreadPriority(HANDLE hThread, int nPriority); - -HANDLE STDCALL -_GetCurrentProcess(); - -HANDLE STDCALL -_GetCurrentThread(); - -VOID STDCALL -_Sleep(DWORD dwMilliseconds); - - -static __inline PCHAR -FrameworkGetExportedFunctionNameInternal(_PAPI_DESCRIPTION ApiDescription) -{ - if (ApiDescription->ForwardedFunctionName != NULL) - { - return ApiDescription->ForwardedFunctionName; - } - else - { - return ApiDescription->FunctionName; - } -} - -static __inline PVOID -FrameworkGetFunction(_PAPI_DESCRIPTION ApiDescription) -{ - HANDLE hModule; - PVOID function = NULL; - PCHAR exportedFunctionName; - - exportedFunctionName = FrameworkGetExportedFunctionNameInternal(ApiDescription); - - hModule = _GetModuleHandleA(ApiDescription->FileName); - if (hModule != NULL) - { - function = _GetProcAddress(hModule, exportedFunctionName); - } - else - { - hModule = _LoadLibraryA(ApiDescription->FileName); - if (hModule != NULL) - { - function = _GetProcAddress(hModule, exportedFunctionName); - //FreeLibrary(hModule); - } - } - return function; -} - -static __inline PVOID -FrameworkGetHookInternal(ULONG index) -{ - PVOID address; - PCHAR exportedFunctionName; - - if (index > MaxExternalDependency) - return NULL; - - if (ExternalDependencies[index].MockFunctionAddress != NULL) - return ExternalDependencies[index].MockFunctionAddress; - - if (ExternalDependencies[index].FunctionAddress != NULL) - return ExternalDependencies[index].FunctionAddress; - - exportedFunctionName = FrameworkGetExportedFunctionNameInternal(&ExternalDependencies[index]); - - printf("Calling function '%s' in DLL '%s'.\n", - exportedFunctionName, - ExternalDependencies[index].FileName); - - address = FrameworkGetFunction(&ExternalDependencies[index]); - - if (address == NULL) - { - printf("Function '%s' not found in DLL '%s'.\n", - exportedFunctionName, - ExternalDependencies[index].FileName); - } - ExternalDependencies[index].FunctionAddress = address; - - return address; -} - - -static __inline VOID -_SetHook(PCHAR name, - PVOID address) -{ - _PAPI_DESCRIPTION api; - ULONG index; - - for (index = 0; index <= MaxExternalDependency; index++) - { - api = &ExternalDependencies[index]; - if (strcmp(api->FunctionName, name) == 0) - { - api->MockFunctionAddress = address; - return; - } - } -} - -typedef struct __HOOK -{ - PCHAR FunctionName; - PVOID FunctionAddress; -} _HOOK, *_PHOOK; - -static __inline VOID -_SetHooks(_PHOOK hookTable) -{ - _PHOOK hook; - - hook = &hookTable[0]; - while (hook->FunctionName != NULL) - { - _SetHook(hook->FunctionName, - hook->FunctionAddress); - hook++; - } -} - -static __inline VOID -_UnsetHooks(_PHOOK hookTable) -{ - _PHOOK hook; - - hook = &hookTable[0]; - while (hook->FunctionName != NULL) - { - _SetHook(hook->FunctionName, - NULL); - hook++; - } -} - -static __inline VOID -_UnsetAllHooks() -{ - _PAPI_DESCRIPTION api; - ULONG index; - - for (index = 0; index <= MaxExternalDependency; index++) - { - api = &ExternalDependencies[index]; - api->MockFunctionAddress = NULL; - } -} - -#endif /* __REGTESTS_H */ diff --git a/rostests/regtests_by_casper/shared/rtshared.rbuild b/rostests/regtests_by_casper/shared/rtshared.rbuild deleted file mode 100644 index 0fa7e5c8cdd..00000000000 --- a/rostests/regtests_by_casper/shared/rtshared.rbuild +++ /dev/null @@ -1,5 +0,0 @@ - - . - - regtests.c - diff --git a/rostests/rosautotest/CConfiguration.cpp b/rostests/rosautotest/CConfiguration.cpp new file mode 100644 index 00000000000..9e577952b29 --- /dev/null +++ b/rostests/rosautotest/CConfiguration.cpp @@ -0,0 +1,207 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class for managing all the configuration parameters + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +#define CONFIGURATION_FILENAMEA "rosautotest.ini" +#define CONFIGURATION_FILENAMEW L"rosautotest.ini" + +typedef void (WINAPI *GETSYSINFO)(LPSYSTEM_INFO); + +/** + * Constructs an empty CConfiguration object + */ +CConfiguration::CConfiguration() +{ + WCHAR WindowsDirectory[MAX_PATH]; + + /* Zero-initialize variables */ + m_CrashRecovery = false; + m_Shutdown = false; + m_Submit = false; + + /* Check if we are running under ReactOS from the SystemRoot directory */ + if(!GetWindowsDirectoryW(WindowsDirectory, MAX_PATH)) + FATAL("GetWindowsDirectoryW failed"); + + m_IsReactOS = !_wcsnicmp(&WindowsDirectory[3], L"reactos", 7); +} + +/** + * Parses the passed parameters and sets the appropriate configuration settings. + * + * @param argc + * The number of parameters (argc parameter of the wmain function) + * + * @param argv + * Pointer to a wchar_t array containing the parameters (argv parameter of the wmain function) + */ +void +CConfiguration::ParseParameters(int argc, wchar_t* argv[]) +{ + /* Parse the command line arguments */ + for(int i = 1; i < argc; i++) + { + if(argv[i][0] == '-' || argv[i][0] == '/') + { + switch(argv[i][1]) + { + case 'c': + ++i; + m_Comment = UnicodeToAscii(argv[i]); + break; + + case 'r': + m_CrashRecovery = true; + break; + + case 's': + m_Shutdown = true; + break; + + case 'w': + m_Submit = true; + break; + + default: + throw CInvalidParameterException(); + } + } + else + { + /* Which parameter is this? */ + if(m_Module.empty()) + { + /* Copy the parameter */ + m_Module = argv[i]; + } + else if(m_Test.empty()) + { + /* Copy the parameter converted to ASCII */ + m_Test = UnicodeToAscii(argv[i]); + } + else + { + throw CInvalidParameterException(); + } + } + } + + /* The /r and /w options shouldn't be used in conjunction */ + if(m_CrashRecovery && m_Submit) + throw CInvalidParameterException(); +} + +/** + * Gets information about the running system and sets the appropriate configuration settings. + */ +void +CConfiguration::GetSystemInformation() +{ + char ProductType; + GETSYSINFO GetSysInfo; + HMODULE hKernel32; + OSVERSIONINFOEXW os; + stringstream ss; + SYSTEM_INFO si; + + /* Get the build from the define */ + ss << "&revision="; + ss << KERNEL_VERSION_BUILD_HEX; + + ss << "&platform="; + + if(m_IsReactOS) + { + ss << "reactos"; + } + else + { + /* No, then use the info from GetVersionExW */ + os.dwOSVersionInfoSize = sizeof(os); + + if(!GetVersionExW((LPOSVERSIONINFOW)&os)) + FATAL("GetVersionExW failed\n"); + + if(os.dwMajorVersion < 5) + EXCEPTION("Application requires at least Windows 2000!\n"); + + if(os.wProductType == VER_NT_WORKSTATION) + ProductType = 'w'; + else + ProductType = 's'; + + /* Print all necessary identification information into the Platform string */ + ss << os.dwMajorVersion << '.' + << os.dwMinorVersion << '.' + << os.dwBuildNumber << '.' + << os.wServicePackMajor << '.' + << os.wServicePackMinor << '.' + << ProductType << '.'; + } + + /* We also need to know about the processor architecture. + To retrieve this information accurately, check whether "GetNativeSystemInfo" is exported and use it then, otherwise fall back to "GetSystemInfo". */ + hKernel32 = GetModuleHandleW(L"KERNEL32.DLL"); + GetSysInfo = (GETSYSINFO)GetProcAddress(hKernel32, "GetNativeSystemInfo"); + + if(!GetSysInfo) + GetSysInfo = (GETSYSINFO)GetProcAddress(hKernel32, "GetSystemInfo"); + + GetSysInfo(&si); + ss << si.wProcessorArchitecture; + + m_SystemInfoRequestString = ss.str(); +} + +/** + * Reads additional configuration options from the INI file. + * + * ParseParameters should be called before this function to get the desired result. + */ +void +CConfiguration::GetConfigurationFromFile() +{ + DWORD Length; + string Value; + WCHAR ConfigFile[MAX_PATH]; + + /* Most values are only needed if we're going to submit anything */ + if(m_Submit) + { + /* Build the path to the configuration file from the application's path */ + GetModuleFileNameW(NULL, ConfigFile, MAX_PATH); + Length = wcsrchr(ConfigFile, '\\') - ConfigFile + 1; + wcscpy(&ConfigFile[Length], CONFIGURATION_FILENAMEW); + + /* Check if it exists */ + if(GetFileAttributesW(ConfigFile) == INVALID_FILE_ATTRIBUTES) + EXCEPTION("Missing \"" CONFIGURATION_FILENAMEA "\" configuration file!\n"); + + /* Get the user name */ + m_AuthenticationRequestString = "&username="; + Value = GetINIValue(L"Login", L"UserName", ConfigFile); + + if(Value.empty()) + EXCEPTION("UserName is missing in the configuration file\n"); + + m_AuthenticationRequestString += EscapeString(Value); + + /* Get the password */ + m_AuthenticationRequestString += "&password="; + Value = GetINIValue(L"Login", L"Password", ConfigFile); + + if(Value.empty()) + EXCEPTION("Password is missing in the configuration file\n"); + + m_AuthenticationRequestString += EscapeString(Value); + + /* If we don't have any Comment string yet, try to find one in the INI file */ + if(m_Comment.empty()) + m_Comment = GetINIValue(L"Submission", L"Comment", ConfigFile); + } +} diff --git a/rostests/rosautotest/CConfiguration.h b/rostests/rosautotest/CConfiguration.h new file mode 100644 index 00000000000..b65db7d6e5e --- /dev/null +++ b/rostests/rosautotest/CConfiguration.h @@ -0,0 +1,38 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class for managing all the configuration parameters + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CConfiguration +{ +private: + bool m_CrashRecovery; + bool m_IsReactOS; + bool m_Shutdown; + bool m_Submit; + string m_Comment; + wstring m_Module; + string m_Test; + + string m_AuthenticationRequestString; + string m_SystemInfoRequestString; + +public: + CConfiguration(); + void ParseParameters(int argc, wchar_t* argv[]); + void GetSystemInformation(); + void GetConfigurationFromFile(); + + bool DoCrashRecovery() const { return m_CrashRecovery; } + bool DoShutdown() const { return m_Shutdown; } + bool DoSubmit() const { return m_Submit; } + bool IsReactOS() const { return m_IsReactOS; } + const string& GetComment() const { return m_Comment; } + const wstring& GetModule() const { return m_Module; } + const string& GetTest() const { return m_Test; } + + const string& GetAuthenticationRequestString() const { return m_AuthenticationRequestString; } + const string& GetSystemInfoRequestString() const { return m_SystemInfoRequestString; } +}; diff --git a/rostests/rosautotest/CFatalException.cpp b/rostests/rosautotest/CFatalException.cpp new file mode 100644 index 00000000000..1c2a1699b9d --- /dev/null +++ b/rostests/rosautotest/CFatalException.cpp @@ -0,0 +1,26 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Fatal program exception with automatically added information + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +/** + * Constructs a CFatalException object, which is catched in wmain as an exception. + * You should always use the FATAL macro for throwing this exception. + * + * @param File + * Constant pointer to a char array with the source file where the exception occured (__FILE__) + * + * @param Line + * Integer value with the appropriate source line (__LINE__) + * + * @param Message + * Constant pointer to a char array containing a short message about the exception + */ +CFatalException::CFatalException(const char* File, int Line, const char* Message) + : m_File(File), m_Line(Line), m_Message(Message) +{ +} diff --git a/rostests/rosautotest/CFatalException.h b/rostests/rosautotest/CFatalException.h new file mode 100644 index 00000000000..a49f0c246c8 --- /dev/null +++ b/rostests/rosautotest/CFatalException.h @@ -0,0 +1,21 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Fatal program exception with automatically added information + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CFatalException +{ +private: + string m_File; + int m_Line; + string m_Message; + +public: + CFatalException(const char* File, int Line, const char* Message); + + const string& GetFile() const { return m_File; } + int GetLine() const { return m_Line; } + const string& GetMessage() const { return m_Message; } +}; diff --git a/rostests/rosautotest/CInvalidParameterException.cpp b/rostests/rosautotest/CInvalidParameterException.cpp new file mode 100644 index 00000000000..f28903f860f --- /dev/null +++ b/rostests/rosautotest/CInvalidParameterException.cpp @@ -0,0 +1,15 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Empty exception thrown when the parameter processor detects an invalid parameter + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +/** + * Constructs an empty CInvalidParameterException object, which is catched in wmain as an exception. + */ +CInvalidParameterException::CInvalidParameterException() +{ +} diff --git a/rostests/rosautotest/CInvalidParameterException.h b/rostests/rosautotest/CInvalidParameterException.h new file mode 100644 index 00000000000..f3a87575cc2 --- /dev/null +++ b/rostests/rosautotest/CInvalidParameterException.h @@ -0,0 +1,12 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Empty exception thrown when the parameter processor detects an invalid parameter + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CInvalidParameterException +{ +public: + CInvalidParameterException(); +}; diff --git a/rostests/rosautotest/CJournaledTestList.cpp b/rostests/rosautotest/CJournaledTestList.cpp new file mode 100644 index 00000000000..ed0a74a32a0 --- /dev/null +++ b/rostests/rosautotest/CJournaledTestList.cpp @@ -0,0 +1,291 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a journaled test list for the Crash Recovery feature + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +static const char szJournalHeader[] = "RAT_J-V1"; +static const WCHAR szJournalFileName[] = L"rosautotest.journal"; + +/** + * Constructs a CJournaledTestList object for an associated CTest-derived object. + * + * @param Test + * Pointer to a CTest-derived object, for which this test list shall serve. + */ +CJournaledTestList::CJournaledTestList(CTest* Test) + : CTestList(Test) +{ + WCHAR JournalFile[MAX_PATH]; + + m_hJournal = INVALID_HANDLE_VALUE; + + /* Build the path to the journal file */ + if(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, JournalFile) != S_OK) + FATAL("SHGetFolderPathW failed\n"); + + m_JournalFile = JournalFile; + m_JournalFile += L"\\rosautotest\\"; + + /* Create the directory if necessary */ + if(GetFileAttributesW(m_JournalFile.c_str()) == INVALID_FILE_ATTRIBUTES) + CreateDirectoryW(m_JournalFile.c_str(), NULL); + + m_JournalFile += szJournalFileName; + + /* Check if the journal already exists */ + if(GetFileAttributesW(m_JournalFile.c_str()) == INVALID_FILE_ATTRIBUTES) + WriteInitialJournalFile(); + else + LoadJournalFile(); +} + +/** + * Destructs a CJournaledTestList object. + */ +CJournaledTestList::~CJournaledTestList() +{ + if(m_hJournal != INVALID_HANDLE_VALUE) + CloseHandle(m_hJournal); +} + +/** + * Opens the journal file through the CreateFileW API using the m_hJournal handle. + * + * @param DesiredAccess + * dwDesiredAccess parameter passed to CreateFileW + * + * @param CreateNew + * true if the journal file shall be created, false if an existing one shall be opened + */ +void +CJournaledTestList::OpenJournal(DWORD DesiredAccess, bool CreateNew) +{ + m_hJournal = CreateFileW(m_JournalFile.c_str(), DesiredAccess, 0, NULL, (CreateNew ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL, NULL); + + if(m_hJournal == INVALID_HANDLE_VALUE) + FATAL("CreateFileW failed\n"); +} + +/** + * Serializes a std::string and writes it into the opened journal file. + * + * @param String + * The std::string to serialize + * + * @see UnserializeFromBuffer + */ +void +CJournaledTestList::SerializeIntoJournal(const string& String) +{ + DWORD BytesWritten; + WriteFile(m_hJournal, String.c_str(), String.size() + 1, &BytesWritten, NULL); +} + +/** + * Serializes a std::wstring and writes it into the opened journal file. + * + * @param String + * The std::wstring to serialize + * + * @see UnserializeFromBuffer + */ +void +CJournaledTestList::SerializeIntoJournal(const wstring& String) +{ + DWORD BytesWritten; + WriteFile(m_hJournal, String.c_str(), (String.size() + 1) * sizeof(WCHAR), &BytesWritten, NULL); +} + +/** + * Unserializes the next std::string from the journal buffer. + * The passed buffer pointer will point at the next element afterwards. + * + * @param Buffer + * Pointer to a pointer to a char array containing the journal buffer + * + * @param Output + * The std::string to unserialize the value into. + */ +void +CJournaledTestList::UnserializeFromBuffer(char** Buffer, string& Output) +{ + Output = string(*Buffer); + *Buffer += Output.size() + 1; +} + +/** + * Unserializes the next std::wstring from the journal buffer. + * The passed buffer pointer will point at the next element afterwards. + * + * @param Buffer + * Pointer to a pointer to a char array containing the journal buffer + * + * @param Output + * The std::wstring to unserialize the value into. + */ +void +CJournaledTestList::UnserializeFromBuffer(char** Buffer, wstring& Output) +{ + Output = wstring((PWSTR)*Buffer); + *Buffer += (Output.size() + 1) * sizeof(WCHAR); +} + +/** + * Gets all tests to be run and writes an initial journal file with this information. + */ +void +CJournaledTestList::WriteInitialJournalFile() +{ + char TerminatingNull = 0; + CTestInfo* TestInfo; + DWORD BytesWritten; + + StringOut("Writing initial journal file...\n\n"); + + m_ListIterator = 0; + + /* Store all command lines in the m_List vector */ + while((TestInfo = m_Test->GetNextTestInfo()) != 0) + { + m_List.push_back(*TestInfo); + delete TestInfo; + } + + /* Serialize the vector and the iterator into a file */ + OpenJournal(GENERIC_WRITE, true); + + WriteFile(m_hJournal, szJournalHeader, sizeof(szJournalHeader), &BytesWritten, NULL); + WriteFile(m_hJournal, &m_ListIterator, sizeof(m_ListIterator), &BytesWritten, NULL); + + for(size_t i = 0; i < m_List.size(); i++) + { + SerializeIntoJournal(m_List[i].CommandLine); + SerializeIntoJournal(m_List[i].Module); + SerializeIntoJournal(m_List[i].Test); + } + + WriteFile(m_hJournal, &TerminatingNull, sizeof(TerminatingNull), &BytesWritten, NULL); + + CloseHandle(m_hJournal); + m_hJournal = INVALID_HANDLE_VALUE; + + /* m_ListIterator will be incremented before its first use */ + m_ListIterator = (size_t)-1; +} + +/** + * Loads the existing journal file and sets all members to the values saved in that file. + */ +void +CJournaledTestList::LoadJournalFile() +{ + char* Buffer; + char* pBuffer; + char FileHeader[sizeof(szJournalHeader)]; + DWORD BytesRead; + DWORD RemainingSize; + + StringOut("Loading journal file...\n\n"); + + OpenJournal(GENERIC_READ); + RemainingSize = GetFileSize(m_hJournal, NULL); + + /* Verify the header of the journal file */ + ReadFile(m_hJournal, FileHeader, sizeof(szJournalHeader), &BytesRead, NULL); + RemainingSize -= BytesRead; + + if(BytesRead != sizeof(szJournalHeader)) + EXCEPTION("Journal file contains no header!\n"); + + if(strcmp(FileHeader, szJournalHeader)) + EXCEPTION("Journal file has an unsupported header!\n"); + + /* Read the iterator */ + ReadFile(m_hJournal, &m_ListIterator, sizeof(m_ListIterator), &BytesRead, NULL); + RemainingSize -= BytesRead; + + if(BytesRead != sizeof(m_ListIterator)) + EXCEPTION("Journal file contains no m_ListIterator member!\n"); + + /* Read the rest of the file into a buffer */ + Buffer = new char[RemainingSize]; + pBuffer = Buffer; + ReadFile(m_hJournal, Buffer, RemainingSize, &BytesRead, NULL); + + CloseHandle(m_hJournal); + m_hJournal = NULL; + + /* Now recreate the m_List vector out of that information */ + while(*pBuffer) + { + CTestInfo TestInfo; + + UnserializeFromBuffer(&pBuffer, TestInfo.CommandLine); + UnserializeFromBuffer(&pBuffer, TestInfo.Module); + UnserializeFromBuffer(&pBuffer, TestInfo.Test); + + m_List.push_back(TestInfo); + } + + delete[] Buffer; +} + +/** + * Writes the current m_ListIterator value into the journal. + */ +void +CJournaledTestList::UpdateJournal() +{ + DWORD BytesWritten; + + OpenJournal(GENERIC_WRITE); + + /* Skip the header */ + SetFilePointer(m_hJournal, sizeof(szJournalHeader), NULL, FILE_CURRENT); + + WriteFile(m_hJournal, &m_ListIterator, sizeof(m_ListIterator), &BytesWritten, NULL); + + CloseHandle(m_hJournal); + m_hJournal = NULL; +} + +/** + * Interface to other classes for receiving information about the next test to be run. + * + * @return + * A pointer to a CTestInfo object, which contains all available information about the next test. + * The caller needs to free that object. + */ +CTestInfo* +CJournaledTestList::GetNextTestInfo() +{ + CTestInfo* TestInfo; + + /* Always jump to the next test here. + - If we're at the beginning of a new test list, the iterator will be set to 0. + - If we started with a loaded one, we assume that the test m_ListIterator is currently set + to crashed, so we move to the next test. */ + ++m_ListIterator; + + /* Check whether the iterator would already exceed the number of stored elements */ + if(m_ListIterator == m_List.size()) + { + /* Delete the journal and return no pointer */ + DeleteFileW(m_JournalFile.c_str()); + + TestInfo = NULL; + } + else + { + /* Update the journal with the current iterator and return the test information */ + UpdateJournal(); + + TestInfo = new CTestInfo(m_List[m_ListIterator]); + } + + return TestInfo; +} diff --git a/rostests/rosautotest/CJournaledTestList.h b/rostests/rosautotest/CJournaledTestList.h new file mode 100644 index 00000000000..47900d3aa13 --- /dev/null +++ b/rostests/rosautotest/CJournaledTestList.h @@ -0,0 +1,30 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a journaled test list for the Crash Recovery feature + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CJournaledTestList : public CTestList +{ +private: + HANDLE m_hJournal; + size_t m_ListIterator; + vector m_List; + wstring m_JournalFile; + + void LoadJournalFile(); + void OpenJournal(DWORD DesiredAccess, bool CreateNew = false); + void SerializeIntoJournal(const string& String); + void SerializeIntoJournal(const wstring& String); + void UnserializeFromBuffer(char** Buffer, string& Output); + void UnserializeFromBuffer(char** Buffer, wstring& Output); + void UpdateJournal(); + void WriteInitialJournalFile(); + +public: + CJournaledTestList(CTest* Test); + ~CJournaledTestList(); + + CTestInfo* GetNextTestInfo(); +}; diff --git a/rostests/rosautotest/CProcess.cpp b/rostests/rosautotest/CProcess.cpp new file mode 100644 index 00000000000..6697318f349 --- /dev/null +++ b/rostests/rosautotest/CProcess.cpp @@ -0,0 +1,36 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class able to create a new process and closing its handles on destruction (exception-safe) + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +/** + * Constructs a CProcess object and uses the CreateProcessW function to start the process immediately. + * + * @param CommandLine + * A std::wstring containing the command line to run + * + * @param StartupInfo + * Pointer to a STARTUPINFOW structure containing process startup information + */ +CProcess::CProcess(const wstring& CommandLine, LPSTARTUPINFOW StartupInfo) +{ + auto_array_ptr CommandLinePtr(new WCHAR[CommandLine.size() + 1]); + + wcscpy(CommandLinePtr, CommandLine.c_str()); + + if(!CreateProcessW(NULL, CommandLinePtr, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, StartupInfo, &m_ProcessInfo)) + FATAL("CreateProcessW failed\n"); +} + +/** + * Destructs a CProcess object and closes all handles belonging to the process. + */ +CProcess::~CProcess() +{ + CloseHandle(m_ProcessInfo.hThread); + CloseHandle(m_ProcessInfo.hProcess); +} diff --git a/rostests/rosautotest/CProcess.h b/rostests/rosautotest/CProcess.h new file mode 100644 index 00000000000..a46310c2c7e --- /dev/null +++ b/rostests/rosautotest/CProcess.h @@ -0,0 +1,18 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class able to create a new process and closing its handles on destruction (exception-safe) + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CProcess +{ +private: + PROCESS_INFORMATION m_ProcessInfo; + +public: + CProcess(const wstring& CommandLine, LPSTARTUPINFOW StartupInfo); + ~CProcess(); + + HANDLE GetProcessHandle() const { return m_ProcessInfo.hProcess; } +}; diff --git a/rostests/rosautotest/CSimpleException.cpp b/rostests/rosautotest/CSimpleException.cpp new file mode 100644 index 00000000000..f7ae841dff0 --- /dev/null +++ b/rostests/rosautotest/CSimpleException.cpp @@ -0,0 +1,20 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Simple exception containing just a message + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +/** + * Constructs a CSimpleException object, which is catched in wmain as an exception. + * You should always use the EXCEPTION or SSEXCEPTION macro for throwing this exception. + * + * @param Message + * Constant pointer to a char array containing a short message about the exception + */ +CSimpleException::CSimpleException(const char* Message) + : m_Message(Message) +{ +} diff --git a/rostests/rosautotest/CSimpleException.h b/rostests/rosautotest/CSimpleException.h new file mode 100644 index 00000000000..08bd09cd809 --- /dev/null +++ b/rostests/rosautotest/CSimpleException.h @@ -0,0 +1,17 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Simple exception containing just a message + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CSimpleException +{ +private: + string m_Message; + +public: + CSimpleException(const char* Message); + + const string& GetMessage() const { return m_Message; } +}; diff --git a/rostests/rosautotest/CTest.cpp b/rostests/rosautotest/CTest.cpp new file mode 100644 index 00000000000..742130072da --- /dev/null +++ b/rostests/rosautotest/CTest.cpp @@ -0,0 +1,8 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a generic Test, needs to be used by a derived class + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" diff --git a/rostests/rosautotest/CTest.h b/rostests/rosautotest/CTest.h new file mode 100644 index 00000000000..1f559b336f1 --- /dev/null +++ b/rostests/rosautotest/CTest.h @@ -0,0 +1,19 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a generic Test, needs to be used by a derived class + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CTest +{ +private: + virtual CTestInfo* GetNextTestInfo() = 0; + +public: + virtual void Run() = 0; + + /* All CTestList-derived classes need to access the private GetNextTestInfo method */ + friend class CJournaledTestList; + friend class CVirtualTestList; +}; diff --git a/rostests/rosautotest/CTestInfo.cpp b/rostests/rosautotest/CTestInfo.cpp new file mode 100644 index 00000000000..bea24821475 --- /dev/null +++ b/rostests/rosautotest/CTestInfo.cpp @@ -0,0 +1,8 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a bucket for Test information + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" diff --git a/rostests/rosautotest/CTestInfo.h b/rostests/rosautotest/CTestInfo.h new file mode 100644 index 00000000000..791480540fc --- /dev/null +++ b/rostests/rosautotest/CTestInfo.h @@ -0,0 +1,15 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a bucket for Test information + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CTestInfo +{ +public: + wstring CommandLine; + string Module; + string Test; + string Log; +}; diff --git a/rostests/rosautotest/CTestList.cpp b/rostests/rosautotest/CTestList.cpp new file mode 100644 index 00000000000..17e31d9739d --- /dev/null +++ b/rostests/rosautotest/CTestList.cpp @@ -0,0 +1,19 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a generic Test list, needs to be used by a derived class + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +/** + * Constructor serving for CTestList-derived classes. + * + * @param Test + * Pointer to a CTest-derived object, for which this test list shall serve. + */ +CTestList::CTestList(CTest* Test) : + m_Test(Test) +{ +} diff --git a/rostests/rosautotest/CTestList.h b/rostests/rosautotest/CTestList.h new file mode 100644 index 00000000000..49a559ac999 --- /dev/null +++ b/rostests/rosautotest/CTestList.h @@ -0,0 +1,17 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a generic Test list, needs to be used by a derived class + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CTestList +{ +protected: + CTest* m_Test; + + CTestList(CTest* Test); + +public: + virtual CTestInfo* GetNextTestInfo() = 0; +}; diff --git a/rostests/rosautotest/CVirtualTestList.cpp b/rostests/rosautotest/CVirtualTestList.cpp new file mode 100644 index 00000000000..0aade7202fa --- /dev/null +++ b/rostests/rosautotest/CVirtualTestList.cpp @@ -0,0 +1,32 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a virtual test list for the tests to be ran + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +/** + * Constructs a CVirtualTestList object for an associated CTest-derived object. + * + * @param Test + * Pointer to a CTest-derived object, for which this test list shall serve. + */ +CVirtualTestList::CVirtualTestList(CTest* Test) + : CTestList(Test) +{ +} + +/** + * Interface to other classes for receiving information about the next test to be run. + * + * @return + * A pointer to a CTestInfo object, which contains all available information about the next test. + * The caller needs to free that object. + */ +CTestInfo* +CVirtualTestList::GetNextTestInfo() +{ + return m_Test->GetNextTestInfo(); +} diff --git a/rostests/rosautotest/CVirtualTestList.h b/rostests/rosautotest/CVirtualTestList.h new file mode 100644 index 00000000000..d9d6d603e95 --- /dev/null +++ b/rostests/rosautotest/CVirtualTestList.h @@ -0,0 +1,14 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing a virtual test list for the tests to be ran + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CVirtualTestList : public CTestList +{ +public: + CVirtualTestList(CTest* Test); + + CTestInfo* GetNextTestInfo(); +}; diff --git a/rostests/rosautotest/CWebService.cpp b/rostests/rosautotest/CWebService.cpp new file mode 100644 index 00000000000..fbf4900ef27 --- /dev/null +++ b/rostests/rosautotest/CWebService.cpp @@ -0,0 +1,214 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing the interface to the "testman" Web Service + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +static const WCHAR szHostname[] = L"localhost"; +static const WCHAR szServerFile[] = L"testman/webservice/"; + +/** + * Constructs a CWebService object and immediately establishes a connection to the "testman" Web Service. + */ +CWebService::CWebService() +{ + /* Zero-initialize variables */ + m_hHTTP = NULL; + m_hHTTPRequest = NULL; + m_TestID = NULL; + + /* Establish an internet connection to the "testman" server */ + m_hInet = InternetOpenW(L"rosautotest", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + + if(!m_hInet) + FATAL("InternetOpenW failed\n"); + + m_hHTTP = InternetConnectW(m_hInet, szHostname, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + + if(!m_hHTTP) + FATAL("InternetConnectW failed\n"); +} + +/** + * Destructs a CWebService object and closes all connections to the Web Service. + */ +CWebService::~CWebService() +{ + if(m_hInet) + InternetCloseHandle(m_hInet); + + if(m_hHTTP) + InternetCloseHandle(m_hHTTP); + + if(m_hHTTPRequest) + InternetCloseHandle(m_hHTTPRequest); + + if(m_TestID) + delete m_TestID; +} + +/** + * Sends data to the Web Service. + * + * @param InputData + * A std::string containing all the data, which is going to be submitted as HTTP POST data. + * + * @return + * Returns a pointer to a char array containing the data received from the Web Service. + * The caller needs to free that pointer. + */ +PCHAR +CWebService::DoRequest(const string& InputData) +{ + const WCHAR szHeaders[] = L"Content-Type: application/x-www-form-urlencoded"; + + auto_array_ptr Data; + DWORD DataLength; + + /* Post our test results to the web service */ + m_hHTTPRequest = HttpOpenRequestW(m_hHTTP, L"POST", szServerFile, NULL, NULL, NULL, INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0); + + if(!m_hHTTPRequest) + FATAL("HttpOpenRequestW failed\n"); + + Data.reset(new char[InputData.size() + 1]); + strcpy(Data, InputData.c_str()); + + if(!HttpSendRequestW(m_hHTTPRequest, szHeaders, wcslen(szHeaders), Data, InputData.size())) + FATAL("HttpSendRequestW failed\n"); + + /* Get the response */ + if(!InternetQueryDataAvailable(m_hHTTPRequest, &DataLength, 0, 0)) + FATAL("InternetQueryDataAvailable failed\n"); + + Data.reset(new char[DataLength + 1]); + + if(!InternetReadFile(m_hHTTPRequest, Data, DataLength, &DataLength)) + FATAL("InternetReadFile failed\n"); + + Data[DataLength] = 0; + + return Data.release(); +} + +/** + * Requests a Test ID from the Web Service for our test run. + * + * @param TestType + * Constant pointer to a char array containing the test type to be run (i.e. "wine") + */ +void +CWebService::GetTestID(const char* TestType) +{ + string Data; + + Data = "action=gettestid"; + Data += Configuration.GetAuthenticationRequestString(); + Data += Configuration.GetSystemInfoRequestString(); + Data += "&testtype="; + Data += TestType; + + if(!Configuration.GetComment().empty()) + { + Data += "&comment="; + Data += Configuration.GetComment(); + } + + m_TestID = DoRequest(Data); + + /* Verify that this is really a number */ + if(!IsNumber(m_TestID)) + { + stringstream ss; + + ss << "Expected Test ID, but received:" << endl << m_TestID << endl; + SSEXCEPTION; + } +} + +/** + * Gets a Suite ID from the Web Service for this module/test combination. + * + * @param TestType + * Constant pointer to a char array containing the test type to be run (i.e. "wine") + * + * @param TestInfo + * Pointer to a CTestInfo object containing information about the test + * + * @return + * Returns a pointer to a char array containing the Suite ID received from the Web Service. + * The caller needs to free that pointer. + */ +PCHAR +CWebService::GetSuiteID(const char* TestType, CTestInfo* TestInfo) +{ + auto_array_ptr SuiteID; + string Data; + + Data = "action=getsuiteid"; + Data += Configuration.GetAuthenticationRequestString(); + Data += "&testtype="; + Data += TestType; + Data += "&module="; + Data += TestInfo->Module; + Data += "&test="; + Data += TestInfo->Test; + + SuiteID.reset(DoRequest(Data)); + + /* Verify that this is really a number */ + if(!IsNumber(SuiteID)) + { + stringstream ss; + + ss << "Expected Suite ID, but received:" << endl << SuiteID << endl; + SSEXCEPTION; + } + + return SuiteID.release(); +} + +/** + * Interface to other classes for submitting a result of one test + * + * @param TestType + * Constant pointer to a char array containing the test type to be run (i.e. "wine") + * + * @param TestInfo + * Pointer to a CTestInfo object containing information about the test + */ +void +CWebService::Submit(const char* TestType, CTestInfo* TestInfo) +{ + auto_array_ptr Response; + auto_array_ptr SuiteID; + string Data; + stringstream ss; + + if(!m_TestID) + GetTestID(TestType); + + SuiteID.reset(GetSuiteID(TestType, TestInfo)); + + Data = "action=submit"; + Data += Configuration.GetAuthenticationRequestString(); + Data += "&testtype="; + Data += TestType; + Data += "&testid="; + Data += m_TestID; + Data += "&suiteid="; + Data += SuiteID; + Data += "&log="; + Data += TestInfo->Log; + + Response.reset(DoRequest(Data)); + + ss << "The server responded:" << endl << Response << endl; + StringOut(ss.str()); + + if(strcmp(Response, "OK")) + EXCEPTION("Aborted!\n"); +} diff --git a/rostests/rosautotest/CWebService.h b/rostests/rosautotest/CWebService.h new file mode 100644 index 00000000000..07dbf897707 --- /dev/null +++ b/rostests/rosautotest/CWebService.h @@ -0,0 +1,25 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing the interface to the "testman" Web Service + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CWebService +{ +private: + HINTERNET m_hInet; + HINTERNET m_hHTTP; + HINTERNET m_hHTTPRequest; + PCHAR m_TestID; + + PCHAR DoRequest(const string& InputData); + void GetTestID(const char* TestType); + PCHAR GetSuiteID(const char* TestType, CTestInfo* TestInfo); + +public: + CWebService(); + ~CWebService(); + + void Submit(const char* TestType, CTestInfo* TestInfo); +}; diff --git a/rostests/rosautotest/CWineTest.cpp b/rostests/rosautotest/CWineTest.cpp new file mode 100644 index 00000000000..976343b8296 --- /dev/null +++ b/rostests/rosautotest/CWineTest.cpp @@ -0,0 +1,366 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing functions for handling Wine tests + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +#include "precomp.h" + +static const DWORD ListTimeout = 10000; + +/** + * Constructs a CWineTest object. + */ +CWineTest::CWineTest() +{ + WCHAR WindowsDirectory[MAX_PATH]; + + /* Zero-initialize variables */ + m_hFind = NULL; + m_hReadPipe = NULL; + m_hWritePipe = NULL; + m_ListBuffer = NULL; + memset(&m_StartupInfo, 0, sizeof(m_StartupInfo)); + + /* Set up m_TestPath */ + if(!GetWindowsDirectoryW(WindowsDirectory, MAX_PATH)) + FATAL("GetWindowsDirectoryW failed"); + + m_TestPath = WindowsDirectory; + m_TestPath += L"\\bin\\"; +} + +/** + * Destructs a CWineTest object. + */ +CWineTest::~CWineTest() +{ + if(m_hFind) + FindClose(m_hFind); + + if(m_hReadPipe) + CloseHandle(m_hReadPipe); + + if(m_hWritePipe) + CloseHandle(m_hWritePipe); + + if(m_ListBuffer) + delete m_ListBuffer; +} + +/** + * Gets the next module test file using the FindFirstFileW/FindNextFileW API. + * + * @return + * true if we found a next file, otherwise false. + */ +bool +CWineTest::GetNextFile() +{ + bool FoundFile = false; + WIN32_FIND_DATAW fd; + + /* Did we already begin searching for files? */ + if(m_hFind) + { + /* Then get the next file (if any) */ + if(FindNextFileW(m_hFind, &fd)) + FoundFile = true; + } + else + { + /* Start searching for test files */ + wstring FindPath = m_TestPath; + + /* Did the user specify a module? */ + if(Configuration.GetModule().empty()) + { + /* No module, so search for all files in that directory */ + FindPath += L"*.exe"; + } + else + { + /* Search for files with the pattern "modulename_*" */ + FindPath += Configuration.GetModule(); + FindPath += L"_*.exe"; + } + + /* Search for the first file and check whether we got one */ + m_hFind = FindFirstFileW(FindPath.c_str(), &fd); + + if(m_hFind != INVALID_HANDLE_VALUE) + FoundFile = true; + } + + if(FoundFile) + m_CurrentFile = fd.cFileName; + + return FoundFile; +} + +/** + * Executes the --list command of a module test file to get information about the available tests. + * + * @return + * The number of bytes we read into the m_ListBuffer member variable by capturing the output of the --list command. + */ +DWORD +CWineTest::DoListCommand() +{ + DWORD BytesAvailable; + DWORD Temp; + wstring CommandLine; + + /* Build the command line */ + CommandLine = m_TestPath; + CommandLine += m_CurrentFile; + CommandLine += L" --list"; + + { + /* Start the process for getting all available tests */ + CProcess Process(CommandLine, &m_StartupInfo); + + /* Wait till this process ended */ + if(WaitForSingleObject(Process.GetProcessHandle(), ListTimeout) == WAIT_FAILED) + FATAL("WaitForSingleObject failed for the test list\n"); + } + + /* Read the output data into a buffer */ + if(!PeekNamedPipe(m_hReadPipe, NULL, 0, NULL, &BytesAvailable, NULL)) + FATAL("PeekNamedPipe failed for the test list\n"); + + /* Check if we got any */ + if(!BytesAvailable) + { + stringstream ss; + + ss << "The --list command did not return any data for " << UnicodeToAscii(m_CurrentFile) << endl; + SSEXCEPTION; + } + + /* Read the data */ + m_ListBuffer = new char[BytesAvailable]; + + if(!ReadFile(m_hReadPipe, m_ListBuffer, BytesAvailable, &Temp, NULL)) + FATAL("ReadPipe failed\n"); + + return BytesAvailable; +} + +/** + * Gets the next test from m_ListBuffer, which was filled with information from the --list command. + * + * @return + * true if a next test was found, otherwise false. + */ +bool +CWineTest::GetNextTest() +{ + PCHAR pEnd; + static DWORD BufferSize; + static PCHAR pStart; + + if(!m_ListBuffer) + { + /* Perform the --list command */ + BufferSize = DoListCommand(); + + /* Move the pointer to the first test */ + pStart = strchr(m_ListBuffer, '\n'); + pStart += 5; + } + + /* If we reach the buffer size, we finished analyzing the output of this test */ + if(pStart >= (m_ListBuffer + BufferSize)) + { + /* Clear m_CurrentFile to indicate that */ + m_CurrentFile.clear(); + + /* Also free the memory for the list buffer */ + delete m_ListBuffer; + m_ListBuffer = NULL; + + return false; + } + + /* Get start and end of this test name */ + pEnd = pStart; + + while(*pEnd != '\r') + ++pEnd; + + /* Store the test name */ + m_CurrentTest = string(pStart, pEnd); + + /* Move the pointer to the next test */ + pStart = pEnd + 6; + + return true; +} + +/** + * Interface to CTestList-derived classes for getting all information about the next test to be run. + * + * @return + * Returns a pointer to a CTestInfo object containing all available information about the next test. + */ +CTestInfo* +CWineTest::GetNextTestInfo() +{ + while(!m_CurrentFile.empty() || GetNextFile()) + { + while(GetNextTest()) + { + /* If the user specified a test through the command line, check this here */ + if(!Configuration.GetTest().empty() && Configuration.GetTest() != m_CurrentTest) + continue; + + { + auto_ptr TestInfo(new CTestInfo()); + size_t UnderscorePosition; + + /* Build the command line */ + TestInfo->CommandLine = m_TestPath; + TestInfo->CommandLine += m_CurrentFile; + TestInfo->CommandLine += ' '; + TestInfo->CommandLine += AsciiToUnicode(m_CurrentTest); + + /* Store the Module name */ + UnderscorePosition = m_CurrentFile.find_last_of('_'); + + if(UnderscorePosition == m_CurrentFile.npos) + { + stringstream ss; + + ss << "Invalid test file name: " << UnicodeToAscii(m_CurrentFile) << endl; + SSEXCEPTION; + } + + TestInfo->Module = UnicodeToAscii(m_CurrentFile.substr(0, UnderscorePosition)); + + /* Store the test */ + TestInfo->Test = m_CurrentTest; + + return TestInfo.release(); + } + } + } + + return NULL; +} + +/** + * Runs a Wine test and captures the output + * + * @param TestInfo + * Pointer to a CTestInfo object containing information about the test. + * Will contain the test log afterwards if the user wants to submit data. + */ +void +CWineTest::RunTest(CTestInfo* TestInfo) +{ + bool BreakLoop = false; + DWORD BytesAvailable; + DWORD Temp; + stringstream ss; + + ss << "Running Wine Test, Module: " << TestInfo->Module << ", Test: " << TestInfo->Test << endl; + StringOut(ss.str()); + + { + /* Execute the test */ + CProcess Process(TestInfo->CommandLine, &m_StartupInfo); + + /* Receive all the data from the pipe */ + do + { + /* When the application finished, make sure that we peek the pipe one more time, so that we get all data. + If the following condition would be the while() condition, we might hit a race condition: + - We check for data with PeekNamedPipe -> no data available + - The application outputs its data and finishes + - WaitForSingleObject reports that the application has finished and we break the loop without receiving any data + */ + if(WaitForSingleObject(Process.GetProcessHandle(), 0) != WAIT_TIMEOUT) + BreakLoop = true; + + if(!PeekNamedPipe(m_hReadPipe, NULL, 0, NULL, &BytesAvailable, NULL)) + FATAL("PeekNamedPipe failed for the test run\n"); + + if(BytesAvailable) + { + /* There is data, so get it and output it */ + auto_array_ptr Buffer(new char[BytesAvailable + 1]); + + if(!ReadFile(m_hReadPipe, Buffer, BytesAvailable, &Temp, NULL)) + FATAL("ReadFile failed for the test run\n"); + + /* Output all test output through StringOut, even while the test is still running */ + Buffer[BytesAvailable] = 0; + StringOut(string(Buffer)); + + if(Configuration.DoSubmit()) + TestInfo->Log += Buffer; + } + } + while(!BreakLoop); + } +} + +/** + * Interface to other classes for running all desired Wine tests. + */ +void +CWineTest::Run() +{ + auto_ptr TestList; + auto_ptr WebService; + CTestInfo* TestInfo; + SECURITY_ATTRIBUTES SecurityAttributes; + + /* Create a pipe for getting the output of the tests */ + SecurityAttributes.nLength = sizeof(SecurityAttributes); + SecurityAttributes.bInheritHandle = TRUE; + SecurityAttributes.lpSecurityDescriptor = NULL; + + if(!CreatePipe(&m_hReadPipe, &m_hWritePipe, &SecurityAttributes, 0)) + FATAL("CreatePipe failed\n"); + + m_StartupInfo.cb = sizeof(m_StartupInfo); + m_StartupInfo.dwFlags = STARTF_USESTDHANDLES; + m_StartupInfo.hStdOutput = m_hWritePipe; + + /* The virtual test list is of course faster, so it should be preferred over + the journaled one. + Enable the journaled one only in case ... + - we're running under ReactOS (as the journal is only useful in conjunction with sysreg2) + - we shall keep information for Crash Recovery + - and the user didn't specify a module (then doing Crash Recovery doesn't really make sense) */ + if(Configuration.IsReactOS() && Configuration.DoCrashRecovery() && Configuration.GetModule().empty()) + { + /* Use a test list with a permanent journal */ + TestList.reset(new CJournaledTestList(this)); + } + else + { + /* Use the fast virtual test list with no additional overhead */ + TestList.reset(new CVirtualTestList(this)); + } + + /* Initialize the Web Service interface if required */ + if(Configuration.DoSubmit()) + WebService.reset(new CWebService()); + + /* Get information for each test to run */ + while((TestInfo = TestList->GetNextTestInfo()) != 0) + { + auto_ptr TestInfoPtr(TestInfo); + + RunTest(TestInfo); + + if(Configuration.DoSubmit() && !TestInfo->Log.empty()) + WebService->Submit("wine", TestInfo); + + StringOut("\n\n"); + } +} diff --git a/rostests/rosautotest/CWineTest.h b/rostests/rosautotest/CWineTest.h new file mode 100644 index 00000000000..58ca5585e84 --- /dev/null +++ b/rostests/rosautotest/CWineTest.h @@ -0,0 +1,32 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Class implementing functions for handling Wine tests + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +class CWineTest : public CTest +{ +private: + HANDLE m_hFind; + HANDLE m_hReadPipe; + HANDLE m_hWritePipe; + PCHAR m_ListBuffer; + STARTUPINFOW m_StartupInfo; + string m_CurrentTest; + wstring m_CurrentFile; + wstring m_CurrentListCommand; + wstring m_TestPath; + + bool GetNextFile(); + bool GetNextTest(); + CTestInfo* GetNextTestInfo(); + DWORD DoListCommand(); + void RunTest(CTestInfo* TestInfo); + +public: + CWineTest(); + ~CWineTest(); + + void Run(); +}; diff --git a/rostests/rosautotest/auto_array_ptr.h b/rostests/rosautotest/auto_array_ptr.h new file mode 100644 index 00000000000..e1e3b291803 --- /dev/null +++ b/rostests/rosautotest/auto_array_ptr.h @@ -0,0 +1,64 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Template similar to std::auto_ptr for arrays + * COPYRIGHT: Copyright 2009 Colin Finck + */ + +template +class auto_array_ptr +{ +private: + Type* m_Ptr; + +public: + typedef Type element_type; + + /* Construct an auto_array_ptr from a pointer */ + explicit auto_array_ptr(Type* Ptr = 0) throw() + : m_Ptr(Ptr) + { + } + + /* Construct an auto_array_ptr from an existing auto_array_ptr */ + auto_array_ptr(auto_array_ptr& Right) throw() + : m_Ptr(Right.release()) + { + } + + /* Destruct the auto_array_ptr and remove the corresponding array from memory */ + ~auto_array_ptr() throw() + { + delete[] m_Ptr; + } + + /* Get the pointer address */ + Type* get() const throw() + { + return m_Ptr; + } + + /* Release the pointer */ + Type* release() throw() + { + Type* Tmp = m_Ptr; + m_Ptr = 0; + + return Tmp; + } + + /* Reset to a new pointer */ + void reset(Type* Ptr = 0) throw() + { + if(Ptr != m_Ptr) + delete[] m_Ptr; + + m_Ptr = Ptr; + } + + /* Simulate all the functionality of real arrays by casting the auto_array_ptr to Type* on demand */ + operator Type*() const throw() + { + return m_Ptr; + } +}; diff --git a/rostests/rosautotest/main.cpp b/rostests/rosautotest/main.cpp new file mode 100644 index 00000000000..5fb5dd4c297 --- /dev/null +++ b/rostests/rosautotest/main.cpp @@ -0,0 +1,96 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Main implementation file + * COPYRIGHT: Copyright 2008-2009 Colin Finck + */ + +#include "precomp.h" +#include + +CConfiguration Configuration; + +/** + * Prints the application usage. + */ +static void +IntPrintUsage() +{ + cout << "rosautotest - ReactOS Automatic Testing Utility" << endl + << "Usage: rosautotest [options] [module] [test]" << endl + << " options:" << endl + << " /? - Shows this help." << endl + << " /c - Specifies the comment to be submitted to the Web Service." << endl + << " Skips the comment set in the configuration file (if any)." << endl + << " Only has an effect when /w is also used." << endl + << " /r - Maintain information to resume from ReactOS crashes" << endl + << " Can only be run under ReactOS and relies on sysreg2," << endl + << " so incompatible with /w" << endl + << " /s - Shut down the system after finishing the tests." << endl + << " /w - Submit the results to the webservice." << endl + << " Requires a \"rosautotest.ini\" with valid login data." << endl + << " Incompatible with the /r option." << endl + << endl + << " module:" << endl + << " The module to be tested (i.e. \"advapi32\")" << endl + << " If this parameter is specified without any test parameter," << endl + << " all tests of the specified module are run." << endl + << endl + << " test:" << endl + << " The test to be run. Needs to be a test of the specified module." << endl; +} + +/** + * Main entry point + */ +extern "C" int +wmain(int argc, wchar_t* argv[]) +{ + CWineTest WineTest; + int ReturnValue = 1; + + try + { + /* Set up the configuration */ + Configuration.ParseParameters(argc, argv); + Configuration.GetSystemInformation(); + Configuration.GetConfigurationFromFile(); + + /* Run the tests */ + WineTest.Run(); + + /* For sysreg2 */ + DbgPrint("SYSREG_CHECKPOINT:THIRDBOOT_COMPLETE\n"); + + ReturnValue = 0; + } + catch(CInvalidParameterException) + { + IntPrintUsage(); + } + catch(CSimpleException& e) + { + StringOut(e.GetMessage()); + } + catch(CFatalException& e) + { + stringstream ss; + + ss << "An exception occured in rosautotest." << endl + << "Message: " << e.GetMessage() << endl + << "File: " << e.GetFile() << endl + << "Line: " << e.GetLine() << endl + << "Last Win32 Error: " << GetLastError() << endl; + StringOut(ss.str()); + } + + /* For sysreg2 to notice if rosautotest itself failed */ + if(ReturnValue == 1) + DbgPrint("SYSREG_ROSAUTOTEST_FAILURE\n"); + + /* Shut down the system if requested, also in case of an exception above */ + if(Configuration.DoShutdown() && !ShutdownSystem()) + ReturnValue = 1; + + return ReturnValue; +} diff --git a/rostests/rosautotest/precomp.h b/rostests/rosautotest/precomp.h new file mode 100644 index 00000000000..f5e65ad0798 --- /dev/null +++ b/rostests/rosautotest/precomp.h @@ -0,0 +1,62 @@ +/* General includes */ +#include +#include +#include +#include +#include + +using namespace std; + +#define WIN32_NO_STATUS +#include +#include +#include +#include +#include + +#include +#include + +/* Class includes */ +#include "auto_array_ptr.h" +#include "CConfiguration.h" +#include "CFatalException.h" +#include "CInvalidParameterException.h" +#include "CProcess.h" +#include "CSimpleException.h" +#include "CTestInfo.h" +#include "CTest.h" +#include "CTestList.h" +#include "CJournaledTestList.h" +#include "CVirtualTestList.h" +#include "CWebService.h" +#include "CWineTest.h" + +/* Useful macros */ +#define EXCEPTION(Message) throw CSimpleException(Message) +#define FATAL(Message) throw CFatalException(__FILE__, __LINE__, Message) +#define SSEXCEPTION throw CSimpleException(ss.str().c_str()) + +/* main.c */ +extern CConfiguration Configuration; + +/* shutdown.c */ +bool ShutdownSystem(); + +/* tools.c */ +wstring AsciiToUnicode(const char* AsciiString); +wstring AsciiToUnicode(const string& AsciiString); +string EscapeString(const char* Input); +string EscapeString(const string& Input); +string GetINIValue(PCWCH AppName, PCWCH KeyName, PCWCH FileName); +bool IsNumber(const char* Input); +void StringOut(const string& String); +string UnicodeToAscii(PCWSTR UnicodeString); +string UnicodeToAscii(const wstring& UnicodeString); + + +/* Lazy HACK to allow compiling/debugging with MSVC while we lack support + for linking against "debugsup_ntdll" in MSVC */ +#ifdef _MSC_VER + #define DbgPrint +#endif diff --git a/rostests/rosautotest/rosautotest.rbuild b/rostests/rosautotest/rosautotest.rbuild new file mode 100644 index 00000000000..5224c24df97 --- /dev/null +++ b/rostests/rosautotest/rosautotest.rbuild @@ -0,0 +1,26 @@ + + + + -fno-rtti + . + advapi32 + shell32 + user32 + wininet + CConfiguration.cpp + CFatalException.cpp + CInvalidParameterException.cpp + CJournaledTestList.cpp + CProcess.cpp + CSimpleException.cpp + CTest.cpp + CTestInfo.cpp + CTestList.cpp + CVirtualTestList.cpp + CWebService.cpp + CWineTest.cpp + main.cpp + shutdown.cpp + tools.cpp + precomp.h + diff --git a/rostests/rosautotest/shutdown.cpp b/rostests/rosautotest/shutdown.cpp new file mode 100644 index 00000000000..dc243fa7afe --- /dev/null +++ b/rostests/rosautotest/shutdown.cpp @@ -0,0 +1,52 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Helper function for shutting down the system + * COPYRIGHT: Copyright 2008-2009 Colin Finck + */ + +#include "precomp.h" + +/** + * Shuts down the system. + * + * @return + * true if everything went well, false if there was a problem while trying to shut down the system. + */ +bool ShutdownSystem() +{ + HANDLE hToken; + TOKEN_PRIVILEGES Privileges; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + StringOut("OpenProcessToken failed\n"); + return false; + } + + /* Get the LUID for the Shutdown privilege */ + if (!LookupPrivilegeValueW(NULL, SE_SHUTDOWN_NAME, &Privileges.Privileges[0].Luid)) + { + StringOut("LookupPrivilegeValue failed\n"); + return false; + } + + /* Assign the Shutdown privilege to our process */ + Privileges.PrivilegeCount = 1; + Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL)) + { + StringOut("AdjustTokenPrivileges failed\n"); + return false; + } + + /* Finally shut down the system */ + if(!ExitWindowsEx(EWX_POWEROFF, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED)) + { + StringOut("ExitWindowsEx failed\n"); + return false; + } + + return true; +} diff --git a/rostests/rosautotest/tools.cpp b/rostests/rosautotest/tools.cpp new file mode 100644 index 00000000000..6b1165c5bd5 --- /dev/null +++ b/rostests/rosautotest/tools.cpp @@ -0,0 +1,257 @@ +/* + * PROJECT: ReactOS Automatic Testing Utility + * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation + * PURPOSE: Various helper functions + * COPYRIGHT: Copyright 2008-2009 Colin Finck + */ + +#include "precomp.h" + +#define DBGPRINT_BUFSIZE 511 +static const char HexCharacters[] = "0123456789ABCDEF"; + +/** + * Escapes a string according to RFC 1738. + * Required for passing parameters to the web service. + * + * @param Input + * Constant pointer to a char array, which contains the input buffer to escape. + * + * @return + * The escaped string as std::string. + */ +string +EscapeString(const char* Input) +{ + string ReturnedString; + + do + { + if(strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~", *Input)) + { + /* It's a character we don't need to escape, just add it to the output string */ + ReturnedString += *Input; + } + else + { + /* We need to escape this character */ + ReturnedString += '%'; + ReturnedString += HexCharacters[((UCHAR)*Input >> 4) % 16]; + ReturnedString += HexCharacters[(UCHAR)*Input % 16]; + } + } + while(*++Input); + + return ReturnedString; +} + +/** + * Escapes a string according to RFC 1738. + * Required for passing parameters to the web service. + * + * @param Input + * Pointer to a std::string, which contains the input buffer to escape. + * + * @return + * The escaped string as std::string. + */ +string +EscapeString(const string& Input) +{ + return EscapeString(Input.c_str()); +} + +/** + * Determines whether a string contains entirely numeric values. + * + * @param Input + * Constant pointer to a char array containing the input to check. + * + * @return + * true if the string is entirely numeric, false otherwise. + */ +bool +IsNumber(const char* Input) +{ + do + { + if(!isdigit(*Input)) + return false; + + ++Input; + } + while(*Input); + + return true; +} + +/** + * Outputs a string through the standard output and the debug output. + * The string may have LF or CRLF line endings. + * + * @param String + * The std::string to output + */ +void +StringOut(const string& String) +{ + char DbgString[DBGPRINT_BUFSIZE + 1]; + size_t i; + string NewString; + + /* Unify the line endings (the piped output of the tests may use CRLF) */ + for(i = 0; i < String.size(); i++) + { + /* If this is a CRLF line-ending, only copy a \n to the new string and skip the next character */ + if(String[i] == '\r' && String[i + 1] == '\n') + { + NewString += '\n'; + ++i; + } + else + { + /* Otherwise copy the string */ + NewString += String[i]; + } + } + + /* Output the string. + For DbgPrint, this must be done in chunks of 512 bytes. */ + cout << NewString; + + for(i = 0; i < NewString.size(); i += DBGPRINT_BUFSIZE) + { + size_t BytesToCopy; + + if(NewString.size() - i > DBGPRINT_BUFSIZE) + BytesToCopy = DBGPRINT_BUFSIZE; + else + BytesToCopy = NewString.size() - i; + + memcpy(DbgString, NewString.c_str() + i, BytesToCopy); + DbgString[BytesToCopy] = 0; + + DbgPrint(DbgString); + } +} + +/** + * Gets a value from a specified INI file and returns it converted to ASCII. + * + * @param AppName + * Constant pointer to a WCHAR array with the INI section to look in (lpAppName parameter passed to GetPrivateProfileStringW) + * + * @param KeyName + * Constant pointer to a WCHAR array containing the key to look for in the specified section (lpKeyName parameter passed to GetPrivateProfileStringW) + * + * @param FileName + * Constant pointer to a WCHAR array containing the path to the INI file + * + * @return + * Returns the data of the value as std::string or an empty string if no data could be retrieved. + */ +string +GetINIValue(PCWCH AppName, PCWCH KeyName, PCWCH FileName) +{ + DWORD Length; + PCHAR AsciiBuffer; + string ReturnedString; + WCHAR Buffer[2048]; + + /* Load the value into a temporary Unicode buffer */ + Length = GetPrivateProfileStringW(AppName, KeyName, NULL, Buffer, sizeof(Buffer) / sizeof(WCHAR), FileName); + + if(Length) + { + /* Convert the string to ASCII charset */ + AsciiBuffer = new char[Length + 1]; + WideCharToMultiByte(CP_ACP, 0, Buffer, Length + 1, AsciiBuffer, Length + 1, NULL, NULL); + + ReturnedString = AsciiBuffer; + delete AsciiBuffer; + } + + return ReturnedString; +} + +/** + * Converts an ASCII string to a Unicode one. + * + * @param AsciiString + * Constant pointer to a char array containing the ASCII string + * + * @return + * The Unicode string as std::wstring + */ +wstring +AsciiToUnicode(const char* AsciiString) +{ + DWORD Length; + PWSTR UnicodeString; + wstring ReturnString; + + Length = MultiByteToWideChar(CP_ACP, 0, AsciiString, -1, NULL, 0); + + UnicodeString = new WCHAR[Length]; + MultiByteToWideChar(CP_ACP, 0, AsciiString, -1, UnicodeString, Length); + ReturnString = UnicodeString; + delete UnicodeString; + + return ReturnString; +} + +/** + * Converts an ASCII string to a Unicode one. + * + * @param AsciiString + * Pointer to a std::string containing the ASCII string + * + * @return + * The Unicode string as std::wstring + */ +wstring +AsciiToUnicode(const string& AsciiString) +{ + return AsciiToUnicode(AsciiString.c_str()); +} + +/** + * Converts a Unicode string to an ASCII one. + * + * @param UnicodeString + * Constant pointer to a WCHAR array containing the Unicode string + * + * @return + * The ASCII string as std::string + */ +string +UnicodeToAscii(PCWSTR UnicodeString) +{ + DWORD Length; + PCHAR AsciiString; + string ReturnString; + + Length = WideCharToMultiByte(CP_ACP, 0, UnicodeString, -1, NULL, 0, NULL, NULL); + + AsciiString = new char[Length]; + WideCharToMultiByte(CP_ACP, 0, UnicodeString, -1, AsciiString, Length, NULL, NULL); + ReturnString = AsciiString; + delete AsciiString; + + return ReturnString; +} + +/** + * Converts a Unicode string to an ASCII one. + * + * @param UnicodeString + * Pointer to a std::wstring containing the Unicode string + * + * @return + * The ASCII string as std::string + */ +string +UnicodeToAscii(const wstring& UnicodeString) +{ + return UnicodeToAscii(UnicodeString.c_str()); +} diff --git a/rostests/tests/D3DParseUnknownCommand_show/D3DParseUnknownCommand_show.rbuild b/rostests/tests/D3DParseUnknownCommand_show/D3DParseUnknownCommand_show.rbuild index d5f99e6a88d..a291d22c87d 100644 --- a/rostests/tests/D3DParseUnknownCommand_show/D3DParseUnknownCommand_show.rbuild +++ b/rostests/tests/D3DParseUnknownCommand_show/D3DParseUnknownCommand_show.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 ddraw user32 diff --git a/rostests/tests/DxHalTest/DxHalTest.rbuild b/rostests/tests/DxHalTest/DxHalTest.rbuild index ed3a146ce00..52587302a6c 100644 --- a/rostests/tests/DxHalTest/DxHalTest.rbuild +++ b/rostests/tests/DxHalTest/DxHalTest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 main.c diff --git a/rostests/tests/DxHalTest/main.c b/rostests/tests/DxHalTest/main.c index af89cd9f4c9..ffc82451534 100644 --- a/rostests/tests/DxHalTest/main.c +++ b/rostests/tests/DxHalTest/main.c @@ -70,14 +70,6 @@ typedef struct _DD_MISCELLANEOUSCALLBACKS { int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) { - /* get the functions we need */ -// DD_GETDRIVERINFODATA drv; - HMODULE lib = LoadLibrary("gdi32.dll"); - DdCreateDirectDrawObject = (BOOL (APIENTRY*)(LPDDRAWI_DIRECTDRAW_GBL, HDC))GetProcAddress(lib, "GdiEntry1"); - DdQueryDirectDrawObject = (BOOL (APIENTRY*)(LPDDRAWI_DIRECTDRAW_GBL, LPDDHALINFO,LPDDHAL_DDCALLBACKS,LPDDHAL_DDSURFACECALLBACKS,LPDDHAL_DDPALETTECALLBACKS,LPD3DHAL_CALLBACKS,LPD3DHAL_GLOBALDRIVERDATA,LPDDHAL_DDEXEBUFCALLBACKS,LPDDSURFACEDESC,LPDWORD,LPVIDMEM))GetProcAddress(lib, "GdiEntry2"); - DdAttachSurface = (BOOL (APIENTRY*)(LPDDRAWI_DDRAWSURFACE_LCL, LPDDRAWI_DDRAWSURFACE_LCL))GetProcAddress(lib, "GdiEntry11"); - DdResetVisrgn = (BOOL (APIENTRY*)(LPDDRAWI_DDRAWSURFACE_LCL, HWND))GetProcAddress(lib, "GdiEntry6"); - /* HAL Startup process */ DEVMODE devmode; HBITMAP hbmp; @@ -90,7 +82,21 @@ int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, //DWORD Status; /* for create surface */ UINT i; UINT j; + UINT cSurfaces; + DDHAL_CANCREATESURFACEDATA mDdCanCreateSurface; + DDHAL_UPDATEOVERLAYDATA mDdUpdateOverlay; + DDRAWI_DDRAWSURFACE_LCL *pDDSurface; + DDHAL_CREATESURFACEDATA mDdCreateSurface; + + + /* get the functions we need */ +// DD_GETDRIVERINFODATA drv; + HMODULE lib = LoadLibrary("gdi32.dll"); + DdCreateDirectDrawObject = (BOOL (APIENTRY*)(LPDDRAWI_DIRECTDRAW_GBL, HDC))GetProcAddress(lib, "GdiEntry1"); + DdQueryDirectDrawObject = (BOOL (APIENTRY*)(LPDDRAWI_DIRECTDRAW_GBL, LPDDHALINFO,LPDDHAL_DDCALLBACKS,LPDDHAL_DDSURFACECALLBACKS,LPDDHAL_DDPALETTECALLBACKS,LPD3DHAL_CALLBACKS,LPD3DHAL_GLOBALDRIVERDATA,LPDDHAL_DDEXEBUFCALLBACKS,LPDDSURFACEDESC,LPDWORD,LPVIDMEM))GetProcAddress(lib, "GdiEntry2"); + DdAttachSurface = (BOOL (APIENTRY*)(LPDDRAWI_DDRAWSURFACE_LCL, LPDDRAWI_DDRAWSURFACE_LCL))GetProcAddress(lib, "GdiEntry11"); + DdResetVisrgn = (BOOL (APIENTRY*)(LPDDRAWI_DDRAWSURFACE_LCL, HWND))GetProcAddress(lib, "GdiEntry6"); printf("This apps showing how to start up directx draw/d3d interface and some other as well\n"); printf("This code have been releae to some close applactons with my premtions, if any company\n"); @@ -364,7 +370,6 @@ int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, mddsdPrimary.dwFlags = DDSD_CAPS; mddsdPrimary.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_VIDEOMEMORY | DDSCAPS_VISIBLE; - DDHAL_CANCREATESURFACEDATA mDdCanCreateSurface; mDdCanCreateSurface.lpDD = &mDDrawGlobal; mDdCanCreateSurface.CanCreateSurface = mCallbacks.HALDD.CanCreateSurface; mDdCanCreateSurface.bIsDifferentPixelFormat = FALSE; //isDifferentPixelFormat; @@ -405,7 +410,6 @@ int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, mpPrimaryLocals[0] = &mPrimaryLocal; - DDHAL_CREATESURFACEDATA mDdCreateSurface; mDdCreateSurface.lpDD = &mDDrawGlobal; mDdCreateSurface.CreateSurface = mCallbacks.HALDD.CreateSurface; mDdCreateSurface.lpDDSurfaceDesc = &mddsdPrimary;//pDDSD; @@ -500,7 +504,7 @@ int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, mOverlayGlobal.ddpfSurface = mddsdOverlay.ddpfPixelFormat; // setup front- and backbuffer surfaces - UINT cSurfaces = mddsdOverlay.dwBackBufferCount + 1; + cSurfaces = mddsdOverlay.dwBackBufferCount + 1; for ( i = 0; i < cSurfaces; i++) { memset(&mOverlayMore[i], 0, sizeof(DDRAWI_DDRAWSURFACE_MORE)); @@ -565,7 +569,6 @@ int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, } - DDHAL_UPDATEOVERLAYDATA mDdUpdateOverlay; mDdUpdateOverlay.lpDD = &mDDrawGlobal; mDdUpdateOverlay.UpdateOverlay = mCallbacks.HALDDSurface.UpdateOverlay; mDdUpdateOverlay.lpDDDestSurface = mpPrimaryLocals[0]; @@ -607,7 +610,7 @@ int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, /* blt */ - DDRAWI_DDRAWSURFACE_LCL *pDDSurface = mpPrimaryLocals[0]; + pDDSurface = mpPrimaryLocals[0]; if (!DdResetVisrgn(pDDSurface, NULL)) { diff --git a/rostests/tests/Imagelistviewer/imagelistviewer.rbuild b/rostests/tests/Imagelistviewer/imagelistviewer.rbuild index 59bff1ec9d2..8593263b062 100644 --- a/rostests/tests/Imagelistviewer/imagelistviewer.rbuild +++ b/rostests/tests/Imagelistviewer/imagelistviewer.rbuild @@ -1,12 +1,8 @@ - - 0x0501 - 0x0501 - - . - kernel32 - user32 - setupapi - comctl32 - main.c - res.rc - + + . + user32 + setupapi + comctl32 + main.c + res.rc + diff --git a/rostests/tests/Imagelistviewer/main.c b/rostests/tests/Imagelistviewer/main.c index 043171b786f..f2832906894 100644 --- a/rostests/tests/Imagelistviewer/main.c +++ b/rostests/tests/Imagelistviewer/main.c @@ -1,145 +1,146 @@ -#include -#include -#include -#include "resource.h" - -typedef BOOL (WINAPI * SH_GIL_PROC)(HIMAGELIST *phLarge, HIMAGELIST *phSmall); -typedef BOOL (WINAPI * FII_PROC)(BOOL fFullInit); - -/*** Shell32 undoc'd functions ***/ - /* Shell_GetImageLists @71 */ - /* FileIconInit @660 */ - -BOOL -DisplayImageList(HWND hwnd, - UINT uID) -{ - HWND hLV; - SP_CLASSIMAGELIST_DATA ImageListData; - LV_ITEM lvItem; - TCHAR Buf[6]; - INT ImageListCount = -1; - INT i = 0; - - hLV = GetDlgItem(hwnd, IDC_LSTVIEW); - (void)ListView_DeleteAllItems(hLV); - - if (uID == IDC_SYSTEM) - { - HIMAGELIST hLarge, hSmall; - HMODULE hShell32; - SH_GIL_PROC Shell_GetImageLists; - FII_PROC FileIconInit; - - hShell32 = LoadLibrary(_T("shell32.dll")); - if(hShell32 == NULL) - return FALSE; - - Shell_GetImageLists = (SH_GIL_PROC)GetProcAddress(hShell32, (LPCSTR)71); - FileIconInit = (FII_PROC)GetProcAddress(hShell32, (LPCSTR)660); - - if(Shell_GetImageLists == NULL || FileIconInit == NULL) - { - FreeLibrary(hShell32); - return FALSE; - } - - FileIconInit(TRUE); - - Shell_GetImageLists(&hLarge, &hSmall); - - ImageListCount = ImageList_GetImageCount(hSmall); - - (void)ListView_SetImageList(hLV, - hSmall, - LVSIL_SMALL); - - FreeLibrary(hShell32); - } - else if (uID == IDC_DEVICE) - { - ImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA); - SetupDiGetClassImageList(&ImageListData); - - ImageListCount = ImageList_GetImageCount(ImageListData.ImageList); - - (void)ListView_SetImageList(hLV, - ImageListData.ImageList, - LVSIL_SMALL); - } - else - return FALSE; - - lvItem.mask = LVIF_TEXT | LVIF_IMAGE; - - while (i <= ImageListCount) - { - lvItem.iItem = i; - lvItem.iSubItem = 0; - lvItem.pszText = _itot(i, Buf, 10); - lvItem.iImage = i; - - (void)ListView_InsertItem(hLV, &lvItem); - - i++; - } - - return TRUE; -} - - -BOOL CALLBACK -DlgProc(HWND hwnd, - UINT message, - WPARAM wParam, - LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - DisplayImageList(hwnd, IDC_SYSTEM); - return TRUE; - - case WM_CLOSE: - EndDialog(hwnd, 0); - return TRUE; - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case IDOK: - EndDialog(hwnd, 0); - return TRUE; - - case IDC_SYSTEM: - DisplayImageList(hwnd, IDC_SYSTEM); - return TRUE; - - case IDC_DEVICE: - DisplayImageList(hwnd, IDC_DEVICE); - return TRUE; - } - } - } - - return FALSE; -} - -int WINAPI -WinMain(HINSTANCE hThisInstance, - HINSTANCE hPrevInstance, - LPSTR lpszArgument, - int nCmdShow) -{ - INITCOMMONCONTROLSEX icex; - - icex.dwSize = sizeof(INITCOMMONCONTROLSEX); - icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES; - InitCommonControlsEx(&icex); - - return DialogBox(hThisInstance, - MAKEINTRESOURCE(IDD_IMGLST), - NULL, - (DLGPROC)DlgProc); -} +#include +#include +#include +#include +#include "resource.h" + +typedef BOOL (WINAPI * SH_GIL_PROC)(HIMAGELIST *phLarge, HIMAGELIST *phSmall); +typedef BOOL (WINAPI * FII_PROC)(BOOL fFullInit); + +/*** Shell32 undoc'd functions ***/ + /* Shell_GetImageLists @71 */ + /* FileIconInit @660 */ + +BOOL +DisplayImageList(HWND hwnd, + UINT uID) +{ + HWND hLV; + SP_CLASSIMAGELIST_DATA ImageListData; + LV_ITEM lvItem; + TCHAR Buf[6]; + INT ImageListCount = -1; + INT i = 0; + + hLV = GetDlgItem(hwnd, IDC_LSTVIEW); + (void)ListView_DeleteAllItems(hLV); + + if (uID == IDC_SYSTEM) + { + HIMAGELIST hLarge, hSmall; + HMODULE hShell32; + SH_GIL_PROC Shell_GetImageLists; + FII_PROC FileIconInit; + + hShell32 = LoadLibrary(_T("shell32.dll")); + if(hShell32 == NULL) + return FALSE; + + Shell_GetImageLists = (SH_GIL_PROC)GetProcAddress(hShell32, (LPCSTR)71); + FileIconInit = (FII_PROC)GetProcAddress(hShell32, (LPCSTR)660); + + if(Shell_GetImageLists == NULL || FileIconInit == NULL) + { + FreeLibrary(hShell32); + return FALSE; + } + + FileIconInit(TRUE); + + Shell_GetImageLists(&hLarge, &hSmall); + + ImageListCount = ImageList_GetImageCount(hSmall); + + (void)ListView_SetImageList(hLV, + hSmall, + LVSIL_SMALL); + + FreeLibrary(hShell32); + } + else if (uID == IDC_DEVICE) + { + ImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA); + SetupDiGetClassImageList(&ImageListData); + + ImageListCount = ImageList_GetImageCount(ImageListData.ImageList); + + (void)ListView_SetImageList(hLV, + ImageListData.ImageList, + LVSIL_SMALL); + } + else + return FALSE; + + lvItem.mask = LVIF_TEXT | LVIF_IMAGE; + + while (i <= ImageListCount) + { + lvItem.iItem = i; + lvItem.iSubItem = 0; + lvItem.pszText = _itot(i, Buf, 10); + lvItem.iImage = i; + + (void)ListView_InsertItem(hLV, &lvItem); + + i++; + } + + return TRUE; +} + + +BOOL CALLBACK +DlgProc(HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + DisplayImageList(hwnd, IDC_SYSTEM); + return TRUE; + + case WM_CLOSE: + EndDialog(hwnd, 0); + return TRUE; + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDOK: + EndDialog(hwnd, 0); + return TRUE; + + case IDC_SYSTEM: + DisplayImageList(hwnd, IDC_SYSTEM); + return TRUE; + + case IDC_DEVICE: + DisplayImageList(hwnd, IDC_DEVICE); + return TRUE; + } + } + } + + return FALSE; +} + +int WINAPI +WinMain(HINSTANCE hThisInstance, + HINSTANCE hPrevInstance, + LPSTR lpszArgument, + int nCmdShow) +{ + INITCOMMONCONTROLSEX icex; + + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES; + InitCommonControlsEx(&icex); + + return DialogBox(hThisInstance, + MAKEINTRESOURCE(IDD_IMGLST), + NULL, + (DLGPROC)DlgProc); +} diff --git a/rostests/tests/Imagelistviewer/resource.h b/rostests/tests/Imagelistviewer/resource.h index 6875d1deb5a..aa606bf1ca5 100644 --- a/rostests/tests/Imagelistviewer/resource.h +++ b/rostests/tests/Imagelistviewer/resource.h @@ -1,4 +1,4 @@ -#define IDD_IMGLST 1000 -#define IDC_LSTVIEW 1001 -#define IDC_SYSTEM 1002 -#define IDC_DEVICE 1003 +#define IDD_IMGLST 1000 +#define IDC_LSTVIEW 1001 +#define IDC_SYSTEM 1002 +#define IDC_DEVICE 1003 diff --git a/rostests/tests/accelerator/accelerator.rbuild b/rostests/tests/accelerator/accelerator.rbuild index 59b32676b1c..f18f0d19174 100644 --- a/rostests/tests/accelerator/accelerator.rbuild +++ b/rostests/tests/accelerator/accelerator.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 accelerator.c diff --git a/rostests/tests/alive/alive.rbuild b/rostests/tests/alive/alive.rbuild index 369699809c1..0f1f48e293c 100644 --- a/rostests/tests/alive/alive.rbuild +++ b/rostests/tests/alive/alive.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 alive.c diff --git a/rostests/tests/apc/apc.c b/rostests/tests/apc/apc.c index 8ff1c00b6c6..5b45c37e772 100644 --- a/rostests/tests/apc/apc.c +++ b/rostests/tests/apc/apc.c @@ -8,7 +8,7 @@ HANDLE OutputHandle; HANDLE InputHandle; -VOID STDCALL +VOID WINAPI ApcRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatus, ULONG Reserved) diff --git a/rostests/tests/apc/apc.rbuild b/rostests/tests/apc/apc.rbuild index a0557d4dc31..2dc589b569c 100644 --- a/rostests/tests/apc/apc.rbuild +++ b/rostests/tests/apc/apc.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 ntdll apc.c diff --git a/rostests/tests/apc2/apc2.rbuild b/rostests/tests/apc2/apc2.rbuild index 9f8ee1f4d13..0226796076c 100644 --- a/rostests/tests/apc2/apc2.rbuild +++ b/rostests/tests/apc2/apc2.rbuild @@ -1,7 +1,3 @@ - 0x0501 - 0x0501 - - kernel32 apc2.c diff --git a/rostests/tests/args/args.rbuild b/rostests/tests/args/args.rbuild index b819892ba7d..ce3579dcf04 100644 --- a/rostests/tests/args/args.rbuild +++ b/rostests/tests/args/args.rbuild @@ -1,7 +1,3 @@ - 0x0501 - 0x0501 - - kernel32 args.c diff --git a/rostests/tests/atomtest/atomtest.rbuild b/rostests/tests/atomtest/atomtest.rbuild index 731d727513b..b2d0039c405 100644 --- a/rostests/tests/atomtest/atomtest.rbuild +++ b/rostests/tests/atomtest/atomtest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 ntdll atomtest.c diff --git a/rostests/tests/bench/bench.rbuild b/rostests/tests/bench/bench.rbuild index edf7605c984..15b8d106780 100644 --- a/rostests/tests/bench/bench.rbuild +++ b/rostests/tests/bench/bench.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 bench-thread.c diff --git a/rostests/tests/button/button.rbuild b/rostests/tests/button/button.rbuild index 0f269c14046..45422cc3e28 100644 --- a/rostests/tests/button/button.rbuild +++ b/rostests/tests/button/button.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 buttontst.c diff --git a/rostests/tests/button/buttontst.c b/rostests/tests/button/buttontst.c index c12887b6aee..57cf7973464 100644 --- a/rostests/tests/button/buttontst.c +++ b/rostests/tests/button/buttontst.c @@ -50,7 +50,7 @@ LRESULT CALLBACK TestWndProc( } } -int STDCALL WinMain( +int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, diff --git a/rostests/tests/button2/button2.rbuild b/rostests/tests/button2/button2.rbuild index 98a94728bab..72a87543eb7 100644 --- a/rostests/tests/button2/button2.rbuild +++ b/rostests/tests/button2/button2.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 buttontst2.c diff --git a/rostests/tests/capclock/capclock.c b/rostests/tests/capclock/capclock.c index 326da118b13..4d69e3ec611 100644 --- a/rostests/tests/capclock/capclock.c +++ b/rostests/tests/capclock/capclock.c @@ -15,7 +15,7 @@ static BOOL CALLBACK DialogFunc(HWND,UINT,WPARAM,LPARAM); static VOID CALLBACK TimerProc(HWND,UINT,UINT,DWORD); -INT STDCALL WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, INT nCmdShow) +INT WINAPI WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, INT nCmdShow) { WNDCLASS wc; diff --git a/rostests/tests/capclock/capclock.rbuild b/rostests/tests/capclock/capclock.rbuild index 78b5a645df8..778f153151b 100644 --- a/rostests/tests/capclock/capclock.rbuild +++ b/rostests/tests/capclock/capclock.rbuild @@ -1,9 +1,5 @@ - 0x0501 - 0x0501 - . - kernel32 user32 gdi32 capclock.c diff --git a/rostests/tests/carets/carets.rbuild b/rostests/tests/carets/carets.rbuild index bbd3acfc54d..33379ce421b 100644 --- a/rostests/tests/carets/carets.rbuild +++ b/rostests/tests/carets/carets.rbuild @@ -1,9 +1,5 @@ - 0x0501 - 0x0501 - . - kernel32 user32 gdi32 ntdll diff --git a/rostests/tests/combotst/combotst.c b/rostests/tests/combotst/combotst.c index db6effa3cfc..561218d7176 100644 --- a/rostests/tests/combotst/combotst.c +++ b/rostests/tests/combotst/combotst.c @@ -115,7 +115,7 @@ static VOID HandlePrintRect(HWND handle,DWORD Msg,WPARAM wParam,LPARAM lParam) { - RECT rect; + RECT rect = *(RECT*)lParam; TextBuffer[8] = (char)(BUFFERLEN - 8); /* Setting the max size to put chars in first byte */ SendMessage(handle,Msg,wParam,lParam); diff --git a/rostests/tests/combotst/combotst.rbuild b/rostests/tests/combotst/combotst.rbuild index 873635bd93d..12bfec4063f 100644 --- a/rostests/tests/combotst/combotst.rbuild +++ b/rostests/tests/combotst/combotst.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 combotst.c diff --git a/rostests/tests/consume/consume.rbuild b/rostests/tests/consume/consume.rbuild index 47cbf669fac..f6297999dcd 100644 --- a/rostests/tests/consume/consume.rbuild +++ b/rostests/tests/consume/consume.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 consume.c diff --git a/rostests/tests/copymove/copymove.rbuild b/rostests/tests/copymove/copymove.rbuild index 4fe0706f8cc..198255ec035 100644 --- a/rostests/tests/copymove/copymove.rbuild +++ b/rostests/tests/copymove/copymove.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 copymove.c diff --git a/rostests/tests/count/count.rbuild b/rostests/tests/count/count.rbuild index 387be4de423..18fe6f29647 100644 --- a/rostests/tests/count/count.rbuild +++ b/rostests/tests/count/count.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 count.c diff --git a/rostests/tests/create-links/create-links.rbuild b/rostests/tests/create-links/create-links.rbuild index bc1e4750bf4..5693bddd372 100644 --- a/rostests/tests/create-links/create-links.rbuild +++ b/rostests/tests/create-links/create-links.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 ole32 uuid diff --git a/rostests/tests/dirdlg/dirdlg.rbuild b/rostests/tests/dirdlg/dirdlg.rbuild index 361f4df1c51..b305100eaf2 100644 --- a/rostests/tests/dirdlg/dirdlg.rbuild +++ b/rostests/tests/dirdlg/dirdlg.rbuild @@ -1,9 +1,9 @@ - 0x0501 - 0x0501 - . - kernel32 + + + _chdir + user32 gdi32 dirdlg.c diff --git a/rostests/tests/directory.rbuild b/rostests/tests/directory.rbuild index 92bca8df9cf..24c0acc688a 100644 --- a/rostests/tests/directory.rbuild +++ b/rostests/tests/directory.rbuild @@ -7,9 +7,6 @@ - - - @@ -25,9 +22,6 @@ - - - @@ -55,9 +49,6 @@ - - - @@ -115,9 +106,6 @@ - - - @@ -177,12 +165,6 @@ - - - - - - @@ -192,6 +174,9 @@ + + + @@ -228,9 +213,6 @@ - - - diff --git a/rostests/tests/diskspeed/diskspeed.rbuild b/rostests/tests/diskspeed/diskspeed.rbuild index 9713d2a01d4..59367b61b1d 100644 --- a/rostests/tests/diskspeed/diskspeed.rbuild +++ b/rostests/tests/diskspeed/diskspeed.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 diskspeed.c diff --git a/rostests/tests/dnsapi/dnsapi.rbuild b/rostests/tests/dnsapi/dnsapi.rbuild index 92aed4dbabd..05a6ca1a8c7 100644 --- a/rostests/tests/dnsapi/dnsapi.rbuild +++ b/rostests/tests/dnsapi/dnsapi.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 dnsapi ws2_32 dnsapi.c diff --git a/rostests/tests/dnsquery/dnsquery.rbuild b/rostests/tests/dnsquery/dnsquery.rbuild index 84325f9bc2f..2f209b31e25 100644 --- a/rostests/tests/dnsquery/dnsquery.rbuild +++ b/rostests/tests/dnsquery/dnsquery.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 dnsapi ws2_32 dnsquery.c diff --git a/rostests/tests/edit/edit.rbuild b/rostests/tests/edit/edit.rbuild index 3f1180bec24..4c257e5bfd3 100644 --- a/rostests/tests/edit/edit.rbuild +++ b/rostests/tests/edit/edit.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 edittest.c diff --git a/rostests/tests/enhmetafile/enhmetafile.rbuild b/rostests/tests/enhmetafile/enhmetafile.rbuild index f37c9049f51..4223d630970 100644 --- a/rostests/tests/enhmetafile/enhmetafile.rbuild +++ b/rostests/tests/enhmetafile/enhmetafile.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 enhmetafile.c diff --git a/rostests/tests/enumfonts/enumfonts.rbuild b/rostests/tests/enumfonts/enumfonts.rbuild index 64d96b3994c..3fea2ce0a5c 100644 --- a/rostests/tests/enumfonts/enumfonts.rbuild +++ b/rostests/tests/enumfonts/enumfonts.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 enumfonts.cpp diff --git a/rostests/tests/enumwnd/enumwnd.rbuild b/rostests/tests/enumwnd/enumwnd.rbuild index 71adefa1a6e..82b8401d11a 100644 --- a/rostests/tests/enumwnd/enumwnd.rbuild +++ b/rostests/tests/enumwnd/enumwnd.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 enumwnd.c diff --git a/rostests/tests/enumws/enumws.rbuild b/rostests/tests/enumws/enumws.rbuild index 336845c8c32..78597aca8af 100644 --- a/rostests/tests/enumws/enumws.rbuild +++ b/rostests/tests/enumws/enumws.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 enumws.c diff --git a/rostests/tests/event/event.rbuild b/rostests/tests/event/event.rbuild index 5aee383207a..b2bf9e92c35 100644 --- a/rostests/tests/event/event.rbuild +++ b/rostests/tests/event/event.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 event.c diff --git a/rostests/tests/fiber/fiber.rbuild b/rostests/tests/fiber/fiber.rbuild index 2f32d6c803a..38ad1bb125b 100644 --- a/rostests/tests/fiber/fiber.rbuild +++ b/rostests/tests/fiber/fiber.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 fiber.c diff --git a/rostests/tests/gethostbyname/gethostbyname.rbuild b/rostests/tests/gethostbyname/gethostbyname.rbuild index 0d1a501906a..63e024e4991 100644 --- a/rostests/tests/gethostbyname/gethostbyname.rbuild +++ b/rostests/tests/gethostbyname/gethostbyname.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 ws2_32 gethostbyname.c diff --git a/rostests/tests/global_mem/global_mem.c b/rostests/tests/global_mem/global_mem.c index 9d5ba22d9eb..c7804dda5ff 100644 --- a/rostests/tests/global_mem/global_mem.c +++ b/rostests/tests/global_mem/global_mem.c @@ -597,8 +597,8 @@ TEST_STATUS TestGlobalReAllocMovable() */ TEST_STATUS TestGlobalReAlloc() { - OUTPUT_Banner("Testing GlobalReAlloc()"); TEST_STATUS result = SKIPPED; + OUTPUT_Banner("Testing GlobalReAlloc()"); result = TEST_CombineStatus(result, TestGlobalReAllocFixed()); result = TEST_CombineStatus(result, TestGlobalReAllocMovable()); @@ -767,8 +767,8 @@ TEST_STATUS TestGlobalFlagsFixed() */ TEST_STATUS TestGlobalFlags() { - OUTPUT_Banner("Testing GlobalFlags()"); TEST_STATUS result = SKIPPED; + OUTPUT_Banner("Testing GlobalFlags()"); result = TEST_CombineStatus(result, TestGlobalFlagsFixed()); result = TEST_CombineStatus(result, TestGlobalFlagsMoveable()); diff --git a/rostests/tests/global_mem/global_mem.rbuild b/rostests/tests/global_mem/global_mem.rbuild index ce274f0804b..f6ff723384a 100644 --- a/rostests/tests/global_mem/global_mem.rbuild +++ b/rostests/tests/global_mem/global_mem.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 global_mem.c diff --git a/rostests/tests/gradient/gradient.rbuild b/rostests/tests/gradient/gradient.rbuild index c1abf616af6..d085e899dff 100644 --- a/rostests/tests/gradient/gradient.rbuild +++ b/rostests/tests/gradient/gradient.rbuild @@ -1,9 +1,4 @@ - 0x0501 - 0x0501 - 0x0501 - - kernel32 user32 gdi32 gradient.c diff --git a/rostests/tests/guithreadinfo/guithreadinfo.rbuild b/rostests/tests/guithreadinfo/guithreadinfo.rbuild index cd90658c0e1..e6637d740b8 100644 --- a/rostests/tests/guithreadinfo/guithreadinfo.rbuild +++ b/rostests/tests/guithreadinfo/guithreadinfo.rbuild @@ -1,9 +1,4 @@ - 0x0501 - 0x0501 - 0x0501 - - kernel32 gdi32 guithreadinfo.c diff --git a/rostests/tests/hello/hello.rbuild b/rostests/tests/hello/hello.rbuild index b7100692a6e..e5016ffba83 100644 --- a/rostests/tests/hello/hello.rbuild +++ b/rostests/tests/hello/hello.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 hello.c diff --git a/rostests/tests/hivetest/hivetest.rbuild b/rostests/tests/hivetest/hivetest.rbuild index 54784969a8e..988c3abf850 100644 --- a/rostests/tests/hivetest/hivetest.rbuild +++ b/rostests/tests/hivetest/hivetest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 ntdll advapi32 diff --git a/rostests/tests/iptest/iptest.rbuild b/rostests/tests/iptest/iptest.rbuild index e789c29265e..d5707db646a 100644 --- a/rostests/tests/iptest/iptest.rbuild +++ b/rostests/tests/iptest/iptest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 iptest.cpp diff --git a/rostests/tests/isotest/isotest.rbuild b/rostests/tests/isotest/isotest.rbuild index 5859084bbc4..4ddf085f5d2 100644 --- a/rostests/tests/isotest/isotest.rbuild +++ b/rostests/tests/isotest/isotest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 ntdll isotest.c diff --git a/rostests/tests/lantst/lantest.cpp b/rostests/tests/lantst/lantest.cpp index 6b678a244bd..4c3f8042f43 100644 --- a/rostests/tests/lantst/lantest.cpp +++ b/rostests/tests/lantst/lantest.cpp @@ -59,7 +59,7 @@ int byte_till_end( char *Packet, int PktLen ) { #define ETYPE_ARP WH2N(0x0806) extern "C" -NTSTATUS STDCALL NtCreateFile( +NTSTATUS NTAPI NtCreateFile( PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, diff --git a/rostests/tests/lantst/lantest.rbuild b/rostests/tests/lantst/lantest.rbuild index 6a0db28fd23..c9bbac74bc9 100644 --- a/rostests/tests/lantst/lantest.rbuild +++ b/rostests/tests/lantst/lantest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 lantest.cpp diff --git a/rostests/tests/lineclip/lineclip.rbuild b/rostests/tests/lineclip/lineclip.rbuild index f18d31a9bdc..ac8811e4721 100644 --- a/rostests/tests/lineclip/lineclip.rbuild +++ b/rostests/tests/lineclip/lineclip.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 lineclip.c diff --git a/rostests/tests/linetest/linetest.rbuild b/rostests/tests/linetest/linetest.rbuild index a2b203b4249..e2f90590d99 100644 --- a/rostests/tests/linetest/linetest.rbuild +++ b/rostests/tests/linetest/linetest.rbuild @@ -1,9 +1,4 @@ - 0x0501 - 0x0501 - 0x0501 - - kernel32 user32 gdi32 linetest.c diff --git a/rostests/tests/lpctst/conport.c b/rostests/tests/lpctst/conport.c index a3d310136cb..cfe7523bafe 100644 --- a/rostests/tests/lpctst/conport.c +++ b/rostests/tests/lpctst/conport.c @@ -31,7 +31,7 @@ #define LPC_CONNECT_FLAG5 0x00010000 NTSTATUS -(STDCALL * ConnectPort)( +(WINAPI * ConnectPort)( OUT PHANDLE PortHandle, IN PUNICODE_STRING PortName, IN POBJECT_ATTRIBUTES ObjectAttributes, @@ -43,7 +43,7 @@ NTSTATUS ); NTSTATUS -(STDCALL * QueryObject)( +(WINAPI * QueryObject)( IN HANDLE ObjectHandle, IN CINT ObjectInformationClass, OUT PVOID ObjectInformation, @@ -52,7 +52,7 @@ NTSTATUS ); NTSTATUS -(STDCALL * YieldExecution)(VOID); +(WINAPI * YieldExecution)(VOID); #define BUF_SIZE 1024 #define MAXARG 1000000 diff --git a/rostests/tests/lpctst/creport.c b/rostests/tests/lpctst/creport.c index ab0f028e3bc..352a29571f9 100644 --- a/rostests/tests/lpctst/creport.c +++ b/rostests/tests/lpctst/creport.c @@ -23,7 +23,7 @@ #define LPC_CONNECT_FLAG5 0x00010000 NTSTATUS -(STDCALL * CreatePort)( +(WINAPI * CreatePort)( /*OUT PHANDLE PortHandle,*/ PVOID Buffer, IN POBJECT_ATTRIBUTES PortAttributes OPTIONAL, @@ -33,7 +33,7 @@ NTSTATUS ); NTSTATUS -(STDCALL * QueryObject)( +(WINAPI * QueryObject)( IN HANDLE ObjectHandle, IN CINT ObjectInformationClass, OUT PVOID ObjectInformation, @@ -42,7 +42,7 @@ NTSTATUS ); NTSTATUS -(STDCALL * YieldExecution)(VOID); +(WINAPI * YieldExecution)(VOID); #define BUF_SIZE 1024 #define MAXARG 5000000 diff --git a/rostests/tests/lpctst/dumpinfo.c b/rostests/tests/lpctst/dumpinfo.c index 404c2cdae40..0e7f2af9870 100644 --- a/rostests/tests/lpctst/dumpinfo.c +++ b/rostests/tests/lpctst/dumpinfo.c @@ -25,7 +25,7 @@ extern NTSTATUS -(STDCALL * QueryObject)( +(WINAPI * QueryObject)( IN HANDLE ObjectHandle, IN CINT ObjectInformationClass, OUT PVOID ObjectInformation, @@ -35,7 +35,7 @@ NTSTATUS extern NTSTATUS -(STDCALL * QueryInformationPort)( +(WINAPI * QueryInformationPort)( IN HANDLE PortHandle, IN CINT PortInformationClass, /* guess */ OUT PVOID PortInformation, /* guess */ diff --git a/rostests/tests/lpctst/lpctst.rbuild b/rostests/tests/lpctst/lpctst.rbuild index 6c2d96997b6..6dd03a63bd1 100644 --- a/rostests/tests/lpctst/lpctst.rbuild +++ b/rostests/tests/lpctst/lpctst.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 lpctst.c diff --git a/rostests/tests/map_dup_inherit/map_dup_inherit.rbuild b/rostests/tests/map_dup_inherit/map_dup_inherit.rbuild index 4db308fe177..1dfece66aab 100644 --- a/rostests/tests/map_dup_inherit/map_dup_inherit.rbuild +++ b/rostests/tests/map_dup_inherit/map_dup_inherit.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 map_dup_inherit.c diff --git a/rostests/tests/mdi/mdi.rbuild b/rostests/tests/mdi/mdi.rbuild index 1198f68df42..04481eca1c9 100644 --- a/rostests/tests/mdi/mdi.rbuild +++ b/rostests/tests/mdi/mdi.rbuild @@ -1,9 +1,4 @@ - 0x0501 - 0x0501 - - . - kernel32 user32 gdi32 comctl32 diff --git a/rostests/tests/miditest/miditest.c b/rostests/tests/miditest/miditest.c index 1310be32569..e58b4acdc09 100644 --- a/rostests/tests/miditest/miditest.c +++ b/rostests/tests/miditest/miditest.c @@ -22,6 +22,9 @@ int main() int c; + HMIDIOUT Handle = NULL; + UINT Result; + printf("MIDI output devices: %d\n", outs); for (c = 0; c < outs; c ++) @@ -32,8 +35,7 @@ int main() printf("Opening MIDI output #0\n"); - HMIDIOUT Handle = NULL; - UINT Result = midiOutOpen(&Handle, 0, 0, 0, CALLBACK_NULL); + Result = midiOutOpen(&Handle, 0, 0, 0, CALLBACK_NULL); printf("Result == %d Handle == %d\n", Result, (int)Handle); // play something: diff --git a/rostests/tests/miditest/miditest.rbuild b/rostests/tests/miditest/miditest.rbuild index 7b58d7bd544..3b942ddd3d6 100644 --- a/rostests/tests/miditest/miditest.rbuild +++ b/rostests/tests/miditest/miditest.rbuild @@ -1,9 +1,4 @@ - 0x0501 - 0x0501 - - . - kernel32 user32 winmm miditest.c diff --git a/rostests/tests/mktime/mktime.rbuild b/rostests/tests/mktime/mktime.rbuild index 46e0d72a032..d8fa65d4d83 100644 --- a/rostests/tests/mktime/mktime.rbuild +++ b/rostests/tests/mktime/mktime.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 mktime.c diff --git a/rostests/tests/moztest/moztest.c b/rostests/tests/moztest/moztest.c index 3680acb7214..dd792e49d5a 100644 --- a/rostests/tests/moztest/moztest.c +++ b/rostests/tests/moztest/moztest.c @@ -240,9 +240,9 @@ int main(int argc, char **argv) return 0; } - if (!stricmp(argv[1], "socket")) + if (!_stricmp(argv[1], "socket")) return SocketTest(); - if (!stricmp(argv[1], "virtual")) + if (!_stricmp(argv[1], "virtual")) return VirtualTest(); printf("Test '%s' doesn't exist\n", argv[1]); diff --git a/rostests/tests/moztest/moztest.rbuild b/rostests/tests/moztest/moztest.rbuild index 40cb603277e..ba7e8ead9c8 100644 --- a/rostests/tests/moztest/moztest.rbuild +++ b/rostests/tests/moztest/moztest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 ntdll ws2_32 moztest.c diff --git a/rostests/tests/mstest/mstest.rbuild b/rostests/tests/mstest/mstest.rbuild index d8288046c4b..f29a7244ece 100644 --- a/rostests/tests/mstest/mstest.rbuild +++ b/rostests/tests/mstest/mstest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 mstest.c diff --git a/rostests/tests/multithrdwin/multithrdwin.rbuild b/rostests/tests/multithrdwin/multithrdwin.rbuild index 91d237c181b..faf432f2ff2 100644 --- a/rostests/tests/multithrdwin/multithrdwin.rbuild +++ b/rostests/tests/multithrdwin/multithrdwin.rbuild @@ -1,11 +1,6 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 ntdll - multithrdwin.c diff --git a/rostests/tests/multiwin/multiwin.rbuild b/rostests/tests/multiwin/multiwin.rbuild index 3b1f2c320ee..c37b37f17bf 100644 --- a/rostests/tests/multiwin/multiwin.rbuild +++ b/rostests/tests/multiwin/multiwin.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 multiwin.c diff --git a/rostests/tests/mutex/mutex.rbuild b/rostests/tests/mutex/mutex.rbuild index 27eba6c1043..c8a8a2bd59c 100644 --- a/rostests/tests/mutex/mutex.rbuild +++ b/rostests/tests/mutex/mutex.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 mutex.c diff --git a/rostests/tests/nameserverlist/nameserverlist.rbuild b/rostests/tests/nameserverlist/nameserverlist.rbuild index df10511cdf3..bd2224c0525 100644 --- a/rostests/tests/nameserverlist/nameserverlist.rbuild +++ b/rostests/tests/nameserverlist/nameserverlist.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 iphlpapi nameserverlist.c diff --git a/rostests/tests/noexecute/noexecute.rbuild b/rostests/tests/noexecute/noexecute.rbuild index 15062c6a1e5..9d8b50acd3c 100644 --- a/rostests/tests/noexecute/noexecute.rbuild +++ b/rostests/tests/noexecute/noexecute.rbuild @@ -1,10 +1,5 @@ - 0x0501 - 0x0501 - pseh - kernel32 user32 - noexecute.c diff --git a/rostests/tests/nptest/nptest.rbuild b/rostests/tests/nptest/nptest.rbuild index f933fe05bfc..ce3ebe05a42 100644 --- a/rostests/tests/nptest/nptest.rbuild +++ b/rostests/tests/nptest/nptest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 nptest.c diff --git a/rostests/tests/oskittcp/oskittcp.rbuild b/rostests/tests/oskittcp/oskittcp.rbuild index 71313c360f2..a9c29623c38 100644 --- a/rostests/tests/oskittcp/oskittcp.rbuild +++ b/rostests/tests/oskittcp/oskittcp.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 tcptest.cpp diff --git a/rostests/tests/p_dup_handle/p_dup_handle.rbuild b/rostests/tests/p_dup_handle/p_dup_handle.rbuild index f3802850387..a404bc49f5f 100644 --- a/rostests/tests/p_dup_handle/p_dup_handle.rbuild +++ b/rostests/tests/p_dup_handle/p_dup_handle.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 p_dup_handle.c diff --git a/rostests/tests/palbitblt/palbitblt.rbuild b/rostests/tests/palbitblt/palbitblt.rbuild deleted file mode 100644 index dc7b902008e..00000000000 --- a/rostests/tests/palbitblt/palbitblt.rbuild +++ /dev/null @@ -1,9 +0,0 @@ - - 0x0501 - 0x0501 - - kernel32 - user32 - gdi32 - pal.c - diff --git a/rostests/tests/polytest/polytest.cpp b/rostests/tests/polytest/polytest.cpp index c05293f3df5..53567c6a6d2 100644 --- a/rostests/tests/polytest/polytest.cpp +++ b/rostests/tests/polytest/polytest.cpp @@ -17,7 +17,6 @@ #include #define FASTCALL -#define STDCALL #define INT int #define CLIPOBJ int #define SURFOBJ int @@ -501,7 +500,6 @@ POLYGONFILL_UpdateScanline(FILL_EDGE* pEdge, int Scanline) */ static void -STDCALL POLYGONFILL_BuildActiveList ( int Scanline, FILL_EDGE_LIST* list, FILL_EDGE** ActiveHead ) { int i; @@ -526,7 +524,6 @@ POLYGONFILL_BuildActiveList ( int Scanline, FILL_EDGE_LIST* list, FILL_EDGE** Ac */ static void -STDCALL POLYGONFILL_FillScanLineAlternate( PDC dc, int ScanLine, @@ -574,7 +571,6 @@ POLYGONFILL_FillScanLineAlternate( static void -STDCALL POLYGONFILL_FillScanLineWinding( PDC dc, int ScanLine, @@ -674,7 +670,6 @@ POLYGONFILL_FillScanLineWinding( //The direction of each edge of the polygon is important. BOOL -STDCALL FillPolygon( PDC dc, SURFOBJ *SurfObj, @@ -689,7 +684,6 @@ FillPolygon( int ScanLine; void - STDCALL (*FillScanLine)( PDC dc, int ScanLine, @@ -800,7 +794,7 @@ Polygon ( CONST PPOINT UnsafePoints, int Count, int polyFillMode ) To = Points[CurrentPoint + 1]; } - DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n", From.x, From.y, To.x, To.y ); + DPRINT1("Polygon Making line from (%ld,%ld) to (%ld,%ld)\n", From.x, From.y, To.x, To.y ); IntEngLineTo(SurfObj, dc.CombinedClip, OutBrushObj, @@ -869,6 +863,6 @@ int main() printf("\n"); } DPRINT1("Done!\n"); - (void)getch(); + (void)_getch(); } /* EOF */ diff --git a/rostests/tests/polytest/polytest.rbuild b/rostests/tests/polytest/polytest.rbuild index 67272c83b5b..afe43b4e927 100644 --- a/rostests/tests/polytest/polytest.rbuild +++ b/rostests/tests/polytest/polytest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 polytest.cpp diff --git a/rostests/tests/popupmenu/popupmenu.rbuild b/rostests/tests/popupmenu/popupmenu.rbuild index d0c527c195e..bf2c82a6462 100644 --- a/rostests/tests/popupmenu/popupmenu.rbuild +++ b/rostests/tests/popupmenu/popupmenu.rbuild @@ -1,9 +1,5 @@ - 0x0501 - 0x0501 - . - kernel32 user32 gdi32 popupmenu.c diff --git a/rostests/tests/primitives/primitives.rbuild b/rostests/tests/primitives/primitives.rbuild index 482e9d47eb7..370350dd414 100644 --- a/rostests/tests/primitives/primitives.rbuild +++ b/rostests/tests/primitives/primitives.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 primitives.cpp diff --git a/rostests/tests/pseh2/pseh2.rbuild b/rostests/tests/pseh2/pseh2.rbuild new file mode 100644 index 00000000000..12b0afa520d --- /dev/null +++ b/rostests/tests/pseh2/pseh2.rbuild @@ -0,0 +1,7 @@ + + + wine + pseh + psehtest.c + psehtest2.c + diff --git a/rostests/tests/pseh2/psehtest.c b/rostests/tests/pseh2/psehtest.c new file mode 100644 index 00000000000..d8839e3c9f9 --- /dev/null +++ b/rostests/tests/pseh2/psehtest.c @@ -0,0 +1,2654 @@ +/* + Copyright (c) 2008 KJK::Hyperion + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include + +extern void no_op(void); +extern int return_arg(int); + +extern int return_zero(void); +extern int return_positive(void); +extern int return_negative(void); +extern int return_one(void); +extern int return_minusone(void); + +extern int return_zero_2(void *); +extern int return_positive_2(void *); +extern int return_negative_2(void *); +extern int return_one_2(void *); +extern int return_minusone_2(void *); + +extern int return_zero_3(int); +extern int return_positive_3(int); +extern int return_negative_3(int); +extern int return_one_3(int); +extern int return_minusone_3(int); + +extern int return_zero_4(void *, int); +extern int return_positive_4(void *, int); +extern int return_negative_4(void *, int); +extern int return_one_4(void *, int); +extern int return_minusone_4(void *, int); + +extern void set_positive(int *); + +static int call_test(int (*)(void)); + +#define DEFINE_TEST(NAME_) static int NAME_(void) + +/* Empty statements *///{{{ +DEFINE_TEST(test_empty_1) +{ + _SEH2_TRY { } _SEH2_EXCEPT(0) { } _SEH2_END; + return 1; +} + +DEFINE_TEST(test_empty_2) +{ + _SEH2_TRY { } _SEH2_EXCEPT(-1) { } _SEH2_END; + return 1; +} + +DEFINE_TEST(test_empty_3) +{ + _SEH2_TRY { } _SEH2_EXCEPT(1) { } _SEH2_END; + return 1; +} + +DEFINE_TEST(test_empty_4) +{ + _SEH2_TRY { } _SEH2_FINALLY { } _SEH2_END; + return 1; +} + +DEFINE_TEST(test_empty_5) +{ + _SEH2_TRY { _SEH2_TRY { } _SEH2_EXCEPT(0) { } _SEH2_END; } _SEH2_FINALLY { } _SEH2_END; + return 1; +} + +DEFINE_TEST(test_empty_6) +{ + _SEH2_TRY { _SEH2_TRY { } _SEH2_EXCEPT(-1) { } _SEH2_END; } _SEH2_FINALLY { } _SEH2_END; + return 1; +} + +DEFINE_TEST(test_empty_7) +{ + _SEH2_TRY { _SEH2_TRY { } _SEH2_EXCEPT(1) { } _SEH2_END; } _SEH2_FINALLY { } _SEH2_END; + return 1; +} + +DEFINE_TEST(test_empty_8) +{ + _SEH2_TRY { _SEH2_TRY { } _SEH2_FINALLY { } _SEH2_END; } _SEH2_FINALLY { } _SEH2_END; + return 1; +} +//}}} + +/* Static exception filters *///{{{ +DEFINE_TEST(test_execute_handler_1) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_1) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(EXCEPTION_CONTINUE_EXECUTION) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_search_1) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(EXCEPTION_CONTINUE_SEARCH) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_execute_handler_2) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(12345) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_2) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(-12345) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* Dynamic exception filters *///{{{ +DEFINE_TEST(test_execute_handler_3) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_one()) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_3) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(return_minusone()) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_search_2) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_zero()) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_execute_handler_4) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_positive()) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_4) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(return_negative()) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* Dynamic exception filters, using _SEH2_GetExceptionInformation() *///{{{ +DEFINE_TEST(test_execute_handler_5) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_one_2(_SEH2_GetExceptionInformation())) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_5) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(return_minusone_2(_SEH2_GetExceptionInformation())) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_search_3) +{ + static int ret; + + ret = return_positive(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_zero_2(_SEH2_GetExceptionInformation())) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_execute_handler_6) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_positive_2(_SEH2_GetExceptionInformation())) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_6) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(return_negative_2(_SEH2_GetExceptionInformation())) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* Dynamic exception filters, using _SEH2_GetExceptionCode() *///{{{ +DEFINE_TEST(test_execute_handler_7) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_one_3(_SEH2_GetExceptionCode())) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_7) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(return_minusone_3(_SEH2_GetExceptionCode())) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_search_4) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_zero_3(_SEH2_GetExceptionCode())) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_execute_handler_8) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_positive_3(_SEH2_GetExceptionCode())) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_8) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(return_negative_3(_SEH2_GetExceptionCode())) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* Dynamic exception filters, using _SEH2_GetExceptionInformation() and _SEH2_GetExceptionCode() *///{{{ +DEFINE_TEST(test_execute_handler_9) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_one_4(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode())) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_9) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(return_minusone_4(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode())) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_search_5) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_zero_4(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode())) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_execute_handler_10) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(return_positive_4(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode())) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_10) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_positive(); + } + _SEH2_EXCEPT(return_negative_4(_SEH2_GetExceptionInformation(), _SEH2_GetExceptionCode())) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* Constant exception filters with side effects *///{{{ +DEFINE_TEST(test_execute_handler_11) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(set_positive(&ret), EXCEPTION_EXECUTE_HANDLER) + { + ret = ret ? return_positive() : return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_11) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = ret ? return_positive() : return_zero(); + } + _SEH2_EXCEPT(set_positive(&ret), EXCEPTION_CONTINUE_EXECUTION) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_search_6) +{ + static int ret; + static int ret2; + + ret = return_zero(); + ret2 = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + ret2 = return_zero(); + } + _SEH2_EXCEPT(set_positive(&ret), EXCEPTION_CONTINUE_SEARCH) + { + ret = return_zero(); + ret2 = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(set_positive(&ret2), EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + ret2 = return_arg(ret2); + } + _SEH2_END; + + return ret == return_positive() && ret2 == return_positive(); +} + +DEFINE_TEST(test_execute_handler_12) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(set_positive(&ret), 12345) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_continue_execution_12) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_arg(ret); + } + _SEH2_EXCEPT(set_positive(&ret), -12345) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* _SEH2_LEAVE *///{{{ +DEFINE_TEST(test_leave_1) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_positive(); + _SEH2_LEAVE; + ret = return_zero(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_leave_2) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_positive(); + _SEH2_LEAVE; + + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_leave_3) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_positive(); + + if(return_one()) + _SEH2_LEAVE; + + ret = return_zero(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_leave_4) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + int i; + int n = return_one() + return_one(); + + for(i = return_zero(); i < n; ++ i) + { + if(i == return_one()) + { + ret = return_positive(); + _SEH2_LEAVE; + } + } + + ret = return_zero(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_leave_5) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + switch(return_one()) + { + case 0: ret = return_zero(); + case 1: ret = return_positive(); _SEH2_LEAVE; + case 2: ret = return_zero(); + } + + ret = return_zero(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_leave_6) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_LEAVE; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + + ret = return_positive(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* _SEH2_YIELD() *///{{{ +static +int test_yield_1_helper(void) +{ + _SEH2_TRY + { + _SEH2_YIELD(return return_positive()); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return return_zero()); + } + _SEH2_END; + + return return_zero(); +} + +DEFINE_TEST(test_yield_1) +{ + return test_yield_1_helper() == return_positive(); +} + +static +int test_yield_2_helper(void) +{ + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + _SEH2_YIELD(return return_zero()); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return return_positive()); + } + _SEH2_END; + + return return_zero(); +} + +DEFINE_TEST(test_yield_2) +{ + return test_yield_2_helper() == return_positive(); +} + +static +int test_yield_3_helper(void) +{ + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_YIELD(return return_positive()); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return return_zero()); + } + _SEH2_END; + + _SEH2_YIELD(return return_zero()); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return return_zero()); + } + _SEH2_END; + + return return_zero(); +} + +DEFINE_TEST(test_yield_3) +{ + return test_yield_3_helper() == return_positive(); +} + +static +int test_yield_4_helper(void) +{ + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + _SEH2_YIELD(return return_zero()); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return return_positive()); + } + _SEH2_END; + + _SEH2_YIELD(return return_zero()); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + _SEH2_YIELD(return return_zero()); + } + _SEH2_END; + + return return_zero(); +} + +DEFINE_TEST(test_yield_4) +{ + return test_yield_4_helper() == return_positive(); +} + +static int test_yield_5_ret; + +static +int test_yield_5_helper(void) +{ + test_yield_5_ret = return_zero(); + + _SEH2_TRY + { + _SEH2_YIELD(return return_positive()); + } + _SEH2_FINALLY + { + test_yield_5_ret = return_positive(); + } + _SEH2_END; + + return return_zero(); +} + +DEFINE_TEST(test_yield_5) +{ + return test_yield_5_helper() == return_positive() && test_yield_5_ret == return_positive(); +} + +int test_yield_6_ret; + +static +int test_yield_6_helper(void) +{ + test_yield_6_ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_YIELD(return return_positive()); + } + _SEH2_FINALLY + { + test_yield_6_ret = return_positive(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + test_yield_6_ret += return_one(); + } + _SEH2_END; + + return return_zero(); +} + +DEFINE_TEST(test_yield_6) +{ + return test_yield_6_helper() == return_positive() && test_yield_6_ret == return_positive() + return_one(); +} +//}}} + +/* Termination blocks *///{{{ +DEFINE_TEST(test_finally_1) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_arg(ret); + } + _SEH2_FINALLY + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_finally_2) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_arg(ret); + _SEH2_LEAVE; + } + _SEH2_FINALLY + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_finally_3) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_arg(ret); + _SEH2_YIELD(goto leave); + } + _SEH2_FINALLY + { + ret = return_positive(); + } + _SEH2_END; + +leave: + return ret == return_positive(); +} + +static int test_finally_4_ret; + +static int test_finally_4_helper(void) +{ + test_finally_4_ret = return_zero(); + + _SEH2_TRY + { + test_finally_4_ret = return_arg(test_finally_4_ret); + _SEH2_YIELD(return return_positive()); + } + _SEH2_FINALLY + { + test_finally_4_ret = return_positive(); + } + _SEH2_END; + + return return_zero(); +} + +DEFINE_TEST(test_finally_4) +{ + return test_finally_4_helper() == return_positive() && test_finally_4_ret; +} + +DEFINE_TEST(test_finally_5) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_FINALLY + { + ret = return_positive(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_finally_6) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + ret = return_arg(ret); + } + _SEH2_FINALLY + { + if(ret == return_zero()) + ret = return_positive(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + if(ret == return_positive()) + ret = return_positive() + return_one(); + } + _SEH2_END; + + return ret == return_positive() + return_one(); +} + +DEFINE_TEST(test_finally_7) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + ret = return_arg(ret); + _SEH2_LEAVE; + } + _SEH2_FINALLY + { + if(ret == return_zero()) + ret = return_positive(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + if(ret == return_positive()) + ret = return_positive() + return_one(); + } + _SEH2_END; + + return ret == return_positive() + return_one(); +} + +DEFINE_TEST(test_finally_8) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + ret = return_arg(ret); + _SEH2_YIELD(goto leave); + } + _SEH2_FINALLY + { + if(ret == return_zero()) + ret = return_positive(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + if(ret == return_positive()) + ret = return_positive() + return_one(); + } + _SEH2_END; + +leave: + return ret == return_positive() + return_one(); +} + +static int test_finally_9_ret; + +static int test_finally_9_helper(void) +{ + test_finally_9_ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + test_finally_9_ret = return_arg(test_finally_9_ret); + _SEH2_YIELD(return return_positive()); + } + _SEH2_FINALLY + { + if(test_finally_9_ret == return_zero()) + test_finally_9_ret = return_positive(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + if(test_finally_9_ret == return_positive()) + test_finally_9_ret = return_positive() + return_one(); + } + _SEH2_END; + + return return_zero(); +} + +DEFINE_TEST(test_finally_9) +{ + return test_finally_9_helper() == return_positive() && test_finally_9_ret == return_positive() + return_one(); +} + +DEFINE_TEST(test_finally_10) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_FINALLY + { + if(ret == return_zero()) + ret = return_positive(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + if(ret == return_positive()) + ret = return_positive() + return_one(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive() + return_one(); +} + +DEFINE_TEST(test_finally_11) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_TRY + { + ret = return_arg(ret); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + ret = return_positive(); + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + if(ret == return_positive()) + ret += return_one(); + } + _SEH2_END; + + return ret == return_positive() + return_one(); +} + +DEFINE_TEST(test_finally_12) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_TRY + { + ret = return_arg(ret); + } + _SEH2_FINALLY + { + ret = return_positive(); + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + if(ret == return_positive()) + ret += return_one(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + if(ret == return_positive() + return_one()) + ret += return_one(); + } + _SEH2_END; + + return ret == return_positive() + return_one() + return_one(); +} + +static int test_finally_13_ret; + +static +void test_finally_13_helper(void) +{ + test_finally_13_ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + test_finally_13_ret = return_positive(); + _SEH2_YIELD(return); + test_finally_13_ret = return_zero(); + } + _SEH2_FINALLY + { + if(test_finally_13_ret == return_positive()) + test_finally_13_ret += return_one(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + if(test_finally_13_ret == return_positive() + return_one()) + test_finally_13_ret += return_one(); + + RaiseException(0xE00DEAD0, 0, 0, NULL); + test_finally_13_ret = return_zero(); + } + _SEH2_END; + + test_finally_13_ret = return_zero(); +} + +DEFINE_TEST(test_finally_13) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_arg(ret); + test_finally_13_helper(); + ret = return_zero(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_positive(); + } + _SEH2_END; + + return ret == return_positive() && test_finally_13_ret == return_positive() + return_one() + return_one(); +} + +static int test_finally_14_ret; + +static +void test_finally_14_helper(void) +{ + test_finally_14_ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_TRY + { + test_finally_14_ret = return_positive(); + RaiseException(0xE00DEAD0, 0, 0, NULL); + test_finally_14_ret = return_zero(); + } + _SEH2_FINALLY + { + if(test_finally_14_ret == return_positive()) + test_finally_14_ret += return_one(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + if(test_finally_14_ret == return_positive() + return_one()) + test_finally_14_ret += return_one(); + + RaiseException(0xE00DEAD0, 0, 0, NULL); + test_finally_14_ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + if(test_finally_14_ret == return_positive() + return_one() + return_one()) + test_finally_14_ret += return_one(); + } + _SEH2_END; + + test_finally_14_ret = return_arg(test_finally_14_ret); +} + +DEFINE_TEST(test_finally_14) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_arg(ret); + test_finally_14_helper(); + ret = return_positive(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive() && test_finally_14_ret == return_positive() + return_one() + return_one() + return_one(); +} +//}}} + +/* _SEH2_GetExceptionInformation() *///{{{ +static +int verify_xpointers(struct _EXCEPTION_POINTERS * ep, DWORD code, DWORD flags, DWORD argc, const ULONG_PTR * argv, int * ret, int filter) +{ + *ret = + ep && + ep->ExceptionRecord && + ep->ContextRecord && + ep->ExceptionRecord->ExceptionCode == code && + ep->ExceptionRecord->ExceptionFlags == flags && + ep->ExceptionRecord->NumberParameters == argc && + (argv || !argc) && + memcmp(ep->ExceptionRecord->ExceptionInformation, argv, sizeof(argv[0]) * argc) == 0; + + if(*ret) + *ret = return_positive(); + + return filter; +} + +DEFINE_TEST(test_xpointers_1) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, 0, 0, NULL, &ret, EXCEPTION_EXECUTE_HANDLER)) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_2) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 0, NULL); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 0, NULL, &ret, EXCEPTION_EXECUTE_HANDLER)) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_3) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 0, args); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 0, args, &ret, EXCEPTION_EXECUTE_HANDLER)) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_4) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 1, args); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 1, args, &ret, EXCEPTION_EXECUTE_HANDLER)) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_5) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 2, args); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 2, args, &ret, EXCEPTION_EXECUTE_HANDLER)) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_6) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 3, args); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 3, args, &ret, EXCEPTION_EXECUTE_HANDLER)) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_7) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_arg(ret); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, 0, 0, NULL, &ret, EXCEPTION_CONTINUE_EXECUTION)) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_8) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, args); + ret = return_arg(ret); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, 0, 0, args, &ret, EXCEPTION_CONTINUE_EXECUTION)) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_9) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 1, args); + ret = return_arg(ret); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, 0, 1, args, &ret, EXCEPTION_CONTINUE_EXECUTION)) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_10) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 2, args); + ret = return_arg(ret); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, 0, 2, args, &ret, EXCEPTION_CONTINUE_EXECUTION)) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_11) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 3, args); + ret = return_arg(ret); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, 0, 3, args, &ret, EXCEPTION_CONTINUE_EXECUTION)) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_12) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 0, NULL); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 0, NULL, &ret, EXCEPTION_CONTINUE_SEARCH)) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_13) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 0, args); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 0, args, &ret, EXCEPTION_CONTINUE_SEARCH)) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_14) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 1, args); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 1, args, &ret, EXCEPTION_CONTINUE_SEARCH)) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_15) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 2, args); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 2, args, &ret, EXCEPTION_CONTINUE_SEARCH)) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xpointers_16) +{ + static int ret; + static const ULONG_PTR args[] = { 1, 2, 12345 }; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 3, args); + } + _SEH2_EXCEPT(verify_xpointers(_SEH2_GetExceptionInformation(), 0xE00DEAD0, EXCEPTION_NONCONTINUABLE, 3, args, &ret, EXCEPTION_CONTINUE_SEARCH)) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* _SEH2_GetExceptionCode() *///{{{ +static +int verify_xcode(int code, int xcode, int * ret, int filter) +{ + *ret = code == xcode; + + if(*ret) + *ret = return_positive(); + + return filter; +} + +DEFINE_TEST(test_xcode_1) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(verify_xcode(_SEH2_GetExceptionCode(), 0xE00DEAD0, &ret, EXCEPTION_EXECUTE_HANDLER)) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xcode_2) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_arg(ret); + } + _SEH2_EXCEPT(verify_xcode(_SEH2_GetExceptionCode(), 0xE00DEAD0, &ret, EXCEPTION_CONTINUE_EXECUTION)) + { + ret = return_zero(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_xcode_3) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_EXCEPT(verify_xcode(_SEH2_GetExceptionCode(), 0xE00DEAD0, &ret, EXCEPTION_CONTINUE_SEARCH)) + { + ret = return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} +//}}} + +/* _SEH2_AbnormalTermination() *///{{{ +DEFINE_TEST(test_abnorm_1) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + ret = return_arg(ret); + } + _SEH2_FINALLY + { + ret = _SEH2_AbnormalTermination() ? return_zero() : return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_abnorm_2) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_LEAVE; + } + _SEH2_FINALLY + { + ret = _SEH2_AbnormalTermination() ? return_zero() : return_positive(); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_abnorm_3) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_YIELD(goto leave); + } + _SEH2_FINALLY + { + ret = _SEH2_AbnormalTermination() ? return_positive() : return_zero(); + } + _SEH2_END; + +leave: + return ret == return_positive(); +} + +DEFINE_TEST(test_abnorm_4) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_FINALLY + { + ret = _SEH2_AbnormalTermination() ? return_positive() : return_zero(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive(); +} + +DEFINE_TEST(test_abnorm_5) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + ret = return_arg(ret); + } + _SEH2_FINALLY + { + ret = _SEH2_AbnormalTermination() ? return_zero() : return_positive(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + ret = ret == return_positive() && !_SEH2_AbnormalTermination() ? return_positive() + return_one() : ret; + } + _SEH2_END; + + return ret == return_positive() + return_one(); +} + +DEFINE_TEST(test_abnorm_6) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_LEAVE; + } + _SEH2_FINALLY + { + ret = _SEH2_AbnormalTermination() ? return_zero() : return_positive(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + ret = ret == return_positive() && !_SEH2_AbnormalTermination() ? return_positive() + return_one() : ret; + } + _SEH2_END; + + return ret == return_positive() + return_one(); +} + +DEFINE_TEST(test_abnorm_7) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_YIELD(goto leave); + } + _SEH2_FINALLY + { + ret = _SEH2_AbnormalTermination() ? return_positive() : return_zero(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + ret = ret == return_positive() && _SEH2_AbnormalTermination() ? return_positive() + return_one() : ret; + } + _SEH2_END; + +leave: + return ret == return_positive() + return_one(); +} + +DEFINE_TEST(test_abnorm_8) +{ + static int ret; + + ret = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + ret = return_zero(); + } + _SEH2_FINALLY + { + ret = _SEH2_AbnormalTermination() ? return_positive() : return_zero(); + } + _SEH2_END; + } + _SEH2_FINALLY + { + ret = ret == return_positive() && _SEH2_AbnormalTermination() ? return_positive() + return_one() : ret; + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ret = return_arg(ret); + } + _SEH2_END; + + return ret == return_positive() + return_one(); +} +//}}} + +/* Use of local variables from _SEH2_EXCEPT(...) and _SEH2_FINALLY { ... } *///{{{ +DEFINE_TEST(test_nested_locals_1) +{ + int var1 = return_one(); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, 0); + } + _SEH2_EXCEPT((var1 = (var1 == return_one() ? return_positive() : var1)), EXCEPTION_EXECUTE_HANDLER) + { + if(var1 == return_positive()) + var1 = return_positive() + 1; + } + _SEH2_END; + + return var1 == return_positive() + 1; +} + +DEFINE_TEST(test_nested_locals_2) +{ + int var1 = return_positive(); + + _SEH2_TRY + { + } + _SEH2_FINALLY + { + if(var1 == return_positive()) + var1 = return_positive() + 1; + } + _SEH2_END; + + return var1 == return_positive() + 1; +} + +DEFINE_TEST(test_nested_locals_3) +{ + int var1 = return_zero(); + + _SEH2_TRY + { + _SEH2_TRY + { + var1 = return_one(); + RaiseException(0xE00DEAD0, 0, 0, 0); + } + _SEH2_FINALLY + { + if(var1 == return_one()) + var1 = return_positive(); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + if(var1 == return_positive()) + var1 = return_positive() + 1; + } + _SEH2_END; + + return var1 == return_positive() + 1; +} +//}}} + +/* System support *///{{{ +// TODO +//}}} + +/* CPU faults *///{{{ +// TODO +//}}} + +/* Past bugs, to detect regressions *///{{{ +/* #4004: volatile registers clobbered when catching across frames (originally misreported) *///{{{ +static +void test_bug_4004_helper_1(void) +{ + int i1, i2, i3; + + i1 = return_positive(); + i2 = return_positive(); + i3 = return_positive(); + (void)return_arg(i1 + i2 + i3); + + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, NULL); + } + _SEH2_FINALLY + { + } + _SEH2_END; +} + +static +void test_bug_4004_helper_2(void) +{ + _SEH2_TRY + { + test_bug_4004_helper_1(); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END; +} + +DEFINE_TEST(test_bug_4004) +{ + int i1, i2, i3; + + i1 = return_positive(); + i2 = return_positive(); + i3 = return_positive(); + + test_bug_4004_helper_2(); + + return return_arg(i1) + return_arg(i2) + return_arg(i3) == return_positive() * 3; +} +//}}} + +/* #4663: *///{{{ +DEFINE_TEST(test_bug_4663) +{ + int i1, i2; + + i1 = return_positive(); + i2 = return_positive(); + + _SEH2_TRY + { + _SEH2_TRY + { + RaiseException(0xE00DEAD0, 0, 0, 0); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + if (i1 == return_positive()) + { + i1 = return_positive() + 1; + } + } + _SEH2_END; + + if (i1 == return_positive() + 1) + { + i1 = return_negative(); + RaiseException(0xE00DEAD0, 0, 0, 0); + } + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + i2 = return_negative(); + } + _SEH2_END; + + return ((i1 == return_negative()) && (i2 == return_negative())); +} +//}}} +//}}} + +static +LONG WINAPI unhandled_exception(PEXCEPTION_POINTERS ExceptionInfo) +{ + trace("unhandled exception %08lX thrown from %p\n", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); + return EXCEPTION_CONTINUE_SEARCH; +} + +#if defined(_M_IX86) +struct volatile_context +{ + void * esp; + void * ebp; + void * ebx; + void * esi; + void * edi; +}; +#else +struct volatile_context +{ + int _ignore; +}; +#endif + +static +DECLSPEC_NOINLINE +int sanity_check(int ret, struct volatile_context * before, struct volatile_context * after) +{ + if(ret && memcmp(before, after, sizeof(before))) + { + trace("volatile context corrupted\n"); + return 0; + } + + return ret; +} + +static +int passthrough_handler(struct _EXCEPTION_RECORD * e, void * f, struct _CONTEXT * c, void * d) +{ + return ExceptionContinueSearch; +} + +static +DECLSPEC_NOINLINE +int call_test(int (* func)(void)) +{ + static int ret; + static struct volatile_context before, after; + static LPTOP_LEVEL_EXCEPTION_FILTER prev_unhandled_exception; + static _SEH2Registration_t * prev_frame; + _SEH2Registration_t passthrough_frame; + + prev_unhandled_exception = SetUnhandledExceptionFilter(&unhandled_exception); + +#if defined(_X86_) + prev_frame = (_SEH2Registration_t *)__readfsdword(0); + passthrough_frame.SER_Prev = prev_frame; + passthrough_frame.SER_Handler = passthrough_handler; + __writefsdword(0, (unsigned long)&passthrough_frame); +#endif + +#if defined(__GNUC__) && defined(__i386__) + __asm__ __volatile__ + ( + "mov %%esp, 0x00 + %c[before]\n" + "mov %%ebp, 0x04 + %c[before]\n" + "mov %%ebx, 0x08 + %c[before]\n" + "mov %%esi, 0x0c + %c[before]\n" + "mov %%edi, 0x10 + %c[before]\n" + "call *%[test]\n" + "mov %%esp, 0x00 + %c[after]\n" + "mov %%ebp, 0x04 + %c[after]\n" + "mov %%ebx, 0x08 + %c[after]\n" + "mov %%esi, 0x0c + %c[after]\n" + "mov %%edi, 0x10 + %c[after]\n" + "push %[after]\n" + "push %[before]\n" + "push %[ret]\n" + "call %c[sanity_check]\n" + "pop %%ecx\n" + "pop %%ecx\n" + "pop %%ecx\n" : + [ret] "=a" (ret) : + [test] "r" (func), [before] "i" (&before), [after] "i" (&after), [sanity_check] "i" (&sanity_check) : + "ebx", "ecx", "edx", "esi", "edi", "flags", "memory" + ); +#else + ret = func(); +#endif + +#if defined(_X86_) + if((_SEH2Registration_t *)__readfsdword(0) != &passthrough_frame || passthrough_frame.SER_Prev != prev_frame) + { + trace("exception registration list corrupted\n"); + ret = 0; + } + + __writefsdword(0, (unsigned long)prev_frame); +#endif + + SetUnhandledExceptionFilter(prev_unhandled_exception); + return ret; +} + +#define USE_TEST_NAME_(NAME_) # NAME_ +#define USE_TEST_NAME(NAME_) USE_TEST_NAME_(NAME_) +#define USE_TEST(NAME_) { USE_TEST_NAME(NAME_), NAME_ } + +struct subtest +{ + const char * name; + int (* func)(void); +}; + +void testsuite_syntax(void) +{ + const struct subtest testsuite[] = + { + USE_TEST(test_empty_1), + USE_TEST(test_empty_2), + USE_TEST(test_empty_3), + USE_TEST(test_empty_4), + USE_TEST(test_empty_5), + USE_TEST(test_empty_6), + USE_TEST(test_empty_7), + USE_TEST(test_empty_8), + + USE_TEST(test_execute_handler_1), + USE_TEST(test_continue_execution_1), + USE_TEST(test_continue_search_1), + USE_TEST(test_execute_handler_2), + USE_TEST(test_continue_execution_2), + + USE_TEST(test_execute_handler_3), + USE_TEST(test_continue_execution_3), + USE_TEST(test_continue_search_2), + USE_TEST(test_execute_handler_4), + USE_TEST(test_continue_execution_4), + + USE_TEST(test_execute_handler_5), + USE_TEST(test_continue_execution_5), + USE_TEST(test_continue_search_3), + USE_TEST(test_execute_handler_6), + USE_TEST(test_continue_execution_6), + + USE_TEST(test_execute_handler_7), + USE_TEST(test_continue_execution_7), + USE_TEST(test_continue_search_4), + USE_TEST(test_execute_handler_8), + USE_TEST(test_continue_execution_8), + + USE_TEST(test_execute_handler_9), + USE_TEST(test_continue_execution_9), + USE_TEST(test_continue_search_5), + USE_TEST(test_execute_handler_10), + USE_TEST(test_continue_execution_10), + + USE_TEST(test_execute_handler_11), + USE_TEST(test_continue_execution_11), + USE_TEST(test_continue_search_6), + USE_TEST(test_execute_handler_12), + USE_TEST(test_continue_execution_12), + + USE_TEST(test_leave_1), + USE_TEST(test_leave_2), + USE_TEST(test_leave_3), + USE_TEST(test_leave_4), + USE_TEST(test_leave_5), + USE_TEST(test_leave_6), + + USE_TEST(test_yield_1), + USE_TEST(test_yield_2), + USE_TEST(test_yield_3), + USE_TEST(test_yield_4), + USE_TEST(test_yield_5), + USE_TEST(test_yield_6), + + USE_TEST(test_finally_1), + USE_TEST(test_finally_2), + USE_TEST(test_finally_3), + USE_TEST(test_finally_4), + USE_TEST(test_finally_5), + USE_TEST(test_finally_6), + USE_TEST(test_finally_7), + USE_TEST(test_finally_8), + USE_TEST(test_finally_9), + USE_TEST(test_finally_10), + USE_TEST(test_finally_11), + USE_TEST(test_finally_12), + USE_TEST(test_finally_13), + USE_TEST(test_finally_14), + + USE_TEST(test_xpointers_1), + USE_TEST(test_xpointers_2), + USE_TEST(test_xpointers_3), + USE_TEST(test_xpointers_4), + USE_TEST(test_xpointers_5), + USE_TEST(test_xpointers_6), + USE_TEST(test_xpointers_7), + USE_TEST(test_xpointers_8), + USE_TEST(test_xpointers_9), + USE_TEST(test_xpointers_10), + USE_TEST(test_xpointers_11), + USE_TEST(test_xpointers_12), + USE_TEST(test_xpointers_13), + USE_TEST(test_xpointers_14), + USE_TEST(test_xpointers_15), + USE_TEST(test_xpointers_16), + + USE_TEST(test_xcode_1), + USE_TEST(test_xcode_2), + USE_TEST(test_xcode_3), + + USE_TEST(test_abnorm_1), + USE_TEST(test_abnorm_2), + USE_TEST(test_abnorm_3), + USE_TEST(test_abnorm_4), + USE_TEST(test_abnorm_5), + USE_TEST(test_abnorm_6), + USE_TEST(test_abnorm_7), + USE_TEST(test_abnorm_8), + + USE_TEST(test_nested_locals_1), + USE_TEST(test_nested_locals_2), + USE_TEST(test_nested_locals_3), + + USE_TEST(test_bug_4004), + USE_TEST(test_bug_4663), + }; + + size_t i; + + for(i = 0; i < sizeof(testsuite) / sizeof(testsuite[0]); ++ i) + ok(call_test(testsuite[i].func), "%s failed\n", testsuite[i].name); +} + +const struct test winetest_testlist[] = { + { "pseh2_syntax", testsuite_syntax }, + { 0, 0 } +}; + +/* EOF */ diff --git a/rostests/tests/pseh2/psehtest2.c b/rostests/tests/pseh2/psehtest2.c new file mode 100644 index 00000000000..dfdeb9e6d8d --- /dev/null +++ b/rostests/tests/pseh2/psehtest2.c @@ -0,0 +1,160 @@ +/* + Copyright (c) 2008 KJK::Hyperion + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +extern +int return_arg(int arg) +{ + return arg; +} + +extern +void no_op(void) +{ +} + +extern +int return_zero(void) +{ + return 0; +} + +extern +int return_positive(void) +{ + return 1234; +} + +extern +int return_negative(void) +{ + return -1234; +} + +extern +int return_one(void) +{ + return 1; +} + +extern +int return_minusone(void) +{ + return -1; +} + +extern +int return_zero_2(void * p) +{ + return 0; +} + +extern +int return_positive_2(void * p) +{ + return 1234; +} + +extern +int return_negative_2(void * p) +{ + return -1234; +} + +extern +int return_one_2(void * p) +{ + return 1; +} + +extern +int return_minusone_2(void * p) +{ + return -1; +} + +extern +int return_zero_3(int n) +{ + return 0; +} + +extern +int return_positive_3(int n) +{ + return 1234; +} + +extern +int return_negative_3(int n) +{ + return -1234; +} + +extern +int return_one_3(int n) +{ + return 1; +} + +extern +int return_minusone_3(int n) +{ + return -1; +} + +extern +int return_zero_4(void * p, int n) +{ + return 0; +} + +extern +int return_positive_4(void * p, int n) +{ + return 1234; +} + +extern +int return_negative_4(void * p, int n) +{ + return -1234; +} + +extern +int return_one_4(void * p, int n) +{ + return 1; +} + +extern +int return_minusone_4(void * p, int n) +{ + return -1; +} + +extern +void set_positive(int * p) +{ + *p = 1234; +} + +/* EOF */ diff --git a/rostests/tests/pteb/pteb.rbuild b/rostests/tests/pteb/pteb.rbuild index 10b920b5165..a32e34a6f6e 100644 --- a/rostests/tests/pteb/pteb.rbuild +++ b/rostests/tests/pteb/pteb.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 pteb.c diff --git a/rostests/tests/readconsole/main.c b/rostests/tests/readconsole/main.c index bc33134a942..0eb98f970d4 100644 --- a/rostests/tests/readconsole/main.c +++ b/rostests/tests/readconsole/main.c @@ -1,33 +1,33 @@ -#include -#include -#include - -int main() -{ - TCHAR Buffer = 0; - DWORD Count = 0; - - // - // We clear the mode, most importantly turn off ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT - // This is the same mode as that is set up by getch() when trying to get a char - // - SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),0); - - // - // We read one char from the input and then return - // - ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&Buffer,1,&Count,NULL); - - // - // We print out this char as an int to show that infact a backspace does count as input - // - _tprintf(TEXT("You printed %c :: "), Buffer); - _tprintf(TEXT("With a value %d :: "), Buffer); - _tprintf(TEXT("Number of chars recieved %lu :: "), Count); - _tprintf(TEXT("Char equal to backspace %d \n"), (Buffer == TEXT('\b'))); - - // - // :) - // - return 0; -} +#include +#include +#include + +int main() +{ + TCHAR Buffer = 0; + DWORD Count = 0; + + // + // We clear the mode, most importantly turn off ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT + // This is the same mode as that is set up by getch() when trying to get a char + // + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),0); + + // + // We read one char from the input and then return + // + ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&Buffer,1,&Count,NULL); + + // + // We print out this char as an int to show that infact a backspace does count as input + // + _tprintf(TEXT("You printed %c :: "), Buffer); + _tprintf(TEXT("With a value %d :: "), Buffer); + _tprintf(TEXT("Number of chars recieved %lu :: "), Count); + _tprintf(TEXT("Char equal to backspace %d \n"), (Buffer == TEXT('\b'))); + + // + // :) + // + return 0; +} diff --git a/rostests/tests/readconsole/readconsole.rbuild b/rostests/tests/readconsole/readconsole.rbuild index 2a1512e5e37..c854aeffc8a 100644 --- a/rostests/tests/readconsole/readconsole.rbuild +++ b/rostests/tests/readconsole/readconsole.rbuild @@ -1,7 +1,3 @@ - - - - kernel32 main.c diff --git a/rostests/tests/regdump/regdump.rbuild b/rostests/tests/regdump/regdump.rbuild index b2e08642362..ff7cdba8944 100644 --- a/rostests/tests/regdump/regdump.rbuild +++ b/rostests/tests/regdump/regdump.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 advapi32 gdi32 main.c diff --git a/rostests/tests/regqueryvalue/regqueryvalue.c b/rostests/tests/regqueryvalue/regqueryvalue.c index b482cd30276..f43179a5e72 100644 --- a/rostests/tests/regqueryvalue/regqueryvalue.c +++ b/rostests/tests/regqueryvalue/regqueryvalue.c @@ -1,4 +1,3 @@ -#define _DISABLE_TIDENTS #include #include #include @@ -10,7 +9,7 @@ int main( int argc, char **argv ) { PWCHAR WcharResult; WCHAR ValueNameWC[100]; PCHAR CharResult; - HANDLE RegKey; + HKEY RegKey; int i; if( argc < 2 ) { @@ -56,14 +55,13 @@ int main( int argc, char **argv ) { return 7; } - RegQueryValueExA( RegKey, argv[2], NULL, NULL, CharResult, &ResultSize ); + RegQueryValueExA( RegKey, argv[2], NULL, NULL, (PBYTE)CharResult, &ResultSize ); printf( " char Value: %s\n", CharResult ); fflush( stdout ); free( WcharResult ); free( CharResult ); - free( ValueNameWC ); return 0; } diff --git a/rostests/tests/regqueryvalue/regqueryvalue.rbuild b/rostests/tests/regqueryvalue/regqueryvalue.rbuild index 0c345e6052c..480491b5c47 100644 --- a/rostests/tests/regqueryvalue/regqueryvalue.rbuild +++ b/rostests/tests/regqueryvalue/regqueryvalue.rbuild @@ -1,8 +1,4 @@ - - 0x0501 - 0x0501 - - kernel32 + user32 advapi32 gdi32 diff --git a/rostests/tests/regtest/regtest.rbuild b/rostests/tests/regtest/regtest.rbuild index 94f49e9fcb5..8cf55c50dff 100644 --- a/rostests/tests/regtest/regtest.rbuild +++ b/rostests/tests/regtest/regtest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 regtest.c diff --git a/rostests/tests/sectest/sectest.rbuild b/rostests/tests/sectest/sectest.rbuild index af901e25d6a..b3405639853 100644 --- a/rostests/tests/sectest/sectest.rbuild +++ b/rostests/tests/sectest/sectest.rbuild @@ -1,9 +1,4 @@ - 0x0501 - 0x0501 - 0x0501 - - kernel32 gdi32 sectest.c diff --git a/rostests/tests/sertest/sertest.rbuild b/rostests/tests/sertest/sertest.rbuild index 26e65251884..924c73af075 100644 --- a/rostests/tests/sertest/sertest.rbuild +++ b/rostests/tests/sertest/sertest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 sertest.c diff --git a/rostests/tests/shaptest/shaptest.rbuild b/rostests/tests/shaptest/shaptest.rbuild index 0bcdafe8ab0..48398589a1e 100644 --- a/rostests/tests/shaptest/shaptest.rbuild +++ b/rostests/tests/shaptest/shaptest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 shaptest.c diff --git a/rostests/tests/shm/shm.rbuild b/rostests/tests/shm/shm.rbuild index fce03b65ccf..702cad48182 100644 --- a/rostests/tests/shm/shm.rbuild +++ b/rostests/tests/shm/shm.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 shm.c diff --git a/rostests/tests/statst/statst.c b/rostests/tests/statst/statst.c index 080b77baddb..a51a67979d7 100644 --- a/rostests/tests/statst/statst.c +++ b/rostests/tests/statst/statst.c @@ -108,7 +108,7 @@ LRESULT CALLBACK TestWndProc( } } -int STDCALL WinMain( +int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, diff --git a/rostests/tests/statst/statst.rbuild b/rostests/tests/statst/statst.rbuild index 5dd54df4c78..d376f443c14 100644 --- a/rostests/tests/statst/statst.rbuild +++ b/rostests/tests/statst/statst.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 statst.c diff --git a/rostests/tests/statst2/statst2.rbuild b/rostests/tests/statst2/statst2.rbuild index a8489f4785c..8ef65a7ec8c 100644 --- a/rostests/tests/statst2/statst2.rbuild +++ b/rostests/tests/statst2/statst2.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 statst2.c diff --git a/rostests/tests/subclass/subclass.c b/rostests/tests/subclass/subclass.c index db299a440c5..63c4f0e568c 100644 --- a/rostests/tests/subclass/subclass.c +++ b/rostests/tests/subclass/subclass.c @@ -15,7 +15,6 @@ WinMain(HINSTANCE hInstance, int nCmdShow) { WNDCLASSW wc; - MSG msg; HWND hWnd; WCHAR WindowTextW[256]; char WindowTextA[256]; @@ -32,11 +31,11 @@ WinMain(HINSTANCE hInstance, wc.cbWndExtra = 0; if (RegisterClassW(&wc) == 0) { - fprintf(stderr, "RegisterClassW failed (last error 0x%X)\n", + fprintf(stderr, "RegisterClassW failed (last error 0x%lu)\n", GetLastError()); return 1; } - printf("Unicode class registered, WndProc = 0x%08x\n", wc.lpfnWndProc); + printf("Unicode class registered, WndProc = 0x%p\n", wc.lpfnWndProc); hWnd = CreateWindowA("UnicodeClass", "Unicode Window", @@ -51,7 +50,7 @@ WinMain(HINSTANCE hInstance, NULL); if (hWnd == NULL) { - fprintf(stderr, "CreateWindowA failed (last error 0x%X)\n", + fprintf(stderr, "CreateWindowA failed (last error 0x%lu)\n", GetLastError()); return 1; } @@ -61,7 +60,7 @@ WinMain(HINSTANCE hInstance, printf("Calling GetWindowTextW\n"); if (! GetWindowTextW(hWnd, WindowTextW, sizeof(WindowTextW) / sizeof(WindowTextW[0]))) { - fprintf(stderr, "GetWindowTextW failed (last error 0x%X)\n", GetLastError()); + fprintf(stderr, "GetWindowTextW failed (last error 0x%lu)\n", GetLastError()); return 1; } printf("GetWindowTextW returned Unicode string \"%S\"\n", WindowTextW); @@ -69,43 +68,43 @@ WinMain(HINSTANCE hInstance, printf("Calling GetWindowTextA\n"); if (! GetWindowTextA(hWnd, WindowTextA, sizeof(WindowTextA) / sizeof(WindowTextA[0]))) { - fprintf(stderr, "GetWindowTextA failed (last error 0x%X)\n", GetLastError()); + fprintf(stderr, "GetWindowTextA failed (last error 0x%lu)\n", GetLastError()); return 1; } printf("GetWindowTextA returned Ansi string \"%s\"\n", WindowTextA); printf("\n"); SavedWndProcW = (WNDPROC) GetWindowLongW(hWnd, GWL_WNDPROC); - printf("GetWindowLongW returned 0x%08x\n", SavedWndProcW); + printf("GetWindowLongW returned 0x%p\n", SavedWndProcW); SavedWndProcA = (WNDPROC) GetWindowLongA(hWnd, GWL_WNDPROC); - printf("GetWindowLongA returned 0x%08x\n", SavedWndProcA); + printf("GetWindowLongA returned 0x%p\n", SavedWndProcA); printf("\n"); - printf("Subclassing window using SetWindowLongW, new WndProc 0x%08x\n", UnicodeSubclassProc); + printf("Subclassing window using SetWindowLongW, new WndProc 0x%p\n", UnicodeSubclassProc); SetWindowLongW(hWnd, GWL_WNDPROC, (LONG) UnicodeSubclassProc); - printf("After subclass, IsWindowUnicode %s, WndProcA 0x%08x, WndProcW 0x%08x\n", + printf("After subclass, IsWindowUnicode %s, WndProcA 0x%lx, WndProcW 0x%lx\n", IsWindowUnicode(hWnd) ? "TRUE" : "FALSE", GetWindowLongA(hWnd, GWL_WNDPROC), GetWindowLongW(hWnd, GWL_WNDPROC)); printf("Calling GetWindowTextW\n"); if (! GetWindowTextW(hWnd, WindowTextW, sizeof(WindowTextW) / sizeof(WindowTextW[0]))) { - fprintf(stderr, "GetWindowTextW failed (last error 0x%X)\n", GetLastError()); + fprintf(stderr, "GetWindowTextW failed (last error 0x%lu)\n", GetLastError()); return 1; } printf("GetWindowTextW returned Unicode string \"%S\"\n", WindowTextW); printf("\n"); - printf("Subclassing window using SetWindowLongA, new WndProc 0x%08x\n", AnsiSubclassProc); + printf("Subclassing window using SetWindowLongA, new WndProc 0x%p\n", AnsiSubclassProc); SetWindowLongA(hWnd, GWL_WNDPROC, (LONG) AnsiSubclassProc); - printf("After subclass, IsWindowUnicode %s, WndProcA 0x%08x, WndProcW 0x%08x\n", + printf("After subclass, IsWindowUnicode %s, WndProcA 0x%lx, WndProcW 0x%lx\n", IsWindowUnicode(hWnd) ? "TRUE" : "FALSE", GetWindowLongA(hWnd, GWL_WNDPROC), GetWindowLongW(hWnd, GWL_WNDPROC)); printf("Calling GetWindowTextW\n"); if (! GetWindowTextW(hWnd, WindowTextW, sizeof(WindowTextW) / sizeof(WindowTextW[0]))) { - fprintf(stderr, "GetWindowTextW failed (last error 0x%X)\n", GetLastError()); + fprintf(stderr, "GetWindowTextW failed (last error 0x%lu)\n", GetLastError()); return 1; } printf("GetWindowTextW returned Unicode string \"%S\"\n", WindowTextW); diff --git a/rostests/tests/subclass/subclass.rbuild b/rostests/tests/subclass/subclass.rbuild index 8eb191482ec..f92a22330c1 100644 --- a/rostests/tests/subclass/subclass.rbuild +++ b/rostests/tests/subclass/subclass.rbuild @@ -1,8 +1,4 @@ - - 0x0501 - 0x0501 - - kernel32 + user32 gdi32 subclass.c diff --git a/rostests/tests/suspend/suspend.c b/rostests/tests/suspend/suspend.c index a1f8a0697b7..93b9a833dca 100644 --- a/rostests/tests/suspend/suspend.c +++ b/rostests/tests/suspend/suspend.c @@ -11,7 +11,7 @@ static volatile DWORD z; static volatile DWORD x=0; -static NTSTATUS STDCALL +static NTSTATUS WINAPI thread_1(PVOID Param) { DWORD y=0; diff --git a/rostests/tests/suspend/suspend.rbuild b/rostests/tests/suspend/suspend.rbuild index 40de7f6f24f..a2077b06d57 100644 --- a/rostests/tests/suspend/suspend.rbuild +++ b/rostests/tests/suspend/suspend.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 suspend.c diff --git a/rostests/tests/tcpsvr/tcpsvr.c b/rostests/tests/tcpsvr/tcpsvr.c index 8f1d6b8c13b..5915cf31126 100644 --- a/rostests/tests/tcpsvr/tcpsvr.c +++ b/rostests/tests/tcpsvr/tcpsvr.c @@ -130,7 +130,7 @@ int read_line(int newSd, char *line_to_return) { return ERROR; } else if (n==0) { printf(" connection closed by client\n"); - close(newSd); + closesocket(newSd); WSACleanup(); return ERROR; } diff --git a/rostests/tests/tcpsvr/tcpsvr.rbuild b/rostests/tests/tcpsvr/tcpsvr.rbuild index 54665b4d027..506274eee39 100644 --- a/rostests/tests/tcpsvr/tcpsvr.rbuild +++ b/rostests/tests/tcpsvr/tcpsvr.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 ws2_32 tcpsvr.c diff --git a/rostests/tests/terminate/terminate.c b/rostests/tests/terminate/terminate.c index 7fd749f6b89..73ad49dd682 100644 --- a/rostests/tests/terminate/terminate.c +++ b/rostests/tests/terminate/terminate.c @@ -11,7 +11,7 @@ static volatile DWORD z; static volatile DWORD x=0; -static NTSTATUS STDCALL +static NTSTATUS WINAPI thread_1(PVOID Param) { DWORD y=0; diff --git a/rostests/tests/terminate/terminate.rbuild b/rostests/tests/terminate/terminate.rbuild index 6caca7336ec..5c651e1107a 100644 --- a/rostests/tests/terminate/terminate.rbuild +++ b/rostests/tests/terminate/terminate.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 terminate.c diff --git a/rostests/tests/thread/thread.rbuild b/rostests/tests/thread/thread.rbuild index 988b98fbdf1..15e413233ab 100644 --- a/rostests/tests/thread/thread.rbuild +++ b/rostests/tests/thread/thread.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 thread.c diff --git a/rostests/tests/thread_msg/thread_msg.rbuild b/rostests/tests/thread_msg/thread_msg.rbuild index f8ed4f07b82..041c9e95b01 100644 --- a/rostests/tests/thread_msg/thread_msg.rbuild +++ b/rostests/tests/thread_msg/thread_msg.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 thread_msg.c diff --git a/rostests/tests/threadwait/threadwait.rbuild b/rostests/tests/threadwait/threadwait.rbuild index a336d8c25bc..8afada02cfd 100644 --- a/rostests/tests/threadwait/threadwait.rbuild +++ b/rostests/tests/threadwait/threadwait.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 ntdll threadwait.c diff --git a/rostests/tests/tmrqueue/tmrqueue.c b/rostests/tests/tmrqueue/tmrqueue.c index d7c4f4b59e1..0e58393bc03 100644 --- a/rostests/tests/tmrqueue/tmrqueue.c +++ b/rostests/tests/tmrqueue/tmrqueue.c @@ -102,7 +102,7 @@ typedef struct _TESTINFO { struct { - /* nothing */ + HANDLE Dummy; } Test1; struct { diff --git a/rostests/tests/tmrqueue/tmrqueue.rbuild b/rostests/tests/tmrqueue/tmrqueue.rbuild index bce3088985d..67140e61b04 100644 --- a/rostests/tests/tmrqueue/tmrqueue.rbuild +++ b/rostests/tests/tmrqueue/tmrqueue.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 tmrqueue.c diff --git a/rostests/tests/tokentest/tokentest.rbuild b/rostests/tests/tokentest/tokentest.rbuild index 789ee8a3780..5d4ed10de95 100644 --- a/rostests/tests/tokentest/tokentest.rbuild +++ b/rostests/tests/tokentest/tokentest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 tokentest.c diff --git a/rostests/tests/txtscale/txtscale.rbuild b/rostests/tests/txtscale/txtscale.rbuild index 2faacefd36a..3f3af4fbbe3 100644 --- a/rostests/tests/txtscale/txtscale.rbuild +++ b/rostests/tests/txtscale/txtscale.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 comctl32 diff --git a/rostests/tests/vmtest/vmtest.c b/rostests/tests/vmtest/vmtest.c index 95a8aa01399..d9559282b6b 100644 --- a/rostests/tests/vmtest/vmtest.c +++ b/rostests/tests/vmtest/vmtest.c @@ -3,7 +3,7 @@ int main() { - PVOID Base; + PBYTE Base; PVOID Ret; Base = VirtualAlloc(NULL, diff --git a/rostests/tests/vmtest/vmtest.rbuild b/rostests/tests/vmtest/vmtest.rbuild index 09ad93b0c83..d4bcf82c3c4 100644 --- a/rostests/tests/vmtest/vmtest.rbuild +++ b/rostests/tests/vmtest/vmtest.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 vmtest.c diff --git a/rostests/tests/wclickat/wclickat.rbuild b/rostests/tests/wclickat/wclickat.rbuild index 2a354eecef3..17adf0b0233 100644 --- a/rostests/tests/wclickat/wclickat.rbuild +++ b/rostests/tests/wclickat/wclickat.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 wclickat.c diff --git a/rostests/tests/wcstombs-tests/wcstombs-tests.c b/rostests/tests/wcstombs-tests/wcstombs-tests.c index 4e24143b38a..012d37e7d96 100644 --- a/rostests/tests/wcstombs-tests/wcstombs-tests.c +++ b/rostests/tests/wcstombs-tests/wcstombs-tests.c @@ -79,7 +79,7 @@ void CRT_Tests() OK(ret == 1, "ret is %d", ret); OK(mbc == 0, "mbc is %d", mbc); - /* msvcr80.dll changes mbc in the following call back to 0, msvcrt.dll from WinXP SP2 leaves it untouched */ + /* msvcr80.dll and later versions of CRT change mbc in the following call back to 0, msvcrt.dll from WinXP SP2 leaves it untouched */ mbc = 84; ret = wctomb(&mbc, dbwcs[0]); OK(ret == -1, "ret is %d", ret); @@ -193,8 +193,6 @@ void CRT_Tests() void Win32_Tests(LPBOOL bUsedDefaultChar) { - /*int i;*/ - SetLastError(0xdeadbeef); puts("Win32-Tests"); @@ -224,6 +222,26 @@ void Win32_Tests(LPBOOL bUsedDefaultChar) if(bUsedDefaultChar) OK(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d", *bUsedDefaultChar); OK(GetLastError() == 0xdeadbeef, "GetLastError() is %lu", GetLastError()); + /* The behaviour for this character is different when WC_NO_BEST_FIT_CHARS is used */ + ret = WideCharToMultiByte(1251, WC_NO_BEST_FIT_CHARS, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar); + OK(ret == 1, "ret is %d", ret); + OK(mbc == 63, "mbc is %d", mbc); + if(bUsedDefaultChar) OK(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d", *bUsedDefaultChar); + OK(GetLastError() == 0xdeadbeef, "GetLastError() is %lu", GetLastError()); + + ret = WideCharToMultiByte(1252, 0, dbwcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + OK(ret == 3, "ret is %d", ret); + OK(!strcmp(mbs, "??"), "mbs is %s", mbs); + if(bUsedDefaultChar) OK(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d", *bUsedDefaultChar); + OK(GetLastError() == 0xdeadbeef, "GetLastError() is %lu", GetLastError()); + ZeroMemory(mbs, 5); + + ret = WideCharToMultiByte(1252, WC_NO_BEST_FIT_CHARS, dbwcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + OK(ret == 3, "ret is %d", ret); + OK(!strcmp(mbs, "??"), "mbs is %s", mbs); + if(bUsedDefaultChar) OK(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d", *bUsedDefaultChar); + OK(GetLastError() == 0xdeadbeef, "GetLastError() is %lu", GetLastError()); + /* This call triggers the last Win32 error */ ret = WideCharToMultiByte(1252, 0, wcs, -1, &mbc, 1, NULL, bUsedDefaultChar); OK(ret == 0, "ret is %d", ret); @@ -255,6 +273,21 @@ void Win32_Tests(LPBOOL bUsedDefaultChar) if(bUsedDefaultChar) OK(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d", *bUsedDefaultChar); OK(GetLastError() == 0xdeadbeef, "GetLastError() is %lu", GetLastError()); + /* Chinese codepage tests + Swapping the WC_NO_BEST_FIT_CHARS and 0 tests causes bUsedDefaultChar to be set to TRUE in the following test, which quits with ERROR_INSUFFICIENT_BUFFER. + But as it isn't documented whether all other variables are undefined if ERROR_INSUFFICIENT_BUFFER is set, we skip this behaviour. */ + ret = WideCharToMultiByte(950, WC_NO_BEST_FIT_CHARS, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar); + OK(ret == 1, "ret is %d", ret); + OK(mbc == 63, "mbc is %d", mbc); + if(bUsedDefaultChar) OK(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d", *bUsedDefaultChar); + OK(GetLastError() == 0xdeadbeef, "GetLastError() is %lu", GetLastError()); + + ret = WideCharToMultiByte(950, 0, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar); + OK(ret == 1, "ret is %d", ret); + OK(mbc == 97, "mbc is %d", mbc); + if(bUsedDefaultChar) OK(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d", *bUsedDefaultChar); + OK(GetLastError() == 0xdeadbeef, "GetLastError() is %lu", GetLastError()); + /* Double-byte tests */ ret = WideCharToMultiByte(950, 0, dbwcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); OK(ret == 5, "ret is %d", ret); @@ -264,7 +297,7 @@ void Win32_Tests(LPBOOL bUsedDefaultChar) ret = WideCharToMultiByte(950, 0, dbwcs, 1, &mbc, 1, NULL, bUsedDefaultChar); OK(ret == 0, "ret is %d", ret); - if(bUsedDefaultChar) OK(*bUsedDefaultChar == FALSE, "bUsedDefaultChar == FALSE"); + if(bUsedDefaultChar) OK(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d", *bUsedDefaultChar); OK(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %lu", GetLastError()); SetLastError(0xdeadbeef); ZeroMemory(mbs, 5); diff --git a/rostests/tests/wcstombs-tests/wcstombs-tests.rbuild b/rostests/tests/wcstombs-tests/wcstombs-tests.rbuild index e7b407e1d30..d647069d3b6 100644 --- a/rostests/tests/wcstombs-tests/wcstombs-tests.rbuild +++ b/rostests/tests/wcstombs-tests/wcstombs-tests.rbuild @@ -1,4 +1,3 @@ - kernel32 wcstombs-tests.c diff --git a/rostests/tests/winhello/winhello.c b/rostests/tests/winhello/winhello.c index 02037cfffb2..e31a5ffc85b 100644 --- a/rostests/tests/winhello/winhello.c +++ b/rostests/tests/winhello/winhello.c @@ -110,7 +110,7 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; /* Also used during window drawing */ HDC hDC; /* A device context used for drawing */ - RECT rc, clr, wir; /* A rectangle used during drawing */ + RECT rc = {0,0,0,0}, clr, wir; /* A rectangle used during drawing */ char spr[100], sir[100]; static HBRUSH hbrWhite=NULL, hbrGray=NULL, hbrBlack=NULL, hbrRed=NULL, hbrBlue=NULL, hbrYellow=NULL; @@ -123,9 +123,8 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_CHAR: { - - hDC = GetDC(hWnd); TCHAR text[2]; + hDC = GetDC(hWnd); text[0] = (TCHAR)wParam; text[1] = _T('\0'); @@ -170,10 +169,9 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_KEYDOWN: { - - hDC = GetDC(hWnd); RECT Rect; TCHAR text[2]; + hDC = GetDC(hWnd); text[0] = (TCHAR)wParam; text[1] = _T('\0'); @@ -201,10 +199,9 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_KEYUP: { - - hDC = GetDC(hWnd); RECT Rect; TCHAR text[2]; + hDC = GetDC(hWnd); text[0] = (TCHAR)wParam; text[1] = _T('\0'); @@ -594,6 +591,8 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_CREATE: { + SCROLLINFO si; + TEXTMETRIC tm; /* Register a Ctrl+Alt+C hotkey*/ RegisterHotKey(hWnd, CTRLC, MOD_CONTROL, VK_C); RegisterHotKey(hWnd, ALTF1, MOD_CONTROL | MOD_ALT, VK_F1); @@ -605,7 +604,6 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) hbrBlue = CreateSolidBrush ( RGB(0x00, 0x00, 0xFF)); hbrYellow = CreateSolidBrush ( RGB(0xFF, 0xFF, 0x00)); - SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_ALL; si.nMin = 0; @@ -619,7 +617,6 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) /* The window is being created. Create our button * window now. */ - TEXTMETRIC tm; /* First we use the system fixed font size to choose * a nice button size. */ diff --git a/rostests/tests/winhello/winhello.rbuild b/rostests/tests/winhello/winhello.rbuild index 2217e6d6b0d..9ee3e128e71 100644 --- a/rostests/tests/winhello/winhello.rbuild +++ b/rostests/tests/winhello/winhello.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 winhello.c diff --git a/rostests/tests/wm_erasebkgnd/wm_erasebkgnd.rbuild b/rostests/tests/wm_erasebkgnd/wm_erasebkgnd.rbuild index 5f0f800d4f7..12b61e673f1 100644 --- a/rostests/tests/wm_erasebkgnd/wm_erasebkgnd.rbuild +++ b/rostests/tests/wm_erasebkgnd/wm_erasebkgnd.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 wm_erasebkgnd.cpp diff --git a/rostests/tests/wm_paint/wm_paint.rbuild b/rostests/tests/wm_paint/wm_paint.rbuild index 5bcfc22d64f..4c1e5e63951 100644 --- a/rostests/tests/wm_paint/wm_paint.rbuild +++ b/rostests/tests/wm_paint/wm_paint.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 user32 gdi32 wm_paint.c diff --git a/rostests/tests/wpickclick/wpickclick.rbuild b/rostests/tests/wpickclick/wpickclick.rbuild index f02a1b97cc3..876f5753785 100644 --- a/rostests/tests/wpickclick/wpickclick.rbuild +++ b/rostests/tests/wpickclick/wpickclick.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 wpickclick.c diff --git a/rostests/tests/zwcontinue/zwcontinue.rbuild b/rostests/tests/zwcontinue/zwcontinue.rbuild index 6e3280c016f..f4cba28443f 100644 --- a/rostests/tests/zwcontinue/zwcontinue.rbuild +++ b/rostests/tests/zwcontinue/zwcontinue.rbuild @@ -1,8 +1,4 @@ - 0x0501 - 0x0501 - - kernel32 gdi32 zwcontinue.c diff --git a/rostests/win32/cmd/cmd_test.rbuild b/rostests/win32/cmd/cmd_test.rbuild index 57cdf55bdec..56b358501b5 100644 --- a/rostests/win32/cmd/cmd_test.rbuild +++ b/rostests/win32/cmd/cmd_test.rbuild @@ -2,13 +2,11 @@ . include/reactos/wine . - - 0x0501 + 0x501 rtshared regtests cmd_base - kernel32 advapi32 cmd_base pseh diff --git a/rostests/win32/kernel32/directory.rbuild b/rostests/win32/kernel32/directory.rbuild index 8919418f6fa..40b39a7ea7e 100644 --- a/rostests/win32/kernel32/directory.rbuild +++ b/rostests/win32/kernel32/directory.rbuild @@ -4,7 +4,4 @@ - - - diff --git a/rostests/win32/kernel32/queuetest/queuetest.c b/rostests/win32/kernel32/queuetest/queuetest.c index f198465bc3a..7b629c54900 100644 --- a/rostests/win32/kernel32/queuetest/queuetest.c +++ b/rostests/win32/kernel32/queuetest/queuetest.c @@ -15,7 +15,7 @@ BOOL WINAPI QueueUserWorkItem(LPTHREAD_START_ROUTINE,PVOID,ULONG); #define TestProc(n) \ DWORD CALLBACK TestProc##n(void *ctx)\ {\ - printf("TestProc%d thread 0x%x context 0x%p\n", n, GetCurrentThreadId(), ctx);\ + printf("TestProc%d thread 0x%lu context 0x%p\n", n, GetCurrentThreadId(), ctx);\ return 0;\ } diff --git a/rostests/win32/kernel32/queuetest/queuetest.rbuild b/rostests/win32/kernel32/queuetest/queuetest.rbuild index 7211e75ea32..7fb8749a83f 100644 --- a/rostests/win32/kernel32/queuetest/queuetest.rbuild +++ b/rostests/win32/kernel32/queuetest/queuetest.rbuild @@ -1,5 +1,3 @@ - - - kernel32 + queuetest.c diff --git a/rostests/win32/kernel32/tests/CreateFile.c b/rostests/win32/kernel32/tests/CreateFile.c deleted file mode 100644 index 392ebd662df..00000000000 --- a/rostests/win32/kernel32/tests/CreateFile.c +++ /dev/null @@ -1,129 +0,0 @@ -#include - -#ifdef __GNUC__ -#include "regtests.h" -#define NDEBUG -#include "debug.h" - -#define TestFilename L"C:\\File" -#define TestExpectedFilename L"\\??\\" TestFilename -#define TestHandle (HANDLE) 1 - -typedef struct -{ - LPCWSTR lpFileName; - DWORD dwDesiredAccess; - DWORD dwShareMode; - LPSECURITY_ATTRIBUTES lpSecurityAttributes; - DWORD dwCreationDisposition; - DWORD dwFlagsAndAttributes; - HANDLE hTemplateFile; -} CreateFile_PARAMETERS; - -typedef struct -{ - PWCHAR ObjectName; - ACCESS_MASK DesiredAccess; - ULONG FileAttributes; - ULONG ShareAccess; - ULONG CreateDisposition; - ULONG CreateOptions; - PVOID EaBuffer; - ULONG EaLength; -} NtCreateFile_PARAMETERS; - -typedef struct -{ - CreateFile_PARAMETERS CreateFileParameters; - NtCreateFile_PARAMETERS NtCreateFileParameters; -} CreateFileTest_Parameters; - -static CreateFileTest_Parameters CreateFileTests[] = -{ - { - CreateFileParameters: - { - lpFileName: TestFilename, - dwDesiredAccess: GENERIC_ALL, - dwShareMode: FILE_SHARE_WRITE, - lpSecurityAttributes: NULL, - dwCreationDisposition: CREATE_ALWAYS, - dwFlagsAndAttributes: 0, - hTemplateFile: NULL - }, - NtCreateFileParameters: - { - ObjectName: TestExpectedFilename, - DesiredAccess: GENERIC_ALL|SYNCHRONIZE|FILE_READ_ATTRIBUTES, - FileAttributes: 0, - ShareAccess: FILE_SHARE_WRITE, - CreateDisposition: FILE_OVERWRITE_IF, - CreateOptions: FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, - NULL, - 0 - } - } -}; - -static CreateFileTest_Parameters *CurrentTest; - -static NTSTATUS STDCALL -MockNtCreateFile(PHANDLE FileHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PIO_STATUS_BLOCK IoStatusBlock, - PLARGE_INTEGER AllocateSize, - ULONG FileAttributes, - ULONG ShareAccess, - ULONG CreateDisposition, - ULONG CreateOptions, - PVOID EaBuffer, - ULONG EaLength) -{ - _AssertEqualWideString(CurrentTest->NtCreateFileParameters.ObjectName, - ObjectAttributes->ObjectName->Buffer); - _AssertEqualValue(CurrentTest->NtCreateFileParameters.DesiredAccess, DesiredAccess); - _AssertEqualValue(CurrentTest->NtCreateFileParameters.FileAttributes, FileAttributes); - _AssertEqualValue(CurrentTest->NtCreateFileParameters.ShareAccess, ShareAccess); - _AssertEqualValue(CurrentTest->NtCreateFileParameters.CreateDisposition, CreateDisposition); - _AssertEqualValue(CurrentTest->NtCreateFileParameters.CreateOptions, CreateOptions); - *FileHandle = TestHandle; - return STATUS_SUCCESS; -} - -static _HOOK NtCreateFileHooks[] = -{ - {"NtCreateFile", MockNtCreateFile}, - {NULL, NULL} -}; - -static void TestFile() -{ - HANDLE FileHandle; - int index; - - _SetHooks(NtCreateFileHooks); - for (index = 0; index < sizeof(CreateFileTests) / sizeof(CreateFileTests[0]); index++) - { - CurrentTest = &CreateFileTests[index]; - FileHandle = CreateFileW(CurrentTest->CreateFileParameters.lpFileName, - CurrentTest->CreateFileParameters.dwDesiredAccess, - CurrentTest->CreateFileParameters.dwShareMode, - CurrentTest->CreateFileParameters.lpSecurityAttributes, - CurrentTest->CreateFileParameters.dwCreationDisposition, - CurrentTest->CreateFileParameters.dwFlagsAndAttributes, - CurrentTest->CreateFileParameters.hTemplateFile); - _AssertEqualValue(NO_ERROR, GetLastError()); - _AssertEqualValue(TestHandle, FileHandle); - } - _UnsetAllHooks(); -} - -static void RunTest() -{ - TestFile(); -} - -_Dispatcher(CreatefileTest, "CreateFileW") - -#endif diff --git a/rostests/win32/kernel32/tests/kernel32.rbuild b/rostests/win32/kernel32/tests/kernel32.rbuild deleted file mode 100644 index d0c1243f342..00000000000 --- a/rostests/win32/kernel32/tests/kernel32.rbuild +++ /dev/null @@ -1,26 +0,0 @@ - - - - - . - . - - - - 0x0502 - - 0x0500 - rtshared - regtests - kernel32_base - pseh - libcntpr - msvcrt - -lgcc - -nostartfiles - -nostdlib - setup.c - CreateFile.c - - - diff --git a/rostests/win32/kernel32/tests/setup.c b/rostests/win32/kernel32/tests/setup.c deleted file mode 100644 index 6f154f68565..00000000000 --- a/rostests/win32/kernel32/tests/setup.c +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - -int -mainCRTStartup(int argc, char *argv[]) -{ - return WinMain(NULL, NULL, NULL, 0); -} - -_SetupOnce() -{ -} diff --git a/rostests/win32/kernel32/tests/stubs.rbuild b/rostests/win32/kernel32/tests/stubs.rbuild deleted file mode 100644 index 7a98daf6b9d..00000000000 --- a/rostests/win32/kernel32/tests/stubs.rbuild +++ /dev/null @@ -1,257 +0,0 @@ - - CsrCaptureParameterBuffer@16 - CsrClientCallServer@16 - CsrClientConnectToServer@0 - CsrReleaseParameterBuffer@4 - DbgUiContinue@8 - HeapAlloc@12 - HeapFree@12 - LdrAccessResource@16 - LdrDisableThreadCalloutsForDll@4 - LdrFindResource_U@16 - LdrLoadDll@16 - LdrShutdownProcess@0 - LdrShutdownThread@0 - LdrUnloadDll@4 - NtAllocateVirtualMemory@24 - NtClose@4 - NtCreateDirectoryObject@12 - NtCreateEvent@20 - NtCreateFile@44 - NtCreateKey@28 - NtCreateProcess@32 - NtCreateSection@28 - NtDelayExecution@8 - NtDeviceIoControlFile@40 - NtDuplicateObject@28 - NtFlushBuffersFile@8 - NtFlushInstructionCache@12 - NtFlushVirtualMemory@16 - NtFreeVirtualMemory@16 - NtFsControlFile@40 - NtGetContextThread@8 - NtLockVirtualMemory@16 - NtOpenDirectoryObject@12 - NtOpenEvent@12 - NtOpenFile@24 - NtOpenKey@12 - NtOpenProcess@16 - NtOpenSection@12 - NtOpenThread@16 - NtProtectVirtualMemory@20 - NtPulseEvent@8 - NtQueryDefaultLocale@8 - NtQueryDefaultUILanguage@4 - NtQueryDirectoryFile@44 - NtQueryInformationFile@20 - NtQueryInformationProcess@20 - NtQueryInformationThread@20 - NtQueryObject@20 - NtQuerySystemInformation@16 - NtQuerySystemTime@4 - NtQueryValueKey@24 - NtQueryVirtualMemory@24 - NtQueryVolumeInformationFile@20 - NtReadFile@36 - NtReadVirtualMemory@20 - NtResetEvent@8 - NtResumeThread@8 - NtSetContextThread@8 - NtSetEvent@8 - NtSetInformationFile@20 - NtSetInformationObject@16 - NtSetInformationProcess@16 - NtSetInformationThread@16 - NtSetSystemInformation@12 - NtSetSystemTime@8 - NtSignalAndWaitForSingleObject@16 - NtSuspendThread@8 - NtTerminateThread@8 - NtUnlockVirtualMemory@16 - NtUnmapViewOfSection@8 - NtWaitForMultipleObjects@20 - NtWaitForSingleObject@12 - NtWriteFile@36 - NtWriteVirtualMemory@20 - NtYieldExecution@0 - RtlAcquirePebLock@0 - RtlAnsiStringToUnicodeSize@4 - RtlBaseProcessStartRoutine - RtlCompactHeap@8 - RtlCopyUnicodeString@8 - RtlCreateHeap@24 - RtlCreateProcessParameters@40 - RtlCreateUnicodeString@8 - RtlCreateUnicodeStringFromAsciiz@8 - RtlDeleteCriticalSection@4 - RtlDestroyHeap@4 - RtlDestroyProcessParameters@4 - RtlDoesFileExists_U@4 - RtlDosPathNameToNtPathName_U@16 - RtlDosSearchPath_U@24 - RtlEnterCriticalSection@4 - RtlExpandEnvironmentStrings_U@16 - RtlFreeHeap@12 - RtlGetCurrentDirectory_U@8 - RtlGetFullPathName_U@16 - RtlGetProcessHeaps@8 - RtlImageNtHeader@4 - RtlInitCodePageTable@8 - RtlInitializeCriticalSection@4 - RtlInitUnicodeString@8 - RtlIntegerToChar@16 - RtlIntegerToUnicodeString@12 - RtlIsNameLegalDOS8Dot3@12 - RtlLeaveCriticalSection@4 - RtlLockHeap@4 - RtlNtStatusToDosError@4 - RtlOemStringToUnicodeSize@4 - RtlOemStringToUnicodeString@12 - RtlOpenCurrentUser@8 - RtlQueryEnvironmentVariable_U@12 - RtlRaiseException@4 - RtlReAllocateHeap@16 - RtlReleasePebLock@0 - RtlRosCreateUserThreadVa - RtlRosExitUserThread@4 - RtlSetCurrentDirectory_U@4 - RtlSetEnvironmentVariable@12 - RtlSetTimeZoneInformation@4 - RtlTimeFieldsToTime@8 - RtlTimeToTimeFields@8 - RtlUnicodeStringToAnsiSize@4 - RtlUnicodeStringToAnsiString@12 - RtlUnicodeStringToInteger@12 - RtlUnicodeStringToOemString@12 - RtlUnicodeToOemN@20 - RtlUnlockHeap@4 - DbgPrint - LdrFindResourceDirectory_U@16 - LdrGetDllHandle@16 - LdrGetProcedureAddress@16 - RtlCharToInteger@12 - RtlUpcaseUnicodeString@12 - RtlCreateTimerQueue@4 - ZwAllocateVirtualMemory@24 - ZwProtectVirtualMemory@20 - ZwWriteVirtualMemory@20 - RtlGetVersion@4 - RtlVerifyVersionInfo@16 - RtlNormalizeProcessParams@4 - RtlDestroyEnvironment@4 - NtCreateJobObject@12 - NtOpenJobObject@12 - NtIsProcessInJob@8 - NtAssignProcessToJobObject@8 - NtQueryInformationJobObject@20 - NtSetInformationJobObject@16 - NtTerminateJobObject@8 - NtTerminateProcess@8 - RtlRaiseStatus@4 - RtlValidateHeap@12 - RtlClearBits@12 - RtlAreBitsSet@12 - RtlFindClearBitsAndSet@12 - NtQueueApcThread@20 - NtCreateThread@32 - CsrNewThread@0 - CsrClientConnectToServer@20 - CsrCaptureMessageBuffer@16 - CsrAllocateCaptureBuffer@8 - CsrFreeCaptureBuffer@4 - RtlAllocateHeap@12 - RtlDeleteTimerQueueEx@8 - RtlDeleteTimerQueue@4 - RtlCreateTimer@28 - RtlDeleteTimer@12 - RtlUpdateTimer@16 - RtlIsTextUnicode@12 - RtlCompareUnicodeString@12 - RtlFindMessage@20 - RtlDetermineDosPathNameType_U@4 - RtlQueryProcessDebugInformation@12 - RtlDestroyQueryDebugBuffer@4 - RtlAllocateAndInitializeSid@44 - RtlLengthSid@4 - RtlCreateAcl@12 - RtlAddAccessAllowedAce@16 - RtlCreateSecurityDescriptor@8 - RtlSetDaclSecurityDescriptor@16 - RtlFreeSid@4 - RtlFreeAnsiString@4 - NtNotifyChangeDirectoryFile@36 - NtCreateSymbolicLinkObject@16 - RtlEqualUnicodeString@12 - NtQueryEaFile@36 - NtQueryDirectoryObject@28 - NlsMbCodePageTag - NlsMbOemCodePageTag - RtlxUnicodeStringToOemSize@4 - RtlMultiByteToUnicodeN@20 - NtQueryFullAttributesFile@8 - NtQuerySymbolicLinkObject@12 - RtlPrefixUnicodeString@12 - NtCreateIoCompletion@16 - NtRemoveIoCompletion@20 - NtSetIoCompletion@20 - NtCancelIoFile@8 - NtLockFile@40 - NtUnlockFile@20 - NtCreateMailslotFile@32 - NtSetValueKey@24 - NtCreateNamedPipeFile@56 - NtSetVolumeInformationFile@20 - RtlSizeHeap@12 - NtQueryEvent@20 - NtAddAtom@12 - NtDeleteAtom@4 - NtQueryPerformanceCounter@8 - RtlUnwind@16 - RtlInitializeCriticalSectionAndSpinCount@8 - NtCreateTimer@16 - NtOpenTimer@12 - NtCreateMutant@16 - NtQueryInstallUILanguage@4 - NtClearEvent@4 - NtOpenMutant@12 - NtReleaseMutant@8 - NtCreateSemaphore@20@12 - NtOpenSemaphore@12 - NtReleaseSemaphore@12 - NtMapViewOfSection@40 - RtlCreateQueryDebugBuffer@8 - RtlInitAnsiString@8 - RtlAnsiStringToUnicodeString@12 - RtlFreeUnicodeString@4 - NtCancelTimer@8 - NtSetTimer@28 - ZwMapViewOfSection@40 - ZwOpenSection@12 - ZwQuerySection@20 - ZwQuerySystemInformation@16 - ZwReadFile@36 - ZwTerminateProcess@8 - ZwClose@4 - DbgUiIssueRemoteBreakin@4 - NtOpenSymbolicLinkObject@12 - RtlxUnicodeStringToAnsiSize@4 - RtlOemToUnicodeN@20 - RtlUnicodeToMultiByteN@20 - NtFindAtom@12 - NtQueryInformationAtom@20 - RtlCreateAtomTable@8 - RtlAddAtomToAtomTable@12 - RtlDeleteAtomFromAtomTable@8 - RtlLookupAtomInAtomTable@12 - RtlQueryAtomInAtomTable@24 - ZwOpenKey@12 - ZwQueryValueKey@24 - RtlQueryRegistryValues@20 - RtlAppendUnicodeToString@8 - @RtlUshortByteSwap@4 - RtlAppendUnicodeStringToString@8 - NtFlushKey@4 - NtEnumerateValueKey@24 - RtlUpcaseUnicodeChar@4 - NtCreateSemaphore@20 - diff --git a/rostests/win32/kmtloader/kmtloader.rbuild b/rostests/win32/kmtloader/kmtloader.rbuild index 56afda216c8..f7a5002e0c9 100644 --- a/rostests/win32/kmtloader/kmtloader.rbuild +++ b/rostests/win32/kmtloader/kmtloader.rbuild @@ -1,6 +1,4 @@ - - kernel32 advapi32 kmtloader.c diff --git a/rostests/win32/smss/movefile/movefile.rbuild b/rostests/win32/smss/movefile/movefile.rbuild index 84c400fce71..21033a1930f 100644 --- a/rostests/win32/smss/movefile/movefile.rbuild +++ b/rostests/win32/smss/movefile/movefile.rbuild @@ -1,12 +1,6 @@ . - - 0x0500 - 0x0600 - 0x0600 - kernel32 advapi32 user32 movefile.cpp movefile.rc - \ No newline at end of file diff --git a/rostests/win32/user32/drawcaption/capicon.c b/rostests/win32/user32/drawcaption/capicon.c index cef5ca22f3c..c113b4dbdf8 100644 --- a/rostests/win32/user32/drawcaption/capicon.c +++ b/rostests/win32/user32/drawcaption/capicon.c @@ -63,7 +63,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, } -INT main(INT argc, CHAR **argv) +int wmain(int argc, wchar_t**argv) { HWND hWnd; MSG msg; @@ -83,7 +83,7 @@ INT main(INT argc, CHAR **argv) return 0; } - testnum = atoi(argv[1]); + testnum = _wtoi(argv[1]); if(testnum < 1 || testnum > 5) { printf("Unknown test %d\n", testnum); diff --git a/rostests/win32/user32/drawcaption/drawcap.c b/rostests/win32/user32/drawcaption/drawcap.c index 5c6b1e11c18..2e31ee4e748 100644 --- a/rostests/win32/user32/drawcaption/drawcap.c +++ b/rostests/win32/user32/drawcaption/drawcap.c @@ -25,7 +25,7 @@ WCHAR CaptWndClass[] = L"captwnd_class"; HINSTANCE hInst; INT testnum = 0; -//BOOL STDCALL (*DrawCaptionTemp) ( +//BOOL WINAPI (*DrawCaptionTemp) ( // HWND hwnd, // HDC hdc, // const RECT *rect, @@ -180,7 +180,7 @@ LRESULT CALLBACK CaptWndProc(HWND hWnd, } -INT main(INT argc, CHAR **argv) +int wmain(int argc, wchar_t**argv) { HWND hWnd; MSG msg; @@ -205,7 +205,7 @@ INT main(INT argc, CHAR **argv) return 0; } - testnum = atoi(argv[1]); + testnum = _wtoi(argv[1]); if(testnum < 1 || testnum > 8) { printf("Unknown test %d\n", testnum); diff --git a/rostests/win32/user32/drawcaption/drawcaption.rbuild b/rostests/win32/user32/drawcaption/drawcaption.rbuild index 10c7ae459fa..351250ec530 100644 --- a/rostests/win32/user32/drawcaption/drawcaption.rbuild +++ b/rostests/win32/user32/drawcaption/drawcaption.rbuild @@ -1,33 +1,18 @@ - + . - - - - 0x0500 - 0x0600 - 0x0600 - kernel32 user32 gdi32 drawcap.c drawcap.rc - + . - - - - 0x0500 - 0x0600 - 0x0600 - kernel32 user32 gdi32 capicon.c capicon.rc - \ No newline at end of file diff --git a/rostests/win32/user32/kbdlayout/kbdlayout.c b/rostests/win32/user32/kbdlayout/kbdlayout.c index 58e7bbb4001..28dc32fe791 100644 --- a/rostests/win32/user32/kbdlayout/kbdlayout.c +++ b/rostests/win32/user32/kbdlayout/kbdlayout.c @@ -1,387 +1,387 @@ -/* - * PROJECT: ReactOS - * LICENSE: GPL - See COPYING in the top level directory - * FILE: base/applications/testset/user32/kbdlayout/kbdlayout.c - * PURPOSE: Keyboard layout testapp - * COPYRIGHT: Copyright 2007 Saveliy Tretiakov - */ - -#define UNICODE -#include -#include -#include "resource.h" - - - -LRESULT MainDialogProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam); - - -HINSTANCE hInst; -HWND hMainDlg; - - -typedef struct { - WNDPROC OrigProc; - WCHAR WndName[25]; -} WND_DATA; - -DWORD WINAPI ThreadProc(LPVOID lpParam) -{ - - DialogBoxParam(hInst, - MAKEINTRESOURCE(IDD_MAINDIALOG), - NULL, - (DLGPROC)MainDialogProc, - (LPARAM)NULL); - - return 0; -} - -INT WINAPI WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - - - hInst = hInstance; - - ThreadProc(0); - - return 0; -} - - -int GetKlList(HKL **list) -{ - HKL *ret; - int n; - - n = GetKeyboardLayoutList(0, NULL); - ret = HeapAlloc(GetProcessHeap(), 0, sizeof(HKL)*n); - GetKeyboardLayoutList(n, ret); - *list = ret; - return n; -} - -void FreeKlList(HKL *list) -{ - HeapFree(GetProcessHeap(), 0, list); -} - - -void UpdateData(HWND hDlg) -{ - WCHAR buf[KL_NAMELENGTH]; - WCHAR buf2[512]; - - HWND hList; - HKL *klList, hKl; - int n, i,j; - - GetKeyboardLayoutName(buf); - swprintf(buf2, L"Active: %s (%x)", buf, GetKeyboardLayout(0)); - SetWindowText(GetDlgItem(hDlg, IDC_ACTIVE), buf2); - - hList = GetDlgItem(hDlg, IDC_LIST); - SendMessage(hList, LB_RESETCONTENT, 0, 0); - - n = GetKlList(&klList); - hKl = GetKeyboardLayout(0); - for(i = 0; i < n; i++) - { - swprintf(buf, L"%x", klList[i] ); - j = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM) buf); - SendMessage(hList, LB_SETITEMDATA, j, (LPARAM) klList[i]); - if(klList[i] == hKl) SendMessage(hList, LB_SETCURSEL, j, 0); - } - - FreeKlList(klList); -} - -void FormatMsg(WCHAR *format, ...) -{ - WCHAR buf[255]; - va_list argptr; - va_start(argptr, format); - _vsnwprintf(buf, sizeof(buf)-1, format, argptr); - MessageBox(0, buf, L"msg", 0); - va_end(argptr); -} - -void FormatBox(HWND hWnd, DWORD Flags, WCHAR *Caption, WCHAR *Format, ...) -{ - WCHAR buf[255]; - va_list argptr; - va_start(argptr, Format); - _vsnwprintf(buf, sizeof(buf)-1, Format, argptr); - MessageBox(hWnd, buf, Caption, Flags); - va_end(argptr); -} - - -LRESULT CALLBACK WndSubclassProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - WND_DATA *data = (WND_DATA*)GetWindowLong(hwnd, GWL_USERDATA); - - if(uMsg == WM_INPUTLANGCHANGE) - { - FormatMsg(L"%s: WM_INPUTLANGCHANGE lParam=%x wParam=%x\n", data->WndName, lParam, wParam); - UpdateData(hMainDlg); - //Pass message to defwindowproc - } - else if(uMsg == WM_INPUTLANGCHANGEREQUEST) - { - FormatMsg(L"%s: WM_INPUTLANGCHANGEREQUEST lParam=%x wParam=%x\n", data->WndName, lParam, wParam); - UpdateData(hMainDlg); - //Pass message to defwindowproc - } - - return ( CallWindowProc( data->OrigProc, hwnd, uMsg, wParam, lParam) ); -} - -void SubclassWnd(HWND hWnd, WCHAR* Name) -{ - WND_DATA *data = HeapAlloc(GetProcessHeap(), 0, sizeof(WND_DATA)); - data->OrigProc = (WNDPROC)SetWindowLong( hWnd, GWL_WNDPROC, (LONG)WndSubclassProc); - wcsncpy(data->WndName, Name, 25); - SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); - return; -} - -DWORD GetActivateFlags(HWND hDlg) -{ - DWORD ret = 0; - - if(IsDlgButtonChecked(hDlg, IDC_KLF_REORDER)) - ret |= KLF_REORDER; - - if(IsDlgButtonChecked(hDlg, IDC_KLF_RESET)) - ret |= KLF_RESET; - - if(IsDlgButtonChecked(hDlg, IDC_KLF_SHIFTLOCK)) - ret |= KLF_SHIFTLOCK; - - if(IsDlgButtonChecked(hDlg, IDC_KLF_SETFORPROCESS)) - ret |= KLF_SETFORPROCESS; - - return ret; - -} - -DWORD GetLoadFlags(HWND hDlg) -{ - DWORD ret = 0; - - if(IsDlgButtonChecked(hDlg, IDL_KLF_ACTIVATE)) - ret |= KLF_ACTIVATE; - - if(IsDlgButtonChecked(hDlg, IDL_KLF_NOTELLSHELL)) - ret |= KLF_NOTELLSHELL; - - if(IsDlgButtonChecked(hDlg, IDL_KLF_REORDER)) - ret |= KLF_REORDER; - - if(IsDlgButtonChecked(hDlg, IDL_KLF_REPLACELANG)) - ret |= KLF_REPLACELANG; - - if(IsDlgButtonChecked(hDlg, IDL_KLF_SUBSTITUTE_OK)) - ret |= KLF_SUBSTITUTE_OK; - - if(IsDlgButtonChecked(hDlg, IDL_KLF_SETFORPROCESS)) - ret |= KLF_SETFORPROCESS; - - return ret; -} - -UINT GetDelayMilliseconds(HWND hDlg) -{ - WCHAR Buf[255]; - UINT ret; - - GetWindowText(GetDlgItem(hDlg, IDC_DELAY), Buf, sizeof(Buf)); - - swscanf(Buf, L"%d", &ret); - - return ret*1000; -} - -HKL GetSelectedLayout(HWND hDlg) -{ - int n; - HWND hList; - hList = GetDlgItem(hDlg, IDC_LIST); - if((n = SendMessage(hList, LB_GETCURSEL, 0, 0)) != LB_ERR) - return (HKL) SendMessage(hList, LB_GETITEMDATA, n, 0); - else return INVALID_HANDLE_VALUE; -} - -HKL GetActivateHandle(HWND hDlg) -{ - - if(IsDlgButtonChecked(hDlg, IDC_FROMLIST)) - return GetSelectedLayout(hDlg); - else if(IsDlgButtonChecked(hDlg, IDC_HKL_NEXT)) - return (HKL)HKL_NEXT; - - return (HKL)HKL_PREV; - -} - - -/*************************************************** - * MainDialogProc * - ***************************************************/ - -LRESULT MainDialogProc(HWND hDlg, - UINT Msg, - WPARAM wParam, - LPARAM lParam) -{ - HKL hKl; - - switch (Msg) - { - case WM_INITDIALOG: - { - WCHAR Buf[255]; - UpdateData(hDlg); - hMainDlg = hDlg; - - SubclassWnd(GetDlgItem(hDlg, IDC_LIST), L"List"); - SubclassWnd(GetDlgItem(hDlg, IDC_EDIT1), L"Edit1"); - SubclassWnd(GetDlgItem(hDlg, IDC_KLID), L"Klid"); - SubclassWnd(GetDlgItem(hDlg, ID_CANCEL), L"CancelB"); - SubclassWnd(GetDlgItem(hDlg, IDC_ACTIVATE), L"ActivateB"); - SubclassWnd(GetDlgItem(hDlg, IDC_REFRESH), L"RefreshB"); - SubclassWnd(GetDlgItem(hDlg, IDC_UNLOAD), L"UnloadB"); - SubclassWnd(GetDlgItem(hDlg, IDC_LOAD), L"LoadB"); - - CheckRadioButton(hDlg, IDC_FROMLIST, IDC_FROMEDIT, IDC_FROMLIST); - SetWindowText(GetDlgItem(hDlg, IDC_KLID), L"00000419"); - - swprintf(Buf, L"Current thread id: %d", GetCurrentThreadId()); - SetWindowText(GetDlgItem(hDlg, IDC_CURTHREAD), Buf); - - SetWindowText(GetDlgItem(hDlg, IDC_DELAY), L"0"); - - return 0; - } /* WM_INITDIALOG */ - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case ID_CANCEL: - { - EndDialog(hDlg, ERROR_CANCELLED); - break; - } - - case IDC_ACTIVATE: - { - if((hKl = GetActivateHandle(hDlg)) != INVALID_HANDLE_VALUE) - { - Sleep(GetDelayMilliseconds(hDlg)); - if(!(hKl = ActivateKeyboardLayout(hKl, GetActivateFlags(hDlg)))) - FormatBox(hDlg, MB_ICONERROR, L"Error", - L"ActivateKeyboardLayout() failed. %d", GetLastError()); - else UpdateData(hDlg); - //FormatBox(hDlg, 0, L"Activated", L"Prev - %x, err - %d.", hKl, - // GetLastError()); - } - else MessageBox(hDlg, L"No item selected", L"Error", MB_ICONERROR); - break; - } - - case IDC_UNLOAD: - { - if((hKl = GetSelectedLayout(hDlg)) != INVALID_HANDLE_VALUE) - { - Sleep(GetDelayMilliseconds(hDlg)); - if(!UnloadKeyboardLayout(hKl)) - FormatBox(hDlg, MB_ICONERROR, L"Error", - L"UnloadKeyboardLayout() failed. %d", - GetLastError()); - else UpdateData(hDlg); - } - else MessageBox(hDlg, L"No item selected", L"Error", MB_ICONERROR); - break; - } - - case IDC_LOAD: - { - WCHAR buf[255]; - GetWindowText(GetDlgItem(hDlg, IDC_KLID), buf, sizeof(buf)); - Sleep(GetDelayMilliseconds(hDlg)); - if(!LoadKeyboardLayout(buf, GetLoadFlags(hDlg))) - FormatBox(hDlg, MB_ICONERROR, L"Error", - L"LoadKeyboardLayout() failed. %d", - GetLastError()); - else UpdateData(hDlg); - break; - } - - case IDC_REFRESH: - { - UpdateData(hDlg); - break; - } - - case IDC_NEWTHREAD: - { - if(!CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL)) - { - FormatBox(hDlg, MB_ICONERROR, L"Error!", - L"Can not create thread (%d).", GetLastError()); - } - } - - case IDC_LIST: - { - if(HIWORD(wParam) == LBN_SELCHANGE) - { - WCHAR buf[25]; - if((hKl = GetSelectedLayout(hDlg)) != NULL) - { - swprintf(buf, L"%x", hKl); - SetWindowText(GetDlgItem(hDlg, IDC_HANDLE), buf); - } - } - break; - } - - } - - return TRUE; - } /* WM_COMMAND */ - - - case WM_INPUTLANGCHANGE: - { - FormatMsg(L"dlg WM_INPUTLANGCHANGE lParam=%x wParam=%x\n", lParam, wParam); - return FALSE; - } - - case WM_INPUTLANGCHANGEREQUEST: - { - FormatMsg(L"dlg WM_INPUTLANGCHANGEREQUEST lParam=%x wParam=%x\n", lParam, wParam); - UpdateData(hDlg); - return FALSE; - } - - case WM_CLOSE: - { - EndDialog(hDlg, ERROR_CANCELLED); - return TRUE; - } /* WM_CLOSE */ - - default: - return FALSE; - } - -} - - - - +/* + * PROJECT: ReactOS + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/testset/user32/kbdlayout/kbdlayout.c + * PURPOSE: Keyboard layout testapp + * COPYRIGHT: Copyright 2007 Saveliy Tretiakov + */ + +#define UNICODE +#include +#include +#include "resource.h" + + + +LRESULT MainDialogProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam); + + +HINSTANCE hInst; +HWND hMainDlg; + + +typedef struct { + WNDPROC OrigProc; + WCHAR WndName[25]; +} WND_DATA; + +DWORD WINAPI ThreadProc(LPVOID lpParam) +{ + + DialogBoxParam(hInst, + MAKEINTRESOURCE(IDD_MAINDIALOG), + NULL, + (DLGPROC)MainDialogProc, + (LPARAM)NULL); + + return 0; +} + +INT WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + + + hInst = hInstance; + + ThreadProc(0); + + return 0; +} + + +int GetKlList(HKL **list) +{ + HKL *ret; + int n; + + n = GetKeyboardLayoutList(0, NULL); + ret = HeapAlloc(GetProcessHeap(), 0, sizeof(HKL)*n); + GetKeyboardLayoutList(n, ret); + *list = ret; + return n; +} + +void FreeKlList(HKL *list) +{ + HeapFree(GetProcessHeap(), 0, list); +} + + +void UpdateData(HWND hDlg) +{ + WCHAR buf[KL_NAMELENGTH]; + WCHAR buf2[512]; + + HWND hList; + HKL *klList, hKl; + int n, i,j; + + GetKeyboardLayoutName(buf); + swprintf(buf2, L"Active: %s (%x)", buf, GetKeyboardLayout(0)); + SetWindowText(GetDlgItem(hDlg, IDC_ACTIVE), buf2); + + hList = GetDlgItem(hDlg, IDC_LIST); + SendMessage(hList, LB_RESETCONTENT, 0, 0); + + n = GetKlList(&klList); + hKl = GetKeyboardLayout(0); + for(i = 0; i < n; i++) + { + swprintf(buf, L"%x", klList[i] ); + j = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM) buf); + SendMessage(hList, LB_SETITEMDATA, j, (LPARAM) klList[i]); + if(klList[i] == hKl) SendMessage(hList, LB_SETCURSEL, j, 0); + } + + FreeKlList(klList); +} + +void FormatMsg(WCHAR *format, ...) +{ + WCHAR buf[255]; + va_list argptr; + va_start(argptr, format); + _vsnwprintf(buf, sizeof(buf)-1, format, argptr); + MessageBox(0, buf, L"msg", 0); + va_end(argptr); +} + +void FormatBox(HWND hWnd, DWORD Flags, WCHAR *Caption, WCHAR *Format, ...) +{ + WCHAR buf[255]; + va_list argptr; + va_start(argptr, Format); + _vsnwprintf(buf, sizeof(buf)-1, Format, argptr); + MessageBox(hWnd, buf, Caption, Flags); + va_end(argptr); +} + + +LRESULT CALLBACK WndSubclassProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WND_DATA *data = (WND_DATA*)GetWindowLong(hwnd, GWL_USERDATA); + + if(uMsg == WM_INPUTLANGCHANGE) + { + FormatMsg(L"%s: WM_INPUTLANGCHANGE lParam=%x wParam=%x\n", data->WndName, lParam, wParam); + UpdateData(hMainDlg); + //Pass message to defwindowproc + } + else if(uMsg == WM_INPUTLANGCHANGEREQUEST) + { + FormatMsg(L"%s: WM_INPUTLANGCHANGEREQUEST lParam=%x wParam=%x\n", data->WndName, lParam, wParam); + UpdateData(hMainDlg); + //Pass message to defwindowproc + } + + return ( CallWindowProc( data->OrigProc, hwnd, uMsg, wParam, lParam) ); +} + +void SubclassWnd(HWND hWnd, WCHAR* Name) +{ + WND_DATA *data = HeapAlloc(GetProcessHeap(), 0, sizeof(WND_DATA)); + data->OrigProc = (WNDPROC)SetWindowLong( hWnd, GWL_WNDPROC, (LONG)WndSubclassProc); + wcsncpy(data->WndName, Name, 25); + SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); + return; +} + +DWORD GetActivateFlags(HWND hDlg) +{ + DWORD ret = 0; + + if(IsDlgButtonChecked(hDlg, IDC_KLF_REORDER)) + ret |= KLF_REORDER; + + if(IsDlgButtonChecked(hDlg, IDC_KLF_RESET)) + ret |= KLF_RESET; + + if(IsDlgButtonChecked(hDlg, IDC_KLF_SHIFTLOCK)) + ret |= KLF_SHIFTLOCK; + + if(IsDlgButtonChecked(hDlg, IDC_KLF_SETFORPROCESS)) + ret |= KLF_SETFORPROCESS; + + return ret; + +} + +DWORD GetLoadFlags(HWND hDlg) +{ + DWORD ret = 0; + + if(IsDlgButtonChecked(hDlg, IDL_KLF_ACTIVATE)) + ret |= KLF_ACTIVATE; + + if(IsDlgButtonChecked(hDlg, IDL_KLF_NOTELLSHELL)) + ret |= KLF_NOTELLSHELL; + + if(IsDlgButtonChecked(hDlg, IDL_KLF_REORDER)) + ret |= KLF_REORDER; + + if(IsDlgButtonChecked(hDlg, IDL_KLF_REPLACELANG)) + ret |= KLF_REPLACELANG; + + if(IsDlgButtonChecked(hDlg, IDL_KLF_SUBSTITUTE_OK)) + ret |= KLF_SUBSTITUTE_OK; + + if(IsDlgButtonChecked(hDlg, IDL_KLF_SETFORPROCESS)) + ret |= KLF_SETFORPROCESS; + + return ret; +} + +UINT GetDelayMilliseconds(HWND hDlg) +{ + WCHAR Buf[255]; + UINT ret; + + GetWindowText(GetDlgItem(hDlg, IDC_DELAY), Buf, sizeof(Buf)); + + swscanf(Buf, L"%d", &ret); + + return ret*1000; +} + +HKL GetSelectedLayout(HWND hDlg) +{ + int n; + HWND hList; + hList = GetDlgItem(hDlg, IDC_LIST); + if((n = SendMessage(hList, LB_GETCURSEL, 0, 0)) != LB_ERR) + return (HKL) SendMessage(hList, LB_GETITEMDATA, n, 0); + else return INVALID_HANDLE_VALUE; +} + +HKL GetActivateHandle(HWND hDlg) +{ + + if(IsDlgButtonChecked(hDlg, IDC_FROMLIST)) + return GetSelectedLayout(hDlg); + else if(IsDlgButtonChecked(hDlg, IDC_HKL_NEXT)) + return (HKL)HKL_NEXT; + + return (HKL)HKL_PREV; + +} + + +/*************************************************** + * MainDialogProc * + ***************************************************/ + +LRESULT MainDialogProc(HWND hDlg, + UINT Msg, + WPARAM wParam, + LPARAM lParam) +{ + HKL hKl; + + switch (Msg) + { + case WM_INITDIALOG: + { + WCHAR Buf[255]; + UpdateData(hDlg); + hMainDlg = hDlg; + + SubclassWnd(GetDlgItem(hDlg, IDC_LIST), L"List"); + SubclassWnd(GetDlgItem(hDlg, IDC_EDIT1), L"Edit1"); + SubclassWnd(GetDlgItem(hDlg, IDC_KLID), L"Klid"); + SubclassWnd(GetDlgItem(hDlg, ID_CANCEL), L"CancelB"); + SubclassWnd(GetDlgItem(hDlg, IDC_ACTIVATE), L"ActivateB"); + SubclassWnd(GetDlgItem(hDlg, IDC_REFRESH), L"RefreshB"); + SubclassWnd(GetDlgItem(hDlg, IDC_UNLOAD), L"UnloadB"); + SubclassWnd(GetDlgItem(hDlg, IDC_LOAD), L"LoadB"); + + CheckRadioButton(hDlg, IDC_FROMLIST, IDC_FROMEDIT, IDC_FROMLIST); + SetWindowText(GetDlgItem(hDlg, IDC_KLID), L"00000419"); + + swprintf(Buf, L"Current thread id: %d", GetCurrentThreadId()); + SetWindowText(GetDlgItem(hDlg, IDC_CURTHREAD), Buf); + + SetWindowText(GetDlgItem(hDlg, IDC_DELAY), L"0"); + + return 0; + } /* WM_INITDIALOG */ + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case ID_CANCEL: + { + EndDialog(hDlg, ERROR_CANCELLED); + break; + } + + case IDC_ACTIVATE: + { + if((hKl = GetActivateHandle(hDlg)) != INVALID_HANDLE_VALUE) + { + Sleep(GetDelayMilliseconds(hDlg)); + if(!(hKl = ActivateKeyboardLayout(hKl, GetActivateFlags(hDlg)))) + FormatBox(hDlg, MB_ICONERROR, L"Error", + L"ActivateKeyboardLayout() failed. %d", GetLastError()); + else UpdateData(hDlg); + //FormatBox(hDlg, 0, L"Activated", L"Prev - %x, err - %d.", hKl, + // GetLastError()); + } + else MessageBox(hDlg, L"No item selected", L"Error", MB_ICONERROR); + break; + } + + case IDC_UNLOAD: + { + if((hKl = GetSelectedLayout(hDlg)) != INVALID_HANDLE_VALUE) + { + Sleep(GetDelayMilliseconds(hDlg)); + if(!UnloadKeyboardLayout(hKl)) + FormatBox(hDlg, MB_ICONERROR, L"Error", + L"UnloadKeyboardLayout() failed. %d", + GetLastError()); + else UpdateData(hDlg); + } + else MessageBox(hDlg, L"No item selected", L"Error", MB_ICONERROR); + break; + } + + case IDC_LOAD: + { + WCHAR buf[255]; + GetWindowText(GetDlgItem(hDlg, IDC_KLID), buf, sizeof(buf)); + Sleep(GetDelayMilliseconds(hDlg)); + if(!LoadKeyboardLayout(buf, GetLoadFlags(hDlg))) + FormatBox(hDlg, MB_ICONERROR, L"Error", + L"LoadKeyboardLayout() failed. %d", + GetLastError()); + else UpdateData(hDlg); + break; + } + + case IDC_REFRESH: + { + UpdateData(hDlg); + break; + } + + case IDC_NEWTHREAD: + { + if(!CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL)) + { + FormatBox(hDlg, MB_ICONERROR, L"Error!", + L"Can not create thread (%d).", GetLastError()); + } + } + + case IDC_LIST: + { + if(HIWORD(wParam) == LBN_SELCHANGE) + { + WCHAR buf[25]; + if((hKl = GetSelectedLayout(hDlg)) != NULL) + { + swprintf(buf, L"%x", hKl); + SetWindowText(GetDlgItem(hDlg, IDC_HANDLE), buf); + } + } + break; + } + + } + + return TRUE; + } /* WM_COMMAND */ + + + case WM_INPUTLANGCHANGE: + { + FormatMsg(L"dlg WM_INPUTLANGCHANGE lParam=%x wParam=%x\n", lParam, wParam); + return FALSE; + } + + case WM_INPUTLANGCHANGEREQUEST: + { + FormatMsg(L"dlg WM_INPUTLANGCHANGEREQUEST lParam=%x wParam=%x\n", lParam, wParam); + UpdateData(hDlg); + return FALSE; + } + + case WM_CLOSE: + { + EndDialog(hDlg, ERROR_CANCELLED); + return TRUE; + } /* WM_CLOSE */ + + default: + return FALSE; + } + +} + + + + diff --git a/rostests/win32/user32/kbdlayout/kbdlayout.rbuild b/rostests/win32/user32/kbdlayout/kbdlayout.rbuild index 1f954ab0875..b2c73909635 100644 --- a/rostests/win32/user32/kbdlayout/kbdlayout.rbuild +++ b/rostests/win32/user32/kbdlayout/kbdlayout.rbuild @@ -1,13 +1,7 @@ - - . - - - 0x0500 - 0x0600 - 0x0600 - kernel32 - user32 - gdi32 - kbdlayout.c - kbdlayout.rc - + + . + user32 + gdi32 + kbdlayout.c + kbdlayout.rc + diff --git a/rostests/win32/user32/kbdlayout/resource.h b/rostests/win32/user32/kbdlayout/resource.h index a245b7f9fbd..91e056ea8e4 100644 --- a/rostests/win32/user32/kbdlayout/resource.h +++ b/rostests/win32/user32/kbdlayout/resource.h @@ -1,46 +1,46 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by kbdlayout.rc -// -#define IDD_MAINDIALOG 101 -#define ID_CANCEL 1000 -#define IDC_EDIT1 1021 -#define IDC_LIST 1022 -#define IDC_ACTIVE 1023 -#define IDC_EDIT2 1024 -#define IDC_DELAY 1024 -#define IDC_UNLOAD 1025 -#define IDC_ACTIVATE 1026 -#define IDC_KLF_REORDER 1027 -#define IDC_KLF_RESET 1028 -#define IDC_KLF_SETFORPROCESS 1029 -#define IDC_KLF_SHIFTLOCK 1030 -#define IDC_FROMLIST 1032 -#define IDC_HKL_NEXT 1033 -#define IDC_HKL_PREV 1034 -#define IDL_KLF_ACTIVATE 1035 -#define IDL_KLF_NOTELLSHELL 1036 -#define IDC_KLID 1037 -#define IDL_KLF_REORDER 1038 -#define IDL_KLF_REPLACELANG 1039 -#define IDL_KLF_SUBSTITUTE_OK 1040 -#define IDL_KLF_SETFORPROCESS 1041 -#define IDC_HKL_PREV2 1042 -#define IDC_FROMEDIT 1042 -#define IDC_LOAD 1043 -#define IDC_REFRESH 1044 -#define IDC_HANDLE 1046 -#define IDC_CURTHREAD 1049 -#define IDC_NEWTHREAD 1050 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1051 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by kbdlayout.rc +// +#define IDD_MAINDIALOG 101 +#define ID_CANCEL 1000 +#define IDC_EDIT1 1021 +#define IDC_LIST 1022 +#define IDC_ACTIVE 1023 +#define IDC_EDIT2 1024 +#define IDC_DELAY 1024 +#define IDC_UNLOAD 1025 +#define IDC_ACTIVATE 1026 +#define IDC_KLF_REORDER 1027 +#define IDC_KLF_RESET 1028 +#define IDC_KLF_SETFORPROCESS 1029 +#define IDC_KLF_SHIFTLOCK 1030 +#define IDC_FROMLIST 1032 +#define IDC_HKL_NEXT 1033 +#define IDC_HKL_PREV 1034 +#define IDL_KLF_ACTIVATE 1035 +#define IDL_KLF_NOTELLSHELL 1036 +#define IDC_KLID 1037 +#define IDL_KLF_REORDER 1038 +#define IDL_KLF_REPLACELANG 1039 +#define IDL_KLF_SUBSTITUTE_OK 1040 +#define IDL_KLF_SETFORPROCESS 1041 +#define IDC_HKL_PREV2 1042 +#define IDC_FROMEDIT 1042 +#define IDC_LOAD 1043 +#define IDC_REFRESH 1044 +#define IDC_HANDLE 1046 +#define IDC_CURTHREAD 1049 +#define IDC_NEWTHREAD 1050 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1051 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/rostests/win32/user32/sysicon/sysicon.c b/rostests/win32/user32/sysicon/sysicon.c index 84802a1dfb8..0e74fbbcbd5 100644 --- a/rostests/win32/user32/sysicon/sysicon.c +++ b/rostests/win32/user32/sysicon/sysicon.c @@ -66,9 +66,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, return DefWindowProc(hWnd, msg, wParam, lParam); } -int APIENTRY WinMain(HINSTANCE hInst, +int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, + LPWSTR lpCmdLine, int nCmdShow) { HWND hWnd1, hWnd2, hWnd3; diff --git a/rostests/win32/user32/sysicon/sysicon.rbuild b/rostests/win32/user32/sysicon/sysicon.rbuild index cc617fee768..030452bbb2c 100644 --- a/rostests/win32/user32/sysicon/sysicon.rbuild +++ b/rostests/win32/user32/sysicon/sysicon.rbuild @@ -1,12 +1,5 @@ - + . - - - - 0x0500 - 0x0600 - 0x0600 - kernel32 user32 gdi32 sysicon.c diff --git a/rostests/win32/win32k/tests/eng-mem-1.c b/rostests/win32/win32k/tests/eng-mem-1.c index 8aa8aecd25f..54a4ed1b1ab 100644 --- a/rostests/win32/win32k/tests/eng-mem-1.c +++ b/rostests/win32/win32k/tests/eng-mem-1.c @@ -14,14 +14,14 @@ static void RunTest() /* Allocate memory with EngAllocMem */ pmem1 = 0; AllocSize1 = 1024; - AllocTag1 = TAG('D','x','y','z'); + AllocTag1 = 'zyxD'; pmem1 = EngAllocMem(FL_ZERO_MEMORY, AllocSize1, AllocTag1); _AssertNotEqualValue(pmem1, NULL); /* Allocate memory with EngAllocMem */ pmem2 = 0; AllocSize2 = 1024; - AllocTag2 = TAG('D','x','y','z'); + AllocTag2 = 'zyxD'; pmem2 = EngAllocUserMem(AllocSize2, AllocTag2); _AssertNotEqualValue(pmem1, NULL); diff --git a/rostests/win32/win32k/win32k.rbuild b/rostests/win32/win32k/win32k.rbuild index 41660f11879..24a410216a7 100644 --- a/rostests/win32/win32k/win32k.rbuild +++ b/rostests/win32/win32k/win32k.rbuild @@ -4,11 +4,6 @@ include include include - - - 0x0501 - 0x600 - rtshared regtests diff --git a/rostests/winetests/GUI/GUI.rbuild b/rostests/winetests/GUI/GUI.rbuild index 746cecc78bd..8aceb4b1268 100644 --- a/rostests/winetests/GUI/GUI.rbuild +++ b/rostests/winetests/GUI/GUI.rbuild @@ -3,9 +3,9 @@ . 0x600 - 0x501 + 0x501 + gdi32 - kernel32 user32 comctl32 browsewnd.c diff --git a/rostests/winetests/GUI/browsewnd.c b/rostests/winetests/GUI/browsewnd.c index 16d104f0f73..4a841eb96a9 100644 --- a/rostests/winetests/GUI/browsewnd.c +++ b/rostests/winetests/GUI/browsewnd.c @@ -9,18 +9,16 @@ #include -#define DLL_SEARCH_DIR L"\\Debug\\testlibs\\*" +#define EXE_SEARCH_DIR L"\\Debug\\testexes\\*" #define IL_MAIN 0 #define IL_TEST 1 #define HAS_NO_CHILD 0 #define HAS_CHILD 1 -typedef wchar_t *(__cdecl *DLLNAME)(); -typedef int (_cdecl *MODULES)(char **); static INT -GetNumberOfDllsInFolder(LPWSTR lpFolder) +GetNumberOfExesInFolder(LPWSTR lpFolder) { HANDLE hFind; WIN32_FIND_DATAW findFileData; @@ -46,52 +44,52 @@ GetNumberOfDllsInFolder(LPWSTR lpFolder) } static INT -GetListOfTestDlls(PMAIN_WND_INFO pInfo) +GetListOfTestExes(PMAIN_WND_INFO pInfo) { HANDLE hFind; WIN32_FIND_DATAW findFileData; - WCHAR szDllPath[MAX_PATH]; + WCHAR szExePath[MAX_PATH]; LPWSTR ptr; INT numFiles = 0; INT len; - len = GetCurrentDirectory(MAX_PATH, szDllPath); + len = GetCurrentDirectoryW(MAX_PATH, szExePath); if (!len) return 0; - wcsncat(szDllPath, DLL_SEARCH_DIR, MAX_PATH - (len + 1)); + wcsncat(szExePath, EXE_SEARCH_DIR, MAX_PATH - (len + 1)); - numFiles = GetNumberOfDllsInFolder(szDllPath); + numFiles = GetNumberOfExesInFolder(szExePath); if (!numFiles) return 0; - pInfo->lpDllList = HeapAlloc(GetProcessHeap(), + pInfo->lpExeList = HeapAlloc(GetProcessHeap(), 0, numFiles * (MAX_PATH * sizeof(WCHAR))); - if (!pInfo->lpDllList) + if (!pInfo->lpExeList) return 0; - hFind = FindFirstFileW(szDllPath, + hFind = FindFirstFileW(szExePath, &findFileData); if (hFind == INVALID_HANDLE_VALUE) { DisplayError(GetLastError()); - HeapFree(GetProcessHeap(), 0, pInfo->lpDllList); + HeapFree(GetProcessHeap(), 0, pInfo->lpExeList); return 0; } /* remove the glob */ - ptr = wcschr(szDllPath, L'*'); + ptr = wcschr(szExePath, L'*'); if (ptr) *ptr = L'\0'; - /* don't mod our base pointer */ - ptr = pInfo->lpDllList; + /* don't modify our base pointer */ + ptr = pInfo->lpExeList; do { if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { /* set the path */ - wcscpy(ptr, szDllPath); + wcscpy(ptr, szExePath); /* tag the file onto the path */ len = MAX_PATH - (wcslen(ptr) + 1); @@ -207,8 +205,8 @@ InsertIntoTreeView(HWND hTreeView, } static PTEST_ITEM -BuildTestItemData(LPWSTR lpDll, - LPWSTR lpRun) +BuildTestItemData(LPWSTR lpName, + LPWSTR lpRunCmd) { PTEST_ITEM pItem; @@ -217,10 +215,14 @@ BuildTestItemData(LPWSTR lpDll, sizeof(TEST_ITEM)); if (pItem) { - if (lpDll) - wcsncpy(pItem->szSelectedDll, lpDll, MAX_PATH); - if (lpRun) - wcsncpy(pItem->szRunString, lpRun, MAX_RUN_CMD); + if (lpName) + { + wcsncpy(pItem->szName, lpName, MAX_PATH); + } + if (lpRunCmd) + { + wcsncpy(pItem->szRunCmd, lpRunCmd, MAX_RUN_CMD); + } } return pItem; @@ -232,12 +234,9 @@ PopulateTreeView(PMAIN_WND_INFO pInfo) HTREEITEM hRoot; HIMAGELIST hImgList; PTEST_ITEM pTestItem; - DLLNAME GetTestName; - MODULES GetModulesInTest; - HMODULE hDll; - LPWSTR lpDllPath; + LPWSTR lpExePath; LPWSTR lpTestName; - INT RootImage, i; + INT i; pInfo->hBrowseTV = GetDlgItem(pInfo->hBrowseDlg, IDC_TREEVIEW); @@ -253,84 +252,44 @@ PopulateTreeView(PMAIN_WND_INFO pInfo) hImgList, TVSIL_NORMAL); - pTestItem = BuildTestItemData(L"", L"Full"); + pTestItem = BuildTestItemData(L"Full", L"runall"); /* insert the root item into the tree */ hRoot = InsertIntoTreeView(pInfo->hBrowseTV, NULL, L"Full", - pTestItem, + (LPARAM)pTestItem, IL_MAIN, HAS_CHILD); - for (i = 0; i < pInfo->numDlls; i++) + for (i = 0; i < pInfo->numExes; i++) { - lpDllPath = pInfo->lpDllList + (MAX_PATH * i); + HTREEITEM hParent; + LPWSTR lpStr; - hDll = LoadLibraryW(lpDllPath); - if (hDll) + lpExePath = pInfo->lpExeList + (MAX_PATH * i); + + lpTestName = wcsrchr(lpExePath, L'\\'); + if (lpTestName) { - GetTestName = (DLLNAME)GetProcAddress(hDll, "GetTestName"); - if (GetTestName) + lpTestName++; + + lpStr = wcschr(lpTestName, L'_'); + if (lpStr) { - HTREEITEM hParent; - LPSTR lpModules, ptr; - LPWSTR lpModW; - INT numMods; + //FIXME: Query the test name from the exe directly - lpTestName = GetTestName(); - - pTestItem = BuildTestItemData(lpDllPath, lpTestName); + pTestItem = BuildTestItemData(lpTestName, lpExePath); hParent = InsertIntoTreeView(pInfo->hBrowseTV, hRoot, lpTestName, - pTestItem, + (LPARAM)pTestItem, IL_TEST, HAS_CHILD); - if (hParent) - { - /* Get the list of modules a dll offers. This is returned as list of - * Ansi null-terminated strings, terminated with an empty string (double null) */ - GetModulesInTest = (MODULES)GetProcAddress(hDll, "GetModulesInTest"); - if ((numMods = GetModulesInTest(&lpModules))) - { - ptr = lpModules; - while (numMods && *ptr != '\0') - { - /* convert the string to unicode */ - if (AnsiToUnicode(ptr, &lpModW)) - { - WCHAR szRunCmd[MAX_RUN_CMD]; - - _snwprintf(szRunCmd, MAX_RUN_CMD, L"%s:%s", lpTestName, lpModW); - pTestItem = BuildTestItemData(lpDllPath, szRunCmd); - - InsertIntoTreeView(pInfo->hBrowseTV, - hParent, - lpModW, - pTestItem, - IL_TEST, - HAS_NO_CHILD); - - HeapFree(GetProcessHeap(), 0, lpModW); } - - /* move onto next string */ - while (*(ptr++) != '\0') - ; - - numMods--; } - - HeapFree(GetProcessHeap(), 0, lpModules); } - } - } - - FreeLibrary(hDll); - } - } if (hRoot) { @@ -343,8 +302,8 @@ PopulateTreeView(PMAIN_WND_INFO pInfo) static VOID PopulateTestList(PMAIN_WND_INFO pInfo) { - pInfo->numDlls = GetListOfTestDlls(pInfo); - if (pInfo->numDlls) + pInfo->numExes = GetListOfTestExes(pInfo); + if (pInfo->numExes) { PopulateTreeView(pInfo); } @@ -417,16 +376,17 @@ BrowseDlgProc(HWND hDlg, DisplayMessage(L"Please select an item"); } - break; + return TRUE; } case IDCANCEL: { - HeapFree(GetProcessHeap(), 0, pInfo->lpDllList); - pInfo->lpDllList = NULL; + HeapFree(GetProcessHeap(), 0, pInfo->lpExeList); + pInfo->lpExeList = NULL; EndDialog(hDlg, LOWORD(wParam)); + return TRUE; } } diff --git a/rostests/winetests/GUI/lang/en-US.rc b/rostests/winetests/GUI/lang/en-US.rc index 3b2578cb931..68d6cb1ef89 100644 --- a/rostests/winetests/GUI/lang/en-US.rc +++ b/rostests/winetests/GUI/lang/en-US.rc @@ -8,7 +8,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,236,241,50,14,WS_GROUP CONTROL "",IDC_LIST,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,69,279,103 EDITTEXT IDC_OUTPUT,7,175,279,62,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY - COMBOBOX IDC_TESTSELECTION,27,12,205,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_TESTSELECTION,27,12,205,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Test:",IDC_STATIC,6,14,18,8 PUSHBUTTON "Browse...",IDC_BROWSE,236,11,50,14 PUSHBUTTON "Run",IDC_RUN,236,30,50,14 @@ -19,8 +19,9 @@ BEGIN LTEXT "?",IDC_NUMERRORS,85,53,8,8 LTEXT "Failures:",IDC_STATIC,107,53,28,8 LTEXT "?",IDC_NUMFAILURES,141,53,8,8 + PUSHBUTTON "Options",IDC_OPTIONS,181,49,50,14 PUSHBUTTON "Stop",IDC_STOP,236,49,50,14 - CONTROL "Run on start",IDC_RUNONSTART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,174,52,56,10 + LTEXT "status bar",IDC_STATUS,7,244,210,8 END @@ -33,3 +34,14 @@ BEGIN PUSHBUTTON "Close", IDCANCEL, 202, 34, 50, 14 CONTROL "", IDC_TREEVIEW, "SysTreeView32", WS_BORDER | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT, 7, 7, 189, 236 END + +IDD_OPTIONS DIALOGEX 0, 0, 180, 100 +STYLE DS_SHELLFONT | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_MODALFRAME +CAPTION "Options" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + PUSHBUTTON "OK", IDOK, 70, 80, 50, 14 + PUSHBUTTON "Cancel", IDCANCEL, 125, 80, 50, 14 + CONTROL "Hide console window",IDC_HIDECONSOLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,10,80,10 + CONTROL "Run on start",IDC_RUNONSTART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,30,80,10 +END diff --git a/rostests/winetests/GUI/mainwnd.c b/rostests/winetests/GUI/mainwnd.c index 485de7ab60b..fc2f6ef431d 100644 --- a/rostests/winetests/GUI/mainwnd.c +++ b/rostests/winetests/GUI/mainwnd.c @@ -8,17 +8,143 @@ */ #include +#include + +#define BUFSIZE 4096 HINSTANCE hInstance; +WCHAR szPipeName[] = L"\\\\.\\pipe\\winetest_pipe"; + typedef int (_cdecl *RUNTEST)(char **); +DWORD WINAPI +PipeReadThread(LPVOID lpParam) +{ + PMAIN_WND_INFO pInfo; + HWND hList, hEdit; + DWORD dwRead; + CHAR chBuf[BUFSIZE]; + BOOL bSuccess = FALSE; + LVITEMA item; + INT count; + + pInfo = (PMAIN_WND_INFO)lpParam; + + hList = GetDlgItem(pInfo->hMainWnd, IDC_LIST); + hEdit = GetDlgItem(pInfo->hMainWnd, IDC_OUTPUT); + + ZeroMemory(&item, sizeof(LVITEMA)); + item.mask = LVIF_TEXT; + + while (TRUE) + { + dwRead = 0; + bSuccess = ReadFile(pInfo->hStdOutRd, + chBuf, + BUFSIZE, + &dwRead, + NULL); + if(!bSuccess || dwRead == 0) + break; + + chBuf[dwRead] = 0; + + count = GetWindowTextLengthA(hEdit); + SendMessageA(hEdit, EM_SETSEL, (WPARAM)count, (LPARAM)count); + SendMessageA(hEdit, EM_REPLACESEL, 0, (LPARAM)chBuf); + + //item.iItem = ListView_GetItemCount(hList); + //item.pszText = chBuf; + //SendMessage(hEdit, LVM_INSERTITEMA, 0, (LPARAM)&item); + } + + return 0; +} + + +DWORD WINAPI +CreateClientProcess(PMAIN_WND_INFO pInfo) +{ + SECURITY_ATTRIBUTES sa; + STARTUPINFO si; + PROCESS_INFORMATION pi; + BOOL bSuccess = FALSE; + + // + // Set up the security attributes + // + sa.nLength= sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + // + // Create a pipe for the child process's STDOUT + // + if (!CreatePipe(&pInfo->hStdOutRd, + &pInfo->hStdOutWr, + &sa, + 0)) + { + return FALSE; + } + + // + // Ensure the read handle to the pipe for STDOUT is not inherited + // + if (!SetHandleInformation(pInfo->hStdOutRd, + HANDLE_FLAG_INHERIT, + 0)) + { + return FALSE; + } + + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.hStdError = pInfo->hStdOutWr; + si.hStdOutput = pInfo->hStdOutWr; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + + bSuccess = CreateProcessW(pInfo->lpCmdLine, + NULL, + NULL, + NULL, + TRUE, + 0,//CREATE_SUSPENDED, + NULL, + NULL, + &si, + &pi); + if (bSuccess) + { + // + // Create thread to handle pipe input from child processes + // + pInfo->hPipeThread = CreateThread(NULL, + 0, + PipeReadThread, + pInfo, + 0, + NULL); + + WaitForSingleObject(pi.hProcess, INFINITE); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + return bSuccess; +} + + static BOOL OnInitMainDialog(HWND hDlg, LPARAM lParam) { PMAIN_WND_INFO pInfo; - LPWSTR lpAboutText; pInfo = (PMAIN_WND_INFO)lParam; @@ -65,8 +191,7 @@ RunSelectedTest(PMAIN_WND_INFO pInfo) { HWND hRunCmd; WCHAR szTextCmd[MAX_RUN_CMD]; - LPWSTR lpDllPath; - INT sel, len; + INT sel; hRunCmd = GetDlgItem(pInfo->hMainWnd, IDC_TESTSELECTION); @@ -79,54 +204,34 @@ RunSelectedTest(PMAIN_WND_INFO pInfo) if (SendMessageW(hRunCmd, CB_GETLBTEXT, sel, - szTextCmd) != CB_ERR) + (LPARAM)szTextCmd) != CB_ERR) { - lpDllPath = SendMessage(hRunCmd, + pInfo->lpCmdLine = (LPWSTR)SendMessage(hRunCmd, CB_GETITEMDATA, 0, 0); - if (lpDllPath) + if (pInfo->lpCmdLine) { - LPWSTR module = szTextCmd; - LPSTR lpTest; - - while (*(module++) != L':' && *module != L'\0') - ; - - if (*module) - { - if (UnicodeToAnsi(module, &lpTest)) - { - HMODULE hDll; - RUNTEST RunTest; - - hDll = LoadLibraryW(lpDllPath); - if (hDll) - { - RunTest = (RUNTEST)GetProcAddress(hDll, "RunTest"); - if (RunTest) - { - RunTest(lpTest); + // + // Create a new thread to create the client process + // and recieve any ouput via stdout + // + CreateThread(NULL, + 0, + CreateClientProcess, + pInfo, + 0, + NULL); } - - FreeLibrary(hDll); } - DisplayError(GetLastError()); - - HeapFree(GetProcessHeap(), 0, lpTest); } } - } - } - } -} - static VOID AddTestToCombo(PMAIN_WND_INFO pInfo) { HWND hRunCmd; - LPWSTR lpDllPath; + LPWSTR lpExePath; INT len; hRunCmd = GetDlgItem(pInfo->hMainWnd, IDC_TESTSELECTION); @@ -135,21 +240,21 @@ AddTestToCombo(PMAIN_WND_INFO pInfo) SendMessageW(hRunCmd, CB_INSERTSTRING, 0, - pInfo->SelectedTest.szRunString); + (LPARAM)pInfo->SelectedTest.szName); - len = (wcslen(pInfo->SelectedTest.szSelectedDll) + 1) * sizeof(WCHAR); - lpDllPath = HeapAlloc(GetProcessHeap(), 0, len); - if (lpDllPath) + len = (wcslen(pInfo->SelectedTest.szRunCmd) + 1) * sizeof(WCHAR); + lpExePath = HeapAlloc(GetProcessHeap(), 0, len); + if (lpExePath) { - wcsncpy(lpDllPath, - pInfo->SelectedTest.szSelectedDll, + wcsncpy(lpExePath, + pInfo->SelectedTest.szRunCmd, len / sizeof(WCHAR)); } SendMessageW(hRunCmd, CB_SETITEMDATA, 0, - lpDllPath); + (LPARAM)lpExePath); SendMessageW(hRunCmd, CB_SETCURSEL, 0, @@ -161,8 +266,7 @@ static VOID FreeTestCmdStrings(PMAIN_WND_INFO pInfo) { HWND hRunCmd; - WCHAR szTextCmd[MAX_RUN_CMD]; - LPWSTR lpDllPath; + LPWSTR lpExePath; INT cnt, i; hRunCmd = GetDlgItem(pInfo->hMainWnd, IDC_TESTSELECTION); @@ -175,13 +279,13 @@ FreeTestCmdStrings(PMAIN_WND_INFO pInfo) { for (i = 0; i < cnt; i++) { - lpDllPath = SendMessage(hRunCmd, + lpExePath = (LPWSTR)SendMessage(hRunCmd, CB_GETITEMDATA, i, 0); - if (lpDllPath) + if (lpExePath) { - HeapFree(GetProcessHeap(), 0, lpDllPath); + HeapFree(GetProcessHeap(), 0, lpExePath); } } } @@ -228,6 +332,13 @@ MainDlgProc(HWND hDlg, break; } + case IDC_OPTIONS: + DialogBoxParamW(hInstance, + MAKEINTRESOURCEW(IDD_OPTIONS), + hDlg, + (DLGPROC)OptionsDlgProc, + (LPARAM)pInfo); + break; case IDC_RUN: RunSelectedTest(pInfo); @@ -271,7 +382,11 @@ wWinMain(HINSTANCE hInst, { INITCOMMONCONTROLSEX iccx; PMAIN_WND_INFO pInfo; - INT Ret = 1; + INT Ret = -1; + + UNREFERENCED_PARAMETER(hPrev); + UNREFERENCED_PARAMETER(Cmd); + UNREFERENCED_PARAMETER(iCmd); hInstance = hInst; @@ -280,7 +395,9 @@ wWinMain(HINSTANCE hInst, iccx.dwICC = ICC_TAB_CLASSES; InitCommonControlsEx(&iccx); - pInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(MAIN_WND_INFO)); + pInfo = HeapAlloc(GetProcessHeap(), + 0, + sizeof(MAIN_WND_INFO)); if (pInfo) { Ret = (DialogBoxParamW(hInstance, @@ -289,8 +406,9 @@ wWinMain(HINSTANCE hInst, (DLGPROC)MainDlgProc, (LPARAM)pInfo) == IDOK); - HeapFree(GetProcessHeap(), 0, pInfo); - + HeapFree(GetProcessHeap(), + 0, + pInfo); } return Ret; diff --git a/rostests/winetests/GUI/misc.c b/rostests/winetests/GUI/misc.c index a77db7ff210..f197174a386 100644 --- a/rostests/winetests/GUI/misc.c +++ b/rostests/winetests/GUI/misc.c @@ -238,7 +238,7 @@ InitImageList(UINT StartResource, /* Add all icons to the image list */ for (i = StartResource; i <= EndResource; i++) { - hIcon = (HBITMAP)LoadImageW(hInstance, + hIcon = (HICON)LoadImageW(hInstance, MAKEINTRESOURCEW(i), IMAGE_ICON, Width, @@ -294,7 +294,7 @@ UnicodeToAnsi(LPCWSTR lpSrcStr, length = wcslen(lpSrcStr) + 1; - *lpDstStr = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, length); + *lpDstStr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, length); if (*lpDstStr) { ret = WideCharToMultiByte(CP_ACP, diff --git a/rostests/winetests/GUI/optionswnd.c b/rostests/winetests/GUI/optionswnd.c new file mode 100644 index 00000000000..be5c01b47ee --- /dev/null +++ b/rostests/winetests/GUI/optionswnd.c @@ -0,0 +1,100 @@ +/* + * PROJECT: ReactOS API Test GUI + * LICENSE: GPL - See COPYING in the top level directory + * FILE: + * PURPOSE: options dialog implementation + * COPYRIGHT: Copyright 2008 Ged Murphy + * + */ + +#include + +static BOOL +OnInitBrowseDialog(HWND hDlg, + LPARAM lParam) +{ + PMAIN_WND_INFO pInfo; + + pInfo = (PMAIN_WND_INFO)lParam; + + pInfo->hBrowseDlg = hDlg; + + SetWindowLongPtr(hDlg, + GWLP_USERDATA, + (LONG_PTR)pInfo); + + return TRUE; +} + + +BOOL CALLBACK +OptionsDlgProc(HWND hDlg, + UINT Message, + WPARAM wParam, + LPARAM lParam) +{ + PMAIN_WND_INFO pInfo; + + //UNREFERENCED_PARAM( + + /* Get the window context */ + pInfo = (PMAIN_WND_INFO)GetWindowLongPtr(hDlg, + GWLP_USERDATA); + if (pInfo == NULL && Message != WM_INITDIALOG) + { + goto HandleDefaultMessage; + } + + switch(Message) + { + case WM_INITDIALOG: + return OnInitBrowseDialog(hDlg, lParam); + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK: + { + if (SendMessageW(GetDlgItem(hDlg, IDC_RUNONSTART), BM_GETCHECK, 0, 0) == BST_CHECKED) + { + pInfo->bRunOnStart = TRUE; + } + else + { + pInfo->bRunOnStart = FALSE; + } + + if (SendMessageW(GetDlgItem(hDlg, IDC_HIDECONSOLE), BM_GETCHECK, 0, 0) == BST_CHECKED) + { + pInfo->bHideConsole = TRUE; + } + else + { + pInfo->bHideConsole = FALSE; + } + + EndDialog(hDlg, + LOWORD(wParam)); + + return TRUE; + } + + case IDCANCEL: + { + EndDialog(hDlg, + LOWORD(wParam)); + + return TRUE; + } + } + + break; + } +HandleDefaultMessage: + default: + return FALSE; + } + + return FALSE; +} diff --git a/rostests/winetests/GUI/precomp.h b/rostests/winetests/GUI/precomp.h index 900276f4cb5..5164e5663a4 100644 --- a/rostests/winetests/GUI/precomp.h +++ b/rostests/winetests/GUI/precomp.h @@ -9,12 +9,13 @@ extern HINSTANCE hInstance; +#define MAX_NAME 32 #define MAX_RUN_CMD 256 typedef struct _TEST_ITEM { - WCHAR szSelectedDll[MAX_PATH]; - WCHAR szRunString[MAX_RUN_CMD]; + WCHAR szName[MAX_NAME]; + WCHAR szRunCmd[MAX_RUN_CMD]; } TEST_ITEM, *PTEST_ITEM; @@ -24,16 +25,23 @@ typedef struct _MAIN_WND_INFO HWND hBrowseDlg; HWND hBrowseTV; HWND hStatus; + HANDLE hPipeThread; + HANDLE hStdOutRd; + HANDLE hStdOutWr; + LPWSTR lpCmdLine; int nCmdShow; HICON hSmIcon; HICON hBgIcon; - LPWSTR lpDllList; - INT numDlls; + LPWSTR lpExeList; + INT numExes; TEST_ITEM SelectedTest; + BOOL bRunOnStart; + BOOL bHideConsole; + } MAIN_WND_INFO, *PMAIN_WND_INFO; /* dll exports */ @@ -42,9 +50,15 @@ int GetModulesInTest(char **modules); int RunTest(const char *lpTest); +/* mainwnd.c */ +BOOL SendCommandToClient(PMAIN_WND_INFO pInfo, LPWSTR lpCommand); + /* browsewnd.c */ BOOL CALLBACK BrowseDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam); +/* optionswnd.c */ +BOOL CALLBACK OptionsDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam); + /* misc.c */ HIMAGELIST InitImageList(UINT StartResource, UINT EndResource, UINT Width, UINT Height); VOID DisplayMessage(LPWSTR lpMsg); diff --git a/rostests/winetests/GUI/resource.h b/rostests/winetests/GUI/resource.h index e206fbcb082..5a0994cb045 100644 --- a/rostests/winetests/GUI/resource.h +++ b/rostests/winetests/GUI/resource.h @@ -1,6 +1,7 @@ #define IDD_WINETESTGUI 102 #define IDD_TESTBROWSER 103 -#define IDM_ABOUT 104 +#define IDD_OPTIONS 104 +//#define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDI_ICON 107 #define IDI_TESTS 108 @@ -16,9 +17,12 @@ #define IDC_NUMERRORS 1007 #define IDC_NUMFAILURES 1008 #define IDC_STOP 1010 -#define IDC_CHECK2 1011 -#define IDC_RUNONSTART 1011 +#define IDC_OPTIONS 1011 +#define IDC_SELECT 1013 +#define IDC_TREEVIEW 1014 + +#define IDC_HIDECONSOLE 1020 +#define IDC_RUNONSTART 1021 #define IDC_STATUS 1012 -#define IDC_SELECT 1020 -#define IDC_TREEVIEW 1021 + #define IDC_STATIC -1 diff --git a/rostests/winetests/advapi32/advapi32.rbuild b/rostests/winetests/advapi32/advapi32.rbuild index 7a056f0908e..2b5b5df8e54 100644 --- a/rostests/winetests/advapi32/advapi32.rbuild +++ b/rostests/winetests/advapi32/advapi32.rbuild @@ -1,11 +1,9 @@ - . - + advapi32 - kernel32 ntdll uuid ole32 @@ -21,4 +19,3 @@ service.c testlist.c - diff --git a/rostests/winetests/advapi32/cred.c b/rostests/winetests/advapi32/cred.c index 6d7b758c195..6b7fa26654b 100644 --- a/rostests/winetests/advapi32/cred.c +++ b/rostests/winetests/advapi32/cred.c @@ -34,6 +34,8 @@ static BOOL (WINAPI *pCredGetSessionTypes)(DWORD,LPDWORD); static BOOL (WINAPI *pCredReadA)(LPCSTR,DWORD,DWORD,PCREDENTIALA *); static BOOL (WINAPI *pCredRenameA)(LPCSTR,LPCSTR,DWORD,DWORD); static BOOL (WINAPI *pCredWriteA)(PCREDENTIALA,DWORD); +static BOOL (WINAPI *pCredReadDomainCredentialsA)(PCREDENTIAL_TARGET_INFORMATIONA,DWORD,DWORD*,PCREDENTIALA**); + #define TEST_TARGET_NAME "credtest.winehq.org" #define TEST_TARGET_NAME2 "credtest2.winehq.org" @@ -97,8 +99,19 @@ static void test_CredWriteA(void) SetLastError(0xdeadbeef); ret = pCredWriteA(&new_cred, 0); - ok(!ret && ( GetLastError() == ERROR_BAD_USERNAME || GetLastError() == ERROR_NO_SUCH_LOGON_SESSION /* Vista */ ), - "CredWrite with username without domain should return ERROR_BAD_USERNAME or ERROR_NO_SUCH_LOGON_SESSION not %d\n", GetLastError()); + if (ret) + { + ok(GetLastError() == ERROR_SUCCESS || + GetLastError() == ERROR_IO_PENDING, /* Vista */ + "Expected ERROR_IO_PENDING, got %d\n", GetLastError()); + } + else + { + ok(GetLastError() == ERROR_BAD_USERNAME || + GetLastError() == ERROR_NO_SUCH_LOGON_SESSION, /* Vista */ + "CredWrite with username without domain should return ERROR_BAD_USERNAME" + "or ERROR_NO_SUCH_LOGON_SESSION not %d\n", GetLastError()); + } new_cred.UserName = NULL; SetLastError(0xdeadbeef); @@ -125,6 +138,66 @@ static void test_CredDeleteA(void) GetLastError()); } +static void test_CredReadDomainCredentialsA(void) +{ + BOOL ret; + char target_name[] = "no_such_target"; + CREDENTIAL_TARGET_INFORMATIONA info = {target_name, NULL, target_name, NULL, NULL, NULL, NULL, 0, 0, NULL}; + DWORD count; + PCREDENTIAL* creds; + + if (!pCredReadDomainCredentialsA) + { + win_skip("CredReadDomainCredentialsA() is not implemented\n"); + return; + } + + /* these two tests would crash on both native and Wine. Implementations + * does not check for NULL output pointers and try to zero them out early */ +if(0) +{ + ok(!pCredReadDomainCredentialsA(&info, 0, NULL, &creds) && + GetLastError() == ERROR_INVALID_PARAMETER, "!\n"); + ok(!pCredReadDomainCredentialsA(&info, 0, &count, NULL) && + GetLastError() == ERROR_INVALID_PARAMETER, "!\n"); +} + + SetLastError(0xdeadbeef); + ret = pCredReadDomainCredentialsA(NULL, 0, &count, &creds); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "CredReadDomainCredentialsA should have failed with ERROR_INVALID_PARAMETER instead of %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + creds = (void*)0x12345; + count = 2; + ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds); + ok(!ret && GetLastError() == ERROR_NOT_FOUND, + "CredReadDomainCredentialsA should have failed with ERROR_NOT_FOUND instead of %d\n", + GetLastError()); + ok(count ==0 && creds == NULL, "CredReadDomainCredentialsA must not return any result\n"); + + info.TargetName = NULL; + + SetLastError(0xdeadbeef); + ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds); + ok(!ret, "CredReadDomainCredentialsA should have failed\n"); + ok(GetLastError() == ERROR_NOT_FOUND || + GetLastError() == ERROR_INVALID_PARAMETER, /* Vista, W2K8 */ + "Expected ERROR_NOT_FOUND or ERROR_INVALID_PARAMETER instead of %d\n", + GetLastError()); + + info.DnsServerName = NULL; + + SetLastError(0xdeadbeef); + ret = pCredReadDomainCredentialsA(&info, 0, &count, &creds); + ok(!ret, "CredReadDomainCredentialsA should have failed\n"); + ok(GetLastError() == ERROR_NOT_FOUND || + GetLastError() == ERROR_INVALID_PARAMETER, /* Vista, W2K8 */ + "Expected ERROR_NOT_FOUND or ERROR_INVALID_PARAMETER instead of %d\n", + GetLastError()); +} + static void check_blob(int line, DWORD cred_type, PCREDENTIALA cred) { if (cred_type == CRED_TYPE_DOMAIN_PASSWORD) @@ -166,7 +239,13 @@ static void test_generic(void) new_cred.UserName = (char *)"winetest"; ret = pCredWriteA(&new_cred, 0); - ok(ret, "CredWriteA failed with error %d\n", GetLastError()); + ok(ret || broken(GetLastError() == ERROR_NO_SUCH_LOGON_SESSION), + "CredWriteA failed with error %d\n", GetLastError()); + if (!ret) + { + skip("couldn't write generic credentials, skipping tests\n"); + return; + } ret = pCredEnumerateA(NULL, 0, &count, &creds); ok(ret, "CredEnumerateA failed with error %d\n", GetLastError()); @@ -175,10 +254,12 @@ static void test_generic(void) { if (!strcmp(creds[i]->TargetName, TEST_TARGET_NAME)) { - ok(creds[i]->Type == CRED_TYPE_GENERIC, "expected creds[%d]->Type CRED_TYPE_GENERIC but got %d\n", i, creds[i]->Type); + ok(creds[i]->Type == CRED_TYPE_GENERIC || + creds[i]->Type == CRED_TYPE_DOMAIN_PASSWORD, /* Vista */ + "expected creds[%d]->Type CRED_TYPE_GENERIC or CRED_TYPE_DOMAIN_PASSWORD but got %d\n", i, creds[i]->Type); ok(!creds[i]->Flags, "expected creds[%d]->Flags 0 but got 0x%x\n", i, creds[i]->Flags); ok(!strcmp(creds[i]->Comment, "Comment"), "expected creds[%d]->Comment \"Comment\" but got \"%s\"\n", i, creds[i]->Comment); - check_blob(__LINE__, CRED_TYPE_GENERIC, creds[i]); + check_blob(__LINE__, creds[i]->Type, creds[i]); ok(creds[i]->Persist, "expected creds[%d]->Persist CRED_PERSIST_ENTERPRISE but got %d\n", i, creds[i]->Persist); ok(!strcmp(creds[i]->UserName, "winetest"), "expected creds[%d]->UserName \"winetest\" but got \"%s\"\n", i, creds[i]->UserName); found = TRUE; @@ -216,6 +297,12 @@ static void test_domain_password(DWORD cred_type) new_cred.TargetAlias = NULL; new_cred.UserName = (char *)"test\\winetest"; ret = pCredWriteA(&new_cred, 0); + if (!ret && GetLastError() == ERROR_NO_SUCH_LOGON_SESSION) + { + skip("CRED_TYPE_DOMAIN_PASSWORD credentials are not supported " + "or are disabled. Skipping\n"); + return; + } ok(ret, "CredWriteA failed with error %d\n", GetLastError()); ret = pCredEnumerateA(NULL, 0, &count, &creds); @@ -260,11 +347,12 @@ START_TEST(cred) pCredDeleteA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredDeleteA"); pCredReadA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredReadA"); pCredRenameA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredRenameA"); + pCredReadDomainCredentialsA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredReadDomainCredentialsA"); if (!pCredEnumerateA || !pCredFree || !pCredWriteA || !pCredDeleteA || !pCredReadA) { - skip("credentials functions not present in advapi32.dll\n"); + win_skip("credentials functions not present in advapi32.dll\n"); return; } @@ -285,6 +373,8 @@ START_TEST(cred) test_CredWriteA(); test_CredDeleteA(); + test_CredReadDomainCredentialsA(); + trace("generic:\n"); if (persists[CRED_TYPE_GENERIC] == CRED_PERSIST_NONE) skip("CRED_TYPE_GENERIC credentials are not supported or are disabled. Skipping\n"); diff --git a/rostests/winetests/advapi32/crypt.c b/rostests/winetests/advapi32/crypt.c index 8ad2b6b258c..f291ae51a0b 100644 --- a/rostests/winetests/advapi32/crypt.c +++ b/rostests/winetests/advapi32/crypt.c @@ -274,11 +274,11 @@ static void test_incorrect_api_usage(void) ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError()); dwLen = 1; - result = pCryptDecrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, &temp, &dwLen); + result = pCryptDecrypt(hKey, 0, TRUE, 0, &temp, &dwLen); ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError()); dwLen = 1; - result = pCryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, &temp, &dwLen, 1); + result = pCryptEncrypt(hKey, 0, TRUE, 0, &temp, &dwLen, 1); ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError()); result = pCryptDeriveKey(hProv, CALG_RC4, hHash, 0, &hKey2); @@ -293,7 +293,7 @@ static void test_incorrect_api_usage(void) #endif dwLen = 1; - result = pCryptExportKey(hKey, (HCRYPTPROV)NULL, 0, 0, &temp, &dwLen); + result = pCryptExportKey(hKey, 0, 0, 0, &temp, &dwLen); ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError()); result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey2); @@ -320,7 +320,7 @@ static void test_incorrect_api_usage(void) result = pCryptHashSessionKey(hHash, hKey, 0); ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError()); - result = pCryptImportKey(hProv, &temp, 1, (HCRYPTKEY)NULL, 0, &hKey2); + result = pCryptImportKey(hProv, &temp, 1, 0, 0, &hKey2); ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError()); if (pCryptSignHashW) @@ -331,7 +331,7 @@ static void test_incorrect_api_usage(void) GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), "%d\n", GetLastError()); } else - skip("CryptSignHashW is not available\n"); + win_skip("CryptSignHashW is not available\n"); result = pCryptSetKeyParam(hKey, 0, &temp, 1); ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError()); @@ -349,7 +349,7 @@ static void test_incorrect_api_usage(void) GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), "%d\n", GetLastError()); } else - skip("CryptVerifySignatureW is not available\n"); + win_skip("CryptVerifySignatureW is not available\n"); result = pCryptDestroyHash(hHash); ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError()); @@ -394,7 +394,7 @@ static void test_verify_sig(void) if (!pCryptVerifySignatureW) { - skip("CryptVerifySignatureW is not available\n"); + win_skip("CryptVerifySignatureW is not available\n"); return; } @@ -402,7 +402,7 @@ static void test_verify_sig(void) ret = pCryptVerifySignatureW(0, NULL, 0, 0, NULL, 0); if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("CryptVerifySignatureW is not implemented\n"); + win_skip("CryptVerifySignatureW is not implemented\n"); return; } ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, @@ -462,7 +462,7 @@ static BOOL FindProvRegVals(DWORD dwIndex, DWORD *pdwProvType, LPSTR *pszProvNam NULL, NULL, NULL, NULL, NULL, NULL); (*pcbProvName)++; - if (!(*pszProvName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, *pcbProvName)))) + if (!(*pszProvName = LocalAlloc(LMEM_ZEROINIT, *pcbProvName))) return FALSE; RegEnumKeyEx(hKey, dwIndex, *pszProvName, pcbProvName, NULL, NULL, NULL, NULL); @@ -497,13 +497,13 @@ static void test_enum_providers(void) if(!pCryptEnumProvidersA) { - skip("CryptEnumProvidersA is not available\n"); + win_skip("CryptEnumProvidersA is not available\n"); return; } if (!FindProvRegVals(dwIndex, &dwType, &pszProvName, &cbName, &provCount)) { - skip("Could not find providers in registry\n"); + win_skip("Could not find providers in registry\n"); return; } @@ -518,7 +518,7 @@ static void test_enum_providers(void) /* alloc provider to half the size required * cbName holds the size required */ providerLen = cbName / 2; - if (!(provider = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, providerLen)))) + if (!(provider = LocalAlloc(LMEM_ZEROINIT, providerLen))) return; result = pCryptEnumProvidersA(dwIndex, NULL, 0, &type, provider, &providerLen); @@ -546,7 +546,7 @@ static void test_enum_providers(void) /* check expected versus actual values returned */ result = pCryptEnumProvidersA(dwIndex, NULL, 0, &type, NULL, &providerLen); ok(result && providerLen==cbName, "expected %i, got %i\n", (int)cbName, (int)providerLen); - if (!(provider = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, providerLen)))) + if (!(provider = LocalAlloc(LMEM_ZEROINIT, providerLen))) return; providerLen = 0xdeadbeef; @@ -560,55 +560,73 @@ static void test_enum_providers(void) LocalFree(provider); } -static BOOL FindProvTypesRegVals(DWORD dwIndex, DWORD *pdwProvType, LPSTR *pszTypeName, +static BOOL FindProvTypesRegVals(DWORD *pdwIndex, DWORD *pdwProvType, LPSTR *pszTypeName, DWORD *pcbTypeName, DWORD *pdwTypeCount) { HKEY hKey; HKEY hSubKey; PSTR ch; + LPSTR szName; + DWORD cbName; + BOOL ret = FALSE; if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\Defaults\\Provider Types", &hKey)) return FALSE; - if (RegQueryInfoKey(hKey, NULL, NULL, NULL, pdwTypeCount, pcbTypeName, NULL, + if (RegQueryInfoKey(hKey, NULL, NULL, NULL, pdwTypeCount, &cbName, NULL, NULL, NULL, NULL, NULL, NULL)) - return FALSE; - (*pcbTypeName)++; + goto cleanup; + cbName++; - if (!(*pszTypeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, *pcbTypeName)))) - return FALSE; + if (!(szName = LocalAlloc(LMEM_ZEROINIT, cbName))) + goto cleanup; - if (RegEnumKeyEx(hKey, dwIndex, *pszTypeName, pcbTypeName, NULL, NULL, NULL, NULL)) - return FALSE; - (*pcbTypeName)++; - ch = *pszTypeName + strlen(*pszTypeName); + while (!RegEnumKeyEx(hKey, *pdwIndex, szName, &cbName, NULL, NULL, NULL, NULL)) + { + cbName++; + ch = szName + strlen(szName); /* Convert "Type 000" to 0, etc/ */ *pdwProvType = *(--ch) - '0'; *pdwProvType += (*(--ch) - '0') * 10; *pdwProvType += (*(--ch) - '0') * 100; - if (RegOpenKey(hKey, *pszTypeName, &hSubKey)) - return FALSE; + if (RegOpenKey(hKey, szName, &hSubKey)) + break; - if (RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, NULL, pcbTypeName)) - return FALSE; + if (!RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, NULL, pcbTypeName)) + { + if (!(*pszTypeName = LocalAlloc(LMEM_ZEROINIT, *pcbTypeName))) + break; - if (!(*pszTypeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, *pcbTypeName)))) - return FALSE; + if (!RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, (LPBYTE)*pszTypeName, pcbTypeName)) + { + ret = TRUE; + break; + } - if (RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, (LPBYTE)*pszTypeName, pcbTypeName)) - return FALSE; + LocalFree(*pszTypeName); + } RegCloseKey(hSubKey); + + (*pdwIndex)++; + } + + if (!ret) + LocalFree(*pszTypeName); + RegCloseKey(hSubKey); + LocalFree(szName); + +cleanup: RegCloseKey(hKey); - return TRUE; + return ret; } static void test_enum_provider_types(void) { /* expected values */ - DWORD dwProvType; + DWORD dwProvType = 0; LPSTR pszTypeName = NULL; DWORD cbTypeName; DWORD dwTypeCount; @@ -625,11 +643,11 @@ static void test_enum_provider_types(void) if(!pCryptEnumProviderTypesA) { - skip("CryptEnumProviderTypesA is not available\n"); + win_skip("CryptEnumProviderTypesA is not available\n"); return; } - if (!FindProvTypesRegVals(index, &dwProvType, &pszTypeName, &cbTypeName, &dwTypeCount)) + if (!FindProvTypesRegVals(&index, &dwProvType, &pszTypeName, &cbTypeName, &dwTypeCount)) { skip("Could not find provider types in registry\n"); return; @@ -637,29 +655,31 @@ static void test_enum_provider_types(void) /* check pdwReserved for NULL */ result = pCryptEnumProviderTypesA(index, ¬Null, 0, &provType, typeName, &typeNameSize); - ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %d\n", - ERROR_INVALID_PARAMETER, GetLastError()); + ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", + GetLastError()); /* check dwFlags == zero */ result = pCryptEnumProviderTypesA(index, NULL, notZeroFlags, &provType, typeName, &typeNameSize); - ok(!result && GetLastError()==NTE_BAD_FLAGS, "expected %i, got %d\n", - ERROR_INVALID_PARAMETER, GetLastError()); + ok(!result && GetLastError()==NTE_BAD_FLAGS, "expected ERROR_INVALID_PARAMETER, got %d\n", + GetLastError()); + /* This test fails under Win2k SP4: + * result = TRUE, GetLastError() == 0xdeadbeef */ + if (0) + { /* alloc provider type to half the size required * cbTypeName holds the size required */ typeNameSize = cbTypeName / 2; - if (!(typeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, typeNameSize)))) - return; + if (!(typeName = LocalAlloc(LMEM_ZEROINIT, typeNameSize))) + goto cleanup; - /* This test fails under Win2k SP4: - result = TRUE, GetLastError() == 0xdeadbeef SetLastError(0xdeadbeef); result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, typeName, &typeNameSize); - ok(!result && GetLastError()==ERROR_MORE_DATA, "expected 0/ERROR_MORE_DATA, got %d/%08lx\n", + ok(!result && GetLastError()==ERROR_MORE_DATA, "expected 0/ERROR_MORE_DATA, got %d/%d\n", result, GetLastError()); - */ LocalFree(typeName); + } /* loop through the provider types to get the number of provider types * after loop ends, count should be dwTypeCount + 1 so subtract 1 @@ -674,15 +694,14 @@ static void test_enum_provider_types(void) * ERROR_NO_MORE_ITEMS */ for (typeCount = 0; typeCount < dwTypeCount + 1; typeCount++) result = pCryptEnumProviderTypesA(typeCount, NULL, 0, &provType, NULL, &typeNameSize); - ok(!result && GetLastError()==ERROR_NO_MORE_ITEMS, "expected %i, got %d\n", - ERROR_NO_MORE_ITEMS, GetLastError()); + ok(!result && GetLastError()==ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %d\n", + GetLastError()); - /* check expected versus actual values returned */ result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, NULL, &typeNameSize); ok(result && typeNameSize==cbTypeName, "expected %d, got %d\n", cbTypeName, typeNameSize); - if (!(typeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, typeNameSize)))) - return; + if (!(typeName = LocalAlloc(LMEM_ZEROINIT, typeNameSize))) + goto cleanup; typeNameSize = 0xdeadbeef; result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, typeName, &typeNameSize); @@ -693,6 +712,8 @@ static void test_enum_provider_types(void) ok(typeNameSize==cbTypeName, "expected %d, got %d\n", cbTypeName, typeNameSize); LocalFree(typeName); +cleanup: + LocalFree(pszTypeName); } static BOOL FindDfltProvRegVals(DWORD dwProvType, DWORD dwFlags, LPSTR *pszProvName, DWORD *pcbProvName) @@ -763,7 +784,7 @@ static void test_get_default_provider(void) if(!pCryptGetDefaultProviderA) { - skip("CryptGetDefaultProviderA is not available\n"); + win_skip("CryptGetDefaultProviderA is not available\n"); return; } @@ -837,7 +858,7 @@ static void test_set_provider_ex(void) if(!pCryptGetDefaultProviderA || !pCryptSetProviderExA) { - skip("CryptGetDefaultProviderA and/or CryptSetProviderExA are not available\n"); + win_skip("CryptGetDefaultProviderA and/or CryptSetProviderExA are not available\n"); return; } @@ -849,12 +870,13 @@ static void test_set_provider_ex(void) /* remove the default provider and then set it to MS_DEF_PROV/PROV_RSA_FULL */ SetLastError(0xdeadbeef); result = pCryptSetProviderExA(MS_DEF_PROV, PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT | CRYPT_DELETE_DEFAULT); - if (!result && (GetLastError() == ERROR_ACCESS_DENIED)) + if (!result) { + ok( GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == ERROR_INVALID_PARAMETER), + "wrong error %u\n", GetLastError() ); skip("Not enough rights to remove the default provider\n"); return; } - ok(result, "%d\n", GetLastError()); result = pCryptSetProviderExA(MS_DEF_PROV, PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT); ok(result, "%d\n", GetLastError()); @@ -903,7 +925,7 @@ static void test_machine_guid(void) /* Create and release a provider */ ret = pCryptAcquireContextA(&hCryptProv, szKeySet, NULL, PROV_RSA_FULL, 0); ok(ret, "CryptAcquireContextA failed: %08x\n", GetLastError()); - CryptReleaseContext(hCryptProv, 0); + pCryptReleaseContext(hCryptProv, 0); if (restoreGuid) RegSetValueExA(key, "MachineGuid", 0, REG_SZ, (const BYTE *)originalGuid, diff --git a/rostests/winetests/advapi32/crypt_lmhash.c b/rostests/winetests/advapi32/crypt_lmhash.c index b90e02ccd15..253090a970e 100644 --- a/rostests/winetests/advapi32/crypt_lmhash.c +++ b/rostests/winetests/advapi32/crypt_lmhash.c @@ -43,8 +43,8 @@ typedef VOID (WINAPI *fnSystemFunction006)( PCSTR passwd, PSTR lmhash ); typedef NTSTATUS (WINAPI *fnSystemFunction008)(const BYTE *, const BYTE *, LPBYTE); typedef NTSTATUS (WINAPI *fnSystemFunction009)(const BYTE *, const BYTE *, LPBYTE); typedef int (WINAPI *descrypt)(unsigned char *, unsigned char *, unsigned char *); -typedef NTSTATUS (WINAPI *fnSystemFunction030)(void*, void*); -typedef NTSTATUS (WINAPI *fnSystemFunction032)(struct ustring *, struct ustring *); +typedef NTSTATUS (WINAPI *fnSystemFunction030)(const void*, const void*); +typedef NTSTATUS (WINAPI *fnSystemFunction032)(struct ustring *, const struct ustring *); fnSystemFunction001 pSystemFunction001; fnSystemFunction002 pSystemFunction002; @@ -259,7 +259,7 @@ static void test_SystemFunction004(void) key.Length = 0x100; key.MaximumLength = 0x100; - r = pSystemFunction004(&in, &key, (struct ustring *)&out); + r = pSystemFunction004(&in, &key, &out); ok(r == STATUS_BUFFER_TOO_SMALL, "function failed\n"); in.Buffer = inbuf; @@ -348,18 +348,24 @@ static void test_SystemFunction005(void) out.Length = 0; out.MaximumLength = 0; r = pSystemFunction005(&out, &key, &res); - ok(r == STATUS_SUCCESS, "function failed\n"); + ok(r == STATUS_SUCCESS || + r == STATUS_INVALID_PARAMETER_1, /* Vista */ + "Expected STATUS_SUCCESS or STATUS_INVALID_PARAMETER_1, got %08x\n", r); ok(res.Length == in.Length, "Length wrong\n"); ok(!memcmp(res.Buffer, in.Buffer, in.Length), "data wrong\n"); res.MaximumLength = 0; r = pSystemFunction005(&out, &key, &res); - ok(r == STATUS_BUFFER_TOO_SMALL, "function failed\n"); + ok(r == STATUS_BUFFER_TOO_SMALL || + r == STATUS_INVALID_PARAMETER_1, /* Vista */ + "Expected STATUS_BUFFER_TOO_SMALL or STATUS_INVALID_PARAMETER_1, got %08x\n", r); key.Length = 1; r = pSystemFunction005(&out, &key, &res); - ok(r == STATUS_UNKNOWN_REVISION, "function failed\n"); + ok(r == STATUS_UNKNOWN_REVISION || + r == STATUS_INVALID_PARAMETER_1, /* Vista */ + "Expected STATUS_UNKNOWN_REVISION or STATUS_INVALID_PARAMETER_1, got %08x\n", r); key.Length = 0; r = pSystemFunction005(&out, &key, &res); @@ -407,7 +413,7 @@ static void test_SystemFunction_encrypt(descrypt func, int num) if (!func) { - skip("SystemFunction%03d is not available\n", num); + win_skip("SystemFunction%03d is not available\n", num); return; } @@ -428,7 +434,7 @@ static void test_SystemFunction_decrypt(descrypt func, int num) if (!func) { - skip("SystemFunction%03d is not available\n", num); + win_skip("SystemFunction%03d is not available\n", num); return; } @@ -454,7 +460,7 @@ static void test_SystemFunction_enc32(descrypt func, int num) if (!func) { - skip("SystemFunction%03d is not available\n", num); + win_skip("SystemFunction%03d is not available\n", num); return; } @@ -476,7 +482,7 @@ static void test_SystemFunction_dec32(descrypt func, int num) if (!func) { - skip("SystemFunction%03d is not available\n", num); + win_skip("SystemFunction%03d is not available\n", num); return; } @@ -498,7 +504,7 @@ static void test_memcmpfunc(memcmpfunc fn) if (!fn) { - skip("function is not available\n"); + win_skip("function is not available\n"); return; } @@ -543,49 +549,49 @@ START_TEST(crypt_lmhash) if (pSystemFunction001) test_SystemFunction001(); else - skip("SystemFunction001 is not available\n"); + win_skip("SystemFunction001 is not available\n"); pSystemFunction002 = (fnSystemFunction002)GetProcAddress( module, "SystemFunction002" ); if (pSystemFunction002) test_SystemFunction002(); else - skip("SystemFunction002 is not available\n"); + win_skip("SystemFunction002 is not available\n"); pSystemFunction003 = (fnSystemFunction003)GetProcAddress( module, "SystemFunction003" ); if (pSystemFunction003) test_SystemFunction003(); else - skip("SystemFunction002 is not available\n"); + win_skip("SystemFunction002 is not available\n"); pSystemFunction004 = (fnSystemFunction004)GetProcAddress( module, "SystemFunction004" ); if (pSystemFunction004) test_SystemFunction004(); else - skip("SystemFunction004 is not available\n"); + win_skip("SystemFunction004 is not available\n"); pSystemFunction005 = (fnSystemFunction005)GetProcAddress( module, "SystemFunction005" ); if (pSystemFunction005) test_SystemFunction005(); else - skip("SystemFunction005 is not available\n"); + win_skip("SystemFunction005 is not available\n"); pSystemFunction006 = (fnSystemFunction006)GetProcAddress( module, "SystemFunction006" ); if (pSystemFunction006) test_SystemFunction006(); else - skip("SystemFunction006 is not available\n"); + win_skip("SystemFunction006 is not available\n"); pSystemFunction008 = (fnSystemFunction008)GetProcAddress( module, "SystemFunction008" ); if (pSystemFunction008) test_SystemFunction008(); else - skip("SystemFunction008 is not available\n"); + win_skip("SystemFunction008 is not available\n"); pSystemFunction009 = (fnSystemFunction009)GetProcAddress( module, "SystemFunction009" ); if (pSystemFunction009) test_SystemFunction009(); else - skip("SystemFunction009 is not available\n"); + win_skip("SystemFunction009 is not available\n"); pSystemFunction012 = (descrypt) GetProcAddress( module, "SystemFunction012"); pSystemFunction013 = (descrypt) GetProcAddress( module, "SystemFunction013"); @@ -639,5 +645,5 @@ START_TEST(crypt_lmhash) if (pSystemFunction032) test_SystemFunction032(); else - skip("SystemFunction032 is not available\n"); + win_skip("SystemFunction032 is not available\n"); } diff --git a/rostests/winetests/advapi32/crypt_md4.c b/rostests/winetests/advapi32/crypt_md4.c index 15a594bf904..e866910d970 100644 --- a/rostests/winetests/advapi32/crypt_md4.c +++ b/rostests/winetests/advapi32/crypt_md4.c @@ -49,7 +49,7 @@ fnSystemFunction007 pSystemFunction007; md4hashfunc pSystemFunction010; md4hashfunc pSystemFunction011; -#define ctxcmp( a, b ) memcmp( (char*)a, (char*)b, FIELD_OFFSET( MD4_CTX, in ) ) +#define ctxcmp( a, b ) memcmp( a, b, FIELD_OFFSET( MD4_CTX, in ) ) static void test_md4_ctx(void) { @@ -156,23 +156,23 @@ START_TEST(crypt_md4) if (pMD4Init && pMD4Update && pMD4Final) test_md4_ctx(); else - skip("MD4Init and/or MD4Update and/or MD4Final are not available\n"); + win_skip("MD4Init and/or MD4Update and/or MD4Final are not available\n"); pSystemFunction007 = (fnSystemFunction007)GetProcAddress( module, "SystemFunction007" ); if (pSystemFunction007) test_SystemFunction007(); else - skip("SystemFunction007 is not available\n"); + win_skip("SystemFunction007 is not available\n"); pSystemFunction010 = (md4hashfunc)GetProcAddress( module, "SystemFunction010" ); if (pSystemFunction010) test_md4hashfunc(pSystemFunction010); else - skip("SystemFunction010 is not available\n"); + win_skip("SystemFunction010 is not available\n"); pSystemFunction011 = (md4hashfunc)GetProcAddress( module, "SystemFunction011" ); if (pSystemFunction011) test_md4hashfunc(pSystemFunction011); else - skip("SystemFunction011 is not available\n"); + win_skip("SystemFunction011 is not available\n"); } diff --git a/rostests/winetests/advapi32/crypt_md5.c b/rostests/winetests/advapi32/crypt_md5.c index 23d7d6bdcaa..9136dfbc28c 100644 --- a/rostests/winetests/advapi32/crypt_md5.c +++ b/rostests/winetests/advapi32/crypt_md5.c @@ -41,7 +41,7 @@ fnMD5Init pMD5Init; fnMD5Update pMD5Update; fnMD5Final pMD5Final; -#define ctxcmp( a, b ) memcmp( (char*)a, (char*)b, FIELD_OFFSET( MD5_CTX, in ) ) +#define ctxcmp( a, b ) memcmp( a, b, FIELD_OFFSET( MD5_CTX, in ) ) static void test_md5_ctx(void) { @@ -85,7 +85,7 @@ static void test_md5_ctx(void) if (!pMD5Init || !pMD5Update || !pMD5Final) { - skip("Needed functions are not available\n"); + win_skip("Needed functions are not available\n"); return; } diff --git a/rostests/winetests/advapi32/crypt_sha.c b/rostests/winetests/advapi32/crypt_sha.c index cfdaf991d41..8b195d74e95 100644 --- a/rostests/winetests/advapi32/crypt_sha.c +++ b/rostests/winetests/advapi32/crypt_sha.c @@ -35,32 +35,33 @@ typedef struct { static void test_sha_ctx(void) { - FARPROC pA_SHAInit, pA_SHAUpdate, pA_SHAFinal; - static const char test_buffer[] = "In our Life there's If" + void (WINAPI *pA_SHAInit)(PSHA_CTX); + void (WINAPI *pA_SHAUpdate)(PSHA_CTX, const unsigned char *, UINT); + void (WINAPI *pA_SHAFinal)(PSHA_CTX, PULONG); + static const unsigned char test_buffer[] = "In our Life there's If" "In our beliefs there's Lie" "In our business there is Sin" "In our bodies, there is Die"; - ULONG test_buffer_size = strlen(test_buffer); HMODULE hmod; SHA_CTX ctx; ULONG result[5]; ULONG result_correct[5] = {0xe014f93, 0xe09791ec, 0x6dcf96c8, 0x8e9385fc, 0x1611c1bb}; hmod = GetModuleHandleA("advapi32.dll"); - pA_SHAInit = GetProcAddress(hmod, "A_SHAInit"); - pA_SHAUpdate = GetProcAddress(hmod, "A_SHAUpdate"); - pA_SHAFinal = GetProcAddress(hmod, "A_SHAFinal"); + pA_SHAInit = (void *)GetProcAddress(hmod, "A_SHAInit"); + pA_SHAUpdate = (void *)GetProcAddress(hmod, "A_SHAUpdate"); + pA_SHAFinal = (void *)GetProcAddress(hmod, "A_SHAFinal"); if (!pA_SHAInit || !pA_SHAUpdate || !pA_SHAFinal) { - skip("A_SHAInit and/or A_SHAUpdate and/or A_SHAFinal are not available\n"); + win_skip("A_SHAInit and/or A_SHAUpdate and/or A_SHAFinal are not available\n"); return; } RtlZeroMemory(&ctx, sizeof(ctx)); pA_SHAInit(&ctx); - pA_SHAUpdate(&ctx, test_buffer, test_buffer_size); - pA_SHAUpdate(&ctx, test_buffer, test_buffer_size); + pA_SHAUpdate(&ctx, test_buffer, sizeof(test_buffer)-1); + pA_SHAUpdate(&ctx, test_buffer, sizeof(test_buffer)-1); pA_SHAFinal(&ctx, result); ok(!memcmp(result, result_correct, sizeof(result)), "incorrect result\n"); } diff --git a/rostests/winetests/advapi32/lsa.c b/rostests/winetests/advapi32/lsa.c index 4035416cdc5..efb75bbe2ba 100644 --- a/rostests/winetests/advapi32/lsa.c +++ b/rostests/winetests/advapi32/lsa.c @@ -30,28 +30,33 @@ #include "sddl.h" #include "winnls.h" #include "objbase.h" -#define INITGUID -#include "guiddef.h" +#include "initguid.h" #include "wine/test.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + static HMODULE hadvapi32; static NTSTATUS (WINAPI *pLsaClose)(LSA_HANDLE); +static NTSTATUS (WINAPI *pLsaEnumerateAccountRights)(LSA_HANDLE,PSID,PLSA_UNICODE_STRING*,PULONG); static NTSTATUS (WINAPI *pLsaFreeMemory)(PVOID); static NTSTATUS (WINAPI *pLsaOpenPolicy)(PLSA_UNICODE_STRING,PLSA_OBJECT_ATTRIBUTES,ACCESS_MASK,PLSA_HANDLE); static NTSTATUS (WINAPI *pLsaQueryInformationPolicy)(LSA_HANDLE,POLICY_INFORMATION_CLASS,PVOID*); -static BOOL (WINAPI *pConvertSidToStringSidA)(PSID pSid, LPSTR *str); +static BOOL (WINAPI *pConvertSidToStringSidA)(PSID,LPSTR*); +static NTSTATUS (WINAPI *pLsaLookupNames2)(LSA_HANDLE,ULONG,ULONG,PLSA_UNICODE_STRING,PLSA_REFERENCED_DOMAIN_LIST*,PLSA_TRANSLATED_SID2*); static BOOL init(void) { hadvapi32 = GetModuleHandle("advapi32.dll"); pLsaClose = (void*)GetProcAddress(hadvapi32, "LsaClose"); + pLsaEnumerateAccountRights = (void*)GetProcAddress(hadvapi32, "LsaEnumerateAccountRights"); pLsaFreeMemory = (void*)GetProcAddress(hadvapi32, "LsaFreeMemory"); pLsaOpenPolicy = (void*)GetProcAddress(hadvapi32, "LsaOpenPolicy"); pLsaQueryInformationPolicy = (void*)GetProcAddress(hadvapi32, "LsaQueryInformationPolicy"); pConvertSidToStringSidA = (void*)GetProcAddress(hadvapi32, "ConvertSidToStringSidA"); + pLsaLookupNames2 = (void*)GetProcAddress(hadvapi32, "LsaLookupNames2"); - if (pLsaClose && pLsaFreeMemory && pLsaOpenPolicy && pLsaQueryInformationPolicy && pConvertSidToStringSidA) + if (pLsaClose && pLsaEnumerateAccountRights && pLsaFreeMemory && pLsaOpenPolicy && pLsaQueryInformationPolicy && pConvertSidToStringSidA) return TRUE; return FALSE; @@ -72,9 +77,9 @@ static void test_lsa(void) /* try a more restricted access mask if necessary */ if (status == STATUS_ACCESS_DENIED) { - trace("LsaOpenPolicy(POLICY_ALL_ACCESS) failed, trying POLICY_VIEW_LOCAL_INFORMATION\n"); - status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_VIEW_LOCAL_INFORMATION, &handle); - ok(status == STATUS_SUCCESS, "LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION) returned 0x%08x\n", status); + trace("LsaOpenPolicy(POLICY_ALL_ACCESS) failed, trying POLICY_VIEW_LOCAL_INFORMATION|POLICY_LOOKUP_NAMES\n"); + status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_VIEW_LOCAL_INFORMATION|POLICY_LOOKUP_NAMES, &handle); + ok(status == STATUS_SUCCESS, "LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION|POLICY_LOOKUP_NAMES) returned 0x%08x\n", status); } if (status == STATUS_SUCCESS) { @@ -82,6 +87,8 @@ static void test_lsa(void) PPOLICY_PRIMARY_DOMAIN_INFO primary_domain_info; PPOLICY_ACCOUNT_DOMAIN_INFO account_domain_info; PPOLICY_DNS_DOMAIN_INFO dns_domain_info; + HANDLE token; + BOOL ret; status = pLsaQueryInformationPolicy(handle, PolicyAuditEventsInformation, (PVOID*)&audit_events_info); if (status == STATUS_ACCESS_DENIED) @@ -95,7 +102,6 @@ static void test_lsa(void) status = pLsaQueryInformationPolicy(handle, PolicyPrimaryDomainInformation, (PVOID*)&primary_domain_info); ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy(PolicyPrimaryDomainInformation) failed, returned 0x%08x\n", status); if (status == STATUS_SUCCESS) { - ok(primary_domain_info->Sid==0,"Sid should be NULL on the local computer\n"); if (primary_domain_info->Sid) { LPSTR strsid; if (pConvertSidToStringSidA(primary_domain_info->Sid, &strsid)) @@ -115,6 +121,8 @@ static void test_lsa(void) else trace("invalid sid\n"); } + else + trace("Running on a standalone system.\n"); pLsaFreeMemory((LPVOID)primary_domain_info); } @@ -129,8 +137,6 @@ static void test_lsa(void) ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER, "LsaQueryInformationPolicy(PolicyDnsDomainInformation) failed, returned 0x%08x\n", status); if (status == STATUS_SUCCESS) { - ok(IsEqualGUID(&dns_domain_info->DomainGuid, &GUID_NULL), "DomainGUID should be GUID_NULL on local computer\n"); - ok(dns_domain_info->Sid==0,"Sid should be NULL on the local computer\n"); if (dns_domain_info->Sid || !IsEqualGUID(&dns_domain_info->DomainGuid, &GUID_NULL)) { LPSTR strsid = NULL; LPSTR name = NULL; @@ -169,20 +175,189 @@ static void test_lsa(void) LocalFree( guidstr ); LocalFree( strsid ); } + else + trace("Running on a standalone system.\n"); pLsaFreeMemory((LPVOID)dns_domain_info); } + /* We need a valid SID to pass to LsaEnumerateAccountRights */ + ret = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token ); + ok(ret, "Unable to obtain process token, error %u\n", GetLastError( )); + if (ret) { + char buffer[64]; + DWORD len; + TOKEN_USER *token_user = (TOKEN_USER *) buffer; + ret = GetTokenInformation( token, TokenUser, (LPVOID) token_user, sizeof(buffer), &len ); + ok(ret || GetLastError( ) == ERROR_INSUFFICIENT_BUFFER, "Unable to obtain token information, error %u\n", GetLastError( )); + if (! ret && GetLastError( ) == ERROR_INSUFFICIENT_BUFFER) { + trace("Resizing buffer to %u.\n", len); + token_user = LocalAlloc( 0, len ); + if (token_user != NULL) + ret = GetTokenInformation( token, TokenUser, (LPVOID) token_user, len, &len ); + } + + if (ret) { + PLSA_UNICODE_STRING rights; + ULONG rights_count; + rights = (PLSA_UNICODE_STRING) 0xdeadbeaf; + rights_count = 0xcafecafe; + status = pLsaEnumerateAccountRights(handle, token_user->User.Sid, &rights, &rights_count); + ok(status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND, "Unexpected status 0x%x\n", status); + if (status == STATUS_SUCCESS) + pLsaFreeMemory( rights ); + else + ok(rights == NULL && rights_count == 0, "Expected rights and rights_count to be set to 0 on failure\n"); + } + if (token_user != NULL && token_user != (TOKEN_USER *) buffer) + LocalFree( token_user ); + CloseHandle( token ); + } + status = pLsaClose(handle); ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status); } } +static void get_sid_info(PSID psid, LPSTR *user, LPSTR *dom) +{ + static char account[257], domain[257]; + DWORD user_size, dom_size; + SID_NAME_USE use; + BOOL ret; + + *user = account; + *dom = domain; + + user_size = dom_size = 257; + account[0] = domain[0] = 0; + ret = LookupAccountSidA(NULL, psid, account, &user_size, domain, &dom_size, &use); + ok(ret, "LookupAccountSidA failed %u\n", GetLastError()); +} + +static void test_LsaLookupNames2(void) +{ + static const WCHAR n1[] = {'L','O','C','A','L',' ','S','E','R','V','I','C','E'}; + static const WCHAR n2[] = {'N','T',' ','A','U','T','H','O','R','I','T','Y','\\','L','o','c','a','l','S','e','r','v','i','c','e'}; + + NTSTATUS status; + LSA_HANDLE handle; + LSA_OBJECT_ATTRIBUTES attrs; + PLSA_REFERENCED_DOMAIN_LIST domains; + PLSA_TRANSLATED_SID2 sids; + LSA_UNICODE_STRING name[3]; + LPSTR account, sid_dom; + + if (!pLsaLookupNames2) + { + win_skip("LsaLookupNames2 not avaliable\n"); + return; + } + + if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH) + { + skip("Non-english locale (skipping LsaLookupNames2 tests)\n"); + return; + } + + memset(&attrs, 0, sizeof(attrs)); + attrs.Length = sizeof(attrs); + + status = pLsaOpenPolicy(NULL, &attrs, POLICY_ALL_ACCESS, &handle); + ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED, + "LsaOpenPolicy(POLICY_ALL_ACCESS) returned 0x%08x\n", status); + + /* try a more restricted access mask if necessary */ + if (status == STATUS_ACCESS_DENIED) + { + trace("LsaOpenPolicy(POLICY_ALL_ACCESS) failed, trying POLICY_VIEW_LOCAL_INFORMATION\n"); + status = pLsaOpenPolicy(NULL, &attrs, POLICY_LOOKUP_NAMES, &handle); + ok(status == STATUS_SUCCESS, "LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION) returned 0x%08x\n", status); + } + if (status != STATUS_SUCCESS) + { + skip("Cannot acquire policy handle\n"); + return; + } + + name[0].Buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(n1)); + name[0].Length = name[0].MaximumLength = sizeof(n1); + memcpy(name[0].Buffer, n1, sizeof(n1)); + + name[1].Buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(n1)); + name[1].Length = name[1].MaximumLength = sizeof(n1) - sizeof(WCHAR); + memcpy(name[1].Buffer, n1, sizeof(n1) - sizeof(WCHAR)); + + name[2].Buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(n2)); + name[2].Length = name[2].MaximumLength = sizeof(n2); + memcpy(name[2].Buffer, n2, sizeof(n2)); + + /* account name only */ + sids = NULL; + domains = NULL; + status = pLsaLookupNames2(handle, 0, 1, &name[0], &domains, &sids); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %x)\n", status); + ok(sids[0].Use == SidTypeWellKnownGroup, "expected SidTypeWellKnownGroup, got %u\n", sids[0].Use); + ok(sids[0].Flags == 0, "expected 0, got 0x%08x\n", sids[0].Flags); + ok(domains->Entries == 1, "expected 1, got %u\n", domains->Entries); + get_sid_info(sids[0].Sid, &account, &sid_dom); + ok(!strcmp(account, "LOCAL SERVICE"), "expected \"LOCAL SERVICE\", got \"%s\"\n", account); + ok(!strcmp(sid_dom, "NT AUTHORITY"), "expected \"NT AUTHORITY\", got \"%s\"\n", sid_dom); + pLsaFreeMemory(sids); + pLsaFreeMemory(domains); + + /* unknown account name */ + sids = NULL; + domains = NULL; + status = pLsaLookupNames2(handle, 0, 1, &name[1], &domains, &sids); + ok(status == STATUS_NONE_MAPPED, "expected STATUS_NONE_MAPPED, got %x)\n", status); + ok(sids[0].Use == SidTypeUnknown, "expected SidTypeUnknown, got %u\n", sids[0].Use); + ok(sids[0].Flags == 0, "expected 0, got 0x%08x\n", sids[0].Flags); + ok(domains->Entries == 0, "expected 0, got %u\n", domains->Entries); + pLsaFreeMemory(sids); + pLsaFreeMemory(domains); + + /* account + domain */ + sids = NULL; + domains = NULL; + status = pLsaLookupNames2(handle, 0, 1, &name[2], &domains, &sids); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %x)\n", status); + ok(sids[0].Use == SidTypeWellKnownGroup, "expected SidTypeWellKnownGroup, got %u\n", sids[0].Use); + ok(sids[0].Flags == 0, "expected 0, got 0x%08x\n", sids[0].Flags); + ok(domains->Entries == 1, "expected 1, got %u\n", domains->Entries); + get_sid_info(sids[0].Sid, &account, &sid_dom); + ok(!strcmp(account, "LOCAL SERVICE"), "expected \"LOCAL SERVICE\", got \"%s\"\n", account); + ok(!strcmp(sid_dom, "NT AUTHORITY"), "expected \"NT AUTHORITY\", got \"%s\"\n", sid_dom); + pLsaFreeMemory(sids); + pLsaFreeMemory(domains); + + /* all three */ + sids = NULL; + domains = NULL; + status = pLsaLookupNames2(handle, 0, 3, name, &domains, &sids); + ok(status == STATUS_SOME_NOT_MAPPED, "expected STATUS_SOME_NOT_MAPPED, got %x)\n", status); + ok(sids[0].Use == SidTypeWellKnownGroup, "expected SidTypeWellKnownGroup, got %u\n", sids[0].Use); + ok(sids[1].Use == SidTypeUnknown, "expected SidTypeUnknown, got %u\n", sids[0].Use); + ok(sids[2].Use == SidTypeWellKnownGroup, "expected SidTypeWellKnownGroup, got %u\n", sids[0].Use); + ok(sids[0].DomainIndex == 0, "expected 0, got %u\n", sids[0].DomainIndex); + ok(domains->Entries == 1, "expected 1, got %u\n", domains->Entries); + pLsaFreeMemory(sids); + pLsaFreeMemory(domains); + + HeapFree(GetProcessHeap(), 0, name[0].Buffer); + HeapFree(GetProcessHeap(), 0, name[1].Buffer); + HeapFree(GetProcessHeap(), 0, name[2].Buffer); + + status = pLsaClose(handle); + ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status); +} + START_TEST(lsa) { if (!init()) { - skip("Needed functions are not available\n"); + win_skip("Needed functions are not available\n"); return; } test_lsa(); + test_LsaLookupNames2(); } diff --git a/rostests/winetests/advapi32/registry.c b/rostests/winetests/advapi32/registry.c index fe3d3ff7c3a..abc2eb4aeb6 100644 --- a/rostests/winetests/advapi32/registry.c +++ b/rostests/winetests/advapi32/registry.c @@ -47,12 +47,16 @@ static DWORD (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR); static char *get_temp_buffer( int size ) { static char *list[32]; - static long pos; + static UINT pos; char *ret; - int idx; + UINT idx; idx = ++pos % (sizeof(list)/sizeof(list[0])); - if ((ret = realloc( list[idx], size ))) list[idx] = ret; + if (list[idx]) + ret = HeapReAlloc( GetProcessHeap(), 0, list[idx], size ); + else + ret = HeapAlloc( GetProcessHeap(), 0, size ); + if (ret) list[idx] = ret; return ret; } @@ -107,61 +111,9 @@ static const char *wine_debugstr_an( const char *str, int n ) return res; } -static const char *wine_debugstr_wn( const WCHAR *str, int n ) -{ - char *dst, *res; - size_t size; - - if (!HIWORD(str)) - { - if (!str) return "(null)"; - res = get_temp_buffer( 6 ); - sprintf( res, "#%04x", LOWORD(str) ); - return res; - } - if (n == -1) n = lstrlenW(str); - if (n < 0) n = 0; - size = 12 + min( 300, n * 5); - dst = res = get_temp_buffer( n * 5 + 7 ); - *dst++ = 'L'; - *dst++ = '"'; - while (n-- > 0 && dst <= res + size - 10) - { - WCHAR c = *str++; - switch (c) - { - case '\n': *dst++ = '\\'; *dst++ = 'n'; break; - case '\r': *dst++ = '\\'; *dst++ = 'r'; break; - case '\t': *dst++ = '\\'; *dst++ = 't'; break; - case '"': *dst++ = '\\'; *dst++ = '"'; break; - case '\\': *dst++ = '\\'; *dst++ = '\\'; break; - default: - if (c >= ' ' && c <= 126) - *dst++ = (char)c; - else - { - *dst++ = '\\'; - sprintf(dst,"%04x",c); - dst+=4; - } - } - } - *dst++ = '"'; - if (n > 0) - { - *dst++ = '.'; - *dst++ = '.'; - *dst++ = '.'; - } - *dst = 0; - return res; -} - - #define ADVAPI32_GET_PROC(func) \ - p ## func = (void*)GetProcAddress(hadvapi32, #func); \ - if(!p ## func) \ - trace("GetProcAddress(%s) failed\n", #func); + p ## func = (void*)GetProcAddress(hadvapi32, #func); + static void InitFunctionPtrs(void) { @@ -200,13 +152,14 @@ static void setup_main_key(void) assert (!RegCreateKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main )); } -static void test_hkey_main_Value_A(LPCSTR name, LPCSTR string, +#define lok ok_(__FILE__, line) +#define test_hkey_main_Value_A(name, string, full_byte_len) _test_hkey_main_Value_A(__LINE__, name, string, full_byte_len) +static void _test_hkey_main_Value_A(int line, LPCSTR name, LPCSTR string, DWORD full_byte_len) { DWORD ret, type, cbData; DWORD str_byte_len; - LPSTR value; - static const char nA[]={'N', 0}; + BYTE* value; type=0xdeadbeef; cbData=0xdeadbeef; @@ -216,43 +169,44 @@ static void test_hkey_main_Value_A(LPCSTR name, LPCSTR string, SetLastError(0xdeadbeef); ret = RegQueryValueExA(hkey_main, name, NULL, &type, NULL, &cbData); GLE = GetLastError(); - ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%d\n", ret, GLE); + lok(ret == ERROR_SUCCESS, "RegQueryValueExA/1 failed: %d, GLE=%d\n", ret, GLE); /* It is wrong for the Ansi version to not be implemented */ ok(GLE == 0xdeadbeef, "RegQueryValueExA set GLE = %u\n", GLE); if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return; str_byte_len = (string ? lstrlenA(string) : 0) + 1; - ok(type == REG_SZ, "RegQueryValueExA returned type %d\n", type); - ok(cbData == full_byte_len || cbData == str_byte_len /* Win9x */, + lok(type == REG_SZ, "RegQueryValueExA/1 returned type %d\n", type); + lok(cbData == full_byte_len || cbData == str_byte_len /* Win9x */, "cbData=%d instead of %d or %d\n", cbData, full_byte_len, str_byte_len); - value = HeapAlloc(GetProcessHeap(), 0, (cbData+2)*sizeof(*value)); - strcpy(value, nA); + value = HeapAlloc(GetProcessHeap(), 0, cbData+1); + memset(value, 0xbd, cbData+1); type=0xdeadbeef; - ret = RegQueryValueExA(hkey_main, name, NULL, &type, (BYTE*)value, &cbData); + ret = RegQueryValueExA(hkey_main, name, NULL, &type, value, &cbData); GLE = GetLastError(); - ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%d\n", ret, GLE); + lok(ret == ERROR_SUCCESS, "RegQueryValueExA/2 failed: %d, GLE=%d\n", ret, GLE); if (!string) { /* When cbData == 0, RegQueryValueExA() should not modify the buffer */ - ok(strcmp(value, nA) == 0 || (cbData == 1 && *value == '\0') /* Win9x */, - "RegQueryValueExA failed: '%s' != '%s'\n", value, string); + lok(*value == 0xbd || (cbData == 1 && *value == '\0') /* Win9x */, + "RegQueryValueExA overflowed: cbData=%u *value=%02x\n", cbData, *value); } else { - ok(memcmp(value, string, cbData) == 0, "RegQueryValueExA failed: %s/%d != %s/%d\n", - wine_debugstr_an(value, cbData), cbData, + lok(memcmp(value, string, cbData) == 0, "RegQueryValueExA/2 failed: %s/%d != %s/%d\n", + wine_debugstr_an((char*)value, cbData), cbData, wine_debugstr_an(string, full_byte_len), full_byte_len); + lok(*(value+cbData) == 0xbd, "RegQueryValueExA/2 overflowed at offset %u: %02x != bd\n", cbData, *(value+cbData)); } HeapFree(GetProcessHeap(), 0, value); } -static void test_hkey_main_Value_W(LPCWSTR name, LPCWSTR string, +#define test_hkey_main_Value_W(name, string, full_byte_len) _test_hkey_main_Value_W(__LINE__, name, string, full_byte_len) +static void _test_hkey_main_Value_W(int line, LPCWSTR name, LPCWSTR string, DWORD full_byte_len) { DWORD ret, type, cbData; - LPWSTR value; - static const WCHAR nW[]={'N', 0}; + BYTE* value; type=0xdeadbeef; cbData=0xdeadbeef; @@ -262,27 +216,33 @@ static void test_hkey_main_Value_W(LPCWSTR name, LPCWSTR string, SetLastError(0xdeadbeef); ret = RegQueryValueExW(hkey_main, name, NULL, &type, NULL, &cbData); GLE = GetLastError(); - ok(ret == ERROR_SUCCESS, "RegQueryValueExW failed: %d, GLE=%d\n", ret, GLE); - if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return; + lok(ret == ERROR_SUCCESS, "RegQueryValueExW/1 failed: %d, GLE=%d\n", ret, GLE); + if(GLE == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("RegQueryValueExW() is not implemented\n"); + return; + } - ok(type == REG_SZ, "RegQueryValueExW returned type %d\n", type); - ok(cbData == full_byte_len, + lok(type == REG_SZ, "RegQueryValueExW/1 returned type %d\n", type); + lok(cbData == full_byte_len, "cbData=%d instead of %d\n", cbData, full_byte_len); - value = HeapAlloc(GetProcessHeap(), 0, (cbData+2)*sizeof(*value)); - lstrcpyW(value, nW); + /* Give enough space to overflow by one WCHAR */ + value = HeapAlloc(GetProcessHeap(), 0, cbData+2); + memset(value, 0xbd, cbData+2); type=0xdeadbeef; - ret = RegQueryValueExW(hkey_main, name, NULL, &type, (BYTE*)value, &cbData); + ret = RegQueryValueExW(hkey_main, name, NULL, &type, value, &cbData); GLE = GetLastError(); - ok(ret == ERROR_SUCCESS, "RegQueryValueExW failed: %d, GLE=%d\n", ret, GLE); - if (!string) + lok(ret == ERROR_SUCCESS, "RegQueryValueExW/2 failed: %d, GLE=%d\n", ret, GLE); + if (string) { - /* When cbData == 0, RegQueryValueExW() should not modify the buffer */ - string=nW; + lok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\n", + wine_dbgstr_wn((WCHAR*)value, cbData / sizeof(WCHAR)), cbData, + wine_dbgstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len); } - ok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\n", - wine_debugstr_wn(value, cbData / sizeof(WCHAR)), cbData, - wine_debugstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len); + /* This implies that when cbData == 0, RegQueryValueExW() should not modify the buffer */ + lok(*(value+cbData) == 0xbd, "RegQueryValueExW/2 overflowed at %u: %02x != bd\n", cbData, *(value+cbData)); + lok(*(value+cbData+1) == 0xbd, "RegQueryValueExW/2 overflowed at %u+1: %02x != bd\n", cbData, *(value+cbData+1)); HeapFree(GetProcessHeap(), 0, value); } @@ -328,13 +288,21 @@ static void test_set_value(void) test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A)); test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W)); - /* only REG_SZ is supported */ + /* only REG_SZ is supported on NT*/ ret = RegSetValueA(hkey_main, NULL, REG_BINARY, string2A, sizeof(string2A)); - ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret); + /* NT: ERROR_INVALID_PARAMETER, 9x: ERROR_SUCCESS */ + ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), + "got %d (expected ERROR_INVALID_PARAMETER or ERROR_SUCCESS)\n", ret); + ret = RegSetValueA(hkey_main, NULL, REG_EXPAND_SZ, string2A, sizeof(string2A)); - ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret); + /* NT: ERROR_INVALID_PARAMETER, 9x: ERROR_SUCCESS */ + ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), + "got %d (expected ERROR_INVALID_PARAMETER or ERROR_SUCCESS)\n", ret); + ret = RegSetValueA(hkey_main, NULL, REG_MULTI_SZ, string2A, sizeof(string2A)); - ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret); + /* NT: ERROR_INVALID_PARAMETER, 9x: ERROR_SUCCESS */ + ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), + "got %d (expected ERROR_INVALID_PARAMETER or ERROR_SUCCESS)\n", ret); /* Test RegSetValueExA with a 'zero-byte' string (as Office 2003 does). * Surprisingly enough we're supposed to get zero bytes out of it. @@ -433,7 +401,7 @@ static void create_test_entries(void) "RegSetValueExA failed\n"); ok(!RegSetValueExA(hkey_main,"TP1_SZ",0,REG_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1), "RegSetValueExA failed\n"); - ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, NULL, 0), + ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, (const BYTE *)"", 0), "RegSetValueExA failed\n"); ok(!RegSetValueExA(hkey_main,"TP2_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath2, strlen(sTestpath2)+1), "RegSetValueExA failed\n"); @@ -556,7 +524,7 @@ static void test_enum_value(void) res = RegSetValueExW( test_key, testW, 0, REG_SZ, (const BYTE *)foobarW, 7*sizeof(WCHAR) ); if (res==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { - skip("RegSetValueExW is not implemented\n"); + win_skip("RegSetValueExW is not implemented\n"); goto cleanup; } ok( res == 0, "RegSetValueExW failed error %d\n", res ); @@ -675,7 +643,7 @@ static void test_get_value(void) if(!pRegGetValueA) { - skip("RegGetValue not available on this platform\n"); + win_skip("RegGetValue not available on this platform\n"); return; } @@ -775,7 +743,7 @@ static void test_get_value(void) ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, NULL, &size); ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */ - ok(size == strlen(sTestpath1)+1 || size == strlen(sTestpath1)+2, + ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2), "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size); ok(type == REG_SZ, "type=%d\n", type); @@ -816,7 +784,7 @@ static void test_get_value(void) ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size); ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */ - ok((size == strlen(expanded)+1) || (size == strlen(sTestpath1)+1), + ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1), "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size); ok(type == REG_SZ, "type=%d\n", type); ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf); @@ -826,7 +794,7 @@ static void test_get_value(void) ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size); ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath2 length + 1 here. */ - ok((size == strlen(expanded2)+1) || (size == strlen(sTestpath2)+1), + ok(size == strlen(expanded2)+1 || broken(size == strlen(sTestpath2)+1), "strlen(expanded2)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size); ok(type == REG_SZ, "type=%d\n", type); ok(!strcmp(expanded2, buf), "expanded2=\"%s\" buf=\"%s\"\n", expanded2, buf); @@ -844,7 +812,7 @@ static void test_get_value(void) ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, NULL, NULL, &size); ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */ - ok(size == strlen(sTestpath1)+1 || size == strlen(sTestpath1)+2, + ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2), "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size); /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (type mismatch) */ @@ -854,6 +822,16 @@ static void test_get_value(void) /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ (not allowed without RRF_NOEXPAND) */ ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ, NULL, NULL, NULL); ok(ret == ERROR_INVALID_PARAMETER, "ret=%d\n", ret); + + /* Query REG_EXPAND_SZ using RRF_RT_ANY */ + buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf); + ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_ANY, &type, buf, &size); + ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); + /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */ + ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1), + "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size); + ok(type == REG_SZ, "type=%d\n", type); + ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf); } static void test_reg_open_key(void) @@ -930,11 +908,38 @@ static void test_reg_open_key(void) ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", NULL); ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret); + ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret); + + ret = RegOpenKeyA(NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret); + /* beginning backslash character */ ret = RegOpenKeyA(HKEY_CURRENT_USER, "\\Software\\Wine\\Test", &hkResult); ok(ret == ERROR_BAD_PATHNAME || /* NT/2k/XP */ ret == ERROR_FILE_NOT_FOUND /* Win9x,ME */ , "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret); + + hkResult = NULL; + ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\clsid", 0, KEY_QUERY_VALUE, &hkResult); + ok(ret == ERROR_SUCCESS || /* 2k/XP */ + ret == ERROR_BAD_PATHNAME || /* NT */ + ret == ERROR_FILE_NOT_FOUND /* Win9x,ME */ + , "expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret); + RegCloseKey(hkResult); + + /* WOW64 flags */ + hkResult = NULL; + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_32KEY, &hkResult); + ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */), + "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret); + RegCloseKey(hkResult); + + hkResult = NULL; + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_64KEY, &hkResult); + ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */), + "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret); + RegCloseKey(hkResult); } static void test_reg_create_key(void) @@ -960,6 +965,19 @@ static void test_reg_create_key(void) ok(!ret, "RegCreateKeyExA failed with error %d\n", ret); RegDeleteKey(hkey1, NULL); } + + /* WOW64 flags - open an existing key */ + hkey1 = NULL; + ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_32KEY, NULL, &hkey1, NULL); + ok((ret == ERROR_SUCCESS && hkey1 != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */), + "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret); + RegCloseKey(hkey1); + + hkey1 = NULL; + ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_64KEY, NULL, &hkey1, NULL); + ok((ret == ERROR_SUCCESS && hkey1 != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */), + "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret); + RegCloseKey(hkey1); } static void test_reg_close_key(void) @@ -1124,7 +1142,7 @@ static void test_regconnectregistry( void) schnd = OpenSCManagerA( compName, NULL, GENERIC_READ); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("OpenSCManagerA is not implemented\n"); + win_skip("OpenSCManagerA is not implemented\n"); return; } @@ -1157,7 +1175,9 @@ static void test_reg_query_value(void) SetLastError(0xdeadbeef); size = MAX_PATH; ret = RegQueryValueA((HKEY)0xcafebabe, "subkey", val, &size); - ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */ + ok(ret == ERROR_INVALID_HANDLE || + ret == ERROR_BADKEY || /* Windows 98 returns BADKEY */ + ret == ERROR_ACCESS_DENIED, /* non-admin winxp */ "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); @@ -1218,7 +1238,7 @@ static void test_reg_query_value(void) ret = RegQueryValueW(subkey, NULL, valW, &size); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("RegQueryValueW is not implemented\n"); + win_skip("RegQueryValueW is not implemented\n"); goto cleanup; } ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret); @@ -1259,6 +1279,87 @@ cleanup: RegCloseKey(subkey); } +static void test_string_termination(void) +{ + HKEY subkey; + LSTATUS ret; + static const char string[] = "FullString"; + char name[11]; + BYTE buffer[11]; + DWORD insize, outsize, nsize; + + ret = RegCreateKeyA(hkey_main, "string_termination", &subkey); + ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret); + + /* Off-by-one RegSetValueExA -> adds a trailing '\0'! */ + insize=sizeof(string)-1; + ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize); + ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret); + outsize=insize; + ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize); + ok(ret == ERROR_MORE_DATA, "RegQueryValueExA returned: %d\n", ret); + + /* Off-by-two RegSetValueExA -> no trailing '\0', except on Win9x */ + insize=sizeof(string)-2; + ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize); + ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret); + outsize=0; + ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, NULL, &outsize); + ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret); + ok(outsize == insize || broken(outsize == sizeof(string)) /* Win9x */, + "wrong size %u != %u\n", outsize, insize); + + if (outsize == insize) + { + /* RegQueryValueExA may return a string with no trailing '\0' */ + outsize=insize; + memset(buffer, 0xbd, sizeof(buffer)); + ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize); + ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret); + ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize); + ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n", + wine_debugstr_an((char*)buffer, outsize), outsize, string); + ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]); + + /* RegQueryValueExA adds a trailing '\0' if there is room */ + outsize=insize+1; + memset(buffer, 0xbd, sizeof(buffer)); + ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize); + ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret); + ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize); + ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n", + wine_debugstr_an((char*)buffer, outsize), outsize, string); + ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]); + + /* RegEnumValueA may return a string with no trailing '\0' */ + outsize=insize; + memset(buffer, 0xbd, sizeof(buffer)); + nsize=sizeof(name); + ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize); + ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret); + ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name); + ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize); + ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n", + wine_debugstr_an((char*)buffer, outsize), outsize, string); + ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]); + + /* RegEnumValueA adds a trailing '\0' if there is room */ + outsize=insize+1; + memset(buffer, 0xbd, sizeof(buffer)); + nsize=sizeof(name); + ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize); + ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret); + ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name); + ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize); + ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n", + wine_debugstr_an((char*)buffer, outsize), outsize, string); + ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]); + } + + RegDeleteKeyA(subkey, ""); + RegCloseKey(subkey); +} + static void test_reg_delete_tree(void) { CHAR buffer[MAX_PATH]; @@ -1266,7 +1367,7 @@ static void test_reg_delete_tree(void) LONG size, ret; if(!pRegDeleteTreeA) { - skip("Skipping RegDeleteTreeA tests, function not present\n"); + win_skip("Skipping RegDeleteTreeA tests, function not present\n"); return; } @@ -1333,6 +1434,52 @@ static void test_reg_delete_tree(void) "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret); } +static void test_rw_order(void) +{ + HKEY hKey; + DWORD dw = 0; + static char keyname[] = "test_rw_order"; + char value_buf[2]; + DWORD values, value_len, value_name_max_len; + LSTATUS ret; + + RegDeleteKeyA(HKEY_CURRENT_USER, keyname); + ret = RegCreateKeyA(HKEY_CURRENT_USER, keyname, &hKey); + if(ret != ERROR_SUCCESS) { + skip("Couldn't create key. Skipping.\n"); + return; + } + + ok(!RegSetValueExA(hKey, "A", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)), + "RegSetValueExA for value \"A\" failed\n"); + ok(!RegSetValueExA(hKey, "C", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)), + "RegSetValueExA for value \"C\" failed\n"); + ok(!RegSetValueExA(hKey, "D", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)), + "RegSetValueExA for value \"D\" failed\n"); + ok(!RegSetValueExA(hKey, "B", 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw)), + "RegSetValueExA for value \"B\" failed\n"); + + ok(!RegQueryInfoKeyA(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &values, + &value_name_max_len, NULL, NULL, NULL), "RegQueryInfoKeyA failed\n"); + ok(values == 4, "Expected 4 values, got %u\n", values); + + /* Value enumeration preserves RegSetValueEx call order */ + value_len = 2; + ok(!RegEnumValueA(hKey, 0, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n"); + ok(strcmp(value_buf, "A") == 0, "Expected name \"A\", got %s\n", value_buf); + value_len = 2; + ok(!RegEnumValueA(hKey, 1, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n"); + todo_wine ok(strcmp(value_buf, "C") == 0, "Expected name \"C\", got %s\n", value_buf); + value_len = 2; + ok(!RegEnumValueA(hKey, 2, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n"); + todo_wine ok(strcmp(value_buf, "D") == 0, "Expected name \"D\", got %s\n", value_buf); + value_len = 2; + ok(!RegEnumValueA(hKey, 3, value_buf, &value_len, NULL, NULL, NULL, NULL), "RegEnumValueA failed\n"); + todo_wine ok(strcmp(value_buf, "B") == 0, "Expected name \"B\", got %s\n", value_buf); + + ok(!RegDeleteKey(HKEY_CURRENT_USER, keyname), "Failed to delete key\n"); +} + START_TEST(registry) { /* Load pointers for functions that are not available in all Windows versions */ @@ -1349,6 +1496,7 @@ START_TEST(registry) test_reg_close_key(); test_reg_delete_key(); test_reg_query_value(); + test_string_termination(); /* SaveKey/LoadKey require the SE_BACKUP_NAME privilege to be set */ if (set_privileges(SE_BACKUP_NAME, TRUE) && @@ -1363,6 +1511,7 @@ START_TEST(registry) } test_reg_delete_tree(); + test_rw_order(); /* cleanup */ delete_key( hkey_main ); diff --git a/rostests/winetests/advapi32/security.c b/rostests/winetests/advapi32/security.c index d393f110b26..7d91ebe7de2 100644 --- a/rostests/winetests/advapi32/security.c +++ b/rostests/winetests/advapi32/security.c @@ -81,13 +81,20 @@ typedef BOOL (WINAPI *fnConvertSidToStringSidA)( PSID pSid, LPSTR *str ); typedef BOOL (WINAPI *fnConvertStringSidToSidA)( LPCSTR str, PSID pSid ); static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR, DWORD, PSECURITY_DESCRIPTOR*, PULONG ); +static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorW)(LPCWSTR, DWORD, + PSECURITY_DESCRIPTOR*, PULONG ); static BOOL (WINAPI *pConvertSecurityDescriptorToStringSecurityDescriptorA)(PSECURITY_DESCRIPTOR, DWORD, SECURITY_INFORMATION, LPSTR *, PULONG ); typedef BOOL (WINAPI *fnGetFileSecurityA)(LPCSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD); +typedef BOOL (WINAPI *fnSetFileSecurityA)(LPCSTR, SECURITY_INFORMATION, + PSECURITY_DESCRIPTOR); static DWORD (WINAPI *pGetNamedSecurityInfoA)(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); +static PDWORD (WINAPI *pGetSidSubAuthority)(PSID, DWORD); +static PUCHAR (WINAPI *pGetSidSubAuthorityCount)(PSID); +static BOOL (WINAPI *pIsValidSid)(PSID); typedef DWORD (WINAPI *fnRtlAdjustPrivilege)(ULONG,BOOLEAN,BOOLEAN,PBOOLEAN); typedef BOOL (WINAPI *fnCreateWellKnownSid)(WELL_KNOWN_SID_TYPE,PSID,PSID,DWORD*); typedef BOOL (WINAPI *fnDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES, @@ -101,6 +108,10 @@ static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,U static DWORD (WINAPI *pSetEntriesInAclW)(ULONG, PEXPLICIT_ACCESSW, PACL, PACL*); static BOOL (WINAPI *pSetSecurityDescriptorControl)(PSECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SECURITY_DESCRIPTOR_CONTROL); +static DWORD (WINAPI *pGetSecurityInfo)(HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, + PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); +static NTSTATUS (WINAPI *pNtAccessCheck)(PSECURITY_DESCRIPTOR, HANDLE, ACCESS_MASK, PGENERIC_MAPPING, + PPRIVILEGE_SET, PULONG, PULONG, NTSTATUS*); static HMODULE hmod; static int myARGC; @@ -115,6 +126,7 @@ fnMakeSelfRelativeSD pMakeSelfRelativeSD; fnConvertSidToStringSidA pConvertSidToStringSidA; fnConvertStringSidToSidA pConvertStringSidToSidA; fnGetFileSecurityA pGetFileSecurityA; +fnSetFileSecurityA pSetFileSecurityA; fnRtlAdjustPrivilege pRtlAdjustPrivilege; fnCreateWellKnownSid pCreateWellKnownSid; fnDuplicateTokenEx pDuplicateTokenEx; @@ -135,6 +147,7 @@ static void init(void) hntdll = GetModuleHandleA("ntdll.dll"); pNtQueryObject = (void *)GetProcAddress( hntdll, "NtQueryObject" ); + pNtAccessCheck = (void *)GetProcAddress( hntdll, "NtAccessCheck" ); hmod = GetModuleHandle("advapi32.dll"); pAddAccessAllowedAceEx = (void *)GetProcAddress(hmod, "AddAccessAllowedAceEx"); @@ -142,13 +155,21 @@ static void init(void) pAddAuditAccessAceEx = (void *)GetProcAddress(hmod, "AddAuditAccessAceEx"); pConvertStringSecurityDescriptorToSecurityDescriptorA = (void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorA" ); + pConvertStringSecurityDescriptorToSecurityDescriptorW = + (void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorW" ); pConvertSecurityDescriptorToStringSecurityDescriptorA = (void *)GetProcAddress(hmod, "ConvertSecurityDescriptorToStringSecurityDescriptorA" ); + pGetFileSecurityA = (fnGetFileSecurityA)GetProcAddress(hmod, "GetFileSecurityA" ); + pSetFileSecurityA = (fnSetFileSecurityA)GetProcAddress(hmod, "SetFileSecurityA" ); pCreateWellKnownSid = (fnCreateWellKnownSid)GetProcAddress( hmod, "CreateWellKnownSid" ); pGetNamedSecurityInfoA = (void *)GetProcAddress(hmod, "GetNamedSecurityInfoA"); + pGetSidSubAuthority = (void *)GetProcAddress(hmod, "GetSidSubAuthority"); + pGetSidSubAuthorityCount = (void *)GetProcAddress(hmod, "GetSidSubAuthorityCount"); + pIsValidSid = (void *)GetProcAddress(hmod, "IsValidSid"); pMakeSelfRelativeSD = (void *)GetProcAddress(hmod, "MakeSelfRelativeSD"); pSetEntriesInAclW = (void *)GetProcAddress(hmod, "SetEntriesInAclW"); pSetSecurityDescriptorControl = (void *)GetProcAddress(hmod, "SetSecurityDescriptorControl"); + pGetSecurityInfo = (void *)GetProcAddress(hmod, "GetSecurityInfo"); myARGC = winetest_get_mainargs( &myARGV ); } @@ -228,7 +249,7 @@ static void test_sid(void) GetLastError() ); ok(pConvertStringSidToSidA("S-1-5-21-93476-23408-4576", &psid), "ConvertStringSidToSidA failed\n"); - pisid = (SID *)psid; + pisid = psid; ok(pisid->SubAuthorityCount == 4, "Invalid sub authority count - expected 4, got %d\n", pisid->SubAuthorityCount); ok(pisid->SubAuthority[0] == 21, "Invalid subauthority 0 - expceted 21, got %d\n", pisid->SubAuthority[0]); ok(pisid->SubAuthority[3] == 4576, "Invalid subauthority 0 - expceted 4576, got %d\n", pisid->SubAuthority[3]); @@ -254,7 +275,7 @@ static void test_sid(void) r = pConvertStringSidToSidA( refs[i].refStr, &psid ); ok( r, "failed to parse sid string\n" ); - pisid = (PISID)psid; + pisid = psid; ok( pisid && !memcmp( pisid->IdentifierAuthority.Value, refs[i].auth.Value, sizeof(refs[i].auth) ), @@ -361,7 +382,7 @@ static void test_trustee(void) "MultipleTrusteeOperation wrong\n"); ok( trustee.TrusteeForm == TRUSTEE_IS_SID, "TrusteeForm wrong\n"); ok( trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, "TrusteeType wrong\n"); - ok( trustee.ptstrName == (LPSTR) psid, "ptstrName wrong\n" ); + ok( trustee.ptstrName == psid, "ptstrName wrong\n" ); /* test BuildTrusteeWithObjectsAndSidA (test 1) */ memset( &trustee, 0xff, sizeof trustee ); @@ -492,7 +513,7 @@ static void test_trustee(void) #define SE_DEBUG_PRIVILEGE 20L #define SE_AUDIT_PRIVILEGE 21L #define SE_SYSTEM_ENVIRONMENT_PRIVILEGE 22L -#define SE_CHANGE_NOTIFY_PRIVILLEGE 23L +#define SE_CHANGE_NOTIFY_PRIVILEGE 23L #define SE_REMOTE_SHUTDOWN_PRIVILEGE 24L #define SE_UNDOCK_PRIVILEGE 25L #define SE_SYNC_AGENT_PRIVILEGE 26L @@ -567,7 +588,7 @@ static void test_lookupPrivilegeName(void) "SeCreateTokenPrivilege (got %d, expected %d)\n", cchName, (int)strlen("SeCreateTokenPrivilege")); /* check known values */ - for (i = SE_MIN_WELL_KNOWN_PRIVILEGE; i < SE_MAX_WELL_KNOWN_PRIVILEGE; i++) + for (i = SE_MIN_WELL_KNOWN_PRIVILEGE; i <= SE_MAX_WELL_KNOWN_PRIVILEGE; i++) { luid.LowPart = i; cchName = sizeof(buf); @@ -586,8 +607,9 @@ static void test_lookupPrivilegeName(void) luid.LowPart = SE_CREATE_TOKEN_PRIVILEGE; cchName = sizeof(buf); ret = pLookupPrivilegeNameA("b0gu5.Nam3", &luid, buf, &cchName); - ok( !ret && GetLastError() == RPC_S_SERVER_UNAVAILABLE, - "LookupPrivilegeNameA didn't fail with RPC_S_SERVER_UNAVAILABLE: %d\n", + ok( !ret && (GetLastError() == RPC_S_SERVER_UNAVAILABLE || + GetLastError() == RPC_S_INVALID_NET_ADDR) /* w2k8 */, + "LookupPrivilegeNameA didn't fail with RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR: %d\n", GetLastError()); } @@ -621,7 +643,7 @@ static void test_lookupPrivilegeValue(void) { "SeDebugPrivilege", SE_DEBUG_PRIVILEGE }, { "SeAuditPrivilege", SE_AUDIT_PRIVILEGE }, { "SeSystemEnvironmentPrivilege", SE_SYSTEM_ENVIRONMENT_PRIVILEGE }, - { "SeChangeNotifyPrivilege", SE_CHANGE_NOTIFY_PRIVILLEGE }, + { "SeChangeNotifyPrivilege", SE_CHANGE_NOTIFY_PRIVILEGE }, { "SeRemoteShutdownPrivilege", SE_REMOTE_SHUTDOWN_PRIVILEGE }, { "SeUndockPrivilege", SE_UNDOCK_PRIVILEGE }, { "SeSyncAgentPrivilege", SE_SYNC_AGENT_PRIVILEGE }, @@ -644,8 +666,9 @@ static void test_lookupPrivilegeValue(void) /* check a bogus system name */ ret = pLookupPrivilegeValueA("b0gu5.Nam3", "SeCreateTokenPrivilege", &luid); - ok( !ret && GetLastError() == RPC_S_SERVER_UNAVAILABLE, - "LookupPrivilegeValueA didn't fail with RPC_S_SERVER_UNAVAILABLE: %d\n", + ok( !ret && (GetLastError() == RPC_S_SERVER_UNAVAILABLE || + GetLastError() == RPC_S_INVALID_NET_ADDR) /* w2k8 */, + "LookupPrivilegeValueA didn't fail with RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR: %d\n", GetLastError()); /* check a NULL string */ ret = pLookupPrivilegeValueA(NULL, 0, &luid); @@ -685,31 +708,128 @@ static void test_luid(void) static void test_FileSecurity(void) { - char directory[MAX_PATH]; - DWORD retval, outSize; - BOOL result; - BYTE buffer[0x40]; + char wintmpdir [MAX_PATH]; + char path [MAX_PATH]; + char file [MAX_PATH]; + BOOL rc; + HANDLE fh; + DWORD sdSize; + DWORD retSize; + BYTE *sd; + SECURITY_INFORMATION const request = OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION; - pGetFileSecurityA = (fnGetFileSecurityA) - GetProcAddress( hmod, "GetFileSecurityA" ); - if( !pGetFileSecurityA ) - return; - - retval = GetTempPathA(sizeof(directory), directory); - if (!retval) { - trace("GetTempPathA failed\n"); + if (!pGetFileSecurityA) { + win_skip ("GetFileSecurity is not available\n"); return; } - strcpy(directory, "\\Should not exist"); + if (!pSetFileSecurityA) { + win_skip ("SetFileSecurity is not available\n"); + return; + } - SetLastError(NO_ERROR); - result = pGetFileSecurityA( directory,OWNER_SECURITY_INFORMATION,buffer,0x40,&outSize); - ok(!result, "GetFileSecurityA should fail for not existing directories/files\n"); - ok( (GetLastError() == ERROR_FILE_NOT_FOUND ) || - (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) , - "last error ERROR_FILE_NOT_FOUND / ERROR_CALL_NOT_IMPLEMENTED (98) " - "expected, got %d\n", GetLastError()); + if (!GetTempPathA (sizeof (wintmpdir), wintmpdir)) { + win_skip ("GetTempPathA failed\n"); + return; + } + + /* Create a temporary directory and in it a temporary file */ + strcat (strcpy (path, wintmpdir), "rary"); + SetLastError(0xdeadbeef); + rc = CreateDirectoryA (path, NULL); + ok (rc || GetLastError() == ERROR_ALREADY_EXISTS, "CreateDirectoryA " + "failed for '%s' with %d\n", path, GetLastError()); + + strcat (strcpy (file, path), "\\ess"); + SetLastError(0xdeadbeef); + fh = CreateFileA (file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + ok (fh != INVALID_HANDLE_VALUE, "CreateFileA " + "failed for '%s' with %d\n", file, GetLastError()); + CloseHandle (fh); + + /* For the temporary file ... */ + + /* Get size needed */ + retSize = 0; + SetLastError(0xdeadbeef); + rc = pGetFileSecurityA (file, request, NULL, 0, &retSize); + if (!rc && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { + win_skip("GetFileSecurityA is not implemented\n"); + goto cleanup; +} + ok (!rc, "GetFileSecurityA " + "was expected to fail for '%s'\n", file); + ok (GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetFileSecurityA " + "returned %d; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError()); + ok (retSize > sizeof (SECURITY_DESCRIPTOR), "GetFileSecurityA returned size %d\n", retSize); + + sdSize = retSize; + sd = HeapAlloc (GetProcessHeap (), 0, sdSize); + + /* Get security descriptor for real */ + retSize = -1; + SetLastError(0xdeadbeef); + rc = pGetFileSecurityA (file, request, sd, sdSize, &retSize); + ok (rc, "GetFileSecurityA " + "was not expected to fail '%s': %d\n", file, GetLastError()); + ok (retSize == sdSize || + broken(retSize == 0), /* NT4 */ + "GetFileSecurityA returned size %d; expected %d\n", retSize, sdSize); + + /* Use it to set security descriptor */ + SetLastError(0xdeadbeef); + rc = pSetFileSecurityA (file, request, sd); + ok (rc, "SetFileSecurityA " + "was not expected to fail '%s': %d\n", file, GetLastError()); + + HeapFree (GetProcessHeap (), 0, sd); + + /* Repeat for the temporary directory ... */ + + /* Get size needed */ + retSize = 0; + SetLastError(0xdeadbeef); + rc = pGetFileSecurityA (path, request, NULL, 0, &retSize); + ok (!rc, "GetFileSecurityA " + "was expected to fail for '%s'\n", path); + ok (GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetFileSecurityA " + "returned %d; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError()); + ok (retSize > sizeof (SECURITY_DESCRIPTOR), "GetFileSecurityA returned size %d\n", retSize); + + sdSize = retSize; + sd = HeapAlloc (GetProcessHeap (), 0, sdSize); + + /* Get security descriptor for real */ + retSize = -1; + SetLastError(0xdeadbeef); + rc = pGetFileSecurityA (path, request, sd, sdSize, &retSize); + ok (rc, "GetFileSecurityA " + "was not expected to fail '%s': %d\n", path, GetLastError()); + ok (retSize == sdSize || + broken(retSize == 0), /* NT4 */ + "GetFileSecurityA returned size %d; expected %d\n", retSize, sdSize); + + /* Use it to set security descriptor */ + SetLastError(0xdeadbeef); + rc = pSetFileSecurityA (path, request, sd); + ok (rc, "SetFileSecurityA " + "was not expected to fail '%s': %d\n", path, GetLastError()); + HeapFree (GetProcessHeap (), 0, sd); + + /* Old test */ + strcpy (wintmpdir, "\\Should not exist"); + SetLastError(0xdeadbeef); + rc = pGetFileSecurityA (wintmpdir, OWNER_SECURITY_INFORMATION, NULL, 0, &sdSize); + ok (!rc, "GetFileSecurityA should fail for not existing directories/files\n"); + ok (GetLastError() == ERROR_FILE_NOT_FOUND, + "last error ERROR_FILE_NOT_FOUND expected, got %d\n", GetLastError()); + +cleanup: + /* Remove temporary file and directory */ + DeleteFileA(file); + RemoveDirectoryA(path); } static void test_AccessCheck(void) @@ -731,6 +851,7 @@ static void test_AccessCheck(void) HMODULE NtDllModule; BOOLEAN Enabled; DWORD err; + NTSTATUS ntret, ntAccessStatus; NtDllModule = GetModuleHandle("ntdll.dll"); if (!NtDllModule) @@ -742,7 +863,7 @@ static void test_AccessCheck(void) GetProcAddress(NtDllModule, "RtlAdjustPrivilege"); if (!pRtlAdjustPrivilege) { - skip("missing RtlAdjustPrivilege, skipping test\n"); + win_skip("missing RtlAdjustPrivilege, skipping test\n"); return; } @@ -806,6 +927,7 @@ static void test_AccessCheck(void) /* Generic access mask */ SetLastError(0xdeadbeef); + Access = AccessStatus = 0xdeadbeef; ret = AccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping, PrivSet, &PrivSetLen, &Access, &AccessStatus); err = GetLastError(); @@ -814,7 +936,41 @@ static void test_AccessCheck(void) ok(Access == 0xdeadbeef && AccessStatus == 0xdeadbeef, "Access and/or AccessStatus were changed!\n"); + /* Generic access mask - no privilegeset buffer */ + SetLastError(0xdeadbeef); + Access = AccessStatus = 0xdeadbeef; + ret = AccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping, + NULL, &PrivSetLen, &Access, &AccessStatus); + err = GetLastError(); + ok(!ret && err == ERROR_NOACCESS, "AccessCheck should have failed " + "with ERROR_NOACCESS, instead of %d\n", err); + ok(Access == 0xdeadbeef && AccessStatus == 0xdeadbeef, + "Access and/or AccessStatus were changed!\n"); + + /* Generic access mask - no returnlength */ + SetLastError(0xdeadbeef); + Access = AccessStatus = 0xdeadbeef; + ret = AccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping, + PrivSet, NULL, &Access, &AccessStatus); + err = GetLastError(); + ok(!ret && err == ERROR_NOACCESS, "AccessCheck should have failed " + "with ERROR_NOACCESS, instead of %d\n", err); + ok(Access == 0xdeadbeef && AccessStatus == 0xdeadbeef, + "Access and/or AccessStatus were changed!\n"); + + /* Generic access mask - no privilegeset buffer, no returnlength */ + SetLastError(0xdeadbeef); + Access = AccessStatus = 0xdeadbeef; + ret = AccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping, + NULL, NULL, &Access, &AccessStatus); + err = GetLastError(); + ok(!ret && err == ERROR_NOACCESS, "AccessCheck should have failed " + "with ERROR_NOACCESS, instead of %d\n", err); + ok(Access == 0xdeadbeef && AccessStatus == 0xdeadbeef, + "Access and/or AccessStatus were changed!\n"); + /* sd with no dacl present */ + Access = AccessStatus = 0xdeadbeef; ret = SetSecurityDescriptorDacl(SecurityDescriptor, FALSE, NULL, FALSE); ok(ret, "SetSecurityDescriptorDacl failed with error %d\n", GetLastError()); ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping, @@ -824,7 +980,63 @@ static void test_AccessCheck(void) "AccessCheck failed to grant access with error %d\n", GetLastError()); + /* sd with no dacl present - no privilegeset buffer */ + SetLastError(0xdeadbeef); + Access = AccessStatus = 0xdeadbeef; + ret = AccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping, + NULL, &PrivSetLen, &Access, &AccessStatus); + err = GetLastError(); + ok(!ret && err == ERROR_NOACCESS, "AccessCheck should have failed " + "with ERROR_NOACCESS, instead of %d\n", err); + ok(Access == 0xdeadbeef && AccessStatus == 0xdeadbeef, + "Access and/or AccessStatus were changed!\n"); + + if(pNtAccessCheck) + { + /* Generic access mask - no privilegeset buffer */ + SetLastError(0xdeadbeef); + Access = ntAccessStatus = 0xdeadbeef; + ntret = pNtAccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping, + NULL, &PrivSetLen, &Access, &ntAccessStatus); + err = GetLastError(); + ok(ntret == STATUS_ACCESS_VIOLATION, + "NtAccessCheck should have failed with STATUS_ACCESS_VIOLATION, got %x\n", ntret); + ok(err == 0xdeadbeef, + "NtAccessCheck shouldn't set last error, got %d\n", err); + ok(Access == 0xdeadbeef && ntAccessStatus == 0xdeadbeef, + "Access and/or AccessStatus were changed!\n"); + + /* Generic access mask - no returnlength */ + SetLastError(0xdeadbeef); + Access = ntAccessStatus = 0xdeadbeef; + ntret = pNtAccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping, + PrivSet, NULL, &Access, &ntAccessStatus); + err = GetLastError(); + ok(ntret == STATUS_ACCESS_VIOLATION, + "NtAccessCheck should have failed with STATUS_ACCESS_VIOLATION, got %x\n", ntret); + ok(err == 0xdeadbeef, + "NtAccessCheck shouldn't set last error, got %d\n", err); + ok(Access == 0xdeadbeef && ntAccessStatus == 0xdeadbeef, + "Access and/or AccessStatus were changed!\n"); + + /* Generic access mask - no privilegeset buffer, no returnlength */ + SetLastError(0xdeadbeef); + Access = ntAccessStatus = 0xdeadbeef; + ntret = pNtAccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping, + NULL, NULL, &Access, &ntAccessStatus); + err = GetLastError(); + ok(ntret == STATUS_ACCESS_VIOLATION, + "NtAccessCheck should have failed with STATUS_ACCESS_VIOLATION, got %x\n", ntret); + ok(err == 0xdeadbeef, + "NtAccessCheck shouldn't set last error, got %d\n", err); + ok(Access == 0xdeadbeef && ntAccessStatus == 0xdeadbeef, + "Access and/or AccessStatus were changed!\n"); + } + else + win_skip("NtAccessCheck unavailable. Skipping.\n"); + /* sd with NULL dacl */ + Access = AccessStatus = 0xdeadbeef; ret = SetSecurityDescriptorDacl(SecurityDescriptor, TRUE, NULL, FALSE); ok(ret, "SetSecurityDescriptorDacl failed with error %d\n", GetLastError()); ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping, @@ -852,6 +1064,7 @@ static void test_AccessCheck(void) ok(res, "AddAccessDeniedAce failed with error %d\n", GetLastError()); /* sd with dacl */ + Access = AccessStatus = 0xdeadbeef; ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping, PrivSet, &PrivSetLen, &Access, &AccessStatus); ok(ret, "AccessCheck failed with error %d\n", GetLastError()); @@ -869,6 +1082,7 @@ static void test_AccessCheck(void) /* Access denied by SD */ SetLastError(0xdeadbeef); + Access = AccessStatus = 0xdeadbeef; ret = AccessCheck(SecurityDescriptor, Token, KEY_WRITE, &Mapping, PrivSet, &PrivSetLen, &Access, &AccessStatus); ok(ret, "AccessCheck failed with error %d\n", GetLastError()); @@ -920,7 +1134,7 @@ static void test_AccessCheck(void) ok(ret, "AddAccessAllowedAceEx failed with error %d\n", GetLastError()); } else - skip("AddAccessAllowedAceEx is not available\n"); + win_skip("AddAccessAllowedAceEx is not available\n"); ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping, PrivSet, &PrivSetLen, &Access, &AccessStatus); @@ -968,27 +1182,29 @@ static void test_AccessCheck(void) static void test_token_attr(void) { HANDLE Token, ImpersonationToken; - DWORD Size; + DWORD Size, Size2; TOKEN_PRIVILEGES *Privileges; TOKEN_GROUPS *Groups; TOKEN_USER *User; + TOKEN_DEFAULT_DACL *Dacl; BOOL ret; DWORD i, GLE; LPSTR SidString; SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + ACL *acl; /* cygwin-like use case */ SetLastError(0xdeadbeef); ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &Token); if(!ret && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("OpenProcessToken is not implemented\n"); + win_skip("OpenProcessToken is not implemented\n"); return; } ok(ret, "OpenProcessToken failed with error %d\n", GetLastError()); if (ret) { - BYTE buf[1024]; + DWORD buf[256]; /* GetTokenInformation wants a dword-aligned buffer */ Size = sizeof(buf); ret = GetTokenInformation(Token, TokenUser,(void*)buf, Size, &Size); ok(ret, "GetTokenInformation failed with error %d\n", GetLastError()); @@ -1001,12 +1217,12 @@ static void test_token_attr(void) if(!pConvertSidToStringSidA) { - skip("ConvertSidToStringSidA is not available\n"); + win_skip("ConvertSidToStringSidA is not available\n"); return; } SetLastError(0xdeadbeef); - ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &Token); + ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &Token); ok(ret, "OpenProcessToken failed with error %d\n", GetLastError()); /* groups */ @@ -1027,10 +1243,11 @@ static void test_token_attr(void) Domain[0] = '\0'; ret = LookupAccountSid(NULL, Groups->Groups[i].Sid, Name, &NameLength, Domain, &DomainLength, &SidNameUse); if (ret) - trace("\t%s, %s\\%s use: %d attr: 0x%08x\n", SidString, Domain, Name, SidNameUse, Groups->Groups[i].Attributes); - else - trace("\t%s, attr: 0x%08x LookupAccountSid failed with error %d\n", SidString, Groups->Groups[i].Attributes, GetLastError()); + { + trace("%s, %s\\%s use: %d attr: 0x%08x\n", SidString, Domain, Name, SidNameUse, Groups->Groups[i].Attributes); LocalFree(SidString); + } + else trace("attr: 0x%08x LookupAccountSid failed with error %d\n", Groups->Groups[i].Attributes, GetLastError()); } HeapFree(GetProcessHeap(), 0, Groups); @@ -1075,6 +1292,49 @@ static void test_token_attr(void) ok(ImpersonationLevel == SecurityAnonymous, "ImpersonationLevel should have been SecurityAnonymous instead of %d\n", ImpersonationLevel); CloseHandle(ImpersonationToken); + + /* default dacl */ + ret = GetTokenInformation(Token, TokenDefaultDacl, NULL, 0, &Size); + ok(!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), + "GetTokenInformation(TokenDefaultDacl) failed with error %u\n", GetLastError()); + + Dacl = HeapAlloc(GetProcessHeap(), 0, Size); + ret = GetTokenInformation(Token, TokenDefaultDacl, Dacl, Size, &Size); + ok(ret, "GetTokenInformation(TokenDefaultDacl) failed with error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = SetTokenInformation(Token, TokenDefaultDacl, NULL, 0); + GLE = GetLastError(); + ok(!ret, "SetTokenInformation(TokenDefaultDacl) succeeded\n"); + ok(GLE == ERROR_BAD_LENGTH, "expected ERROR_BAD_LENGTH got %u\n", GLE); + + SetLastError(0xdeadbeef); + ret = SetTokenInformation(Token, TokenDefaultDacl, NULL, Size); + GLE = GetLastError(); + ok(!ret, "SetTokenInformation(TokenDefaultDacl) succeeded\n"); + ok(GLE == ERROR_NOACCESS, "expected ERROR_NOACCESS got %u\n", GLE); + + acl = Dacl->DefaultDacl; + Dacl->DefaultDacl = NULL; + + ret = SetTokenInformation(Token, TokenDefaultDacl, Dacl, Size); + ok(ret, "SetTokenInformation(TokenDefaultDacl) succeeded\n"); + + Size2 = 0; + Dacl->DefaultDacl = (ACL *)0xdeadbeef; + ret = GetTokenInformation(Token, TokenDefaultDacl, Dacl, Size, &Size2); + ok(ret, "GetTokenInformation(TokenDefaultDacl) failed with error %u\n", GetLastError()); + ok(Dacl->DefaultDacl == NULL, "expected NULL, got %p\n", Dacl->DefaultDacl); + ok(Size2 == sizeof(TOKEN_DEFAULT_DACL), "got %u expected sizeof(TOKEN_DEFAULT_DACL)\n", Size2); + + Dacl->DefaultDacl = acl; + ret = SetTokenInformation(Token, TokenDefaultDacl, Dacl, Size); + ok(ret, "SetTokenInformation(TokenDefaultDacl) failed with error %u\n", GetLastError()); + + ret = GetTokenInformation(Token, TokenDefaultDacl, Dacl, Size, &Size2); + ok(ret, "GetTokenInformation(TokenDefaultDacl) failed with error %u\n", GetLastError()); + + HeapFree(GetProcessHeap(), 0, Dacl); CloseHandle(Token); } @@ -1143,18 +1403,39 @@ struct well_known_sid_value /* 74 */ {TRUE, "S-1-5-22"}, {FALSE, "S-1-5-21-12-23-34-45-56-521"}, {TRUE, "S-1-5-32-573"} }; -static void test_CreateWellKnownSid() +static void test_CreateWellKnownSid(void) { SID_IDENTIFIER_AUTHORITY ident = { SECURITY_NT_AUTHORITY }; - PSID domainsid; + PSID domainsid, sid; + DWORD size, error; + BOOL ret; int i; if (!pCreateWellKnownSid) { - skip("CreateWellKnownSid not available\n"); + win_skip("CreateWellKnownSid not available\n"); return; } + size = 0; + SetLastError(0xdeadbeef); + ret = pCreateWellKnownSid(WinInteractiveSid, NULL, NULL, &size); + error = GetLastError(); + ok(!ret, "CreateWellKnownSid succeeded\n"); + ok(error == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", error); + ok(size, "expected size > 0\n"); + + SetLastError(0xdeadbeef); + ret = pCreateWellKnownSid(WinInteractiveSid, NULL, NULL, &size); + error = GetLastError(); + ok(!ret, "CreateWellKnownSid succeeded\n"); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + + sid = HeapAlloc(GetProcessHeap(), 0, size); + ret = pCreateWellKnownSid(WinInteractiveSid, NULL, sid, &size); + ok(ret, "CreateWellKnownSid failed %u\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, sid); + /* a domain sid usually have three subauthorities but we test that CreateWellKnownSid doesn't check it */ AllocateAndInitializeSid(&ident, 6, SECURITY_NT_NON_UNIQUE, 12, 23, 34, 45, 56, 0, 0, &domainsid); @@ -1202,8 +1483,8 @@ static void test_CreateWellKnownSid() static void test_LookupAccountSid(void) { SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY }; - CHAR accountA[MAX_PATH], domainA[MAX_PATH]; - DWORD acc_sizeA, dom_sizeA; + CHAR accountA[MAX_PATH], domainA[MAX_PATH], usernameA[MAX_PATH]; + DWORD acc_sizeA, dom_sizeA, user_sizeA; DWORD real_acc_sizeA, real_dom_sizeA; WCHAR accountW[MAX_PATH], domainW[MAX_PATH]; DWORD acc_sizeW, dom_sizeW; @@ -1211,10 +1492,12 @@ static void test_LookupAccountSid(void) PSID pUsersSid = NULL; SID_NAME_USE use; BOOL ret; - DWORD size; + DWORD size,cbti = 0; MAX_SID max_sid; CHAR *str_sidA; int i; + HANDLE hToken; + PTOKEN_USER ptiUser = NULL; /* native windows crashes if account size, domain size, or name use is NULL */ @@ -1305,6 +1588,14 @@ static void test_LookupAccountSid(void) ret = LookupAccountSidW(NULL, pUsersSid, accountW, &real_acc_sizeW, domainW, &real_dom_sizeW, &use); ok(ret, "LookupAccountSidW() Expected TRUE, got FALSE\n"); + /* try an invalid system name */ + real_acc_sizeA = MAX_PATH; + real_dom_sizeA = MAX_PATH; + ret = LookupAccountSidA("deepthought", pUsersSid, accountA, &real_acc_sizeA, domainA, &real_dom_sizeA, &use); + ok(!ret, "LookupAccountSidA() Expected FALSE got TRUE\n"); + ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || GetLastError() == RPC_S_INVALID_NET_ADDR /* Vista */, + "LookupAccountSidA() Expected RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR, got %u\n", GetLastError()); + /* native windows crashes if domainW or accountW is NULL */ /* try a small account buffer */ @@ -1365,6 +1656,26 @@ static void test_LookupAccountSid(void) FreeSid(pUsersSid); + /* Test LookupAccountSid with Sid retrieved from token information. + This assumes this process is running under the account of the current user.*/ + ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &hToken); + ret = GetTokenInformation(hToken, TokenUser, NULL, 0, &cbti); + ptiUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap(), 0, cbti); + if (GetTokenInformation(hToken, TokenUser, ptiUser, cbti, &cbti)) + { + acc_sizeA = dom_sizeA = MAX_PATH; + ret = LookupAccountSidA(NULL, ptiUser->User.Sid, accountA, &acc_sizeA, domainA, &dom_sizeA, &use); + ok(ret, "LookupAccountSidA() Expected TRUE, got FALSE\n"); + user_sizeA = MAX_PATH; + ret = GetUserNameA(usernameA , &user_sizeA); + ok(ret, "GetUserNameA() Expected TRUE, got FALSE\n"); + todo_wine + { + ok(lstrcmpA(usernameA, accountA) == 0, "LookupAccountSidA() Expected account name: %s got: %s\n", usernameA, accountA ); + } + } + HeapFree(GetProcessHeap(), 0, ptiUser); + if (pCreateWellKnownSid && pConvertSidToStringSidA) { trace("Well Known SIDs:\n"); @@ -1468,7 +1779,7 @@ static void test_LookupAccountSid(void) } } -static void get_sid_info(PSID psid, LPSTR *user, LPSTR *dom) +static BOOL get_sid_info(PSID psid, LPSTR *user, LPSTR *dom) { static CHAR account[UNLEN + 1]; static CHAR domain[UNLEN + 1]; @@ -1481,7 +1792,65 @@ static void get_sid_info(PSID psid, LPSTR *user, LPSTR *dom) size = dom_size = UNLEN + 1; account[0] = '\0'; domain[0] = '\0'; - LookupAccountSidA(NULL, psid, account, &size, domain, &dom_size, &use); + SetLastError(0xdeadbeef); + return LookupAccountSidA(NULL, psid, account, &size, domain, &dom_size, &use); +} + +static void check_wellknown_name(const char* name, WELL_KNOWN_SID_TYPE result) +{ + SID_IDENTIFIER_AUTHORITY ident = { SECURITY_NT_AUTHORITY }; + PSID domainsid; + char wk_sid[SECURITY_MAX_SID_SIZE]; + DWORD cb; + + DWORD sid_size, domain_size; + SID_NAME_USE sid_use; + LPSTR domain, account, sid_domain, wk_domain, wk_account; + PSID psid; + BOOL ret ,ret2; + + sid_size = 0; + domain_size = 0; + ret = LookupAccountNameA(NULL, name, NULL, &sid_size, NULL, &domain_size, &sid_use); + psid = HeapAlloc(GetProcessHeap(),0,sid_size); + domain = HeapAlloc(GetProcessHeap(),0,domain_size); + ret = LookupAccountNameA(NULL, name, psid, &sid_size, domain, &domain_size, &sid_use); + + if (!result) + { + ok(!ret, " %s Should have failed to lookup account name\n",name); + goto cleanup; + } + + AllocateAndInitializeSid(&ident, 6, SECURITY_NT_NON_UNIQUE, 12, 23, 34, 45, 56, 0, 0, &domainsid); + cb = sizeof(wk_sid); + if (!pCreateWellKnownSid(result, domainsid, wk_sid, &cb)) + { + win_skip("SID %i is not available on the system\n",result); + goto cleanup; + } + + ret2 = get_sid_info(wk_sid, &wk_account, &wk_domain); + if (!ret2 && GetLastError() == ERROR_NONE_MAPPED) + { + win_skip("CreateWellKnownSid() succeeded but the account '%s' is not present (W2K)\n", name); + goto cleanup; + } + + get_sid_info(psid, &account, &sid_domain); + + ok(ret, "Failed to lookup account name %s\n",name); + ok(sid_size != 0, "sid_size was zero\n"); + + ok(EqualSid(psid,wk_sid),"(%s) Sids fail to match well known sid!\n",name); + + ok(!lstrcmp(account, wk_account), "Expected %s , got %s\n", account, wk_account); + ok(!lstrcmp(domain, wk_domain), "Expected %s, got %s\n", wk_domain, domain); + ok(sid_use == SidTypeWellKnownGroup , "Expected Use (5), got %d\n", sid_use); + +cleanup: + HeapFree(GetProcessHeap(),0,psid); + HeapFree(GetProcessHeap(),0,domain); } static void test_LookupAccountName(void) @@ -1489,6 +1858,7 @@ static void test_LookupAccountName(void) DWORD sid_size, domain_size, user_size; DWORD sid_save, domain_save; CHAR user_name[UNLEN + 1]; + CHAR computer_name[UNLEN + 1]; SID_NAME_USE sid_use; LPSTR domain, account, sid_dom; PSID psid; @@ -1520,7 +1890,7 @@ static void test_LookupAccountName(void) ret = LookupAccountNameA(NULL, user_name, NULL, &sid_size, NULL, &domain_size, &sid_use); if(!ret && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("LookupAccountNameA is not implemented\n"); + win_skip("LookupAccountNameA is not implemented\n"); return; } ok(!ret, "Expected 0, got %d\n", ret); @@ -1545,10 +1915,10 @@ static void test_LookupAccountName(void) { ok(!lstrcmp(account, user_name), "Expected %s, got %s\n", user_name, account); ok(!lstrcmp(domain, sid_dom), "Expected %s, got %s\n", sid_dom, domain); - ok(domain_size == domain_save - 1, "Expected %d, got %d\n", domain_save - 1, domain_size); - ok(lstrlen(domain) == domain_size, "Expected %d\n", lstrlen(domain)); - ok(sid_use == SidTypeUser, "Expected SidTypeUser, got %d\n", sid_use); } + ok(domain_size == domain_save - 1, "Expected %d, got %d\n", domain_save - 1, domain_size); + ok(lstrlen(domain) == domain_size, "Expected %d, got %d\n", lstrlen(domain), domain_size); + ok(sid_use == SidTypeUser, "Expected SidTypeUser (%d), got %d\n", SidTypeUser, sid_use); domain_size = domain_save; sid_size = sid_save; @@ -1563,12 +1933,10 @@ static void test_LookupAccountName(void) ok(ret, "Failed to lookup account name\n"); ok(sid_size != 0, "sid_size was zero\n"); ok(!lstrcmp(account, "Everyone"), "Expected Everyone, got %s\n", account); - todo_wine ok(!lstrcmp(domain, sid_dom), "Expected %s, got %s\n", sid_dom, domain); ok(domain_size == 0, "Expected 0, got %d\n", domain_size); - todo_wine ok(lstrlen(domain) == domain_size, "Expected %d, got %d\n", lstrlen(domain), domain_size); - ok(sid_use == SidTypeWellKnownGroup, "Expected SidTypeUser, got %d\n", sid_use); + ok(sid_use == SidTypeWellKnownGroup, "Expected SidTypeWellKnownGroup (%d), got %d\n", SidTypeWellKnownGroup, sid_use); domain_size = domain_save; } @@ -1611,6 +1979,10 @@ static void test_LookupAccountName(void) sid_use = 0xcafebabe; SetLastError(0xdeadbeef); ret = LookupAccountNameA(NULL, NULL, NULL, &sid_size, NULL, &domain_size, &sid_use); + if (!ret && GetLastError() == ERROR_NONE_MAPPED) + win_skip("NULL account name doesn't work on NT4\n"); + else + { ok(!ret, "Expected 0, got %d\n", ret); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); @@ -1625,13 +1997,14 @@ static void test_LookupAccountName(void) ret = LookupAccountNameA(NULL, NULL, psid, &sid_size, domain, &domain_size, &sid_use); get_sid_info(psid, &account, &sid_dom); ok(ret, "Failed to lookup account name\n"); - todo_wine - { /* Using a fixed string will not work on different locales */ ok(!lstrcmp(account, domain), "Got %s for account and %s for domain, these should be the same\n", account, domain); - ok(sid_use == SidTypeDomain, "Expected SidTypeDomain, got %d\n", SidTypeDomain); + ok(sid_use == SidTypeDomain, "Expected SidTypeDomain (%d), got %d\n", SidTypeDomain, sid_use); + + HeapFree(GetProcessHeap(), 0, psid); + HeapFree(GetProcessHeap(), 0, domain); } /* try an invalid account name */ @@ -1640,16 +2013,85 @@ static void test_LookupAccountName(void) domain_size = 0; ret = LookupAccountNameA(NULL, "oogabooga", NULL, &sid_size, NULL, &domain_size, &sid_use); ok(!ret, "Expected 0, got %d\n", ret); - todo_wine - { - ok(GetLastError() == ERROR_NONE_MAPPED, + ok(GetLastError() == ERROR_NONE_MAPPED || + broken(GetLastError() == ERROR_TRUSTED_RELATIONSHIP_FAILURE), "Expected ERROR_NONE_MAPPED, got %d\n", GetLastError()); ok(sid_size == 0, "Expected 0, got %d\n", sid_size); ok(domain_size == 0, "Expected 0, got %d\n", domain_size); + + /* try an invalid system name */ + SetLastError(0xdeadbeef); + sid_size = 0; + domain_size = 0; + ret = LookupAccountNameA("deepthought", NULL, NULL, &sid_size, NULL, &domain_size, &sid_use); + ok(!ret, "Expected 0, got %d\n", ret); + ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || GetLastError() == RPC_S_INVALID_NET_ADDR /* Vista */, + "Expected RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR, got %d\n", GetLastError()); + ok(sid_size == 0, "Expected 0, got %d\n", sid_size); + ok(domain_size == 0, "Expected 0, got %d\n", domain_size); + + /* try with the computer name as the account name */ + domain_size = sizeof(computer_name); + GetComputerNameA(computer_name, &domain_size); + sid_size = 0; + domain_size = 0; + ret = LookupAccountNameA(NULL, computer_name, NULL, &sid_size, NULL, &domain_size, &sid_use); + ok(!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER || + GetLastError() == ERROR_NONE_MAPPED /* in a domain */ || + broken(GetLastError() == ERROR_TRUSTED_DOMAIN_FAILURE) || + broken(GetLastError() == ERROR_TRUSTED_RELATIONSHIP_FAILURE)), + "LookupAccountNameA failed: %d\n", GetLastError()); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + psid = HeapAlloc(GetProcessHeap(), 0, sid_size); + domain = HeapAlloc(GetProcessHeap(), 0, domain_size); + ret = LookupAccountNameA(NULL, computer_name, psid, &sid_size, domain, &domain_size, &sid_use); + ok(ret, "LookupAccountNameA failed: %d\n", GetLastError()); + ok(sid_use == SidTypeDomain, "expected SidTypeDomain, got %d\n", sid_use); + HeapFree(GetProcessHeap(), 0, domain); + HeapFree(GetProcessHeap(), 0, psid); +} + + /* Well Known names */ + if (!pCreateWellKnownSid) + { + win_skip("CreateWellKnownSid not available\n"); + return; } - HeapFree(GetProcessHeap(), 0, psid); - HeapFree(GetProcessHeap(), 0, domain); + if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH) + { + skip("Non-english locale (skipping well known name creation tests)\n"); + return; + } + + check_wellknown_name("LocalService", WinLocalServiceSid); + check_wellknown_name("Local Service", WinLocalServiceSid); + /* 2 spaces */ + check_wellknown_name("Local Service", 0); + check_wellknown_name("NetworkService", WinNetworkServiceSid); + check_wellknown_name("Network Service", WinNetworkServiceSid); + + /* example of some names where the spaces are not optional */ + check_wellknown_name("Terminal Server User", WinTerminalServerSid); + check_wellknown_name("TerminalServer User", 0); + check_wellknown_name("TerminalServerUser", 0); + check_wellknown_name("Terminal ServerUser", 0); + + check_wellknown_name("enterprise domain controllers",WinEnterpriseControllersSid); + check_wellknown_name("enterprisedomain controllers", 0); + check_wellknown_name("enterprise domaincontrollers", 0); + check_wellknown_name("enterprisedomaincontrollers", 0); + + /* case insensitivity */ + check_wellknown_name("lOCAlServICE", WinLocalServiceSid); + + /* fully qualified account names */ + check_wellknown_name("NT AUTHORITY\\LocalService", WinLocalServiceSid); + check_wellknown_name("nt authority\\Network Service", WinNetworkServiceSid); + check_wellknown_name("nt authority test\\Network Service", 0); + check_wellknown_name("Dummy\\Network Service", 0); + check_wellknown_name("ntauthority\\Network Service", 0); } static void test_security_descriptor(void) @@ -1665,7 +2107,7 @@ static void test_security_descriptor(void) ret = InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("InitializeSecurityDescriptor is not implemented\n"); + win_skip("InitializeSecurityDescriptor is not implemented\n"); return; } @@ -1699,8 +2141,10 @@ static void test_security_descriptor(void) } } -#define TEST_GRANTED_ACCESS(a,b) test_granted_access(a,b,__LINE__) -static void test_granted_access(HANDLE handle, ACCESS_MASK access, int line) +#define TEST_GRANTED_ACCESS(a,b) test_granted_access(a,b,0,__LINE__) +#define TEST_GRANTED_ACCESS2(a,b,c) test_granted_access(a,b,c,__LINE__) +static void test_granted_access(HANDLE handle, ACCESS_MASK access, + ACCESS_MASK alt, int line) { OBJECT_BASIC_INFORMATION obj_info; NTSTATUS status; @@ -1714,6 +2158,11 @@ static void test_granted_access(HANDLE handle, ACCESS_MASK access, int line) status = pNtQueryObject( handle, ObjectBasicInformation, &obj_info, sizeof(obj_info), NULL ); ok_(__FILE__, line)(!status, "NtQueryObject with err: %08x\n", status); + if (alt) + ok_(__FILE__, line)(obj_info.GrantedAccess == access || + obj_info.GrantedAccess == alt, "Granted access should be 0x%08x " + "or 0x%08x, instead of 0x%08x\n", access, alt, obj_info.GrantedAccess); + else ok_(__FILE__, line)(obj_info.GrantedAccess == access, "Granted access should " "be 0x%08x, instead of 0x%08x\n", access, obj_info.GrantedAccess); } @@ -1735,7 +2184,8 @@ static void test_granted_access(HANDLE handle, ACCESS_MASK access, int line) static void test_process_security(void) { BOOL res; - char owner[32], group[32]; + PTOKEN_OWNER owner; + PTOKEN_PRIMARY_GROUP group; PSID AdminSid = NULL, UsersSid = NULL; PACL Acl = NULL; SECURITY_DESCRIPTOR *SecurityDescriptor = NULL; @@ -1744,13 +2194,13 @@ static void test_process_security(void) STARTUPINFOA startup; SECURITY_ATTRIBUTES psa; HANDLE token, event; - DWORD tmp; + DWORD size; Acl = HeapAlloc(GetProcessHeap(), 0, 256); res = InitializeAcl(Acl, 256, ACL_REVISION); if (!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("ACLs not implemented - skipping tests\n"); + win_skip("ACLs not implemented - skipping tests\n"); HeapFree(GetProcessHeap(), 0, Acl); return; } @@ -1765,16 +2215,31 @@ static void test_process_security(void) return; } - res = GetTokenInformation( token, TokenOwner, owner, sizeof(owner), &tmp ); + res = GetTokenInformation( token, TokenOwner, NULL, 0, &size ); + ok(!res, "Expected failure, got %d\n", res); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + + owner = HeapAlloc(GetProcessHeap(), 0, size); + res = GetTokenInformation( token, TokenOwner, owner, size, &size ); ok(res, "GetTokenInformation failed with error %d\n", GetLastError()); AdminSid = ((TOKEN_OWNER*)owner)->Owner; - res = GetTokenInformation( token, TokenPrimaryGroup, group, sizeof(group), &tmp ); + + res = GetTokenInformation( token, TokenPrimaryGroup, NULL, 0, &size ); + ok(!res, "Expected failure, got %d\n", res); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + + group = HeapAlloc(GetProcessHeap(), 0, size); + res = GetTokenInformation( token, TokenPrimaryGroup, group, size, &size ); ok(res, "GetTokenInformation failed with error %d\n", GetLastError()); UsersSid = ((TOKEN_PRIMARY_GROUP*)group)->PrimaryGroup; CloseHandle( token ); if (!res) { + HeapFree(GetProcessHeap(), 0, group); + HeapFree(GetProcessHeap(), 0, owner); HeapFree(GetProcessHeap(), 0, Acl); return; } @@ -1827,12 +2292,15 @@ static void test_process_security(void) /* Doesn't matter what ACL say we should get full access for ourselves */ ok(CreateProcessA( NULL, buffer, &psa, NULL, FALSE, 0, NULL, NULL, &startup, &info ), "CreateProcess with err:%d\n", GetLastError()); - TEST_GRANTED_ACCESS( info.hProcess, PROCESS_ALL_ACCESS ); + TEST_GRANTED_ACCESS2( info.hProcess, PROCESS_ALL_ACCESS, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL ); winetest_wait_child_process( info.hProcess ); CloseHandle( info.hProcess ); CloseHandle( info.hThread ); CloseHandle( event ); + HeapFree(GetProcessHeap(), 0, group); + HeapFree(GetProcessHeap(), 0, owner); HeapFree(GetProcessHeap(), 0, Acl); HeapFree(GetProcessHeap(), 0, SecurityDescriptor); } @@ -1876,7 +2344,8 @@ static void test_process_security_child(void) ok(DuplicateHandle( GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS ), "duplicating handle err:%d\n", GetLastError()); - TEST_GRANTED_ACCESS( handle, PROCESS_ALL_ACCESS ); + TEST_GRANTED_ACCESS2( handle, PROCESS_ALL_ACCESS, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL ); CloseHandle( handle ); @@ -1884,7 +2353,8 @@ static void test_process_security_child(void) ok(DuplicateHandle( GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &handle, PROCESS_ALL_ACCESS, TRUE, 0 ), "duplicating handle err:%d\n", GetLastError()); - TEST_GRANTED_ACCESS( handle, PROCESS_ALL_ACCESS ); + TEST_GRANTED_ACCESS2( handle, PROCESS_ALL_ACCESS, + PROCESS_ALL_ACCESS | PROCESS_QUERY_LIMITED_INFORMATION ); ok(DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle1, PROCESS_VM_READ, TRUE, 0 ), "duplicating handle err:%d\n", GetLastError()); @@ -1908,14 +2378,14 @@ static void test_impersonation_level(void) pDuplicateTokenEx = (fnDuplicateTokenEx) GetProcAddress(hmod, "DuplicateTokenEx"); if( !pDuplicateTokenEx ) { - skip("DuplicateTokenEx is not available\n"); + win_skip("DuplicateTokenEx is not available\n"); return; } SetLastError(0xdeadbeef); ret = ImpersonateSelf(SecurityAnonymous); if(!ret && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("ImpersonateSelf is not implemented\n"); + win_skip("ImpersonateSelf is not implemented\n"); return; } ok(ret, "ImpersonateSelf(SecurityAnonymous) failed with error %d\n", GetLastError()); @@ -1926,7 +2396,8 @@ static void test_impersonation_level(void) /* can't perform access check when opening object against an anonymous impersonation token */ todo_wine { error = RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey); - ok(error == ERROR_INVALID_HANDLE, "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE instead of %d\n", error); + ok(error == ERROR_INVALID_HANDLE || error == ERROR_CANT_OPEN_ANONYMOUS, + "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE or ERROR_CANT_OPEN_ANONYMOUS instead of %d\n", error); } RevertToSelf(); @@ -1946,7 +2417,7 @@ static void test_impersonation_level(void) ret = GetTokenInformation(Token, TokenUser, NULL, 0, &Size); error = GetLastError(); ok(!ret && error == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenUser) should have failed with ERROR_INSUFFICIENT_BUFFER instead of %d\n", error); - User = (TOKEN_USER *)HeapAlloc(GetProcessHeap(), 0, Size); + User = HeapAlloc(GetProcessHeap(), 0, Size); ret = GetTokenInformation(Token, TokenUser, User, Size, &Size); ok(ret, "GetTokenInformation(TokenUser) failed with error %d\n", GetLastError()); HeapFree(GetProcessHeap(), 0, User); @@ -1955,11 +2426,11 @@ static void test_impersonation_level(void) ret = GetTokenInformation(Token, TokenPrivileges, NULL, 0, &Size); error = GetLastError(); ok(!ret && error == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenPrivileges) should have failed with ERROR_INSUFFICIENT_BUFFER instead of %d\n", error); - Privileges = (TOKEN_PRIVILEGES *)HeapAlloc(GetProcessHeap(), 0, Size); + Privileges = HeapAlloc(GetProcessHeap(), 0, Size); ret = GetTokenInformation(Token, TokenPrivileges, Privileges, Size, &Size); ok(ret, "GetTokenInformation(TokenPrivileges) failed with error %d\n", GetLastError()); - PrivilegeSet = (PRIVILEGE_SET *)HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(PRIVILEGE_SET, Privilege[Privileges->PrivilegeCount])); + PrivilegeSet = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(PRIVILEGE_SET, Privilege[Privileges->PrivilegeCount])); PrivilegeSet->PrivilegeCount = Privileges->PrivilegeCount; memcpy(PrivilegeSet->Privilege, Privileges->Privileges, PrivilegeSet->PrivilegeCount * sizeof(PrivilegeSet->Privilege[0])); PrivilegeSet->Control = PRIVILEGE_SET_ALL_NECESSARY; @@ -1979,7 +2450,8 @@ static void test_impersonation_level(void) /* can't perform access check when opening object against an identification impersonation token */ error = RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey); todo_wine { - ok(error == ERROR_INVALID_HANDLE, "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE instead of %d\n", error); + ok(error == ERROR_INVALID_HANDLE || error == ERROR_BAD_IMPERSONATION_LEVEL, + "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE or ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error); } ret = PrivilegeCheck(Token, PrivilegeSet, &AccessGranted); ok(ret, "PrivilegeCheck for SecurityIdentification failed with error %d\n", GetLastError()); @@ -2012,10 +2484,11 @@ static void test_SetEntriesInAcl(void) SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY }; EXPLICIT_ACCESSW ExplicitAccess; static const WCHAR wszEveryone[] = {'E','v','e','r','y','o','n','e',0}; + static const WCHAR wszCurrentUser[] = { 'C','U','R','R','E','N','T','_','U','S','E','R','\0'}; if (!pSetEntriesInAclW) { - skip("SetEntriesInAclW is not available\n"); + win_skip("SetEntriesInAclW is not available\n"); return; } @@ -2023,17 +2496,20 @@ static void test_SetEntriesInAcl(void) res = pSetEntriesInAclW(0, NULL, NULL, &NewAcl); if(res == ERROR_CALL_NOT_IMPLEMENTED) { - skip("SetEntriesInAclW is not implemented\n"); + win_skip("SetEntriesInAclW is not implemented\n"); return; } ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res); - ok(NewAcl == NULL, "NewAcl=%p, expected NULL\n", NewAcl); + ok(NewAcl == NULL || + broken(NewAcl != NULL), /* NT4 */ + "NewAcl=%p, expected NULL\n", NewAcl); + LocalFree(NewAcl); OldAcl = HeapAlloc(GetProcessHeap(), 0, 256); res = InitializeAcl(OldAcl, 256, ACL_REVISION); if(!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("ACLs not implemented - skipping tests\n"); + win_skip("ACLs not implemented - skipping tests\n"); HeapFree(GetProcessHeap(), 0, OldAcl); return; } @@ -2056,7 +2532,7 @@ static void test_SetEntriesInAcl(void) ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID; ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; - ExplicitAccess.Trustee.ptstrName = (LPWSTR)EveryoneSid; + ExplicitAccess.Trustee.ptstrName = EveryoneSid; res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl); ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res); ok(NewAcl != NULL, "returned acl was NULL\n"); @@ -2077,16 +2553,22 @@ static void test_SetEntriesInAcl(void) ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_BAD_FORM; res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl); - ok(res == ERROR_INVALID_PARAMETER, "SetEntriesInAclW failed: %u\n", res); - ok(NewAcl == NULL, "returned acl wasn't NULL: %p\n", NewAcl); - LocalFree(NewAcl); + ok(res == ERROR_INVALID_PARAMETER || + broken(res == ERROR_NOT_SUPPORTED), /* NT4 */ + "SetEntriesInAclW failed: %u\n", res); + ok(NewAcl == NULL || + broken(NewAcl != NULL), /* NT4 */ + "returned acl wasn't NULL: %p\n", NewAcl); ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_USER; ExplicitAccess.Trustee.MultipleTrusteeOperation = TRUSTEE_IS_IMPERSONATE; res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl); - ok(res == ERROR_INVALID_PARAMETER, "SetEntriesInAclW failed: %u\n", res); - ok(NewAcl == NULL, "returned acl wasn't NULL: %p\n", NewAcl); - LocalFree(NewAcl); + ok(res == ERROR_INVALID_PARAMETER || + broken(res == ERROR_NOT_SUPPORTED), /* NT4 */ + "SetEntriesInAclW failed: %u\n", res); + ok(NewAcl == NULL || + broken(NewAcl != NULL), /* NT4 */ + "returned acl wasn't NULL: %p\n", NewAcl); ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ExplicitAccess.grfAccessMode = SET_ACCESS; @@ -2096,9 +2578,16 @@ static void test_SetEntriesInAcl(void) LocalFree(NewAcl); } + ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_USER; + ExplicitAccess.Trustee.ptstrName = (LPWSTR)wszCurrentUser; + res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl); + ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res); + ok(NewAcl != NULL, "returned acl was NULL\n"); + LocalFree(NewAcl); + ExplicitAccess.grfAccessMode = REVOKE_ACCESS; ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID; - ExplicitAccess.Trustee.ptstrName = (LPWSTR)UsersSid; + ExplicitAccess.Trustee.ptstrName = UsersSid; res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl); ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res); ok(NewAcl != NULL, "returned acl was NULL\n"); @@ -2124,7 +2613,7 @@ static void test_GetNamedSecurityInfoA(void) if (!pGetNamedSecurityInfoA) { - skip("GetNamedSecurityInfoA is not available\n"); + win_skip("GetNamedSecurityInfoA is not available\n"); return; } @@ -2137,14 +2626,15 @@ static void test_GetNamedSecurityInfoA(void) NULL, NULL, NULL, NULL, &pSecDesc); if (error != ERROR_SUCCESS && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("GetNamedSecurityInfoA is not implemented\n"); + win_skip("GetNamedSecurityInfoA is not implemented\n"); return; } ok(!error, "GetNamedSecurityInfo failed with error %d\n", error); ret = GetSecurityDescriptorControl(pSecDesc, &control, &revision); ok(ret, "GetSecurityDescriptorControl failed with error %d\n", GetLastError()); - ok((control & (SE_SELF_RELATIVE|SE_DACL_PRESENT)) == (SE_SELF_RELATIVE|SE_DACL_PRESENT), + ok((control & (SE_SELF_RELATIVE|SE_DACL_PRESENT)) == (SE_SELF_RELATIVE|SE_DACL_PRESENT) || + broken((control & (SE_SELF_RELATIVE|SE_DACL_PRESENT)) == SE_DACL_PRESENT), /* NT4 */ "control (0x%x) doesn't have (SE_SELF_RELATIVE|SE_DACL_PRESENT) flags set\n", control); ok(revision == SECURITY_DESCRIPTOR_REVISION1, "revision was %d instead of 1\n", revision); ret = GetSecurityDescriptorOwner(pSecDesc, &owner, &owner_defaulted); @@ -2153,16 +2643,18 @@ static void test_GetNamedSecurityInfoA(void) ret = GetSecurityDescriptorGroup(pSecDesc, &group, &group_defaulted); ok(ret, "GetSecurityDescriptorGroup failed with error %d\n", GetLastError()); ok(group != NULL, "group should not be NULL\n"); + LocalFree(pSecDesc); } static void test_ConvertStringSecurityDescriptor(void) { BOOL ret; PSECURITY_DESCRIPTOR pSD; + static const WCHAR Blank[] = { 0 }; if (!pConvertStringSecurityDescriptorToSecurityDescriptorA) { - skip("ConvertStringSecurityDescriptorToSecurityDescriptor is not available\n"); + win_skip("ConvertStringSecurityDescriptorToSecurityDescriptor is not available\n"); return; } @@ -2239,11 +2731,51 @@ static void test_ConvertStringSecurityDescriptor(void) SetLastError(0xdeadbeef); ret = pConvertStringSecurityDescriptorToSecurityDescriptorA( "D:(A;;ROB;;;WD)", SDDL_REVISION_1, &pSD, NULL); - todo_wine ok(!ret && GetLastError() == ERROR_INVALID_ACL, "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_ACL instead of %d\n", GetLastError()); + /* test behaviour with NULL parameters */ + SetLastError(0xdeadbeef); + ret = pConvertStringSecurityDescriptorToSecurityDescriptorA( + NULL, 0xdeadbeef, &pSD, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pConvertStringSecurityDescriptorToSecurityDescriptorW( + NULL, 0xdeadbeef, &pSD, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pConvertStringSecurityDescriptorToSecurityDescriptorA( + "D:(A;;ROB;;;WD)", 0xdeadbeef, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pConvertStringSecurityDescriptorToSecurityDescriptorA( + "D:(A;;ROB;;;WD)", SDDL_REVISION_1, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n", + GetLastError()); + + /* test behaviour with empty strings */ + SetLastError(0xdeadbeef); + ret = pConvertStringSecurityDescriptorToSecurityDescriptorA( + "", SDDL_REVISION_1, &pSD, NULL); + ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pConvertStringSecurityDescriptorToSecurityDescriptorW( + Blank, SDDL_REVISION_1, &pSD, NULL); + ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError()); + /* test ACE string SID */ SetLastError(0xdeadbeef); ret = pConvertStringSecurityDescriptorToSecurityDescriptorA( @@ -2259,7 +2791,7 @@ static void test_ConvertStringSecurityDescriptor(void) "Expected ERROR_INVALID_ACL or ERROR_INVALID_SID, got %d\n", GetLastError()); } -static void test_ConvertSecurityDescriptorToString() +static void test_ConvertSecurityDescriptorToString(void) { SECURITY_DESCRIPTOR desc; SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION; @@ -2273,12 +2805,12 @@ static void test_ConvertSecurityDescriptorToString() if (!pConvertSecurityDescriptorToStringSecurityDescriptorA) { - skip("ConvertSecurityDescriptorToStringSecurityDescriptor is not available\n"); + win_skip("ConvertSecurityDescriptorToStringSecurityDescriptor is not available\n"); return; } if (!pCreateWellKnownSid) { - skip("CreateWellKnownSid is not available\n"); + win_skip("CreateWellKnownSid is not available\n"); return; } @@ -2300,17 +2832,17 @@ static void test_ConvertSecurityDescriptorToString() size = 4096; pCreateWellKnownSid(WinLocalSid, NULL, sid_buf, &size); - SetSecurityDescriptorOwner(&desc, (PSID)sid_buf, FALSE); + SetSecurityDescriptorOwner(&desc, sid_buf, FALSE); ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n"); CHECK_RESULT_AND_FREE("O:S-1-2-0"); - SetSecurityDescriptorOwner(&desc, (PSID)sid_buf, TRUE); + SetSecurityDescriptorOwner(&desc, sid_buf, TRUE); ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n"); CHECK_RESULT_AND_FREE("O:S-1-2-0"); size = sizeof(sid_buf); pCreateWellKnownSid(WinLocalSystemSid, NULL, sid_buf, &size); - SetSecurityDescriptorOwner(&desc, (PSID)sid_buf, TRUE); + SetSecurityDescriptorOwner(&desc, sid_buf, TRUE); ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n"); CHECK_RESULT_AND_FREE("O:SY"); @@ -2370,6 +2902,95 @@ static void test_ConvertSecurityDescriptorToString() } } +static void test_SetSecurityDescriptorControl (PSECURITY_DESCRIPTOR sec) +{ + SECURITY_DESCRIPTOR_CONTROL ref; + SECURITY_DESCRIPTOR_CONTROL test; + + SECURITY_DESCRIPTOR_CONTROL const mutable + = SE_DACL_AUTO_INHERIT_REQ | SE_SACL_AUTO_INHERIT_REQ + | SE_DACL_AUTO_INHERITED | SE_SACL_AUTO_INHERITED + | SE_DACL_PROTECTED | SE_SACL_PROTECTED + | 0x00000040 | 0x00000080 /* not defined in winnt.h */ + ; + SECURITY_DESCRIPTOR_CONTROL const immutable + = SE_OWNER_DEFAULTED | SE_GROUP_DEFAULTED + | SE_DACL_PRESENT | SE_DACL_DEFAULTED + | SE_SACL_PRESENT | SE_SACL_DEFAULTED + | SE_RM_CONTROL_VALID | SE_SELF_RELATIVE + ; + + int bit; + DWORD dwRevision; + LPCSTR fmt = "Expected error %s, got %u\n"; + + GetSecurityDescriptorControl (sec, &ref, &dwRevision); + + /* The mutable bits are mutable regardless of the truth of + SE_DACL_PRESENT and/or SE_SACL_PRESENT */ + + /* Check call barfs if any bit-of-interest is immutable */ + for (bit = 0; bit < 16; ++bit) + { + SECURITY_DESCRIPTOR_CONTROL const bitOfInterest = 1 << bit; + SECURITY_DESCRIPTOR_CONTROL setOrClear = ref & bitOfInterest; + + SECURITY_DESCRIPTOR_CONTROL ctrl; + + DWORD dwExpect = (bitOfInterest & immutable) + ? ERROR_INVALID_PARAMETER : 0xbebecaca; + LPCSTR strExpect = (bitOfInterest & immutable) + ? "ERROR_INVALID_PARAMETER" : "0xbebecaca"; + + ctrl = (bitOfInterest & mutable) ? ref + bitOfInterest : ref; + setOrClear ^= bitOfInterest; + SetLastError (0xbebecaca); + pSetSecurityDescriptorControl (sec, bitOfInterest, setOrClear); + ok (GetLastError () == dwExpect, fmt, strExpect, GetLastError ()); + GetSecurityDescriptorControl(sec, &test, &dwRevision); + expect_eq(test, ctrl, int, "%x"); + + ctrl = ref; + setOrClear ^= bitOfInterest; + SetLastError (0xbebecaca); + pSetSecurityDescriptorControl (sec, bitOfInterest, setOrClear); + ok (GetLastError () == dwExpect, fmt, strExpect, GetLastError ()); + GetSecurityDescriptorControl (sec, &test, &dwRevision); + expect_eq(test, ref, int, "%x"); + } + + /* Check call barfs if any bit-to-set is immutable + even when not a bit-of-interest */ + for (bit = 0; bit < 16; ++bit) + { + SECURITY_DESCRIPTOR_CONTROL const bitsOfInterest = mutable; + SECURITY_DESCRIPTOR_CONTROL setOrClear = ref & bitsOfInterest; + + SECURITY_DESCRIPTOR_CONTROL ctrl; + + DWORD dwExpect = ((1 << bit) & immutable) + ? ERROR_INVALID_PARAMETER : 0xbebecaca; + LPCSTR strExpect = ((1 << bit) & immutable) + ? "ERROR_INVALID_PARAMETER" : "0xbebecaca"; + + ctrl = ((1 << bit) & immutable) ? test : ref | mutable; + setOrClear ^= bitsOfInterest; + SetLastError (0xbebecaca); + pSetSecurityDescriptorControl (sec, bitsOfInterest, setOrClear | (1 << bit)); + ok (GetLastError () == dwExpect, fmt, strExpect, GetLastError ()); + GetSecurityDescriptorControl(sec, &test, &dwRevision); + expect_eq(test, ctrl, int, "%x"); + + ctrl = ((1 << bit) & immutable) ? test : ref | (1 << bit); + setOrClear ^= bitsOfInterest; + SetLastError (0xbebecaca); + pSetSecurityDescriptorControl (sec, bitsOfInterest, setOrClear | (1 << bit)); + ok (GetLastError () == dwExpect, fmt, strExpect, GetLastError ()); + GetSecurityDescriptorControl(sec, &test, &dwRevision); + expect_eq(test, ctrl, int, "%x"); + } +} + static void test_PrivateObjectSecurity(void) { SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION; @@ -2384,10 +3005,31 @@ static void test_PrivateObjectSecurity(void) if (!pConvertStringSecurityDescriptorToSecurityDescriptorA) { - skip("ConvertStringSecurityDescriptorToSecurityDescriptor is not available\n"); + win_skip("ConvertStringSecurityDescriptorToSecurityDescriptor is not available\n"); return; } + ok(pConvertStringSecurityDescriptorToSecurityDescriptorA( + "O:SY" + "G:S-1-5-21-93476-23408-4576" + "D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)" + "(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)" + "S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)", + SDDL_REVISION_1, &sec, &dwDescSize), "Creating descriptor failed\n"); + + test_SetSecurityDescriptorControl(sec); + + LocalFree(sec); + + ok(pConvertStringSecurityDescriptorToSecurityDescriptorA( + "O:SY" + "G:S-1-5-21-93476-23408-4576", + SDDL_REVISION_1, &sec, &dwDescSize), "Creating descriptor failed\n"); + + test_SetSecurityDescriptorControl(sec); + + LocalFree(sec); + ok(pConvertStringSecurityDescriptorToSecurityDescriptorA( "O:SY" "G:S-1-5-21-93476-23408-4576" @@ -2396,7 +3038,7 @@ static void test_PrivateObjectSecurity(void) buf = HeapAlloc(GetProcessHeap(), 0, dwDescSize); pSetSecurityDescriptorControl(sec, SE_DACL_PROTECTED, SE_DACL_PROTECTED); GetSecurityDescriptorControl(sec, &ctrl, &dwRevision); - todo_wine expect_eq(ctrl, 0x9014, int, "%x"); + expect_eq(ctrl, 0x9014, int, "%x"); ok(GetPrivateObjectSecurity(sec, GROUP_SECURITY_INFORMATION, buf, dwDescSize, &retSize), "GetPrivateObjectSecurity failed (err=%u)\n", GetLastError()); @@ -2410,20 +3052,25 @@ static void test_PrivateObjectSecurity(void) "GetPrivateObjectSecurity failed (err=%u)\n", GetLastError()); ok(retSize <= dwDescSize, "Buffer too small (%d vs %d)\n", retSize, dwDescSize); ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(buf, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed err=%u\n", GetLastError()); - CHECK_RESULT_AND_FREE("G:S-1-5-21-93476-23408-4576D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)"); + CHECK_ONE_OF_AND_FREE("G:S-1-5-21-93476-23408-4576D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)", + "G:S-1-5-21-93476-23408-4576D:P(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)"); /* Win7 */ GetSecurityDescriptorControl(buf, &ctrl, &dwRevision); - expect_eq(ctrl, 0x8004, int, "%x"); + expect_eq(ctrl & (~ SE_DACL_PROTECTED), 0x8004, int, "%x"); ok(GetPrivateObjectSecurity(sec, sec_info, buf, dwDescSize, &retSize), "GetPrivateObjectSecurity failed (err=%u)\n", GetLastError()); ok(retSize == dwDescSize, "Buffer too small (%d vs %d)\n", retSize, dwDescSize); ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(buf, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n"); - CHECK_RESULT_AND_FREE("O:SY" + CHECK_ONE_OF_AND_FREE("O:SY" "G:S-1-5-21-93476-23408-4576" "D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)" - "S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)"); + "S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)", + "O:SY" + "G:S-1-5-21-93476-23408-4576" + "D:P(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)" + "S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)"); /* Win7 */ GetSecurityDescriptorControl(buf, &ctrl, &dwRevision); - expect_eq(ctrl, 0x8014, int, "%x"); + expect_eq(ctrl & (~ SE_DACL_PROTECTED), 0x8014, int, "%x"); SetLastError(0xdeadbeef); ok(GetPrivateObjectSecurity(sec, sec_info, buf, 5, &retSize) == FALSE, "GetPrivateObjectSecurity should have failed\n"); @@ -2445,7 +3092,7 @@ static void test_acls(void) ret = InitializeAcl(pAcl, sizeof(ACL) - 1, ACL_REVISION); if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("InitializeAcl is not implemented\n"); + win_skip("InitializeAcl is not implemented\n"); return; } @@ -2471,17 +3118,113 @@ static void test_acls(void) ret = IsValidAcl(pAcl); ok(ret, "IsValidAcl failed with error %d\n", GetLastError()); + SetLastError(0xdeadbeef); ret = InitializeAcl(pAcl, sizeof(buffer), ACL_REVISION4); + if (GetLastError() != ERROR_INVALID_PARAMETER) + { ok(ret, "InitializeAcl(ACL_REVISION4) failed with error %d\n", GetLastError()); ret = IsValidAcl(pAcl); ok(ret, "IsValidAcl failed with error %d\n", GetLastError()); + } + else + win_skip("ACL_REVISION4 is not implemented on NT4\n"); SetLastError(0xdeadbeef); ret = InitializeAcl(pAcl, sizeof(buffer), -1); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "InitializeAcl(-1) failed with error %d\n", GetLastError()); } +static void test_GetSecurityInfo(void) +{ + HANDLE obj; + PSECURITY_DESCRIPTOR sd; + PSID owner, group; + PACL dacl; + DWORD ret; + + if (!pGetSecurityInfo) + { + win_skip("GetSecurityInfo is not available\n"); + return; + } + + /* Create something. Files have lots of associated security info. */ + obj = CreateFile(myARGV[0], GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (obj == INVALID_HANDLE_VALUE) + { + skip("Couldn't create an object for GetSecurityInfo test\n"); + return; + } + + ret = pGetSecurityInfo(obj, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + &owner, &group, &dacl, NULL, &sd); + if (ret == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetSecurityInfo is not implemented\n"); + CloseHandle(obj); + return; + } + ok(ret == ERROR_SUCCESS, "GetSecurityInfo returned %d\n", ret); + ok(sd != NULL, "GetSecurityInfo\n"); + ok(owner != NULL, "GetSecurityInfo\n"); + ok(group != NULL, "GetSecurityInfo\n"); + ok(dacl != NULL, "GetSecurityInfo\n"); + ok(IsValidAcl(dacl), "GetSecurityInfo\n"); + + LocalFree(sd); + + if (!pCreateWellKnownSid) + { + win_skip("NULL parameter test would crash on NT4\n"); + CloseHandle(obj); + return; + } + + /* If we don't ask for the security descriptor, Windows will still give us + the other stuff, leaving us no way to free it. */ + ret = pGetSecurityInfo(obj, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + &owner, &group, &dacl, NULL, NULL); + ok(ret == ERROR_SUCCESS, "GetSecurityInfo returned %d\n", ret); + ok(owner != NULL, "GetSecurityInfo\n"); + ok(group != NULL, "GetSecurityInfo\n"); + ok(dacl != NULL, "GetSecurityInfo\n"); + ok(IsValidAcl(dacl), "GetSecurityInfo\n"); + + CloseHandle(obj); +} + +static void test_GetSidSubAuthority(void) +{ + PSID psid = NULL; + + if (!pGetSidSubAuthority || !pConvertStringSidToSidA || !pIsValidSid || !pGetSidSubAuthorityCount) + { + win_skip("Some functions not available\n"); + return; + } + /* Note: on windows passing in an invalid index like -1, lets GetSidSubAuthority return 0x05000000 but + still GetLastError returns ERROR_SUCCESS then. We don't test these unlikely cornercases here for now */ + ok(pConvertStringSidToSidA("S-1-5-21-93476-23408-4576",&psid),"ConvertStringSidToSidA failed\n"); + ok(pIsValidSid(psid),"Sid is not valid\n"); + SetLastError(0xbebecaca); + ok(*pGetSidSubAuthorityCount(psid) == 4,"GetSidSubAuthorityCount gave %d expected 4\n",*pGetSidSubAuthorityCount(psid)); + ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError()); + SetLastError(0xbebecaca); + ok(*pGetSidSubAuthority(psid,0) == 21,"GetSidSubAuthority gave %d expected 21\n",*pGetSidSubAuthority(psid,0)); + ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError()); + SetLastError(0xbebecaca); + ok(*pGetSidSubAuthority(psid,1) == 93476,"GetSidSubAuthority gave %d expected 93476\n",*pGetSidSubAuthority(psid,1)); + ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError()); + SetLastError(0xbebecaca); + todo_wine ok(*pGetSidSubAuthority(psid,4) == 0,"GetSidSubAuthority gave %d,expected 0\n",*pGetSidSubAuthority(psid,4)); + ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError()); + LocalFree(psid); +} + START_TEST(security) { init(); @@ -2510,4 +3253,6 @@ START_TEST(security) test_ConvertSecurityDescriptorToString(); test_PrivateObjectSecurity(); test_acls(); + test_GetSecurityInfo(); + test_GetSidSubAuthority(); } diff --git a/rostests/winetests/advapi32/service.c b/rostests/winetests/advapi32/service.c index 8ffe2e8c242..0851384b70b 100644 --- a/rostests/winetests/advapi32/service.c +++ b/rostests/winetests/advapi32/service.c @@ -28,11 +28,35 @@ #include "winsvc.h" #include "winnls.h" #include "lmcons.h" +#include "aclapi.h" #include "wine/test.h" static const CHAR spooler[] = "Spooler"; /* Should be available on all platforms */ +static BOOL (WINAPI *pChangeServiceConfig2A)(SC_HANDLE,DWORD,LPVOID); +static BOOL (WINAPI *pEnumServicesStatusExA)(SC_HANDLE, SC_ENUM_TYPE, DWORD, + DWORD, LPBYTE, DWORD, LPDWORD, + LPDWORD, LPDWORD, LPCSTR); +static DWORD (WINAPI *pGetSecurityInfo)(HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, + PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); +static BOOL (WINAPI *pQueryServiceConfig2A)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); +static BOOL (WINAPI *pQueryServiceConfig2W)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); +static BOOL (WINAPI *pQueryServiceStatusEx)(SC_HANDLE, SC_STATUS_TYPE, LPBYTE, + DWORD, LPDWORD); + +static void init_function_pointers(void) +{ + HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); + + pChangeServiceConfig2A = (void*)GetProcAddress(hadvapi32, "ChangeServiceConfig2A"); + pEnumServicesStatusExA= (void*)GetProcAddress(hadvapi32, "EnumServicesStatusExA"); + pGetSecurityInfo = (void *)GetProcAddress(hadvapi32, "GetSecurityInfo"); + pQueryServiceConfig2A= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2A"); + pQueryServiceConfig2W= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2W"); + pQueryServiceStatusEx= (void*)GetProcAddress(hadvapi32, "QueryServiceStatusEx"); +} + static void test_open_scm(void) { SC_HANDLE scm_handle; @@ -40,11 +64,7 @@ static void test_open_scm(void) /* No access rights */ SetLastError(0xdeadbeef); scm_handle = OpenSCManagerA(NULL, NULL, 0); - ok(scm_handle != NULL, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ || - GetLastError() == 0xdeadbeef /* NT4, XP */ || - GetLastError() == ERROR_IO_PENDING /* W2K */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); + ok(scm_handle != NULL, "Expected success, got error %u\n", GetLastError()); CloseServiceHandle(scm_handle); /* Unknown database name */ @@ -64,30 +84,24 @@ static void test_open_scm(void) /* Remote unknown host */ SetLastError(0xdeadbeef); scm_handle = OpenSCManagerA("DOESNOTEXIST", SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT); - ok(!scm_handle, "Expected failure\n"); todo_wine - ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE, "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError()); + { + ok(!scm_handle, "Expected failure\n"); + ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || GetLastError() == RPC_S_INVALID_NET_ADDR /* w2k8 */, + "Expected RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR, got %d\n", GetLastError()); + } CloseServiceHandle(scm_handle); /* Just in case */ /* Proper call with an empty hostname */ SetLastError(0xdeadbeef); scm_handle = OpenSCManagerA("", SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT); - ok(scm_handle != NULL, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ || - GetLastError() == ERROR_ENVVAR_NOT_FOUND /* NT4 */ || - GetLastError() == 0xdeadbeef /* XP */ || - GetLastError() == ERROR_IO_PENDING /* W2K */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING, ERROR_ENVVAR_NOT_FOUND or 0xdeadbeef, got %d\n", GetLastError()); + ok(scm_handle != NULL, "Expected success, got error %u\n", GetLastError()); CloseServiceHandle(scm_handle); /* Again a correct one */ SetLastError(0xdeadbeef); scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); - ok(scm_handle != NULL, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ || - GetLastError() == 0xdeadbeef /* NT4, XP */ || - GetLastError() == ERROR_IO_PENDING /* W2K */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); + ok(scm_handle != NULL, "Expected success, got error %u\n", GetLastError()); CloseServiceHandle(scm_handle); } @@ -130,11 +144,7 @@ static void test_open_svc(void) skip("Not enough rights to get a handle to the service\n"); else { - ok(svc_handle != NULL, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ || - GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == 0xdeadbeef /* XP, NT4 */, - "Expected ERROR_SUCCESS or 0xdeadbeef, got %d\n", GetLastError()); + ok(svc_handle != NULL, "Expected success, got error %u\n", GetLastError()); CloseServiceHandle(svc_handle); } @@ -145,7 +155,17 @@ static void test_open_svc(void) GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize); /* Get the displayname */ GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize); - /* Try to open the service with this displayname */ + /* Try to open the service with this displayname, unless the displayname equals + * the servicename as that would defeat the purpose of this test. + */ + if (!lstrcmpi(spooler, displayname)) + { + skip("displayname equals servicename\n"); + CloseServiceHandle(scm_handle); + return; + } + + SetLastError(0xdeadbeef); svc_handle = OpenServiceA(scm_handle, displayname, GENERIC_READ); ok(!svc_handle, "Expected failure\n"); ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); @@ -291,7 +311,8 @@ static void test_create_delete_svc(void) svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, account, password); ok(!svc_handle1, "Expected failure\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_SERVICE_ACCOUNT, + "Expected ERROR_INVALID_PARAMETER or ERROR_INVALID_SERVICE_ACCOUNT, got %d\n", GetLastError()); /* Illegal (start-type is not a mask and should only be one of the possibilities) * Remark : 'OR'-ing them could result in a valid possibility (but doesn't make sense as @@ -355,10 +376,6 @@ static void test_create_delete_svc(void) svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL); ok(svc_handle1 != NULL, "Could not create the service : %d\n", GetLastError()); - ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ || - GetLastError() == 0xdeadbeef /* NT4, XP */ || - GetLastError() == ERROR_IO_PENDING /* W2K */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); /* DeleteService however must have proper rights */ SetLastError(0xdeadbeef); @@ -376,14 +393,9 @@ static void test_create_delete_svc(void) /* Now that we have the proper rights, we should be able to delete */ SetLastError(0xdeadbeef); ret = DeleteService(svc_handle1); - ok(ret, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */ || - GetLastError() == ERROR_IO_PENDING /* W2K */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); + ok(ret, "Expected success, got error %u\n", GetLastError()); CloseServiceHandle(svc_handle1); - CloseServiceHandle(scm_handle); /* Wait a while. One of the following tests also does a CreateService for the @@ -409,6 +421,8 @@ static void test_get_displayname(void) DWORD displaysize, tempsize, tempsizeW; static const CHAR deadbeef[] = "Deadbeef"; static const WCHAR spoolerW[] = {'S','p','o','o','l','e','r',0}; + static const WCHAR deadbeefW[] = {'D','e','a','d','b','e','e','f',0}; + static const WCHAR abcW[] = {'A','B','C',0}; static const CHAR servicename[] = "Winetest"; static const CHAR pathname[] = "we_dont_care.exe"; @@ -445,6 +459,85 @@ static void test_get_displayname(void) ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = GetServiceDisplayNameA(scm_handle, deadbeef, NULL, &displaysize); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + todo_wine ok(displaysize == 1, "Service size expected 1, got %d\n", displaysize); + + displaysize = 15; + strcpy(displayname, "ABC"); + ret = GetServiceDisplayNameA(scm_handle, deadbeef, displayname, &displaysize); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + todo_wine ok(displaysize == 15, "Service size expected 15, got %d\n", displaysize); + ok(displayname[0] == 0, "Service name not empty\n"); + + displaysize = 15; + lstrcpyW( displaynameW, abcW ); + ret = GetServiceDisplayNameW(scm_handle, deadbeefW, displaynameW, &displaysize); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + ok(displaysize == 15, "Service size expected 15, got %d\n", displaysize); + ok(displaynameW[0] == 0, "Service name not empty\n"); + + displaysize = 0; + strcpy(displayname, "ABC"); + ret = GetServiceDisplayNameA(scm_handle, deadbeef, displayname, &displaysize); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + todo_wine ok(displaysize == 1, "Service size expected 1, got %d\n", displaysize); + ok(displayname[0] == 'A', "Service name changed\n"); + + displaysize = 0; + lstrcpyW( displaynameW, abcW ); + ret = GetServiceDisplayNameW(scm_handle, deadbeefW, displaynameW, &displaysize); + ok(!ret, "Expected failure\n"); + ok(displaysize == 2, "Service size expected 2, got %d\n", displaysize); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + ok(displaynameW[0] == 'A', "Service name changed\n"); + + displaysize = 1; + strcpy(displayname, "ABC"); + ret = GetServiceDisplayNameA(scm_handle, deadbeef, displayname, &displaysize); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + todo_wine ok(displaysize == 1, "Service size expected 1, got %d\n", displaysize); + ok(displayname[0] == 0, "Service name not empty\n"); + + displaysize = 1; + lstrcpyW( displaynameW, abcW ); + ret = GetServiceDisplayNameW(scm_handle, deadbeefW, displaynameW, &displaysize); + ok(!ret, "Expected failure\n"); + ok(displaysize == 2, "Service size expected 2, got %d\n", displaysize); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + ok(displaynameW[0] == 'A', "Service name changed\n"); + + displaysize = 2; + strcpy(displayname, "ABC"); + ret = GetServiceDisplayNameA(scm_handle, deadbeef, displayname, &displaysize); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + todo_wine ok(displaysize == 2, "Service size expected 2, got %d\n", displaysize); + ok(displayname[0] == 0, "Service name not empty\n"); + + displaysize = 2; + lstrcpyW( displaynameW, abcW ); + ret = GetServiceDisplayNameW(scm_handle, deadbeefW, displaynameW, &displaysize); + ok(!ret, "Expected failure\n"); + ok(displaysize == 2, "Service size expected 2, got %d\n", displaysize); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + ok(displaynameW[0] == 0, "Service name not empty\n"); + /* Check if 'Spooler' exists */ svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ); if (!svc_handle) @@ -487,33 +580,21 @@ static void test_get_displayname(void) SetLastError(0xdeadbeef); displaysize = (tempsize / 2) + 1; ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize); - ok(ret, "Expected success\n"); + ok(ret, "Expected success, got error %u\n", GetLastError()); ok(displaysize == ((tempsize / 2) + 1), "Expected no change for the needed buffer size\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); /* Now with the original returned size */ SetLastError(0xdeadbeef); displaysize = tempsize; ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize); - ok(ret, "Expected success\n"); + ok(ret, "Expected success, got error %u\n", GetLastError()); ok(displaysize == tempsize, "Expected no change for the needed buffer size\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); /* And with a bigger than needed buffer */ SetLastError(0xdeadbeef); displaysize = tempsize * 2; ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize); - ok(ret, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); + ok(ret, "Expected success, got error %u\n", GetLastError()); /* Test that shows that if the buffersize is enough, it's not changed */ ok(displaysize == tempsize * 2, "Expected no change for the needed buffer size\n"); ok(lstrlen(displayname) == tempsize/2, @@ -533,7 +614,7 @@ static void test_get_displayname(void) displaysize = tempsizeW / 2; ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize); ok(!ret, "Expected failure\n"); - ok(displaysize = tempsizeW, "Expected the needed buffersize\n"); + ok(displaysize == tempsizeW, "Expected the needed buffersize\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); @@ -542,7 +623,7 @@ static void test_get_displayname(void) displaysize = tempsizeW; ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize); ok(!ret, "Expected failure\n"); - ok(displaysize = tempsizeW, "Expected the needed buffersize\n"); + ok(displaysize == tempsizeW, "Expected the needed buffersize\n"); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); @@ -550,11 +631,7 @@ static void test_get_displayname(void) SetLastError(0xdeadbeef); displaysize = tempsizeW + 1; /* This caters for the null terminating character */ ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize); - ok(ret, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); + ok(ret, "Expected success, got error %u\n", GetLastError()); ok(displaysize == tempsizeW, "Expected the needed buffersize\n"); ok(lstrlenW(displaynameW) == displaysize, "Expected the buffer to be the length of the string\n") ; @@ -608,17 +685,13 @@ static void test_get_displayname(void) /* Get the displayname */ SetLastError(0xdeadbeef); ret = GetServiceDisplayNameA(scm_handle, servicename, displayname, &displaysize); - ok(ret, "Expected success\n"); + ok(ret, "Expected success, got error %u\n", GetLastError()); ok(!lstrcmpi(displayname, servicename), "Expected displayname to be %s, got %s\n", servicename, displayname); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); /* Delete the service */ ret = DeleteService(svc_handle); - ok(ret, "Expected success\n"); + ok(ret, "Expected success (err=%d)\n", GetLastError()); CloseServiceHandle(svc_handle); CloseServiceHandle(scm_handle); @@ -638,6 +711,7 @@ static void test_get_servicekeyname(void) BOOL ret; static const CHAR deadbeef[] = "Deadbeef"; static const WCHAR deadbeefW[] = {'D','e','a','d','b','e','e','f',0}; + static const WCHAR abcW[] = {'A','B','C',0}; /* Having NULL for the size of the buffer will crash on W2K3 */ @@ -680,30 +754,74 @@ static void test_get_servicekeyname(void) strcpy(servicename, "ABC"); ret = GetServiceKeyNameA(scm_handle, deadbeef, servicename, &servicesize); ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); todo_wine ok(servicesize == 15, "Service size expected 15, got %d\n", servicesize); ok(servicename[0] == 0, "Service name not empty\n"); servicesize = 15; - servicenameW[0] = 'A'; + lstrcpyW( servicenameW, abcW ); ret = GetServiceKeyNameW(scm_handle, deadbeefW, servicenameW, &servicesize); ok(!ret, "Expected failure\n"); - todo_wine ok(servicesize == 15, "Service size expected 15, got %d\n", servicesize); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + ok(servicesize == 15, "Service size expected 15, got %d\n", servicesize); ok(servicenameW[0] == 0, "Service name not empty\n"); servicesize = 0; strcpy(servicename, "ABC"); ret = GetServiceKeyNameA(scm_handle, deadbeef, servicename, &servicesize); ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); todo_wine ok(servicesize == 1, "Service size expected 1, got %d\n", servicesize); ok(servicename[0] == 'A', "Service name changed\n"); servicesize = 0; - servicenameW[0] = 'A'; + lstrcpyW( servicenameW, abcW ); ret = GetServiceKeyNameW(scm_handle, deadbeefW, servicenameW, &servicesize); ok(!ret, "Expected failure\n"); - todo_wine ok(servicesize == 2, "Service size expected 2, got %d\n", servicesize); + ok(servicesize == 2, "Service size expected 2, got %d\n", servicesize); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); ok(servicenameW[0] == 'A', "Service name changed\n"); + servicesize = 1; + strcpy(servicename, "ABC"); + ret = GetServiceKeyNameA(scm_handle, deadbeef, servicename, &servicesize); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + todo_wine ok(servicesize == 1, "Service size expected 1, got %d\n", servicesize); + ok(servicename[0] == 0, "Service name not empty\n"); + + servicesize = 1; + lstrcpyW( servicenameW, abcW ); + ret = GetServiceKeyNameW(scm_handle, deadbeefW, servicenameW, &servicesize); + ok(!ret, "Expected failure\n"); + ok(servicesize == 2, "Service size expected 2, got %d\n", servicesize); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + ok(servicenameW[0] == 'A', "Service name changed\n"); + + servicesize = 2; + strcpy(servicename, "ABC"); + ret = GetServiceKeyNameA(scm_handle, deadbeef, servicename, &servicesize); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + todo_wine ok(servicesize == 2, "Service size expected 2, got %d\n", servicesize); + ok(servicename[0] == 0, "Service name not empty\n"); + + servicesize = 2; + lstrcpyW( servicenameW, abcW ); + ret = GetServiceKeyNameW(scm_handle, deadbeefW, servicenameW, &servicesize); + ok(!ret, "Expected failure\n"); + ok(servicesize == 2, "Service size expected 2, got %d\n", servicesize); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + ok(servicenameW[0] == 0, "Service name not empty\n"); + /* Check if 'Spooler' exists */ svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ); if (!svc_handle) @@ -731,11 +849,7 @@ static void test_get_servicekeyname(void) tempsize = servicesize; servicesize *= 2; ret = GetServiceKeyNameA(scm_handle, displayname, servicename, &servicesize); - ok(ret, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); + ok(ret, "Expected success, got error %u\n", GetLastError()); if (ret) { ok(lstrlen(servicename) == tempsize/2, @@ -749,11 +863,7 @@ static void test_get_servicekeyname(void) SetLastError(0xdeadbeef); servicesize *= 2; ret = GetServiceKeyNameW(scm_handle, displaynameW, servicenameW, &servicesize); - ok(ret, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); + ok(ret, "Expected success, got error %u\n", GetLastError()); if (ret) { ok(lstrlen(servicename) == tempsize/2, @@ -773,6 +883,793 @@ static void test_get_servicekeyname(void) CloseServiceHandle(scm_handle); } +static void test_query_svc(void) +{ + SC_HANDLE scm_handle, svc_handle; + BOOL ret; + SERVICE_STATUS status; + SERVICE_STATUS_PROCESS *statusproc; + DWORD bufsize, needed; + + /* All NULL or wrong */ + SetLastError(0xdeadbeef); + ret = QueryServiceStatus(NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + + /* Check if 'Spooler' exists. + * Open with not enough rights to query the status. + */ + svc_handle = OpenServiceA(scm_handle, spooler, STANDARD_RIGHTS_READ); + if (!svc_handle) + { + skip("Spooler service doesn't exist\n"); + CloseServiceHandle(scm_handle); + return; + } + + SetLastError(0xdeadbeef); + ret = QueryServiceStatus(svc_handle, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = QueryServiceStatus(svc_handle, &status); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* Open the service with just enough rights. + * (Verified with 'SERVICE_ALL_ACCESS &~ SERVICE_QUERY_STATUS') + */ + CloseServiceHandle(svc_handle); + svc_handle = OpenServiceA(scm_handle, spooler, SERVICE_QUERY_STATUS); + + SetLastError(0xdeadbeef); + ret = QueryServiceStatus(svc_handle, &status); + ok(ret, "Expected success, got error %u\n", GetLastError()); + + CloseServiceHandle(svc_handle); + + /* More or less the same tests for QueryServiceStatusEx */ + + /* Open service with not enough rights to query the status */ + svc_handle = OpenServiceA(scm_handle, spooler, STANDARD_RIGHTS_READ); + + /* All NULL or wrong, this proves that info level is checked first */ + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(NULL, 1, NULL, 0, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_LEVEL, + "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError()); + + /* Passing a NULL parameter for the needed buffer size + * will crash on anything but NT4. + */ + + /* Only info level is correct. It looks like the buffer/size is checked second */ + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(NULL, 0, NULL, 0, &needed); + /* NT4 and Wine check the handle first */ + if (GetLastError() != ERROR_INVALID_HANDLE) + { + ok(!ret, "Expected failure\n"); + ok(needed == sizeof(SERVICE_STATUS_PROCESS), + "Needed buffersize is wrong : %d\n", needed); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + } + + /* Pass a correct buffer and buffersize but a NULL handle */ + statusproc = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_STATUS_PROCESS)); + bufsize = needed; + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(NULL, 0, (BYTE*)statusproc, bufsize, &needed); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, statusproc); + + /* Correct handle and info level */ + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(svc_handle, 0, NULL, 0, &needed); + /* NT4 doesn't return the needed size */ + if (GetLastError() != ERROR_INVALID_PARAMETER) + { + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == sizeof(SERVICE_STATUS_PROCESS), + "Needed buffersize is wrong : %d\n", needed); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + } + } + + /* All parameters are OK but we don't have enough rights */ + statusproc = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_STATUS_PROCESS)); + bufsize = sizeof(SERVICE_STATUS_PROCESS); + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(svc_handle, 0, (BYTE*)statusproc, bufsize, &needed); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, statusproc); + + /* Open the service with just enough rights. */ + CloseServiceHandle(svc_handle); + svc_handle = OpenServiceA(scm_handle, spooler, SERVICE_QUERY_STATUS); + + /* Everything should be fine now. */ + statusproc = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_STATUS_PROCESS)); + bufsize = sizeof(SERVICE_STATUS_PROCESS); + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(svc_handle, 0, (BYTE*)statusproc, bufsize, &needed); + ok(ret, "Expected success, got error %u\n", GetLastError()); + if (statusproc->dwCurrentState == SERVICE_RUNNING) + ok(statusproc->dwProcessId != 0, + "Expect a process id for this running service\n"); + else + ok(statusproc->dwProcessId == 0, + "Expect no process id for this stopped service\n"); + HeapFree(GetProcessHeap(), 0, statusproc); + + CloseServiceHandle(svc_handle); + CloseServiceHandle(scm_handle); +} + +static void test_enum_svc(void) +{ + SC_HANDLE scm_handle; + BOOL ret; + DWORD bufsize, needed, returned, resume; + DWORD tempneeded, tempreturned, missing; + DWORD servicecountactive, servicecountinactive; + ENUM_SERVICE_STATUS *services; + ENUM_SERVICE_STATUS_PROCESS *exservices; + INT i; + + /* All NULL or wrong */ + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(NULL, 1, 0, NULL, 0, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + + /* Open the service control manager with not enough rights at first */ + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + + /* Valid handle but rest is still NULL or wrong */ + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 1, 0, NULL, 0, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* Don't specify the two required pointers */ + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, NULL, &returned, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0xdeadbeef, "Expected no change to the number of services variable\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* Don't specify the two required pointers */ + needed = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, &needed, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(needed == 0xdeadbeef || broken(needed != 0xdeadbeef), /* nt4 */ + "Expected no change to the needed buffer variable\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of services to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, 0, NULL, 0, &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of services to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 0, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of services to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* All parameters are correct but our access rights are wrong */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of services to be set to 0, got %d\n", returned); + } + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* Open the service control manager with the needed rights */ + CloseServiceHandle(scm_handle); + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); + + /* All parameters are correct. Request the needed buffer size */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\n"); + ok(returned == 0, "Expected no service returned, got %d\n", returned); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Store the needed bytes */ + tempneeded = needed; + + /* Allocate the correct needed bytes */ + services = HeapAlloc(GetProcessHeap(), 0, needed); + bufsize = needed; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, + services, bufsize, &needed, &returned, NULL); + todo_wine + { + ok(ret, "Expected success, got error %u\n", GetLastError()); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned != 0xdeadbeef && returned > 0, "Expected some returned services\n"); + } + HeapFree(GetProcessHeap(), 0, services); + + /* Store the number of returned services */ + tempreturned = returned; + + /* Allocate less than the needed bytes and don't specify a resume handle */ + services = HeapAlloc(GetProcessHeap(), 0, tempneeded); + bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS); + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, + services, bufsize, &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\n"); + ok(returned < tempreturned, "Expected fewer services to be returned\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Allocate less than the needed bytes, this time with a correct resume handle */ + bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS); + needed = 0xdeadbeef; + returned = 0xdeadbeef; + resume = 0; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, + services, bufsize, &needed, &returned, &resume); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\n"); + ok(returned < tempreturned, "Expected fewer services to be returned\n"); + ok(resume, "Expected a resume handle\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Fetch the missing services but pass a bigger buffer size */ + missing = tempreturned - returned; + bufsize = tempneeded; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, + services, bufsize, &needed, &returned, &resume); + todo_wine + { + ok(ret, "Expected success, got error %u\n", GetLastError()); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned == missing, "Expected %u services to be returned\n", missing); + } + ok(resume == 0, "Expected the resume handle to be 0\n"); + HeapFree(GetProcessHeap(), 0, services); + + /* See if things add up */ + + /* Vista only shows the drivers with a state of SERVICE_RUNNING as active + * and doesn't count the others as inactive. This means that Vista could + * show a total that is greater than the sum of active and inactive + * drivers. + * The number of active and inactive drivers is greatly influenced by the + * time when tests are run, immediately after boot or later for example. + * + * Both reasons make calculations for drivers not so useful + */ + + /* Get the number of active win32 services */ + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_ACTIVE, NULL, 0, + &needed, &returned, NULL); + services = HeapAlloc(GetProcessHeap(), 0, needed); + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_ACTIVE, services, + needed, &needed, &returned, NULL); + HeapFree(GetProcessHeap(), 0, services); + + servicecountactive = returned; + + /* Get the number of inactive win32 services */ + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_INACTIVE, NULL, 0, + &needed, &returned, NULL); + services = HeapAlloc(GetProcessHeap(), 0, needed); + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_INACTIVE, services, + needed, &needed, &returned, NULL); + HeapFree(GetProcessHeap(), 0, services); + + servicecountinactive = returned; + + /* Get the number of win32 services */ + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL); + services = HeapAlloc(GetProcessHeap(), 0, needed); + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, services, + needed, &needed, &returned, NULL); + HeapFree(GetProcessHeap(), 0, services); + + /* Check if total is the same as active and inactive win32 services */ + todo_wine + ok(returned == (servicecountactive + servicecountinactive), + "Something wrong in the calculation\n"); + + /* Get all drivers and services + * + * Fetch the status of the last call as failing could make the following tests crash + * on Wine (we don't return anything yet). + */ + EnumServicesStatusA(scm_handle, SERVICE_DRIVER | SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL); + services = HeapAlloc(GetProcessHeap(), 0, needed); + ret = EnumServicesStatusA(scm_handle, SERVICE_DRIVER | SERVICE_WIN32, SERVICE_STATE_ALL, + services, needed, &needed, &returned, NULL); + + /* Loop through all those returned drivers and services */ + for (i = 0; ret && i < returned; i++) + { + SERVICE_STATUS status = services[i].ServiceStatus; + + /* lpServiceName and lpDisplayName should always be filled */ + ok(lstrlenA(services[i].lpServiceName) > 0, "Expected a service name\n"); + ok(lstrlenA(services[i].lpDisplayName) > 0, "Expected a display name\n"); + + /* Decrement the counters to see if the functions calls return the same + * numbers as the contents of these structures. + */ + if (status.dwServiceType & (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS)) + { + if (status.dwCurrentState == SERVICE_RUNNING) + servicecountactive--; + else + servicecountinactive--; + } + } + HeapFree(GetProcessHeap(), 0, services); + + todo_wine + { + ok(servicecountactive == 0, "Active services mismatch %u\n", servicecountactive); + ok(servicecountinactive == 0, "Inactive services mismatch %u\n", servicecountinactive); + } + + CloseServiceHandle(scm_handle); + + /* More or less the same for EnumServicesStatusExA */ + + /* All NULL or wrong */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(NULL, 1, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_LEVEL, + "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError()); + + /* All NULL or wrong, just the info level is correct */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + + /* Open the service control manager with not enough rights at first */ + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + + /* Valid handle and info level but rest is still NULL or wrong */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* Don't specify the two required pointers */ + needed = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(needed == 0xdeadbeef || broken(needed != 0xdeadbeef), /* nt4 */ + "Expected no change to the needed buffer variable\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* Don't specify the two required pointers */ + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, NULL, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(returned == 0xdeadbeef, "Expected no change to the number of services variable\n"); + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, 0, NULL, 0, + &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate and unknown service group */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, + &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* All parameters are correct but our access rights are wrong */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* All parameters are correct, access rights are wrong but the + * group name won't be checked yet. + */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + todo_wine + ok(needed == 0 || broken(needed != 0), /* nt4 */ + "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* Open the service control manager with the needed rights */ + CloseServiceHandle(scm_handle); + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); + + /* All parameters are correct and the group will be checked */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + } + + /* TODO: Create a test that makes sure we enumerate all services that don't + * belong to a group. (specifying ""). + */ + + /* All parameters are correct. Request the needed buffer size */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected no service returned, got %d\n", returned); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Store the needed bytes */ + tempneeded = needed; + + /* Allocate the correct needed bytes */ + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + bufsize = needed; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); + todo_wine + { + ok(ret, "Expected success, got error %u\n", GetLastError()); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned == tempreturned, "Expected the same number of service from this function\n"); + } + HeapFree(GetProcessHeap(), 0, exservices); + + /* Store the number of returned services */ + tempreturned = returned; + + /* Allocate less than the needed bytes and don't specify a resume handle */ + exservices = HeapAlloc(GetProcessHeap(), 0, tempneeded); + bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS); + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(returned < tempreturned, "Expected fewer services to be returned\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Allocate less than the needed bytes, this time with a correct resume handle */ + bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS); + needed = 0xdeadbeef; + returned = 0xdeadbeef; + resume = 0; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(returned < tempreturned, "Expected fewer services to be returned\n"); + ok(resume, "Expected a resume handle\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Fetch that last service but pass a bigger buffer size */ + missing = tempreturned - returned; + bufsize = tempneeded; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL); + todo_wine + { + ok(ret, "Expected success, got error %u\n", GetLastError()); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + } + ok(returned == missing, "Expected %u services to be returned\n", missing); + ok(resume == 0, "Expected the resume handle to be 0\n"); + HeapFree(GetProcessHeap(), 0, exservices); + + /* See if things add up */ + + /* Get the number of active win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_ACTIVE, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_ACTIVE, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + servicecountactive = returned; + + /* Get the number of inactive win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_INACTIVE, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_INACTIVE, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + servicecountinactive = returned; + + /* Get the number of win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + /* Check if total is the same as active and inactive win32 services */ + ok(returned == (servicecountactive + servicecountinactive), + "Something wrong in the calculation\n"); + + /* Get all drivers and services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER, + SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER, + SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + + /* Loop through all those returned drivers and services */ + for (i = 0; i < returned; i++) + { + SERVICE_STATUS_PROCESS status = exservices[i].ServiceStatusProcess; + + + /* lpServiceName and lpDisplayName should always be filled */ + ok(lstrlenA(exservices[i].lpServiceName) > 0, "Expected a service name\n"); + ok(lstrlenA(exservices[i].lpDisplayName) > 0, "Expected a display name\n"); + + /* Decrement the counters to see if the functions calls return the + * same numbers as the contents of these structures. + * Check some process id specifics. + */ + if (status.dwServiceType & (SERVICE_FILE_SYSTEM_DRIVER | SERVICE_KERNEL_DRIVER)) + { + /* We shouldn't have a process id for drivers */ + ok(status.dwProcessId == 0, + "This driver shouldn't have an associated process id\n"); + } + + if (status.dwServiceType & (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS)) + { + if (status.dwCurrentState == SERVICE_RUNNING) + { + /* We expect a process id for every running service */ + ok(status.dwProcessId > 0, "Expected a process id for this running service (%s)\n", + exservices[i].lpServiceName); + + servicecountactive--; + } + else + { + /* We shouldn't have a process id for inactive services */ + ok(status.dwProcessId == 0, "Service %s state %u shouldn't have an associated process id\n", + exservices[i].lpServiceName, status.dwCurrentState); + + servicecountinactive--; + } + } + } + HeapFree(GetProcessHeap(), 0, exservices); + + ok(servicecountactive == 0, "Active services mismatch %u\n", servicecountactive); + ok(servicecountinactive == 0, "Inactive services mismatch %u\n", servicecountinactive); + + CloseServiceHandle(scm_handle); +} + static void test_close(void) { SC_HANDLE handle; @@ -790,11 +1687,7 @@ static void test_close(void) handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); SetLastError(0xdeadbeef); ret = CloseServiceHandle(handle); - ok(ret, "Expected success\n"); - ok(GetLastError() == ERROR_IO_PENDING /* W2K */ || - GetLastError() == ERROR_SUCCESS /* W2K3 */ || - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); + ok(ret, "Expected success got error %u\n", GetLastError()); } static void test_sequence(void) @@ -854,7 +1747,17 @@ static void test_sequence(void) return; } else + { ok(svc_handle != NULL, "Could not create the service : %d\n", GetLastError()); + if ((svc_handle != NULL) && (pGetSecurityInfo != NULL)) + { + PSID sidOwner, sidGroup; + PACL dacl, sacl; + PSECURITY_DESCRIPTOR pSD; + HRESULT retval = pGetSecurityInfo(svc_handle,SE_SERVICE,DACL_SECURITY_INFORMATION,&sidOwner,&sidGroup,&dacl,&sacl,&pSD); + todo_wine ok(ERROR_SUCCESS == retval, "Expected GetSecurityInfo to succeed: result %d\n",retval); + } + } if (!svc_handle) return; @@ -873,15 +1776,8 @@ static void test_sequence(void) given = needed; SetLastError(0xdeadbeef); ret = QueryServiceConfigA(svc_handle, config, given, &needed); - ok(ret, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */|| - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */ || - GetLastError() == ERROR_IO_PENDING /* W2K */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); - todo_wine - { - ok(given == needed, "Expected the given (%d) and needed (%d) buffersizes to be equal\n", given, needed); - } + ok(ret, "Expected success, got error %u\n", GetLastError()); + ok(config->lpBinaryPathName && config->lpLoadOrderGroup && config->lpDependencies && config->lpServiceStartName && config->lpDisplayName, "Expected all string struct members to be non-NULL\n"); ok(config->dwServiceType == (SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS), @@ -919,12 +1815,7 @@ static void test_sequence(void) SetLastError(0xdeadbeef); ret = DeleteService(svc_handle); - ok(ret, "Expected success\n"); - ok(GetLastError() == ERROR_SUCCESS /* W2K3 */|| - GetLastError() == 0xdeadbeef /* NT4, XP, Vista */ || - GetLastError() == ERROR_IO_PENDING /* W2K */, - "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError()); - + ok(ret, "Expected success, got error %u\n", GetLastError()); CloseServiceHandle(svc_handle); /* Wait a while. The following test does a CreateService again */ @@ -947,16 +1838,10 @@ static void test_queryconfig2(void) static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0"; static const CHAR password [] = ""; static const CHAR description [] = "Description"; - HMODULE dllhandle = GetModuleHandleA("advapi32.dll"); - BOOL (WINAPI *pChangeServiceConfig2A)(SC_HANDLE,DWORD,LPVOID) - = (void*)GetProcAddress(dllhandle, "ChangeServiceConfig2A"); - BOOL (WINAPI *pQueryServiceConfig2A)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD) - = (void*)GetProcAddress(dllhandle, "QueryServiceConfig2A"); - BOOL (WINAPI *pQueryServiceConfig2W)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD) - = (void*)GetProcAddress(dllhandle, "QueryServiceConfig2W"); + if(!pQueryServiceConfig2A) { - skip("function QueryServiceConfig2A not present\n"); + win_skip("function QueryServiceConfig2A not present\n"); return; } @@ -1060,7 +1945,7 @@ static void test_queryconfig2(void) if(!pChangeServiceConfig2A) { - skip("function ChangeServiceConfig2A not present\n"); + win_skip("function ChangeServiceConfig2A not present\n"); goto cleanup; } @@ -1098,7 +1983,7 @@ static void test_queryconfig2(void) if(!pQueryServiceConfig2W) { - skip("function QueryServiceConfig2W not present\n"); + win_skip("function QueryServiceConfig2W not present\n"); goto cleanup; } SetLastError(0xdeadbeef); @@ -1144,31 +2029,31 @@ static void test_refcount(void) svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL); - ok(svc_handle1 != NULL, "Expected success\n"); + ok(svc_handle1 != NULL, "Expected success, got error %u\n", GetLastError()); /* Get a handle to this new service */ svc_handle2 = OpenServiceA(scm_handle, servicename, GENERIC_READ); - ok(svc_handle2 != NULL, "Expected success\n"); + ok(svc_handle2 != NULL, "Expected success, got error %u\n", GetLastError()); /* Get another handle to this new service */ svc_handle3 = OpenServiceA(scm_handle, servicename, GENERIC_READ); - ok(svc_handle3 != NULL, "Expected success\n"); + ok(svc_handle3 != NULL, "Expected success, got error %u\n", GetLastError()); /* Check if we can close the handle to the Service Control Manager */ ret = CloseServiceHandle(scm_handle); - ok(ret, "Expected success\n"); + ok(ret, "Expected success (err=%d)\n", GetLastError()); /* Get a new handle to the Service Control Manager */ scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL); - ok(scm_handle != NULL, "Expected success\n"); + ok(scm_handle != NULL, "Expected success, got error %u\n", GetLastError()); /* Get a handle to this new service */ svc_handle4 = OpenServiceA(scm_handle, servicename, GENERIC_ALL); - ok(svc_handle4 != NULL, "Expected success\n"); + ok(svc_handle4 != NULL, "Expected success, got error %u\n", GetLastError()); /* Delete the service */ ret = DeleteService(svc_handle4); - ok(ret, "Expected success\n"); + ok(ret, "Expected success (err=%d)\n", GetLastError()); /* We cannot create the same service again as it's still marked as 'being deleted'. * The reason is that we still have 4 open handles to this service even though we @@ -1194,13 +2079,13 @@ static void test_refcount(void) /* Close all the handles to the service and try again */ ret = CloseServiceHandle(svc_handle4); - ok(ret, "Expected success\n"); + ok(ret, "Expected success (err=%d)\n", GetLastError()); ret = CloseServiceHandle(svc_handle3); - ok(ret, "Expected success\n"); + ok(ret, "Expected success (err=%d)\n", GetLastError()); ret = CloseServiceHandle(svc_handle2); - ok(ret, "Expected success\n"); + ok(ret, "Expected success (err=%d)\n", GetLastError()); ret = CloseServiceHandle(svc_handle1); - ok(ret, "Expected success\n"); + ok(ret, "Expected success (err=%d)\n", GetLastError()); /* Wait a while. Doing a CreateService too soon will result again * in an ERROR_SERVICE_MARKED_FOR_DELETE error. @@ -1211,11 +2096,11 @@ static void test_refcount(void) svc_handle5 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL); - ok(svc_handle5 != NULL, "Expected success\n"); + ok(svc_handle5 != NULL, "Expected success, got error %u\n", GetLastError()); /* Delete the service */ ret = DeleteService(svc_handle5); - ok(ret, "Expected success\n"); + ok(ret, "Expected success (err=%d)\n", GetLastError()); /* Wait a while. Just in case one of the following tests does a CreateService again */ Sleep(1000); @@ -1234,17 +2119,21 @@ START_TEST(service) if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("OpenSCManagerA is not implemented, we are most likely on win9x\n"); + win_skip("OpenSCManagerA is not implemented, we are most likely on win9x\n"); return; } CloseServiceHandle(scm_handle); + init_function_pointers(); + /* First some parameter checking */ test_open_scm(); test_open_svc(); test_create_delete_svc(); test_get_displayname(); test_get_servicekeyname(); + test_query_svc(); + test_enum_svc(); test_close(); /* Test the creation, querying and deletion of a service */ test_sequence(); diff --git a/rostests/winetests/advpack/advpack.c b/rostests/winetests/advpack/advpack.c index eeb35c6264c..3ead0f25c4b 100644 --- a/rostests/winetests/advpack/advpack.c +++ b/rostests/winetests/advpack/advpack.c @@ -83,7 +83,7 @@ static BOOL init_function_pointers(void) if (!pCloseINFEngine || !pDelNode || !pGetVersionFromFile || !pOpenINFEngine || !pSetPerUserSecValues || !pTranslateInfString) { - skip("Needed functions are not available\n"); + win_skip("Needed functions are not available\n"); FreeLibrary(hAdvPack); return FALSE; } @@ -264,7 +264,7 @@ static void translateinfstring_test(void) if(hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)) { - trace("WinNT 3.51 detected. Skipping tests for TranslateInfString()\n"); + win_skip("WinNT 3.51 detected. Skipping tests for TranslateInfString()\n"); return; } @@ -272,6 +272,11 @@ static void translateinfstring_test(void) buffer[0] = 0; hr = pTranslateInfString(inf_file, "idontexist", "Options.NTx86", "InstallDir", buffer, MAX_PATH, &dwSize, NULL); + if (hr == E_ACCESSDENIED) + { + skip("TranslateInfString is broken\n"); + return; + } ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", (UINT)hr); ok(!strcmp(buffer, TEST_STRING2), "Expected %s, got %s\n", TEST_STRING2, buffer); ok(dwSize == 25, "Expected size 25, got %d\n", dwSize); @@ -325,6 +330,13 @@ static void translateinfstringex_test(void) char buffer[MAX_PATH]; DWORD size = MAX_PATH; + hr = pOpenINFEngine(inf_file, NULL, 0, &hinf, NULL); + if (hr == E_UNEXPECTED) + { + win_skip("Skipping tests on win9x because of brokenness\n"); + return; + } + create_inf_file(); /* need to see if there are any flags */ @@ -584,6 +596,11 @@ static void setperusersecvalues_test(void) /* set initial values */ lstrcpy(peruser.szGUID, "guid"); hr = pSetPerUserSecValues(&peruser); + if (hr == E_FAIL) + { + skip("SetPerUserSecValues is broken\n"); + return; + } ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(OPEN_GUID_KEY(), "Expected guid key to exist\n"); ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n"); diff --git a/rostests/winetests/advpack/advpack.rbuild b/rostests/winetests/advpack/advpack.rbuild index a9faacde7f2..cc1868832df 100644 --- a/rostests/winetests/advpack/advpack.rbuild +++ b/rostests/winetests/advpack/advpack.rbuild @@ -3,8 +3,7 @@ . - 0x600 - 0x600 + advpack.c files.c install.c @@ -12,7 +11,6 @@ wine cabinet advapi32 - kernel32 ntdll diff --git a/rostests/winetests/advpack/files.c b/rostests/winetests/advpack/files.c index d018975dcaf..9e79a295912 100644 --- a/rostests/winetests/advpack/files.c +++ b/rostests/winetests/advpack/files.c @@ -97,6 +97,7 @@ static BOOL check_ini_file_attr(LPSTR filename) static void test_AddDelBackupEntry(void) { + BOOL ret; HRESULT res; CHAR path[MAX_PATH]; CHAR windir[MAX_PATH]; @@ -132,8 +133,13 @@ static void test_AddDelBackupEntry(void) /* create the INF file */ res = pAddDelBackupEntry("one\0two\0three\0", "c:\\", "basename", AADBE_ADD_ENTRY); ok(res == S_OK, "Expected S_OK, got %d\n", res); + if (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES) + { ok(check_ini_file_attr(path), "Expected ini file to be hidden\n"); ok(DeleteFileA(path), "Expected path to exist\n"); + } + else + win_skip("Test file could not be created\n"); lstrcpyA(path, CURR_DIR); lstrcatA(path, "\\backup\\basename.INI"); @@ -165,38 +171,41 @@ static void test_AddDelBackupEntry(void) res = pAddDelBackupEntry("one\0three\0", NULL, "basename", AADBE_DEL_ENTRY); SetFileAttributesA(path, FILE_ATTRIBUTE_NORMAL); ok(res == S_OK, "Expected S_OK, got %d\n", res); - ok(DeleteFileA(path), "Expected path to exist\n"); + ret = DeleteFileA(path); + ok(ret == TRUE || + broken(ret == FALSE), /* win98 */ + "Expected path to exist\n"); } /* the FCI callbacks */ -static void *mem_alloc(ULONG cb) +static void * CDECL mem_alloc(ULONG cb) { return HeapAlloc(GetProcessHeap(), 0, cb); } -static void mem_free(void *memory) +static void CDECL mem_free(void *memory) { HeapFree(GetProcessHeap(), 0, memory); } -static BOOL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) +static BOOL CDECL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) { return TRUE; } -static long progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) +static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) { return 0; } -static int file_placed(PCCAB pccab, char *pszFile, long cbFile, +static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile, BOOL fContinuation, void *pv) { return 0; } -static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) +static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) { HANDLE handle; DWORD dwAccess = 0; @@ -220,7 +229,7 @@ static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) return (INT_PTR)handle; } -static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD dwRead; @@ -232,7 +241,7 @@ static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) return dwRead; } -static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD dwWritten; @@ -244,7 +253,7 @@ static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) return dwWritten; } -static int fci_close(INT_PTR hf, int *err, void *pv) +static int CDECL fci_close(INT_PTR hf, int *err, void *pv) { HANDLE handle = (HANDLE)hf; ok(CloseHandle(handle), "Failed to CloseHandle\n"); @@ -252,7 +261,7 @@ static int fci_close(INT_PTR hf, int *err, void *pv) return 0; } -static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv) +static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD ret; @@ -263,7 +272,7 @@ static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv) return ret; } -static int fci_delete(char *pszFile, int *err, void *pv) +static int CDECL fci_delete(char *pszFile, int *err, void *pv) { BOOL ret = DeleteFileA(pszFile); ok(ret, "Failed to DeleteFile %s\n", pszFile); @@ -271,7 +280,7 @@ static int fci_delete(char *pszFile, int *err, void *pv) return 0; } -static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv) +static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv) { LPSTR tempname; @@ -290,7 +299,7 @@ static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv) return FALSE; } -static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, +static INT_PTR CDECL get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, USHORT *pattribs, int *err, void *pv) { BY_HANDLE_FILE_INFORMATION finfo; diff --git a/rostests/winetests/advpack/install.c b/rostests/winetests/advpack/install.c index 854ede6dae5..3b0954fcf23 100644 --- a/rostests/winetests/advpack/install.c +++ b/rostests/winetests/advpack/install.c @@ -55,27 +55,20 @@ static BOOL is_spapi_err(DWORD err) return (((err & SPAPI_MASK) ^ SPAPI_PREFIX) == 0); } -static void append_str(char **str, const char *data) -{ - sprintf(*str, data); - *str += strlen(*str); -} - static void create_inf_file(LPCSTR filename) { - char data[1024]; - char *ptr = data; DWORD dwNumberOfBytesWritten; HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - append_str(&ptr, "[Version]\n"); - append_str(&ptr, "Signature=\"$Chicago$\"\n"); - append_str(&ptr, "AdvancedINF=2.5\n"); - append_str(&ptr, "[DefaultInstall]\n"); - append_str(&ptr, "CheckAdminRights=1\n"); + static const char data[] = + "[Version]\n" + "Signature=\"$Chicago$\"\n" + "AdvancedINF=2.5\n" + "[DefaultInstall]\n" + "CheckAdminRights=1\n"; - WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); + WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL); CloseHandle(hf); } diff --git a/rostests/winetests/browseui/autocomplete.c b/rostests/winetests/browseui/autocomplete.c index bddaa52274a..85a7da5ebc7 100644 --- a/rostests/winetests/browseui/autocomplete.c +++ b/rostests/winetests/browseui/autocomplete.c @@ -20,9 +20,11 @@ #include #include +#include #include #include #include +#include #include "wine/test.h" @@ -43,10 +45,10 @@ ok(FALSE, #exp " failed: %x\n", res); \ } -LPWSTR strdup_AtoW(LPCSTR str) +static LPWSTR strdup_AtoW(LPCSTR str) { int size = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); - LPWSTR wstr = (LPWSTR)CoTaskMemAlloc((size + 1)*sizeof(WCHAR)); + LPWSTR wstr = CoTaskMemAlloc((size + 1)*sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, size+1); return wstr; } @@ -84,14 +86,14 @@ static TestACL *TestACL_Constructor(int limit, const char **strings) return This; } -ULONG STDMETHODCALLTYPE TestACL_AddRef(IEnumString *iface) +static ULONG STDMETHODCALLTYPE TestACL_AddRef(IEnumString *iface) { TestACL *This = (TestACL *)iface; trace("ACL(%p): addref (%d)\n", This, This->ref+1); return InterlockedIncrement(&This->ref); } -ULONG STDMETHODCALLTYPE TestACL_Release(IEnumString *iface) +static ULONG STDMETHODCALLTYPE TestACL_Release(IEnumString *iface) { TestACL *This = (TestACL *)iface; ULONG res; @@ -101,7 +103,7 @@ ULONG STDMETHODCALLTYPE TestACL_Release(IEnumString *iface) return res; } -HRESULT STDMETHODCALLTYPE TestACL_QueryInterface(IEnumString *iface, REFIID iid, LPVOID *ppvOut) +static HRESULT STDMETHODCALLTYPE TestACL_QueryInterface(IEnumString *iface, REFIID iid, LPVOID *ppvOut) { TestACL *This = (TestACL *)iface; *ppvOut = NULL; @@ -127,7 +129,7 @@ HRESULT STDMETHODCALLTYPE TestACL_QueryInterface(IEnumString *iface, REFIID iid, return E_NOINTERFACE; } -HRESULT STDMETHODCALLTYPE TestACL_Next(IEnumString *iface, ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched) +static HRESULT STDMETHODCALLTYPE TestACL_Next(IEnumString *iface, ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched) { TestACL *This = (TestACL *)iface; ULONG i; @@ -148,19 +150,19 @@ HRESULT STDMETHODCALLTYPE TestACL_Next(IEnumString *iface, ULONG celt, LPOLESTR return S_FALSE; } -HRESULT STDMETHODCALLTYPE TestACL_Skip(IEnumString *iface, ULONG celt) +static HRESULT STDMETHODCALLTYPE TestACL_Skip(IEnumString *iface, ULONG celt) { ok(FALSE, "Unexpected call to TestACL_Skip\n"); return E_NOTIMPL; } -HRESULT STDMETHODCALLTYPE TestACL_Clone(IEnumString *iface, IEnumString **out) +static HRESULT STDMETHODCALLTYPE TestACL_Clone(IEnumString *iface, IEnumString **out) { ok(FALSE, "Unexpected call to TestACL_Clone\n"); return E_OUTOFMEMORY; } -HRESULT STDMETHODCALLTYPE TestACL_Reset(IEnumString *iface) +static HRESULT STDMETHODCALLTYPE TestACL_Reset(IEnumString *iface) { TestACL *This = (TestACL *)iface; trace("ACL(%p): Reset\n", This); @@ -168,7 +170,7 @@ HRESULT STDMETHODCALLTYPE TestACL_Reset(IEnumString *iface) return S_OK; } -HRESULT STDMETHODCALLTYPE TestACL_Expand(IACList *iface, LPCOLESTR str) +static HRESULT STDMETHODCALLTYPE TestACL_Expand(IACList *iface, LPCOLESTR str) { TestACL *This = impl_from_IACList(iface); trace("ACL(%p): Expand\n", impl_from_IACList(iface)); @@ -188,17 +190,17 @@ IEnumStringVtbl TestACLVtbl = TestACL_Clone }; -ULONG STDMETHODCALLTYPE TestACL_ACList_AddRef(IACList *iface) +static ULONG STDMETHODCALLTYPE TestACL_ACList_AddRef(IACList *iface) { return TestACL_AddRef((IEnumString *)impl_from_IACList(iface)); } -ULONG STDMETHODCALLTYPE TestACL_ACList_Release(IACList *iface) +static ULONG STDMETHODCALLTYPE TestACL_ACList_Release(IACList *iface) { return TestACL_Release((IEnumString *)impl_from_IACList(iface)); } -HRESULT STDMETHODCALLTYPE TestACL_ACList_QueryInterface(IACList *iface, REFIID iid, LPVOID *ppvout) +static HRESULT STDMETHODCALLTYPE TestACL_ACList_QueryInterface(IACList *iface, REFIID iid, LPVOID *ppvout) { return TestACL_QueryInterface((IEnumString *)impl_from_IACList(iface), iid, ppvout); } diff --git a/rostests/winetests/browseui/browseui.rbuild b/rostests/winetests/browseui/browseui.rbuild index 05711a227bf..12d5649fc37 100644 --- a/rostests/winetests/browseui/browseui.rbuild +++ b/rostests/winetests/browseui/browseui.rbuild @@ -3,12 +3,10 @@ . - 0x600 - 0x600 + wine ole32 user32 - kernel32 uuid ntdll autocomplete.c diff --git a/rostests/winetests/cabinet/cabinet.rbuild b/rostests/winetests/cabinet/cabinet.rbuild index 7264960ea68..727c66b9c9f 100644 --- a/rostests/winetests/cabinet/cabinet.rbuild +++ b/rostests/winetests/cabinet/cabinet.rbuild @@ -3,14 +3,12 @@ . - 0x600 - 0x600 + extract.c fdi.c testlist.c wine cabinet - kernel32 ntdll diff --git a/rostests/winetests/cabinet/extract.c b/rostests/winetests/cabinet/extract.c index 156df177a9b..0bf29be4a4e 100644 --- a/rostests/winetests/cabinet/extract.c +++ b/rostests/winetests/cabinet/extract.c @@ -111,33 +111,33 @@ static void delete_test_files(void) /* the FCI callbacks */ -static void *mem_alloc(ULONG cb) +static void * CDECL mem_alloc(ULONG cb) { return HeapAlloc(GetProcessHeap(), 0, cb); } -static void mem_free(void *memory) +static void CDECL mem_free(void *memory) { HeapFree(GetProcessHeap(), 0, memory); } -static BOOL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) +static BOOL CDECL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) { return TRUE; } -static long progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) +static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) { return 0; } -static int file_placed(PCCAB pccab, char *pszFile, long cbFile, +static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile, BOOL fContinuation, void *pv) { return 0; } -static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) +static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) { HANDLE handle; DWORD dwAccess = 0; @@ -161,7 +161,7 @@ static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) return (INT_PTR)handle; } -static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD dwRead; @@ -173,7 +173,7 @@ static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) return dwRead; } -static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD dwWritten; @@ -185,7 +185,7 @@ static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) return dwWritten; } -static int fci_close(INT_PTR hf, int *err, void *pv) +static int CDECL fci_close(INT_PTR hf, int *err, void *pv) { HANDLE handle = (HANDLE)hf; ok(CloseHandle(handle), "Failed to CloseHandle\n"); @@ -193,7 +193,7 @@ static int fci_close(INT_PTR hf, int *err, void *pv) return 0; } -static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv) +static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD ret; @@ -204,7 +204,7 @@ static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv) return ret; } -static int fci_delete(char *pszFile, int *err, void *pv) +static int CDECL fci_delete(char *pszFile, int *err, void *pv) { BOOL ret = DeleteFileA(pszFile); ok(ret, "Failed to DeleteFile %s\n", pszFile); @@ -212,7 +212,7 @@ static int fci_delete(char *pszFile, int *err, void *pv) return 0; } -static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv) +static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv) { LPSTR tempname; @@ -231,7 +231,7 @@ static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv) return FALSE; } -static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, +static INT_PTR CDECL get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, USHORT *pattribs, int *err, void *pv) { BY_HANDLE_FILE_INFORMATION finfo; diff --git a/rostests/winetests/cabinet/fdi.c b/rostests/winetests/cabinet/fdi.c index f90b6f0abea..9fa3051d9a7 100644 --- a/rostests/winetests/cabinet/fdi.c +++ b/rostests/winetests/cabinet/fdi.c @@ -32,22 +32,22 @@ CHAR CURR_DIR[MAX_PATH]; /* FDI callbacks */ -static void *fdi_alloc(ULONG cb) +static void * CDECL fdi_alloc(ULONG cb) { return HeapAlloc(GetProcessHeap(), 0, cb); } -static void *fdi_alloc_bad(ULONG cb) +static void * CDECL fdi_alloc_bad(ULONG cb) { return NULL; } -static void fdi_free(void *pv) +static void CDECL fdi_free(void *pv) { HeapFree(GetProcessHeap(), 0, pv); } -static INT_PTR fdi_open(char *pszFile, int oflag, int pmode) +static INT_PTR CDECL fdi_open(char *pszFile, int oflag, int pmode) { HANDLE handle; handle = CreateFileA(pszFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -57,7 +57,7 @@ static INT_PTR fdi_open(char *pszFile, int oflag, int pmode) return (INT_PTR) handle; } -static UINT fdi_read(INT_PTR hf, void *pv, UINT cb) +static UINT CDECL fdi_read(INT_PTR hf, void *pv, UINT cb) { HANDLE handle = (HANDLE) hf; DWORD dwRead; @@ -66,7 +66,7 @@ static UINT fdi_read(INT_PTR hf, void *pv, UINT cb) return 0; } -static UINT fdi_write(INT_PTR hf, void *pv, UINT cb) +static UINT CDECL fdi_write(INT_PTR hf, void *pv, UINT cb) { HANDLE handle = (HANDLE) hf; DWORD dwWritten; @@ -75,13 +75,13 @@ static UINT fdi_write(INT_PTR hf, void *pv, UINT cb) return 0; } -static int fdi_close(INT_PTR hf) +static int CDECL fdi_close(INT_PTR hf) { HANDLE handle = (HANDLE) hf; return CloseHandle(handle) ? 0 : -1; } -static long fdi_seek(INT_PTR hf, long dist, int seektype) +static LONG CDECL fdi_seek(INT_PTR hf, LONG dist, int seektype) { HANDLE handle = (HANDLE) hf; return SetFilePointer(handle, dist, NULL, seektype); @@ -287,10 +287,9 @@ static void createTestFile(const CHAR *name) static void create_test_files(void) { - int len; + DWORD len; - GetCurrentDirectoryA(MAX_PATH, CURR_DIR); - len = lstrlenA(CURR_DIR); + len = GetCurrentDirectoryA(MAX_PATH, CURR_DIR); if(len && (CURR_DIR[len-1] == '\\')) CURR_DIR[len-1] = 0; @@ -315,33 +314,33 @@ static void delete_test_files(void) /* FCI callbacks */ -static void *mem_alloc(ULONG cb) +static void * CDECL mem_alloc(ULONG cb) { return HeapAlloc(GetProcessHeap(), 0, cb); } -static void mem_free(void *memory) +static void CDECL mem_free(void *memory) { HeapFree(GetProcessHeap(), 0, memory); } -static BOOL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) +static BOOL CDECL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) { return TRUE; } -static long progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) +static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) { return 0; } -static int file_placed(PCCAB pccab, char *pszFile, long cbFile, +static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile, BOOL fContinuation, void *pv) { return 0; } -static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) +static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) { HANDLE handle; DWORD dwAccess = 0; @@ -365,7 +364,7 @@ static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) return (INT_PTR)handle; } -static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD dwRead; @@ -377,7 +376,7 @@ static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) return dwRead; } -static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD dwWritten; @@ -389,7 +388,7 @@ static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) return dwWritten; } -static int fci_close(INT_PTR hf, int *err, void *pv) +static int CDECL fci_close(INT_PTR hf, int *err, void *pv) { HANDLE handle = (HANDLE)hf; ok(CloseHandle(handle), "Failed to CloseHandle\n"); @@ -397,7 +396,7 @@ static int fci_close(INT_PTR hf, int *err, void *pv) return 0; } -static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv) +static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD ret; @@ -408,7 +407,7 @@ static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv) return ret; } -static int fci_delete(char *pszFile, int *err, void *pv) +static int CDECL fci_delete(char *pszFile, int *err, void *pv) { BOOL ret = DeleteFileA(pszFile); ok(ret, "Failed to DeleteFile %s\n", pszFile); @@ -416,7 +415,7 @@ static int fci_delete(char *pszFile, int *err, void *pv) return 0; } -static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv) +static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv) { LPSTR tempname; @@ -435,7 +434,7 @@ static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv) return FALSE; } -static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, +static INT_PTR CDECL get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, USHORT *pattribs, int *err, void *pv) { BY_HANDLE_FILE_INFORMATION finfo; @@ -544,11 +543,11 @@ static void test_FDIIsCabinet(void) /* invalid file handle */ ZeroMemory(&cabinfo, sizeof(FDICABINETINFO)); SetLastError(0xdeadbeef); - ret = FDIIsCabinet(hfdi, (int)INVALID_HANDLE_VALUE, &cabinfo); + ret = FDIIsCabinet(hfdi, -1, &cabinfo); ok(ret == FALSE, "Expected FALSE, got %d\n", ret); ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); - ok(cabinfo.cbCabinet == 0, "Expected 0, got %ld\n", cabinfo.cbCabinet); + ok(cabinfo.cbCabinet == 0, "Expected 0, got %d\n", cabinfo.cbCabinet); ok(cabinfo.cFiles == 0, "Expected 0, got %d\n", cabinfo.cFiles); ok(cabinfo.cFolders == 0, "Expected 0, got %d\n", cabinfo.cFolders); ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet); @@ -563,7 +562,7 @@ static void test_FDIIsCabinet(void) ret = FDIIsCabinet(hfdi, fd, &cabinfo); ok(ret == FALSE, "Expected FALSE, got %d\n", ret); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(cabinfo.cbCabinet == 0, "Expected 0, got %ld\n", cabinfo.cbCabinet); + ok(cabinfo.cbCabinet == 0, "Expected 0, got %d\n", cabinfo.cbCabinet); ok(cabinfo.cFiles == 0, "Expected 0, got %d\n", cabinfo.cFiles); ok(cabinfo.cFolders == 0, "Expected 0, got %d\n", cabinfo.cFolders); ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet); @@ -584,7 +583,7 @@ static void test_FDIIsCabinet(void) ok(cabinfo.setID == 0xbeef, "Expected 0xbeef, got %d\n", cabinfo.setID); todo_wine { - ok(cabinfo.cbCabinet == 182, "Expected 182, got %ld\n", cabinfo.cbCabinet); + ok(cabinfo.cbCabinet == 182, "Expected 182, got %d\n", cabinfo.cbCabinet); ok(cabinfo.iCabinet == 0, "Expected 0, got %d\n", cabinfo.iCabinet); } @@ -594,7 +593,7 @@ static void test_FDIIsCabinet(void) } -INT_PTR __cdecl CopyProgress (FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) +static INT_PTR __cdecl CopyProgress(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) { return 0; } @@ -609,8 +608,6 @@ static void test_FDICopy(void) char name[] = "extract.cab"; char path[MAX_PATH + 1]; - GetCurrentDirectoryA(MAX_PATH, path); - set_cab_parameters(&cabParams); hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open, @@ -622,11 +619,15 @@ static void test_FDICopy(void) FCIDestroy(hfci); + lstrcpyA(path, CURR_DIR); + + /* path doesn't have a trailing backslash */ + if (lstrlenA(path) > 2) + { hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read, fdi_write, fdi_close, fdi_seek, cpuUNKNOWN, &erf); - /* cabinet with no files or folders */ SetLastError(0xdeadbeef); ret = FDICopy(hfdi, name, path, 0, CopyProgress, NULL, 0); ok(ret == FALSE, "Expected FALSE, got %d\n", ret); @@ -637,6 +638,25 @@ static void test_FDICopy(void) } FDIDestroy(hfdi); + } + else + skip("Running on a root drive directory.\n"); + + lstrcatA(path, "\\"); + + hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read, + fdi_write, fdi_close, fdi_seek, + cpuUNKNOWN, &erf); + + /* cabinet with no files or folders */ + SetLastError(0xdeadbeef); + ret = FDICopy(hfdi, name, path, 0, CopyProgress, NULL, 0); + todo_wine + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(GetLastError() == 0, "Expected 0f, got %d\n", GetLastError()); + + FDIDestroy(hfdi); + DeleteFileA(name); } diff --git a/rostests/winetests/comcat/comcat.c b/rostests/winetests/comcat/comcat.c index 914cbe8b2a2..da3f66490b5 100644 --- a/rostests/winetests/comcat/comcat.c +++ b/rostests/winetests/comcat/comcat.c @@ -21,6 +21,7 @@ #define COBJMACROS #include +#include #include #include "objbase.h" @@ -30,19 +31,19 @@ #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x \n", hr) -static void register_testentry(void) +static BOOL register_testentry(void) { - HKEY hkey,hkey2; + HKEY hkey = 0, hkey2 = 0; + DWORD ret; - RegCreateKeyA(HKEY_CLASSES_ROOT,"CLSID\\{deadcafe-beed-bead-dead-cafebeaddead}", - &hkey); - RegSetValueA(hkey,NULL,REG_SZ,"ComCat Test key",16); - RegCreateKeyA(hkey, + ret = RegCreateKeyA(HKEY_CLASSES_ROOT,"CLSID\\{deadcafe-beed-bead-dead-cafebeaddead}", &hkey); + if (!ret) ret = RegSetValueA(hkey,NULL,REG_SZ,"ComCat Test key",16); + if (!ret) ret = RegCreateKeyA(hkey, "Implemented Categories\\{deadcafe-0000-0000-0000-000000000000}", &hkey2); - RegCloseKey(hkey); RegCloseKey(hkey2); + return !ret; } static void unregister_testentry(void) @@ -83,8 +84,8 @@ static void do_enum(void) IEnumCLSID *pIEnum =(IEnumCLSID*)0xdeadcafe; - CLSIDFromString((LPOLESTR)szCatID,the_cat); - CLSIDFromString((LPOLESTR)szGuid,&wanted_guid); + CLSIDFromString(szCatID,the_cat); + CLSIDFromString(szGuid,&wanted_guid); OleInitialize(NULL); @@ -106,9 +107,9 @@ static void do_enum(void) ok (fetched == 0,"Fetched wrong number of guids %u\n",fetched); IEnumGUID_Release(pIEnum); - register_testentry(); - hr = ICatInformation_EnumClassesOfCategories(pICat, 1, the_cat, -1, NULL, - &pIEnum); + if (register_testentry()) + { + hr = ICatInformation_EnumClassesOfCategories(pICat, 1, the_cat, -1, NULL, &pIEnum); ok_ole_success(hr,"ICatInformation_EnumClassesOfCategories"); hr = IEnumGUID_Next(pIEnum,1,the_guid, &fetched); @@ -116,8 +117,11 @@ static void do_enum(void) ok (IsEqualGUID(the_guid,&wanted_guid),"Guids do not match\n"); IEnumGUID_Release(pIEnum); - ICatInformation_Release(pICat); unregister_testentry(); + } + else skip( "Could not register the test category\n" ); + + ICatInformation_Release(pICat); OleUninitialize(); } diff --git a/rostests/winetests/comcat/comcat.rbuild b/rostests/winetests/comcat/comcat.rbuild index fc2c18175fb..f6f98c32876 100644 --- a/rostests/winetests/comcat/comcat.rbuild +++ b/rostests/winetests/comcat/comcat.rbuild @@ -3,14 +3,12 @@ . - 0x600 - 0x600 + comcat.c testlist.c wine ole32 advapi32 - kernel32 uuid ntdll diff --git a/rostests/winetests/comctl32/comboex.c b/rostests/winetests/comctl32/comboex.c index eca7ca4b6ee..1e741924ce8 100644 --- a/rostests/winetests/comctl32/comboex.c +++ b/rostests/winetests/comctl32/comboex.c @@ -183,6 +183,13 @@ static void test_WM_LBUTTONDOWN(void) WCHAR buffer[3]; static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72}; static const WCHAR stringFormat[] = {'%','2','d','\0'}; + BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO); + + pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo"); + if (!pGetComboBoxInfo){ + win_skip("GetComboBoxInfo is not available\n"); + return; + } hComboEx = CreateWindowExA(0, WC_COMBOBOXEXA, NULL, WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150, @@ -205,7 +212,7 @@ static void test_WM_LBUTTONDOWN(void) hEdit = (HWND)SendMessage(hComboEx, CBEM_GETEDITCONTROL, 0, 0); cbInfo.cbSize = sizeof(COMBOBOXINFO); - result = SendMessage(hCombo, CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbInfo); + result = pGetComboBoxInfo(hCombo, &cbInfo); ok(result, "Failed to get combobox info structure. LastError=%d\n", GetLastError()); hList = cbInfo.hwndList; @@ -221,7 +228,8 @@ static void test_WM_LBUTTONDOWN(void) result = SendMessage(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", GetLastError()); - ok(GetFocus() == hCombo, + ok(GetFocus() == hCombo || + broken(GetFocus() != hCombo), /* win98 */ "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", GetFocus()); ok(SendMessage(hComboEx, CB_GETDROPPEDSTATE, 0, 0), @@ -232,7 +240,8 @@ static void test_WM_LBUTTONDOWN(void) result = SendMessage(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n", GetLastError()); - ok(GetFocus() == hCombo, + ok(GetFocus() == hCombo || + broken(GetFocus() != hCombo), /* win98 */ "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", GetFocus()); @@ -244,14 +253,16 @@ static void test_WM_LBUTTONDOWN(void) result = SendMessage(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y)); ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n", GetLastError()); - ok(GetFocus() == hCombo, + ok(GetFocus() == hCombo || + broken(GetFocus() != hCombo), /* win98 */ "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", GetFocus()); result = SendMessage(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", GetLastError()); - ok(GetFocus() == hCombo, + ok(GetFocus() == hCombo || + broken(GetFocus() != hCombo), /* win98 */ "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", GetFocus()); ok(SendMessage(hComboEx, CB_GETDROPPEDSTATE, 0, 0), @@ -260,13 +271,19 @@ static void test_WM_LBUTTONDOWN(void) result = SendMessage(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n", GetLastError()); - todo_wine ok(GetFocus() == hEdit, + todo_wine ok(GetFocus() == hEdit || + broken(GetFocus() == hCombo), /* win98 */ "Focus not on ComboBoxEx's Edit Control, instead on %p\n", GetFocus()); - ok(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0), + + result = SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0); + ok(!result || + broken(result != 0), /* win98 */ "The dropdown list should have been rolled up.\n"); idx = SendMessage(hComboEx, CB_GETCURSEL, 0, 0); - ok(idx == 4, "Current Selection: expected %d, got %d\n", 4, idx); + ok(idx == 4 || + broken(idx == -1), /* win98 */ + "Current Selection: expected %d, got %d\n", 4, idx); DestroyWindow(hComboEx); } @@ -297,7 +314,7 @@ static int init(void) pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); if (!pInitCommonControlsEx) { - skip("InitCommonControlsEx() is missing. Skipping the tests\n"); + win_skip("InitCommonControlsEx() is missing. Skipping the tests\n"); return 0; } iccex.dwSize = sizeof(iccex); @@ -334,6 +351,7 @@ static void cleanup(void) DispatchMessageA(&msg); } + DestroyWindow(hComboExParentWnd); UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL)); } diff --git a/rostests/winetests/comctl32/comctl32.rbuild b/rostests/winetests/comctl32/comctl32.rbuild index 49f06a479de..94804620870 100644 --- a/rostests/winetests/comctl32/comctl32.rbuild +++ b/rostests/winetests/comctl32/comctl32.rbuild @@ -3,13 +3,13 @@ . - 0x600 - 0x600 + comboex.c datetime.c dpa.c header.c imagelist.c + ipaddress.c listview.c misc.c monthcal.c @@ -34,7 +34,6 @@ user32 gdi32 advapi32 - kernel32 ntdll diff --git a/rostests/winetests/comctl32/datetime.c b/rostests/winetests/comctl32/datetime.c index b194cc1b6ae..8fdbbe53608 100644 --- a/rostests/winetests/comctl32/datetime.c +++ b/rostests/winetests/comctl32/datetime.c @@ -140,7 +140,7 @@ struct subclass_info static LRESULT WINAPI datetime_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -197,7 +197,7 @@ static void test_dtm_set_format(HWND hWndDateTime) SYSTEMTIME systime; LRESULT r; - r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, (LPARAM)NULL); + r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, 0); expect(1, r); r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, @@ -256,7 +256,7 @@ static void test_dtm_set_and_get_mcfont(HWND hWndDateTime) { HFONT hFontOrig, hFontNew; - hFontOrig = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + hFontOrig = GetStockObject(DEFAULT_GUI_FONT); SendMessage(hWndDateTime, DTM_SETMCFONT, (WPARAM)hFontOrig, TRUE); hFontNew = (HFONT)SendMessage(hWndDateTime, DTM_GETMCFONT, 0, 0); ok(hFontOrig == hFontNew, "Expected hFontOrig==hFontNew, hFontOrig=%p, hFontNew=%p\n", hFontOrig, hFontNew); @@ -271,7 +271,7 @@ static void test_dtm_get_monthcal(HWND hWndDateTime) todo_wine { r = SendMessage(hWndDateTime, DTM_GETMONTHCAL, 0, 0); - ok(r == (LPARAM)NULL, "Expected NULL(no child month calendar control), got %ld\n", r); + ok(r == 0, "Expected NULL(no child month calendar control), got %ld\n", r); } ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_get_monthcal_seq, "test_dtm_get_monthcal", FALSE); diff --git a/rostests/winetests/comctl32/dpa.c b/rostests/winetests/comctl32/dpa.c index b2ea3d8c327..221bcba1678 100644 --- a/rostests/winetests/comctl32/dpa.c +++ b/rostests/winetests/comctl32/dpa.c @@ -25,7 +25,6 @@ #include "windef.h" #include "winbase.h" -#include "wingdi.h" #include "winuser.h" #include "commctrl.h" #include "objidl.h" @@ -42,7 +41,6 @@ typedef struct _ITEMDATA PVOID pvData; } ITEMDATA, *LPITEMDATA; -typedef PVOID (CALLBACK *PFNDPAMERGE)(UINT,PVOID,PVOID,LPARAM); typedef HRESULT (CALLBACK *PFNDPASTM)(LPITEMDATA,IStream*,LPARAM); static HDPA (WINAPI *pDPA_Clone)(const HDPA,const HDPA); @@ -183,7 +181,7 @@ static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut) do { - pDPA_InsertPtr(dpa, 0, (PVOID)(dwIn & 0xf)); + pDPA_InsertPtr(dpa, 0, (PVOID)(ULONG_PTR)(dwIn & 0xf)); dwIn >>= 4; } while(dwIn); @@ -243,9 +241,9 @@ static void test_dpa(void) for(i = 1; i <= 6; i++) { INT j, k; - k = pDPA_GetPtrIndex(dpa, (PVOID)i); + k = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i); /* Linear searches should work on unsorted DPAs */ - j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpLT, 0xdeadbeef, 0); + j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0xdeadbeef, 0); ok(j == k, "j=%d k=%d\n", j, k); } @@ -280,16 +278,16 @@ static void test_dpa(void) INT j; /* The array is in order so ptr == index+1 */ - j = pDPA_GetPtrIndex(dpa, (PVOID)i); + j = pDPA_GetPtrIndex(dpa, (PVOID)(INT_PTR)i); ok(j+1 == i, "j=%d i=%d\n", j, i); - j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpLT, 0xdeadbeef, DPAS_SORTED); + j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpLT, 0xdeadbeef, DPAS_SORTED); ok(j+1 == i, "j=%d i=%d\n", j, i); /* Linear searches respect iStart ... */ - j = pDPA_Search(dpa, (PVOID)i, i+1, CB_CmpLT, 0xdeadbeef, 0); + j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, 0); ok(j == DPA_ERR, "j=%d\n", j); /* ... but for a binary search it's ignored */ - j = pDPA_Search(dpa, (PVOID)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED); + j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED); todo_wine ok(j+1 == i, "j=%d i=%d\n", j, i); } @@ -332,7 +330,7 @@ static void test_dpa(void) * should be bogus */ for(i = 0; i < 6; i++) { - INT j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpGT, 0xdeadbeef, + INT j = pDPA_Search(dpa, (PVOID)(INT_PTR)i, 0, CB_CmpGT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTBEFORE); ok(j != i, "i=%d\n", i); } @@ -364,7 +362,9 @@ static void test_dpa(void) rc=CheckDPA(dpa, 0x123456, &dw); ok(rc, "dw=0x%x\n", dw); rc=CheckDPA(dpa2, 0x123456, &dw2); - ok(rc, "dw2=0x%x\n", dw2); + ok(rc || + broken(!rc), /* win98 */ + "dw2=0x%x\n", dw2); rc=CheckDPA(dpa3, 0x123456, &dw3); ok(rc, "dw3=0x%x\n", dw3); } @@ -372,7 +372,7 @@ static void test_dpa(void) if(pDPA_EnumCallback) { nEnum = 0; - pDPA_EnumCallback(dpa2, CB_EnumFirstThree, (PVOID)dpa2); + pDPA_EnumCallback(dpa2, CB_EnumFirstThree, dpa2); rc=CheckDPA(dpa2, 0x777456, &dw2); ok(rc, "dw=0x%x\n", dw2); ok(nEnum == 3, "nEnum=%d\n", nEnum); @@ -453,5 +453,5 @@ START_TEST(dpa) if(InitFunctionPtrs(hcomctl32)) test_dpa(); else - trace("skipping tests\n"); + win_skip("Needed functions are not available\n"); } diff --git a/rostests/winetests/comctl32/header.c b/rostests/winetests/comctl32/header.c index a3778cff588..74670c86287 100644 --- a/rostests/winetests/comctl32/header.c +++ b/rostests/winetests/comctl32/header.c @@ -39,6 +39,7 @@ static CUSTOMDRAWPROC g_CustomDrawProc; static int g_CustomDrawCount; static DRAWITEMSTRUCT g_DrawItem; static BOOL g_DrawItemReceived; +static DWORD g_customheight; static EXPECTEDNOTIFY expectedNotify[10]; static INT nExpectedNotify = 0; @@ -89,7 +90,7 @@ static const struct message add_header_to_parent_seq_interactive[] = { static const struct message add_header_to_parent_seq[] = { { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, - { WM_QUERYUISTATE, sent }, + { WM_QUERYUISTATE, sent|optional }, { WM_PARENTNOTIFY, sent }, { 0 } }; @@ -196,8 +197,8 @@ static const struct message filterMessages_seq_noninteractive[] = { { HDM_SETFILTERCHANGETIMEOUT, sent|wparam|lparam, 1, 100 }, { HDM_CLEARFILTER, sent|wparam|lparam, 0, 1 }, { HDM_EDITFILTER, sent|wparam|lparam, 1, 0 }, - { WM_PARENTNOTIFY, sent|wparam|defwinproc, WM_CREATE }, - { WM_COMMAND, sent|defwinproc }, + { WM_PARENTNOTIFY, sent|wparam|defwinproc|optional, WM_CREATE }, + { WM_COMMAND, sent|defwinproc|optional }, { 0 } }; @@ -304,11 +305,11 @@ static LONG getItem(HWND hdex, int idx, LPSTR textBuffer) static void addReadDelItem(HWND hdex, HDITEMA *phdiCreate, int maskRead, HDITEMA *phdiRead) { - ok(SendMessage(hdex, HDM_INSERTITEMA, (WPARAM)0, (LPARAM)phdiCreate)!=-1, "Adding item failed\n"); + ok(SendMessage(hdex, HDM_INSERTITEMA, 0, (LPARAM)phdiCreate)!=-1, "Adding item failed\n"); ZeroMemory(phdiRead, sizeof(HDITEMA)); phdiRead->mask = maskRead; - ok(SendMessage(hdex, HDM_GETITEMA, (WPARAM)0, (LPARAM)phdiRead)!=0, "Getting item data failed\n"); - ok(SendMessage(hdex, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0)!=0, "Deleting item failed\n"); + ok(SendMessage(hdex, HDM_GETITEMA, 0, (LPARAM)phdiRead)!=0, "Getting item data failed\n"); + ok(SendMessage(hdex, HDM_DELETEITEM, 0, 0)!=0, "Deleting item failed\n"); } static HWND create_header_control (void) @@ -403,7 +404,7 @@ struct subclass_info static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -424,7 +425,7 @@ static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wPara static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -465,7 +466,7 @@ static BOOL register_parent_wnd_class(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(NULL); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "Header test parent class"; @@ -661,24 +662,24 @@ static void check_mask(void) hdi.iOrder = 0; hdi.lParam = 17; hdi.cchTextMax = 260; - ret = SendMessage(hWndHeader, HDM_INSERTITEM, (WPARAM)0, (LPARAM)&hdi); + ret = SendMessage(hWndHeader, HDM_INSERTITEM, 0, (LPARAM)&hdi); ok(ret == -1, "Creating an item with a zero mask should have failed\n"); - if (ret != -1) SendMessage(hWndHeader, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0); + if (ret != -1) SendMessage(hWndHeader, HDM_DELETEITEM, 0, 0); /* with a non-zero mask creation will succeed */ ZeroMemory(&hdi, sizeof(hdi)); hdi.mask = HDI_LPARAM; - ret = SendMessage(hWndHeader, HDM_INSERTITEM, (WPARAM)0, (LPARAM)&hdi); + ret = SendMessage(hWndHeader, HDM_INSERTITEM, 0, (LPARAM)&hdi); ok(ret != -1, "Adding item with non-zero mask failed\n"); if (ret != -1) - SendMessage(hWndHeader, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0); + SendMessage(hWndHeader, HDM_DELETEITEM, 0, 0); /* in SETITEM if the mask contains a unknown bit, it is ignored */ ZeroMemory(&hdi, sizeof(hdi)); hdi.mask = 0x08000000 | HDI_LPARAM | HDI_IMAGE; hdi.lParam = 133; hdi.iImage = 17; - ret = SendMessage(hWndHeader, HDM_INSERTITEM, (WPARAM)0, (LPARAM)&hdi); + ret = SendMessage(hWndHeader, HDM_INSERTITEM, 0, (LPARAM)&hdi); ok(ret != -1, "Adding item failed\n"); if (ret != -1) @@ -686,18 +687,18 @@ static void check_mask(void) /* check result */ ZeroMemory(&hdi, sizeof(hdi)); hdi.mask = HDI_LPARAM | HDI_IMAGE; - SendMessage(hWndHeader, HDM_GETITEM, (WPARAM)0, (LPARAM)&hdi); + SendMessage(hWndHeader, HDM_GETITEM, 0, (LPARAM)&hdi); ok(hdi.lParam == 133, "comctl32 4.0 field not set\n"); ok(hdi.iImage == 17, "comctl32 >4.0 field not set\n"); /* but in GETITEM if an unknown bit is set, comctl32 uses only version 4.0 fields */ ZeroMemory(&hdi, sizeof(hdi)); hdi.mask = 0x08000000 | HDI_LPARAM | HDI_IMAGE; - SendMessage(hWndHeader, HDM_GETITEM, (WPARAM)0, (LPARAM)&hdi); + SendMessage(hWndHeader, HDM_GETITEM, 0, (LPARAM)&hdi); ok(hdi.lParam == 133, "comctl32 4.0 field not read\n"); ok(hdi.iImage == 0, "comctl32 >4.0 field shouldn't be read\n"); - SendMessage(hWndHeader, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0); + SendMessage(hWndHeader, HDM_DELETEITEM, 0, 0); } } @@ -811,7 +812,7 @@ static void test_hdm_getitemrect(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); retVal = SendMessage(hChild, HDM_GETITEMRECT, 1, (LPARAM) &rect); ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal); @@ -821,7 +822,7 @@ static void test_hdm_getitemrect(HWND hParent) expect(160, rect.right); todo_wine { - expect(18, rect.bottom); + expect(g_customheight, rect.bottom); } retVal = SendMessage(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect); @@ -833,7 +834,7 @@ static void test_hdm_getitemrect(HWND hParent) expect(80, rect.right); todo_wine { - expect(18, rect.bottom); + expect(g_customheight, rect.bottom); } retVal = SendMessage(hChild, HDM_GETITEMRECT, 10, (LPARAM) &rect); ok(retVal == 0, "Getting rect of nonexistent item should return 0, got %d\n", retVal); @@ -855,7 +856,7 @@ static void test_hdm_layout(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); retVal = SendMessage(hChild, HDM_LAYOUT, 0, (LPARAM) &hdLayout); @@ -874,7 +875,7 @@ static void test_hdm_ordertoindex(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); retVal = SendMessage(hChild, HDM_ORDERTOINDEX, 1, 0); @@ -892,7 +893,7 @@ static void test_hdm_hittest(HWND hParent) HDHITTESTINFO hdHitTestInfo; const int firstItemRightBoundary = 80; const int secondItemRightBoundary = 160; - const int bottomBoundary = 18; + const int bottomBoundary = g_customheight; pt.x = firstItemRightBoundary - 1; pt.y = bottomBoundary - 1; @@ -902,7 +903,7 @@ static void test_hdm_hittest(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); retVal = SendMessage(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo); @@ -947,12 +948,12 @@ static void test_hdm_sethotdivider(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); todo_wine { - retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, TRUE, (LPARAM) 0X00050005); + retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, TRUE, 0X00050005); expect(0, retVal); } retVal = SendMessage(hChild, HDM_SETHOTDIVIDER, FALSE, 100); @@ -978,18 +979,18 @@ static void test_hdm_imageMessages(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_SETIMAGELIST, 0, (LPARAM) hImageList); - ok(hImageListRetVal == NULL, "Expected NULL, got %d\n", (int) hImageListRetVal); + ok(hImageListRetVal == NULL, "Expected NULL, got %p\n", hImageListRetVal); hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_GETIMAGELIST, 0, 0); - ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %d\n", (int) hImageListRetVal); + ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %p\n", hImageListRetVal); hImageListRetVal = (HIMAGELIST) SendMessage(hChild, HDM_CREATEDRAGIMAGE, 0, 0); - ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %d\n", (int) hImageListRetVal); + ok(hImageListRetVal != NULL, "Expected non-NULL handle, got %p\n", hImageListRetVal); ok_sequence(sequences, HEADER_SEQ_INDEX, imageMessages_seq, "imageMessages sequence testing", FALSE); @@ -999,24 +1000,30 @@ static void test_hdm_imageMessages(HWND hParent) static void test_hdm_filterMessages(HWND hParent) { HWND hChild; - int retVal; + int retVal, timeout; flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); assert(hChild); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); + + timeout = SendMessage(hChild, HDM_SETFILTERCHANGETIMEOUT, 1, 100); + SendMessage(hChild, HDM_SETFILTERCHANGETIMEOUT, 1, timeout); flush_sequences(sequences, NUM_MSG_SEQUENCES); - todo_wine - { + /* msdn incorrectly states that return value * is the index of the filter control being * modified. The sendMessage here should * return previous filter timeout value */ + retVal = SendMessage(hChild, HDM_SETFILTERCHANGETIMEOUT, 1, 100); - expect(1000, retVal); + expect(timeout, retVal); + + todo_wine + { retVal = SendMessage(hChild, HDM_CLEARFILTER, 0, 1); expect(1, retVal); retVal = SendMessage(hChild, HDM_EDITFILTER, 1, 0); @@ -1027,7 +1034,11 @@ static void test_hdm_filterMessages(HWND hParent) "filterMessages sequence testing", TRUE); else ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_noninteractive, - "filterMessages sequence testing", TRUE); + "filterMessages sequence testing", FALSE); + /* Some Win9x versions don't send a WM_KILLFOCUS. + * Set the focus explicitly to the parent to avoid a crash. + */ + SetFocus(hParent); DestroyWindow(hChild); } @@ -1040,7 +1051,7 @@ static void test_hdm_unicodeformatMessages(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); retVal = SendMessage(hChild, HDM_SETUNICODEFORMAT, TRUE, 0); @@ -1061,7 +1072,7 @@ static void test_hdm_bitmapmarginMessages(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); hChild = create_custom_header_control(hParent, TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); retVal = SendMessage(hChild, HDM_GETBITMAPMARGIN, 0, 0); @@ -1100,7 +1111,7 @@ static void test_hdm_index_messages(HWND hParent) "adder header control to parent", TRUE); else ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq, - "adder header control to parent", TRUE); + "adder header control to parent", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); for ( loopcnt = 0 ; loopcnt < 4 ; loopcnt++ ) { @@ -1148,10 +1159,10 @@ static void test_hdm_index_messages(HWND hParent) flush_sequences(sequences, NUM_MSG_SEQUENCES); iSize = SendMessage(hChild, HDM_GETITEMCOUNT, 0, (LPARAM) &hdItem); - retVal = SendMessage(hChild, HDM_SETORDERARRAY, (WPARAM) iSize , (LPARAM) (LPINT) lpiarray ); + retVal = SendMessage(hChild, HDM_SETORDERARRAY, iSize, (LPARAM) lpiarray); ok(retVal == TRUE, "Setting header items order should return TRUE, got %d\n", retVal); - retVal = SendMessage(hChild, HDM_GETORDERARRAY, (WPARAM) iSize, (LPARAM) (LPINT) lpiarrayReceived ); + retVal = SendMessage(hChild, HDM_GETORDERARRAY, iSize, (LPARAM) lpiarrayReceived); ok(retVal == TRUE, "Getting header items order should return TRUE, got %d\n", retVal); ok_sequence(sequences, HEADER_SEQ_INDEX, orderArray_seq, "set_get_orderArray sequence testing", FALSE); @@ -1196,7 +1207,7 @@ static LRESULT customdraw_1(int n, NMCUSTOMDRAW *nm) { case 0: /* don't test dwItemSpec - it's 0 no comctl5 but 1308756 on comctl6 */ - TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18); + TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, g_customheight); return 0; } @@ -1214,16 +1225,16 @@ static LRESULT customdraw_2(int n, NMCUSTOMDRAW *nm) switch (n) { case 0: - TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18); + TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, g_customheight); return CDRF_NOTIFYITEMDRAW; case 1: - TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18); + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, g_customheight); return 0; case 2: - TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, 18); + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, g_customheight); return 0; case 3: - TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18); + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, g_customheight); return 0; } @@ -1241,19 +1252,19 @@ static LRESULT customdraw_3(int n, NMCUSTOMDRAW *nm) switch (n) { case 0: - TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18); + TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, g_customheight); return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTERASE|CDRF_NOTIFYPOSTPAINT|CDRF_SKIPDEFAULT; case 1: - TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18); + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, g_customheight); return 0; case 2: - TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, 18); + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, g_customheight); return 0; case 3: - TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18); + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, g_customheight); return 0; case 4: - TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, 18); + TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, g_customheight); return 0; } @@ -1272,16 +1283,16 @@ static LRESULT customdraw_4(int n, NMCUSTOMDRAW *nm) switch (n) { case 0: - TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, 18); + TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, g_customheight); return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT; case 1: - TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, 18); + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, g_customheight); return 0; case 2: - TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, 18); + TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, g_customheight); return 0; case 3: - TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, 18); + TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, g_customheight); return 0; } @@ -1307,9 +1318,9 @@ static void test_customdraw(void) CHAR name[] = "Test"; hWndHeader = create_header_control(); GetClientRect(hWndHeader, &rect); - ok(rect.right - rect.left == 670 && rect.bottom - rect.top == 18, - "Tests will fail as header size is %dx%d instead of 670x18\n", - rect.right - rect.left, rect.bottom - rect.top); + ok(rect.right - rect.left == 670 && rect.bottom - rect.top == g_customheight, + "Tests will fail as header size is %dx%d instead of 670x%d\n", + rect.right - rect.left, rect.bottom - rect.top, g_customheight); for (i = 0; i < 3; i++) { @@ -1486,6 +1497,9 @@ static int init(void) BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); WNDCLASSA wc; INITCOMMONCONTROLSEX iccex; + TEXTMETRICA tm; + HFONT hOldFont; + HDC hdc; hComctl32 = GetModuleHandleA("comctl32.dll"); pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); @@ -1511,6 +1525,17 @@ static int init(void) wc.lpfnWndProc = HeaderTestWndProc; RegisterClassA(&wc); + /* The height of the header control depends on the height of the system font. + The height of the system font is dpi dependent */ + hdc = GetDC(0); + hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT)); + GetTextMetricsA(hdc, &tm); + /* 2 dot extra space are needed for the border */ + g_customheight = tm.tmHeight + 2; + trace("customdraw height: %d (dpi: %d)\n", g_customheight, GetDeviceCaps(hdc, LOGPIXELSY)); + SelectObject(hdc, hOldFont); + ReleaseDC(0, hdc); + hHeaderParentWnd = CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME), 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME), diff --git a/rostests/winetests/comctl32/imagelist.c b/rostests/winetests/comctl32/imagelist.c index 0d1770b3cbc..3fe249f3ad5 100644 --- a/rostests/winetests/comctl32/imagelist.c +++ b/rostests/winetests/comctl32/imagelist.c @@ -136,9 +136,9 @@ static HWND create_a_window(void) cls.cbClsExtra = 0; cls.cbWndExtra = 0; cls.hInstance = 0; - cls.hIcon = LoadIconA (0, (LPSTR)IDI_APPLICATION); - cls.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW); - cls.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); + cls.hIcon = LoadIconA (0, IDI_APPLICATION); + cls.hCursor = LoadCursorA (0, IDC_ARROW); + cls.hbrBackground = GetStockObject (WHITE_BRUSH); cls.lpszMenuName = 0; cls.lpszClassName = className; @@ -433,7 +433,7 @@ static BOOL DoTest3(void) if (!pImageList_DrawIndirect) { - trace("ImageList_DrawIndirect not available, skipping test\n"); + win_skip("ImageList_DrawIndirect not available, skipping test\n"); return TRUE; } @@ -835,10 +835,18 @@ static void check_ilhead_data(const char *ilh_data, INT cx, INT cy, INT cur, INT ok(ilh->cy == cy, "wrong cy %d (expected %d)\n", ilh->cy, cy); ok(ilh->bkcolor == CLR_NONE, "wrong bkcolor %x\n", ilh->bkcolor); ok(ilh->flags == ILC_COLOR24, "wrong flags %04x\n", ilh->flags); - ok(ilh->ovls[0] == -1, "wrong ovls[0] %04x\n", ilh->ovls[0]); - ok(ilh->ovls[1] == -1, "wrong ovls[1] %04x\n", ilh->ovls[1]); - ok(ilh->ovls[2] == -1, "wrong ovls[2] %04x\n", ilh->ovls[2]); - ok(ilh->ovls[3] == -1, "wrong ovls[3] %04x\n", ilh->ovls[3]); + ok(ilh->ovls[0] == -1 || + ilh->ovls[0] == 0, /* win95 */ + "wrong ovls[0] %04x\n", ilh->ovls[0]); + ok(ilh->ovls[1] == -1 || + ilh->ovls[1] == 0, /* win95 */ + "wrong ovls[1] %04x\n", ilh->ovls[1]); + ok(ilh->ovls[2] == -1 || + ilh->ovls[2] == 0, /* win95 */ + "wrong ovls[2] %04x\n", ilh->ovls[2]); + ok(ilh->ovls[3] == -1 || + ilh->ovls[3] == 0, /* win95 */ + "wrong ovls[3] %04x\n", ilh->ovls[3]); } static HBITMAP create_bitmap(INT cx, INT cy, COLORREF color, const char *comment) diff --git a/rostests/winetests/comctl32/ipaddress.c b/rostests/winetests/comctl32/ipaddress.c new file mode 100644 index 00000000000..d04223cb4fc --- /dev/null +++ b/rostests/winetests/comctl32/ipaddress.c @@ -0,0 +1,90 @@ +/* Unit test suite for IP Address control. + * + * Copyright 2009 Nikolay Sivov + * + * 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 + */ + + +#include +#include +#include + +#include "wine/test.h" + +#define expect(expected, got) ok(expected == got, "expected %d, got %d\n", expected,got) + +static HWND create_ipaddress_control (void) +{ + HWND handle; + + handle = CreateWindowEx(0, WC_IPADDRESS, NULL, + WS_BORDER|WS_VISIBLE, 0, 0, 0, 0, + NULL, NULL, NULL, NULL); + assert(handle); + + return handle; +} + +static void test_get_set_text(void) +{ + HWND hwnd; + CHAR ip[16]; + INT r; + + hwnd = create_ipaddress_control(); + + /* check text just after creation */ + r = GetWindowText(hwnd, ip, sizeof(ip)/sizeof(CHAR)); + expect(7, r); + ok(strcmp(ip, "0.0.0.0") == 0, "Expected null IP address, got %s\n", ip); + + SendMessage(hwnd, IPM_SETADDRESS, 0, MAKEIPADDRESS(127, 0, 0, 1)); + r = GetWindowText(hwnd, ip, sizeof(ip)/sizeof(CHAR)); + expect(9, r); + ok(strcmp(ip, "127.0.0.1") == 0, "Expected 127.0.0.1, got %s\n", ip); + + DestroyWindow(hwnd); +} + +static int init(void) +{ + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); + INITCOMMONCONTROLSEX iccex; + + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (!pInitCommonControlsEx) + { + win_skip("InitCommonControlsEx() is missing.\n"); + return 0; + } + + iccex.dwSize = sizeof(iccex); + /* W2K and below need ICC_INTERNET_CLASSES for the IP Address Control */ + iccex.dwICC = ICC_INTERNET_CLASSES; + pInitCommonControlsEx(&iccex); + + return 1; +} + +START_TEST(ipaddress) +{ + if (!init()) + return; + + test_get_set_text(); +} diff --git a/rostests/winetests/comctl32/listview.c b/rostests/winetests/comctl32/listview.c index 23b5f90e9b8..7253a13b02e 100644 --- a/rostests/winetests/comctl32/listview.c +++ b/rostests/winetests/comctl32/listview.c @@ -27,8 +27,9 @@ #include "msg.h" #define PARENT_SEQ_INDEX 0 -#define LISTVIEW_SEQ_INDEX 1 -#define NUM_MSG_SEQUENCES 2 +#define PARENT_FULL_SEQ_INDEX 1 +#define LISTVIEW_SEQ_INDEX 2 +#define NUM_MSG_SEQUENCES 3 #define LISTVIEW_ID 0 #define HEADER_ID 1 @@ -48,7 +49,10 @@ static const struct message create_parent_wnd_seq[] = { { WM_CREATE, sent }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_QUERYNEWPALETTE, sent|optional }, { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_WINDOWPOSCHANGED, sent|optional }, + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, { WM_ACTIVATEAPP, sent|wparam, 1 }, { WM_NCACTIVATE, sent|wparam, 1 }, { WM_ACTIVATE, sent|wparam, 1 }, @@ -75,9 +79,9 @@ static const struct message redraw_listview_seq[] = { }; static const struct message listview_icon_spacing_seq[] = { - { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(20, 30) }, - { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(25, 35) }, - { LVM_SETICONSPACING, sent|lparam, 0, (LPARAM) MAKELONG(-1, -1) }, + { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) }, + { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) }, + { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) }, { 0 } }; @@ -143,6 +147,27 @@ static const struct message listview_itempos_seq[] = { { 0 } }; +static const struct message listview_ownerdata_switchto_seq[] = { + { WM_STYLECHANGING, sent }, + { WM_STYLECHANGED, sent }, + { 0 } +}; + +static const struct message listview_getorderarray_seq[] = { + { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID }, + { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID }, + { 0 } +}; + +static const struct message empty_seq[] = { + { 0 } +}; + +static const struct message forward_erasebkgnd_parent_seq[] = { + { WM_ERASEBKGND, sent }, + { 0 } +}; + struct subclass_info { WNDPROC oldproc; @@ -150,12 +175,19 @@ struct subclass_info static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; - /* do not log painting messages */ - if (message != WM_PAINT && + msg.message = message; + msg.flags = sent|wparam|lparam; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.lParam = lParam; + + /* log system messages, except for painting */ + if (message < WM_USER && + message != WM_PAINT && message != WM_ERASEBKGND && message != WM_NCPAINT && message != WM_NCHITTEST && @@ -165,13 +197,9 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP { trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - msg.message = message; - msg.flags = sent|wparam|lparam; - if (defwndproc_counter) msg.flags |= defwinproc; - msg.wParam = wParam; - msg.lParam = lParam; add_message(sequences, PARENT_SEQ_INDEX, &msg); } + add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg); defwndproc_counter++; ret = DefWindowProcA(hwnd, message, wParam, lParam); @@ -190,7 +218,7 @@ static BOOL register_parent_wnd_class(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(NULL); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "Listview test parent class"; @@ -213,12 +241,20 @@ static HWND create_parent_window(void) static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + /* some debug output for style changing */ + if ((message == WM_STYLECHANGING || + message == WM_STYLECHANGED) && lParam) + { + STYLESTRUCT *style = (STYLESTRUCT*)lParam; + trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew); + } + msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; @@ -233,7 +269,7 @@ static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wPa return ret; } -static HWND create_listview_control(void) +static HWND create_listview_control(DWORD style) { struct subclass_info *info; HWND hwnd; @@ -245,7 +281,7 @@ static HWND create_listview_control(void) GetClientRect(hwndparent, &rect); hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo", - WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT, + WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | style, 0, 0, rect.right, rect.bottom, hwndparent, NULL, GetModuleHandleA(NULL), NULL); ok(hwnd != NULL, "gle=%d\n", GetLastError()); @@ -296,7 +332,7 @@ static HWND create_custom_listview_control(DWORD style) static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -630,6 +666,72 @@ static void test_items(void) insert_column(hwnd, 0); insert_column(hwnd, 1); + /* LVIS_SELECTED with zero stateMask */ + /* set */ + memset (&item, 0, sizeof (item)); + item.mask = LVIF_STATE; + item.state = LVIS_SELECTED; + item.stateMask = 0; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); + ok(r == 0, "ret %d\n", r); + /* get */ + memset (&item, 0xcc, sizeof (item)); + item.mask = LVIF_STATE; + item.stateMask = LVIS_SELECTED; + item.state = 0; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n"); + SendMessage(hwnd, LVM_DELETEITEM, 0, 0); + + /* LVIS_SELECTED with zero stateMask */ + /* set */ + memset (&item, 0, sizeof (item)); + item.mask = LVIF_STATE; + item.state = LVIS_FOCUSED; + item.stateMask = 0; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); + ok(r == 0, "ret %d\n", r); + /* get */ + memset (&item, 0xcc, sizeof (item)); + item.mask = LVIF_STATE; + item.stateMask = LVIS_FOCUSED; + item.state = 0; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n"); + SendMessage(hwnd, LVM_DELETEITEM, 0, 0); + + /* LVIS_CUT with LVIS_FOCUSED stateMask */ + /* set */ + memset (&item, 0, sizeof (item)); + item.mask = LVIF_STATE; + item.state = LVIS_CUT; + item.stateMask = LVIS_FOCUSED; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item); + ok(r == 0, "ret %d\n", r); + /* get */ + memset (&item, 0xcc, sizeof (item)); + item.mask = LVIF_STATE; + item.stateMask = LVIS_CUT; + item.state = 0; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n"); + SendMessage(hwnd, LVM_DELETEITEM, 0, 0); + /* Insert an item with just a param */ memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_PARAM; @@ -711,14 +813,29 @@ static void test_items(void) ok(r != 0, "ret %d\n", r); todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED); + /* some notnull but meaningless masks */ + memset (&item, 0, sizeof(item)); + item.mask = LVIF_NORECOMPUTE; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + memset (&item, 0, sizeof(item)); + item.mask = LVIF_DI_SETITEM; + item.iItem = 0; + item.iSubItem = 0; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(r != 0, "ret %d\n", r); + DestroyWindow(hwnd); } static void test_columns(void) { - HWND hwnd; + HWND hwnd, hwndheader; LVCOLUMN column; DWORD rc; + INT order[2]; hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, 10, 10, 100, 200, hwndparent, NULL, NULL, NULL); @@ -732,7 +849,34 @@ static void test_columns(void) /* Check its width */ rc = ListView_GetColumnWidth(hwnd, 0); - ok(rc==10, "Inserting column with no mask failed to set width to 10 with %d\n", rc); + ok(rc==10 || + broken(rc==0), /* win9x */ + "Inserting column with no mask failed to set width to 10 with %d\n", rc); + + DestroyWindow(hwnd); + + /* LVM_GETCOLUMNORDERARRAY */ + hwnd = create_listview_control(0); + hwndheader = subclass_header(hwnd); + + memset(&column, 0, sizeof(column)); + column.mask = LVCF_WIDTH; + column.cx = 100; + rc = ListView_InsertColumn(hwnd, 0, &column); + ok(rc == 0, "Inserting column failed with %d\n", rc); + + column.cx = 200; + rc = ListView_InsertColumn(hwnd, 1, &column); + ok(rc == 1, "Inserting column failed with %d\n", rc); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + rc = SendMessage(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order); + ok(rc != 0, "Expected LVM_GETCOLUMNORDERARRAY to succeed\n"); + ok(order[0] == 0, "Expected order 0, got %d\n", order[0]); + ok(order[1] == 1, "Expected order 1, got %d\n", order[1]); + + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE); DestroyWindow(hwnd); } @@ -742,19 +886,26 @@ static HIMAGELIST test_create_imagelist; static LRESULT CALLBACK create_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + LRESULT ret; + if (uMsg == WM_CREATE) { LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; lpcs->style |= LVS_REPORT; - SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist); } - return CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam); + ret = CallWindowProc(listviewWndProc, hwnd, uMsg, wParam, lParam); + if (uMsg == WM_CREATE) SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)test_create_imagelist); + return ret; } static void test_create(void) { HWND hList; HWND hHeader; + LONG_PTR ret; + LONG r; + LVCOLUMNA col; + RECT rect; WNDCLASSEX cls; cls.cbSize = sizeof(WNDCLASSEX); ok(GetClassInfoEx(GetModuleHandle(NULL), "SysListView32", &cls), "GetClassInfoEx failed\n"); @@ -768,14 +919,158 @@ static void test_create(void) ok((HIMAGELIST)SendMessage(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n"); hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + DestroyWindow(hList); + + /* header isn't created on LVS_ICON and LVS_LIST styles */ + hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, + GetModuleHandle(NULL), 0); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(!IsWindow(hHeader), "Header shouldn't be created\n"); + ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); + /* insert column */ + memset(&col, 0, sizeof(LVCOLUMNA)); + col.mask = LVCF_WIDTH; + col.cx = 100; + r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col); + ok(r == 0, "Expected 0 column's inserted\n"); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + DestroyWindow(hList); + + hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL, + GetModuleHandle(NULL), 0); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(!IsWindow(hHeader), "Header shouldn't be created\n"); + ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); + /* insert column */ + memset(&col, 0, sizeof(LVCOLUMNA)); + col.mask = LVCF_WIDTH; + col.cx = 100; + r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col); + ok(r == 0, "Expected 0 column's inserted\n"); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + DestroyWindow(hList); + + /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */ + hList = CreateWindow("SysListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, + GetModuleHandle(NULL), 0); + ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLongPtr(hList, GWL_STYLE) | LVS_REPORT); + ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n"); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ret = SetWindowLongPtr(hList, GWL_STYLE, GetWindowLong(hList, GWL_STYLE) & ~LVS_REPORT); + ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n"); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + DestroyWindow(hList); + + /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */ + hList = CreateWindow("SysListView32", "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL, + GetModuleHandle(NULL), 0); + ret = SetWindowLongPtr(hList, GWL_STYLE, + (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_LIST) | LVS_REPORT); + ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n"); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + ret = SetWindowLongPtr(hList, GWL_STYLE, + (GetWindowLongPtr(hList, GWL_STYLE) & ~LVS_REPORT) | LVS_LIST); + ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n"); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + DestroyWindow(hList); + + /* LVS_REPORT without WS_VISIBLE */ + hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL, + GetModuleHandle(NULL), 0); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(!IsWindow(hHeader), "Header shouldn't be created\n"); + ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); + /* insert column */ + memset(&col, 0, sizeof(LVCOLUMNA)); + col.mask = LVCF_WIDTH; + col.cx = 100; + r = SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&col); + ok(r == 0, "Expected 0 column's inserted\n"); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + DestroyWindow(hList); + + /* LVS_REPORT without WS_VISIBLE, try to show it */ + hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL, + GetModuleHandle(NULL), 0); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(!IsWindow(hHeader), "Header shouldn't be created\n"); + ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); + ShowWindow(hList, SW_SHOW); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + DestroyWindow(hList); + + /* LVS_REPORT with LVS_NOCOLUMNHEADER */ + hList = CreateWindow("SysListView32", "Test", LVS_REPORT|LVS_NOCOLUMNHEADER|WS_VISIBLE, + 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), 0); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + /* HDS_DRAGDROP set by default */ + ok(GetWindowLongPtr(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n"); + DestroyWindow(hList); + + /* setting LVS_EX_HEADERDRAGDROP creates header */ + hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL, + GetModuleHandle(NULL), 0); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(!IsWindow(hHeader), "Header shouldn't be created\n"); + ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); + SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP); + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(IsWindow(hHeader), "Header should be created\n"); + ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n"); + DestroyWindow(hList); + + /* not report style accepts LVS_EX_HEADERDRAGDROP too */ + hList = create_custom_listview_control(0); + SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_HEADERDRAGDROP); + r = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n"); + DestroyWindow(hList); + + /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */ + hList = CreateWindow("SysListView32", "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL, + GetModuleHandle(NULL), 0); + ok(!IsWindow(hHeader), "Header shouldn't be created\n"); + ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); + + rect.left = LVIR_BOUNDS; + rect.top = 1; + rect.right = rect.bottom = -10; + r = SendMessage(hList, LVM_GETSUBITEMRECT, -1, (LPARAM)&rect); + ok(r != 0, "Expected not-null LRESULT\n"); + + hHeader = (HWND)SendMessage(hList, LVM_GETHEADER, 0, 0); + ok(!IsWindow(hHeader), "Header shouldn't be created\n"); + ok(NULL == GetDlgItem(hList, 0), "NULL dialog item expected\n"); + DestroyWindow(hList); } static void test_redraw(void) { HWND hwnd, hwndheader; + HDC hdc; + BOOL res; + DWORD r; - hwnd = create_listview_control(); + hwnd = create_listview_control(0); hwndheader = subclass_header(hwnd); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -787,6 +1082,51 @@ static void test_redraw(void) flush_sequences(sequences, NUM_MSG_SEQUENCES); + /* forward WM_ERASEBKGND to parent on CLR_NONE background color */ + /* 1. Without backbuffer */ + res = ListView_SetBkColor(hwnd, CLR_NONE); + expect(TRUE, res); + + hdc = GetWindowDC(hwndparent); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + ok(r != 0, "Expected not zero result\n"); + ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq, + "forward WM_ERASEBKGND on CLR_NONE", FALSE); + + res = ListView_SetBkColor(hwnd, CLR_DEFAULT); + expect(TRUE, res); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + ok(r != 0, "Expected not zero result\n"); + ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq, + "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE); + + /* 2. With backbuffer */ + SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER, + LVS_EX_DOUBLEBUFFER); + res = ListView_SetBkColor(hwnd, CLR_NONE); + expect(TRUE, res); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + ok(r != 0, "Expected not zero result\n"); + ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, forward_erasebkgnd_parent_seq, + "forward WM_ERASEBKGND on CLR_NONE", FALSE); + + res = ListView_SetBkColor(hwnd, CLR_DEFAULT); + expect(TRUE, res); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + r = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + todo_wine ok(r != 0, "Expected not zero result\n"); + ok_sequence(sequences, PARENT_FULL_SEQ_INDEX, empty_seq, + "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE); + + ReleaseDC(hwndparent, hdc); + DestroyWindow(hwnd); } @@ -827,7 +1167,7 @@ static void test_customdraw(void) HWND hwnd; WNDPROC oldwndproc; - hwnd = create_listview_control(); + hwnd = create_listview_control(0); insert_column(hwnd, 0); insert_column(hwnd, 1); @@ -859,21 +1199,27 @@ static void test_icon_spacing(void) r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, (LPARAM)NF_REQUERY); expect(NFR_ANSI, r); - r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1, -1)); + /* reset the icon spacing to defaults */ + SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1)); + + /* now we can request what the defaults are */ + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1, -1)); w = LOWORD(r); - h = LOWORD(r); + h = HIWORD(r); flush_sequences(sequences, NUM_MSG_SEQUENCES); trace("test icon spacing\n"); - r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(20, 30)); - expect(MAKELONG(w,h), r); + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(20, 30)); + ok(r == MAKELONG(w, h) || + broken(r == MAKELONG(w, w)), /* win98 */ + "Expected %d, got %d\n", MAKELONG(w, h), r); - r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(25, 35)); + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(25, 35)); expect(MAKELONG(20,30), r); - r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1,-1)); + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELPARAM(-1,-1)); expect(MAKELONG(25,35), r); ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE); @@ -893,7 +1239,7 @@ static void test_color(void) COLORREF color; COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)}; - hwnd = create_listview_control(); + hwnd = create_listview_control(0); ok(hwnd != NULL, "failed to create a listview window\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -939,7 +1285,7 @@ static void test_item_count(void) static CHAR item1text[] = "item1"; static CHAR item2text[] = "item2"; - hwnd = create_listview_control(); + hwnd = create_listview_control(0); ok(hwnd != NULL, "failed to create a listview window\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -977,7 +1323,7 @@ static void test_item_count(void) expect(3, r); /* [item0, item1] */ - r = SendMessage(hwnd, LVM_DELETEITEM, (WPARAM) 2, 0); + r = SendMessage(hwnd, LVM_DELETEITEM, 2, 0); expect(TRUE, r); r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0); @@ -1149,6 +1495,7 @@ static void test_multiselect(void) static const int items=5; BYTE kstate[256]; select_task task; + LONG_PTR style; static struct t_select_task task_list[] = { { "using VK_DOWN", 0, VK_DOWN, -1, -1 }, @@ -1158,7 +1505,7 @@ static void test_multiselect(void) }; - hwnd = create_listview_control(); + hwnd = create_listview_control(0); for (i=0;i second ? 1 : -1); +} + +static void test_sorting(void) +{ + HWND hwnd; + LVITEMA item = {0}; + DWORD r; + LONG_PTR style; + static CHAR names[][5] = {"A", "B", "C", "D", "0"}; + CHAR buff[10]; + + hwnd = create_listview_control(0); + ok(hwnd != NULL, "failed to create a listview window\n"); + + /* insert some items */ + item.mask = LVIF_PARAM | LVIF_STATE; + item.state = LVIS_SELECTED; + item.iItem = 0; + item.iSubItem = 0; + item.lParam = 3; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); + expect(0, r); + + item.mask = LVIF_PARAM; + item.iItem = 1; + item.iSubItem = 0; + item.lParam = 2; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); + expect(1, r); + + item.mask = LVIF_STATE | LVIF_PARAM; + item.state = LVIS_SELECTED; + item.iItem = 2; + item.iSubItem = 0; + item.lParam = 4; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); + expect(2, r); + + r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0); + expect(-1, r); + + r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0); + expect(2, r); + + r = SendMessage(hwnd, LVM_SORTITEMS, 0, (LPARAM)test_CallBackCompare); + expect(TRUE, r); + + r = SendMessage(hwnd, LVM_GETSELECTEDCOUNT, 0, 0); + expect(2, r); + r = SendMessage(hwnd, LVM_GETSELECTIONMARK, 0, 0); + expect(-1, r); + r = SendMessage(hwnd, LVM_GETITEMSTATE, 0, LVIS_SELECTED); + expect(0, r); + r = SendMessage(hwnd, LVM_GETITEMSTATE, 1, LVIS_SELECTED); + expect(LVIS_SELECTED, r); + r = SendMessage(hwnd, LVM_GETITEMSTATE, 2, LVIS_SELECTED); + expect(LVIS_SELECTED, r); + + DestroyWindow(hwnd); + + /* switch to LVS_SORTASCENDING when some items added */ + hwnd = create_listview_control(0); + ok(hwnd != NULL, "failed to create a listview window\n"); + + item.mask = LVIF_TEXT; + item.iItem = 0; + item.iSubItem = 0; + item.pszText = names[1]; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); + expect(0, r); + + item.mask = LVIF_TEXT; + item.iItem = 1; + item.iSubItem = 0; + item.pszText = names[2]; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); + expect(1, r); + + item.mask = LVIF_TEXT; + item.iItem = 2; + item.iSubItem = 0; + item.pszText = names[0]; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); + expect(2, r); + + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SORTASCENDING); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n"); + + /* no sorting performed when switched to LVS_SORTASCENDING */ + item.mask = LVIF_TEXT; + item.iItem = 0; + item.pszText = buff; + item.cchTextMax = sizeof(buff); + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff); + + item.iItem = 1; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff); + + item.iItem = 2; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff); + + /* adding new item doesn't resort list */ + item.mask = LVIF_TEXT; + item.iItem = 3; + item.iSubItem = 0; + item.pszText = names[3]; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); + expect(3, r); + + item.mask = LVIF_TEXT; + item.iItem = 0; + item.pszText = buff; + item.cchTextMax = sizeof(buff); + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff); + + item.iItem = 1; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff); + + item.iItem = 2; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff); + + item.iItem = 3; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff); + + /* corner case - item should be placed at first position */ + item.mask = LVIF_TEXT; + item.iItem = 4; + item.iSubItem = 0; + item.pszText = names[4]; + r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item); + expect(0, r); + + item.iItem = 0; + item.pszText = buff; + item.cchTextMax = sizeof(buff); + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff); + + item.iItem = 1; + item.pszText = buff; + item.cchTextMax = sizeof(buff); + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff); + + item.iItem = 2; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff); + + item.iItem = 3; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff); + + item.iItem = 4; + r = SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM) &item); + expect(TRUE, r); + ok(lstrcmp(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff); + + DestroyWindow(hwnd); +} + +static void test_ownerdata(void) +{ + HWND hwnd; + LONG_PTR style, ret; + DWORD res; + LVITEMA item; + + /* it isn't possible to set LVS_OWNERDATA after creation */ + hwnd = create_listview_control(0); + ok(hwnd != NULL, "failed to create a listview window\n"); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA); + ok(ret == style, "Expected set GWL_STYLE to succeed\n"); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq, + "try to switch to LVS_OWNERDATA seq", FALSE); + + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n"); + DestroyWindow(hwnd); + + /* try to set LVS_OWNERDATA after creation just having it */ + hwnd = create_listview_control(LVS_OWNERDATA); + ok(hwnd != NULL, "failed to create a listview window\n"); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_OWNERDATA); + ok(ret == style, "Expected set GWL_STYLE to succeed\n"); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq, + "try to switch to LVS_OWNERDATA seq", FALSE); + DestroyWindow(hwnd); + + /* try to remove LVS_OWNERDATA after creation just having it */ + hwnd = create_listview_control(LVS_OWNERDATA); + ok(hwnd != NULL, "failed to create a listview window\n"); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n"); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + ret = SetWindowLongPtrA(hwnd, GWL_STYLE, style & ~LVS_OWNERDATA); + ok(ret == style, "Expected set GWL_STYLE to succeed\n"); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_ownerdata_switchto_seq, + "try to switch to LVS_OWNERDATA seq", FALSE); + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n"); + DestroyWindow(hwnd); + + /* try select an item */ + hwnd = create_listview_control(LVS_OWNERDATA); + ok(hwnd != NULL, "failed to create a listview window\n"); + res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0); + ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n"); + res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0); + expect(0, res); + memset(&item, 0, sizeof(item)); + item.stateMask = LVIS_SELECTED; + item.state = LVIS_SELECTED; + res = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, (LPARAM)&item); + expect(TRUE, res); + res = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0); + expect(1, res); + res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0); + expect(1, res); + DestroyWindow(hwnd); + + /* LVM_SETITEM is unsupported on LVS_OWNERDATA */ + hwnd = create_listview_control(LVS_OWNERDATA); + ok(hwnd != NULL, "failed to create a listview window\n"); + res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0); + ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n"); + res = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0); + expect(1, res); + memset(&item, 0, sizeof(item)); + item.mask = LVIF_STATE; + item.iItem = 0; + item.stateMask = LVIS_SELECTED; + item.state = LVIS_SELECTED; + res = SendMessageA(hwnd, LVM_SETITEM, 0, (LPARAM)&item); + expect(FALSE, res); + DestroyWindow(hwnd); +} + +static void test_norecompute(void) +{ + static CHAR testA[] = "test"; + CHAR buff[10]; + LVITEMA item; + HWND hwnd; + DWORD res; + + /* self containing control */ + hwnd = create_listview_control(0); + ok(hwnd != NULL, "failed to create a listview window\n"); + memset(&item, 0, sizeof(item)); + item.mask = LVIF_TEXT | LVIF_STATE; + item.iItem = 0; + item.stateMask = LVIS_SELECTED; + item.state = LVIS_SELECTED; + item.pszText = testA; + res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item); + expect(0, res); + /* retrieve with LVIF_NORECOMPUTE */ + item.mask = LVIF_TEXT | LVIF_NORECOMPUTE; + item.iItem = 0; + item.pszText = buff; + item.cchTextMax = sizeof(buff)/sizeof(CHAR); + res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item); + expect(TRUE, res); + ok(lstrcmp(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff); + + item.mask = LVIF_TEXT; + item.iItem = 1; + item.pszText = LPSTR_TEXTCALLBACK; + res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item); + expect(1, res); + + item.mask = LVIF_TEXT | LVIF_NORECOMPUTE; + item.iItem = 1; + item.pszText = buff; + item.cchTextMax = sizeof(buff)/sizeof(CHAR); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item); + expect(TRUE, res); + ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n", + LPSTR_TEXTCALLBACK, (VOID*)item.pszText); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq", FALSE); + + DestroyWindow(hwnd); + + /* LVS_OWNERDATA */ + hwnd = create_listview_control(LVS_OWNERDATA); + ok(hwnd != NULL, "failed to create a listview window\n"); + + item.mask = LVIF_STATE; + item.stateMask = LVIS_SELECTED; + item.state = LVIS_SELECTED; + item.iItem = 0; + res = SendMessageA(hwnd, LVM_INSERTITEM, 0, (LPARAM)&item); + expect(0, res); + + item.mask = LVIF_TEXT | LVIF_NORECOMPUTE; + item.iItem = 0; + item.pszText = buff; + item.cchTextMax = sizeof(buff)/sizeof(CHAR); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + res = SendMessageA(hwnd, LVM_GETITEM, 0, (LPARAM)&item); + expect(TRUE, res); + ok(item.pszText == LPSTR_TEXTCALLBACK, "Expected (%p), got (%p)\n", + LPSTR_TEXTCALLBACK, (VOID*)item.pszText); + ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "retrieve with LVIF_NORECOMPUTE seq 2", FALSE); + + DestroyWindow(hwnd); +} + +static void test_nosortheader(void) +{ + HWND hwnd, header; + LONG_PTR style; + + hwnd = create_listview_control(0); + ok(hwnd != NULL, "failed to create a listview window\n"); + + header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "header expected\n"); + + style = GetWindowLongPtr(header, GWL_STYLE); + ok(style & HDS_BUTTONS, "expected header to have HDS_BUTTONS\n"); + + style = GetWindowLongPtr(hwnd, GWL_STYLE); + SetWindowLongPtr(hwnd, GWL_STYLE, style | LVS_NOSORTHEADER); + /* HDS_BUTTONS retained */ + style = GetWindowLongPtr(header, GWL_STYLE); + ok(style & HDS_BUTTONS, "expected header to retain HDS_BUTTONS\n"); + + DestroyWindow(hwnd); + + /* create with LVS_NOSORTHEADER */ + hwnd = create_listview_control(LVS_NOSORTHEADER); + ok(hwnd != NULL, "failed to create a listview window\n"); + + header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); + ok(IsWindow(header), "header expected\n"); + + style = GetWindowLongPtr(header, GWL_STYLE); + ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n"); + + style = GetWindowLongPtr(hwnd, GWL_STYLE); + SetWindowLongPtr(hwnd, GWL_STYLE, style & ~LVS_NOSORTHEADER); + /* not changed here */ + style = GetWindowLongPtr(header, GWL_STYLE); + ok(!(style & HDS_BUTTONS), "expected header to have no HDS_BUTTONS\n"); + + DestroyWindow(hwnd); } START_TEST(listview) @@ -1244,4 +2105,9 @@ START_TEST(listview) test_columns(); test_getorigin(); test_multiselect(); + test_subitem_rect(); + test_sorting(); + test_ownerdata(); + test_norecompute(); + test_nosortheader(); } diff --git a/rostests/winetests/comctl32/monthcal.c b/rostests/winetests/comctl32/monthcal.c index 7f3b4e53ab6..ee38f1c4612 100644 --- a/rostests/winetests/comctl32/monthcal.c +++ b/rostests/winetests/comctl32/monthcal.c @@ -23,7 +23,6 @@ #include "windef.h" #include "winbase.h" -#include "wingdi.h" #include "winuser.h" #include "commctrl.h" @@ -53,7 +52,9 @@ static const struct message create_parent_window_seq[] = { { WM_CREATE, sent }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_QUERYNEWPALETTE, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, 0 }, + { WM_WINDOWPOSCHANGED, sent|optional }, { WM_ACTIVATEAPP, sent|wparam, 1 }, { WM_NCACTIVATE, sent|wparam, 1 }, { WM_ACTIVATE, sent|wparam, 1 }, @@ -70,7 +71,7 @@ static const struct message create_parent_window_seq[] = { static const struct message create_monthcal_control_seq[] = { { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, - { WM_QUERYUISTATE, sent }, + { WM_QUERYUISTATE, sent|optional }, { WM_GETFONT, sent }, { WM_PARENTNOTIFY, sent|wparam, WM_CREATE}, { 0 } @@ -78,7 +79,7 @@ static const struct message create_monthcal_control_seq[] = { static const struct message create_monthcal_multi_sel_style_seq[] = { { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, - { WM_QUERYUISTATE, sent }, + { WM_QUERYUISTATE, sent|optional }, { WM_GETFONT, sent }, { 0 } }; @@ -215,10 +216,6 @@ static const struct message monthcal_hit_test_seq[] = { { MCM_HITTEST, sent|wparam, 0}, { MCM_HITTEST, sent|wparam, 0}, { MCM_HITTEST, sent|wparam, 0}, - { MCM_HITTEST, sent|wparam, 0}, - { MCM_HITTEST, sent|wparam, 0}, - { MCM_HITTEST, sent|wparam, 0}, - { MCM_HITTEST, sent|wparam, 0}, { 0 } }; @@ -302,8 +299,10 @@ static const struct message destroy_parent_seq[] = { { 0x0090, sent|optional }, /* Vista */ { WM_WINDOWPOSCHANGING, sent|wparam, 0}, { WM_WINDOWPOSCHANGED, sent|wparam, 0}, - { WM_NCACTIVATE, sent|wparam|lparam, 0, 0}, - { WM_ACTIVATE, sent|wparam|lparam, 0, 0}, + { WM_NCACTIVATE, sent|wparam, 0}, + { WM_ACTIVATE, sent|wparam, 0}, + { WM_NCACTIVATE, sent|wparam|lparam|optional, 0, 0}, + { WM_ACTIVATE, sent|wparam|lparam|optional, 0, 0}, { WM_ACTIVATEAPP, sent|wparam, 0}, { WM_KILLFOCUS, sent|wparam|lparam, 0, 0}, { WM_IME_SETCONTEXT, sent|wparam|optional, 0}, @@ -379,12 +378,13 @@ static void test_monthcal(void) static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; - /* do not log painting messages */ - if (message != WM_PAINT && + /* log system messages, except for painting */ + if (message < WM_USER && + message != WM_PAINT && message != WM_ERASEBKGND && message != WM_NCPAINT && message != WM_NCHITTEST && @@ -419,7 +419,7 @@ static BOOL register_parent_wnd_class(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(NULL); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "Month-Cal test parent class"; @@ -448,7 +448,7 @@ static HWND create_parent_window(void) assert(hwnd); /* check for message sequences */ - ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", TRUE); + ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_window_seq, "create parent window", FALSE); return hwnd; } @@ -456,12 +456,10 @@ static HWND create_parent_window(void) static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; - trace("monthcal: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; @@ -636,7 +634,7 @@ static void test_monthcal_currDate(HWND hwnd) expect(st_original.wSecond, st_new.wSecond); /* lparam cannot be NULL */ - res = SendMessage(hwnd, MCM_GETCURSEL, 0, (LPARAM) NULL); + res = SendMessage(hwnd, MCM_GETCURSEL, 0, 0); expect(0, res); ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_curr_date_seq, "monthcal currDate", TRUE); @@ -654,6 +652,7 @@ static void test_monthcal_firstDay(HWND hwnd) /* check for locale first day */ if(GetLocaleInfo(lcid, LOCALE_IFIRSTDAYOFWEEK, b, 128)){ fday = atoi(b); + trace("fday: %d\n", fday); res = SendMessage(hwnd, MCM_GETFIRSTDAYOFWEEK, 0, 0); expect(fday, res); prev = fday; @@ -669,7 +668,8 @@ static void test_monthcal_firstDay(HWND hwnd) if (i == -1){ expect(MAKELONG(fday, FALSE), res); }else if (i >= 7){ - expect(MAKELONG(fday, TRUE), res); + /* out of range sets max first day of week, locale is ignored */ + expect(MAKELONG(6, TRUE), res); }else{ expect(MAKELONG(i, TRUE), res); } @@ -722,6 +722,12 @@ static void test_monthcal_HitTest(HWND hwnd) MCHITTESTINFO mchit; UINT res; SYSTEMTIME st; + LONG x; + UINT title_index; + static const UINT title_hits[] = + { MCHT_NOWHERE, MCHT_TITLEBK, MCHT_TITLEBTNPREV, MCHT_TITLEBK, + MCHT_TITLEMONTH, MCHT_TITLEBK, MCHT_TITLEYEAR, MCHT_TITLEBK, + MCHT_TITLEBTNNEXT, MCHT_TITLEBK, MCHT_NOWHERE }; memset(&mchit, 0, sizeof(MCHITTESTINFO)); @@ -776,42 +782,6 @@ static void test_monthcal_HitTest(HWND hwnd) expect(mchit.uHit, res); expect(MCHT_CALENDARBK, res); - /* (50, 40) is in active area - previous month button */ - mchit.pt.x = 50; - mchit.pt.y = 40; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(50, mchit.pt.x); - expect(40, mchit.pt.y); - expect(mchit.uHit, res); - todo_wine {expect(MCHT_TITLEBTNPREV, res);} - - /* (90, 40) is in active area - background section of the title */ - mchit.pt.x = 90; - mchit.pt.y = 40; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(90, mchit.pt.x); - expect(40, mchit.pt.y); - expect(mchit.uHit, res); - todo_wine {expect(MCHT_TITLE, res);} - - /* (140, 40) is in active area - month section of the title */ - mchit.pt.x = 140; - mchit.pt.y = 40; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(140, mchit.pt.x); - expect(40, mchit.pt.y); - expect(mchit.uHit, res); - todo_wine {expect(MCHT_TITLEMONTH, res);} - - /* (250, 40) is in active area - next month button */ - mchit.pt.x = 250; - mchit.pt.y = 40; - res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); - expect(250, mchit.pt.x); - expect(40, mchit.pt.y); - expect(mchit.uHit, res); - todo_wine {expect(MCHT_TITLEBTNNEXT, res);} - /* (70, 70) is in active area - day of the week */ mchit.pt.x = 70; mchit.pt.y = 70; @@ -905,6 +875,27 @@ static void test_monthcal_HitTest(HWND hwnd) todo_wine {expect(MCHT_TODAYLINK, res);} ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_hit_test_seq, "monthcal hit test", TRUE); + + /* The horizontal position of title bar elements depends on locale (y pos + is constant), so we sample across a horizontal line and make sure we + find all elements. */ + mchit.pt.y = 40; + title_index = 0; + for (x = 0; x < 300; x++){ + mchit.pt.x = x; + res = SendMessage(hwnd, MCM_HITTEST, 0, (LPARAM) & mchit); + expect(x, mchit.pt.x); + expect(40, mchit.pt.y); + expect(mchit.uHit, res); + if (res != title_hits[title_index]){ + title_index++; + if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index) + break; + todo_wine {expect(title_hits[title_index], res);} +} + } + todo_wine {ok(300 <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]), + "Wrong title layout\n");} } static void test_monthcal_todaylink(HWND hwnd) @@ -1107,6 +1098,34 @@ static void test_monthcal_MaxSelDay(HWND hwnd) ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_max_sel_day_seq, "monthcal MaxSelDay", FALSE); } +static void test_monthcal_size(HWND hwnd) +{ + int res; + RECT r1, r2; + HFONT hFont1, hFont2; + LOGFONTA logfont; + + lstrcpyA(logfont.lfFaceName, "Arial"); + memset(&logfont, 0, sizeof(logfont)); + logfont.lfHeight = 12; + hFont1 = CreateFontIndirectA(&logfont); + + logfont.lfHeight = 24; + hFont2 = CreateFontIndirectA(&logfont); + + /* initialize to a font we can compare against */ + SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont1, 0); + res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r1); + + /* check that setting a larger font results in an larger rect */ + SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont2, 0); + res = SendMessage(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&r2); + + OffsetRect(&r1, -r1.left, -r1.top); + OffsetRect(&r2, -r2.left, -r2.top); + + ok(r1.bottom < r2.bottom, "Failed to get larger rect with larger font\n"); +} START_TEST(monthcal) { @@ -1148,6 +1167,7 @@ START_TEST(monthcal) test_monthcal_monthrange(hwnd); test_monthcal_HitTest(hwnd); test_monthcal_todaylink(hwnd); + test_monthcal_size(hwnd); flush_sequences(sequences, NUM_MSG_SEQUENCES); DestroyWindow(hwnd); diff --git a/rostests/winetests/comctl32/mru.c b/rostests/winetests/comctl32/mru.c index 8ef1617503d..8ebec86f148 100644 --- a/rostests/winetests/comctl32/mru.c +++ b/rostests/winetests/comctl32/mru.c @@ -75,7 +75,7 @@ static INT (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT); /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */ -static LONG mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey) +static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey) { LONG ret; DWORD dwMaxSubkeyLen, dwMaxValueLen; @@ -353,15 +353,15 @@ static void test_MRUListA(void) /* NULL buffer = get list size */ iRet = pEnumMRUList(hMRU, 0, NULL, 0); - ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet); + ok(iRet == 3 || iRet == -1 /* Vista */, "EnumMRUList expected %d or -1, got %d\n", LIST_SIZE, iRet); /* negative item pos = get list size */ iRet = pEnumMRUList(hMRU, -1, NULL, 0); - ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet); + ok(iRet == 3 || iRet == -1 /* Vista */, "EnumMRUList expected %d or -1, got %d\n", LIST_SIZE, iRet); /* negative item pos = get list size */ iRet = pEnumMRUList(hMRU, -5, NULL, 0); - ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet); + ok(iRet == 3 || iRet == -1 /* Vista */, "EnumMRUList expected %d or -1, got %d\n", LIST_SIZE, iRet); /* negative item pos = get list size */ iRet = pEnumMRUList(hMRU, -1, buffer, 255); @@ -410,8 +410,7 @@ static void test_MRUListA(void) pFreeMRUList(hMRU); } - /* Free (NULL list) - Doesn't crash */ - pFreeMRUList(NULL); + /* FreeMRUList(NULL) crashes on Win98 OSR0 */ } START_TEST(mru) diff --git a/rostests/winetests/comctl32/propsheet.c b/rostests/winetests/comctl32/propsheet.c index 8627351b7fc..4164f68c60e 100644 --- a/rostests/winetests/comctl32/propsheet.c +++ b/rostests/winetests/comctl32/propsheet.c @@ -22,6 +22,8 @@ #include "wine/test.h" +static HWND parent; + static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam) { switch(msg) @@ -132,8 +134,74 @@ static void test_nopage(void) DestroyWindow(hdlg); } +static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam) +{ + switch(msg) + { + case PSCB_INITIALIZED: + { + ok(IsWindowEnabled(parent) == 0, "parent window should be disabled\n"); + PostQuitMessage(0); + return FALSE; + } + } + return FALSE; +} + +static void register_parent_wnd_class(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = DefWindowProcA; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "parent class"; + RegisterClassA(&cls); +} + +static void test_disableowner(void) +{ + HPROPSHEETPAGE hpsp[1]; + PROPSHEETPAGEA psp; + PROPSHEETHEADERA psh; + + register_parent_wnd_class(); + parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0); + + memset(&psp, 0, sizeof(psp)); + psp.dwSize = sizeof(psp); + psp.dwFlags = 0; + psp.hInstance = GetModuleHandleW(NULL); + U(psp).pszTemplate = "prop_page1"; + U2(psp).pszIcon = NULL; + psp.pfnDlgProc = NULL; + psp.lParam = 0; + + hpsp[0] = CreatePropertySheetPageA(&psp); + + memset(&psh, 0, sizeof(psh)); + psh.dwSize = sizeof(psh); + psh.dwFlags = PSH_USECALLBACK; + psh.pszCaption = "test caption"; + psh.nPages = 1; + psh.hwndParent = parent; + U3(psh).phpage = hpsp; + psh.pfnCallback = disableowner_callback; + + PropertySheetA(&psh); + ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n"); + DestroyWindow(parent); +} + START_TEST(propsheet) { test_title(); test_nopage(); + test_disableowner(); } diff --git a/rostests/winetests/comctl32/rebar.c b/rostests/winetests/comctl32/rebar.c index e5bea381025..933d515ff01 100644 --- a/rostests/winetests/comctl32/rebar.c +++ b/rostests/winetests/comctl32/rebar.c @@ -512,7 +512,7 @@ static void dump_client(HWND hRebar) RECT r; BOOL notify; GetWindowRect(hRebar, &r); - MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); + MapWindowPoints(HWND_DESKTOP, hMainWnd, &r, 2); if (height_change_notify_rect.top != -1) { RECT rcClient; diff --git a/rostests/winetests/comctl32/status.c b/rostests/winetests/comctl32/status.c index 4e643c1f4fa..f44853595b7 100644 --- a/rostests/winetests/comctl32/status.c +++ b/rostests/winetests/comctl32/status.c @@ -24,9 +24,26 @@ #include "wine/test.h" -#define expect(expected,got) ok (expected == got,"Expected %d, got %d\n",expected,got); +#define SUBCLASS_NAME "MyStatusBar" + +#define expect(expected,got) ok (expected == got,"Expected %d, got %d\n",expected,got) +#define expect_rect(_left,_top,_right,_bottom,got) do { \ + RECT exp = {abs(got.left - _left), abs(got.top - _top), \ + abs(got.right - _right), abs(got.bottom - _bottom)}; \ + ok(exp.left <= 2 && exp.top <= 2 && exp.right <= 2 && exp.bottom <= 2, \ + "Expected rect {%d,%d, %d,%d}, got {%d,%d, %d,%d}\n", \ + _left, _top, _right, _bottom, \ + (got).left, (got).top, (got).right, (got).bottom); } while (0) static HINSTANCE hinst; +static WNDPROC g_status_wndproc; +static RECT g_rcCreated; +static HWND g_hMainWnd; +static int g_wmsize_count = 0; +static DWORD g_ysize; +static DWORD g_dpisize; +static int g_wmdrawitm_ctr; +static WNDPROC g_wndproc_saved; static HWND create_status_control(DWORD style, DWORD exstyle) { @@ -42,6 +59,195 @@ static HWND create_status_control(DWORD style, DWORD exstyle) return hWndStatus; } +static LRESULT WINAPI create_test_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret; + + if (msg == WM_CREATE) + { + CREATESTRUCT *cs = (CREATESTRUCT *)lParam; + ret = CallWindowProc(g_status_wndproc, hwnd, msg, wParam, lParam); + GetWindowRect(hwnd, &g_rcCreated); + MapWindowPoints(HWND_DESKTOP, g_hMainWnd, (LPPOINT)&g_rcCreated, 2); + ok(cs->x == g_rcCreated.left, "CREATESTRUCT.x modified\n"); + ok(cs->y == g_rcCreated.top, "CREATESTRUCT.y modified\n"); + } else if (msg == WM_SIZE) + { + g_wmsize_count++; + ret = CallWindowProc(g_status_wndproc, hwnd, msg, wParam, lParam); + } + else + ret = CallWindowProc(g_status_wndproc, hwnd, msg, wParam, lParam); + + return ret; +} + +static void register_subclass(void) +{ + WNDCLASSEX cls; + + cls.cbSize = sizeof(WNDCLASSEX); + GetClassInfoEx(NULL, STATUSCLASSNAME, &cls); + g_status_wndproc = cls.lpfnWndProc; + cls.lpfnWndProc = create_test_wndproc; + cls.lpszClassName = SUBCLASS_NAME; + cls.hInstance = NULL; + ok(RegisterClassEx(&cls), "RegisterClassEx failed\n"); +} + +static void test_create(void) +{ + RECT rc; + HWND hwnd; + + ok((hwnd = CreateWindowA(SUBCLASS_NAME, "", WS_CHILD|WS_VISIBLE|SBARS_SIZEGRIP, 0, 0, 100, 100, + g_hMainWnd, NULL, NULL, 0)) != NULL, "CreateWindowA failed\n"); + MapWindowPoints(HWND_DESKTOP, g_hMainWnd, (LPPOINT)&rc, 2); + GetWindowRect(hwnd, &rc); + MapWindowPoints(HWND_DESKTOP, g_hMainWnd, (LPPOINT)&rc, 2); + expect_rect(0, 0, 100, 100, g_rcCreated); + expect(0, rc.left); + expect(672, rc.right); + expect(226, rc.bottom); + /* we don't check rc.top as this may depend on user font settings */ + DestroyWindow(hwnd); +} + +static int CALLBACK check_height_font_enumproc(ENUMLOGFONTEX *enumlf, NEWTEXTMETRICEX *ntm, DWORD type, LPARAM lParam) +{ + HWND hwndStatus = (HWND)lParam; + HDC hdc = GetDC(NULL); + static const int sizes[] = { 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, + 20, 22, 28, 36, 48, 72}; + DWORD i; + DWORD y; + LPSTR facename = (CHAR *)enumlf->elfFullName; + + /* on win9x, enumlf->elfFullName is only valid for truetype fonts */ + if (type != TRUETYPE_FONTTYPE) + facename = enumlf->elfLogFont.lfFaceName; + + for (i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++) + { + HFONT hFont; + TEXTMETRIC tm; + HFONT hCtrlFont; + HFONT hOldFont; + RECT rcCtrl; + + enumlf->elfLogFont.lfHeight = sizes[i]; + hFont = CreateFontIndirect(&enumlf->elfLogFont); + hCtrlFont = (HFONT)SendMessage(hwndStatus, WM_SETFONT, (WPARAM)hFont, TRUE); + hOldFont = SelectObject(hdc, hFont); + + GetClientRect(hwndStatus, &rcCtrl); + GetTextMetrics(hdc, &tm); + y = tm.tmHeight + (tm.tmInternalLeading ? tm.tmInternalLeading : 2) + 4; + + ok( (rcCtrl.bottom == max(y, g_ysize)) || (rcCtrl.bottom == max(y, g_dpisize)), + "got %d (expected %d or %d) for %s #%d\n", + rcCtrl.bottom, max(y, g_ysize), max(y, g_dpisize), facename, sizes[i]); + + SelectObject(hdc, hOldFont); + SendMessage(hwndStatus, WM_SETFONT, (WPARAM)hCtrlFont, TRUE); + DeleteObject(hFont); + } + ReleaseDC(NULL, hdc); + return 1; +} + +static int CALLBACK check_height_family_enumproc(ENUMLOGFONTEX *enumlf, NEWTEXTMETRICEX *ntm, DWORD type, LPARAM lParam) +{ + HDC hdc = GetDC(NULL); + enumlf->elfLogFont.lfHeight = 0; + EnumFontFamiliesEx(hdc, &enumlf->elfLogFont, (FONTENUMPROC)check_height_font_enumproc, lParam, 0); + ReleaseDC(NULL, hdc); + return 1; +} + +static void test_height(void) +{ + LOGFONT lf; + HFONT hFont, hFontSm; + RECT rc1, rc2; + HWND hwndStatus = CreateWindow(SUBCLASS_NAME, NULL, WS_CHILD|WS_VISIBLE, + 0, 0, 300, 20, g_hMainWnd, NULL, NULL, NULL); + HDC hdc; + + GetClientRect(hwndStatus, &rc1); + hFont = CreateFont(32, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, "Tahoma"); + + g_wmsize_count = 0; + SendMessage(hwndStatus, WM_SETFONT, (WPARAM)hFont, TRUE); + if (!g_wmsize_count) + { + skip("Status control not resized in win95, skipping broken tests.\n"); + return; + } + ok(g_wmsize_count > 0, "WM_SETFONT should issue WM_SIZE\n"); + + GetClientRect(hwndStatus, &rc2); + expect_rect(0, 0, 672, 42, rc2); /* GetTextMetrics returns invalid tmInternalLeading for this font */ + + g_wmsize_count = 0; + SendMessage(hwndStatus, WM_SETFONT, (WPARAM)hFont, TRUE); + ok(g_wmsize_count > 0, "WM_SETFONT should issue WM_SIZE\n"); + + GetClientRect(hwndStatus, &rc2); + expect_rect(0, 0, 672, 42, rc2); + + /* minheight < fontsize - no effects*/ + SendMessage(hwndStatus, SB_SETMINHEIGHT, 12, 0); + SendMessage(hwndStatus, WM_SIZE, 0, 0); + GetClientRect(hwndStatus, &rc2); + expect_rect(0, 0, 672, 42, rc2); + + /* minheight > fontsize - has an effect after WM_SIZE */ + SendMessage(hwndStatus, SB_SETMINHEIGHT, 60, 0); + GetClientRect(hwndStatus, &rc2); + expect_rect(0, 0, 672, 42, rc2); + SendMessage(hwndStatus, WM_SIZE, 0, 0); + GetClientRect(hwndStatus, &rc2); + expect_rect(0, 0, 672, 62, rc2); + + /* font changed to smaller than minheight - has an effect */ + SendMessage(hwndStatus, SB_SETMINHEIGHT, 30, 0); + expect_rect(0, 0, 672, 62, rc2); + SendMessage(hwndStatus, WM_SIZE, 0, 0); + GetClientRect(hwndStatus, &rc2); + expect_rect(0, 0, 672, 42, rc2); + hFontSm = CreateFont(9, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, "Tahoma"); + SendMessage(hwndStatus, WM_SETFONT, (WPARAM)hFontSm, TRUE); + GetClientRect(hwndStatus, &rc2); + expect_rect(0, 0, 672, 32, rc2); + + /* test the height formula */ + ZeroMemory(&lf, sizeof(lf)); + SendMessage(hwndStatus, SB_SETMINHEIGHT, 0, 0); + hdc = GetDC(NULL); + + /* used only for some fonts (tahoma as example) */ + g_ysize = GetSystemMetrics(SM_CYSIZE) + 2; + if (g_ysize & 1) g_ysize--; /* The min height is always even */ + + g_dpisize = MulDiv(18, GetDeviceCaps(hdc, LOGPIXELSY), 96) + 2; + if (g_dpisize & 1) g_dpisize--; /* The min height is always even */ + + + trace("dpi=%d (min height: %d or %d) SM_CYSIZE: %d\n", + GetDeviceCaps(hdc, LOGPIXELSY), g_ysize, g_dpisize, + GetSystemMetrics(SM_CYSIZE)); + + EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)check_height_family_enumproc, (LPARAM)hwndStatus, 0); + ReleaseDC(NULL, hdc); + + DestroyWindow(hwndStatus); + DeleteObject(hFont); + DeleteObject(hFontSm); +} + static void test_status_control(void) { HWND hWndStatus; @@ -52,11 +258,13 @@ static void test_status_control(void) RECT rc; CHAR charArray[20]; HICON hIcon; + char ch; + char chstr[10] = "Inval id"; hWndStatus = create_status_control(WS_VISIBLE, 0); /* Divide into parts and set text */ - r = SendMessage(hWndStatus, SB_SETPARTS, 3, (long)nParts); + r = SendMessage(hWndStatus, SB_SETPARTS, 3, (LPARAM)nParts); expect(TRUE,r); r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)"First"); expect(TRUE,r); @@ -87,12 +295,12 @@ static void test_status_control(void) expect(0,HIWORD(r)); /* Get parts and borders */ - r = SendMessage(hWndStatus, SB_GETPARTS, 3, (long)checkParts); + r = SendMessage(hWndStatus, SB_GETPARTS, 3, (LPARAM)checkParts); ok(r == 3, "Expected 3, got %d\n", r); expect(50,checkParts[0]); expect(150,checkParts[1]); expect(-1,checkParts[2]); - r = SendMessage(hWndStatus, SB_GETBORDERS, 0, (long)borders); + r = SendMessage(hWndStatus, SB_GETBORDERS, 0, (LPARAM)borders); ok(r == TRUE, "Expected TRUE, got %d\n", r); expect(0,borders[0]); expect(2,borders[1]); @@ -101,7 +309,7 @@ static void test_status_control(void) /* Test resetting text with different characters */ r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)"First@Again"); expect(TRUE,r); - r = SendMessage(hWndStatus, SB_SETTEXT, 1, (LPARAM)"InvalidChars\\7\7"); + r = SendMessage(hWndStatus, SB_SETTEXT, 1, (LPARAM)"Invalid\tChars\\7\7"); expect(TRUE,r); r = SendMessage(hWndStatus, SB_SETTEXT, 2, (LPARAM)"InvalidChars\\n\n"); expect(TRUE,r); @@ -112,34 +320,52 @@ static void test_status_control(void) expect(11,LOWORD(r)); expect(0,HIWORD(r)); r = SendMessage(hWndStatus, SB_GETTEXT, 1, (LPARAM) charArray); - todo_wine - { - ok(strcmp(charArray,"InvalidChars\\7 ") == 0, "Expected InvalidChars\\7 , got %s\n", charArray); - } - expect(15,LOWORD(r)); + ok(strcmp(charArray,"Invalid\tChars\\7 ") == 0, "Expected Invalid\tChars\\7 , got %s\n", charArray); + + expect(16,LOWORD(r)); expect(0,HIWORD(r)); r = SendMessage(hWndStatus, SB_GETTEXT, 2, (LPARAM) charArray); - todo_wine - { ok(strcmp(charArray,"InvalidChars\\n ") == 0, "Expected InvalidChars\\n , got %s\n", charArray); - } + expect(15,LOWORD(r)); expect(0,HIWORD(r)); + /* test more nonprintable chars */ + for(ch = 0x00; ch < 0x7F; ch++) { + chstr[5] = ch; + r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)chstr); + expect(TRUE,r); + r = SendMessage(hWndStatus, SB_GETTEXT, 0, (LPARAM)charArray); + /* substitution with single space */ + if (ch > 0x00 && ch < 0x20 && ch != '\t') + chstr[5] = ' '; + ok(strcmp(charArray, chstr) == 0, "Expected %s, got %s\n", chstr, charArray); + } + /* Set background color */ r = SendMessage(hWndStatus, SB_SETBKCOLOR , 0, RGB(255,0,0)); - expect(CLR_DEFAULT,r); + ok(r == CLR_DEFAULT || + broken(r == 0), /* win95 */ + "Expected %d, got %d\n", CLR_DEFAULT, r); r = SendMessage(hWndStatus, SB_SETBKCOLOR , 0, CLR_DEFAULT); - expect(RGB(255,0,0),r); + ok(r == RGB(255,0,0) || + broken(r == 0), /* win95 */ + "Expected %d, got %d\n", RGB(255,0,0), r); /* Add an icon to the status bar */ hIcon = LoadIcon(NULL, IDI_QUESTION); - r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) NULL); - ok(r != 0, "Expected non-zero, got %d\n", r); + r = SendMessage(hWndStatus, SB_SETICON, 1, 0); + ok(r != 0 || + broken(r == 0), /* win95 */ + "Expected non-zero, got %d\n", r); r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) hIcon); - ok(r != 0, "Expected non-zero, got %d\n", r); - r = SendMessage(hWndStatus, SB_SETICON, 1, (LPARAM) NULL); - ok(r != 0, "Expected non-zero, got %d\n", r); + ok(r != 0 || + broken(r == 0), /* win95 */ + "Expected non-zero, got %d\n", r); + r = SendMessage(hWndStatus, SB_SETICON, 1, 0); + ok(r != 0 || + broken(r == 0), /* win95 */ + "Expected non-zero, got %d\n", r); /* Set the Unicode format */ r = SendMessage(hWndStatus, SB_SETUNICODEFORMAT, FALSE, 0); @@ -148,15 +374,17 @@ static void test_status_control(void) r = SendMessage(hWndStatus, SB_SETUNICODEFORMAT, TRUE, 0); expect(FALSE,r); r = SendMessage(hWndStatus, SB_GETUNICODEFORMAT, 0, 0); - expect(TRUE,r); + ok(r == TRUE || + broken(r == FALSE), /* win95 */ + "Expected TRUE, got %d\n", r); /* Reset number of parts */ - r = SendMessage(hWndStatus, SB_SETPARTS, 2, (long)nParts); + r = SendMessage(hWndStatus, SB_SETPARTS, 2, (LPARAM)nParts); expect(TRUE,r); /* Set the minimum height and get rectangle information again */ - SendMessage(hWndStatus, SB_SETMINHEIGHT, 50, (LPARAM) 0); - r = SendMessage(hWndStatus, WM_SIZE, 0, (LPARAM) 0); + SendMessage(hWndStatus, SB_SETMINHEIGHT, 50, 0); + r = SendMessage(hWndStatus, WM_SIZE, 0, 0); expect(0,r); r = SendMessage(hWndStatus, SB_GETRECT, 0, (LPARAM)&rc); expect(TRUE,r); @@ -174,23 +402,85 @@ static void test_status_control(void) todo_wine { SendMessage(hWndStatus, SB_SETTIPTEXT, 0,(LPARAM) "Tooltip Text"); + lstrcpyA(charArray, "apple"); SendMessage(hWndStatus, SB_GETTIPTEXT, MAKEWPARAM (0, 20),(LPARAM) charArray); - ok(strcmp(charArray,"Tooltip Text") == 0, "Expected Tooltip Text, got %s\n", charArray); + ok(strcmp(charArray,"Tooltip Text") == 0 || + broken(!strcmp(charArray, "apple")), /* win95 */ + "Expected Tooltip Text, got %s\n", charArray); } /* Make simple */ SendMessage(hWndStatus, SB_SIMPLE, TRUE, 0); r = SendMessage(hWndStatus, SB_ISSIMPLE, 0, 0); - expect(TRUE,r); + ok(r == TRUE || + broken(r == FALSE), /* win95 */ + "Expected TRUE, got %d\n", r); DestroyWindow(hWndStatus); } +static LRESULT WINAPI ownerdraw_test_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret; + if (msg == WM_DRAWITEM) + g_wmdrawitm_ctr++; + ret = CallWindowProc(g_wndproc_saved, hwnd, msg, wParam, lParam); + return ret; +} + +static void test_status_ownerdraw(void) +{ + HWND hWndStatus; + int r; + const char* statustext = "STATUS TEXT"; + LONG oldstyle; + + /* subclass the main window and make sure it is visible */ + g_wndproc_saved = (WNDPROC) SetWindowLongPtr( g_hMainWnd, GWLP_WNDPROC, + (LONG_PTR)ownerdraw_test_wndproc ); + ok( g_wndproc_saved != 0, "failed to set the WndProc\n"); + SetWindowPos( g_hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + oldstyle = GetWindowLong( g_hMainWnd, GWL_STYLE); + SetWindowLong( g_hMainWnd, GWL_STYLE, oldstyle | WS_VISIBLE); + /* create a status child window */ + ok((hWndStatus = CreateWindowA(SUBCLASS_NAME, "", WS_CHILD|WS_VISIBLE, 0, 0, 100, 100, + g_hMainWnd, NULL, NULL, 0)) != NULL, "CreateWindowA failed\n"); + /* set text */ + g_wmdrawitm_ctr = 0; + r = SendMessage(hWndStatus, SB_SETTEXT, 0, (LPARAM)statustext); + ok( r == TRUE, "Sendmessage returned %d, expected 1\n", r); + ok( 0 == g_wmdrawitm_ctr, "got %d drawitem messages expected none\n", g_wmdrawitm_ctr); + /* set same text, with ownerdraw flag */ + g_wmdrawitm_ctr = 0; + r = SendMessage(hWndStatus, SB_SETTEXT, SBT_OWNERDRAW, (LPARAM)statustext); + ok( r == TRUE, "Sendmessage returned %d, expected 1\n", r); + ok( 1 == g_wmdrawitm_ctr, "got %d drawitem messages expected 1\n", g_wmdrawitm_ctr); + /* ;and again */ + g_wmdrawitm_ctr = 0; + r = SendMessage(hWndStatus, SB_SETTEXT, SBT_OWNERDRAW, (LPARAM)statustext); + ok( r == TRUE, "Sendmessage returned %d, expected 1\n", r); + ok( 1 == g_wmdrawitm_ctr, "got %d drawitem messages expected 1\n", g_wmdrawitm_ctr); + /* clean up */ + DestroyWindow(hWndStatus); + SetWindowLong( g_hMainWnd, GWL_STYLE, oldstyle); + SetWindowLongPtr( g_hMainWnd, GWLP_WNDPROC, (LONG_PTR)g_wndproc_saved ); +} + START_TEST(status) { hinst = GetModuleHandleA(NULL); + g_hMainWnd = CreateWindowExA(0, "static", "", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME), + 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME), + NULL, NULL, GetModuleHandleA(NULL), 0); + InitCommonControls(); + register_subclass(); + test_status_control(); + test_create(); + test_height(); + test_status_ownerdraw(); } diff --git a/rostests/winetests/comctl32/subclass.c b/rostests/winetests/comctl32/subclass.c index 9c879e30395..f4d0b727794 100644 --- a/rostests/winetests/comctl32/subclass.c +++ b/rostests/winetests/comctl32/subclass.c @@ -17,11 +17,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define _WIN32_WINNT 0x0501 /* For SetWindowSubclass/etc */ + #include #include -#define _WIN32_WINNT 0x0501 /* For SetWindowSubclass/etc */ - #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -234,7 +234,7 @@ static void test_subclass(void) ok_sequence(Sub_AfterDeletedTest, "After Deleted"); pSetWindowSubclass(hwnd, WndProcSub, 2, 0); - origProc3 = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG)WndProc3); + origProc3 = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc3); SendMessage(hwnd, WM_USER, 1, 0); SendMessage(hwnd, WM_USER, 2, 0); ok_sequence(Sub_OldAfterNewTest, "Old after New"); diff --git a/rostests/winetests/comctl32/tab.c b/rostests/winetests/comctl32/tab.c index 94893767452..33c8855b3ca 100644 --- a/rostests/winetests/comctl32/tab.c +++ b/rostests/winetests/comctl32/tab.c @@ -27,7 +27,6 @@ #include "msg.h" #define DEFAULT_MIN_TAB_WIDTH 54 -#define TAB_DEFAULT_WIDTH 96 #define TAB_PADDING_X 6 #define EXTRA_ICON_PADDING 3 #define MAX_TABLEN 32 @@ -92,7 +91,7 @@ static const struct message add_tab_to_parent[] = { { TCM_INSERTITEMA, sent }, { TCM_INSERTITEMA, sent }, { WM_NOTIFYFORMAT, sent|defwinproc }, - { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc, 0, 0 }, + { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc|optional, 0, 0 }, { WM_PARENTNOTIFY, sent|defwinproc }, { TCM_INSERTITEMA, sent }, { TCM_INSERTITEMA, sent }, @@ -125,7 +124,7 @@ static const struct message add_tab_to_parent_interactive[] = { static const struct message add_tab_control_parent_seq[] = { { WM_NOTIFYFORMAT, sent }, - { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 }, + { WM_QUERYUISTATE, sent|wparam|lparam|optional, 0, 0 }, { 0 } }; @@ -217,10 +216,10 @@ static const struct message getset_item_seq[] = { }; static const struct message getset_tooltip_seq[] = { - { WM_NOTIFYFORMAT, sent }, - { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 }, + { WM_NOTIFYFORMAT, sent|optional }, + { WM_QUERYUISTATE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_NOTIFYFORMAT, sent }, + { WM_NOTIFYFORMAT, sent|optional }, { TCM_SETTOOLTIPS, sent|lparam, 0 }, { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 }, { TCM_SETTOOLTIPS, sent|lparam, 0 }, @@ -241,7 +240,7 @@ static const struct message insert_focus_seq[] = { { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, { TCM_INSERTITEM, sent|wparam, 2 }, { WM_NOTIFYFORMAT, sent|defwinproc, }, - { WM_QUERYUISTATE, sent|defwinproc, }, + { WM_QUERYUISTATE, sent|defwinproc|optional, }, { WM_PARENTNOTIFY, sent|defwinproc, }, { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 }, { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 }, @@ -311,7 +310,7 @@ create_tabcontrol (DWORD style, DWORD mask) static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -351,7 +350,7 @@ static BOOL registerParentWindowClass(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(NULL); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "Tab test parent class"; @@ -379,7 +378,7 @@ struct subclass_info static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -493,7 +492,7 @@ static HWND create_tooltip (HWND hTab, char toolTipText[]) ti.rect = rect; /* Add toolinfo structure to the tooltip control */ - SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); + SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) &ti); return hwndTT; } @@ -506,12 +505,16 @@ static void test_tab(INT nMinTabWidth) SIZE size; HDC hdc; HFONT hOldFont; - INT i; + INT i, dpi; hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE); SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth); + /* Get System default MinTabWidth */ + if (nMinTabWidth < 0) + nMinTabWidth = SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth); hdc = GetDC(hwTab); + dpi = GetDeviceCaps(hdc, LOGPIXELSX); hOldFont = SelectObject(hdc, (HFONT)SendMessage(hwTab, WM_GETFONT, 0, 0)); GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size); trace("Tab1 text size: size.cx=%d size.cy=%d\n", size.cx, size.cy); @@ -519,7 +522,7 @@ static void test_tab(INT nMinTabWidth) ReleaseDC(hwTab, hdc); trace (" TCS_FIXEDWIDTH tabs no icon...\n"); - CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "default width"); + CheckSize(hwTab, dpi, -1, "default width"); TabCheckSetSize(hwTab, 50, 20, 50, 20, "set size"); TabCheckSetSize(hwTab, 0, 1, 0, 1, "min size"); @@ -535,8 +538,11 @@ static void test_tab(INT nMinTabWidth) hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS, TCIF_TEXT|TCIF_IMAGE); SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth); + hdc = GetDC(hwTab); + dpi = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(hwTab, hdc); trace (" TCS_FIXEDWIDTH buttons no icon...\n"); - CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "default width"); + CheckSize(hwTab, dpi, -1, "default width"); TabCheckSetSize(hwTab, 20, 20, 20, 20, "set size 1"); TabCheckSetSize(hwTab, 10, 50, 10, 50, "set size 2"); TabCheckSetSize(hwTab, 0, 1, 0, 1, "min size"); @@ -555,8 +561,11 @@ static void test_tab(INT nMinTabWidth) hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM, TCIF_TEXT|TCIF_IMAGE); SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth); + hdc = GetDC(hwTab); + dpi = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(hwTab, hdc); trace (" TCS_FIXEDWIDTH | TCS_BOTTOM tabs...\n"); - CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "no icon, default width"); + CheckSize(hwTab, dpi, -1, "no icon, default width"); TabCheckSetSize(hwTab, 20, 20, 20, 20, "no icon, set size 1"); TabCheckSetSize(hwTab, 10, 50, 10, 50, "no icon, set size 2"); @@ -633,6 +642,8 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) RECT rTab; INT nTabsRetrieved; INT rowCount; + INT dpi; + HDC hdc; ok(parent_wnd != NULL, "no parent window!\n"); flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -655,10 +666,7 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) "Parent after sequence, adding tab control to parent", TRUE); flush_sequences(sequences, NUM_MSG_SEQUENCES); - todo_wine{ - expect(DEFAULT_MIN_TAB_WIDTH, (int)SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1)); - } - ok_sequence(sequences, TAB_SEQ_INDEX, set_min_tab_width_seq, "Set minTabWidth test sequence", FALSE); + ok(SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1) > 0,"TCM_SETMINTABWIDTH returned < 0\n"); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Set minTabWidth test parent sequence", FALSE); /* Testing GetItemCount */ @@ -678,7 +686,11 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) /* Testing GetItemRect */ flush_sequences(sequences, NUM_MSG_SEQUENCES); ok(SendMessage(hTab, TCM_GETITEMRECT, 0, (LPARAM) &rTab), "GetItemRect failed.\n"); - CheckSize(hTab, TAB_DEFAULT_WIDTH, -1 , "Default Width"); + + hdc = GetDC(hTab); + dpi = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(hTab, hdc); + CheckSize(hTab, dpi, -1 , "Default Width"); ok_sequence(sequences, TAB_SEQ_INDEX, get_item_rect_seq, "Get itemRect test sequence", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get itemRect test parent sequence", FALSE); @@ -715,6 +727,7 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) { INT selectionIndex; INT focusIndex; + TCITEM tcItem; flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -744,6 +757,15 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE); + + /* selected item should have TCIS_BUTTONPRESSED state + It doesn't depend on button state */ + memset(&tcItem, 0, sizeof(TCITEM)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0); + SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem); + ok (tcItem.dwState & TCIS_BUTTONPRESSED, "Selected item should have TCIS_BUTTONPRESSED\n"); } /* Testing ExtendedStyle */ @@ -759,9 +781,7 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) expect(extendedStyle, prevExtendedStyle); extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0); - todo_wine{ expect(TCS_EX_FLATSEPARATORS, extendedStyle); - } /* Testing Register Drop */ prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP); @@ -821,6 +841,29 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE); + + /* TCIS_BUTTONPRESSED doesn't depend on tab style */ + memset(&tcItem, 0, sizeof(tcItem)); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + tcItem.dwState = TCIS_BUTTONPRESSED; + ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); + /* next highlight item, test that dwStateMask actually masks */ + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_HIGHLIGHTED; + tcItem.dwState = TCIS_HIGHLIGHTED; + ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n"); + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n"); + tcItem.mask = TCIF_STATE; + tcItem.dwStateMask = TCIS_BUTTONPRESSED; + tcItem.dwState = 0; + ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n"); + ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n"); } /* Testing GetSet ToolTip */ @@ -834,7 +877,7 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0); ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); - SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) NULL, 0); + SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0); ok (NULL == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n"); ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE); @@ -844,6 +887,22 @@ static void test_getters_setters(HWND parent_wnd, INT nTabs) DestroyWindow(hTab); } +static void test_adjustrect(HWND parent_wnd) +{ + HWND hTab; + INT r; + + ok(parent_wnd != NULL, "no parent window!\n"); + + hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, 0, 0); + ok(hTab != NULL, "Failed to create tab control\n"); + + r = SendMessage(hTab, TCM_ADJUSTRECT, FALSE, 0); + expect(-1, r); + + r = SendMessage(hTab, TCM_ADJUSTRECT, TRUE, 0); + expect(-1, r); +} static void test_insert_focus(HWND parent_wnd) { HWND hTab; @@ -956,6 +1015,69 @@ static void test_delete_focus(HWND parent_wnd) DestroyWindow(hTab); } +static void test_removeimage(HWND parent_wnd) +{ + static const BYTE bits[32]; + HWND hwTab; + INT i; + TCITEM item; + HICON hicon; + HIMAGELIST himl = ImageList_Create(16, 16, ILC_COLOR, 3, 4); + + hicon = CreateIcon(NULL, 16, 16, 1, 1, bits, bits); + ImageList_AddIcon(himl, hicon); + ImageList_AddIcon(himl, hicon); + ImageList_AddIcon(himl, hicon); + + hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE); + SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl); + + memset(&item, 0, sizeof(TCITEM)); + item.mask = TCIF_IMAGE; + + for(i = 0; i < 3; i++) { + SendMessage(hwTab, TCM_GETITEM, i, (LPARAM)&item); + expect(i, item.iImage); + } + + /* remove image middle image */ + SendMessage(hwTab, TCM_REMOVEIMAGE, 1, 0); + expect(2, ImageList_GetImageCount(himl)); + item.iImage = -1; + SendMessage(hwTab, TCM_GETITEM, 0, (LPARAM)&item); + expect(0, item.iImage); + item.iImage = 0; + SendMessage(hwTab, TCM_GETITEM, 1, (LPARAM)&item); + expect(-1, item.iImage); + item.iImage = 0; + SendMessage(hwTab, TCM_GETITEM, 2, (LPARAM)&item); + expect(1, item.iImage); + /* remove first image */ + SendMessage(hwTab, TCM_REMOVEIMAGE, 0, 0); + expect(1, ImageList_GetImageCount(himl)); + item.iImage = 0; + SendMessage(hwTab, TCM_GETITEM, 0, (LPARAM)&item); + expect(-1, item.iImage); + item.iImage = 0; + SendMessage(hwTab, TCM_GETITEM, 1, (LPARAM)&item); + expect(-1, item.iImage); + item.iImage = -1; + SendMessage(hwTab, TCM_GETITEM, 2, (LPARAM)&item); + expect(0, item.iImage); + /* remove the last one */ + SendMessage(hwTab, TCM_REMOVEIMAGE, 0, 0); + expect(0, ImageList_GetImageCount(himl)); + for(i = 0; i < 3; i++) { + item.iImage = 0; + SendMessage(hwTab, TCM_GETITEM, i, (LPARAM)&item); + expect(-1, item.iImage); + } + + DestroyWindow(hwTab); + ImageList_Destroy(himl); + DestroyIcon(hicon); +} + START_TEST(tab) { HWND parent_wnd; @@ -989,8 +1111,11 @@ START_TEST(tab) /* Testing getters and setters with 5 tabs */ test_getters_setters(parent_wnd, 5); + test_adjustrect(parent_wnd); + test_insert_focus(parent_wnd); test_delete_focus(parent_wnd); + test_removeimage(parent_wnd); DestroyWindow(parent_wnd); } diff --git a/rostests/winetests/comctl32/testlist.c b/rostests/winetests/comctl32/testlist.c index be88bef0a74..7e32af490c3 100644 --- a/rostests/winetests/comctl32/testlist.c +++ b/rostests/winetests/comctl32/testlist.c @@ -27,6 +27,7 @@ extern void func_tooltips(void); extern void func_trackbar(void); extern void func_treeview(void); extern void func_updown(void); +extern void func_ipaddress(void); const struct test winetest_testlist[] = { @@ -51,5 +52,6 @@ const struct test winetest_testlist[] = { "trackbar", func_trackbar }, { "treeview", func_treeview }, { "updown", func_updown }, + { "ipaddress", func_ipaddress }, { 0, 0 } }; diff --git a/rostests/winetests/comctl32/toolbar.c b/rostests/winetests/comctl32/toolbar.c index 2693025b2e3..4408e53036f 100644 --- a/rostests/winetests/comctl32/toolbar.c +++ b/rostests/winetests/comctl32/toolbar.c @@ -1,4 +1,4 @@ -/* Unit tests for treeview. +/* Unit tests for toolbar. * * Copyright 2005 Krzysztof Foltman * Copyright 2007 Mikolaj Zalewski @@ -114,7 +114,7 @@ static void basic_test(void) WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP | WS_CHILD | TBSTYLE_LIST, 100, - 0, NULL, (UINT)0, + 0, NULL, 0, buttons, sizeof(buttons)/sizeof(buttons[0]), 0, 0, 20, 16, sizeof(TBBUTTON)); ok(hToolbar != NULL, "Toolbar creation\n"); @@ -168,7 +168,7 @@ static void rebuild_toolbar(HWND *hToolbar) *hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL); ok(*hToolbar != NULL, "Toolbar creation problem\n"); - ok(SendMessage(*hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n"); + ok(SendMessage(*hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0) == 0, "TB_BUTTONSTRUCTSIZE failed\n"); ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n"); ok(SendMessage(*hToolbar, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0)==1, "WM_SETFONT\n"); } @@ -203,6 +203,13 @@ static void rebuild_toolbar_with_buttons(HWND *hToolbar) ok(SendMessage(*hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n"); } +static void add_128x15_bitmap(HWND hToolbar, int nCmds) +{ + TBADDBITMAP bmp128; + bmp128.hInst = GetModuleHandle(NULL); + bmp128.nID = IDB_BITMAP_128x15; + ok(SendMessageA(hToolbar, TB_ADDBITMAP, nCmds, (LPARAM)&bmp128) == 0, "TB_ADDBITMAP - unexpected return\n"); +} #define CHECK_IMAGELIST(count, dx, dy) { \ int cx, cy; \ @@ -711,6 +718,18 @@ static tbsize_result_t tbsize_results[] = { 0, 0, 163, 38}, {163, 0, 326, 38}, {326, 0, 489, 38}, {489, 0, 652, 38}, {652, 0, 819, 38}, {819, 0, 850, 38}, }, }, + { {0, 0, 672, 100}, {239, 102}, 3, { + { 0, 2, 100, 102}, {100, 2, 139, 102}, {139, 2, 239, 102}, + }, }, + { {0, 0, 672, 42}, {185, 40}, 3, { + { 0, 2, 75, 40}, {75, 2, 118, 40}, {118, 2, 185, 40}, + }, }, + { {0, 0, 672, 42}, {67, 40}, 1, { + { 0, 2, 67, 40}, + }, }, + { {0, 0, 672, 42}, {67, 41}, 2, { + { 0, 2, 672, 41}, { 0, 41, 672, 80}, + }, }, }; static int tbsize_numtests = 0; @@ -758,7 +777,8 @@ static TBBUTTON buttons3[] = { static void test_sizes(void) { HWND hToolbar = NULL; - HIMAGELIST himl; + HIMAGELIST himl, himl2; + TBBUTTONINFO tbinfo; int style; int i; @@ -854,6 +874,18 @@ static void test_sizes(void) ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 22), "Unexpected button size\n"); SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 15)); ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(23, 21), "Unexpected button size\n"); + /* -1 in TB_SETBITMAPSIZE is a special code meaning that the coordinate shouldn't be changed */ + add_128x15_bitmap(hToolbar, 16); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(14, -1)), "TB_SETBITMAPSIZE failed\n"); + compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 21), "%x"); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(-1, 12)), "TB_SETBITMAPSIZE failed\n"); + compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 18), "%x"); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(-1, -1)), "TB_SETBITMAPSIZE failed\n"); + compare((int)SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0), MAKELONG(21, 18), "%x"); + /* check the imagelist */ + InvalidateRect(hToolbar, NULL, TRUE); + UpdateWindow(hToolbar); + CHECK_IMAGELIST(16, 14, 12); rebuild_toolbar(&hToolbar); SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"A\0MMMMMMMMMMMMM\0"); @@ -896,9 +928,13 @@ static void test_sizes(void) ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 21), "Unexpected button size\n"); SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(100, 100)); ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n"); + /* But there are no update when we change imagelist, and image sizes are the same */ + himl2 = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_128x15), 20, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR); + ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, (LRESULT)himl2) == (LRESULT)himl, "TB_SETIMAGELIST failed\n"); + ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(100, 100), "Unexpected button size\n"); SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1)); ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 21), "Unexpected button size\n"); - ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl, "TB_SETIMAGELIST failed\n"); + ok(SendMessageA(hToolbar, TB_SETIMAGELIST, 0, 0) == (LRESULT)himl2, "TB_SETIMAGELIST failed\n"); ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 7), "Unexpected button size\n"); SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(1, 1)); ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(8, 7), "Unexpected button size\n"); @@ -924,6 +960,148 @@ static void test_sizes(void) SendMessageA(hToolbar, TB_DELETEBUTTON, 0, 0); ok(SendMessageA(hToolbar, TB_GETBUTTONSIZE, 0, 0) == MAKELONG(27, 39), "Unexpected button size\n"); + rebuild_toolbar(&hToolbar); + + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]) == 1, "TB_ADDBUTTONS failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]) == 1, "TB_ADDBUTTONS failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[0]) == 1, "TB_ADDBUTTONS failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 ); + check_sizes(); + + rebuild_toolbar(&hToolbar); + SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_LIST | GetWindowLong(hToolbar, GWL_STYLE)); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons2[0]) == 1, "TB_ADDBUTTONS failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[2]) == 1, "TB_ADDBUTTONS failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 ); + check_sizes_todo(0xff); + + rebuild_toolbar(&hToolbar); + SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_LIST | GetWindowLong(hToolbar, GWL_STYLE)); + ok(SendMessageA(hToolbar, TB_SETBITMAPSIZE, 0, MAKELPARAM(32, 32)) == 1, "TB_SETBITMAPSIZE failed\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(100, 100)) == 1, "TB_SETBUTTONSIZE failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 ); + check_sizes(); + + rebuild_toolbar(&hToolbar); + SetWindowLong(hToolbar, GWL_STYLE, TBSTYLE_WRAPABLE | GetWindowLong(hToolbar, GWL_STYLE)); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n"); + ok(SendMessageA(hToolbar, TB_ADDBUTTONS, 1, (LPARAM)&buttons3[3]) == 1, "TB_ADDBUTTONS failed\n"); + tbinfo.cx = 672; + tbinfo.cbSize = sizeof(TBBUTTONINFO); + tbinfo.dwMask = TBIF_SIZE | TBIF_BYINDEX; + ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 0, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONINFO, 1, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFO failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0); + check_sizes(); + + DestroyWindow(hToolbar); +} + +/* Toolbar control has two ways of reacting to a change. We call them a + * relayout and recalc. A recalc forces a recompute of values like button size + * and top margin (the latter in comctl32 code == NM_CUSTOMDRAW) { NMTTCUSTOMDRAW *ttcd = (NMTTCUSTOMDRAW*) lParam; - ok(ttcd->nmcd.hdr.hwndFrom == g_hwnd, "Unexpected hwnd source %x (%x)\n", - (int)ttcd->nmcd.hdr.hwndFrom, (int) g_hwnd); + ok(ttcd->nmcd.hdr.hwndFrom == g_hwnd, "Unexpected hwnd source %p (%p)\n", + ttcd->nmcd.hdr.hwndFrom, g_hwnd); ok(ttcd->nmcd.hdr.idFrom == 0x1234ABCD, "Unexpected id %x\n", (int)ttcd->nmcd.hdr.idFrom); switch (ttcd->nmcd.dwDrawStage) { @@ -205,7 +205,7 @@ static void test_customdraw(void) { toolInfo.hwnd = parent; toolInfo.hinst = GetModuleHandleA(NULL); toolInfo.uFlags = TTF_SUBCLASS; - toolInfo.uId = (UINT_PTR)0x1234ABCD; + toolInfo.uId = 0x1234ABCD; toolInfo.lpszText = (LPSTR)"This is a test tooltip"; toolInfo.lParam = 0xdeadbeef; GetClientRect (parent, &toolInfo.rect); @@ -213,7 +213,7 @@ static void test_customdraw(void) { ok(lResult, "Adding the tool to the tooltip failed\n"); /* Make tooltip appear quickly */ - SendMessage(hwndTip, TTM_SETDELAYTIME, (WPARAM)TTDT_INITIAL, (LPARAM)MAKELONG(1,0)); + SendMessage(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0)); /* Put cursor inside window, tooltip will appear immediately */ SetCursorPos(100, 100); @@ -232,10 +232,82 @@ static void test_customdraw(void) { } +static void test_gettext(void) +{ + HWND hwnd; + TTTOOLINFOA toolinfoA; + TTTOOLINFOW toolinfoW; + LRESULT r; + char bufA[10] = ""; + WCHAR bufW[10] = { 0 }; + + /* For bug 14790 - lpszText is NULL */ + hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, + 10, 10, 300, 100, + NULL, NULL, NULL, 0); + assert(hwnd); + + toolinfoA.cbSize = sizeof(TTTOOLINFOA); + toolinfoA.hwnd = NULL; + toolinfoA.hinst = GetModuleHandleA(NULL); + toolinfoA.uFlags = 0; + toolinfoA.uId = 0x1234ABCD; + toolinfoA.lpszText = NULL; + toolinfoA.lParam = 0xdeadbeef; + GetClientRect(hwnd, &toolinfoA.rect); + r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA); + ok(r, "Adding the tool to the tooltip failed\n"); + if (r) + { + toolinfoA.hwnd = NULL; + toolinfoA.uId = 0x1234ABCD; + toolinfoA.lpszText = bufA; + SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA); + ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n"); + } + + DestroyWindow(hwnd); + + SetLastError(0xdeadbeef); + hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0, + 10, 10, 300, 100, + NULL, NULL, NULL, 0); + + if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + win_skip("CreateWindowExW is not implemented\n"); + return; + } + + assert(hwnd); + + toolinfoW.cbSize = sizeof(TTTOOLINFOW); + toolinfoW.hwnd = NULL; + toolinfoW.hinst = GetModuleHandleA(NULL); + toolinfoW.uFlags = 0; + toolinfoW.uId = 0x1234ABCD; + toolinfoW.lpszText = NULL; + toolinfoW.lParam = 0xdeadbeef; + GetClientRect(hwnd, &toolinfoW.rect); + r = SendMessageW(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoW); + ok(r, "Adding the tool to the tooltip failed\n"); + + if (0) /* crashes on NT4 */ + { + toolinfoW.hwnd = NULL; + toolinfoW.uId = 0x1234ABCD; + toolinfoW.lpszText = bufW; + SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW); + ok(toolinfoW.lpszText[0] == 0, "lpszText should be an empty string\n"); + } + + DestroyWindow(hwnd); +} + START_TEST(tooltips) { InitCommonControls(); test_create_tooltip(); test_customdraw(); + test_gettext(); } diff --git a/rostests/winetests/comctl32/trackbar.c b/rostests/winetests/comctl32/trackbar.c index 13f56fdae78..7b7bf9efc90 100644 --- a/rostests/winetests/comctl32/trackbar.c +++ b/rostests/winetests/comctl32/trackbar.c @@ -40,6 +40,7 @@ static const struct message create_parent_wnd_seq[] = { { WM_CREATE, sent }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_QUERYNEWPALETTE, sent|optional }, { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, { WM_ACTIVATEAPP, sent|wparam, 1 }, { WM_NCACTIVATE, sent|wparam, 1 }, @@ -65,7 +66,7 @@ static const struct message parent_empty_test_seq[] = { static const struct message parent_create_trackbar_wnd_seq[] = { { WM_NOTIFYFORMAT, sent}, - { 0x0129, sent}, /* should be WM_QUERYUISTATE instead of 0x0129 */ + { WM_QUERYUISTATE, sent|optional}, { WM_WINDOWPOSCHANGING, sent}, { WM_NCACTIVATE, sent}, { PBT_APMRESUMECRITICAL, sent}, @@ -79,6 +80,7 @@ static const struct message parent_create_trackbar_wnd_seq[] = { }; static const struct message parent_new_window_test_seq[] = { + { WM_QUERYNEWPALETTE, sent|optional }, { WM_WINDOWPOSCHANGING, sent}, { WM_NCACTIVATE, sent}, { PBT_APMRESUMECRITICAL, sent}, @@ -86,7 +88,7 @@ static const struct message parent_new_window_test_seq[] = { { WM_IME_NOTIFY, sent|defwinproc|optional}, { WM_SETFOCUS, sent|defwinproc}, { WM_NOTIFYFORMAT, sent}, - { 0x0129, sent}, /* should be WM_QUERYUISTATE instead of 0x0129*/ + { WM_QUERYUISTATE, sent|optional}, {0} }; @@ -139,11 +141,13 @@ static const struct message position_test_seq[] = { { TBM_SETPOS, sent|wparam|lparam, TRUE, 5}, { WM_PAINT, sent|defwinproc}, { TBM_GETPOS, sent}, + { TBM_SETPOS, sent|wparam|lparam, TRUE, 5}, { TBM_SETPOS, sent|wparam|lparam, TRUE, 1000}, { WM_PAINT, sent|defwinproc}, { TBM_GETPOS, sent}, { TBM_SETPOS, sent|wparam|lparam, FALSE, 20}, { TBM_GETPOS, sent}, + { TBM_SETPOS, sent|wparam|lparam, TRUE, 20}, { TBM_GETPOS, sent}, {0} }; @@ -331,10 +335,10 @@ static const struct message parent_thumb_length_test_seq[] = { static const struct message tic_placement_test_seq[] = { { TBM_GETPTICS, sent}, { TBM_GETTIC, sent|wparam, 0}, + { TBM_GETTIC, sent|wparam, 2}, { TBM_GETTIC, sent|wparam, 4}, - { TBM_GETTIC, sent|wparam, 11}, { TBM_GETTICPOS, sent|wparam, 0}, - { TBM_GETTICPOS, sent|wparam, 4}, + { TBM_GETTICPOS, sent|wparam, 2}, {0} }; @@ -388,12 +392,13 @@ struct subclass_info }; static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; - /* do not log painting messages */ - if (message != WM_PAINT && + /* log system messages, except for painting */ + if (message < WM_USER && + message != WM_PAINT && message != WM_ERASEBKGND && message != WM_NCPAINT && message != WM_NCHITTEST && @@ -401,6 +406,8 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP message != WM_GETICON && message != WM_DEVICECHANGE) { + trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; @@ -425,7 +432,7 @@ static BOOL register_parent_wnd_class(void){ cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(NULL); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "Trackbar test parent class"; @@ -446,10 +453,12 @@ static HWND create_parent_window(void){ static LRESULT WINAPI trackbar_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ struct subclass_info *info = (struct subclass_info *) GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; + trace("trackbar: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; @@ -502,7 +511,7 @@ static void test_trackbar_buddy(HWND hWndTrackbar){ flush_sequences(sequences, NUM_MSG_SEQUENCE); - hWndLeftBuddy = (HWND) CreateWindowEx(0, STATUSCLASSNAME, NULL, 0, + hWndLeftBuddy = CreateWindowEx(0, STATUSCLASSNAME, NULL, 0, 0,0,300,20, NULL, NULL, NULL, NULL); ok(hWndLeftBuddy != NULL, "Expected non NULL value\n"); @@ -515,7 +524,7 @@ static void test_trackbar_buddy(HWND hWndTrackbar){ } else skip ("left buddy control not present?\n"); - hWndRightBuddy = (HWND) CreateWindowEx(0, STATUSCLASSNAME, NULL, 0, + hWndRightBuddy = CreateWindowEx(0, STATUSCLASSNAME, NULL, 0, 0,0,300,20,NULL,NULL, NULL, NULL); ok(hWndRightBuddy != NULL, "expected non NULL value\n"); @@ -579,12 +588,26 @@ static void test_page_size(HWND hWndTrackbar){ /* test TBM_GETPAGESIZE */ r = SendMessage(hWndTrackbar, TBM_GETPAGESIZE, 0,0); - todo_wine{ expect(20, r); - } ok_sequence(sequences, TRACKBAR_SEQ_INDEX, page_size_test_seq, "page size test sequence", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent page size test sequence", FALSE); + + /* check for zero page size */ + r = SendMessage(hWndTrackbar, TBM_SETPAGESIZE, 0, 0); + expect(20, r); + r = SendMessage(hWndTrackbar, TBM_GETPAGESIZE, 0, 0); + expect(0, r); + /* revert to default */ + r = SendMessage(hWndTrackbar, TBM_SETPAGESIZE, 0, -1); + expect(0, r); + r = SendMessage(hWndTrackbar, TBM_GETPAGESIZE, 0, 0); + expect(20, r); + /* < -1 */ + r = SendMessage(hWndTrackbar, TBM_SETPAGESIZE, 0, -2); + expect(20, r); + r = SendMessage(hWndTrackbar, TBM_GETPAGESIZE, 0, 0); + expect(-2, r); } static void test_position(HWND hWndTrackbar){ @@ -598,12 +621,14 @@ static void test_position(HWND hWndTrackbar){ SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, 5); r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0); expect(5, r); + SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, 5); SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, 1000); r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0); expect(100, r); SendMessage(hWndTrackbar, TBM_SETPOS, FALSE, 20); r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0); expect(20, r); + SendMessage(hWndTrackbar, TBM_SETPOS, TRUE, 20); /* test TBM_GETPOS */ r = SendMessage(hWndTrackbar, TBM_GETPOS, 0,0); @@ -799,34 +824,37 @@ static void test_tic_settings(HWND hWndTrackbar){ static void test_tic_placement(HWND hWndTrackbar){ int r; DWORD *rPTics; + DWORD numtics; + + SendMessage(hWndTrackbar, TBM_SETRANGE, TRUE, MAKELONG(1, 6)); + SendMessage(hWndTrackbar, TBM_SETTICFREQ, 1, 0); + + numtics = SendMessage(hWndTrackbar, TBM_GETNUMTICS, 0, 0); + ok(numtics == 6, "Expected 6, got %d\n", numtics); flush_sequences(sequences, NUM_MSG_SEQUENCE); /* test TBM_GETPTICS */ rPTics = (DWORD *) SendMessage(hWndTrackbar, TBM_GETPTICS, 0,0); - todo_wine{ - expect(1, rPTics[0]); - expect(2, rPTics[1]); - expect(3, rPTics[2]); - expect(4, rPTics[3]); - } + expect(2, rPTics[0]); + expect(3, rPTics[1]); + expect(4, rPTics[2]); + expect(5, rPTics[3]); /* test TBM_GETTIC */ r = SendMessage(hWndTrackbar, TBM_GETTIC, 0,0); + expect(2, r); + r = SendMessage(hWndTrackbar, TBM_GETTIC, 2,0); + expect(4, r); + r = SendMessage(hWndTrackbar, TBM_GETTIC, 4,0); todo_wine{ - expect(1, r); - r = SendMessage(hWndTrackbar, TBM_GETTIC, 4,0); - expect(5, r); + expect(-1, r); } - r = SendMessage(hWndTrackbar, TBM_GETTIC, 11,0); - expect(-1, r); /* test TBM_GETTICPIC */ r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 0, 0); - todo_wine{ ok(r > 0, "Expected r > 0, got %d\n", r); - r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 4, 0); + r = SendMessage(hWndTrackbar, TBM_GETTICPOS, 2, 0); ok(r > 0, "Expected r > 0, got %d\n", r); - } ok_sequence(sequences, TRACKBAR_SEQ_INDEX, tic_placement_test_seq, "get tic placement test sequence", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_empty_test_seq, "parent get tic placement test sequence", FALSE); @@ -861,7 +889,7 @@ static void test_tool_tips(HWND hWndTrackbar){ SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) hWndTooltip, 0); rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0); ok(rTest == hWndTooltip, "Expected hWndToolTip, got\n"); - SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) NULL, 0); + SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, 0, 0); rTest = (HWND) SendMessage(hWndTrackbar, TBM_GETTOOLTIPS, 0,0); ok(rTest == NULL, "Expected NULL\n"); SendMessage(hWndTrackbar, TBM_SETTOOLTIPS, (LPARAM) hWndTooltip, 5); diff --git a/rostests/winetests/comctl32/treeview.c b/rostests/winetests/comctl32/treeview.c index c1ba7f309be..7e7b4de3e50 100644 --- a/rostests/winetests/comctl32/treeview.c +++ b/rostests/winetests/comctl32/treeview.c @@ -32,6 +32,8 @@ #include "wine/test.h" #include "msg.h" +const char *TEST_CALLBACK_TEXT = "callback_text"; + #define NUM_MSG_SEQUENCES 1 #define LISTVIEW_SEQ_INDEX 0 @@ -64,6 +66,13 @@ static const struct message DoTest2Seq[] = { { 0 } }; +static const struct message DoTest3Seq[] = { + { TVM_INSERTITEM, sent }, + { TVM_GETITEM, sent }, + { TVM_DELETEITEM, sent }, + { 0 } +}; + static const struct message DoFocusTestSeq[] = { { TVM_INSERTITEM, sent }, { TVM_INSERTITEM, sent }, @@ -75,10 +84,10 @@ static const struct message DoFocusTestSeq[] = { { WM_NCCALCSIZE, sent|wparam, 0x00000001 }, { WM_WINDOWPOSCHANGED, sent }, { WM_SIZE, sent|defwinproc }, - { WM_WINDOWPOSCHANGING, sent|defwinproc }, - { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 }, - { WM_WINDOWPOSCHANGED, sent|defwinproc }, - { WM_SIZE, sent|defwinproc }, + { WM_WINDOWPOSCHANGING, sent|defwinproc|optional }, + { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 0x00000001 }, + { WM_WINDOWPOSCHANGED, sent|defwinproc|optional }, + { WM_SIZE, sent|defwinproc|optional }, { TVM_SELECTITEM, sent|wparam, 0x00000009 }, /* The following end up out of order in wine */ { WM_PAINT, sent|defwinproc }, @@ -104,7 +113,7 @@ static const struct message TestGetSetBkColorSeq[] = { { TVM_GETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff }, { TVM_GETBKCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, 0xffffffff }, + { TVM_SETBKCOLOR, sent|wparam|lparam, 0x00000000, -1 }, { 0 } }; @@ -139,11 +148,11 @@ static const struct message TestGetSetItemSeq[] = { static const struct message TestGetSetItemHeightSeq[] = { { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETITEMHEIGHT, sent|wparam|lparam, 0xffffffff, 0x00000000 }, + { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0x00000000 }, { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0x00000000 }, - { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETITEMHEIGHT, sent|wparam|lparam, 0x00000009, 0x00000000 }, + { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0x00000000, 0x00000000 }, + { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 0x00000009, 0x00000000 }, { WM_WINDOWPOSCHANGING, sent|defwinproc }, { WM_NCCALCSIZE, sent|wparam|defwinproc, 0x00000001 }, { WM_WINDOWPOSCHANGED, sent|defwinproc }, @@ -164,7 +173,7 @@ static const struct message TestGetSetTextColorSeq[] = { { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00ffffff }, { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0x00000000 }, - { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, 0xffffffff }, + { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0x00000000, -1 }, { 0 } }; @@ -257,6 +266,64 @@ static void FillRoot(void) ok(!strcmp(sequence, "AB."), "Item creation\n"); } +static void TestCallback(void) +{ + HTREEITEM hRoot; + HTREEITEM hItem1, hItem2; + TVINSERTSTRUCTA ins; + TVITEM tvi; + CHAR test_string[] = "Test_string"; + CHAR buf[128]; + LRESULT ret; + + TreeView_DeleteAllItems(hTree); + ins.hParent = TVI_ROOT; + ins.hInsertAfter = TVI_ROOT; + U(ins).item.mask = TVIF_TEXT; + U(ins).item.pszText = LPSTR_TEXTCALLBACK; + hRoot = TreeView_InsertItem(hTree, &ins); + assert(hRoot); + + tvi.hItem = hRoot; + tvi.mask = TVIF_TEXT; + tvi.pszText = buf; + tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]); + ret = TreeView_GetItem(hTree, &tvi); + ok(ret == 1, "ret\n"); + ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n", + tvi.pszText, TEST_CALLBACK_TEXT); + + ins.hParent = hRoot; + ins.hInsertAfter = TVI_FIRST; + U(ins).item.mask = TVIF_TEXT; + U(ins).item.pszText = test_string; + hItem1 = TreeView_InsertItem(hTree, &ins); + assert(hItem1); + + tvi.hItem = hItem1; + TreeView_GetItem(hTree, &tvi); + ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n", + tvi.pszText, test_string); + + /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */ + tvi.pszText = NULL; + ret = TreeView_SetItem(hTree, &tvi); + ok(ret == 1, "Expected SetItem return 1, got %ld\n", ret); + tvi.pszText = buf; + TreeView_GetItem(hTree, &tvi); + ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n", + tvi.pszText, TEST_CALLBACK_TEXT); + + U(ins).item.pszText = NULL; + hItem2 = TreeView_InsertItem(hTree, &ins); + assert(hItem2); + tvi.hItem = hItem2; + memset(buf, 0, sizeof(buf)); + TreeView_GetItem(hTree, &tvi); + ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n", + tvi.pszText, TEST_CALLBACK_TEXT); +} + static void DoTest1(void) { BOOL r; @@ -295,6 +362,35 @@ static void DoTest2(void) ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n"); } +static void DoTest3(void) +{ + TVINSERTSTRUCTA ins; + HTREEITEM hChild; + TVITEM tvi; + + int nBufferSize = 80; + CHAR szBuffer[80] = "Blah"; + + /* add an item without TVIF_TEXT mask and pszText == NULL */ + ins.hParent = hRoot; + ins.hInsertAfter = TVI_ROOT; + U(ins).item.mask = 0; + U(ins).item.pszText = NULL; + U(ins).item.cchTextMax = 0; + hChild = TreeView_InsertItem(hTree, &ins); + assert(hChild); + + /* retrieve it with TVIF_TEXT mask */ + tvi.hItem = hChild; + tvi.mask = TVIF_TEXT; + tvi.cchTextMax = nBufferSize; + tvi.pszText = szBuffer; + + SendMessageA( hTree, TVM_GETITEM, 0, (LPARAM)&tvi ); + ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer); + ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n"); +} + static void DoFocusTest(void) { TVINSERTSTRUCTA ins; @@ -331,11 +427,9 @@ static void TestGetSetBkColor(void) { COLORREF crColor = RGB(0,0,0); - todo_wine{ /* If the value is -1, the control is using the system color for the background color. */ crColor = (COLORREF)SendMessage( hTree, TVM_GETBKCOLOR, 0, 0 ); ok(crColor == -1, "Default background color reported as 0x%.8x\n", crColor); - } /* Test for black background */ SendMessage( hTree, TVM_SETBKCOLOR, 0, (LPARAM)RGB(0,0,0) ); @@ -571,7 +665,7 @@ static void TestGetSet(void) /* This function hooks in and records all messages to the treeview control */ static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); @@ -628,6 +722,13 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa IdentifyItem(pTreeView->itemOld.hItem); IdentifyItem(pTreeView->itemNew.hItem); return 0; + case TVN_GETDISPINFOA: { + NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam; + if (disp->item.mask & TVIF_TEXT) { + lstrcpyn(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax); + } + return 0; + } } } return 0; @@ -647,6 +748,76 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa return 0L; } +static void TestExpandInvisible(void) +{ + static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"}; + TVINSERTSTRUCTA ins; + HTREEITEM node[5]; + RECT dummyRect; + BOOL nodeVisible; + + /* The test builds the following tree and expands then node 1, while node 0 is collapsed. + * + * 0 + * |- 1 + * | |- 2 + * | |- 3 + * |- 4 + * + */ + + TreeView_DeleteAllItems(hTree); + + ins.hParent = TVI_ROOT; + ins.hInsertAfter = TVI_ROOT; + U(ins).item.mask = TVIF_TEXT; + U(ins).item.pszText = nodeText[0]; + node[0] = TreeView_InsertItem(hTree, &ins); + assert(node[0]); + + ins.hInsertAfter = TVI_LAST; + U(ins).item.mask = TVIF_TEXT; + ins.hParent = node[0]; + + U(ins).item.pszText = nodeText[1]; + node[1] = TreeView_InsertItem(hTree, &ins); + assert(node[1]); + U(ins).item.pszText = nodeText[4]; + node[4] = TreeView_InsertItem(hTree, &ins); + assert(node[4]); + + ins.hParent = node[1]; + + U(ins).item.pszText = nodeText[2]; + node[2] = TreeView_InsertItem(hTree, &ins); + assert(node[2]); + U(ins).item.pszText = nodeText[3]; + node[3] = TreeView_InsertItem(hTree, &ins); + assert(node[3]); + + + nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE); + ok(!nodeVisible, "Node 1 should not be visible.\n"); + nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE); + ok(!nodeVisible, "Node 2 should not be visible.\n"); + nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE); + ok(!nodeVisible, "Node 3 should not be visible.\n"); + nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE); + ok(!nodeVisible, "Node 4 should not be visible.\n"); + + ok(TreeView_Expand(hTree, node[1], TVE_EXPAND), "Expand of node 1 failed.\n"); + + nodeVisible = TreeView_GetItemRect(hTree, node[1], &dummyRect, FALSE); + ok(!nodeVisible, "Node 1 should not be visible.\n"); + nodeVisible = TreeView_GetItemRect(hTree, node[2], &dummyRect, FALSE); + ok(!nodeVisible, "Node 2 should not be visible.\n"); + nodeVisible = TreeView_GetItemRect(hTree, node[3], &dummyRect, FALSE); + ok(!nodeVisible, "Node 3 should not be visible.\n"); + nodeVisible = TreeView_GetItemRect(hTree, node[4], &dummyRect, FALSE); + ok(!nodeVisible, "Node 4 should not be visible.\n"); +} + + START_TEST(treeview) { HMODULE hComctl32; @@ -699,6 +870,10 @@ START_TEST(treeview) DoTest2(); ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoTest2Seq, "DoTest2", FALSE); + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); + DoTest3(); + ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoTest3Seq, "DoTest3", FALSE); + flush_sequences(MsgSequences, NUM_MSG_SEQUENCES); DoFocusTest(); ok_sequence(MsgSequences, LISTVIEW_SEQ_INDEX, DoFocusTestSeq, "DoFocusTest", TRUE); @@ -706,6 +881,12 @@ START_TEST(treeview) /* Sequences tested inside due to number */ TestGetSet(); + /* Clears all the previous items */ + TestCallback(); + + /* Clears all the previous items */ + TestExpandInvisible(); + PostMessageA(hMainWnd, WM_CLOSE, 0, 0); while(GetMessageA(&msg,0,0,0)) { TranslateMessage(&msg); diff --git a/rostests/winetests/comctl32/updown.c b/rostests/winetests/comctl32/updown.c index 6f8e395f26d..433c190ae97 100644 --- a/rostests/winetests/comctl32/updown.c +++ b/rostests/winetests/comctl32/updown.c @@ -70,6 +70,7 @@ static const struct message create_parent_wnd_seq[] = { { WM_CREATE, sent }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_QUERYNEWPALETTE, sent|optional }, { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, { WM_ACTIVATEAPP, sent|wparam, 1 }, { WM_NCACTIVATE, sent|wparam, 1 }, @@ -100,7 +101,7 @@ static const struct message add_updown_with_edit_seq[] = { static const struct message add_updown_to_parent_seq[] = { { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY }, - { WM_QUERYUISTATE, sent }, + { WM_QUERYUISTATE, sent|optional }, { WM_PARENTNOTIFY, sent|wparam, MAKELONG(WM_CREATE, WM_CREATE) }, { 0 } }; @@ -192,12 +193,13 @@ static const struct message test_updown_destroy_seq[] = { static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; - /* do not log painting messages */ - if (message != WM_PAINT && + /* log system messages, except for painting */ + if (message < WM_USER && + message != WM_PAINT && message != WM_ERASEBKGND && message != WM_NCPAINT && message != WM_NCHITTEST && @@ -232,7 +234,7 @@ static BOOL register_parent_wnd_class(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(NULL); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "Up-Down test parent class"; @@ -260,7 +262,7 @@ struct subclass_info static LRESULT WINAPI edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; @@ -308,7 +310,7 @@ static HWND create_edit_control(void) static LRESULT WINAPI updown_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; struct message msg; diff --git a/rostests/winetests/comdlg32/comdlg32.rbuild b/rostests/winetests/comdlg32/comdlg32.rbuild index e694a7f0554..d24dc1bd3c8 100644 --- a/rostests/winetests/comdlg32/comdlg32.rbuild +++ b/rostests/winetests/comdlg32/comdlg32.rbuild @@ -3,15 +3,15 @@ . - 0x600 - 0x600 + filedlg.c printdlg.c testlist.c + rsrc.rc wine comdlg32 user32 - kernel32 + gdi32 ntdll diff --git a/rostests/winetests/comdlg32/filedlg.c b/rostests/winetests/comdlg32/filedlg.c index ea999f330db..9714dda1fe3 100644 --- a/rostests/winetests/comdlg32/filedlg.c +++ b/rostests/winetests/comdlg32/filedlg.c @@ -22,10 +22,14 @@ #include #include +#include "initguid.h" +#include "shlguid.h" +#define COBJMACROS +#include "shobjidl.h" /* ##### */ -static UINT CALLBACK OFNHookProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +static UINT_PTR CALLBACK OFNHookProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { LPNMHDR nmh; @@ -70,7 +74,7 @@ static void test_DialogCancel(void) ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLEHOOK; ofn.lpstrDefExt = "txt"; - ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProc; + ofn.lpfnHook = OFNHookProc; ofn.lpstrInitialDir = szInitialDir; PrintDlgA(NULL); @@ -107,7 +111,7 @@ static void test_DialogCancel(void) SetLastError(0xdeadbeef); result = GetOpenFileNameW((LPOPENFILENAMEW) &ofn); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - skip("GetOpenFileNameW is not implemented\n"); + win_skip("GetOpenFileNameW is not implemented\n"); else { ok(0 == result, "expected %d, got %d\n", 0, result); @@ -120,7 +124,7 @@ static void test_DialogCancel(void) SetLastError(0xdeadbeef); result = GetSaveFileNameW((LPOPENFILENAMEW) &ofn); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - skip("GetSaveFileNameW is not implemented\n"); + win_skip("GetSaveFileNameW is not implemented\n"); else { ok(0 == result, "expected %d, got %d\n", 0, result); @@ -131,9 +135,144 @@ static void test_DialogCancel(void) } } +static UINT_PTR CALLBACK create_view_window2_hook(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_NOTIFY) + { + if (((LPNMHDR)lParam)->code == CDN_FOLDERCHANGE) + { + IShellBrowser *shell_browser = (IShellBrowser *)SendMessage(GetParent(dlg), WM_USER + 7 /* WM_GETISHELLBROWSER */, 0, 0); + IShellView *shell_view = NULL; + IShellView2 *shell_view2 = NULL; + SV2CVW2_PARAMS view_params; + FOLDERSETTINGS folder_settings; + HRESULT hr; + RECT rect = {0, 0, 0, 0}; + + hr = IShellBrowser_QueryActiveShellView(shell_browser, &shell_view); + ok(SUCCEEDED(hr), "QueryActiveShellView returned %#x\n", hr); + if (FAILED(hr)) goto cleanup; + + hr = IShellView_QueryInterface(shell_view, &IID_IShellView2, (void **)&shell_view2); + if (hr == E_NOINTERFACE) + { + win_skip("IShellView2 not supported\n"); + goto cleanup; + } + ok(SUCCEEDED(hr), "QueryInterface returned %#x\n", hr); + if (FAILED(hr)) goto cleanup; + + hr = IShellView2_DestroyViewWindow(shell_view2); + ok(SUCCEEDED(hr), "DestroyViewWindow returned %#x\n", hr); + + folder_settings.ViewMode = FVM_LIST; + folder_settings.fFlags = 0; + + view_params.cbSize = sizeof(view_params); + view_params.psvPrev = NULL; + view_params.pfs = &folder_settings; + view_params.psbOwner = shell_browser; + view_params.prcView = ▭ + view_params.pvid = NULL; + view_params.hwndView = NULL; + + hr = IShellView2_CreateViewWindow2(shell_view2, &view_params); + ok(SUCCEEDED(hr), "CreateViewWindow2 returned %#x\n", hr); + if (FAILED(hr)) goto cleanup; + + hr = IShellView2_GetCurrentInfo(shell_view2, &folder_settings); + ok(SUCCEEDED(hr), "GetCurrentInfo returned %#x\n", hr); + ok(folder_settings.ViewMode == FVM_LIST, "view mode is %d, expected %d\n", folder_settings.ViewMode, FVM_LIST); + + hr = IShellView2_DestroyViewWindow(shell_view2); + ok(SUCCEEDED(hr), "DestroyViewWindow returned %#x\n", hr); + + /* XP and W2K3 need this. On Win9x and W2K the call to DestroyWindow() fails and has + * no side effects. NT4 doesn't get here. (FIXME: Vista doesn't get here yet). + */ + DestroyWindow(view_params.hwndView); + + view_params.pvid = &VID_Details; + hr = IShellView2_CreateViewWindow2(shell_view2, &view_params); + ok(SUCCEEDED(hr), "CreateViewWindow2 returned %#x\n", hr); + if (FAILED(hr)) goto cleanup; + + hr = IShellView2_GetCurrentInfo(shell_view2, &folder_settings); + ok(SUCCEEDED(hr), "GetCurrentInfo returned %#x\n", hr); + ok(folder_settings.ViewMode == FVM_DETAILS || + broken(folder_settings.ViewMode == FVM_LIST), /* Win9x */ + "view mode is %d, expected %d\n", folder_settings.ViewMode, FVM_DETAILS); + +cleanup: + if (shell_view2) IShellView2_Release(shell_view2); + if (shell_view) IShellView_Release(shell_view); + PostMessage(GetParent(dlg), WM_COMMAND, IDCANCEL, 0); + } + } + return 0; +} + +static LONG_PTR WINAPI template_hook(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_INITDIALOG) + { + HWND p,cb; + INT sel; + p = GetParent(dlg); + ok(p!=NULL, "Failed to get parent of template\n"); + cb = GetDlgItem(p,0x470); + ok(cb!=NULL, "Failed to get filter combobox\n"); + sel = SendMessage(cb, CB_GETCURSEL, 0, 0); + ok (sel != -1, "Failed to get selection from filter listbox\n"); + } + if (msg == WM_NOTIFY) + { + if (((LPNMHDR)lParam)->code == CDN_FOLDERCHANGE) + PostMessage(GetParent(dlg), WM_COMMAND, IDCANCEL, 0); + } + return 0; +} + +static void test_create_view_window2(void) +{ + OPENFILENAMEA ofn = {0}; + char filename[1024] = {0}; + DWORD ret; + + ofn.lStructSize = sizeof(ofn); + ofn.lpstrFile = filename; + ofn.nMaxFile = 1042; + ofn.lpfnHook = create_view_window2_hook; + ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER; + ret = GetOpenFileNameA(&ofn); + ok(!ret, "GetOpenFileNameA returned %#x\n", ret); + ret = CommDlgExtendedError(); + ok(!ret, "CommDlgExtendedError returned %#x\n", ret); +} + +static void test_create_view_template(void) +{ + OPENFILENAMEA ofn = {0}; + char filename[1024] = {0}; + DWORD ret; + + ofn.lStructSize = sizeof(ofn); + ofn.lpstrFile = filename; + ofn.nMaxFile = 1042; + ofn.lpfnHook = (LPOFNHOOKPROC)template_hook; + ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATE; + ofn.hInstance = GetModuleHandleA(NULL); + ofn.lpTemplateName = "template1"; + ofn.lpstrFilter="text\0*.txt\0All\0*\0\0"; + ret = GetOpenFileNameA(&ofn); + ok(!ret, "GetOpenFileNameA returned %#x\n", ret); + ret = CommDlgExtendedError(); + ok(!ret, "CommDlgExtendedError returned %#x\n", ret); +} START_TEST(filedlg) { test_DialogCancel(); - + test_create_view_window2(); + test_create_view_template(); } diff --git a/rostests/winetests/comdlg32/printdlg.c b/rostests/winetests/comdlg32/printdlg.c index fef274de27b..ec63da9a6c7 100644 --- a/rostests/winetests/comdlg32/printdlg.c +++ b/rostests/winetests/comdlg32/printdlg.c @@ -289,6 +289,90 @@ static void test_PrintDlgExW(void) } +static BOOL abort_proc_called = FALSE; +static BOOL CALLBACK abort_proc(HDC hdc, int error) { return abort_proc_called = TRUE; } +static void test_abort_proc(void) +{ + HDC print_dc; + RECT rect = {0, 0, 100, 100}; + DOCINFOA doc_info = {0}; + PRINTDLGA pd = {0}; + char filename[MAX_PATH]; + int job_id; + + if (!GetTempFileNameA(".", "prn", 0, filename)) + { + skip("Failed to create a temporary file name\n"); + return; + } + + pd.lStructSize = sizeof(pd); + pd.Flags = PD_RETURNDEFAULT | PD_ALLPAGES | PD_RETURNDC | PD_PRINTTOFILE; + pd.nFromPage = 1; + pd.nToPage = 1; + pd.nCopies = 1; + + if (!PrintDlgA(&pd)) + { + skip("No default printer available.\n"); + ok(DeleteFileA(filename), "Failed to delete temporary file\n"); + return; + } + + ok(pd.hDC != NULL, "PrintDlg didn't return a DC.\n"); + if (!(print_dc = pd.hDC)) + { + ok(DeleteFileA(filename), "Failed to delete temporary file\n"); + return; + } + + ok(SetAbortProc(print_dc, abort_proc) > 0, "SetAbortProc failed\n"); + ok(!abort_proc_called, "AbortProc got called unexpectedly by SetAbortProc.\n"); + abort_proc_called = FALSE; + + doc_info.cbSize = sizeof(doc_info); + doc_info.lpszDocName = "Some document"; + doc_info.lpszOutput = filename; + + job_id = StartDocA(print_dc, &doc_info); + + ok(job_id > 0 || + GetLastError() == ERROR_SPL_NO_STARTDOC, /* Vista can fail with this error when using the XPS driver */ + "StartDocA failed ret %d gle %d\n", job_id, GetLastError()); + + if(job_id <= 0) + { + skip("StartDoc failed\n"); + goto end; + } + + ok(abort_proc_called, "AbortProc didn't get called by StartDoc.\n"); + abort_proc_called = FALSE; + + ok(StartPage(print_dc) > 0, "StartPage failed\n"); + ok(!abort_proc_called, "AbortProc got called unexpectedly by StartPage.\n"); + abort_proc_called = FALSE; + + ok(FillRect(print_dc, &rect, (HBRUSH)(COLOR_BACKGROUND + 1)), "FillRect failed\n"); + ok(!abort_proc_called, "AbortProc got called unexpectedly by StretchBlt.\n"); + abort_proc_called = FALSE; + + ok(EndPage(print_dc) > 0, "EndPage failed\n"); + ok(!abort_proc_called, "AbortProc got called unexpectedly by EndPage.\n"); + abort_proc_called = FALSE; + + ok(EndDoc(print_dc) > 0, "EndDoc failed\n"); + ok(!abort_proc_called, "AbortProc got called unexpectedly by EndDoc.\n"); + abort_proc_called = FALSE; + + ok(DeleteDC(print_dc), "DeleteDC failed\n"); + ok(!abort_proc_called, "AbortProc got called unexpectedly by DeleteDC.\n"); + abort_proc_called = FALSE; + +end: + ok(DeleteFileA(filename), "Failed to delete temporary file\n"); +} + /* ########################### */ START_TEST(printdlg) @@ -299,10 +383,11 @@ START_TEST(printdlg) test_PageSetupDlgA(); test_PrintDlgA(); + test_abort_proc(); /* PrintDlgEx not present before w2k */ if (ptr) { - skip("%s\n", ptr); + win_skip("%s\n", ptr); return; } diff --git a/rostests/winetests/comdlg32/rsrc.rc b/rostests/winetests/comdlg32/rsrc.rc new file mode 100644 index 00000000000..51415fddb26 --- /dev/null +++ b/rostests/winetests/comdlg32/rsrc.rc @@ -0,0 +1,34 @@ +/* Resources for the common dialog unit test suite. + * + * Copyright 2008 CodeWeavers, Aric Stewart + * + * 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 + */ + +#include "windef.h" +#include "winuser.h" + +TEMPLATE1 DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215 +STYLE WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS +FONT 8, "MS Shell Dlg" +{ + LTEXT "Path:",-1,28,4,36,8 + LTEXT "Text1",-1,4,16,20,40 + LTEXT "Selected:",-1,32,49,40,8 + EDITTEXT 55,74,47,200,12,ES_AUTOHSCROLL + LTEXT "Text2",-1,232,20,65,8 + LTEXT "",-1,28,16,204,31 + EDITTEXT 56,65,2,200,12,ES_AUTOHSCROLL +} diff --git a/rostests/winetests/credui/credui.c b/rostests/winetests/credui/credui.c new file mode 100644 index 00000000000..969b096a766 --- /dev/null +++ b/rostests/winetests/credui/credui.c @@ -0,0 +1,132 @@ +/* + * Credentials User Interface Tests + * + * Copyright 2007 Robert Shearman for CodeWeavers + * + * 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 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "wincred.h" + +#include "wine/test.h" + +static void test_CredUIPromptForCredentials(void) +{ + static const WCHAR wszServerName[] = {'W','i','n','e','T','e','s','t',0}; + DWORD ret; + WCHAR username[256]; + WCHAR password[256]; + CREDUI_INFOW credui_info; + BOOL save = FALSE; + + credui_info.cbSize = sizeof(credui_info); + credui_info.hwndParent = NULL; + credui_info.pszMessageText = NULL; + credui_info.hbmBanner = NULL; + + ret = CredUIConfirmCredentialsW(NULL, TRUE); + ok(ret == ERROR_INVALID_PARAMETER /* 2003 + */ || ret == ERROR_NOT_FOUND /* XP */, + "CredUIConfirmCredentials should have returned ERROR_INVALID_PARAMETER or ERROR_NOT_FOUND instead of %d\n", ret); + + ret = CredUIConfirmCredentialsW(wszServerName, TRUE); + ok(ret == ERROR_NOT_FOUND, "CredUIConfirmCredentials should have returned ERROR_NOT_FOUND instead of %d\n", ret); + + username[0] = '\0'; + password[0] = '\0'; + ret = CredUIPromptForCredentialsW(NULL, NULL, NULL, 0, username, + sizeof(username)/sizeof(username[0]), + password, sizeof(password)/sizeof(password[0]), + NULL, CREDUI_FLAGS_ALWAYS_SHOW_UI); + ok(ret == ERROR_INVALID_FLAGS, "CredUIPromptForCredentials should have returned ERROR_INVALID_FLAGS instead of %d\n", ret); + + ret = CredUIPromptForCredentialsW(NULL, NULL, NULL, 0, username, + sizeof(username)/sizeof(username[0]), + password, sizeof(password)/sizeof(password[0]), + NULL, CREDUI_FLAGS_ALWAYS_SHOW_UI | CREDUI_FLAGS_GENERIC_CREDENTIALS); + ok(ret == ERROR_INVALID_PARAMETER, "CredUIPromptForCredentials should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret); + + ret = CredUIPromptForCredentialsW(NULL, wszServerName, NULL, 0, username, + sizeof(username)/sizeof(username[0]), + password, sizeof(password)/sizeof(password[0]), + NULL, CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX); + ok(ret == ERROR_INVALID_PARAMETER, "CredUIPromptForCredentials should have returned ERROR_INVALID_FLAGS instead of %d\n", ret); + + if (winetest_interactive) + { + static const WCHAR wszCaption1[] = {'C','R','E','D','U','I','_','F','L','A','G','S','_','E','X','P','E','C','T','_','C','O','N','F','I','R','M','A','T','I','O','N',0}; + static const WCHAR wszCaption2[] = {'C','R','E','D','U','I','_','F','L','A','G','S','_','I','N','C','O','R','R','E','C','T','_','P','A','S','S','W','O','R','D','|', + 'C','R','E','D','U','I','_','F','L','A','G','S','_','E','X','P','E','C','T','_','C','O','N','F','I','R','M','A','T','I','O','N',0}; + static const WCHAR wszCaption3[] = {'C','R','E','D','U','I','_','F','L','A','G','S','_','D','O','_','N','O','T','_','P','E','R','S','I','S','T','|', + 'C','R','E','D','U','I','_','F','L','A','G','S','_','E','X','P','E','C','T','_','C','O','N','F','I','R','M','A','T','I','O','N',0}; + static const WCHAR wszCaption4[] = {'C','R','E','D','U','I','_','F','L','A','G','S','_','P','E','R','S','I','S','T','|', + 'C','R','E','D','U','I','_','F','L','A','G','S','_','E','X','P','E','C','T','_','C','O','N','F','I','R','M','A','T','I','O','N',0}; + + ret = CredUIPromptForCredentialsW(NULL, wszServerName, NULL, 0, username, + sizeof(username)/sizeof(username[0]), + password, sizeof(password)/sizeof(password[0]), + &save, CREDUI_FLAGS_EXPECT_CONFIRMATION); + ok(ret == ERROR_SUCCESS || ret == ERROR_CANCELLED, "CredUIPromptForCredentials failed with error %d\n", ret); + if (ret == ERROR_SUCCESS) + ret = CredUIConfirmCredentialsW(wszServerName, FALSE); + + credui_info.pszCaptionText = wszCaption1; + ret = CredUIPromptForCredentialsW(&credui_info, wszServerName, NULL, + ERROR_ACCESS_DENIED, + username, sizeof(username)/sizeof(username[0]), + password, sizeof(password)/sizeof(password[0]), + &save, CREDUI_FLAGS_EXPECT_CONFIRMATION); + ok(ret == ERROR_SUCCESS || ret == ERROR_CANCELLED, "CredUIPromptForCredentials failed with error %d\n", ret); + if (ret == ERROR_SUCCESS) + ret = CredUIConfirmCredentialsW(wszServerName, FALSE); + + credui_info.pszCaptionText = wszCaption2; + ret = CredUIPromptForCredentialsW(&credui_info, wszServerName, NULL, 0, + username, sizeof(username)/sizeof(username[0]), + password, sizeof(password)/sizeof(password[0]), + NULL, CREDUI_FLAGS_INCORRECT_PASSWORD|CREDUI_FLAGS_EXPECT_CONFIRMATION); + ok(ret == ERROR_SUCCESS || ret == ERROR_CANCELLED, "CredUIPromptForCredentials failed with error %d\n", ret); + if (ret == ERROR_SUCCESS) + ret = CredUIConfirmCredentialsW(wszServerName, FALSE); + + save = TRUE; + credui_info.pszCaptionText = wszCaption3; + ret = CredUIPromptForCredentialsW(&credui_info, wszServerName, NULL, 0, + username, sizeof(username)/sizeof(username[0]), + password, sizeof(password)/sizeof(password[0]), + &save, CREDUI_FLAGS_DO_NOT_PERSIST|CREDUI_FLAGS_EXPECT_CONFIRMATION); + ok(ret == ERROR_SUCCESS || ret == ERROR_CANCELLED, "CredUIPromptForCredentials failed with error %d\n", ret); + ok(save, "save flag should have been untouched\n"); + + save = FALSE; + credui_info.pszCaptionText = wszCaption4; + ret = CredUIPromptForCredentialsW(&credui_info, wszServerName, NULL, 0, + username, sizeof(username)/sizeof(username[0]), + password, sizeof(password)/sizeof(password[0]), + &save, CREDUI_FLAGS_PERSIST|CREDUI_FLAGS_EXPECT_CONFIRMATION); + ok(ret == ERROR_SUCCESS || ret == ERROR_CANCELLED, "CredUIPromptForCredentials failed with error %d\n", ret); + ok(!save, "save flag should have been untouched\n"); + if (ret == ERROR_SUCCESS) + ret = CredUIConfirmCredentialsW(wszServerName, FALSE); + } +} + +START_TEST(credui) +{ + test_CredUIPromptForCredentials(); +} diff --git a/rostests/winetests/credui/credui.rbuild b/rostests/winetests/credui/credui.rbuild new file mode 100644 index 00000000000..90863a6492d --- /dev/null +++ b/rostests/winetests/credui/credui.rbuild @@ -0,0 +1,9 @@ + + . + + credui.c + testlist.c + wine + credui + ntdll + diff --git a/rostests/winetests/credui/testlist.c b/rostests/winetests/credui/testlist.c new file mode 100644 index 00000000000..838ca5037d0 --- /dev/null +++ b/rostests/winetests/credui/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_credui(void); + +const struct test winetest_testlist[] = +{ + { "credui", func_credui }, + { 0, 0 } +}; diff --git a/rostests/winetests/crypt32/base64.c b/rostests/winetests/crypt32/base64.c new file mode 100644 index 00000000000..5a260edfd6e --- /dev/null +++ b/rostests/winetests/crypt32/base64.c @@ -0,0 +1,458 @@ +/* + * Unit test suite for crypt32.dll's CryptStringToBinary and CryptBinaryToString + * functions. + * + * Copyright 2006 Juan Lang + * + * 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 + */ +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +#define CERT_HEADER "-----BEGIN CERTIFICATE-----\r\n" +#define CERT_TRAILER "-----END CERTIFICATE-----\r\n" +#define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n" +#define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----\r\n" +#define X509_HEADER "-----BEGIN X509 CRL-----\r\n" +#define X509_TRAILER "-----END X509 CRL-----\r\n" +#define CERT_HEADER_NOCR "-----BEGIN CERTIFICATE-----\n" +#define CERT_TRAILER_NOCR "-----END CERTIFICATE-----\n" +#define CERT_REQUEST_HEADER_NOCR "-----BEGIN NEW CERTIFICATE REQUEST-----\n" +#define CERT_REQUEST_TRAILER_NOCR "-----END NEW CERTIFICATE REQUEST-----\n" +#define X509_HEADER_NOCR "-----BEGIN X509 CRL-----\n" +#define X509_TRAILER_NOCR "-----END X509 CRL-----\n" + +typedef BOOL (WINAPI *CryptBinaryToStringAFunc)(const BYTE *pbBinary, + DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString); +typedef BOOL (WINAPI *CryptStringToBinaryAFunc)(LPCSTR pszString, + DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary, + DWORD *pdwSkip, DWORD *pdwFlags); + +CryptBinaryToStringAFunc pCryptBinaryToStringA; +CryptStringToBinaryAFunc pCryptStringToBinaryA; + +struct BinTests +{ + const BYTE *toEncode; + DWORD toEncodeLen; + const char *base64; +}; + +static const BYTE toEncode1[] = { 0 }; +static const BYTE toEncode2[] = { 1,2 }; +static const BYTE toEncode3[] = { 1,2,3 }; +static const BYTE toEncode4[] = + "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890" + "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890" + "abcdefghijlkmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"; + +struct BinTests tests[] = { + { toEncode1, sizeof(toEncode1), "AA==\r\n", }, + { toEncode2, sizeof(toEncode2), "AQI=\r\n", }, + /* { toEncode3, sizeof(toEncode3), "AQID\r\n", }, This test fails on Vista. */ + { toEncode4, sizeof(toEncode4), + "YWJjZGVmZ2hpamxrbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5MEFCQ0RFRkdISUpL\r\n" + "TE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4OTBhYmNkZWZnaGlqbGttbm9wcXJzdHV2\r\n" + "d3h5ejAxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2\r\n" + "Nzg5MGFiY2RlZmdoaWpsa21ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OTBBQkNERUZH\r\n" + "SElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkwAA==\r\n" }, +}; + +struct BinTests testsNoCR[] = { + { toEncode1, sizeof(toEncode1), "AA==\n", }, + { toEncode2, sizeof(toEncode2), "AQI=\n", }, + /* { toEncode3, sizeof(toEncode3), "AQID\n", }, This test fails on Vista. */ + { toEncode4, sizeof(toEncode4), + "YWJjZGVmZ2hpamxrbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5MEFCQ0RFRkdISUpL\n" + "TE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4OTBhYmNkZWZnaGlqbGttbm9wcXJzdHV2\n" + "d3h5ejAxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2\n" + "Nzg5MGFiY2RlZmdoaWpsa21ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OTBBQkNERUZH\n" + "SElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkwAA==\n" }, +}; + +static void encodeAndCompareBase64_A(const BYTE *toEncode, DWORD toEncodeLen, + DWORD format, const char *expected, const char *header, const char *trailer) +{ + DWORD strLen = 0; + LPSTR str = NULL; + BOOL ret; + + ret = pCryptBinaryToStringA(toEncode, toEncodeLen, format, NULL, &strLen); + ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError()); + str = HeapAlloc(GetProcessHeap(), 0, strLen); + if (str) + { + DWORD strLen2 = strLen; + LPCSTR ptr = str; + + ret = pCryptBinaryToStringA(toEncode, toEncodeLen, format, str, + &strLen2); + ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError()); + ok(strLen2 == strLen - 1, "Expected length %d, got %d\n", + strLen - 1, strLen); + if (header) + { + ok(!strncmp(header, ptr, strlen(header)), + "Expected header %s, got %s\n", header, ptr); + ptr += strlen(header); + } + ok(!strncmp(expected, ptr, strlen(expected)), + "Expected %s, got %s\n", expected, ptr); + ptr += strlen(expected); + if (trailer) + { + ok(!strncmp(trailer, ptr, strlen(trailer)), + "Expected trailer %s, got %s\n", trailer, ptr); + ptr += strlen(trailer); + } + HeapFree(GetProcessHeap(), 0, str); + } +} + +static void testBinaryToStringA(void) +{ + BOOL ret; + DWORD strLen = 0, i; + + ret = pCryptBinaryToStringA(NULL, 0, 0, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ret = pCryptBinaryToStringA(NULL, 0, 0, NULL, &strLen); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + { + DWORD strLen = 0; + LPSTR str = NULL; + BOOL ret; + + ret = pCryptBinaryToStringA(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BINARY, NULL, &strLen); + ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError()); + str = HeapAlloc(GetProcessHeap(), 0, strLen); + if (str) + { + DWORD strLen2 = strLen; + + ret = pCryptBinaryToStringA(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BINARY, str, &strLen2); + ok(strLen == strLen2, "Expected length %d, got %d\n", strLen, + strLen2); + ok(!memcmp(str, tests[i].toEncode, tests[i].toEncodeLen), + "Unexpected value\n"); + HeapFree(GetProcessHeap(), 0, str); + } + encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BASE64, tests[i].base64, NULL, NULL); + encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BASE64HEADER, tests[i].base64, CERT_HEADER, + CERT_TRAILER); + encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BASE64REQUESTHEADER, tests[i].base64, + CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER); + encodeAndCompareBase64_A(tests[i].toEncode, tests[i].toEncodeLen, + CRYPT_STRING_BASE64X509CRLHEADER, tests[i].base64, X509_HEADER, + X509_TRAILER); + } + for (i = 0; i < sizeof(testsNoCR) / sizeof(testsNoCR[0]); i++) + { + DWORD strLen = 0; + LPSTR str = NULL; + BOOL ret; + + ret = pCryptBinaryToStringA(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, CRYPT_STRING_BINARY | CRYPT_STRING_NOCR, + NULL, &strLen); + ok(ret, "CryptBinaryToStringA failed: %d\n", GetLastError()); + str = HeapAlloc(GetProcessHeap(), 0, strLen); + if (str) + { + DWORD strLen2 = strLen; + + ret = pCryptBinaryToStringA(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, CRYPT_STRING_BINARY | CRYPT_STRING_NOCR, + str, &strLen2); + ok(strLen == strLen2, "Expected length %d, got %d\n", strLen, + strLen2); + ok(!memcmp(str, testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen), + "Unexpected value\n"); + HeapFree(GetProcessHeap(), 0, str); + } + encodeAndCompareBase64_A(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, + testsNoCR[i].base64, NULL, NULL); + encodeAndCompareBase64_A(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, + CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, testsNoCR[i].base64, + CERT_HEADER_NOCR, CERT_TRAILER_NOCR); + encodeAndCompareBase64_A(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, + CRYPT_STRING_BASE64REQUESTHEADER | CRYPT_STRING_NOCR, + testsNoCR[i].base64, CERT_REQUEST_HEADER_NOCR, + CERT_REQUEST_TRAILER_NOCR); + encodeAndCompareBase64_A(testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen, + CRYPT_STRING_BASE64X509CRLHEADER | CRYPT_STRING_NOCR, + testsNoCR[i].base64, X509_HEADER_NOCR, X509_TRAILER_NOCR); + } +} + +static void decodeAndCompareBase64_A(LPCSTR toDecode, LPCSTR header, + LPCSTR trailer, DWORD useFormat, DWORD expectedFormat, const BYTE *expected, + DWORD expectedLen) +{ + static const char garbage[] = "garbage\r\n"; + LPSTR str; + DWORD len = strlen(toDecode) + strlen(garbage) + 1; + + if (header) + len += strlen(header); + if (trailer) + len += strlen(trailer); + str = HeapAlloc(GetProcessHeap(), 0, len); + if (str) + { + LPBYTE buf; + DWORD bufLen = 0; + BOOL ret; + + if (header) + strcpy(str, header); + else + *str = 0; + strcat(str, toDecode); + if (trailer) + strcat(str, trailer); + ret = pCryptStringToBinaryA(str, 0, useFormat, NULL, &bufLen, NULL, + NULL); + ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError()); + buf = HeapAlloc(GetProcessHeap(), 0, bufLen); + if (buf) + { + DWORD skipped, usedFormat; + + /* check as normal, make sure last two parameters are optional */ + ret = pCryptStringToBinaryA(str, 0, useFormat, buf, &bufLen, NULL, + NULL); + ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError()); + ok(bufLen == expectedLen, + "Expected length %d, got %d\n", expectedLen, bufLen); + ok(!memcmp(buf, expected, bufLen), "Unexpected value\n"); + /* check last two params */ + ret = pCryptStringToBinaryA(str, 0, useFormat, buf, &bufLen, + &skipped, &usedFormat); + ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError()); + ok(skipped == 0, "Expected skipped 0, got %d\n", skipped); + ok(usedFormat == expectedFormat, "Expected format %d, got %d\n", + expectedFormat, usedFormat); + HeapFree(GetProcessHeap(), 0, buf); + } + + /* Check again, but with garbage up front */ + strcpy(str, garbage); + if (header) + strcat(str, header); + strcat(str, toDecode); + if (trailer) + strcat(str, trailer); + ret = pCryptStringToBinaryA(str, 0, useFormat, NULL, &bufLen, NULL, + NULL); + /* expect failure with no header, and success with one */ + if (header) + ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError()); + else + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected !ret and last error ERROR_INVALID_DATA, got ret=%d, error=%d\n", ret, GetLastError()); + if (ret) + { + buf = HeapAlloc(GetProcessHeap(), 0, bufLen); + if (buf) + { + DWORD skipped, usedFormat; + + ret = pCryptStringToBinaryA(str, 0, useFormat, buf, &bufLen, + &skipped, &usedFormat); + ok(skipped == strlen(garbage), + "Expected %d characters of \"%s\" skipped when trying format %08x, got %d (used format is %08x)\n", + lstrlenA(garbage), str, useFormat, skipped, usedFormat); + HeapFree(GetProcessHeap(), 0, buf); + } + } + HeapFree(GetProcessHeap(), 0, str); + } +} + +struct BadString +{ + const char *str; + DWORD format; +}; + +struct BadString badStrings[] = { + { "A\r\nA\r\n=\r\n=\r\n", CRYPT_STRING_BASE64 }, + { "AA\r\n=\r\n=\r\n", CRYPT_STRING_BASE64 }, + { "AA=\r\n=\r\n", CRYPT_STRING_BASE64 }, + { "-----BEGIN X509 CRL-----\r\nAA==\r\n", CRYPT_STRING_BASE64X509CRLHEADER }, +}; + +static void testStringToBinaryA(void) +{ + BOOL ret; + DWORD bufLen = 0, i; + + ret = pCryptStringToBinaryA(NULL, 0, 0, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ret = pCryptStringToBinaryA(NULL, 0, 0, NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Bogus format */ + ret = pCryptStringToBinaryA(tests[0].base64, 0, 0, NULL, &bufLen, NULL, + NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %d\n", GetLastError()); + /* Decoding doesn't expect the NOCR flag to be specified */ + ret = pCryptStringToBinaryA(tests[0].base64, 1, + CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %d\n", GetLastError()); + /* Bad strings */ + for (i = 0; i < sizeof(badStrings) / sizeof(badStrings[0]); i++) + { + bufLen = 0; + ret = pCryptStringToBinaryA(badStrings[i].str, 0, badStrings[i].format, + NULL, &bufLen, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %d\n", GetLastError()); + } + /* Good strings */ + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + { + bufLen = 0; + /* Bogus length--oddly enough, that succeeds, even though it's not + * properly padded. + */ + ret = pCryptStringToBinaryA(tests[i].base64, 1, CRYPT_STRING_BASE64, + NULL, &bufLen, NULL, NULL); + todo_wine ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError()); + /* Check with the precise format */ + decodeAndCompareBase64_A(tests[i].base64, NULL, NULL, + CRYPT_STRING_BASE64, CRYPT_STRING_BASE64, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_BASE64HEADER, CRYPT_STRING_BASE64HEADER, + tests[i].toEncode, tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER, + CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64REQUESTHEADER, + CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER, + CRYPT_STRING_BASE64X509CRLHEADER, CRYPT_STRING_BASE64X509CRLHEADER, + tests[i].toEncode, tests[i].toEncodeLen); + /* And check with the "any" formats */ + decodeAndCompareBase64_A(tests[i].base64, NULL, NULL, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64, tests[i].toEncode, + tests[i].toEncodeLen); + /* Don't check with no header and the string_any format, that'll + * always succeed. + */ + decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64HEADER, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_ANY, CRYPT_STRING_BASE64HEADER, tests[i].toEncode, + tests[i].toEncodeLen); + /* oddly, these seem to decode using the wrong format + decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER, + CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64_ANY, + CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, CERT_REQUEST_HEADER, + CERT_REQUEST_TRAILER, CRYPT_STRING_ANY, + CRYPT_STRING_BASE64REQUESTHEADER, tests[i].toEncode, + tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64X509CRLHEADER, + tests[i].toEncode, tests[i].toEncodeLen); + decodeAndCompareBase64_A(tests[i].base64, X509_HEADER, X509_TRAILER, + CRYPT_STRING_ANY, CRYPT_STRING_BASE64X509CRLHEADER, tests[i].toEncode, + tests[i].toEncodeLen); + */ + } + /* And again, with no CR--decoding handles this automatically */ + for (i = 0; i < sizeof(testsNoCR) / sizeof(testsNoCR[0]); i++) + { + bufLen = 0; + /* Bogus length--oddly enough, that succeeds, even though it's not + * properly padded. + */ + ret = pCryptStringToBinaryA(testsNoCR[i].base64, 1, CRYPT_STRING_BASE64, + NULL, &bufLen, NULL, NULL); + todo_wine ok(ret, "CryptStringToBinaryA failed: %d\n", GetLastError()); + /* Check with the precise format */ + decodeAndCompareBase64_A(testsNoCR[i].base64, NULL, NULL, + CRYPT_STRING_BASE64, CRYPT_STRING_BASE64, testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen); + decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_BASE64HEADER, CRYPT_STRING_BASE64HEADER, + testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen); + decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_REQUEST_HEADER, + CERT_REQUEST_TRAILER, CRYPT_STRING_BASE64REQUESTHEADER, + CRYPT_STRING_BASE64REQUESTHEADER, testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen); + decodeAndCompareBase64_A(testsNoCR[i].base64, X509_HEADER, X509_TRAILER, + CRYPT_STRING_BASE64X509CRLHEADER, CRYPT_STRING_BASE64X509CRLHEADER, + testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen); + /* And check with the "any" formats */ + decodeAndCompareBase64_A(testsNoCR[i].base64, NULL, NULL, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64, testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen); + /* Don't check with no header and the string_any format, that'll + * always succeed. + */ + decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_BASE64_ANY, CRYPT_STRING_BASE64HEADER, + testsNoCR[i].toEncode, testsNoCR[i].toEncodeLen); + decodeAndCompareBase64_A(testsNoCR[i].base64, CERT_HEADER, CERT_TRAILER, + CRYPT_STRING_ANY, CRYPT_STRING_BASE64HEADER, testsNoCR[i].toEncode, + testsNoCR[i].toEncodeLen); + } +} + +START_TEST(base64) +{ + HMODULE lib = GetModuleHandleA("crypt32"); + + pCryptBinaryToStringA = (CryptBinaryToStringAFunc)GetProcAddress(lib, + "CryptBinaryToStringA"); + pCryptStringToBinaryA = (CryptStringToBinaryAFunc)GetProcAddress(lib, + "CryptStringToBinaryA"); + + if (pCryptBinaryToStringA) + testBinaryToStringA(); + else + win_skip("CryptBinaryToStringA is not available\n"); + + if (pCryptStringToBinaryA) + testStringToBinaryA(); + else + win_skip("CryptStringToBinaryA is not available\n"); +} diff --git a/rostests/winetests/crypt32/cert.c b/rostests/winetests/crypt32/cert.c new file mode 100644 index 00000000000..0566797925b --- /dev/null +++ b/rostests/winetests/crypt32/cert.c @@ -0,0 +1,3645 @@ +/* + * crypt32 cert functions tests + * + * Copyright 2005-2006 Juan Lang + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static BOOL (WINAPI *pCertAddStoreToCollection)(HCERTSTORE,HCERTSTORE,DWORD,DWORD); +static PCCERT_CONTEXT (WINAPI *pCertCreateSelfSignCertificate)(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE,PCERT_NAME_BLOB,DWORD,PCRYPT_KEY_PROV_INFO,PCRYPT_ALGORITHM_IDENTIFIER,PSYSTEMTIME,PSYSTEMTIME,PCERT_EXTENSIONS); +static BOOL (WINAPI *pCertGetValidUsages)(DWORD,PCCERT_CONTEXT*,int*,LPSTR*,DWORD*); +static BOOL (WINAPI *pCryptAcquireCertificatePrivateKey)(PCCERT_CONTEXT,DWORD,void*,HCRYPTPROV_OR_NCRYPT_KEY_HANDLE*,DWORD*,BOOL*); +static BOOL (WINAPI *pCryptEncodeObjectEx)(DWORD,LPCSTR,const void*,DWORD,PCRYPT_ENCODE_PARA,void*,DWORD*); +static BOOL (WINAPI * pCryptVerifyCertificateSignatureEx) + (HCRYPTPROV, DWORD, DWORD, void *, DWORD, void *, DWORD, void *); + +static BOOL (WINAPI * pCryptAcquireContextA) + (HCRYPTPROV *, LPCSTR, LPCSTR, DWORD, DWORD); + +static void init_function_pointers(void) +{ + HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll"); + HMODULE hAdvapi32 = GetModuleHandleA("advapi32.dll"); + +#define GET_PROC(dll, func) \ + p ## func = (void *)GetProcAddress(dll, #func); \ + if(!p ## func) \ + trace("GetProcAddress(%s) failed\n", #func); + + GET_PROC(hCrypt32, CertAddStoreToCollection) + GET_PROC(hCrypt32, CertCreateSelfSignCertificate) + GET_PROC(hCrypt32, CertGetValidUsages) + GET_PROC(hCrypt32, CryptAcquireCertificatePrivateKey) + GET_PROC(hCrypt32, CryptEncodeObjectEx) + GET_PROC(hCrypt32, CryptVerifyCertificateSignatureEx) + + GET_PROC(hAdvapi32, CryptAcquireContextA) + +#undef GET_PROC +} + +static BYTE subjectName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, + 0x6e, 0x67, 0x00 }; +static BYTE serialNum[] = { 1 }; +static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static BYTE bigCertHash[] = { 0x6e, 0x30, 0x90, 0x71, 0x5f, 0xd9, 0x23, + 0x56, 0xeb, 0xae, 0x25, 0x40, 0xe6, 0x22, 0xda, 0x19, 0x26, 0x02, 0xa6, 0x08 }; + +static const BYTE bigCertWithDifferentSubject[] = { 0x30, 0x7a, 0x02, 0x01, 0x02, + 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, + 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, + 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, + 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, + 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x01 }; +static const BYTE bigCertWithDifferentIssuer[] = { 0x30, 0x7a, 0x02, 0x01, + 0x01, 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, + 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, + 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, + 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, + 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, + 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x01 }; + +static BYTE subjectName2[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, + 0x6e, 0x67, 0x00 }; +static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE bigCert2WithDifferentSerial[] = { 0x30, 0x7a, 0x02, 0x01, + 0x02, 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, + 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, + 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, + 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, + 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, + 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x01 }; +static BYTE bigCert2Hash[] = { 0x4a, 0x7f, 0x32, 0x1f, 0xcf, 0x3b, 0xc0, + 0x87, 0x48, 0x2b, 0xa1, 0x86, 0x54, 0x18, 0xe4, 0x3a, 0x0e, 0x53, 0x7e, 0x2b }; + +static const BYTE certWithUsage[] = { 0x30, 0x81, 0x93, 0x02, 0x01, 0x01, 0x30, + 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, + 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, + 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, + 0x03, 0x01, 0x00, 0xa3, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x1d, + 0x25, 0x01, 0x01, 0xff, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x03, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 }; + +static void testAddCert(void) +{ + HCERTSTORE store; + HCERTSTORE collection; + PCCERT_CONTEXT context; + PCCERT_CONTEXT copyContext; + BOOL ret; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store != NULL, "CertOpenStore failed: %d\n", GetLastError()); + if (!store) + return; + + /* Weird--bad add disposition leads to an access violation in Windows. + * Both tests crash on some win9x boxes. + */ + if (0) + { + ret = CertAddEncodedCertificateToStore(0, X509_ASN_ENCODING, bigCert, + sizeof(bigCert), 0, NULL); + ok(!ret && (GetLastError() == STATUS_ACCESS_VIOLATION || + GetLastError() == E_INVALIDARG), + "Expected STATUS_ACCESS_VIOLATION or E_INVALIDARG, got %08x\n", + GetLastError()); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), 0, NULL); + ok(!ret && (GetLastError() == STATUS_ACCESS_VIOLATION || + GetLastError() == E_INVALIDARG), + "Expected STATUS_ACCESS_VIOLATION or E_INVALIDARG, got %08x\n", + GetLastError()); + } + + /* Weird--can add a cert to the NULL store (does this have special + * meaning?) + */ + context = NULL; + ret = CertAddEncodedCertificateToStore(0, X509_ASN_ENCODING, bigCert, + sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* win98 */), + "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + if (context) + CertFreeCertificateContext(context); + if (!ret && GetLastError() == OSS_DATA_ERROR) + { + skip("bigCert can't be decoded, skipping tests\n"); + return; + } + + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + /* This has the same name as bigCert, so finding isn't done by name */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + ok(context != NULL, "Expected a context\n"); + if (context) + { + CRYPT_DATA_BLOB hash = { sizeof(bigCert2Hash), bigCert2Hash }; + + /* Duplicate (AddRef) the context so we can still use it after + * deleting it from the store. + */ + CertDuplicateCertificateContext(context); + CertDeleteCertificateFromStore(context); + /* Set the same hash as bigCert2, and try to readd it */ + ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, + 0, &hash); + ok(ret, "CertSetCertificateContextProperty failed: %08x\n", + GetLastError()); + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_NEW, NULL); + /* The failure is a bit odd (CRYPT_E_ASN1_BADTAG), so just check + * that it fails. + */ + ok(!ret, "Expected failure\n"); + CertFreeCertificateContext(context); + } + context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2, + sizeof(bigCert2)); + ok(context != NULL, "Expected a context\n"); + if (context) + { + /* Try to readd bigCert2 to the store */ + ret = CertAddCertificateContextToStore(store, context, + CERT_STORE_ADD_NEW, NULL); + ok(!ret && GetLastError() == CRYPT_E_EXISTS, + "Expected CRYPT_E_EXISTS, got %08x\n", GetLastError()); + CertFreeCertificateContext(context); + } + + /* Adding a cert with the same issuer name and serial number (but + * different subject) as an existing cert succeeds. + */ + context = NULL; + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert2WithDifferentSerial, sizeof(bigCert2WithDifferentSerial), + CERT_STORE_ADD_NEW, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + if (context) + CertDeleteCertificateFromStore(context); + + /* Adding a cert with the same subject name and serial number (but + * different issuer) as an existing cert succeeds. + */ + context = NULL; + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCertWithDifferentSubject, sizeof(bigCertWithDifferentSubject), + CERT_STORE_ADD_NEW, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + if (context) + CertDeleteCertificateFromStore(context); + + /* Adding a cert with the same issuer name and serial number (but + * different otherwise) as an existing cert succeeds. + */ + context = NULL; + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCertWithDifferentIssuer, sizeof(bigCertWithDifferentIssuer), + CERT_STORE_ADD_NEW, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + if (context) + CertDeleteCertificateFromStore(context); + + collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(collection != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (collection && pCertAddStoreToCollection) + { + /* Add store to the collection, but disable updates */ + pCertAddStoreToCollection(collection, store, 0, 0); + + context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2, + sizeof(bigCert2)); + ok(context != NULL, "Expected a context\n"); + if (context) + { + /* Try to readd bigCert2 to the collection */ + ret = CertAddCertificateContextToStore(collection, context, + CERT_STORE_ADD_NEW, NULL); + ok(!ret && GetLastError() == CRYPT_E_EXISTS, + "Expected CRYPT_E_EXISTS, got %08x\n", GetLastError()); + /* Replacing an existing certificate context is allowed, even + * though updates to the collection aren't.. + */ + ret = CertAddCertificateContextToStore(collection, context, + CERT_STORE_ADD_REPLACE_EXISTING, NULL); + ok(ret, "CertAddCertificateContextToStore failed: %08x\n", + GetLastError()); + /* use the existing certificate and ask for a copy of the context*/ + copyContext = NULL; + ret = CertAddCertificateContextToStore(collection, context, + CERT_STORE_ADD_USE_EXISTING, ©Context); + ok(ret, "CertAddCertificateContextToStore failed: %08x\n", + GetLastError()); + ok(copyContext != NULL, "Expected on output a non NULL copyContext\n"); + if (copyContext) + CertFreeCertificateContext(copyContext); + /* but adding a new certificate isn't allowed. */ + ret = CertAddCertificateContextToStore(collection, context, + CERT_STORE_ADD_ALWAYS, NULL); + ok(!ret && GetLastError() == E_ACCESSDENIED, + "Expected E_ACCESSDENIED, got %08x\n", GetLastError()); + CertFreeCertificateContext(context); + } + + CertCloseStore(collection, 0); + } + + CertCloseStore(store, 0); +} + +static void checkHash(const BYTE *data, DWORD dataLen, ALG_ID algID, + PCCERT_CONTEXT context, DWORD propID) +{ + BYTE hash[20] = { 0 }, hashProperty[20]; + BOOL ret; + DWORD size; + DWORD dwSizeWithNull; + + memset(hash, 0, sizeof(hash)); + memset(hashProperty, 0, sizeof(hashProperty)); + size = sizeof(hash); + ret = CryptHashCertificate(0, algID, 0, data, dataLen, hash, &size); + ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError()); + ret = CertGetCertificateContextProperty(context, propID, NULL, + &dwSizeWithNull); + ok(ret, "algID %08x, propID %d: CertGetCertificateContextProperty failed: %08x\n", + algID, propID, GetLastError()); + ret = CertGetCertificateContextProperty(context, propID, hashProperty, + &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + ok(!memcmp(hash, hashProperty, size), "Unexpected hash for property %d\n", + propID); + ok(size == dwSizeWithNull, "Unexpected length of hash for property: received %d instead of %d\n", + dwSizeWithNull,size); +} + +static CHAR cspNameA[] = "WineCryptTemp"; +static WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e','m','p',0 }; +static const BYTE v1CertWithPubKey[] = { +0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, +0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06, +0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02, +0x01,0x01 }; +static const BYTE v1CertWithSubjectKeyId[] = { +0x30,0x7b,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67, +0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x17,0x30,0x15,0x30, +0x13,0x06,0x03,0x55,0x1d,0x0e,0x04,0x0c,0x04,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00 }; +static const BYTE subjectKeyId[] = { +0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static const BYTE selfSignedCert[] = { + 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, + 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49, + 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, + 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30, + 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31, + 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, + 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, + 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4, + 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b, + 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0, + 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96, + 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, + 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41, + 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66, + 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a, + 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7, + 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f, + 0xa8, 0x76, 0x57, 0x92, 0x36 }; +static const BYTE selfSignedSignatureHash[] = { 0x07,0x5a,0x3e,0xfd,0x0d,0xf6, + 0x88,0xeb,0x00,0x64,0xbd,0xc9,0xd6,0xea,0x0a,0x7c,0xcc,0x24,0xdb,0x5d }; + +static void testCertProperties(void) +{ + PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING, + bigCert, sizeof(bigCert)); + DWORD propID, numProps, access, size; + BOOL ret; + BYTE hash[20] = { 0 }, hashProperty[20]; + CRYPT_DATA_BLOB blob; + CERT_KEY_CONTEXT keyContext; + + ok(context != NULL || broken(GetLastError() == OSS_DATA_ERROR /* win98 */), + "CertCreateCertificateContext failed: %08x\n", GetLastError()); + if (!context) + return; + + /* This crashes + propID = CertEnumCertificateContextProperties(NULL, 0); + */ + + propID = 0; + numProps = 0; + do { + propID = CertEnumCertificateContextProperties(context, propID); + if (propID) + numProps++; + } while (propID != 0); + ok(numProps == 0, "Expected 0 properties, got %d\n", numProps); + + /* Tests with a NULL cert context. Prop ID 0 fails.. */ + ret = CertSetCertificateContextProperty(NULL, 0, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* while this just crashes. + ret = CertSetCertificateContextProperty(NULL, + CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL); + */ + + ret = CertSetCertificateContextProperty(context, 0, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Can't set the cert property directly, this crashes. + ret = CertSetCertificateContextProperty(context, + CERT_CERT_PROP_ID, 0, bigCert2); + */ + + /* These all crash. + ret = CertGetCertificateContextProperty(context, + CERT_ACCESS_STATE_PROP_ID, 0, NULL); + ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, + NULL, NULL); + ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, + hashProperty, NULL); + */ + /* A missing prop */ + size = 0; + ret = CertGetCertificateContextProperty(context, + CERT_KEY_PROV_INFO_PROP_ID, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* And, an implicit property */ + size = sizeof(access); + ret = CertGetCertificateContextProperty(context, + CERT_ACCESS_STATE_PROP_ID, &access, &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG), + "Didn't expect a persisted cert\n"); + /* Trying to set this "read only" property crashes. + access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; + ret = CertSetCertificateContextProperty(context, + CERT_ACCESS_STATE_PROP_ID, 0, &access); + */ + + /* Can I set the hash to an invalid hash? */ + blob.pbData = hash; + blob.cbData = sizeof(hash); + ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0, + &blob); + ok(ret, "CertSetCertificateContextProperty failed: %08x\n", + GetLastError()); + size = sizeof(hashProperty); + ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, + hashProperty, &size); + ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n"); + /* Delete the (bogus) hash, and get the real one */ + ret = CertSetCertificateContextProperty(context, CERT_HASH_PROP_ID, 0, + NULL); + ok(ret, "CertSetCertificateContextProperty failed: %08x\n", + GetLastError()); + checkHash(bigCert, sizeof(bigCert), CALG_SHA1, context, + CERT_HASH_PROP_ID); + + /* Now that the hash property is set, we should get one property when + * enumerating. + */ + propID = 0; + numProps = 0; + do { + propID = CertEnumCertificateContextProperties(context, propID); + if (propID) + numProps++; + } while (propID != 0); + ok(numProps == 1, "Expected 1 properties, got %d\n", numProps); + + /* Check a few other implicit properties */ + checkHash(bigCert, sizeof(bigCert), CALG_MD5, context, + CERT_MD5_HASH_PROP_ID); + + /* Getting the signature hash fails with this bogus certificate */ + size = 0; + ret = CertGetCertificateContextProperty(context, + CERT_SIGNATURE_HASH_PROP_ID, NULL, &size); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == CRYPT_E_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR), /* win9x */ + "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); + + /* Test key contexts and handles and such */ + size = 0; + ret = CertGetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID, + NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + size = sizeof(CERT_KEY_CONTEXT); + ret = CertGetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID, + NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + ret = CertGetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID, + &keyContext, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* Key context with an invalid size */ + keyContext.cbSize = 0; + ret = CertSetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID, + 0, &keyContext); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + size = sizeof(keyContext); + ret = CertGetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID, + &keyContext, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + keyContext.cbSize = sizeof(keyContext); + keyContext.hCryptProv = 0; + keyContext.dwKeySpec = AT_SIGNATURE; + ret = CertSetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID, + 0, &keyContext); + ok(ret, "CertSetCertificateContextProperty failed: %08x\n", GetLastError()); + /* Now that that's set, the key prov handle property is also gettable. + */ + size = sizeof(keyContext.hCryptProv); + ret = CertGetCertificateContextProperty(context, + CERT_KEY_PROV_HANDLE_PROP_ID, &keyContext.hCryptProv, &size); + ok(ret, "Expected to get the CERT_KEY_PROV_HANDLE_PROP_ID, got %08x\n", + GetLastError()); + /* Remove the key prov handle property.. */ + ret = CertSetCertificateContextProperty(context, + CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL); + ok(ret, "CertSetCertificateContextProperty failed: %08x\n", + GetLastError()); + /* and the key context's CSP is set to NULL. */ + size = sizeof(keyContext); + ret = CertGetCertificateContextProperty(context, + CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + ok(keyContext.hCryptProv == 0, "Expected no hCryptProv\n"); + + /* According to MSDN the subject key id can be stored as a property, + * as a subject key extension, or as the SHA1 hash of the public key, + * but this cert has none of them: + */ + ret = CertGetCertificateContextProperty(context, + CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + CertFreeCertificateContext(context); + /* This cert does have a public key, but its subject key identifier still + * isn't available: */ + context = CertCreateCertificateContext(X509_ASN_ENCODING, + v1CertWithPubKey, sizeof(v1CertWithPubKey)); + ret = CertGetCertificateContextProperty(context, + CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_DATA, + "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + CertFreeCertificateContext(context); + /* This cert with a subject key extension can have its key identifier + * property retrieved: + */ + context = CertCreateCertificateContext(X509_ASN_ENCODING, + v1CertWithSubjectKeyId, sizeof(v1CertWithSubjectKeyId)); + ret = CertGetCertificateContextProperty(context, + CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", GetLastError()); + if (ret) + { + LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size); + + if (buf) + { + ret = CertGetCertificateContextProperty(context, + CERT_KEY_IDENTIFIER_PROP_ID, buf, &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + ok(!memcmp(buf, subjectKeyId, size), "Unexpected subject key id\n"); + HeapFree(GetProcessHeap(), 0, buf); + } + } + CertFreeCertificateContext(context); + + context = CertCreateCertificateContext(X509_ASN_ENCODING, + selfSignedCert, sizeof(selfSignedCert)); + /* Getting the signature hash of a valid (self-signed) cert succeeds */ + size = 0; + ret = CertGetCertificateContextProperty(context, + CERT_SIGNATURE_HASH_PROP_ID, NULL, &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", GetLastError()); + ok(size == sizeof(selfSignedSignatureHash), "unexpected size %d\n", size); + ret = CertGetCertificateContextProperty(context, + CERT_SIGNATURE_HASH_PROP_ID, hashProperty, &size); + if (ret) + ok(!memcmp(hashProperty, selfSignedSignatureHash, size), + "unexpected value\n"); + CertFreeCertificateContext(context); +} + +static void testDupCert(void) +{ + HCERTSTORE store; + PCCERT_CONTEXT context, dupContext; + BOOL ret; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store != NULL, "CertOpenStore failed: %d\n", GetLastError()); + if (!store) + return; + + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* win98 */), + "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + if (!ret && GetLastError() == OSS_DATA_ERROR) + { + skip("bigCert can't be decoded, skipping tests\n"); + return; + } + ok(context != NULL, "Expected a valid cert context\n"); + if (context) + { + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong cert size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)), + "Unexpected encoded cert in context\n"); + ok(context->hCertStore == store, "Unexpected store\n"); + + dupContext = CertDuplicateCertificateContext(context); + ok(dupContext != NULL, "Expected valid duplicate\n"); + /* Not only is it a duplicate, it's identical: the address is the + * same. + */ + ok(dupContext == context, "Expected identical context addresses\n"); + CertFreeCertificateContext(dupContext); + CertFreeCertificateContext(context); + } + CertCloseStore(store, 0); + + SetLastError(0xdeadbeef); + context = CertDuplicateCertificateContext(NULL); + ok(context == NULL, "Expected context to be NULL\n"); +} + +static BYTE subjectName3[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x52, 0x6f, 0x62, 0x20, 0x20, 0x4c, 0x61, + 0x6e, 0x67, 0x00 }; +static const BYTE iTunesCert0[] = { +0x30,0x82,0x03,0xc4,0x30,0x82,0x03,0x2d,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x47,0xbf,0x19,0x95,0xdf,0x8d,0x52,0x46,0x43,0xf7,0xdb,0x6d,0x48,0x0d,0x31, +0xa4,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x81,0x8b,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x5a,0x41,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x08,0x13,0x0c,0x57,0x65, +0x73,0x74,0x65,0x72,0x6e,0x20,0x43,0x61,0x70,0x65,0x31,0x14,0x30,0x12,0x06, +0x03,0x55,0x04,0x07,0x13,0x0b,0x44,0x75,0x72,0x62,0x61,0x6e,0x76,0x69,0x6c, +0x6c,0x65,0x31,0x0f,0x30,0x0d,0x06,0x03,0x55,0x04,0x0a,0x13,0x06,0x54,0x68, +0x61,0x77,0x74,0x65,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55,0x04,0x0b,0x13,0x14, +0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, +0x61,0x74,0x69,0x6f,0x6e,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13, +0x16,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x54,0x69,0x6d,0x65,0x73,0x74,0x61, +0x6d,0x70,0x69,0x6e,0x67,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x30,0x33,0x31, +0x32,0x30,0x34,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x31,0x33,0x31, +0x32,0x30,0x33,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x53,0x31,0x0b,0x30, +0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06, +0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x2c, +0x20,0x49,0x6e,0x63,0x2e,0x31,0x2b,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13, +0x22,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x54,0x69,0x6d,0x65,0x20, +0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x20,0x53,0x65,0x72,0x76,0x69,0x63, +0x65,0x73,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30, +0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0xca,0xb2,0xa4,0xcc,0xcd,0x20, +0xaf,0x0a,0x7d,0x89,0xac,0x87,0x75,0xf0,0xb4,0x4e,0xf1,0xdf,0xc1,0x0f,0xbf, +0x67,0x61,0xbd,0xa3,0x64,0x1c,0xda,0xbb,0xf9,0xca,0x33,0xab,0x84,0x30,0x89, +0x58,0x7e,0x8c,0xdb,0x6b,0xdd,0x36,0x9e,0x0f,0xbf,0xd1,0xec,0x78,0xf2,0x77, +0xa6,0x7e,0x6f,0x3c,0xbf,0x93,0xaf,0x0d,0xba,0x68,0xf4,0x6c,0x94,0xca,0xbd, +0x52,0x2d,0xab,0x48,0x3d,0xf5,0xb6,0xd5,0x5d,0x5f,0x1b,0x02,0x9f,0xfa,0x2f, +0x6b,0x1e,0xa4,0xf7,0xa3,0x9a,0xa6,0x1a,0xc8,0x02,0xe1,0x7f,0x4c,0x52,0xe3, +0x0e,0x60,0xec,0x40,0x1c,0x7e,0xb9,0x0d,0xde,0x3f,0xc7,0xb4,0xdf,0x87,0xbd, +0x5f,0x7a,0x6a,0x31,0x2e,0x03,0x99,0x81,0x13,0xa8,0x47,0x20,0xce,0x31,0x73, +0x0d,0x57,0x2d,0xcd,0x78,0x34,0x33,0x95,0x12,0x99,0x12,0xb9,0xde,0x68,0x2f, +0xaa,0xe6,0xe3,0xc2,0x8a,0x8c,0x2a,0xc3,0x8b,0x21,0x87,0x66,0xbd,0x83,0x58, +0x57,0x6f,0x75,0xbf,0x3c,0xaa,0x26,0x87,0x5d,0xca,0x10,0x15,0x3c,0x9f,0x84, +0xea,0x54,0xc1,0x0a,0x6e,0xc4,0xfe,0xc5,0x4a,0xdd,0xb9,0x07,0x11,0x97,0x22, +0x7c,0xdb,0x3e,0x27,0xd1,0x1e,0x78,0xec,0x9f,0x31,0xc9,0xf1,0xe6,0x22,0x19, +0xdb,0xc4,0xb3,0x47,0x43,0x9a,0x1a,0x5f,0xa0,0x1e,0x90,0xe4,0x5e,0xf5,0xee, +0x7c,0xf1,0x7d,0xab,0x62,0x01,0x8f,0xf5,0x4d,0x0b,0xde,0xd0,0x22,0x56,0xa8, +0x95,0xcd,0xae,0x88,0x76,0xae,0xee,0xba,0x0d,0xf3,0xe4,0x4d,0xd9,0xa0,0xfb, +0x68,0xa0,0xae,0x14,0x3b,0xb3,0x87,0xc1,0xbb,0x02,0x03,0x01,0x00,0x01,0xa3, +0x81,0xdb,0x30,0x81,0xd8,0x30,0x34,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07, +0x01,0x01,0x04,0x28,0x30,0x26,0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05, +0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73, +0x70,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x30, +0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01, +0xff,0x02,0x01,0x00,0x30,0x41,0x06,0x03,0x55,0x1d,0x1f,0x04,0x3a,0x30,0x38, +0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, +0x63,0x72,0x6c,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f, +0x6d,0x2f,0x54,0x68,0x61,0x77,0x74,0x65,0x54,0x69,0x6d,0x65,0x73,0x74,0x61, +0x6d,0x70,0x69,0x6e,0x67,0x43,0x41,0x2e,0x63,0x72,0x6c,0x30,0x13,0x06,0x03, +0x55,0x1d,0x25,0x04,0x0c,0x30,0x0a,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07, +0x03,0x08,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03, +0x02,0x01,0x06,0x30,0x24,0x06,0x03,0x55,0x1d,0x11,0x04,0x1d,0x30,0x1b,0xa4, +0x19,0x30,0x17,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x03,0x13,0x0c,0x54, +0x53,0x41,0x32,0x30,0x34,0x38,0x2d,0x31,0x2d,0x35,0x33,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00, +0x4a,0x6b,0xf9,0xea,0x58,0xc2,0x44,0x1c,0x31,0x89,0x79,0x99,0x2b,0x96,0xbf, +0x82,0xac,0x01,0xd6,0x1c,0x4c,0xcd,0xb0,0x8a,0x58,0x6e,0xdf,0x08,0x29,0xa3, +0x5e,0xc8,0xca,0x93,0x13,0xe7,0x04,0x52,0x0d,0xef,0x47,0x27,0x2f,0x00,0x38, +0xb0,0xe4,0xc9,0x93,0x4e,0x9a,0xd4,0x22,0x62,0x15,0xf7,0x3f,0x37,0x21,0x4f, +0x70,0x31,0x80,0xf1,0x8b,0x38,0x87,0xb3,0xe8,0xe8,0x97,0x00,0xfe,0xcf,0x55, +0x96,0x4e,0x24,0xd2,0xa9,0x27,0x4e,0x7a,0xae,0xb7,0x61,0x41,0xf3,0x2a,0xce, +0xe7,0xc9,0xd9,0x5e,0xdd,0xbb,0x2b,0x85,0x3e,0xb5,0x9d,0xb5,0xd9,0xe1,0x57, +0xff,0xbe,0xb4,0xc5,0x7e,0xf5,0xcf,0x0c,0x9e,0xf0,0x97,0xfe,0x2b,0xd3,0x3b, +0x52,0x1b,0x1b,0x38,0x27,0xf7,0x3f,0x4a }; +static const BYTE iTunesCert1[] = { +0x30,0x82,0x03,0xff,0x30,0x82,0x02,0xe7,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x0d,0xe9,0x2b,0xf0,0xd4,0xd8,0x29,0x88,0x18,0x32,0x05,0x09,0x5e,0x9a,0x76, +0x88,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72, +0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x2b,0x30,0x29, +0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e, +0x20,0x54,0x69,0x6d,0x65,0x20,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x20, +0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d, +0x30,0x33,0x31,0x32,0x30,0x34,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x30,0x38,0x31,0x32,0x30,0x33,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x57, +0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69, +0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x2f,0x30,0x2d,0x06,0x03,0x55, +0x04,0x03,0x13,0x26,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x54,0x69, +0x6d,0x65,0x20,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x20,0x53,0x65,0x72, +0x76,0x69,0x63,0x65,0x73,0x20,0x53,0x69,0x67,0x6e,0x65,0x72,0x30,0x82,0x01, +0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00, +0xb2,0x50,0x28,0x48,0xdd,0xd3,0x68,0x7a,0x84,0x18,0x44,0x66,0x75,0x5d,0x7e, +0xc4,0xb8,0x9f,0x63,0x26,0xff,0x3d,0x43,0x9c,0x7c,0x11,0x38,0x10,0x25,0x55, +0x73,0xd9,0x75,0x27,0x69,0xfd,0x4e,0xb9,0x20,0x5c,0xd3,0x0a,0xf9,0xa0,0x1b, +0x2a,0xed,0x55,0x56,0x21,0x61,0xd8,0x1e,0xdb,0xe4,0xbc,0x33,0x6b,0xc7,0xef, +0xdd,0xa3,0x37,0x65,0x8e,0x1b,0x93,0x0c,0xb6,0x53,0x1e,0x5c,0x7c,0x66,0x35, +0x5f,0x05,0x8a,0x45,0xfe,0x76,0x4e,0xdf,0x53,0x80,0xa2,0x81,0x20,0x9d,0xae, +0x88,0x5c,0xa2,0x08,0xf7,0xe5,0x30,0xf9,0xee,0x22,0x37,0x4c,0x42,0x0a,0xce, +0xdf,0xc6,0x1f,0xc4,0xd6,0x55,0xe9,0x81,0x3f,0xb5,0x52,0xa3,0x2c,0xaa,0x01, +0x7a,0xf2,0xa2,0xaa,0x8d,0x35,0xfe,0x9f,0xe6,0x5d,0x6a,0x05,0x9f,0x3d,0x6b, +0xe3,0xbf,0x96,0xc0,0xfe,0xcc,0x60,0xf9,0x40,0xe7,0x07,0xa0,0x44,0xeb,0x81, +0x51,0x6e,0xa5,0x2a,0xf2,0xb6,0x8a,0x10,0x28,0xed,0x8f,0xdc,0x06,0xa0,0x86, +0x50,0x9a,0x7b,0x4a,0x08,0x0d,0x30,0x1d,0xca,0x10,0x9e,0x6b,0xf7,0xe9,0x58, +0xae,0x04,0xa9,0x40,0x99,0xb2,0x28,0xe8,0x8f,0x16,0xac,0x3c,0xe3,0x53,0x6f, +0x4b,0xd3,0x35,0x9d,0xb5,0x6f,0x64,0x1d,0xb3,0x96,0x2c,0xbb,0x3d,0xe7,0x79, +0xeb,0x6d,0x7a,0xf9,0x16,0xe6,0x26,0xad,0xaf,0xef,0x99,0x53,0xb7,0x40,0x2c, +0x95,0xb8,0x79,0xaa,0xfe,0xd4,0x52,0xab,0x29,0x74,0x7e,0x42,0xec,0x39,0x1e, +0xa2,0x6a,0x16,0xe6,0x59,0xbb,0x24,0x68,0xd8,0x00,0x80,0x43,0x10,0x87,0x80, +0x6b,0x02,0x03,0x01,0x00,0x01,0xa3,0x81,0xca,0x30,0x81,0xc7,0x30,0x34,0x06, +0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x28,0x30,0x26,0x30,0x24, +0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74, +0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e,0x76,0x65,0x72,0x69,0x73,0x69, +0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01, +0xff,0x04,0x02,0x30,0x00,0x30,0x33,0x06,0x03,0x55,0x1d,0x1f,0x04,0x2c,0x30, +0x2a,0x30,0x28,0xa0,0x26,0xa0,0x24,0x86,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f, +0x2f,0x63,0x72,0x6c,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63, +0x6f,0x6d,0x2f,0x74,0x73,0x73,0x2d,0x63,0x61,0x2e,0x63,0x72,0x6c,0x30,0x16, +0x06,0x03,0x55,0x1d,0x25,0x01,0x01,0xff,0x04,0x0c,0x30,0x0a,0x06,0x08,0x2b, +0x06,0x01,0x05,0x05,0x07,0x03,0x08,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01, +0x01,0xff,0x04,0x04,0x03,0x02,0x06,0xc0,0x30,0x24,0x06,0x03,0x55,0x1d,0x11, +0x04,0x1d,0x30,0x1b,0xa4,0x19,0x30,0x17,0x31,0x15,0x30,0x13,0x06,0x03,0x55, +0x04,0x03,0x13,0x0c,0x54,0x53,0x41,0x32,0x30,0x34,0x38,0x2d,0x31,0x2d,0x35, +0x34,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x03,0x82,0x01,0x01,0x00,0x87,0x78,0x70,0xda,0x4e,0x52,0x01,0x20,0x5b, +0xe0,0x79,0xc9,0x82,0x30,0xc4,0xfd,0xb9,0x19,0x96,0xbd,0x91,0x00,0xc3,0xbd, +0xcd,0xcd,0xc6,0xf4,0x0e,0xd8,0xff,0xf9,0x4d,0xc0,0x33,0x62,0x30,0x11,0xc5, +0xf5,0x74,0x1b,0xd4,0x92,0xde,0x5f,0x9c,0x20,0x13,0xb1,0x7c,0x45,0xbe,0x50, +0xcd,0x83,0xe7,0x80,0x17,0x83,0xa7,0x27,0x93,0x67,0x13,0x46,0xfb,0xca,0xb8, +0x98,0x41,0x03,0xcc,0x9b,0x51,0x5b,0x05,0x8b,0x7f,0xa8,0x6f,0xf3,0x1b,0x50, +0x1b,0x24,0x2e,0xf2,0x69,0x8d,0x6c,0x22,0xf7,0xbb,0xca,0x16,0x95,0xed,0x0c, +0x74,0xc0,0x68,0x77,0xd9,0xeb,0x99,0x62,0x87,0xc1,0x73,0x90,0xf8,0x89,0x74, +0x7a,0x23,0xab,0xa3,0x98,0x7b,0x97,0xb1,0xf7,0x8f,0x29,0x71,0x4d,0x2e,0x75, +0x1b,0x48,0x41,0xda,0xf0,0xb5,0x0d,0x20,0x54,0xd6,0x77,0xa0,0x97,0x82,0x63, +0x69,0xfd,0x09,0xcf,0x8a,0xf0,0x75,0xbb,0x09,0x9b,0xd9,0xf9,0x11,0x55,0x26, +0x9a,0x61,0x32,0xbe,0x7a,0x02,0xb0,0x7b,0x86,0xbe,0xa2,0xc3,0x8b,0x22,0x2c, +0x78,0xd1,0x35,0x76,0xbc,0x92,0x73,0x5c,0xf9,0xb9,0xe6,0x4c,0x15,0x0a,0x23, +0xcc,0xe4,0xd2,0xd4,0x34,0x2e,0x49,0x40,0x15,0x3c,0x0f,0x60,0x7a,0x24,0xc6, +0xa5,0x66,0xef,0x96,0xcf,0x70,0xeb,0x3e,0xe7,0xf4,0x0d,0x7e,0xdc,0xd1,0x7c, +0xa3,0x76,0x71,0x69,0xc1,0x9c,0x4f,0x47,0x30,0x35,0x21,0xb1,0xa2,0xaf,0x1a, +0x62,0x3c,0x2b,0xd9,0x8e,0xaa,0x2a,0x07,0x7b,0xd8,0x18,0xb3,0x5c,0x7b,0xe2, +0x9d,0xa5,0x6f,0xfe,0x3c,0x89,0xad }; +static const BYTE iTunesCert2[] = { +0x30,0x82,0x04,0xbf,0x30,0x82,0x04,0x28,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x41,0x91,0xa1,0x5a,0x39,0x78,0xdf,0xcf,0x49,0x65,0x66,0x38,0x1d,0x4c,0x75, +0xc2,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x5f,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72, +0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x37,0x30,0x35, +0x06,0x03,0x55,0x04,0x0b,0x13,0x2e,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20, +0x50,0x75,0x62,0x6c,0x69,0x63,0x20,0x50,0x72,0x69,0x6d,0x61,0x72,0x79,0x20, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41, +0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x30,0x1e,0x17,0x0d,0x30,0x34,0x30, +0x37,0x31,0x36,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x31,0x34,0x30, +0x37,0x31,0x35,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xb4,0x31,0x0b, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15, +0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e, +0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x0b, +0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x54,0x72,0x75,0x73, +0x74,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x3b,0x30,0x39,0x06,0x03, +0x55,0x04,0x0b,0x13,0x32,0x54,0x65,0x72,0x6d,0x73,0x20,0x6f,0x66,0x20,0x75, +0x73,0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77, +0x77,0x77,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d, +0x2f,0x72,0x70,0x61,0x20,0x28,0x63,0x29,0x30,0x34,0x31,0x2e,0x30,0x2c,0x06, +0x03,0x55,0x04,0x03,0x13,0x25,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20, +0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x43,0x6f,0x64,0x65,0x20,0x53,0x69, +0x67,0x6e,0x69,0x6e,0x67,0x20,0x32,0x30,0x30,0x34,0x20,0x43,0x41,0x30,0x82, +0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, +0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01, +0x00,0xbe,0xbc,0xee,0xbc,0x7e,0xef,0x83,0xeb,0xe0,0x37,0x4f,0xfb,0x03,0x10, +0x38,0xbe,0x08,0xd2,0x8c,0x7d,0x9d,0xfa,0x92,0x7f,0x19,0x0c,0xc2,0x6b,0xee, +0x42,0x52,0x8c,0xde,0xd3,0x1c,0x48,0x13,0x25,0xea,0xc1,0x63,0x7a,0xf9,0x51, +0x65,0xee,0xd3,0xaa,0x3b,0xf5,0xf0,0x94,0x9c,0x2b,0xfb,0xf2,0x66,0xd4,0x24, +0xda,0xf7,0xf5,0x9f,0x6e,0x19,0x39,0x36,0xbc,0xd0,0xa3,0x76,0x08,0x1e,0x22, +0x27,0x24,0x6c,0x38,0x91,0x27,0xe2,0x84,0x49,0xae,0x1b,0x8a,0xa1,0xfd,0x25, +0x82,0x2c,0x10,0x30,0xe8,0x71,0xab,0x28,0xe8,0x77,0x4a,0x51,0xf1,0xec,0xcd, +0xf8,0xf0,0x54,0xd4,0x6f,0xc0,0xe3,0x6d,0x0a,0x8f,0xd9,0xd8,0x64,0x8d,0x63, +0xb2,0x2d,0x4e,0x27,0xf6,0x85,0x0e,0xfe,0x6d,0xe3,0x29,0x99,0xe2,0x85,0x47, +0x7c,0x2d,0x86,0x7f,0xe8,0x57,0x8f,0xad,0x67,0xc2,0x33,0x32,0x91,0x13,0x20, +0xfc,0xa9,0x23,0x14,0x9a,0x6d,0xc2,0x84,0x4b,0x76,0x68,0x04,0xd5,0x71,0x2c, +0x5d,0x21,0xfa,0x88,0x0d,0x26,0xfd,0x1f,0x2d,0x91,0x2b,0xe7,0x01,0x55,0x4d, +0xf2,0x6d,0x35,0x28,0x82,0xdf,0xd9,0x6b,0x5c,0xb6,0xd6,0xd9,0xaa,0x81,0xfd, +0x5f,0xcd,0x83,0xba,0x63,0x9d,0xd0,0x22,0xfc,0xa9,0x3b,0x42,0x69,0xb2,0x8e, +0x3a,0xb5,0xbc,0xb4,0x9e,0x0f,0x5e,0xc4,0xea,0x2c,0x82,0x8b,0x28,0xfd,0x53, +0x08,0x96,0xdd,0xb5,0x01,0x20,0xd1,0xf9,0xa5,0x18,0xe7,0xc0,0xee,0x51,0x70, +0x37,0xe1,0xb6,0x05,0x48,0x52,0x48,0x6f,0x38,0xea,0xc3,0xe8,0x6c,0x7b,0x44, +0x84,0xbb,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xa0,0x30,0x82,0x01,0x9c, +0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01, +0x01,0xff,0x02,0x01,0x00,0x30,0x44,0x06,0x03,0x55,0x1d,0x20,0x04,0x3d,0x30, +0x3b,0x30,0x39,0x06,0x0b,0x60,0x86,0x48,0x01,0x86,0xf8,0x45,0x01,0x07,0x17, +0x03,0x30,0x2a,0x30,0x28,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01, +0x16,0x1c,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76, +0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61, +0x30,0x31,0x06,0x03,0x55,0x1d,0x1f,0x04,0x2a,0x30,0x28,0x30,0x26,0xa0,0x24, +0xa0,0x22,0x86,0x20,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e, +0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x70,0x63, +0x61,0x33,0x2e,0x63,0x72,0x6c,0x30,0x1d,0x06,0x03,0x55,0x1d,0x25,0x04,0x16, +0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x08,0x2b, +0x06,0x01,0x05,0x05,0x07,0x03,0x03,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01, +0x01,0xff,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x11,0x06,0x09,0x60,0x86,0x48, +0x01,0x86,0xf8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x01,0x30,0x29,0x06, +0x03,0x55,0x1d,0x11,0x04,0x22,0x30,0x20,0xa4,0x1e,0x30,0x1c,0x31,0x1a,0x30, +0x18,0x06,0x03,0x55,0x04,0x03,0x13,0x11,0x43,0x6c,0x61,0x73,0x73,0x33,0x43, +0x41,0x32,0x30,0x34,0x38,0x2d,0x31,0x2d,0x34,0x33,0x30,0x1d,0x06,0x03,0x55, +0x1d,0x0e,0x04,0x16,0x04,0x14,0x08,0xf5,0x51,0xe8,0xfb,0xfe,0x3d,0x3d,0x64, +0x36,0x7c,0x68,0xcf,0x5b,0x78,0xa8,0xdf,0xb9,0xc5,0x37,0x30,0x81,0x80,0x06, +0x03,0x55,0x1d,0x23,0x04,0x79,0x30,0x77,0xa1,0x63,0xa4,0x61,0x30,0x5f,0x31, +0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30, +0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04, +0x0b,0x13,0x2e,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6c, +0x69,0x63,0x20,0x50,0x72,0x69,0x6d,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f, +0x72,0x69,0x74,0x79,0x82,0x10,0x70,0xba,0xe4,0x1d,0x10,0xd9,0x29,0x34,0xb6, +0x38,0xca,0x7b,0x03,0xcc,0xba,0xbf,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0xae,0x3a,0x17,0xb8, +0x4a,0x7b,0x55,0xfa,0x64,0x55,0xec,0x40,0xa4,0xed,0x49,0x41,0x90,0x99,0x9c, +0x89,0xbc,0xaf,0x2e,0x1d,0xca,0x78,0x23,0xf9,0x1c,0x19,0x0f,0x7f,0xeb,0x68, +0xbc,0x32,0xd9,0x88,0x38,0xde,0xdc,0x3f,0xd3,0x89,0xb4,0x3f,0xb1,0x82,0x96, +0xf1,0xa4,0x5a,0xba,0xed,0x2e,0x26,0xd3,0xde,0x7c,0x01,0x6e,0x00,0x0a,0x00, +0xa4,0x06,0x92,0x11,0x48,0x09,0x40,0xf9,0x1c,0x18,0x79,0x67,0x23,0x24,0xe0, +0xbb,0xd5,0xe1,0x50,0xae,0x1b,0xf5,0x0e,0xdd,0xe0,0x2e,0x81,0xcd,0x80,0xa3, +0x6c,0x52,0x4f,0x91,0x75,0x55,0x8a,0xba,0x22,0xf2,0xd2,0xea,0x41,0x75,0x88, +0x2f,0x63,0x55,0x7d,0x1e,0x54,0x5a,0x95,0x59,0xca,0xd9,0x34,0x81,0xc0,0x5f, +0x5e,0xf6,0x7a,0xb5 }; +static const BYTE iTunesCert3[] = { +0x30,0x82,0x04,0xf1,0x30,0x82,0x03,0xd9,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x0f,0x1a,0xa0,0xe0,0x9b,0x9b,0x61,0xa6,0xb6,0xfe,0x40,0xd2,0xdf,0x6a,0xf6, +0x8d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x81,0xb4,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65, +0x72,0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x1f,0x30, +0x1d,0x06,0x03,0x55,0x04,0x0b,0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b, +0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04,0x0b,0x13,0x32,0x54,0x65,0x72,0x6d, +0x73,0x20,0x6f,0x66,0x20,0x75,0x73,0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74, +0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76,0x65,0x72,0x69,0x73,0x69, +0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61,0x20,0x28,0x63,0x29,0x30, +0x34,0x31,0x2e,0x30,0x2c,0x06,0x03,0x55,0x04,0x03,0x13,0x25,0x56,0x65,0x72, +0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x43, +0x6f,0x64,0x65,0x20,0x53,0x69,0x67,0x6e,0x69,0x6e,0x67,0x20,0x32,0x30,0x30, +0x34,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x30,0x36,0x30,0x31,0x31,0x37,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x38,0x30,0x31,0x32,0x32,0x32, +0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xb4,0x31,0x0b,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04, +0x08,0x13,0x0a,0x43,0x61,0x6c,0x69,0x66,0x6f,0x72,0x6e,0x69,0x61,0x31,0x12, +0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13,0x09,0x43,0x75,0x70,0x65,0x72,0x74, +0x69,0x6e,0x6f,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55,0x04,0x0a,0x14,0x14,0x41, +0x70,0x70,0x6c,0x65,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x2c,0x20, +0x49,0x6e,0x63,0x2e,0x31,0x3e,0x30,0x3c,0x06,0x03,0x55,0x04,0x0b,0x13,0x35, +0x44,0x69,0x67,0x69,0x74,0x61,0x6c,0x20,0x49,0x44,0x20,0x43,0x6c,0x61,0x73, +0x73,0x20,0x33,0x20,0x2d,0x20,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74, +0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x56,0x61,0x6c,0x69,0x64, +0x61,0x74,0x69,0x6f,0x6e,0x20,0x76,0x32,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55, +0x04,0x03,0x14,0x14,0x41,0x70,0x70,0x6c,0x65,0x20,0x43,0x6f,0x6d,0x70,0x75, +0x74,0x65,0x72,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xd3,0xab,0x3b,0x7f,0xec,0x48,0x84, +0xce,0xa8,0x1a,0x12,0xf3,0x3c,0x87,0xcb,0x24,0x58,0x96,0x02,0x87,0x66,0x49, +0xeb,0x89,0xee,0x79,0x44,0x70,0x8d,0xe7,0xd4,0x1f,0x30,0x92,0xc0,0x9c,0x35, +0x78,0xc0,0xaf,0x1c,0xb6,0x28,0xd3,0xe0,0xe0,0x9d,0xd3,0x49,0x76,0x73,0x57, +0x19,0x4d,0x8d,0x70,0x85,0x64,0x4d,0x1d,0xc6,0x02,0x3e,0xe5,0x2c,0x66,0x07, +0xd2,0x27,0x4b,0xd6,0xc8,0x3c,0x93,0xb6,0x15,0x0c,0xde,0x5b,0xd7,0x93,0xdd, +0xbe,0x85,0x62,0x34,0x17,0x8a,0x05,0x60,0xf0,0x8a,0x1c,0x5a,0x40,0x21,0x8d, +0x51,0x6c,0xb0,0x62,0xd8,0xb5,0xd4,0xf9,0xb1,0xd0,0x58,0x7a,0x7a,0x82,0x55, +0xb3,0xf9,0x53,0x71,0xde,0xd2,0xc9,0x37,0x8c,0xf6,0x5a,0x1f,0x2d,0xcd,0x7c, +0x67,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0x7f,0x30,0x82,0x01,0x7b,0x30, +0x09,0x06,0x03,0x55,0x1d,0x13,0x04,0x02,0x30,0x00,0x30,0x0e,0x06,0x03,0x55, +0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x07,0x80,0x30,0x40,0x06,0x03, +0x55,0x1d,0x1f,0x04,0x39,0x30,0x37,0x30,0x35,0xa0,0x33,0xa0,0x31,0x86,0x2f, +0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30, +0x34,0x2d,0x63,0x72,0x6c,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e, +0x63,0x6f,0x6d,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2e,0x63, +0x72,0x6c,0x30,0x44,0x06,0x03,0x55,0x1d,0x20,0x04,0x3d,0x30,0x3b,0x30,0x39, +0x06,0x0b,0x60,0x86,0x48,0x01,0x86,0xf8,0x45,0x01,0x07,0x17,0x03,0x30,0x2a, +0x30,0x28,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1c,0x68, +0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76,0x65,0x72,0x69, +0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61,0x30,0x13,0x06, +0x03,0x55,0x1d,0x25,0x04,0x0c,0x30,0x0a,0x06,0x08,0x2b,0x06,0x01,0x05,0x05, +0x07,0x03,0x03,0x30,0x75,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01, +0x04,0x69,0x30,0x67,0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30, +0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e, +0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x30,0x3f,0x06, +0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x33,0x68,0x74,0x74,0x70, +0x3a,0x2f,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2d,0x61,0x69, +0x61,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f, +0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2d,0x61,0x69,0x61,0x2e,0x63, +0x65,0x72,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14, +0x08,0xf5,0x51,0xe8,0xfb,0xfe,0x3d,0x3d,0x64,0x36,0x7c,0x68,0xcf,0x5b,0x78, +0xa8,0xdf,0xb9,0xc5,0x37,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xf8, +0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x04,0x10,0x30,0x16,0x06,0x0a,0x2b,0x06, +0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x1b,0x04,0x08,0x30,0x06,0x01,0x01,0x00, +0x01,0x01,0xff,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x6a,0xa6,0x06,0xd0,0x33,0x18,0x64, +0xe2,0x69,0x82,0xee,0x6e,0x36,0x9e,0x9d,0x9a,0x0e,0x18,0xa8,0xac,0x9d,0x10, +0xed,0x01,0x3c,0xb9,0x61,0x04,0x62,0xf3,0x85,0x8f,0xcc,0x4f,0x2c,0x66,0x35, +0x54,0x25,0x45,0x8d,0x95,0x1c,0xd2,0x33,0xbe,0x2e,0xdd,0x7f,0x74,0xaf,0x03, +0x7b,0x86,0x63,0xb0,0xc9,0xe6,0xbd,0xc7,0x8e,0xde,0x03,0x18,0x98,0x82,0xc3, +0xbb,0xf8,0x15,0x99,0x1a,0xa9,0xdd,0xb9,0x5d,0xb9,0xbd,0x53,0x95,0x25,0x76, +0xfb,0x5c,0x53,0x90,0xea,0x01,0x0a,0xa0,0xb1,0xbf,0x09,0x1b,0x97,0x8f,0x40, +0xfa,0x85,0x12,0x74,0x01,0xdb,0xf6,0xdb,0x09,0xd6,0x5f,0x4f,0xd7,0x17,0xb4, +0xbf,0x9e,0x2f,0x86,0x52,0x5d,0x70,0x24,0x52,0x32,0x1e,0xa5,0x1d,0x39,0x8b, +0x66,0xf6,0xba,0x9b,0x69,0x8e,0x12,0x60,0xdb,0xb6,0xcf,0xe6,0x0d,0xd6,0x1c, +0x8f,0xd4,0x5b,0x4b,0x00,0xde,0x21,0x93,0xfb,0x6e,0xc7,0x3d,0xb4,0x66,0x0d, +0x29,0x0c,0x4e,0xe9,0x3f,0x94,0xd6,0xd6,0xdc,0xec,0xf8,0x53,0x3b,0x62,0xd5, +0x97,0x50,0x53,0x84,0x17,0xfe,0xe2,0xed,0x4c,0x23,0x0a,0x49,0xce,0x5b,0xe9, +0x70,0x31,0xc1,0x04,0x02,0x02,0x6c,0xb8,0x52,0xcd,0xc7,0x4e,0x70,0xb4,0x13, +0xd7,0xe0,0x92,0xba,0x44,0x1a,0x10,0x4c,0x6e,0x45,0xc6,0x86,0x04,0xc6,0x64, +0xd3,0x9c,0x6e,0xc1,0x9c,0xac,0x74,0x3d,0x77,0x06,0x5e,0x28,0x28,0x5c,0xf5, +0xe0,0x9c,0x19,0xd8,0xba,0x74,0x81,0x2d,0x67,0x77,0x93,0x8d,0xbf,0xd2,0x52, +0x00,0xe6,0xa5,0x38,0x4e,0x2e,0x73,0x66,0x7a }; +static BYTE iTunesIssuer[] = { +0x30,0x81,0xb4,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04, +0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x2c, +0x20,0x49,0x6e,0x63,0x2e,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55, +0x04,0x0b,0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e, +0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4e,0x65,0x74,0x77,0x6f, +0x72,0x6b,0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04,0x0b,0x13, +0x32,0x54,0x65,0x72,0x6d,0x73,0x20,0x6f,0x66,0x20,0x75,0x73, +0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f, +0x2f,0x77,0x77,0x77,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67, +0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61,0x20,0x28,0x63, +0x29,0x30,0x34,0x31,0x2e,0x30,0x2c,0x06,0x03,0x55,0x04,0x03, +0x13,0x25,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x43, +0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x43,0x6f,0x64,0x65,0x20, +0x53,0x69,0x67,0x6e,0x69,0x6e,0x67,0x20,0x32,0x30,0x30,0x34, +0x20,0x43,0x41 }; +static BYTE iTunesSerialNum[] = { +0x8d,0xf6,0x6a,0xdf,0xd2,0x40,0xfe,0xb6,0xa6,0x61,0x9b,0x9b, +0xe0,0xa0,0x1a,0x0f }; + +static void testFindCert(void) +{ + HCERTSTORE store; + PCCERT_CONTEXT context = NULL, subject; + BOOL ret; + CERT_INFO certInfo = { 0 }; + CRYPT_HASH_BLOB blob; + BYTE otherSerialNumber[] = { 2 }; + DWORD count; + static const WCHAR juan[] = { 'j','u','a','n',0 }; + static const WCHAR lang[] = { 'L','A','N','G',0 }; + static const WCHAR malcolm[] = { 'm','a','l','c','o','l','m',0 }; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store != NULL, "CertOpenStore failed: %d\n", GetLastError()); + if (!store) + return; + + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_NEW, NULL); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* win98 */), + "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + if (!ret && GetLastError() == OSS_DATA_ERROR) + { + skip("bigCert can't be decoded, skipping tests\n"); + return; + } + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + /* This has the same name as bigCert */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + + /* Crashes + context = CertFindCertificateInStore(NULL, 0, 0, 0, NULL, NULL); + */ + + /* Check first cert's there, by issuer */ + certInfo.Subject.pbData = subjectName; + certInfo.Subject.cbData = sizeof(subjectName); + certInfo.SerialNumber.pbData = serialNum; + certInfo.SerialNumber.cbData = sizeof(serialNum); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_NAME, &certInfo.Subject, NULL); + ok(context != NULL, "CertFindCertificateInStore failed: %08x\n", + GetLastError()); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_NAME, &certInfo.Subject, context); + ok(context != NULL, "Expected more than one cert\n"); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, + 0, CERT_FIND_ISSUER_NAME, &certInfo.Subject, context); + ok(context == NULL, "Expected precisely two certs\n"); + } + } + + /* Check second cert's there as well, by subject name */ + certInfo.Subject.pbData = subjectName2; + certInfo.Subject.cbData = sizeof(subjectName2); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_NAME, &certInfo.Subject, NULL); + ok(context != NULL, "CertFindCertificateInStore failed: %08x\n", + GetLastError()); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_NAME, &certInfo.Subject, context); + ok(context == NULL, "Expected one cert only\n"); + } + + /* Strange but true: searching for the subject cert requires you to set + * the issuer, not the subject + */ + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, NULL); + ok(context == NULL, "Expected no certificate\n"); + certInfo.Subject.pbData = NULL; + certInfo.Subject.cbData = 0; + certInfo.Issuer.pbData = subjectName2; + certInfo.Issuer.cbData = sizeof(subjectName2); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, NULL); + ok(context != NULL, "CertFindCertificateInStore failed: %08x\n", + GetLastError()); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, context); + ok(context == NULL, "Expected one cert only\n"); + } + /* A non-matching serial number will not match. */ + certInfo.SerialNumber.pbData = otherSerialNumber; + certInfo.SerialNumber.cbData = sizeof(otherSerialNumber); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, NULL); + ok(context == NULL, "Expected no match\n"); + /* No serial number will not match */ + certInfo.SerialNumber.cbData = 0; + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, NULL); + ok(context == NULL, "Expected no match\n"); + /* A serial number still won't match if the name doesn't */ + certInfo.SerialNumber.pbData = serialNum; + certInfo.SerialNumber.cbData = sizeof(serialNum); + certInfo.Issuer.pbData = subjectName3; + certInfo.Issuer.cbData = sizeof(subjectName3); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, NULL); + ok(context == NULL, "Expected no match\n"); + + /* The nice thing about hashes, they're unique */ + blob.pbData = bigCertHash; + blob.cbData = sizeof(bigCertHash); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SHA1_HASH, &blob, NULL); + ok(context != NULL, "CertFindCertificateInStore failed: %08x\n", + GetLastError()); + if (context) + { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SHA1_HASH, &certInfo.Subject, context); + ok(context == NULL, "Expected one cert only\n"); + } + + /* Searching for NULL string matches any context. */ + count = 0; + context = NULL; + do { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_STR, NULL, context); + if (context) + count++; + } while (context); + ok(count == 3, "expected 3 contexts\n"); + count = 0; + context = NULL; + do { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_STR, juan, context); + if (context) + count++; + } while (context); + ok(count == 2, "expected 2 contexts\n"); + count = 0; + context = NULL; + do { + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_STR, lang, context); + if (context) + count++; + } while (context); + ok(count == 3, "expected 3 contexts\n"); + SetLastError(0xdeadbeef); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_STR, malcolm, NULL); + ok(!context, "expected no certs\n"); + ok(GetLastError() == CRYPT_E_NOT_FOUND, + "expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + + CertCloseStore(store, 0); + + /* Another subject cert search, using iTunes's certs */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + iTunesCert0, sizeof(iTunesCert0), CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + iTunesCert1, sizeof(iTunesCert1), CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + iTunesCert2, sizeof(iTunesCert2), CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + iTunesCert3, sizeof(iTunesCert3), CERT_STORE_ADD_NEW, &subject); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + + /* The certInfo's issuer does not match any subject, but the serial + * number does match a cert whose issuer matches certInfo's issuer. + * This yields a match. + */ + certInfo.SerialNumber.cbData = sizeof(iTunesSerialNum); + certInfo.SerialNumber.pbData = iTunesSerialNum; + certInfo.Issuer.cbData = sizeof(iTunesIssuer); + certInfo.Issuer.pbData = iTunesIssuer; + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, NULL); + ok(context != NULL, "Expected a match\n"); + if (context) + { + ret = CertCompareCertificateName(context->dwCertEncodingType, + &certInfo.Issuer, &context->pCertInfo->Subject); + ok(!ret, "Expected subject name not to match\n"); + ret = CertCompareCertificateName(context->dwCertEncodingType, + &certInfo.Issuer, &context->pCertInfo->Issuer); + ok(ret, "Expected issuer name to match\n"); + ret = CertCompareIntegerBlob(&certInfo.SerialNumber, + &context->pCertInfo->SerialNumber); + ok(ret, "Expected serial number to match\n"); + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_SUBJECT_CERT, &certInfo, context); + ok(context == NULL, "Expected one cert only\n"); + } + + context = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_ISSUER_OF, subject, NULL); + ok(context != NULL, "Expected an issuer\n"); + if (context) + { + PCCERT_CONTEXT none = CertFindCertificateInStore(store, + X509_ASN_ENCODING, 0, CERT_FIND_ISSUER_OF, context, NULL); + + ok(!none, "Expected no parent of issuer\n"); + CertFreeCertificateContext(context); + } + CertFreeCertificateContext(subject); + CertCloseStore(store, 0); +} + +static void testGetSubjectCert(void) +{ + HCERTSTORE store; + PCCERT_CONTEXT context1, context2; + CERT_INFO info = { 0 }; + BOOL ret; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store != NULL, "CertOpenStore failed: %d\n", GetLastError()); + if (!store) + return; + + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* win98 */), + "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + if (!ret && GetLastError() == OSS_DATA_ERROR) + { + skip("bigCert can't be decoded, skipping tests\n"); + return; + } + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert2, sizeof(bigCert2), CERT_STORE_ADD_NEW, &context1); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + ok(context1 != NULL, "Expected a context\n"); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + certWithUsage, sizeof(certWithUsage), CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + + context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING, + NULL); + ok(!context2 && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING, + &info); + ok(!context2 && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + info.SerialNumber.cbData = sizeof(serialNum); + info.SerialNumber.pbData = serialNum; + context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING, + &info); + ok(!context2 && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + info.Issuer.cbData = sizeof(subjectName2); + info.Issuer.pbData = subjectName2; + context2 = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING, + &info); + ok(context2 != NULL, + "CertGetSubjectCertificateFromStore failed: %08x\n", GetLastError()); + /* Not only should this find a context, but it should be the same + * (same address) as context1. + */ + ok(context1 == context2, "Expected identical context addresses\n"); + CertFreeCertificateContext(context2); + + CertFreeCertificateContext(context1); + CertCloseStore(store, 0); +} + +/* This expires in 1970 or so */ +static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6, + 0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06, + 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40, + 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40, + 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, + 0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29, + 0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e, + 0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5, + 0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a, + 0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, + 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0, + 0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3, + 0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31, + 0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70, + 0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef, + 0x49, 0xe5, 0xf9, 0x65, 0xf3 }; + +/* This expires in 2036 or so */ +static const BYTE childOfExpired[] = { 0x30, 0x81, 0xcc, 0x30, 0x78, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, + 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, + 0x40, 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x35, 0x30, 0x35, + 0x31, 0x37, 0x31, 0x32, 0x34, 0x39, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x35, + 0x30, 0x35, 0x31, 0x37, 0x31, 0x32, 0x34, 0x39, 0x5a, 0x30, 0x15, 0x31, 0x13, + 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, + 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, + 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x20, 0x3b, 0xdb, 0x4d, 0x67, 0x50, + 0xec, 0x73, 0x9d, 0xf9, 0x85, 0x5d, 0x18, 0xe9, 0xb4, 0x98, 0xe3, 0x31, 0xb7, + 0x03, 0x0b, 0xc0, 0x39, 0x93, 0x56, 0x81, 0x0a, 0xfc, 0x78, 0xa8, 0x29, 0x42, + 0x5f, 0x69, 0xfb, 0xbc, 0x5b, 0xf2, 0xa6, 0x2a, 0xbe, 0x91, 0x2c, 0xfc, 0x89, + 0x69, 0x15, 0x18, 0x58, 0xe5, 0x02, 0x75, 0xf7, 0x2a, 0xb6, 0xa9, 0xfb, 0x47, + 0x6a, 0x6e, 0x0a, 0x9b, 0xe9, 0xdc }; +/* chain10_0 -+ + * +-> chain7_1 + * chain10_1 -+ + * A chain with two issuers, only one of whose dates is valid. + */ +static const BYTE chain10_0[] = { +0x30,0x82,0x01,0x9b,0x30,0x82,0x01,0x08,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x4a,0x30,0x3a,0x42,0xa2,0x5a,0xb3,0x93,0x4d,0x94,0x06,0xad,0x6d,0x1c,0x34, +0xe6,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x36,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x36,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81, +0x81,0x00,0x85,0x6e,0x35,0x2f,0x2c,0x51,0x4f,0xd6,0x2a,0xe4,0x9e,0xd0,0x4b, +0xe6,0x90,0xfd,0xf7,0x20,0xad,0x76,0x3f,0x93,0xea,0x7f,0x0d,0x1f,0xb3,0x8e, +0xfd,0xe0,0xe1,0xd6,0xd7,0x9c,0x7d,0x46,0x6b,0x15,0x5c,0xe6,0xc9,0x62,0x3b, +0x70,0x4a,0x4b,0xb2,0x82,0xe3,0x55,0x0c,0xc4,0x90,0x44,0x06,0x6c,0x86,0x1c, +0x6d,0x47,0x12,0xda,0x33,0x95,0x5d,0x98,0x43,0xcb,0x7c,0xfa,0x2b,0xee,0xc4, +0x2d,0xc8,0x95,0x33,0x89,0x08,0x3f,0x9f,0x87,0xea,0x20,0x04,0xaf,0x58,0x4b, +0x9d,0xc0,0x7c,0x0a,0x1b,0x05,0x31,0x3b,0xbb,0x13,0x58,0x2e,0x3f,0x61,0x6b, +0x10,0xb4,0xeb,0xb9,0x1a,0x30,0xfd,0xea,0xca,0x29,0x99,0x5f,0x42,0x2b,0x00, +0xb0,0x08,0xc3,0xf0,0xb6,0xd6,0x6b,0xf9,0x35,0x95 }; +static const BYTE chain10_1[] = { +0x30,0x82,0x01,0x9b,0x30,0x82,0x01,0x08,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0xbf,0x99,0x4f,0x14,0x03,0x77,0x44,0xb8,0x49,0x02,0x70,0xa1,0xb8,0x9c,0xa7, +0x24,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81, +0x81,0x00,0xa8,0xec,0x8c,0x34,0xe7,0x2c,0xdf,0x75,0x87,0xc4,0xf7,0xda,0x71, +0x72,0x29,0xb2,0x48,0xa8,0x2a,0xec,0x7b,0x7d,0x19,0xb9,0x5f,0x1d,0xd9,0x91, +0x2b,0xc4,0x28,0x7e,0xd6,0xb5,0x91,0x69,0xa5,0x8a,0x1a,0x1f,0x97,0x98,0x46, +0x9d,0xdf,0x12,0xf6,0x45,0x62,0xad,0x60,0xb6,0xba,0xb0,0xfd,0xf5,0x9f,0xc6, +0x98,0x05,0x4f,0x4d,0x48,0xdc,0xee,0x69,0xbe,0xb8,0xc4,0xc4,0xd7,0x1b,0xb1, +0x1f,0x64,0xd6,0x45,0xa7,0xdb,0xb3,0x87,0x63,0x0f,0x54,0xe1,0x3a,0x6b,0x57, +0x36,0xd7,0x68,0x65,0xcf,0xda,0x57,0x8d,0xcd,0x84,0x75,0x47,0x26,0x2c,0xef, +0x1e,0x8f,0xc7,0x3b,0xee,0x5d,0x03,0xa6,0xdf,0x3a,0x20,0xb2,0xcc,0xc9,0x09, +0x2c,0xfe,0x2b,0x79,0xb0,0xca,0x2c,0x9a,0x81,0x6b }; +static const BYTE chain7_1[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x9f,0x69,0xfd,0x26,0xd5,0x4b, +0xe0,0xab,0x12,0x21,0xb9,0xfc,0xf7,0xe0,0x0c,0x09,0x94,0xad,0x27,0xd7,0x9d, +0xa3,0xcc,0x46,0x2a,0x25,0x9a,0x24,0xa7,0x31,0x58,0x78,0xf5,0xfc,0x30,0xe1, +0x6d,0xfd,0x59,0xab,0xbe,0x69,0xa0,0xea,0xe3,0x7d,0x7a,0x7b,0xe5,0x85,0xeb, +0x86,0x6a,0x84,0x3c,0x96,0x01,0x1a,0x70,0xa7,0xb8,0xcb,0xf2,0x11,0xe7,0x52, +0x9c,0x58,0x2d,0xac,0x63,0xce,0x72,0x4b,0xad,0x62,0xa8,0x1d,0x75,0x96,0xe2, +0x27,0xf5,0x6f,0xba,0x91,0xf8,0xf1,0xb0,0xbf,0x90,0x24,0x6d,0xba,0x5d,0xd7, +0x39,0x63,0x3b,0x7c,0x04,0x5d,0x89,0x9d,0x1c,0xf2,0xf7,0xcc,0xdf,0x6e,0x8a, +0x43,0xa9,0xdd,0x86,0x05,0xa2,0xf3,0x22,0x2d,0x1e,0x70,0xa1,0x59,0xd7,0xa5, +0x94,0x7d }; + +static void testGetIssuerCert(void) +{ + BOOL ret; + PCCERT_CONTEXT parent, child, cert1, cert2; + DWORD flags = 0xffffffff; + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + expiredCert, sizeof(expiredCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + childOfExpired, sizeof(childOfExpired), CERT_STORE_ADD_ALWAYS, &child); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + + /* These crash: + parent = CertGetIssuerCertificateFromStore(NULL, NULL, NULL, NULL); + parent = CertGetIssuerCertificateFromStore(store, NULL, NULL, NULL); + */ + parent = CertGetIssuerCertificateFromStore(NULL, NULL, NULL, &flags); + ok(!parent && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + parent = CertGetIssuerCertificateFromStore(store, NULL, NULL, &flags); + ok(!parent && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(!parent && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Confusing: the caller cannot set either of the + * CERT_STORE_NO_*_FLAGs, as these are not checks, + * they're results: + */ + flags = CERT_STORE_NO_CRL_FLAG | CERT_STORE_NO_ISSUER_FLAG; + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(!parent && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Perform no checks */ + flags = 0; + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08x\n", + GetLastError()); + if (parent) + CertFreeCertificateContext(parent); + /* Check revocation and signature only */ + flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG; + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(parent != NULL, "CertGetIssuerCertificateFromStore failed: %08x\n", + GetLastError()); + /* Confusing: CERT_STORE_REVOCATION_FLAG succeeds when there is no CRL by + * setting CERT_STORE_NO_CRL_FLAG. + */ + ok(flags == (CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG), + "Expected CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG, got %08x\n", + flags); + if (parent) + CertFreeCertificateContext(parent); + /* Checking time validity is not productive, because while most Windows + * versions return 0 (time valid) because the child is not expired, + * Windows 2003 SP1 returns that it is expired. Thus the range of + * possibilities is covered, and a test verifies nothing. + */ + + CertFreeCertificateContext(child); + CertCloseStore(store, 0); + + flags = 0; + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* With only the child certificate, no issuer will be found */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + chain7_1, sizeof(chain7_1), CERT_STORE_ADD_ALWAYS, &child); + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(parent == NULL, "Expected no issuer\n"); + /* Adding an issuer allows one (and only one) issuer to be found */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + chain10_1, sizeof(chain10_1), CERT_STORE_ADD_ALWAYS, &cert1); + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(parent == cert1, "Expected cert1 to be the issuer\n"); + parent = CertGetIssuerCertificateFromStore(store, child, parent, &flags); + ok(parent == NULL, "Expected only one issuer\n"); + /* Adding a second issuer allows two issuers to be found - and the second + * issuer is found before the first, implying certs are added to the head + * of a list. + */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + chain10_0, sizeof(chain10_0), CERT_STORE_ADD_ALWAYS, &cert2); + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(parent == cert2, "Expected cert2 to be the first issuer\n"); + parent = CertGetIssuerCertificateFromStore(store, child, parent, &flags); + ok(parent == cert1, "Expected cert1 to be the second issuer\n"); + parent = CertGetIssuerCertificateFromStore(store, child, parent, &flags); + ok(parent == NULL, "Expected no more than two issuers\n"); + CertFreeCertificateContext(child); + CertFreeCertificateContext(cert1); + CertFreeCertificateContext(cert2); + CertCloseStore(store, 0); + + /* Repeat the test, reversing the order in which issuers are added, + * to show it's order-dependent. + */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* With only the child certificate, no issuer will be found */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + chain7_1, sizeof(chain7_1), CERT_STORE_ADD_ALWAYS, &child); + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(parent == NULL, "Expected no issuer\n"); + /* Adding an issuer allows one (and only one) issuer to be found */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + chain10_0, sizeof(chain10_0), CERT_STORE_ADD_ALWAYS, &cert1); + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(parent == cert1, "Expected cert1 to be the issuer\n"); + parent = CertGetIssuerCertificateFromStore(store, child, parent, &flags); + ok(parent == NULL, "Expected only one issuer\n"); + /* Adding a second issuer allows two issuers to be found - and the second + * issuer is found before the first, implying certs are added to the head + * of a list. + */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + chain10_1, sizeof(chain10_1), CERT_STORE_ADD_ALWAYS, &cert2); + parent = CertGetIssuerCertificateFromStore(store, child, NULL, &flags); + ok(parent == cert2, "Expected cert2 to be the first issuer\n"); + parent = CertGetIssuerCertificateFromStore(store, child, parent, &flags); + ok(parent == cert1, "Expected cert1 to be the second issuer\n"); + parent = CertGetIssuerCertificateFromStore(store, child, parent, &flags); + ok(parent == NULL, "Expected no more than two issuers\n"); + CertFreeCertificateContext(child); + CertFreeCertificateContext(cert1); + CertFreeCertificateContext(cert2); + CertCloseStore(store, 0); +} + +static void testCryptHashCert(void) +{ + static const BYTE emptyHash[] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, + 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, + 0x09 }; + static const BYTE knownHash[] = { 0xae, 0x9d, 0xbf, 0x6d, 0xf5, 0x46, 0xee, + 0x8b, 0xc5, 0x7a, 0x13, 0xba, 0xc2, 0xb1, 0x04, 0xf2, 0xbf, 0x52, 0xa8, + 0xa2 }; + static const BYTE toHash[] = "abcdefghijklmnopqrstuvwxyz0123456789.,;!?:"; + BOOL ret; + BYTE hash[20]; + DWORD hashLen = sizeof(hash); + + /* NULL buffer and nonzero length crashes + ret = CryptHashCertificate(0, 0, 0, NULL, size, hash, &hashLen); + empty hash length also crashes + ret = CryptHashCertificate(0, 0, 0, buf, size, hash, NULL); + */ + /* Test empty hash */ + ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), NULL, + &hashLen); + ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError()); + ok(hashLen == sizeof(hash), "Got unexpected size of hash %d\n", hashLen); + /* Test with empty buffer */ + ret = CryptHashCertificate(0, 0, 0, NULL, 0, hash, &hashLen); + ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError()); + ok(!memcmp(hash, emptyHash, sizeof(emptyHash)), + "Unexpected hash of nothing\n"); + /* Test a known value */ + ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), hash, + &hashLen); + ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError()); + ok(!memcmp(hash, knownHash, sizeof(knownHash)), "Unexpected hash\n"); +} + +static void verifySig(HCRYPTPROV csp, const BYTE *toSign, size_t toSignLen, + const BYTE *sig, unsigned int sigLen) +{ + HCRYPTHASH hash; + BOOL ret = CryptCreateHash(csp, CALG_SHA1, 0, 0, &hash); + + ok(ret, "CryptCreateHash failed: %08x\n", GetLastError()); + if (ret) + { + BYTE mySig[64]; + DWORD mySigSize = sizeof(mySig); + + ret = CryptHashData(hash, toSign, toSignLen, 0); + ok(ret, "CryptHashData failed: %08x\n", GetLastError()); + /* use the A variant so the test can run on Win9x */ + ret = CryptSignHashA(hash, AT_SIGNATURE, NULL, 0, mySig, &mySigSize); + ok(ret, "CryptSignHash failed: %08x\n", GetLastError()); + if (ret) + { + ok(mySigSize == sigLen, "Expected sig length %d, got %d\n", + sigLen, mySigSize); + ok(!memcmp(mySig, sig, sigLen), "Unexpected signature\n"); + } + CryptDestroyHash(hash); + } +} + +/* Tests signing the certificate described by toBeSigned with the CSP passed in, + * using the algorithm with OID sigOID. The CSP is assumed to be empty, and a + * keyset named AT_SIGNATURE will be added to it. The signing key will be + * stored in *key, and the signature will be stored in sig. sigLen should be + * at least 64 bytes. + */ +static void testSignCert(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned, + LPCSTR sigOID, HCRYPTKEY *key, BYTE *sig, DWORD *sigLen) +{ + BOOL ret; + DWORD size = 0; + CRYPT_ALGORITHM_IDENTIFIER algoID = { NULL, { 0, NULL } }; + + /* These all crash + ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, &size); + ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData, + NULL, NULL, NULL, &size); + */ + ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData, + &algoID, NULL, NULL, &size); + ok(!ret && GetLastError() == NTE_BAD_ALGID, + "Expected NTE_BAD_ALGID, got %08x\n", GetLastError()); + algoID.pszObjId = (LPSTR)sigOID; + ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData, + &algoID, NULL, NULL, &size); + ok(!ret && + (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == NTE_BAD_ALGID), + "Expected ERROR_INVALID_PARAMETER or NTE_BAD_ALGID, got %08x\n", + GetLastError()); + ret = CryptSignCertificate(0, AT_SIGNATURE, 0, toBeSigned->pbData, + toBeSigned->cbData, &algoID, NULL, NULL, &size); + ok(!ret && + (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == NTE_BAD_ALGID), + "Expected ERROR_INVALID_PARAMETER or NTE_BAD_ALGID, got %08x\n", + GetLastError()); + + /* No keys exist in the new CSP yet.. */ + ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData, + toBeSigned->cbData, &algoID, NULL, NULL, &size); + ok(!ret && (GetLastError() == NTE_BAD_KEYSET || GetLastError() == + NTE_NO_KEY), "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %08x\n", + GetLastError()); + ret = CryptGenKey(csp, AT_SIGNATURE, 0, key); + ok(ret, "CryptGenKey failed: %08x\n", GetLastError()); + if (ret) + { + ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData, + toBeSigned->cbData, &algoID, NULL, NULL, &size); + ok(ret, "CryptSignCertificate failed: %08x\n", GetLastError()); + ok(size <= *sigLen, "Expected size <= %d, got %d\n", *sigLen, size); + if (ret) + { + ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData, + toBeSigned->cbData, &algoID, NULL, sig, &size); + ok(ret, "CryptSignCertificate failed: %08x\n", GetLastError()); + if (ret) + { + *sigLen = size; + verifySig(csp, toBeSigned->pbData, toBeSigned->cbData, sig, + size); + } + } + } +} + +static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned, + LPCSTR sigOID, const BYTE *sig, DWORD sigLen) +{ + CERT_SIGNED_CONTENT_INFO info; + LPBYTE cert = NULL; + DWORD size = 0; + BOOL ret; + + if (!pCryptVerifyCertificateSignatureEx) + { + win_skip("no CryptVerifyCertificateSignatureEx support\n"); + return; + } + if (!pCryptEncodeObjectEx) + { + win_skip("no CryptEncodeObjectEx support\n"); + return; + } + ret = pCryptVerifyCertificateSignatureEx(0, 0, 0, NULL, 0, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = pCryptVerifyCertificateSignatureEx(csp, 0, 0, NULL, 0, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, 0, NULL, 0, + NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* This crashes + ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, NULL, 0, NULL, 0, NULL); + */ + info.ToBeSigned.cbData = toBeSigned->cbData; + info.ToBeSigned.pbData = toBeSigned->pbData; + info.SignatureAlgorithm.pszObjId = (LPSTR)sigOID; + info.SignatureAlgorithm.Parameters.cbData = 0; + info.Signature.cbData = sigLen; + info.Signature.pbData = (BYTE *)sig; + info.Signature.cUnusedBits = 0; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &cert, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (cert) + { + CRYPT_DATA_BLOB certBlob = { 0, NULL }; + PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL; + + ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL); + ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD, + "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); + certBlob.cbData = 1; + certBlob.pbData = (void *)0xdeadbeef; + ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL); + ok(!ret && (GetLastError() == STATUS_ACCESS_VIOLATION || + GetLastError() == CRYPT_E_ASN1_EOD /* Win9x */ || + GetLastError() == CRYPT_E_ASN1_BADTAG /* Win98 */), + "Expected STATUS_ACCESS_VIOLATION, CRYPT_E_ASN1_EOD, OR CRYPT_E_ASN1_BADTAG, got %08x\n", + GetLastError()); + + certBlob.cbData = size; + certBlob.pbData = cert; + ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, + CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* This crashes + ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, + CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, NULL, 0, NULL); + */ + CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, + (LPSTR)sigOID, 0, NULL, NULL, &size); + pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size); + if (pubKeyInfo) + { + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, + X509_ASN_ENCODING, (LPSTR)sigOID, 0, NULL, pubKeyInfo, &size); + ok(ret, "CryptExportKey failed: %08x\n", GetLastError()); + if (ret) + { + ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, + CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, + CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pubKeyInfo, 0, NULL); + ok(ret, "CryptVerifyCertificateSignatureEx failed: %08x\n", + GetLastError()); + } + HeapFree(GetProcessHeap(), 0, pubKeyInfo); + } + LocalFree(cert); + } +} + +static BYTE emptyCert[] = { 0x30, 0x00 }; + +static void testCertSigs(void) +{ + HCRYPTPROV csp; + CRYPT_DATA_BLOB toBeSigned = { sizeof(emptyCert), emptyCert }; + BOOL ret; + HCRYPTKEY key; + BYTE sig[64]; + DWORD sigSize = sizeof(sig); + + /* Just in case a previous run failed, delete this thing */ + pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + ret = pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_NEWKEYSET); + ok(ret, "CryptAcquireContext failed: %08x\n", GetLastError()); + + testSignCert(csp, &toBeSigned, szOID_RSA_SHA1RSA, &key, sig, &sigSize); + testVerifyCertSig(csp, &toBeSigned, szOID_RSA_SHA1RSA, sig, sigSize); + + CryptDestroyKey(key); + CryptReleaseContext(csp, 0); + ret = pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); +} + +static const BYTE md5SignedEmptyCert[] = { +0x30,0x56,0x30,0x33,0x02,0x00,0x30,0x02,0x06,0x00,0x30,0x22,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31, +0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x07, +0x30,0x02,0x06,0x00,0x03,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x02,0x05,0x05,0x00,0x03,0x11,0x00,0xfb,0x0f,0x66,0x82,0x66,0xd9,0xe5,0xf8, +0xd8,0xa2,0x55,0x2b,0xe1,0xa5,0xd9,0x04 }; +static const BYTE md5SignedEmptyCertNoNull[] = { +0x30,0x54,0x30,0x33,0x02,0x00,0x30,0x02,0x06,0x00,0x30,0x22,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31, +0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x07, +0x30,0x02,0x06,0x00,0x03,0x01,0x00,0x30,0x0a,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x02,0x05,0x03,0x11,0x00,0x04,0xd9,0xa5,0xe1,0x2b,0x55,0xa2,0xd8,0xf8,0xe5, +0xd9,0x66,0x82,0x66,0x0f,0xfb }; + +static void testSignAndEncodeCert(void) +{ + static char oid_rsa_md5rsa[] = szOID_RSA_MD5RSA; + static char oid_rsa_md5[] = szOID_RSA_MD5; + BOOL ret; + DWORD size; + CRYPT_ALGORITHM_IDENTIFIER algID = { 0 }; + CERT_INFO info = { 0 }; + + /* Crash + ret = CryptSignAndEncodeCertificate(0, 0, 0, NULL, NULL, NULL, NULL, NULL, + NULL); + ret = CryptSignAndEncodeCertificate(0, 0, 0, NULL, NULL, NULL, NULL, NULL, + &size); + */ + ret = CryptSignAndEncodeCertificate(0, 0, 0, NULL, NULL, &algID, NULL, NULL, + &size); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING, NULL, NULL, + &algID, NULL, NULL, &size); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = CryptSignAndEncodeCertificate(0, 0, 0, X509_CERT_TO_BE_SIGNED, NULL, + &algID, NULL, NULL, &size); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* Crashes on some win9x boxes */ + if (0) + { + ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING, + X509_CERT_TO_BE_SIGNED, NULL, &algID, NULL, NULL, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* Crashes + ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING, + X509_CERT_TO_BE_SIGNED, &info, NULL, NULL, NULL, &size); + */ + ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING, + X509_CERT_TO_BE_SIGNED, &info, &algID, NULL, NULL, &size); + ok(!ret && + (GetLastError() == NTE_BAD_ALGID || + GetLastError() == OSS_BAD_PTR), /* win9x */ + "Expected NTE_BAD_ALGID, got %08x\n", GetLastError()); + algID.pszObjId = oid_rsa_md5rsa; + ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING, + X509_CERT_TO_BE_SIGNED, &info, &algID, NULL, NULL, &size); + ok(!ret && + (GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == NTE_BAD_ALGID || + GetLastError() == OSS_BAD_PTR), /* Win9x */ + "Expected ERROR_INVALID_PARAMETER or NTE_BAD_ALGID, got %08x\n", + GetLastError()); + algID.pszObjId = oid_rsa_md5; + ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING, + X509_CERT_TO_BE_SIGNED, &info, &algID, NULL, NULL, &size); + /* oid_rsa_md5 not present in some win2k */ + if (ret) + { + LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size); + + if (buf) + { + ret = CryptSignAndEncodeCertificate(0, 0, X509_ASN_ENCODING, + X509_CERT_TO_BE_SIGNED, &info, &algID, NULL, buf, &size); + ok(ret, "CryptSignAndEncodeCertificate failed: %08x\n", + GetLastError()); + /* Tricky: because the NULL parameters may either be omitted or + * included as an asn.1-encoded NULL (0x05,0x00), two different + * values are allowed. + */ + ok(size == sizeof(md5SignedEmptyCert) || + size == sizeof(md5SignedEmptyCertNoNull), "Unexpected size %d\n", + size); + if (size == sizeof(md5SignedEmptyCert)) + ok(!memcmp(buf, md5SignedEmptyCert, size), + "Unexpected value\n"); + else if (size == sizeof(md5SignedEmptyCertNoNull)) + ok(!memcmp(buf, md5SignedEmptyCertNoNull, size), + "Unexpected value\n"); + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +static void testCreateSelfSignCert(void) +{ + PCCERT_CONTEXT context; + CERT_NAME_BLOB name = { sizeof(subjectName), subjectName }; + HCRYPTPROV csp; + BOOL ret; + HCRYPTKEY key; + CRYPT_KEY_PROV_INFO info; + + if (!pCertCreateSelfSignCertificate) + { + win_skip("CertCreateSelfSignCertificate() is not available\n"); + return; + } + + /* This crashes: + context = pCertCreateSelfSignCertificate(0, NULL, 0, NULL, NULL, NULL, NULL, + NULL); + * Calling this with no first parameter creates a new key container, which + * lasts beyond the test, so I don't test that. Nb: the generated key + * name is a GUID. + context = pCertCreateSelfSignCertificate(0, &name, 0, NULL, NULL, NULL, NULL, + NULL); + */ + + /* Acquire a CSP */ + pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + ret = pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_NEWKEYSET); + ok(ret, "CryptAcquireContext failed: %08x\n", GetLastError()); + + context = pCertCreateSelfSignCertificate(csp, &name, 0, NULL, NULL, NULL, + NULL, NULL); + ok(!context && GetLastError() == NTE_NO_KEY, + "Expected NTE_NO_KEY, got %08x\n", GetLastError()); + ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key); + ok(ret, "CryptGenKey failed: %08x\n", GetLastError()); + if (ret) + { + context = pCertCreateSelfSignCertificate(csp, &name, 0, NULL, NULL, NULL, + NULL, NULL); + ok(context != NULL, "CertCreateSelfSignCertificate failed: %08x\n", + GetLastError()); + if (context) + { + DWORD size = 0; + PCRYPT_KEY_PROV_INFO info; + + /* The context must have a key provider info property */ + ret = CertGetCertificateContextProperty(context, + CERT_KEY_PROV_INFO_PROP_ID, NULL, &size); + ok(ret && size, "Expected non-zero key provider info\n"); + if (size) + { + info = HeapAlloc(GetProcessHeap(), 0, size); + if (info) + { + ret = CertGetCertificateContextProperty(context, + CERT_KEY_PROV_INFO_PROP_ID, info, &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + if (ret) + { + /* Sanity-check the key provider */ + ok(!lstrcmpW(info->pwszContainerName, cspNameW), + "Unexpected key container\n"); + ok(!lstrcmpW(info->pwszProvName, MS_DEF_PROV_W), + "Unexpected provider\n"); + ok(info->dwKeySpec == AT_SIGNATURE, + "Expected AT_SIGNATURE, got %d\n", info->dwKeySpec); + } + HeapFree(GetProcessHeap(), 0, info); + } + } + + CertFreeCertificateContext(context); + } + + CryptDestroyKey(key); + } + + CryptReleaseContext(csp, 0); + ret = pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + + /* do the same test with AT_KEYEXCHANGE and key info*/ + memset(&info,0,sizeof(info)); + info.dwProvType = PROV_RSA_FULL; + info.dwKeySpec = AT_KEYEXCHANGE; + info.pwszProvName = (LPWSTR) MS_DEF_PROV_W; + info.pwszContainerName = cspNameW; + context = pCertCreateSelfSignCertificate(0, &name, 0, &info, NULL, NULL, + NULL, NULL); + ok(context != NULL, "CertCreateSelfSignCertificate failed: %08x\n", + GetLastError()); + if (context) + { + DWORD size = 0; + PCRYPT_KEY_PROV_INFO info; + + /* The context must have a key provider info property */ + ret = CertGetCertificateContextProperty(context, + CERT_KEY_PROV_INFO_PROP_ID, NULL, &size); + ok(ret && size, "Expected non-zero key provider info\n"); + if (size) + { + info = HeapAlloc(GetProcessHeap(), 0, size); + if (info) + { + ret = CertGetCertificateContextProperty(context, + CERT_KEY_PROV_INFO_PROP_ID, info, &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + if (ret) + { + /* Sanity-check the key provider */ + ok(!lstrcmpW(info->pwszContainerName, cspNameW), + "Unexpected key container\n"); + ok(!lstrcmpW(info->pwszProvName, MS_DEF_PROV_W), + "Unexpected provider\n"); + ok(info->dwKeySpec == AT_KEYEXCHANGE, + "Expected AT_KEYEXCHANGE, got %d\n", info->dwKeySpec); + } + HeapFree(GetProcessHeap(), 0, info); + } + } + + CertFreeCertificateContext(context); + } + + pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); +} + +static void testIntendedKeyUsage(void) +{ + BOOL ret; + CERT_INFO info = { 0 }; + static char oid_key_usage[] = szOID_KEY_USAGE; + /* A couple "key usages". Really they're just encoded bits which aren't + * necessarily restricted to the defined key usage values. + */ + static BYTE usage1[] = { 0x03,0x03,0x00,0xff,0xff }; + static BYTE usage2[] = { 0x03,0x03,0x01,0xff,0xfe }; + static const BYTE expected_usage1[] = { 0xff,0xff,0x00,0x00 }; + static const BYTE expected_usage2[] = { 0xff,0xfe,0x00,0x00 }; + CERT_EXTENSION ext = { oid_key_usage, TRUE, { sizeof(usage1), usage1 } }; + BYTE usage_bytes[4]; + + if (0) + { + /* Crash */ + ret = CertGetIntendedKeyUsage(0, NULL, NULL, 0); + } + ret = CertGetIntendedKeyUsage(0, &info, NULL, 0); + ok(!ret, "expected failure\n"); + ret = CertGetIntendedKeyUsage(0, &info, usage_bytes, sizeof(usage_bytes)); + ok(!ret, "expected failure\n"); + ret = CertGetIntendedKeyUsage(X509_ASN_ENCODING, &info, NULL, 0); + ok(!ret, "expected failure\n"); + ret = CertGetIntendedKeyUsage(X509_ASN_ENCODING, &info, usage_bytes, + sizeof(usage_bytes)); + info.cExtension = 1; + info.rgExtension = &ext; + ret = CertGetIntendedKeyUsage(X509_ASN_ENCODING, &info, NULL, 0); + ok(!ret, "expected failure\n"); + /* The unused bytes are filled with 0. */ + ret = CertGetIntendedKeyUsage(X509_ASN_ENCODING, &info, usage_bytes, + sizeof(usage_bytes)); + ok(ret, "CertGetIntendedKeyUsage failed: %08x\n", GetLastError()); + ok(!memcmp(usage_bytes, expected_usage1, sizeof(expected_usage1)), + "unexpected value\n"); + /* The usage bytes are copied in big-endian order. */ + ext.Value.cbData = sizeof(usage2); + ext.Value.pbData = usage2; + ret = CertGetIntendedKeyUsage(X509_ASN_ENCODING, &info, usage_bytes, + sizeof(usage_bytes)); + ok(ret, "CertGetIntendedKeyUsage failed: %08x\n", GetLastError()); + ok(!memcmp(usage_bytes, expected_usage2, sizeof(expected_usage2)), + "unexpected value\n"); +} + +static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING, + szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA }; + +static void testKeyUsage(void) +{ + BOOL ret; + PCCERT_CONTEXT context; + DWORD size; + + /* Test base cases */ + ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + size = 1; + ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + size = 0; + ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + /* These crash + ret = CertSetEnhancedKeyUsage(NULL, NULL); + usage.cUsageIdentifier = 0; + ret = CertSetEnhancedKeyUsage(NULL, &usage); + */ + /* Test with a cert with no enhanced key usage extension */ + context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + ok(context != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + if (context) + { + static const char oid[] = "1.2.3.4"; + BYTE buf[sizeof(CERT_ENHKEY_USAGE) + 2 * (sizeof(LPSTR) + sizeof(oid))]; + PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf; + + ret = CertGetEnhancedKeyUsage(context, 0, NULL, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + size = 1; + ret = CertGetEnhancedKeyUsage(context, 0, NULL, &size); + if (ret) + { + /* Windows 2000, ME, or later: even though it succeeded, we expect + * CRYPT_E_NOT_FOUND, which indicates there is no enhanced key + * usage set for this cert (which implies it's valid for all uses.) + */ + ok(GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + ok(size == sizeof(CERT_ENHKEY_USAGE), "Wrong size %d\n", size); + ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size); + ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %d\n", + pUsage->cUsageIdentifier); + } + else + { + /* Windows NT, 95, or 98: it fails, and the last error is + * CRYPT_E_NOT_FOUND. + */ + ok(GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + } + /* I can add a usage identifier when no key usage has been set */ + ret = CertAddEnhancedKeyUsageIdentifier(context, oid); + ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08x\n", + GetLastError()); + size = sizeof(buf); + ret = CertGetEnhancedKeyUsage(context, + CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size); + ok(ret && GetLastError() == 0, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %d\n", + pUsage->cUsageIdentifier); + if (pUsage->cUsageIdentifier) + ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid), + "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]); + /* Now set an empty key usage */ + pUsage->cUsageIdentifier = 0; + ret = CertSetEnhancedKeyUsage(context, pUsage); + ok(ret, "CertSetEnhancedKeyUsage failed: %08x\n", GetLastError()); + /* Shouldn't find it in the cert */ + size = sizeof(buf); + ret = CertGetEnhancedKeyUsage(context, + CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* Should find it as an extended property */ + ret = CertGetEnhancedKeyUsage(context, + CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size); + ok(ret && GetLastError() == 0, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %d\n", + pUsage->cUsageIdentifier); + /* Should find it as either */ + ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size); + ok(ret && GetLastError() == 0, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %d\n", + pUsage->cUsageIdentifier); + /* Add a usage identifier */ + ret = CertAddEnhancedKeyUsageIdentifier(context, oid); + ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08x\n", + GetLastError()); + size = sizeof(buf); + ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size); + ok(ret && GetLastError() == 0, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 1, "Expected 1 identifier, got %d\n", + pUsage->cUsageIdentifier); + if (pUsage->cUsageIdentifier) + ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid), + "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]); + /* Re-adding the same usage identifier succeeds, though it only adds + * a duplicate usage identifier on versions prior to Vista + */ + ret = CertAddEnhancedKeyUsageIdentifier(context, oid); + ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08x\n", + GetLastError()); + size = sizeof(buf); + ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size); + ok(ret && GetLastError() == 0, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 1 || pUsage->cUsageIdentifier == 2, + "Expected 1 or 2 identifiers, got %d\n", pUsage->cUsageIdentifier); + if (pUsage->cUsageIdentifier) + ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid), + "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]); + if (pUsage->cUsageIdentifier >= 2) + ok(!strcmp(pUsage->rgpszUsageIdentifier[1], oid), + "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[1]); + /* Now set a NULL extended property--this deletes the property. */ + ret = CertSetEnhancedKeyUsage(context, NULL); + ok(ret, "CertSetEnhancedKeyUsage failed: %08x\n", GetLastError()); + SetLastError(0xbaadcafe); + size = sizeof(buf); + ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size); + ok(GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + + CertFreeCertificateContext(context); + } + /* Now test with a cert with an enhanced key usage extension */ + context = CertCreateCertificateContext(X509_ASN_ENCODING, certWithUsage, + sizeof(certWithUsage)); + ok(context != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + if (context) + { + LPBYTE buf = NULL; + DWORD bufSize = 0, i; + + /* The size may depend on what flags are used to query it, so I + * realloc the buffer for each test. + */ + ret = CertGetEnhancedKeyUsage(context, + CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize); + ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + buf = HeapAlloc(GetProcessHeap(), 0, bufSize); + if (buf) + { + PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf; + + /* Should find it in the cert */ + size = bufSize; + ret = CertGetEnhancedKeyUsage(context, + CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size); + ok(ret && GetLastError() == 0, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %d\n", + pUsage->cUsageIdentifier); + for (i = 0; i < pUsage->cUsageIdentifier; i++) + ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]), + "Expected %s, got %s\n", keyUsages[i], + pUsage->rgpszUsageIdentifier[i]); + HeapFree(GetProcessHeap(), 0, buf); + } + ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize); + ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + buf = HeapAlloc(GetProcessHeap(), 0, bufSize); + if (buf) + { + PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf; + + /* Should find it as either */ + size = bufSize; + ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size); + /* In Windows, GetLastError returns CRYPT_E_NOT_FOUND not found + * here, even though the return is successful and the usage id + * count is positive. I don't enforce that here. + */ + ok(ret, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %d\n", + pUsage->cUsageIdentifier); + for (i = 0; i < pUsage->cUsageIdentifier; i++) + ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]), + "Expected %s, got %s\n", keyUsages[i], + pUsage->rgpszUsageIdentifier[i]); + HeapFree(GetProcessHeap(), 0, buf); + } + /* Shouldn't find it as an extended property */ + ret = CertGetEnhancedKeyUsage(context, + CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* Adding a usage identifier overrides the cert's usage!? */ + ret = CertAddEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA); + ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08x\n", + GetLastError()); + ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize); + ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + buf = HeapAlloc(GetProcessHeap(), 0, bufSize); + if (buf) + { + PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf; + + /* Should find it as either */ + size = bufSize; + ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size); + ok(ret, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %d\n", + pUsage->cUsageIdentifier); + ok(!strcmp(pUsage->rgpszUsageIdentifier[0], szOID_RSA_RSA), + "Expected %s, got %s\n", szOID_RSA_RSA, + pUsage->rgpszUsageIdentifier[0]); + HeapFree(GetProcessHeap(), 0, buf); + } + /* But querying the cert directly returns its usage */ + ret = CertGetEnhancedKeyUsage(context, + CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize); + ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + buf = HeapAlloc(GetProcessHeap(), 0, bufSize); + if (buf) + { + PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf; + + size = bufSize; + ret = CertGetEnhancedKeyUsage(context, + CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size); + ok(ret, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %d\n", + pUsage->cUsageIdentifier); + for (i = 0; i < pUsage->cUsageIdentifier; i++) + ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]), + "Expected %s, got %s\n", keyUsages[i], + pUsage->rgpszUsageIdentifier[i]); + HeapFree(GetProcessHeap(), 0, buf); + } + /* And removing the only usage identifier in the extended property + * results in the cert's key usage being found. + */ + ret = CertRemoveEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA); + ok(ret, "CertRemoveEnhancedKeyUsage failed: %08x\n", GetLastError()); + ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize); + ok(ret, "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + buf = HeapAlloc(GetProcessHeap(), 0, bufSize); + if (buf) + { + PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf; + + /* Should find it as either */ + size = bufSize; + ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size); + ok(ret, + "CertGetEnhancedKeyUsage failed: %08x\n", GetLastError()); + ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %d\n", + pUsage->cUsageIdentifier); + for (i = 0; i < pUsage->cUsageIdentifier; i++) + ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]), + "Expected %s, got %s\n", keyUsages[i], + pUsage->rgpszUsageIdentifier[i]); + HeapFree(GetProcessHeap(), 0, buf); + } + + CertFreeCertificateContext(context); + } +} + +static const BYTE cert2WithUsage[] = { +0x30,0x81,0x89,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x25,0x30,0x23, +0x30,0x21,0x06,0x03,0x55,0x1d,0x25,0x01,0x01,0xff,0x04,0x17,0x30,0x15,0x06, +0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x01 }; + +static void testGetValidUsages(void) +{ + static const LPCSTR expectedOIDs[] = { + "1.3.6.1.5.5.7.3.3", + "1.3.6.1.5.5.7.3.2", + "1.2.840.113549.1.1.1", + }; + static const LPCSTR expectedOIDs2[] = { + "1.3.6.1.5.5.7.3.2", + "1.2.840.113549.1.1.1", + }; + BOOL ret; + int numOIDs; + DWORD size; + LPSTR *oids = NULL; + PCCERT_CONTEXT contexts[3]; + + if (!pCertGetValidUsages) + { + win_skip("CertGetValidUsages() is not available\n"); + return; + } + + /* Crash + ret = pCertGetValidUsages(0, NULL, NULL, NULL, NULL); + ret = pCertGetValidUsages(0, NULL, NULL, NULL, &size); + */ + contexts[0] = NULL; + numOIDs = size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pCertGetValidUsages(1, &contexts[0], &numOIDs, NULL, &size); + ok(ret, "CertGetValidUsages failed: %d\n", GetLastError()); + ok(numOIDs == -1, "Expected -1, got %d\n", numOIDs); + ok(size == 0, "Expected size 0, got %d\n", size); + contexts[0] = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + contexts[1] = CertCreateCertificateContext(X509_ASN_ENCODING, certWithUsage, + sizeof(certWithUsage)); + contexts[2] = CertCreateCertificateContext(X509_ASN_ENCODING, + cert2WithUsage, sizeof(cert2WithUsage)); + numOIDs = size = 0xdeadbeef; + ret = pCertGetValidUsages(0, NULL, &numOIDs, NULL, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + ok(numOIDs == -1, "Expected -1, got %d\n", numOIDs); + ok(size == 0, "Expected size 0, got %d\n", size); + numOIDs = size = 0xdeadbeef; + ret = pCertGetValidUsages(1, contexts, &numOIDs, NULL, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + ok(numOIDs == -1, "Expected -1, got %d\n", numOIDs); + ok(size == 0, "Expected size 0, got %d\n", size); + ret = pCertGetValidUsages(1, &contexts[1], &numOIDs, NULL, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + ok(numOIDs == 3, "Expected 3, got %d\n", numOIDs); + ok(size, "Expected non-zero size\n"); + oids = HeapAlloc(GetProcessHeap(), 0, size); + if (oids) + { + int i; + DWORD smallSize = 1; + + SetLastError(0xdeadbeef); + ret = pCertGetValidUsages(1, &contexts[1], &numOIDs, oids, &smallSize); + ok(!ret && GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + ret = pCertGetValidUsages(1, &contexts[1], &numOIDs, oids, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + for (i = 0; i < numOIDs; i++) + ok(!lstrcmpA(oids[i], expectedOIDs[i]), "unexpected OID %s\n", + oids[i]); + HeapFree(GetProcessHeap(), 0, oids); + } + numOIDs = size = 0xdeadbeef; + /* Oddly enough, this crashes when the number of contexts is not 1: + ret = pCertGetValidUsages(2, contexts, &numOIDs, NULL, &size); + * but setting size to 0 allows it to succeed: + */ + size = 0; + ret = pCertGetValidUsages(2, contexts, &numOIDs, NULL, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + ok(numOIDs == 3, "Expected 3, got %d\n", numOIDs); + ok(size, "Expected non-zero size\n"); + oids = HeapAlloc(GetProcessHeap(), 0, size); + if (oids) + { + int i; + + ret = pCertGetValidUsages(1, &contexts[1], &numOIDs, oids, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + for (i = 0; i < numOIDs; i++) + ok(!lstrcmpA(oids[i], expectedOIDs[i]), "unexpected OID %s\n", + oids[i]); + HeapFree(GetProcessHeap(), 0, oids); + } + numOIDs = 0xdeadbeef; + size = 0; + ret = pCertGetValidUsages(1, &contexts[2], &numOIDs, NULL, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + ok(numOIDs == 2, "Expected 2, got %d\n", numOIDs); + ok(size, "Expected non-zero size\n"); + oids = HeapAlloc(GetProcessHeap(), 0, size); + if (oids) + { + int i; + + ret = pCertGetValidUsages(1, &contexts[2], &numOIDs, oids, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + for (i = 0; i < numOIDs; i++) + ok(!lstrcmpA(oids[i], expectedOIDs2[i]), "unexpected OID %s\n", + oids[i]); + HeapFree(GetProcessHeap(), 0, oids); + } + numOIDs = 0xdeadbeef; + size = 0; + ret = pCertGetValidUsages(3, contexts, &numOIDs, NULL, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + ok(numOIDs == 2, "Expected 2, got %d\n", numOIDs); + ok(size, "Expected non-zero size\n"); + oids = HeapAlloc(GetProcessHeap(), 0, size); + if (oids) + { + int i; + + ret = pCertGetValidUsages(3, contexts, &numOIDs, oids, &size); + ok(ret, "CertGetValidUsages failed: %08x\n", GetLastError()); + for (i = 0; i < numOIDs; i++) + ok(!lstrcmpA(oids[i], expectedOIDs2[i]), "unexpected OID %s\n", + oids[i]); + HeapFree(GetProcessHeap(), 0, oids); + } + CertFreeCertificateContext(contexts[0]); + CertFreeCertificateContext(contexts[1]); + CertFreeCertificateContext(contexts[2]); +} + +static BYTE cn[] = { +0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67 }; +static BYTE cnWithLeadingSpace[] = { +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x20,0x4a, +0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67 }; +static BYTE cnWithTrailingSpace[] = { +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x20 }; +static BYTE cnWithIntermediateSpace[] = { +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x20,0x4c,0x61,0x6e,0x67 }; +static BYTE cnThenO[] = { +0x30,0x2d,0x31,0x2b,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x30,0x17,0x06,0x03,0x55,0x04,0x0a,0x13, +0x10,0x54,0x68,0x65,0x20,0x57,0x69,0x6e,0x65,0x20,0x50,0x72,0x6f,0x6a,0x65, +0x63,0x74 }; +static BYTE oThenCN[] = { +0x30,0x2d,0x31,0x2b,0x30,0x10,0x06,0x03,0x55,0x04,0x0a,0x13,0x09,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x30,0x17,0x06,0x03,0x55,0x04,0x03,0x13, +0x10,0x54,0x68,0x65,0x20,0x57,0x69,0x6e,0x65,0x20,0x50,0x72,0x6f,0x6a,0x65, +0x63,0x74 }; + +static void testCompareCertName(void) +{ + static BYTE bogus[] = { 1, 2, 3, 4 }; + static BYTE bogusPrime[] = { 0, 1, 2, 3, 4 }; + static BYTE emptyPrime[] = { 0x30, 0x00, 0x01 }; + BOOL ret; + CERT_NAME_BLOB blob1, blob2; + + /* crashes + ret = CertCompareCertificateName(0, NULL, NULL); + */ + /* An empty name checks against itself.. */ + blob1.pbData = emptyCert; + blob1.cbData = sizeof(emptyCert); + ret = CertCompareCertificateName(0, &blob1, &blob1); + ok(ret, "CertCompareCertificateName failed: %08x\n", GetLastError()); + /* It doesn't have to be a valid encoded name.. */ + blob1.pbData = bogus; + blob1.cbData = sizeof(bogus); + ret = CertCompareCertificateName(0, &blob1, &blob1); + ok(ret, "CertCompareCertificateName failed: %08x\n", GetLastError()); + /* Leading zeroes matter.. */ + blob2.pbData = bogusPrime; + blob2.cbData = sizeof(bogusPrime); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + /* As do trailing extra bytes. */ + blob2.pbData = emptyPrime; + blob2.cbData = sizeof(emptyPrime); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + /* Tests to show that CertCompareCertificateName doesn't decode the name + * to remove spaces, or to do an order-independent comparison. + */ + /* Compare CN="Juan Lang" with CN=" Juan Lang" */ + blob1.pbData = cn; + blob1.cbData = sizeof(cn); + blob2.pbData = cnWithLeadingSpace; + blob2.cbData = sizeof(cnWithLeadingSpace); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + ret = CertCompareCertificateName(X509_ASN_ENCODING, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + /* Compare CN="Juan Lang" with CN="Juan Lang " */ + blob2.pbData = cnWithTrailingSpace; + blob2.cbData = sizeof(cnWithTrailingSpace); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + ret = CertCompareCertificateName(X509_ASN_ENCODING, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + /* Compare CN="Juan Lang" with CN="Juan Lang" */ + blob2.pbData = cnWithIntermediateSpace; + blob2.cbData = sizeof(cnWithIntermediateSpace); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + ret = CertCompareCertificateName(X509_ASN_ENCODING, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + /* Compare 'CN="Juan Lang", O="The Wine Project"' with + * 'O="The Wine Project", CN="Juan Lang"' + */ + blob1.pbData = cnThenO; + blob1.cbData = sizeof(cnThenO); + blob2.pbData = oThenCN; + blob2.cbData = sizeof(oThenCN); + ret = CertCompareCertificateName(0, &blob1, &blob2); + ok(!ret, "Expected failure\n"); + ret = CertCompareCertificateName(X509_ASN_ENCODING, &blob1, &blob2); + ok(!ret, "Expected failure\n"); +} + +static void testIsRDNAttrsInCertificateName(void) +{ + static char oid_1_2_3[] = "1.2.3"; + static char oid_common_name[] = szOID_COMMON_NAME; + static char oid_organization[] = szOID_ORGANIZATION_NAME; + static char juan[] = "Juan Lang"; + static char juan_with_leading_space[] = " Juan Lang"; + static char juan_with_intermediate_space[] = "Juan Lang"; + static char juan_with_trailing_space[] = "Juan Lang "; + static char juan_lower_case[] = "juan lang"; + static WCHAR juanW[] = { 'J','u','a','n',' ','L','a','n','g',0 }; + static char the_wine_project[] = "The Wine Project"; + BOOL ret; + CERT_NAME_BLOB name; + CERT_RDN_ATTR attr[2]; + CERT_RDN rdn = { 0, NULL }; + + name.cbData = sizeof(cn); + name.pbData = cn; + if (0) + { + /* Crash */ + ret = CertIsRDNAttrsInCertificateName(0, 0, NULL, NULL); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, + NULL); + } + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(0, 0, &name, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(ret, "CertIsRDNAttrsInCertificateName failed: %08x\n", GetLastError()); + attr[0].pszObjId = oid_1_2_3; + rdn.rgRDNAttr = attr; + rdn.cRDNAttr = 1; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + attr[0].pszObjId = oid_common_name; + attr[0].dwValueType = CERT_RDN_PRINTABLE_STRING; + attr[0].Value.cbData = strlen(juan); + attr[0].Value.pbData = (BYTE *)juan; + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(ret, "CertIsRDNAttrsInCertificateName failed: %08x\n", GetLastError()); + /* Again, spaces are not removed for name comparison. */ + attr[0].Value.cbData = strlen(juan_with_leading_space); + attr[0].Value.pbData = (BYTE *)juan_with_leading_space; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + attr[0].Value.cbData = strlen(juan_with_intermediate_space); + attr[0].Value.pbData = (BYTE *)juan_with_intermediate_space; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + attr[0].Value.cbData = strlen(juan_with_trailing_space); + attr[0].Value.pbData = (BYTE *)juan_with_trailing_space; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + /* The lower case name isn't matched unless a case insensitive match is + * specified. + */ + attr[0].Value.cbData = strlen(juan_lower_case); + attr[0].Value.pbData = (BYTE *)juan_lower_case; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, + CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG, &name, &rdn); + ok(ret || + broken(!ret && GetLastError() == CRYPT_E_NO_MATCH), /* Older crypt32 */ + "CertIsRDNAttrsInCertificateName failed: %08x\n", GetLastError()); + /* The values don't match unless they have the same RDN type */ + attr[0].dwValueType = CERT_RDN_UNICODE_STRING; + attr[0].Value.cbData = lstrlenW(juanW) * sizeof(WCHAR); + attr[0].Value.pbData = (BYTE *)juanW; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, + CERT_UNICODE_IS_RDN_ATTRS_FLAG, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + attr[0].dwValueType = CERT_RDN_IA5_STRING; + attr[0].Value.cbData = strlen(juan); + attr[0].Value.pbData = (BYTE *)juan; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + /* All attributes must be present */ + attr[0].dwValueType = CERT_RDN_PRINTABLE_STRING; + attr[0].Value.cbData = strlen(juan); + attr[0].Value.pbData = (BYTE *)juan; + attr[1].pszObjId = oid_organization; + attr[1].dwValueType = CERT_RDN_PRINTABLE_STRING; + attr[1].Value.cbData = strlen(the_wine_project); + attr[1].Value.pbData = (BYTE *)the_wine_project; + rdn.cRDNAttr = 2; + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + /* Order also matters */ + name.pbData = cnThenO; + name.cbData = sizeof(cnThenO); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(ret, "CertIsRDNAttrsInCertificateName failed: %08x\n", GetLastError()); + name.pbData = oThenCN; + name.cbData = sizeof(oThenCN); + SetLastError(0xdeadbeef); + ret = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING, 0, &name, &rdn); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); +} + +static BYTE int1[] = { 0x88, 0xff, 0xff, 0xff }; +static BYTE int2[] = { 0x88, 0xff }; +static BYTE int3[] = { 0x23, 0xff }; +static BYTE int4[] = { 0x7f, 0x00 }; +static BYTE int5[] = { 0x7f }; +static BYTE int6[] = { 0x80, 0x00, 0x00, 0x00 }; +static BYTE int7[] = { 0x80, 0x00 }; + +static struct IntBlobTest +{ + CRYPT_INTEGER_BLOB blob1; + CRYPT_INTEGER_BLOB blob2; + BOOL areEqual; +} intBlobs[] = { + { { sizeof(int1), int1 }, { sizeof(int2), int2 }, TRUE }, + { { sizeof(int3), int3 }, { sizeof(int3), int3 }, TRUE }, + { { sizeof(int4), int4 }, { sizeof(int5), int5 }, TRUE }, + { { sizeof(int6), int6 }, { sizeof(int7), int7 }, TRUE }, + { { sizeof(int1), int1 }, { sizeof(int7), int7 }, FALSE }, +}; + +static void testCompareIntegerBlob(void) +{ + DWORD i; + BOOL ret; + + for (i = 0; i < sizeof(intBlobs) / sizeof(intBlobs[0]); i++) + { + ret = CertCompareIntegerBlob(&intBlobs[i].blob1, &intBlobs[i].blob2); + ok(ret == intBlobs[i].areEqual, + "%d: expected blobs %s compare\n", i, intBlobs[i].areEqual ? + "to" : "not to"); + } +} + +static void testComparePublicKeyInfo(void) +{ + BOOL ret; + CERT_PUBLIC_KEY_INFO info1 = { { 0 } }, info2 = { { 0 } }; + static CHAR oid_rsa_rsa[] = szOID_RSA_RSA; + static CHAR oid_rsa_sha1rsa[] = szOID_RSA_SHA1RSA; + static CHAR oid_x957_dsa[] = szOID_X957_DSA; + static BYTE bits1[] = { 1, 0 }; + static BYTE bits2[] = { 0 }; + static BYTE bits3[] = { 1 }; + static BYTE bits4[] = { 0x30,8, 2,1,0x81, 2,3,1,0,1 }; + static BYTE bits5[] = { 0x30,9, 2,2,0,0x81, 2,3,1,0,1 }; + static BYTE bits6[] = { 0x30,9, 2,2,0,0x82, 2,3,1,0,1 }; + + /* crashes + ret = CertComparePublicKeyInfo(0, NULL, NULL); + */ + /* Empty public keys compare */ + ret = CertComparePublicKeyInfo(0, &info1, &info2); + ok(ret, "CertComparePublicKeyInfo failed: %08x\n", GetLastError()); + /* Different OIDs appear to compare */ + info1.Algorithm.pszObjId = oid_rsa_rsa; + info2.Algorithm.pszObjId = oid_rsa_sha1rsa; + ret = CertComparePublicKeyInfo(0, &info1, &info2); + ok(ret, "CertComparePublicKeyInfo failed: %08x\n", GetLastError()); + info2.Algorithm.pszObjId = oid_x957_dsa; + ret = CertComparePublicKeyInfo(0, &info1, &info2); + ok(ret, "CertComparePublicKeyInfo failed: %08x\n", GetLastError()); + info1.PublicKey.cbData = sizeof(bits1); + info1.PublicKey.pbData = bits1; + info1.PublicKey.cUnusedBits = 0; + info2.PublicKey.cbData = sizeof(bits1); + info2.PublicKey.pbData = bits1; + info2.PublicKey.cUnusedBits = 0; + ret = CertComparePublicKeyInfo(0, &info1, &info2); + ok(ret, "CertComparePublicKeyInfo failed: %08x\n", GetLastError()); + info2.Algorithm.pszObjId = oid_rsa_rsa; + info1.PublicKey.cbData = sizeof(bits4); + info1.PublicKey.pbData = bits4; + info1.PublicKey.cUnusedBits = 0; + info2.PublicKey.cbData = sizeof(bits5); + info2.PublicKey.pbData = bits5; + info2.PublicKey.cUnusedBits = 0; + ret = CertComparePublicKeyInfo(0, &info1, &info2); + ok(!ret, "CertComparePublicKeyInfo: as raw binary: keys should be unequal\n"); + ret = CertComparePublicKeyInfo(X509_ASN_ENCODING, &info1, &info2); + ok(ret || + broken(!ret), /* win9x */ + "CertComparePublicKeyInfo: as ASN.1 encoded: keys should be equal\n"); + info1.PublicKey.cUnusedBits = 1; + info2.PublicKey.cUnusedBits = 5; + ret = CertComparePublicKeyInfo(X509_ASN_ENCODING, &info1, &info2); + ok(ret || + broken(!ret), /* win9x */ + "CertComparePublicKeyInfo: ASN.1 encoding should ignore cUnusedBits\n"); + info1.PublicKey.cUnusedBits = 0; + info2.PublicKey.cUnusedBits = 0; + info1.PublicKey.cbData--; /* kill one byte, make ASN.1 encoded data invalid */ + ret = CertComparePublicKeyInfo(X509_ASN_ENCODING, &info1, &info2); + ok(!ret, "CertComparePublicKeyInfo: comparing bad ASN.1 encoded key should fail\n"); + /* Even though they compare in their used bits, these do not compare */ + info1.PublicKey.cbData = sizeof(bits2); + info1.PublicKey.pbData = bits2; + info1.PublicKey.cUnusedBits = 0; + info2.PublicKey.cbData = sizeof(bits3); + info2.PublicKey.pbData = bits3; + info2.PublicKey.cUnusedBits = 1; + ret = CertComparePublicKeyInfo(0, &info1, &info2); + /* Simple (non-comparing) case */ + ok(!ret, "Expected keys not to compare\n"); + info2.PublicKey.cbData = sizeof(bits1); + info2.PublicKey.pbData = bits1; + info2.PublicKey.cUnusedBits = 0; + ret = CertComparePublicKeyInfo(0, &info1, &info2); + ok(!ret, "Expected keys not to compare\n"); + /* ASN.1 encoded non-comparing case */ + info1.PublicKey.cbData = sizeof(bits5); + info1.PublicKey.pbData = bits5; + info1.PublicKey.cUnusedBits = 0; + info2.PublicKey.cbData = sizeof(bits6); + info2.PublicKey.pbData = bits6; + info2.PublicKey.cUnusedBits = 0; + ret = CertComparePublicKeyInfo(X509_ASN_ENCODING, &info1, &info2); + ok(!ret, "CertComparePublicKeyInfo: different keys should be unequal\n"); +} + +static void testHashPublicKeyInfo(void) +{ + BOOL ret; + CERT_PUBLIC_KEY_INFO info = { { 0 } }; + DWORD len; + + /* Crash + ret = CryptHashPublicKeyInfo(0, 0, 0, 0, NULL, NULL, NULL); + ret = CryptHashPublicKeyInfo(0, 0, 0, 0, &info, NULL, NULL); + */ + ret = CryptHashPublicKeyInfo(0, 0, 0, 0, NULL, NULL, &len); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* Crashes on some win9x boxes */ + if (0) + { + ret = CryptHashPublicKeyInfo(0, 0, 0, X509_ASN_ENCODING, NULL, NULL, &len); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + ret = CryptHashPublicKeyInfo(0, 0, 0, X509_ASN_ENCODING, &info, NULL, &len); + ok(ret || + broken(!ret), /* win9x */ + "CryptHashPublicKeyInfo failed: %08x\n", GetLastError()); + if (ret) + { + ok(len == 16, "Expected hash size 16, got %d\n", len); + if (len == 16) + { + static const BYTE emptyHash[] = { 0xb8,0x51,0x3a,0x31,0x0e,0x9f,0x40, + 0x36,0x9c,0x92,0x45,0x1b,0x9d,0xc8,0xf9,0xf6 }; + BYTE buf[16]; + + ret = CryptHashPublicKeyInfo(0, 0, 0, X509_ASN_ENCODING, &info, buf, + &len); + ok(ret, "CryptHashPublicKeyInfo failed: %08x\n", GetLastError()); + ok(!memcmp(buf, emptyHash, len), "Unexpected hash\n"); + } + } +} + +static const BYTE md5SignedEmptyCertHash[] = { 0xfb,0x0f,0x66,0x82,0x66,0xd9, + 0xe5,0xf8,0xd8,0xa2,0x55,0x2b,0xe1,0xa5,0xd9,0x04 }; + +static void testHashToBeSigned(void) +{ + BOOL ret; + DWORD size; + BYTE hash[16]; + + /* Crash */ + if (0) + { + ret = CryptHashToBeSigned(0, 0, NULL, 0, NULL, NULL); + } + SetLastError(0xdeadbeef); + ret = CryptHashToBeSigned(0, 0, NULL, 0, NULL, &size); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptHashToBeSigned(0, X509_ASN_ENCODING, NULL, 0, NULL, &size); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG), /* win9x */ + "expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); + /* Can't sign anything: has to be asn.1 encoded, at least */ + SetLastError(0xdeadbeef); + ret = CryptHashToBeSigned(0, X509_ASN_ENCODING, int1, sizeof(int1), + NULL, &size); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_MORE_INPUT), /* win9x */ + "expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); + /* Can't be empty, either */ + SetLastError(0xdeadbeef); + ret = CryptHashToBeSigned(0, X509_ASN_ENCODING, emptyCert, + sizeof(emptyCert), NULL, &size); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR), /* win9x */ + "expected CRYPT_E_ASN1_CORRUPT, got %08x\n", GetLastError()); + /* Signing a cert works */ + ret = CryptHashToBeSigned(0, X509_ASN_ENCODING, md5SignedEmptyCert, + sizeof(md5SignedEmptyCert), NULL, &size); + ok(ret || + broken(!ret), /* win9x */ + "CryptHashToBeSigned failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(md5SignedEmptyCertHash), "unexpected size %d\n", size); + } + + ret = CryptHashToBeSigned(0, X509_ASN_ENCODING, md5SignedEmptyCert, + sizeof(md5SignedEmptyCert), hash, &size); + ok(!memcmp(hash, md5SignedEmptyCertHash, size), "unexpected value\n"); +} + +static void testCompareCert(void) +{ + CERT_INFO info1 = { 0 }, info2 = { 0 }; + BOOL ret; + + /* Crashes + ret = CertCompareCertificate(X509_ASN_ENCODING, NULL, NULL); + */ + + /* Certs with the same issuer and serial number are equal, even if they + * differ in other respects (like subject). + */ + info1.SerialNumber.pbData = serialNum; + info1.SerialNumber.cbData = sizeof(serialNum); + info1.Issuer.pbData = subjectName; + info1.Issuer.cbData = sizeof(subjectName); + info1.Subject.pbData = subjectName2; + info1.Subject.cbData = sizeof(subjectName2); + info2.SerialNumber.pbData = serialNum; + info2.SerialNumber.cbData = sizeof(serialNum); + info2.Issuer.pbData = subjectName; + info2.Issuer.cbData = sizeof(subjectName); + info2.Subject.pbData = subjectName; + info2.Subject.cbData = sizeof(subjectName); + ret = CertCompareCertificate(X509_ASN_ENCODING, &info1, &info2); + ok(ret, "Expected certs to be equal\n"); + + info2.Issuer.pbData = subjectName2; + info2.Issuer.cbData = sizeof(subjectName2); + ret = CertCompareCertificate(X509_ASN_ENCODING, &info1, &info2); + ok(!ret, "Expected certs not to be equal\n"); +} + +static void testVerifySubjectCert(void) +{ + BOOL ret; + DWORD flags; + PCCERT_CONTEXT context1, context2; + + /* Crashes + ret = CertVerifySubjectCertificateContext(NULL, NULL, NULL); + */ + flags = 0; + ret = CertVerifySubjectCertificateContext(NULL, NULL, &flags); + ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n", + GetLastError()); + flags = CERT_STORE_NO_CRL_FLAG; + ret = CertVerifySubjectCertificateContext(NULL, NULL, &flags); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + + flags = 0; + context1 = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + ret = CertVerifySubjectCertificateContext(NULL, context1, &flags); + ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n", + GetLastError()); + ret = CertVerifySubjectCertificateContext(context1, NULL, &flags); + ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n", + GetLastError()); + ret = CertVerifySubjectCertificateContext(context1, context1, &flags); + ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n", + GetLastError()); + + context2 = CertCreateCertificateContext(X509_ASN_ENCODING, + bigCertWithDifferentSubject, sizeof(bigCertWithDifferentSubject)); + SetLastError(0xdeadbeef); + ret = CertVerifySubjectCertificateContext(context1, context2, &flags); + ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n", + GetLastError()); + flags = CERT_STORE_REVOCATION_FLAG; + ret = CertVerifySubjectCertificateContext(context1, context2, &flags); + ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n", + GetLastError()); + ok(flags == (CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG), + "Expected CERT_STORE_REVOCATION_FLAG | CERT_STORE_NO_CRL_FLAG, got %08x\n", + flags); + flags = CERT_STORE_SIGNATURE_FLAG; + ret = CertVerifySubjectCertificateContext(context1, context2, &flags); + ok(ret, "CertVerifySubjectCertificateContext failed; %08x\n", + GetLastError()); + ok(flags == CERT_STORE_SIGNATURE_FLAG, + "Expected CERT_STORE_SIGNATURE_FLAG, got %08x\n", flags); + CertFreeCertificateContext(context2); + + CertFreeCertificateContext(context1); +} + +static const BYTE rootWithKeySignAndCRLSign[] = { +0x30,0x82,0x01,0xdf,0x30,0x82,0x01,0x4c,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x5b,0xc7,0x0b,0x27,0x99,0xbb,0x2e,0x99,0x47,0x9d,0x45,0x4e,0x7c,0x1a,0xca, +0xe8,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x42,0x30,0x40,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x06,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1d,0x06,0x03,0x55,0x1d, +0x0e,0x04,0x16,0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0, +0x58,0xff,0x98,0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x09,0x06,0x05,0x2b, +0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81,0x81,0x00,0x74,0xcb,0x21,0xfd,0x2d, +0x25,0xdc,0xa5,0xaa,0xa1,0x26,0xdc,0x8b,0x40,0x11,0x64,0xae,0x5c,0x71,0x3c, +0x28,0xbc,0xf9,0xb3,0xcb,0xa5,0x94,0xb2,0x8d,0x4c,0x23,0x2b,0x9b,0xde,0x2c, +0x4c,0x30,0x04,0xc6,0x88,0x10,0x2f,0x53,0xfd,0x6c,0x82,0xf1,0x13,0xfb,0xda, +0x27,0x75,0x25,0x48,0xe4,0x72,0x09,0x2a,0xee,0xb4,0x1e,0xc9,0x55,0xf5,0xf7, +0x82,0x91,0xd8,0x4b,0xe4,0x3a,0xfe,0x97,0x87,0xdf,0xfb,0x15,0x5a,0x12,0x3e, +0x12,0xe6,0xad,0x40,0x0b,0xcf,0xee,0x1a,0x44,0xe0,0x83,0xb2,0x67,0x94,0xd4, +0x2e,0x7c,0xf2,0x06,0x9d,0xb3,0x3b,0x7e,0x2f,0xda,0x25,0x66,0x7e,0xa7,0x1f, +0x45,0xd4,0xf5,0xe3,0xdf,0x2a,0xf1,0x18,0x28,0x20,0xb5,0xf8,0xf5,0x8d,0x7a, +0x2e,0x84,0xee }; +static const BYTE eeCert[] = { +0x30,0x82,0x01,0xb9,0x30,0x82,0x01,0x22,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x1f,0x06,0x03,0x55, +0x1d,0x23,0x04,0x18,0x30,0x18,0x80,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2, +0x28,0x89,0xa0,0x58,0xff,0x98,0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81, +0x81,0x00,0x8a,0x49,0xa9,0x86,0x5e,0xc9,0x33,0x7e,0xfd,0xab,0x64,0x1f,0x6d, +0x00,0xd7,0x9b,0xec,0xd1,0x5b,0x38,0xcc,0xd6,0xf3,0xf2,0xb4,0x75,0x70,0x00, +0x82,0x9d,0x37,0x58,0xe1,0xcd,0x2c,0x61,0xb3,0x28,0xe7,0x8a,0x00,0xbe,0x6e, +0xca,0xe8,0x55,0xd5,0xad,0x3a,0xea,0xaf,0x13,0x20,0x1c,0x44,0xfc,0xb4,0xf9, +0x29,0x2b,0xdc,0x8a,0x2d,0x1b,0x27,0x9e,0xb9,0x3b,0x4a,0x71,0x9d,0x47,0x7d, +0xf7,0x92,0x6b,0x21,0x7f,0xfa,0x88,0x79,0x94,0x33,0xf6,0xdd,0x92,0x04,0x92, +0xd6,0x5e,0x0a,0x74,0xf2,0x85,0xa6,0xd5,0x3c,0x28,0xc0,0x89,0x5d,0xda,0xf3, +0xa6,0x01,0xc2,0xe9,0xa3,0xc1,0xb7,0x21,0x08,0xba,0x18,0x07,0x45,0xeb,0x77, +0x7d,0xcd,0xc6,0xe7,0x2a,0x7b,0x46,0xd2,0x3d,0xb5 }; +static const BYTE rootSignedCRL[] = { +0x30,0x82,0x01,0x1f,0x30,0x81,0x89,0x02,0x01,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x17,0x0d, +0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x14, +0x30,0x12,0x02,0x01,0x01,0x17,0x0d,0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0xa0,0x2f,0x30,0x2d,0x30,0x0a,0x06,0x03,0x55,0x1d, +0x14,0x04,0x03,0x02,0x01,0x01,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18, +0x30,0x18,0x80,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0,0x58, +0xff,0x98,0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0xa3,0xcf, +0x17,0x5d,0x7a,0x08,0xab,0x11,0x1a,0xbd,0x5c,0xde,0x9a,0x22,0x92,0x38,0xe6, +0x96,0xcc,0xb1,0xc5,0x42,0x86,0xa6,0xae,0xad,0xa3,0x1a,0x2b,0xa0,0xb0,0x65, +0xaa,0x9c,0xd7,0x2d,0x44,0x8c,0xae,0x61,0xc7,0x30,0x17,0x89,0x84,0x3b,0x4a, +0x8f,0x17,0x08,0x06,0x37,0x1c,0xf7,0x2d,0x4e,0x47,0x07,0x61,0x50,0xd9,0x06, +0xd1,0x46,0xed,0x0a,0xbb,0xc3,0x9b,0x36,0x0b,0xa7,0x27,0x2f,0x2b,0x55,0xce, +0x2a,0xa5,0x60,0xc6,0x53,0x28,0xe8,0xee,0xad,0x0e,0x2b,0xe8,0xd7,0x5f,0xc9, +0xa5,0xed,0xf9,0x77,0xb0,0x3c,0x81,0xcf,0xcc,0x49,0xb2,0x1a,0xc3,0xfd,0x34, +0xd5,0xbc,0xb0,0xd5,0xa5,0x9c,0x1b,0x72,0xc3,0x0f,0xa3,0xe3,0x3c,0xf0,0xc3, +0x91,0xe8,0x93,0x4f,0xd4,0x2f }; + +static void testVerifyRevocation(void) +{ + BOOL ret; + CERT_REVOCATION_STATUS status = { 0 }; + PCCERT_CONTEXT certs[2]; + CERT_REVOCATION_PARA revPara = { sizeof(revPara), 0 }; + + /* Crash + ret = CertVerifyRevocation(0, 0, 0, NULL, 0, NULL, NULL); + */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(0, 0, 0, NULL, 0, NULL, &status); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + status.cbSize = sizeof(status); + ret = CertVerifyRevocation(0, 0, 0, NULL, 0, NULL, &status); + ok(ret, "CertVerifyRevocation failed: %08x\n", GetLastError()); + ret = CertVerifyRevocation(0, 2, 0, NULL, 0, NULL, &status); + ok(ret, "CertVerifyRevocation failed: %08x\n", GetLastError()); + ret = CertVerifyRevocation(2, 0, 0, NULL, 0, NULL, &status); + ok(ret, "CertVerifyRevocation failed: %08x\n", GetLastError()); + certs[0] = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(0, 0, 1, (void **)certs, 0, NULL, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_DLL, + "Expected CRYPT_E_NO_REVOCATION_DLL, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(0, 2, 1, (void **)certs, 0, NULL, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_DLL, + "Expected CRYPT_E_NO_REVOCATION_DLL, got %08x\n", GetLastError()); + + CertFreeCertificateContext(certs[0]); + + certs[0] = CertCreateCertificateContext(X509_ASN_ENCODING, + rootWithKeySignAndCRLSign, sizeof(rootWithKeySignAndCRLSign)); + certs[1] = CertCreateCertificateContext(X509_ASN_ENCODING, + eeCert, sizeof(eeCert)); + /* The root cert itself can't be checked for revocation */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)certs, 0, NULL, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Neither can the end cert */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)&certs[1], 0, NULL, &status); + ok(!ret && (GetLastError() == CRYPT_E_NO_REVOCATION_CHECK /* Win9x */ || + GetLastError() == CRYPT_E_REVOCATION_OFFLINE), + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK /* Win9x */ || + status.dwError == CRYPT_E_REVOCATION_OFFLINE, + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Both certs together can't, either (they're not CRLs) */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, 0, NULL, &status); + ok(!ret && (GetLastError() == CRYPT_E_NO_REVOCATION_CHECK || + GetLastError() == CRYPT_E_REVOCATION_OFFLINE /* WinME */), + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK || + status.dwError == CRYPT_E_REVOCATION_OFFLINE /* WinME */, + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Now add a CRL to the hCrlStore */ + revPara.hCrlStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCRLToStore(revPara.hCrlStore, X509_ASN_ENCODING, + rootSignedCRL, sizeof(rootSignedCRL), CERT_STORE_ADD_ALWAYS, NULL); + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, 0, &revPara, &status); + ok(!ret && (GetLastError() == CRYPT_E_NO_REVOCATION_CHECK || + GetLastError() == CRYPT_E_REVOCATION_OFFLINE /* WinME */), + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK || + status.dwError == CRYPT_E_REVOCATION_OFFLINE /* WinME */, + "expected CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, got %08x\n", + status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Specifying CERT_VERIFY_REV_CHAIN_FLAG doesn't change things either */ + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 2, (void **)certs, CERT_VERIFY_REV_CHAIN_FLAG, &revPara, &status); + ok(!ret && GetLastError() == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK, + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + /* Again, specifying the issuer cert: no change */ + revPara.pIssuerCert = certs[0]; + SetLastError(0xdeadbeef); + ret = CertVerifyRevocation(X509_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, + 1, (void **)&certs[1], 0, &revPara, &status); + /* Win2k thinks the cert is revoked, and it is, except the CRL is out of + * date, hence the revocation status should be unknown. + */ + ok(!ret && (GetLastError() == CRYPT_E_NO_REVOCATION_CHECK || + broken(GetLastError() == CRYPT_E_REVOKED /* Win2k */)), + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", GetLastError()); + ok(status.dwError == CRYPT_E_NO_REVOCATION_CHECK || + broken(status.dwError == CRYPT_E_REVOKED /* Win2k */), + "expected CRYPT_E_NO_REVOCATION_CHECK, got %08x\n", status.dwError); + ok(status.dwIndex == 0, "expected index 0, got %d\n", status.dwIndex); + CertCloseStore(revPara.hCrlStore, 0); + CertFreeCertificateContext(certs[1]); + CertFreeCertificateContext(certs[0]); +} + +static BYTE privKey[] = { + 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, + 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10, + 0x18, 0x30, 0x94, 0x61, 0xdc, 0x0e, 0xcb, 0x96, 0x4e, 0x21, 0x3f, 0x79, 0xcd, + 0xa9, 0x17, 0x62, 0xbc, 0xbb, 0x61, 0x4c, 0xe0, 0x75, 0x38, 0x6c, 0xf3, 0xde, + 0x60, 0x86, 0x03, 0x97, 0x65, 0xeb, 0x1e, 0x6b, 0xdb, 0x53, 0x85, 0xad, 0x68, + 0x21, 0xf1, 0x5d, 0xe7, 0x1f, 0xe6, 0x53, 0xb4, 0xbb, 0x59, 0x3e, 0x14, 0x27, + 0xb1, 0x83, 0xa7, 0x3a, 0x54, 0xe2, 0x8f, 0x65, 0x8e, 0x6a, 0x4a, 0xcf, 0x3b, + 0x1f, 0x65, 0xff, 0xfe, 0xf1, 0x31, 0x3a, 0x37, 0x7a, 0x8b, 0xcb, 0xc6, 0xd4, + 0x98, 0x50, 0x36, 0x67, 0xe4, 0xa1, 0xe8, 0x7e, 0x8a, 0xc5, 0x23, 0xf2, 0x77, + 0xf5, 0x37, 0x61, 0x49, 0x72, 0x59, 0xe8, 0x3d, 0xf7, 0x60, 0xb2, 0x77, 0xca, + 0x78, 0x54, 0x6d, 0x65, 0x9e, 0x03, 0x97, 0x1b, 0x61, 0xbd, 0x0c, 0xd8, 0x06, + 0x63, 0xe2, 0xc5, 0x48, 0xef, 0xb3, 0xe2, 0x6e, 0x98, 0x7d, 0xbd, 0x4e, 0x72, + 0x91, 0xdb, 0x31, 0x57, 0xe3, 0x65, 0x3a, 0x49, 0xca, 0xec, 0xd2, 0x02, 0x4e, + 0x22, 0x7e, 0x72, 0x8e, 0xf9, 0x79, 0x84, 0x82, 0xdf, 0x7b, 0x92, 0x2d, 0xaf, + 0xc9, 0xe4, 0x33, 0xef, 0x89, 0x5c, 0x66, 0x99, 0xd8, 0x80, 0x81, 0x47, 0x2b, + 0xb1, 0x66, 0x02, 0x84, 0x59, 0x7b, 0xc3, 0xbe, 0x98, 0x45, 0x4a, 0x3d, 0xdd, + 0xea, 0x2b, 0xdf, 0x4e, 0xb4, 0x24, 0x6b, 0xec, 0xe7, 0xd9, 0x0c, 0x45, 0xb8, + 0xbe, 0xca, 0x69, 0x37, 0x92, 0x4c, 0x38, 0x6b, 0x96, 0x6d, 0xcd, 0x86, 0x67, + 0x5c, 0xea, 0x54, 0x94, 0xa4, 0xca, 0xa4, 0x02, 0xa5, 0x21, 0x4d, 0xae, 0x40, + 0x8f, 0x9d, 0x51, 0x83, 0xf2, 0x3f, 0x33, 0xc1, 0x72, 0xb4, 0x1d, 0x94, 0x6e, + 0x7d, 0xe4, 0x27, 0x3f, 0xea, 0xff, 0xe5, 0x9b, 0xa7, 0x5e, 0x55, 0x8e, 0x0d, + 0x69, 0x1c, 0x7a, 0xff, 0x81, 0x9d, 0x53, 0x52, 0x97, 0x9a, 0x76, 0x79, 0xda, + 0x93, 0x32, 0x16, 0xec, 0x69, 0x51, 0x1a, 0x4e, 0xc3, 0xf1, 0x72, 0x80, 0x78, + 0x5e, 0x66, 0x4a, 0x8d, 0x85, 0x2f, 0x3f, 0xb2, 0xa7 }; + +static const BYTE exportedPublicKeyBlob[] = { +0x06,0x02,0x00,0x00,0x00,0xa4,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x02,0x00,0x00, +0x01,0x00,0x01,0x00,0x79,0x10,0x1c,0xd0,0x6b,0x10,0x18,0x30,0x94,0x61,0xdc,0x0e, +0xcb,0x96,0x4e,0x21,0x3f,0x79,0xcd,0xa9,0x17,0x62,0xbc,0xbb,0x61,0x4c,0xe0,0x75, +0x38,0x6c,0xf3,0xde,0x60,0x86,0x03,0x97,0x65,0xeb,0x1e,0x6b,0xdb,0x53,0x85,0xad, +0x68,0x21,0xf1,0x5d,0xe7,0x1f,0xe6,0x53,0xb4,0xbb,0x59,0x3e,0x14,0x27,0xb1,0x83, +0xa7,0x3a,0x54,0xe2 }; + +static const BYTE asnEncodedPublicKey[] = { +0x30,0x48,0x02,0x41,0x00,0xe2,0x54,0x3a,0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb, +0xb4,0x53,0xe6,0x1f,0xe7,0x5d,0xf1,0x21,0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb, +0x65,0x97,0x03,0x86,0x60,0xde,0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc,0x62, +0x17,0xa9,0xcd,0x79,0x3f,0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30,0x18,0x10, +0x6b,0xd0,0x1c,0x10,0x79,0x02,0x03,0x01,0x00,0x01 }; + +static void testAcquireCertPrivateKey(void) +{ + BOOL ret; + PCCERT_CONTEXT cert; + HCRYPTPROV csp; + DWORD size, keySpec; + BOOL callerFree; + CRYPT_KEY_PROV_INFO keyProvInfo; + HCRYPTKEY key; + WCHAR ms_def_prov_w[MAX_PATH]; + + if (!pCryptAcquireCertificatePrivateKey) + { + win_skip("CryptAcquireCertificatePrivateKey() is not available\n"); + return; + } + + lstrcpyW(ms_def_prov_w, MS_DEF_PROV_W); + + keyProvInfo.pwszContainerName = cspNameW; + keyProvInfo.pwszProvName = ms_def_prov_w; + keyProvInfo.dwProvType = PROV_RSA_FULL; + keyProvInfo.dwFlags = 0; + keyProvInfo.cProvParam = 0; + keyProvInfo.rgProvParam = NULL; + keyProvInfo.dwKeySpec = AT_SIGNATURE; + + pCryptAcquireContextA(NULL, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + + cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert, + sizeof(selfSignedCert)); + + /* Crash + ret = pCryptAcquireCertificatePrivateKey(NULL, 0, NULL, NULL, NULL, NULL); + ret = pCryptAcquireCertificatePrivateKey(NULL, 0, NULL, NULL, NULL, + &callerFree); + ret = pCryptAcquireCertificatePrivateKey(NULL, 0, NULL, NULL, &keySpec, + NULL); + ret = pCryptAcquireCertificatePrivateKey(NULL, 0, NULL, &csp, NULL, NULL); + ret = pCryptAcquireCertificatePrivateKey(NULL, 0, NULL, &csp, &keySpec, + &callerFree); + ret = pCryptAcquireCertificatePrivateKey(cert, 0, NULL, NULL, NULL, NULL); + */ + + /* Missing private key */ + ret = pCryptAcquireCertificatePrivateKey(cert, 0, NULL, &csp, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_KEY_PROPERTY, + "Expected CRYPT_E_NO_KEY_PROPERTY, got %08x\n", GetLastError()); + ret = pCryptAcquireCertificatePrivateKey(cert, 0, NULL, &csp, &keySpec, + &callerFree); + ok(!ret && GetLastError() == CRYPT_E_NO_KEY_PROPERTY, + "Expected CRYPT_E_NO_KEY_PROPERTY, got %08x\n", GetLastError()); + CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, + &keyProvInfo); + ret = pCryptAcquireCertificatePrivateKey(cert, 0, NULL, &csp, &keySpec, + &callerFree); + ok(!ret && GetLastError() == CRYPT_E_NO_KEY_PROPERTY, + "Expected CRYPT_E_NO_KEY_PROPERTY, got %08x\n", GetLastError()); + + pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_NEWKEYSET); + ret = CryptImportKey(csp, privKey, sizeof(privKey), 0, 0, &key); + ok(ret, "CryptImportKey failed: %08x\n", GetLastError()); + if (ret) + { + HCRYPTPROV certCSP; + DWORD size; + CERT_KEY_CONTEXT keyContext; + + /* Don't cache provider */ + ret = pCryptAcquireCertificatePrivateKey(cert, 0, NULL, &certCSP, + &keySpec, &callerFree); + ok(ret || + broken(!ret), /* win95 */ + "CryptAcquireCertificatePrivateKey failed: %08x\n", + GetLastError()); + if (ret) + { + ok(callerFree, "Expected callerFree to be TRUE\n"); + CryptReleaseContext(certCSP, 0); + } + + ret = pCryptAcquireCertificatePrivateKey(cert, 0, NULL, &certCSP, + NULL, NULL); + ok(ret || + broken(!ret), /* win95 */ + "CryptAcquireCertificatePrivateKey failed: %08x\n", + GetLastError()); + CryptReleaseContext(certCSP, 0); + + /* Use the key prov info's caching (there shouldn't be any) */ + ret = pCryptAcquireCertificatePrivateKey(cert, + CRYPT_ACQUIRE_USE_PROV_INFO_FLAG, NULL, &certCSP, &keySpec, + &callerFree); + ok(ret || + broken(!ret), /* win95 */ + "CryptAcquireCertificatePrivateKey failed: %08x\n", + GetLastError()); + if (ret) + { + ok(callerFree, "Expected callerFree to be TRUE\n"); + CryptReleaseContext(certCSP, 0); + } + + /* Cache it (and check that it's cached) */ + ret = pCryptAcquireCertificatePrivateKey(cert, + CRYPT_ACQUIRE_CACHE_FLAG, NULL, &certCSP, &keySpec, &callerFree); + ok(ret || + broken(!ret), /* win95 */ + "CryptAcquireCertificatePrivateKey failed: %08x\n", + GetLastError()); + ok(!callerFree, "Expected callerFree to be FALSE\n"); + size = sizeof(keyContext); + ret = CertGetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID, + &keyContext, &size); + ok(ret || + broken(!ret), /* win95 */ + "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + + /* Remove the cached provider */ + CryptReleaseContext(keyContext.hCryptProv, 0); + CertSetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID, 0, + NULL); + /* Allow caching via the key prov info */ + keyProvInfo.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; + CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, + &keyProvInfo); + /* Now use the key prov info's caching */ + ret = pCryptAcquireCertificatePrivateKey(cert, + CRYPT_ACQUIRE_USE_PROV_INFO_FLAG, NULL, &certCSP, &keySpec, + &callerFree); + ok(ret || + broken(!ret), /* win95 */ + "CryptAcquireCertificatePrivateKey failed: %08x\n", + GetLastError()); + ok(!callerFree, "Expected callerFree to be FALSE\n"); + size = sizeof(keyContext); + ret = CertGetCertificateContextProperty(cert, CERT_KEY_CONTEXT_PROP_ID, + &keyContext, &size); + ok(ret || + broken(!ret), /* win95 */ + "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + CryptReleaseContext(certCSP, 0); + + CryptDestroyKey(key); + } + + /* Some sanity-checking on public key exporting */ + ret = CryptImportPublicKeyInfo(csp, X509_ASN_ENCODING, + &cert->pCertInfo->SubjectPublicKeyInfo, &key); + ok(ret, "CryptImportPublicKeyInfo failed: %08x\n", GetLastError()); + if (ret) + { + ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &size); + ok(ret, "CryptExportKey failed: %08x\n", GetLastError()); + if (ret) + { + LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size), encodedKey; + + ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, buf, &size); + ok(ret, "CryptExportKey failed: %08x\n", GetLastError()); + ok(size == sizeof(exportedPublicKeyBlob), "Unexpected size %d\n", + size); + ok(!memcmp(buf, exportedPublicKeyBlob, size), "Unexpected value\n"); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, + buf, CRYPT_ENCODE_ALLOC_FLAG, NULL, &encodedKey, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(asnEncodedPublicKey), "Unexpected size %d\n", + size); + ok(!memcmp(encodedKey, asnEncodedPublicKey, size), + "Unexpected value\n"); + LocalFree(encodedKey); + } + HeapFree(GetProcessHeap(), 0, buf); + } + CryptDestroyKey(key); + } + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, + NULL, 0, NULL, NULL, &size); + ok(ret, "CryptExportPublicKeyInfoEx failed: %08x\n", GetLastError()); + if (ret) + { + PCERT_PUBLIC_KEY_INFO info = HeapAlloc(GetProcessHeap(), 0, size); + + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, + NULL, 0, NULL, info, &size); + ok(ret, "CryptExportPublicKeyInfoEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->PublicKey.cbData == sizeof(asnEncodedPublicKey), + "Unexpected size %d\n", info->PublicKey.cbData); + ok(!memcmp(info->PublicKey.pbData, asnEncodedPublicKey, + info->PublicKey.cbData), "Unexpected value\n"); + } + HeapFree(GetProcessHeap(), 0, info); + } + + CryptReleaseContext(csp, 0); + pCryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + + CertFreeCertificateContext(cert); +} + +static void testGetPublicKeyLength(void) +{ + static char oid_rsa_rsa[] = szOID_RSA_RSA; + static char oid_rsa_dh[] = szOID_RSA_DH; + static char bogusOID[] = "1.2.3"; + DWORD ret; + CERT_PUBLIC_KEY_INFO info = { { 0 } }; + BYTE bogusKey[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + BYTE key[] = { 0x30,0x0f,0x02,0x08,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x02,0x03,0x01,0x00,0x01 }; + + /* Crashes + ret = CertGetPublicKeyLength(0, NULL); + */ + /* With an empty public key info */ + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(0, &info); + ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %d, %08x\n", + ret, GetLastError()); + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info); + ok(ret == 0 && + (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG), /* win9x */ + "Expected length 0 and CRYPT_E_ASN1_EOD, got length %d, %08x\n", + ret, GetLastError()); + /* With a nearly-empty public key info */ + info.Algorithm.pszObjId = oid_rsa_rsa; + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(0, &info); + ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %d, %08x\n", + ret, GetLastError()); + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info); + ok(ret == 0 && + (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG), /* win9x */ + "Expected length 0 and CRYPT_E_ASN1_EOD, got length %d, %08x\n", + ret, GetLastError()); + /* With a bogus key */ + info.PublicKey.cbData = sizeof(bogusKey); + info.PublicKey.pbData = bogusKey; + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(0, &info); + ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %d, %08x\n", + ret, GetLastError()); + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info); + ok(ret == 0 && + (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH), /* win9x */ + "Expected length 0 and CRYPT_E_ASN1_BADTAGTAG, got length %d, %08x\n", + ret, GetLastError()); + /* With a believable RSA key but a bogus OID */ + info.Algorithm.pszObjId = bogusOID; + info.PublicKey.cbData = sizeof(key); + info.PublicKey.pbData = key; + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(0, &info); + ok(ret == 0 && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected length 0 and ERROR_FILE_NOT_FOUND, got length %d, %08x\n", + ret, GetLastError()); + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info); + ok(ret == 56 || broken(ret == 0 && GetLastError() == NTE_BAD_LEN) /* Win7 */, + "Expected length 56, got %d\n", ret); + /* An RSA key with the DH OID */ + info.Algorithm.pszObjId = oid_rsa_dh; + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info); + ok(ret == 0 && + (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == E_INVALIDARG), /* win9x */ + "Expected length 0 and CRYPT_E_ASN1_BADTAG, got length %d, %08x\n", + ret, GetLastError()); + /* With the RSA OID */ + info.Algorithm.pszObjId = oid_rsa_rsa; + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(X509_ASN_ENCODING, &info); + ok(ret == 56 || broken(ret == 0 && GetLastError() == NTE_BAD_LEN) /* Win7 */, + "Expected length 56, got %d\n", ret); + /* With the RSA OID and a message encoding */ + info.Algorithm.pszObjId = oid_rsa_rsa; + SetLastError(0xdeadbeef); + ret = CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &info); + ok(ret == 56 || broken(ret == 0 && GetLastError() == NTE_BAD_LEN) /* Win7 */, + "Expected length 56, got %d\n", ret); +} + +START_TEST(cert) +{ + init_function_pointers(); + + testAddCert(); + testCertProperties(); + testDupCert(); + testFindCert(); + testGetSubjectCert(); + testGetIssuerCert(); + + testCryptHashCert(); + testCertSigs(); + testSignAndEncodeCert(); + testCreateSelfSignCert(); + testIntendedKeyUsage(); + testKeyUsage(); + testGetValidUsages(); + testCompareCertName(); + testCompareIntegerBlob(); + testComparePublicKeyInfo(); + testHashPublicKeyInfo(); + testHashToBeSigned(); + testCompareCert(); + testVerifySubjectCert(); + testVerifyRevocation(); + testAcquireCertPrivateKey(); + testGetPublicKeyLength(); + testIsRDNAttrsInCertificateName(); +} diff --git a/rostests/winetests/crypt32/chain.c b/rostests/winetests/crypt32/chain.c new file mode 100644 index 00000000000..4192e116d17 --- /dev/null +++ b/rostests/winetests/crypt32/chain.c @@ -0,0 +1,4202 @@ +/* + * crypt32 certificate chain functions tests + * + * Copyright 2006 Juan Lang + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static const BYTE selfSignedCert[] = { + 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, + 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49, + 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, + 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30, + 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31, + 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, + 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, + 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4, + 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b, + 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0, + 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96, + 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, + 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41, + 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66, + 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a, + 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7, + 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f, + 0xa8, 0x76, 0x57, 0x92, 0x36 }; + +static BOOL (WINAPI *pCertCreateCertificateChainEngine)(PCERT_CHAIN_ENGINE_CONFIG,HCERTCHAINENGINE*); +static BOOL (WINAPI *pCertGetCertificateChain)(HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,PCCERT_CHAIN_CONTEXT*); +static VOID (WINAPI *pCertFreeCertificateChain)(PCCERT_CHAIN_CONTEXT); +static VOID (WINAPI *pCertFreeCertificateChainEngine)(HCERTCHAINENGINE); +static BOOL (WINAPI *pCertVerifyCertificateChainPolicy)(LPCSTR,PCCERT_CHAIN_CONTEXT,PCERT_CHAIN_POLICY_PARA,PCERT_CHAIN_POLICY_STATUS); + + +static void testCreateCertChainEngine(void) +{ + BOOL ret; + CERT_CHAIN_ENGINE_CONFIG config = { 0 }; + HCERTCHAINENGINE engine; + HCERTSTORE store; + + if (!pCertCreateCertificateChainEngine || !pCertFreeCertificateChainEngine) + { + win_skip("Cert*CertificateChainEngine() functions are not available\n"); + return; + } + + /* Crash + ret = pCertCreateCertificateChainEngine(NULL, NULL); + ret = pCertCreateCertificateChainEngine(NULL, &engine); + ret = pCertCreateCertificateChainEngine(&config, NULL); + */ + ret = pCertCreateCertificateChainEngine(&config, &engine); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Crashes + config.cbSize = sizeof(config); + ret = pCertCreateCertificateChainEngine(&config, NULL); + */ + config.cbSize = sizeof(config); + ret = pCertCreateCertificateChainEngine(&config, &engine); + ok(ret, "CertCreateCertificateChainEngine failed: %08x\n", GetLastError()); + pCertFreeCertificateChainEngine(engine); + config.dwFlags = 0xff000000; + ret = pCertCreateCertificateChainEngine(&config, &engine); + ok(ret, "CertCreateCertificateChainEngine failed: %08x\n", GetLastError()); + pCertFreeCertificateChainEngine(engine); + + /* Creating a cert with no root certs at all is allowed.. */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + config.hRestrictedRoot = store; + ret = pCertCreateCertificateChainEngine(&config, &engine); + ok(ret, "CertCreateCertificateChainEngine failed: %08x\n", GetLastError()); + pCertFreeCertificateChainEngine(engine); + + /* but creating one with a restricted root with a cert that isn't a member + * of the Root store isn't allowed. + */ + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, selfSignedCert, + sizeof(selfSignedCert), CERT_STORE_ADD_ALWAYS, NULL); + ret = pCertCreateCertificateChainEngine(&config, &engine); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + + CertCloseStore(store, 0); +} + +static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE iTunesCert0[] = { +0x30,0x82,0x04,0xbf,0x30,0x82,0x04,0x28,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x41,0x91,0xa1,0x5a,0x39,0x78,0xdf,0xcf,0x49,0x65,0x66,0x38,0x1d,0x4c,0x75, +0xc2,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x5f,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72, +0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x37,0x30,0x35, +0x06,0x03,0x55,0x04,0x0b,0x13,0x2e,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20, +0x50,0x75,0x62,0x6c,0x69,0x63,0x20,0x50,0x72,0x69,0x6d,0x61,0x72,0x79,0x20, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41, +0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x30,0x1e,0x17,0x0d,0x30,0x34,0x30, +0x37,0x31,0x36,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x31,0x34,0x30, +0x37,0x31,0x35,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xb4,0x31,0x0b, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15, +0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e, +0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x0b, +0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x54,0x72,0x75,0x73, +0x74,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x3b,0x30,0x39,0x06,0x03, +0x55,0x04,0x0b,0x13,0x32,0x54,0x65,0x72,0x6d,0x73,0x20,0x6f,0x66,0x20,0x75, +0x73,0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77, +0x77,0x77,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d, +0x2f,0x72,0x70,0x61,0x20,0x28,0x63,0x29,0x30,0x34,0x31,0x2e,0x30,0x2c,0x06, +0x03,0x55,0x04,0x03,0x13,0x25,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20, +0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x43,0x6f,0x64,0x65,0x20,0x53,0x69, +0x67,0x6e,0x69,0x6e,0x67,0x20,0x32,0x30,0x30,0x34,0x20,0x43,0x41,0x30,0x82, +0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, +0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01, +0x00,0xbe,0xbc,0xee,0xbc,0x7e,0xef,0x83,0xeb,0xe0,0x37,0x4f,0xfb,0x03,0x10, +0x38,0xbe,0x08,0xd2,0x8c,0x7d,0x9d,0xfa,0x92,0x7f,0x19,0x0c,0xc2,0x6b,0xee, +0x42,0x52,0x8c,0xde,0xd3,0x1c,0x48,0x13,0x25,0xea,0xc1,0x63,0x7a,0xf9,0x51, +0x65,0xee,0xd3,0xaa,0x3b,0xf5,0xf0,0x94,0x9c,0x2b,0xfb,0xf2,0x66,0xd4,0x24, +0xda,0xf7,0xf5,0x9f,0x6e,0x19,0x39,0x36,0xbc,0xd0,0xa3,0x76,0x08,0x1e,0x22, +0x27,0x24,0x6c,0x38,0x91,0x27,0xe2,0x84,0x49,0xae,0x1b,0x8a,0xa1,0xfd,0x25, +0x82,0x2c,0x10,0x30,0xe8,0x71,0xab,0x28,0xe8,0x77,0x4a,0x51,0xf1,0xec,0xcd, +0xf8,0xf0,0x54,0xd4,0x6f,0xc0,0xe3,0x6d,0x0a,0x8f,0xd9,0xd8,0x64,0x8d,0x63, +0xb2,0x2d,0x4e,0x27,0xf6,0x85,0x0e,0xfe,0x6d,0xe3,0x29,0x99,0xe2,0x85,0x47, +0x7c,0x2d,0x86,0x7f,0xe8,0x57,0x8f,0xad,0x67,0xc2,0x33,0x32,0x91,0x13,0x20, +0xfc,0xa9,0x23,0x14,0x9a,0x6d,0xc2,0x84,0x4b,0x76,0x68,0x04,0xd5,0x71,0x2c, +0x5d,0x21,0xfa,0x88,0x0d,0x26,0xfd,0x1f,0x2d,0x91,0x2b,0xe7,0x01,0x55,0x4d, +0xf2,0x6d,0x35,0x28,0x82,0xdf,0xd9,0x6b,0x5c,0xb6,0xd6,0xd9,0xaa,0x81,0xfd, +0x5f,0xcd,0x83,0xba,0x63,0x9d,0xd0,0x22,0xfc,0xa9,0x3b,0x42,0x69,0xb2,0x8e, +0x3a,0xb5,0xbc,0xb4,0x9e,0x0f,0x5e,0xc4,0xea,0x2c,0x82,0x8b,0x28,0xfd,0x53, +0x08,0x96,0xdd,0xb5,0x01,0x20,0xd1,0xf9,0xa5,0x18,0xe7,0xc0,0xee,0x51,0x70, +0x37,0xe1,0xb6,0x05,0x48,0x52,0x48,0x6f,0x38,0xea,0xc3,0xe8,0x6c,0x7b,0x44, +0x84,0xbb,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xa0,0x30,0x82,0x01,0x9c, +0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01, +0x01,0xff,0x02,0x01,0x00,0x30,0x44,0x06,0x03,0x55,0x1d,0x20,0x04,0x3d,0x30, +0x3b,0x30,0x39,0x06,0x0b,0x60,0x86,0x48,0x01,0x86,0xf8,0x45,0x01,0x07,0x17, +0x03,0x30,0x2a,0x30,0x28,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01, +0x16,0x1c,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76, +0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61, +0x30,0x31,0x06,0x03,0x55,0x1d,0x1f,0x04,0x2a,0x30,0x28,0x30,0x26,0xa0,0x24, +0xa0,0x22,0x86,0x20,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e, +0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x70,0x63, +0x61,0x33,0x2e,0x63,0x72,0x6c,0x30,0x1d,0x06,0x03,0x55,0x1d,0x25,0x04,0x16, +0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x08,0x2b, +0x06,0x01,0x05,0x05,0x07,0x03,0x03,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01, +0x01,0xff,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x11,0x06,0x09,0x60,0x86,0x48, +0x01,0x86,0xf8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x01,0x30,0x29,0x06, +0x03,0x55,0x1d,0x11,0x04,0x22,0x30,0x20,0xa4,0x1e,0x30,0x1c,0x31,0x1a,0x30, +0x18,0x06,0x03,0x55,0x04,0x03,0x13,0x11,0x43,0x6c,0x61,0x73,0x73,0x33,0x43, +0x41,0x32,0x30,0x34,0x38,0x2d,0x31,0x2d,0x34,0x33,0x30,0x1d,0x06,0x03,0x55, +0x1d,0x0e,0x04,0x16,0x04,0x14,0x08,0xf5,0x51,0xe8,0xfb,0xfe,0x3d,0x3d,0x64, +0x36,0x7c,0x68,0xcf,0x5b,0x78,0xa8,0xdf,0xb9,0xc5,0x37,0x30,0x81,0x80,0x06, +0x03,0x55,0x1d,0x23,0x04,0x79,0x30,0x77,0xa1,0x63,0xa4,0x61,0x30,0x5f,0x31, +0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30, +0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04, +0x0b,0x13,0x2e,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6c, +0x69,0x63,0x20,0x50,0x72,0x69,0x6d,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f, +0x72,0x69,0x74,0x79,0x82,0x10,0x70,0xba,0xe4,0x1d,0x10,0xd9,0x29,0x34,0xb6, +0x38,0xca,0x7b,0x03,0xcc,0xba,0xbf,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0xae,0x3a,0x17,0xb8, +0x4a,0x7b,0x55,0xfa,0x64,0x55,0xec,0x40,0xa4,0xed,0x49,0x41,0x90,0x99,0x9c, +0x89,0xbc,0xaf,0x2e,0x1d,0xca,0x78,0x23,0xf9,0x1c,0x19,0x0f,0x7f,0xeb,0x68, +0xbc,0x32,0xd9,0x88,0x38,0xde,0xdc,0x3f,0xd3,0x89,0xb4,0x3f,0xb1,0x82,0x96, +0xf1,0xa4,0x5a,0xba,0xed,0x2e,0x26,0xd3,0xde,0x7c,0x01,0x6e,0x00,0x0a,0x00, +0xa4,0x06,0x92,0x11,0x48,0x09,0x40,0xf9,0x1c,0x18,0x79,0x67,0x23,0x24,0xe0, +0xbb,0xd5,0xe1,0x50,0xae,0x1b,0xf5,0x0e,0xdd,0xe0,0x2e,0x81,0xcd,0x80,0xa3, +0x6c,0x52,0x4f,0x91,0x75,0x55,0x8a,0xba,0x22,0xf2,0xd2,0xea,0x41,0x75,0x88, +0x2f,0x63,0x55,0x7d,0x1e,0x54,0x5a,0x95,0x59,0xca,0xd9,0x34,0x81,0xc0,0x5f, +0x5e,0xf6,0x7a,0xb5 }; +static const BYTE iTunesCert1[] = { +0x30,0x82,0x04,0xf1,0x30,0x82,0x03,0xd9,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x0f,0x1a,0xa0,0xe0,0x9b,0x9b,0x61,0xa6,0xb6,0xfe,0x40,0xd2,0xdf,0x6a,0xf6, +0x8d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x81,0xb4,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65, +0x72,0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x1f,0x30, +0x1d,0x06,0x03,0x55,0x04,0x0b,0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b, +0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04,0x0b,0x13,0x32,0x54,0x65,0x72,0x6d, +0x73,0x20,0x6f,0x66,0x20,0x75,0x73,0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74, +0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76,0x65,0x72,0x69,0x73,0x69, +0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61,0x20,0x28,0x63,0x29,0x30, +0x34,0x31,0x2e,0x30,0x2c,0x06,0x03,0x55,0x04,0x03,0x13,0x25,0x56,0x65,0x72, +0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x43, +0x6f,0x64,0x65,0x20,0x53,0x69,0x67,0x6e,0x69,0x6e,0x67,0x20,0x32,0x30,0x30, +0x34,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x30,0x36,0x30,0x31,0x31,0x37,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x38,0x30,0x31,0x32,0x32,0x32, +0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xb4,0x31,0x0b,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04, +0x08,0x13,0x0a,0x43,0x61,0x6c,0x69,0x66,0x6f,0x72,0x6e,0x69,0x61,0x31,0x12, +0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13,0x09,0x43,0x75,0x70,0x65,0x72,0x74, +0x69,0x6e,0x6f,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55,0x04,0x0a,0x14,0x14,0x41, +0x70,0x70,0x6c,0x65,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x2c,0x20, +0x49,0x6e,0x63,0x2e,0x31,0x3e,0x30,0x3c,0x06,0x03,0x55,0x04,0x0b,0x13,0x35, +0x44,0x69,0x67,0x69,0x74,0x61,0x6c,0x20,0x49,0x44,0x20,0x43,0x6c,0x61,0x73, +0x73,0x20,0x33,0x20,0x2d,0x20,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74, +0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x56,0x61,0x6c,0x69,0x64, +0x61,0x74,0x69,0x6f,0x6e,0x20,0x76,0x32,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55, +0x04,0x03,0x14,0x14,0x41,0x70,0x70,0x6c,0x65,0x20,0x43,0x6f,0x6d,0x70,0x75, +0x74,0x65,0x72,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xd3,0xab,0x3b,0x7f,0xec,0x48,0x84, +0xce,0xa8,0x1a,0x12,0xf3,0x3c,0x87,0xcb,0x24,0x58,0x96,0x02,0x87,0x66,0x49, +0xeb,0x89,0xee,0x79,0x44,0x70,0x8d,0xe7,0xd4,0x1f,0x30,0x92,0xc0,0x9c,0x35, +0x78,0xc0,0xaf,0x1c,0xb6,0x28,0xd3,0xe0,0xe0,0x9d,0xd3,0x49,0x76,0x73,0x57, +0x19,0x4d,0x8d,0x70,0x85,0x64,0x4d,0x1d,0xc6,0x02,0x3e,0xe5,0x2c,0x66,0x07, +0xd2,0x27,0x4b,0xd6,0xc8,0x3c,0x93,0xb6,0x15,0x0c,0xde,0x5b,0xd7,0x93,0xdd, +0xbe,0x85,0x62,0x34,0x17,0x8a,0x05,0x60,0xf0,0x8a,0x1c,0x5a,0x40,0x21,0x8d, +0x51,0x6c,0xb0,0x62,0xd8,0xb5,0xd4,0xf9,0xb1,0xd0,0x58,0x7a,0x7a,0x82,0x55, +0xb3,0xf9,0x53,0x71,0xde,0xd2,0xc9,0x37,0x8c,0xf6,0x5a,0x1f,0x2d,0xcd,0x7c, +0x67,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0x7f,0x30,0x82,0x01,0x7b,0x30, +0x09,0x06,0x03,0x55,0x1d,0x13,0x04,0x02,0x30,0x00,0x30,0x0e,0x06,0x03,0x55, +0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x07,0x80,0x30,0x40,0x06,0x03, +0x55,0x1d,0x1f,0x04,0x39,0x30,0x37,0x30,0x35,0xa0,0x33,0xa0,0x31,0x86,0x2f, +0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30, +0x34,0x2d,0x63,0x72,0x6c,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e, +0x63,0x6f,0x6d,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2e,0x63, +0x72,0x6c,0x30,0x44,0x06,0x03,0x55,0x1d,0x20,0x04,0x3d,0x30,0x3b,0x30,0x39, +0x06,0x0b,0x60,0x86,0x48,0x01,0x86,0xf8,0x45,0x01,0x07,0x17,0x03,0x30,0x2a, +0x30,0x28,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1c,0x68, +0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76,0x65,0x72,0x69, +0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61,0x30,0x13,0x06, +0x03,0x55,0x1d,0x25,0x04,0x0c,0x30,0x0a,0x06,0x08,0x2b,0x06,0x01,0x05,0x05, +0x07,0x03,0x03,0x30,0x75,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01, +0x04,0x69,0x30,0x67,0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30, +0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e, +0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x30,0x3f,0x06, +0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x33,0x68,0x74,0x74,0x70, +0x3a,0x2f,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2d,0x61,0x69, +0x61,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f, +0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2d,0x61,0x69,0x61,0x2e,0x63, +0x65,0x72,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14, +0x08,0xf5,0x51,0xe8,0xfb,0xfe,0x3d,0x3d,0x64,0x36,0x7c,0x68,0xcf,0x5b,0x78, +0xa8,0xdf,0xb9,0xc5,0x37,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xf8, +0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x04,0x10,0x30,0x16,0x06,0x0a,0x2b,0x06, +0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x1b,0x04,0x08,0x30,0x06,0x01,0x01,0x00, +0x01,0x01,0xff,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x6a,0xa6,0x06,0xd0,0x33,0x18,0x64, +0xe2,0x69,0x82,0xee,0x6e,0x36,0x9e,0x9d,0x9a,0x0e,0x18,0xa8,0xac,0x9d,0x10, +0xed,0x01,0x3c,0xb9,0x61,0x04,0x62,0xf3,0x85,0x8f,0xcc,0x4f,0x2c,0x66,0x35, +0x54,0x25,0x45,0x8d,0x95,0x1c,0xd2,0x33,0xbe,0x2e,0xdd,0x7f,0x74,0xaf,0x03, +0x7b,0x86,0x63,0xb0,0xc9,0xe6,0xbd,0xc7,0x8e,0xde,0x03,0x18,0x98,0x82,0xc3, +0xbb,0xf8,0x15,0x99,0x1a,0xa9,0xdd,0xb9,0x5d,0xb9,0xbd,0x53,0x95,0x25,0x76, +0xfb,0x5c,0x53,0x90,0xea,0x01,0x0a,0xa0,0xb1,0xbf,0x09,0x1b,0x97,0x8f,0x40, +0xfa,0x85,0x12,0x74,0x01,0xdb,0xf6,0xdb,0x09,0xd6,0x5f,0x4f,0xd7,0x17,0xb4, +0xbf,0x9e,0x2f,0x86,0x52,0x5d,0x70,0x24,0x52,0x32,0x1e,0xa5,0x1d,0x39,0x8b, +0x66,0xf6,0xba,0x9b,0x69,0x8e,0x12,0x60,0xdb,0xb6,0xcf,0xe6,0x0d,0xd6,0x1c, +0x8f,0xd4,0x5b,0x4b,0x00,0xde,0x21,0x93,0xfb,0x6e,0xc7,0x3d,0xb4,0x66,0x0d, +0x29,0x0c,0x4e,0xe9,0x3f,0x94,0xd6,0xd6,0xdc,0xec,0xf8,0x53,0x3b,0x62,0xd5, +0x97,0x50,0x53,0x84,0x17,0xfe,0xe2,0xed,0x4c,0x23,0x0a,0x49,0xce,0x5b,0xe9, +0x70,0x31,0xc1,0x04,0x02,0x02,0x6c,0xb8,0x52,0xcd,0xc7,0x4e,0x70,0xb4,0x13, +0xd7,0xe0,0x92,0xba,0x44,0x1a,0x10,0x4c,0x6e,0x45,0xc6,0x86,0x04,0xc6,0x64, +0xd3,0x9c,0x6e,0xc1,0x9c,0xac,0x74,0x3d,0x77,0x06,0x5e,0x28,0x28,0x5c,0xf5, +0xe0,0x9c,0x19,0xd8,0xba,0x74,0x81,0x2d,0x67,0x77,0x93,0x8d,0xbf,0xd2,0x52, +0x00,0xe6,0xa5,0x38,0x4e,0x2e,0x73,0x66,0x7a }; +static const BYTE verisignCA[] = { +0x30,0x82,0x02,0x3c,0x30,0x82,0x01,0xa5,0x02,0x10,0x70,0xba,0xe4,0x1d,0x10, +0xd9,0x29,0x34,0xb6,0x38,0xca,0x7b,0x03,0xcc,0xba,0xbf,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x02,0x05,0x00,0x30,0x5f,0x31,0x0b, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15, +0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e, +0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04,0x0b, +0x13,0x2e,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6c,0x69, +0x63,0x20,0x50,0x72,0x69,0x6d,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f,0x72, +0x69,0x74,0x79,0x30,0x1e,0x17,0x0d,0x39,0x36,0x30,0x31,0x32,0x39,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x32,0x38,0x30,0x38,0x30,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5a,0x30,0x5f,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04, +0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13, +0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e, +0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04,0x0b,0x13,0x2e,0x43,0x6c,0x61,0x73, +0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6c,0x69,0x63,0x20,0x50,0x72,0x69,0x6d, +0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, +0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x30,0x81,0x9f, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00, +0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc9,0x5c,0x59,0x9e, +0xf2,0x1b,0x8a,0x01,0x14,0xb4,0x10,0xdf,0x04,0x40,0xdb,0xe3,0x57,0xaf,0x6a, +0x45,0x40,0x8f,0x84,0x0c,0x0b,0xd1,0x33,0xd9,0xd9,0x11,0xcf,0xee,0x02,0x58, +0x1f,0x25,0xf7,0x2a,0xa8,0x44,0x05,0xaa,0xec,0x03,0x1f,0x78,0x7f,0x9e,0x93, +0xb9,0x9a,0x00,0xaa,0x23,0x7d,0xd6,0xac,0x85,0xa2,0x63,0x45,0xc7,0x72,0x27, +0xcc,0xf4,0x4c,0xc6,0x75,0x71,0xd2,0x39,0xef,0x4f,0x42,0xf0,0x75,0xdf,0x0a, +0x90,0xc6,0x8e,0x20,0x6f,0x98,0x0f,0xf8,0xac,0x23,0x5f,0x70,0x29,0x36,0xa4, +0xc9,0x86,0xe7,0xb1,0x9a,0x20,0xcb,0x53,0xa5,0x85,0xe7,0x3d,0xbe,0x7d,0x9a, +0xfe,0x24,0x45,0x33,0xdc,0x76,0x15,0xed,0x0f,0xa2,0x71,0x64,0x4c,0x65,0x2e, +0x81,0x68,0x45,0xa7,0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x02,0x05,0x00,0x03,0x81,0x81,0x00,0xbb,0x4c, +0x12,0x2b,0xcf,0x2c,0x26,0x00,0x4f,0x14,0x13,0xdd,0xa6,0xfb,0xfc,0x0a,0x11, +0x84,0x8c,0xf3,0x28,0x1c,0x67,0x92,0x2f,0x7c,0xb6,0xc5,0xfa,0xdf,0xf0,0xe8, +0x95,0xbc,0x1d,0x8f,0x6c,0x2c,0xa8,0x51,0xcc,0x73,0xd8,0xa4,0xc0,0x53,0xf0, +0x4e,0xd6,0x26,0xc0,0x76,0x01,0x57,0x81,0x92,0x5e,0x21,0xf1,0xd1,0xb1,0xff, +0xe7,0xd0,0x21,0x58,0xcd,0x69,0x17,0xe3,0x44,0x1c,0x9c,0x19,0x44,0x39,0x89, +0x5c,0xdc,0x9c,0x00,0x0f,0x56,0x8d,0x02,0x99,0xed,0xa2,0x90,0x45,0x4c,0xe4, +0xbb,0x10,0xa4,0x3d,0xf0,0x32,0x03,0x0e,0xf1,0xce,0xf8,0xe8,0xc9,0x51,0x8c, +0xe6,0x62,0x9f,0xe6,0x9f,0xc0,0x7d,0xb7,0x72,0x9c,0xc9,0x36,0x3a,0x6b,0x9f, +0x4e,0xa8,0xff,0x64,0x0d,0x64 }; +/* www.google.com's cert */ +static const BYTE google[] = { +0x30,0x82,0x03,0x21,0x30,0x82,0x02,0x8a,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x01,0x2a,0x39,0x76,0x0d,0x3f,0x4f,0xc9,0x0b,0xe7,0xbd,0x2b,0xcf,0x95,0x2e, +0x7a,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x4c,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5a, +0x41,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0a,0x13,0x1c,0x54,0x68,0x61, +0x77,0x74,0x65,0x20,0x43,0x6f,0x6e,0x73,0x75,0x6c,0x74,0x69,0x6e,0x67,0x20, +0x28,0x50,0x74,0x79,0x29,0x20,0x4c,0x74,0x64,0x2e,0x31,0x16,0x30,0x14,0x06, +0x03,0x55,0x04,0x03,0x13,0x0d,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x53,0x47, +0x43,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x30,0x39,0x30,0x33,0x32,0x37,0x32, +0x32,0x32,0x30,0x30,0x37,0x5a,0x17,0x0d,0x31,0x30,0x30,0x33,0x32,0x37,0x32, +0x32,0x32,0x30,0x30,0x37,0x5a,0x30,0x68,0x31,0x0b,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08, +0x13,0x0a,0x43,0x61,0x6c,0x69,0x66,0x6f,0x72,0x6e,0x69,0x61,0x31,0x16,0x30, +0x14,0x06,0x03,0x55,0x04,0x07,0x13,0x0d,0x4d,0x6f,0x75,0x6e,0x74,0x61,0x69, +0x6e,0x20,0x56,0x69,0x65,0x77,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0a, +0x13,0x0a,0x47,0x6f,0x6f,0x67,0x6c,0x65,0x20,0x49,0x6e,0x63,0x31,0x17,0x30, +0x15,0x06,0x03,0x55,0x04,0x03,0x13,0x0e,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f, +0x67,0x6c,0x65,0x2e,0x63,0x6f,0x6d,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30, +0x81,0x89,0x02,0x81,0x81,0x00,0xd6,0xb9,0xe1,0xad,0xb8,0x61,0x0b,0x1f,0x4e, +0xb6,0x3c,0x09,0x3d,0xab,0xe8,0xe3,0x2b,0xb6,0xe8,0xa4,0x3a,0x78,0x2f,0xd3, +0x51,0x20,0x22,0x45,0x95,0xd8,0x00,0x91,0x33,0x9a,0xa7,0xa2,0x48,0xea,0x30, +0x57,0x26,0x97,0x66,0xc7,0x5a,0xef,0xf1,0x9b,0x0c,0x3f,0xe1,0xb9,0x7f,0x7b, +0xc3,0xc7,0xcc,0xaf,0x9c,0xd0,0x1f,0x3c,0x81,0x15,0x10,0x58,0xfc,0x06,0xb3, +0xbf,0xbc,0x9c,0x02,0xb9,0x51,0xdc,0xfb,0xa6,0xb9,0x17,0x42,0xe6,0x46,0xe7, +0x22,0xcf,0x6c,0x27,0x10,0xfe,0x54,0xe6,0x92,0x6c,0x0c,0x60,0x76,0x9a,0xce, +0xf8,0x7f,0xac,0xb8,0x5a,0x08,0x4a,0xdc,0xb1,0x64,0xbd,0xa0,0x74,0x41,0xb2, +0xac,0x8f,0x86,0x9d,0x1a,0xde,0x58,0x09,0xfd,0x6c,0x0a,0x25,0xe0,0x79,0x02, +0x03,0x01,0x00,0x01,0xa3,0x81,0xe7,0x30,0x81,0xe4,0x30,0x28,0x06,0x03,0x55, +0x1d,0x25,0x04,0x21,0x30,0x1f,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03, +0x01,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x09,0x60,0x86, +0x48,0x01,0x86,0xf8,0x42,0x04,0x01,0x30,0x36,0x06,0x03,0x55,0x1d,0x1f,0x04, +0x2f,0x30,0x2d,0x30,0x2b,0xa0,0x29,0xa0,0x27,0x86,0x25,0x68,0x74,0x74,0x70, +0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x74,0x68,0x61,0x77,0x74,0x65,0x2e,0x63, +0x6f,0x6d,0x2f,0x54,0x68,0x61,0x77,0x74,0x65,0x53,0x47,0x43,0x43,0x41,0x2e, +0x63,0x72,0x6c,0x30,0x72,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01, +0x04,0x66,0x30,0x64,0x30,0x22,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30, +0x01,0x86,0x16,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e, +0x74,0x68,0x61,0x77,0x74,0x65,0x2e,0x63,0x6f,0x6d,0x30,0x3e,0x06,0x08,0x2b, +0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x32,0x68,0x74,0x74,0x70,0x3a,0x2f, +0x2f,0x77,0x77,0x77,0x2e,0x74,0x68,0x61,0x77,0x74,0x65,0x2e,0x63,0x6f,0x6d, +0x2f,0x72,0x65,0x70,0x6f,0x73,0x69,0x74,0x6f,0x72,0x79,0x2f,0x54,0x68,0x61, +0x77,0x74,0x65,0x5f,0x53,0x47,0x43,0x5f,0x43,0x41,0x2e,0x63,0x72,0x74,0x30, +0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81, +0x81,0x00,0x39,0xb6,0xfb,0x11,0xbc,0x33,0x2c,0xc3,0x90,0x48,0xe3,0x6e,0xc3, +0x9b,0x38,0xb1,0x42,0xd1,0x00,0x09,0x58,0x63,0xa0,0xe1,0x98,0x1c,0x85,0xf2, +0xef,0x10,0x1d,0x60,0x4e,0x51,0x09,0x62,0xf5,0x05,0xbd,0x9d,0x4f,0x87,0x6c, +0x98,0x72,0x07,0x80,0xc3,0x59,0x48,0x14,0xe2,0xd6,0xef,0xd0,0x8f,0x33,0x6a, +0x68,0x31,0xfa,0xb7,0xbb,0x85,0xcc,0xf7,0xc7,0x47,0x7b,0x67,0x93,0x3c,0xc3, +0x16,0x51,0x9b,0x6f,0x87,0x20,0xfd,0x67,0x4c,0x2b,0xea,0x6a,0x49,0xdb,0x11, +0xd1,0xbd,0xd7,0x95,0x22,0x43,0x7a,0x06,0x7b,0x4e,0xf6,0x37,0x8e,0xa2,0xb9, +0xcf,0x1f,0xa5,0xd2,0xbd,0x3b,0x04,0x97,0x39,0xb3,0x0f,0xfa,0x38,0xb5,0xaf, +0x55,0x20,0x88,0x60,0x93,0xf2,0xde,0xdb,0xff,0xdf }; +static const BYTE thawte_sgc_ca[] = { +0x30,0x82,0x03,0x23,0x30,0x82,0x02,0x8c,0xa0,0x03,0x02,0x01,0x02,0x02,0x04, +0x30,0x00,0x00,0x02,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x05,0x05,0x00,0x30,0x5f,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06, +0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e, +0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31, +0x37,0x30,0x35,0x06,0x03,0x55,0x04,0x0b,0x13,0x2e,0x43,0x6c,0x61,0x73,0x73, +0x20,0x33,0x20,0x50,0x75,0x62,0x6c,0x69,0x63,0x20,0x50,0x72,0x69,0x6d,0x61, +0x72,0x79,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f, +0x6e,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x30,0x1e,0x17,0x0d, +0x30,0x34,0x30,0x35,0x31,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x31,0x34,0x30,0x35,0x31,0x32,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x4c, +0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x5a,0x41,0x31,0x25, +0x30,0x23,0x06,0x03,0x55,0x04,0x0a,0x13,0x1c,0x54,0x68,0x61,0x77,0x74,0x65, +0x20,0x43,0x6f,0x6e,0x73,0x75,0x6c,0x74,0x69,0x6e,0x67,0x20,0x28,0x50,0x74, +0x79,0x29,0x20,0x4c,0x74,0x64,0x2e,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04, +0x03,0x13,0x0d,0x54,0x68,0x61,0x77,0x74,0x65,0x20,0x53,0x47,0x43,0x20,0x43, +0x41,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00, +0xd4,0xd3,0x67,0xd0,0x8d,0x15,0x7f,0xae,0xcd,0x31,0xfe,0x7d,0x1d,0x91,0xa1, +0x3f,0x0b,0x71,0x3c,0xac,0xcc,0xc8,0x64,0xfb,0x63,0xfc,0x32,0x4b,0x07,0x94, +0xbd,0x6f,0x80,0xba,0x2f,0xe1,0x04,0x93,0xc0,0x33,0xfc,0x09,0x33,0x23,0xe9, +0x0b,0x74,0x2b,0x71,0xc4,0x03,0xc6,0xd2,0xcd,0xe2,0x2f,0xf5,0x09,0x63,0xcd, +0xff,0x48,0xa5,0x00,0xbf,0xe0,0xe7,0xf3,0x88,0xb7,0x2d,0x32,0xde,0x98,0x36, +0xe6,0x0a,0xad,0x00,0x7b,0xc4,0x64,0x4a,0x3b,0x84,0x75,0x03,0xf2,0x70,0x92, +0x7d,0x0e,0x62,0xf5,0x21,0xab,0x69,0x36,0x84,0x31,0x75,0x90,0xf8,0xbf,0xc7, +0x6c,0x88,0x1b,0x06,0x95,0x7c,0xc9,0xe5,0xa8,0xde,0x75,0xa1,0x2c,0x7a,0x68, +0xdf,0xd5,0xca,0x1c,0x87,0x58,0x60,0x19,0x02,0x03,0x01,0x00,0x01,0xa3,0x81, +0xfe,0x30,0x81,0xfb,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04, +0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x00,0x30,0x0b,0x06,0x03,0x55,0x1d, +0x0f,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01, +0x86,0xf8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x28,0x06,0x03, +0x55,0x1d,0x11,0x04,0x21,0x30,0x1f,0xa4,0x1d,0x30,0x1b,0x31,0x19,0x30,0x17, +0x06,0x03,0x55,0x04,0x03,0x13,0x10,0x50,0x72,0x69,0x76,0x61,0x74,0x65,0x4c, +0x61,0x62,0x65,0x6c,0x33,0x2d,0x31,0x35,0x30,0x31,0x06,0x03,0x55,0x1d,0x1f, +0x04,0x2a,0x30,0x28,0x30,0x26,0xa0,0x24,0xa0,0x22,0x86,0x20,0x68,0x74,0x74, +0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67, +0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x70,0x63,0x61,0x33,0x2e,0x63,0x72,0x6c,0x30, +0x32,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x26,0x30,0x24, +0x30,0x22,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x16,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e,0x74,0x68,0x61,0x77, +0x74,0x65,0x2e,0x63,0x6f,0x6d,0x30,0x34,0x06,0x03,0x55,0x1d,0x25,0x04,0x2d, +0x30,0x2b,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b, +0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xf8, +0x42,0x04,0x01,0x06,0x0a,0x60,0x86,0x48,0x01,0x86,0xf8,0x45,0x01,0x08,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x03,0x81,0x81,0x00,0x55,0xac,0x63,0xea,0xde,0xa1,0xdd,0xd2,0x90,0x5f,0x9f, +0x0b,0xce,0x76,0xbe,0x13,0x51,0x8f,0x93,0xd9,0x05,0x2b,0xc8,0x1b,0x77,0x4b, +0xad,0x69,0x50,0xa1,0xee,0xde,0xdc,0xfd,0xdb,0x07,0xe9,0xe8,0x39,0x94,0xdc, +0xab,0x72,0x79,0x2f,0x06,0xbf,0xab,0x81,0x70,0xc4,0xa8,0xed,0xea,0x53,0x34, +0xed,0xef,0x1e,0x53,0xd9,0x06,0xc7,0x56,0x2b,0xd1,0x5c,0xf4,0xd1,0x8a,0x8e, +0xb4,0x2b,0xb1,0x37,0x90,0x48,0x08,0x42,0x25,0xc5,0x3e,0x8a,0xcb,0x7f,0xeb, +0x6f,0x04,0xd1,0x6d,0xc5,0x74,0xa2,0xf7,0xa2,0x7c,0x7b,0x60,0x3c,0x77,0xcd, +0x0e,0xce,0x48,0x02,0x7f,0x01,0x2f,0xb6,0x9b,0x37,0xe0,0x2a,0x2a,0x36,0xdc, +0xd5,0x85,0xd6,0xac,0xe5,0x3f,0x54,0x6f,0x96,0x1e,0x05,0xaf }; +/* global_sign_root -> global_sign_ca -> openssl_org: + * "*.openssl.org"'s certificate + */ +static const BYTE global_sign_root[] = { +0x30,0x82,0x04,0x6e,0x30,0x82,0x03,0x56,0xa0,0x03,0x02,0x01,0x02,0x02,0x0b,0x04, +0x00,0x00,0x00,0x00,0x01,0x12,0x56,0xad,0x62,0x04,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x57,0x31,0x0b,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0a,0x13,0x10,0x47,0x6c,0x6f,0x62,0x61,0x6c,0x53,0x69,0x67,0x6e,0x20,0x6e,0x76, +0x2d,0x73,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x0b,0x13,0x07,0x52,0x6f, +0x6f,0x74,0x20,0x43,0x41,0x31,0x1b,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12, +0x47,0x6c,0x6f,0x62,0x61,0x6c,0x53,0x69,0x67,0x6e,0x20,0x52,0x6f,0x6f,0x74,0x20, +0x43,0x41,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x34,0x31,0x30,0x30,0x30, +0x30,0x30,0x5a,0x17,0x0d,0x31,0x34,0x30,0x31,0x32,0x37,0x31,0x31,0x30,0x30,0x30, +0x30,0x5a,0x30,0x71,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42, +0x45,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55,0x04,0x0b,0x13,0x14,0x44,0x6f,0x6d,0x61, +0x69,0x6e,0x20,0x56,0x61,0x6c,0x69,0x64,0x61,0x74,0x69,0x6f,0x6e,0x20,0x43,0x41, +0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0a,0x13,0x10,0x47,0x6c,0x6f,0x62,0x61, +0x6c,0x53,0x69,0x67,0x6e,0x20,0x6e,0x76,0x2d,0x73,0x61,0x31,0x28,0x30,0x26,0x06, +0x03,0x55,0x04,0x03,0x13,0x1f,0x47,0x6c,0x6f,0x62,0x61,0x6c,0x53,0x69,0x67,0x6e, +0x20,0x44,0x6f,0x6d,0x61,0x69,0x6e,0x20,0x56,0x61,0x6c,0x69,0x64,0x61,0x74,0x69, +0x6f,0x6e,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01, +0x0a,0x02,0x82,0x01,0x01,0x00,0xb4,0x9f,0x49,0xe6,0xb3,0x9f,0x01,0x55,0x36,0xd0, +0x36,0x95,0x6c,0xcb,0x16,0x5a,0x6c,0x72,0xb5,0xe2,0x9d,0xe2,0xfa,0x39,0xe9,0x0a, +0xdc,0x73,0x5c,0xa0,0x3b,0x76,0x6d,0x05,0x28,0x93,0x0d,0xa5,0x42,0xf3,0xe8,0xcb, +0xee,0xd3,0x33,0x1a,0x13,0x27,0x0a,0xdf,0x5c,0xd1,0x54,0x62,0x6a,0x9a,0x17,0x36, +0xd6,0x3c,0x58,0x87,0x1e,0xb2,0x66,0x1f,0x55,0x69,0x2b,0x89,0x56,0x47,0xb4,0xc2, +0x50,0x0c,0xe5,0x5d,0xc1,0xfd,0x29,0x1b,0x66,0x73,0x43,0xf4,0x6f,0xd1,0x14,0x4f, +0x2a,0x6d,0x48,0x52,0x3a,0xf5,0xe4,0x90,0x3f,0xde,0xb2,0xf4,0x10,0xd5,0xf9,0xfa, +0xac,0x96,0x0d,0x10,0x32,0x23,0xd2,0xd3,0x51,0xa7,0x95,0x85,0x50,0xfa,0x0f,0x29, +0x9d,0xa7,0x88,0x4e,0x0d,0x31,0x9b,0x44,0x41,0x8e,0x41,0x2f,0x6e,0x9a,0x1a,0xb4, +0xb6,0xa5,0x59,0xf1,0x49,0x59,0x09,0x7e,0x7e,0x49,0xd3,0x69,0x33,0x4b,0x00,0x92, +0xc5,0x1b,0x42,0x20,0x69,0xf8,0x64,0xdf,0xd8,0xa7,0x44,0xd1,0x90,0x5e,0xfd,0x39, +0xad,0x6b,0x7d,0xfe,0xd5,0x8b,0xa4,0x01,0x64,0xf6,0xa7,0xb4,0x20,0x84,0xcc,0x05, +0x2f,0x27,0xee,0x1e,0xd5,0x24,0x96,0xae,0x84,0x43,0xa4,0x3e,0x43,0xf3,0x3b,0x99, +0xd7,0xf9,0xf2,0xde,0x3d,0x19,0xed,0xd0,0x65,0xf1,0x49,0xca,0x48,0xd2,0x38,0x7d, +0xc6,0x48,0xd7,0x72,0x61,0xb8,0xc6,0xc2,0x67,0x0a,0xd8,0x65,0x5a,0xfd,0x5b,0xf3, +0xc5,0xfd,0xbe,0x8c,0x69,0xcf,0x99,0x20,0xb6,0xea,0xec,0x39,0x80,0xe9,0x66,0xa8, +0xee,0x3d,0x9d,0x46,0x7b,0x87,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0x1f,0x30, +0x82,0x01,0x1b,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03, +0x02,0x01,0x06,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30, +0x06,0x01,0x01,0xff,0x02,0x01,0x00,0x30,0x4b,0x06,0x03,0x55,0x1d,0x20,0x04,0x44, +0x30,0x42,0x30,0x40,0x06,0x09,0x2b,0x06,0x01,0x04,0x01,0xa0,0x32,0x01,0x0a,0x30, +0x33,0x30,0x31,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x25,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c, +0x73,0x69,0x67,0x6e,0x2e,0x6e,0x65,0x74,0x2f,0x72,0x65,0x70,0x6f,0x73,0x69,0x74, +0x6f,0x72,0x79,0x2f,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0x36, +0x12,0x4e,0x9e,0x71,0xc4,0x26,0x41,0xf1,0xfa,0xf1,0x29,0x4c,0xbf,0x17,0xa4,0x53, +0x28,0xb6,0xeb,0x30,0x33,0x06,0x03,0x55,0x1d,0x1f,0x04,0x2c,0x30,0x2a,0x30,0x28, +0xa0,0x26,0xa0,0x24,0x86,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c, +0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x73,0x69,0x67,0x6e,0x2e,0x6e,0x65,0x74,0x2f, +0x72,0x6f,0x6f,0x74,0x2e,0x63,0x72,0x6c,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01, +0x86,0xf8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x02,0x04,0x30,0x20,0x06,0x03,0x55, +0x1d,0x25,0x04,0x19,0x30,0x17,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a, +0x03,0x03,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xf8,0x42,0x04,0x01,0x30,0x1f,0x06, +0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x60,0x7b,0x66,0x1a,0x45,0x0d, +0x97,0xca,0x89,0x50,0x2f,0x7d,0x04,0xcd,0x34,0xa8,0xff,0xfc,0xfd,0x4b,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0xc3,0x25,0x79,0x4a,0xfa,0xcd,0x26,0x6f,0x40,0x6a,0xb8,0x94,0x1b,0xe6, +0xa0,0xe1,0x6b,0xd2,0x31,0x9a,0x3f,0x89,0xfb,0xc5,0x0a,0x22,0x75,0x7a,0xfd,0xbb, +0x40,0x34,0x9c,0xbc,0x9e,0x85,0x49,0x59,0x7a,0x95,0xcc,0x0d,0x2d,0x44,0x0b,0xc7, +0xcb,0x15,0x10,0x1e,0xd2,0xdc,0xe3,0x78,0xea,0x5f,0xf5,0x35,0x51,0xa6,0xc8,0x3f, +0x39,0x90,0x15,0x9e,0x5f,0x15,0xc9,0xb7,0x8f,0x5d,0x6b,0x63,0x99,0x68,0xe1,0x6e, +0x5c,0xfc,0x9d,0x37,0x33,0x0a,0xae,0x87,0x70,0x4a,0xa2,0xe3,0xab,0x26,0x7d,0x73, +0x07,0xe4,0xf7,0x0a,0xaa,0x75,0x8f,0xa6,0xee,0x9b,0x04,0xd1,0x05,0x43,0x74,0x1a, +0xba,0xd4,0xc2,0x9d,0x7f,0xb7,0xa0,0x6c,0xed,0x16,0x9a,0x67,0x40,0x56,0xab,0x83, +0x9f,0x4c,0x9c,0xeb,0x28,0x34,0x1f,0x8d,0xe6,0x5a,0x0f,0x69,0x40,0xd9,0xa9,0x9e, +0x6a,0xf9,0x89,0x7f,0xd0,0xf8,0x8c,0xb3,0x48,0x2e,0x0b,0x4f,0xf1,0xf9,0xcf,0xf5, +0x0e,0x11,0x02,0x0c,0x89,0x16,0x73,0x53,0x5d,0x2c,0xd3,0xef,0xde,0x5f,0x0b,0x25, +0xba,0xd5,0x4e,0x8f,0x85,0x90,0x3f,0x88,0x93,0x79,0xa5,0x20,0xac,0xff,0xb0,0x8a, +0xcb,0xcb,0xa5,0x55,0x78,0x83,0x39,0x41,0x32,0xaa,0x5d,0x25,0x93,0xa7,0xea,0xee, +0x18,0x72,0xb5,0xe2,0x1d,0x7f,0x08,0x74,0x11,0xb6,0x01,0x27,0x4e,0x96,0xcf,0xa8, +0xf0,0x2a,0xf9,0x52,0xac,0x24,0x1a,0x19,0x9e,0x9f,0x6c,0x52,0x7c,0x8b,0x3a,0xa6, +0x54,0xde,0xc1,0xc7,0x21,0x7d,0x3a,0xd3,0xbc,0x1a,0xa8,0x6d,0xf2,0xbf,0xdf,0x76, +0xca,0x03 +}; +static const BYTE global_sign_ca[] = { +0x30,0x82,0x04,0x6e,0x30,0x82,0x03,0x56,0xa0,0x03,0x02,0x01,0x02,0x02,0x0b,0x04, +0x00,0x00,0x00,0x00,0x01,0x12,0x56,0xad,0x62,0x04,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x57,0x31,0x0b,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, +0x0a,0x13,0x10,0x47,0x6c,0x6f,0x62,0x61,0x6c,0x53,0x69,0x67,0x6e,0x20,0x6e,0x76, +0x2d,0x73,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x0b,0x13,0x07,0x52,0x6f, +0x6f,0x74,0x20,0x43,0x41,0x31,0x1b,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12, +0x47,0x6c,0x6f,0x62,0x61,0x6c,0x53,0x69,0x67,0x6e,0x20,0x52,0x6f,0x6f,0x74,0x20, +0x43,0x41,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x34,0x31,0x30,0x30,0x30, +0x30,0x30,0x5a,0x17,0x0d,0x31,0x34,0x30,0x31,0x32,0x37,0x31,0x31,0x30,0x30,0x30, +0x30,0x5a,0x30,0x71,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42, +0x45,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55,0x04,0x0b,0x13,0x14,0x44,0x6f,0x6d,0x61, +0x69,0x6e,0x20,0x56,0x61,0x6c,0x69,0x64,0x61,0x74,0x69,0x6f,0x6e,0x20,0x43,0x41, +0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0a,0x13,0x10,0x47,0x6c,0x6f,0x62,0x61, +0x6c,0x53,0x69,0x67,0x6e,0x20,0x6e,0x76,0x2d,0x73,0x61,0x31,0x28,0x30,0x26,0x06, +0x03,0x55,0x04,0x03,0x13,0x1f,0x47,0x6c,0x6f,0x62,0x61,0x6c,0x53,0x69,0x67,0x6e, +0x20,0x44,0x6f,0x6d,0x61,0x69,0x6e,0x20,0x56,0x61,0x6c,0x69,0x64,0x61,0x74,0x69, +0x6f,0x6e,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01, +0x0a,0x02,0x82,0x01,0x01,0x00,0xb4,0x9f,0x49,0xe6,0xb3,0x9f,0x01,0x55,0x36,0xd0, +0x36,0x95,0x6c,0xcb,0x16,0x5a,0x6c,0x72,0xb5,0xe2,0x9d,0xe2,0xfa,0x39,0xe9,0x0a, +0xdc,0x73,0x5c,0xa0,0x3b,0x76,0x6d,0x05,0x28,0x93,0x0d,0xa5,0x42,0xf3,0xe8,0xcb, +0xee,0xd3,0x33,0x1a,0x13,0x27,0x0a,0xdf,0x5c,0xd1,0x54,0x62,0x6a,0x9a,0x17,0x36, +0xd6,0x3c,0x58,0x87,0x1e,0xb2,0x66,0x1f,0x55,0x69,0x2b,0x89,0x56,0x47,0xb4,0xc2, +0x50,0x0c,0xe5,0x5d,0xc1,0xfd,0x29,0x1b,0x66,0x73,0x43,0xf4,0x6f,0xd1,0x14,0x4f, +0x2a,0x6d,0x48,0x52,0x3a,0xf5,0xe4,0x90,0x3f,0xde,0xb2,0xf4,0x10,0xd5,0xf9,0xfa, +0xac,0x96,0x0d,0x10,0x32,0x23,0xd2,0xd3,0x51,0xa7,0x95,0x85,0x50,0xfa,0x0f,0x29, +0x9d,0xa7,0x88,0x4e,0x0d,0x31,0x9b,0x44,0x41,0x8e,0x41,0x2f,0x6e,0x9a,0x1a,0xb4, +0xb6,0xa5,0x59,0xf1,0x49,0x59,0x09,0x7e,0x7e,0x49,0xd3,0x69,0x33,0x4b,0x00,0x92, +0xc5,0x1b,0x42,0x20,0x69,0xf8,0x64,0xdf,0xd8,0xa7,0x44,0xd1,0x90,0x5e,0xfd,0x39, +0xad,0x6b,0x7d,0xfe,0xd5,0x8b,0xa4,0x01,0x64,0xf6,0xa7,0xb4,0x20,0x84,0xcc,0x05, +0x2f,0x27,0xee,0x1e,0xd5,0x24,0x96,0xae,0x84,0x43,0xa4,0x3e,0x43,0xf3,0x3b,0x99, +0xd7,0xf9,0xf2,0xde,0x3d,0x19,0xed,0xd0,0x65,0xf1,0x49,0xca,0x48,0xd2,0x38,0x7d, +0xc6,0x48,0xd7,0x72,0x61,0xb8,0xc6,0xc2,0x67,0x0a,0xd8,0x65,0x5a,0xfd,0x5b,0xf3, +0xc5,0xfd,0xbe,0x8c,0x69,0xcf,0x99,0x20,0xb6,0xea,0xec,0x39,0x80,0xe9,0x66,0xa8, +0xee,0x3d,0x9d,0x46,0x7b,0x87,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0x1f,0x30, +0x82,0x01,0x1b,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03, +0x02,0x01,0x06,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30, +0x06,0x01,0x01,0xff,0x02,0x01,0x00,0x30,0x4b,0x06,0x03,0x55,0x1d,0x20,0x04,0x44, +0x30,0x42,0x30,0x40,0x06,0x09,0x2b,0x06,0x01,0x04,0x01,0xa0,0x32,0x01,0x0a,0x30, +0x33,0x30,0x31,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x25,0x68, +0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c, +0x73,0x69,0x67,0x6e,0x2e,0x6e,0x65,0x74,0x2f,0x72,0x65,0x70,0x6f,0x73,0x69,0x74, +0x6f,0x72,0x79,0x2f,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0x36, +0x12,0x4e,0x9e,0x71,0xc4,0x26,0x41,0xf1,0xfa,0xf1,0x29,0x4c,0xbf,0x17,0xa4,0x53, +0x28,0xb6,0xeb,0x30,0x33,0x06,0x03,0x55,0x1d,0x1f,0x04,0x2c,0x30,0x2a,0x30,0x28, +0xa0,0x26,0xa0,0x24,0x86,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c, +0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x73,0x69,0x67,0x6e,0x2e,0x6e,0x65,0x74,0x2f, +0x72,0x6f,0x6f,0x74,0x2e,0x63,0x72,0x6c,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01, +0x86,0xf8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x02,0x04,0x30,0x20,0x06,0x03,0x55, +0x1d,0x25,0x04,0x19,0x30,0x17,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a, +0x03,0x03,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xf8,0x42,0x04,0x01,0x30,0x1f,0x06, +0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x60,0x7b,0x66,0x1a,0x45,0x0d, +0x97,0xca,0x89,0x50,0x2f,0x7d,0x04,0xcd,0x34,0xa8,0xff,0xfc,0xfd,0x4b,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01, +0x01,0x00,0xc3,0x25,0x79,0x4a,0xfa,0xcd,0x26,0x6f,0x40,0x6a,0xb8,0x94,0x1b,0xe6, +0xa0,0xe1,0x6b,0xd2,0x31,0x9a,0x3f,0x89,0xfb,0xc5,0x0a,0x22,0x75,0x7a,0xfd,0xbb, +0x40,0x34,0x9c,0xbc,0x9e,0x85,0x49,0x59,0x7a,0x95,0xcc,0x0d,0x2d,0x44,0x0b,0xc7, +0xcb,0x15,0x10,0x1e,0xd2,0xdc,0xe3,0x78,0xea,0x5f,0xf5,0x35,0x51,0xa6,0xc8,0x3f, +0x39,0x90,0x15,0x9e,0x5f,0x15,0xc9,0xb7,0x8f,0x5d,0x6b,0x63,0x99,0x68,0xe1,0x6e, +0x5c,0xfc,0x9d,0x37,0x33,0x0a,0xae,0x87,0x70,0x4a,0xa2,0xe3,0xab,0x26,0x7d,0x73, +0x07,0xe4,0xf7,0x0a,0xaa,0x75,0x8f,0xa6,0xee,0x9b,0x04,0xd1,0x05,0x43,0x74,0x1a, +0xba,0xd4,0xc2,0x9d,0x7f,0xb7,0xa0,0x6c,0xed,0x16,0x9a,0x67,0x40,0x56,0xab,0x83, +0x9f,0x4c,0x9c,0xeb,0x28,0x34,0x1f,0x8d,0xe6,0x5a,0x0f,0x69,0x40,0xd9,0xa9,0x9e, +0x6a,0xf9,0x89,0x7f,0xd0,0xf8,0x8c,0xb3,0x48,0x2e,0x0b,0x4f,0xf1,0xf9,0xcf,0xf5, +0x0e,0x11,0x02,0x0c,0x89,0x16,0x73,0x53,0x5d,0x2c,0xd3,0xef,0xde,0x5f,0x0b,0x25, +0xba,0xd5,0x4e,0x8f,0x85,0x90,0x3f,0x88,0x93,0x79,0xa5,0x20,0xac,0xff,0xb0,0x8a, +0xcb,0xcb,0xa5,0x55,0x78,0x83,0x39,0x41,0x32,0xaa,0x5d,0x25,0x93,0xa7,0xea,0xee, +0x18,0x72,0xb5,0xe2,0x1d,0x7f,0x08,0x74,0x11,0xb6,0x01,0x27,0x4e,0x96,0xcf,0xa8, +0xf0,0x2a,0xf9,0x52,0xac,0x24,0x1a,0x19,0x9e,0x9f,0x6c,0x52,0x7c,0x8b,0x3a,0xa6, +0x54,0xde,0xc1,0xc7,0x21,0x7d,0x3a,0xd3,0xbc,0x1a,0xa8,0x6d,0xf2,0xbf,0xdf,0x76, +0xca,0x03 +}; +static const BYTE openssl_org[] = { +0x30,0x82,0x04,0xc8,0x30,0x82,0x03,0xb0,0xa0,0x03,0x02,0x01,0x02,0x02,0x0b,0x01, +0x00,0x00,0x00,0x00,0x01,0x1c,0x57,0x8e,0x3a,0xeb,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x71,0x31,0x0b,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55,0x04, +0x0b,0x13,0x14,0x44,0x6f,0x6d,0x61,0x69,0x6e,0x20,0x56,0x61,0x6c,0x69,0x64,0x61, +0x74,0x69,0x6f,0x6e,0x20,0x43,0x41,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0a, +0x13,0x10,0x47,0x6c,0x6f,0x62,0x61,0x6c,0x53,0x69,0x67,0x6e,0x20,0x6e,0x76,0x2d, +0x73,0x61,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x03,0x13,0x1f,0x47,0x6c,0x6f, +0x62,0x61,0x6c,0x53,0x69,0x67,0x6e,0x20,0x44,0x6f,0x6d,0x61,0x69,0x6e,0x20,0x56, +0x61,0x6c,0x69,0x64,0x61,0x74,0x69,0x6f,0x6e,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d, +0x30,0x38,0x30,0x39,0x31,0x32,0x31,0x37,0x31,0x34,0x31,0x31,0x5a,0x17,0x0d,0x31, +0x31,0x30,0x39,0x31,0x33,0x31,0x37,0x31,0x34,0x30,0x36,0x5a,0x30,0x60,0x31,0x0b, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x21,0x30,0x1f,0x06, +0x03,0x55,0x04,0x0b,0x13,0x18,0x44,0x6f,0x6d,0x61,0x69,0x6e,0x20,0x43,0x6f,0x6e, +0x74,0x72,0x6f,0x6c,0x20,0x56,0x61,0x6c,0x69,0x64,0x61,0x74,0x65,0x64,0x31,0x16, +0x30,0x14,0x06,0x03,0x55,0x04,0x0a,0x14,0x0d,0x2a,0x2e,0x6f,0x70,0x65,0x6e,0x73, +0x73,0x6c,0x2e,0x6f,0x72,0x67,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x03,0x14, +0x0d,0x2a,0x2e,0x6f,0x70,0x65,0x6e,0x73,0x73,0x6c,0x2e,0x6f,0x72,0x67,0x30,0x82, +0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xb9, +0x23,0x4e,0x1d,0xb5,0xef,0x87,0xb2,0xce,0x43,0x75,0x6a,0xc3,0x11,0x1c,0xd2,0xf7, +0x32,0xf3,0xf7,0x92,0x9b,0xed,0xe6,0x86,0xc3,0xb7,0x93,0x93,0x5e,0x7d,0x32,0x6a, +0x2b,0x03,0xb7,0x2a,0xc8,0x80,0x98,0x91,0x41,0x40,0x08,0xac,0xde,0xa6,0x7a,0x7c, +0x4f,0x44,0x8b,0x9c,0xd8,0xd3,0x87,0x71,0xf2,0x4e,0x3e,0x54,0xd7,0xa4,0x11,0x81, +0xb7,0x71,0x68,0x87,0xc1,0xc9,0xaf,0x2a,0xfa,0xb2,0x74,0xa3,0x70,0xa1,0x4d,0x19, +0x06,0x8d,0x1c,0x95,0x04,0x14,0x9c,0x8f,0x1f,0xf0,0x98,0xc1,0xc0,0x70,0xfa,0xb1, +0x10,0x1d,0x77,0xda,0x80,0x14,0x53,0xa5,0x5c,0xbe,0x05,0x9a,0x43,0xf4,0x54,0xf3, +0x70,0xf4,0x71,0x39,0xea,0x50,0x9c,0xe6,0xa8,0xd0,0x78,0xa6,0x30,0x1e,0x6d,0x4d, +0x22,0x10,0xdd,0x15,0x2d,0x50,0x00,0x5d,0xd9,0xc9,0xd2,0xa6,0xb9,0xdb,0x7f,0xad, +0xd8,0xeb,0xef,0x65,0x1f,0xce,0xbb,0x8d,0x4e,0x51,0x95,0x84,0x6e,0x95,0x16,0xef, +0x0b,0xf0,0x7b,0xff,0x2d,0x6c,0x1b,0x81,0x6c,0xca,0xe0,0x25,0x3d,0x2a,0x5c,0x6f, +0xad,0xce,0x4b,0x5c,0x46,0x7c,0xb1,0xa9,0xf4,0xea,0x72,0x02,0xa1,0xcc,0x87,0x63, +0x85,0x19,0x52,0x01,0x23,0x04,0x8e,0x2a,0xb4,0x94,0xde,0x6d,0x69,0x13,0x65,0x0b, +0x70,0x5f,0x92,0x1a,0x44,0x68,0x41,0xcd,0x80,0xef,0xc9,0xe9,0x83,0xd8,0x1e,0x95, +0x86,0xc7,0x1a,0x51,0xaf,0x3d,0xaa,0xca,0x97,0x19,0xe0,0xb4,0x69,0x87,0x75,0xe1, +0x09,0x9a,0x53,0xcd,0xf5,0x43,0xcf,0x2b,0x1d,0xe7,0x81,0x20,0x1e,0x97,0x25,0x02, +0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0x70,0x30,0x82,0x01,0x6c,0x30,0x1f,0x06,0x03, +0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x36,0x12,0x4e,0x9e,0x71,0xc4,0x26, +0x41,0xf1,0xfa,0xf1,0x29,0x4c,0xbf,0x17,0xa4,0x53,0x28,0xb6,0xeb,0x30,0x49,0x06, +0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x3d,0x30,0x3b,0x30,0x39,0x06, +0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2d,0x68,0x74,0x74,0x70,0x3a, +0x2f,0x2f,0x73,0x65,0x63,0x75,0x72,0x65,0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x73, +0x69,0x67,0x6e,0x2e,0x6e,0x65,0x74,0x2f,0x63,0x61,0x63,0x65,0x72,0x74,0x2f,0x64, +0x76,0x68,0x65,0x31,0x2e,0x63,0x72,0x74,0x30,0x39,0x06,0x03,0x55,0x1d,0x1f,0x04, +0x32,0x30,0x30,0x30,0x2e,0xa0,0x2c,0xa0,0x2a,0x86,0x28,0x68,0x74,0x74,0x70,0x3a, +0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x73,0x69,0x67,0x6e, +0x2e,0x6e,0x65,0x74,0x2f,0x44,0x6f,0x6d,0x61,0x69,0x6e,0x56,0x61,0x6c,0x31,0x2e, +0x63,0x72,0x6c,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0xec,0x81, +0x7d,0x47,0xa8,0xc0,0x19,0xa7,0xbc,0x6b,0x52,0x5e,0xb6,0x90,0xfb,0x17,0xae,0x7f, +0x41,0x8f,0x30,0x09,0x06,0x03,0x55,0x1d,0x13,0x04,0x02,0x30,0x00,0x30,0x0e,0x06, +0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x04,0xf0,0x30,0x29,0x06, +0x03,0x55,0x1d,0x25,0x04,0x22,0x30,0x20,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07, +0x03,0x01,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x0a,0x2b,0x06, +0x01,0x04,0x01,0x82,0x37,0x0a,0x03,0x03,0x30,0x4b,0x06,0x03,0x55,0x1d,0x20,0x04, +0x44,0x30,0x42,0x30,0x40,0x06,0x09,0x2b,0x06,0x01,0x04,0x01,0xa0,0x32,0x01,0x0a, +0x30,0x33,0x30,0x31,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x25, +0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6c,0x6f,0x62,0x61, +0x6c,0x73,0x69,0x67,0x6e,0x2e,0x6e,0x65,0x74,0x2f,0x72,0x65,0x70,0x6f,0x73,0x69, +0x74,0x6f,0x72,0x79,0x2f,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xf8,0x42, +0x01,0x01,0x04,0x04,0x03,0x02,0x06,0xc0,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x2b,0x22,0xdd,0xa3, +0x1a,0xf9,0x12,0xee,0x77,0xbf,0x34,0xdd,0xbf,0x57,0x98,0x72,0xb3,0x05,0x8d,0x49, +0xa4,0x5d,0x55,0xec,0x08,0xf4,0x70,0xb9,0x83,0xaf,0x57,0xb2,0x0f,0x54,0x12,0xc5, +0xf4,0x0e,0x6e,0xd9,0xe4,0xd4,0x7c,0x6a,0x11,0x4a,0xd7,0xc3,0x46,0x42,0x7e,0x13, +0x4c,0x39,0x1b,0xe3,0x53,0xb1,0x8b,0x8a,0xd7,0xa2,0x74,0xcb,0x18,0x0a,0x40,0x50, +0xbe,0xbe,0x86,0x81,0xa9,0x8e,0x23,0x0b,0xa0,0x38,0x02,0x1c,0x55,0x57,0xfd,0xf7, +0x98,0x43,0x7f,0x6e,0xe9,0x26,0xc5,0x64,0x7d,0x8a,0x42,0xfb,0x67,0xbd,0x93,0x39, +0x75,0x49,0xcd,0x26,0x20,0x71,0xb4,0x65,0xca,0x04,0x15,0xfb,0x1a,0xcb,0x80,0x2e, +0x20,0x43,0x81,0x3e,0x58,0x7f,0x3f,0x2c,0x93,0x92,0x06,0x96,0x69,0xb0,0x49,0x4c, +0xd1,0xa8,0x53,0x9b,0x41,0x55,0x13,0x75,0xc3,0x51,0xe8,0x16,0x3d,0x3e,0x6f,0xbd, +0xb7,0x0c,0x49,0x48,0x64,0x97,0xb4,0x14,0x89,0x57,0x62,0x75,0x32,0x31,0xda,0x94, +0x82,0xf8,0xb3,0xc6,0x02,0x20,0x5e,0x0e,0x00,0x87,0x9c,0x0f,0x34,0x65,0xda,0xf2, +0x47,0x78,0x18,0xf5,0xd5,0xea,0xf3,0x93,0x4e,0x60,0xd6,0x6b,0x7a,0xe8,0x88,0xd7, +0x69,0x41,0xaa,0x10,0x56,0xd7,0x16,0x14,0xde,0xc9,0x1c,0xb6,0xb6,0x10,0xab,0x6b, +0x97,0xbd,0x6a,0xa9,0xb7,0x67,0xd7,0x96,0xeb,0x52,0x12,0x9e,0x9a,0x69,0xaf,0x38, +0x53,0x4d,0x99,0xd8,0x84,0xea,0x54,0xba,0x89,0x67,0xff,0x40,0x66,0x0d,0x53,0x99, +0xb6,0x65,0xba,0xf3,0x8a,0x01,0x3d,0xd0,0xf1,0x21,0x5f,0xdd +}; +/* entrust_ca -> aaa_certificate_services -> cs_stanford_edu: + * cs.stanford.edu's chain, also valid for www.cs.stanford.edu + */ +static const BYTE entrust_ca[] = { +0x30,0x82,0x04,0xd8,0x30,0x82,0x04,0x41,0xa0,0x03,0x02,0x01,0x02,0x02,0x04,0x37, +0x4a,0xd2,0x43,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xc3,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x45,0x6e,0x74, +0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04, +0x0b,0x13,0x32,0x77,0x77,0x77,0x2e,0x65,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e, +0x65,0x74,0x2f,0x43,0x50,0x53,0x20,0x69,0x6e,0x63,0x6f,0x72,0x70,0x2e,0x20,0x62, +0x79,0x20,0x72,0x65,0x66,0x2e,0x20,0x28,0x6c,0x69,0x6d,0x69,0x74,0x73,0x20,0x6c, +0x69,0x61,0x62,0x2e,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0b,0x13,0x1c, +0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6e,0x74,0x72,0x75,0x73,0x74, +0x2e,0x6e,0x65,0x74,0x20,0x4c,0x69,0x6d,0x69,0x74,0x65,0x64,0x31,0x3a,0x30,0x38, +0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e, +0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41, +0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x30,0x1e,0x17,0x0d,0x39,0x39,0x30,0x35, +0x32,0x35,0x31,0x36,0x30,0x39,0x34,0x30,0x5a,0x17,0x0d,0x31,0x39,0x30,0x35,0x32, +0x35,0x31,0x36,0x33,0x39,0x34,0x30,0x5a,0x30,0x81,0xc3,0x31,0x0b,0x30,0x09,0x06, +0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, +0x0a,0x13,0x0b,0x45,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x31,0x3b, +0x30,0x39,0x06,0x03,0x55,0x04,0x0b,0x13,0x32,0x77,0x77,0x77,0x2e,0x65,0x6e,0x74, +0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x2f,0x43,0x50,0x53,0x20,0x69,0x6e,0x63, +0x6f,0x72,0x70,0x2e,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2e,0x20,0x28,0x6c,0x69, +0x6d,0x69,0x74,0x73,0x20,0x6c,0x69,0x61,0x62,0x2e,0x29,0x31,0x25,0x30,0x23,0x06, +0x03,0x55,0x04,0x0b,0x13,0x1c,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45, +0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x20,0x4c,0x69,0x6d,0x69,0x74, +0x65,0x64,0x31,0x3a,0x30,0x38,0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6e,0x74, +0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20, +0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x69,0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x30,0x81, +0x9d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00, +0x03,0x81,0x8b,0x00,0x30,0x81,0x87,0x02,0x81,0x81,0x00,0xcd,0x28,0x83,0x34,0x54, +0x1b,0x89,0xf3,0x0f,0xaf,0x37,0x91,0x31,0xff,0xaf,0x31,0x60,0xc9,0xa8,0xe8,0xb2, +0x10,0x68,0xed,0x9f,0xe7,0x93,0x36,0xf1,0x0a,0x64,0xbb,0x47,0xf5,0x04,0x17,0x3f, +0x23,0x47,0x4d,0xc5,0x27,0x19,0x81,0x26,0x0c,0x54,0x72,0x0d,0x88,0x2d,0xd9,0x1f, +0x9a,0x12,0x9f,0xbc,0xb3,0x71,0xd3,0x80,0x19,0x3f,0x47,0x66,0x7b,0x8c,0x35,0x28, +0xd2,0xb9,0x0a,0xdf,0x24,0xda,0x9c,0xd6,0x50,0x79,0x81,0x7a,0x5a,0xd3,0x37,0xf7, +0xc2,0x4a,0xd8,0x29,0x92,0x26,0x64,0xd1,0xe4,0x98,0x6c,0x3a,0x00,0x8a,0xf5,0x34, +0x9b,0x65,0xf8,0xed,0xe3,0x10,0xff,0xfd,0xb8,0x49,0x58,0xdc,0xa0,0xde,0x82,0x39, +0x6b,0x81,0xb1,0x16,0x19,0x61,0xb9,0x54,0xb6,0xe6,0x43,0x02,0x01,0x03,0xa3,0x82, +0x01,0xd7,0x30,0x82,0x01,0xd3,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xf8, +0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x07,0x30,0x82,0x01,0x19,0x06,0x03,0x55, +0x1d,0x1f,0x04,0x82,0x01,0x10,0x30,0x82,0x01,0x0c,0x30,0x81,0xde,0xa0,0x81,0xdb, +0xa0,0x81,0xd8,0xa4,0x81,0xd5,0x30,0x81,0xd2,0x31,0x0b,0x30,0x09,0x06,0x03,0x55, +0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13, +0x0b,0x45,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x31,0x3b,0x30,0x39, +0x06,0x03,0x55,0x04,0x0b,0x13,0x32,0x77,0x77,0x77,0x2e,0x65,0x6e,0x74,0x72,0x75, +0x73,0x74,0x2e,0x6e,0x65,0x74,0x2f,0x43,0x50,0x53,0x20,0x69,0x6e,0x63,0x6f,0x72, +0x70,0x2e,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2e,0x20,0x28,0x6c,0x69,0x6d,0x69, +0x74,0x73,0x20,0x6c,0x69,0x61,0x62,0x2e,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55, +0x04,0x0b,0x13,0x1c,0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6e,0x74, +0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x20,0x4c,0x69,0x6d,0x69,0x74,0x65,0x64, +0x31,0x3a,0x30,0x38,0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6e,0x74,0x72,0x75, +0x73,0x74,0x2e,0x6e,0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65, +0x72,0x76,0x65,0x72,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69, +0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x31,0x0d,0x30,0x0b, +0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4c,0x31,0x30,0x29,0xa0,0x27,0xa0, +0x25,0x86,0x23,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x65,0x6e, +0x74,0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x2f,0x43,0x52,0x4c,0x2f,0x6e,0x65, +0x74,0x31,0x2e,0x63,0x72,0x6c,0x30,0x2b,0x06,0x03,0x55,0x1d,0x10,0x04,0x24,0x30, +0x22,0x80,0x0f,0x31,0x39,0x39,0x39,0x30,0x35,0x32,0x35,0x31,0x36,0x30,0x39,0x34, +0x30,0x5a,0x81,0x0f,0x32,0x30,0x31,0x39,0x30,0x35,0x32,0x35,0x31,0x36,0x30,0x39, +0x34,0x30,0x5a,0x30,0x0b,0x06,0x03,0x55,0x1d,0x0f,0x04,0x04,0x03,0x02,0x01,0x06, +0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xf0,0x17,0x62, +0x13,0x55,0x3d,0xb3,0xff,0x0a,0x00,0x6b,0xfb,0x50,0x84,0x97,0xf3,0xed,0x62,0xd0, +0x1a,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0xf0,0x17,0x62,0x13, +0x55,0x3d,0xb3,0xff,0x0a,0x00,0x6b,0xfb,0x50,0x84,0x97,0xf3,0xed,0x62,0xd0,0x1a, +0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x19, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf6,0x7d,0x07,0x41,0x00,0x04,0x0c,0x30,0x0a,0x1b, +0x04,0x56,0x34,0x2e,0x30,0x03,0x02,0x04,0x90,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x90,0xdc,0x30,0x02, +0xfa,0x64,0x74,0xc2,0xa7,0x0a,0xa5,0x7c,0x21,0x8d,0x34,0x17,0xa8,0xfb,0x47,0x0e, +0xff,0x25,0x7c,0x8d,0x13,0x0a,0xfb,0xe4,0x98,0xb5,0xef,0x8c,0xf8,0xc5,0x10,0x0d, +0xf7,0x92,0xbe,0xf1,0xc3,0xd5,0xd5,0x95,0x6a,0x04,0xbb,0x2c,0xce,0x26,0x36,0x65, +0xc8,0x31,0xc6,0xe7,0xee,0x3f,0xe3,0x57,0x75,0x84,0x7a,0x11,0xef,0x46,0x4f,0x18, +0xf4,0xd3,0x98,0xbb,0xa8,0x87,0x32,0xba,0x72,0xf6,0x3c,0xe2,0x3d,0x9f,0xd7,0x1d, +0xd9,0xc3,0x60,0x43,0x8c,0x58,0x0e,0x22,0x96,0x2f,0x62,0xa3,0x2c,0x1f,0xba,0xad, +0x05,0xef,0xab,0x32,0x78,0x87,0xa0,0x54,0x73,0x19,0xb5,0x5c,0x05,0xf9,0x52,0x3e, +0x6d,0x2d,0x45,0x0b,0xf7,0x0a,0x93,0xea,0xed,0x06,0xf9,0xb2 +}; +static const BYTE aaa_certificate_services[] = { +0x30,0x82,0x04,0xf9,0x30,0x82,0x04,0x62,0xa0,0x03,0x02,0x01,0x02,0x02,0x04,0x42, +0x86,0xf2,0x3d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05, +0x05,0x00,0x30,0x81,0xc3,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x45,0x6e,0x74, +0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04, +0x0b,0x13,0x32,0x77,0x77,0x77,0x2e,0x65,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e, +0x65,0x74,0x2f,0x43,0x50,0x53,0x20,0x69,0x6e,0x63,0x6f,0x72,0x70,0x2e,0x20,0x62, +0x79,0x20,0x72,0x65,0x66,0x2e,0x20,0x28,0x6c,0x69,0x6d,0x69,0x74,0x73,0x20,0x6c, +0x69,0x61,0x62,0x2e,0x29,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0b,0x13,0x1c, +0x28,0x63,0x29,0x20,0x31,0x39,0x39,0x39,0x20,0x45,0x6e,0x74,0x72,0x75,0x73,0x74, +0x2e,0x6e,0x65,0x74,0x20,0x4c,0x69,0x6d,0x69,0x74,0x65,0x64,0x31,0x3a,0x30,0x38, +0x06,0x03,0x55,0x04,0x03,0x13,0x31,0x45,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e, +0x65,0x74,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41, +0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x30,0x1e,0x17,0x0d,0x30,0x36,0x31,0x30, +0x31,0x39,0x31,0x34,0x33,0x39,0x35,0x31,0x5a,0x17,0x0d,0x31,0x32,0x31,0x30,0x31, +0x39,0x31,0x35,0x30,0x39,0x35,0x31,0x5a,0x30,0x7b,0x31,0x0b,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1b,0x30,0x19,0x06,0x03,0x55,0x04,0x08, +0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4d,0x61,0x6e,0x63,0x68,0x65, +0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53, +0x61,0x6c,0x66,0x6f,0x72,0x64,0x31,0x1a,0x30,0x18,0x06,0x03,0x55,0x04,0x0a,0x13, +0x11,0x43,0x6f,0x6d,0x6f,0x64,0x6f,0x20,0x43,0x41,0x20,0x4c,0x69,0x6d,0x69,0x74, +0x65,0x64,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x41,0x41,0x41, +0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x53,0x65,0x72, +0x76,0x69,0x63,0x65,0x73,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01, +0x0a,0x02,0x82,0x01,0x01,0x00,0xb0,0x4e,0x2e,0xd1,0x3f,0x51,0x8f,0x37,0x99,0x5d, +0x76,0x6c,0xf8,0xe1,0x23,0x02,0x93,0x44,0x2b,0x4c,0x88,0xf2,0x50,0x04,0x90,0xc6, +0xd7,0xca,0xd7,0x40,0xfe,0xcd,0x17,0xda,0x94,0x6b,0x73,0xf0,0x3d,0x0a,0x9b,0x23, +0xdd,0x98,0x18,0x07,0x62,0xa8,0x6e,0x11,0x99,0x78,0x3d,0x72,0x90,0x14,0x96,0x71, +0xfe,0xfa,0x8f,0xf5,0x03,0x84,0x8e,0xfb,0x85,0xa5,0xc5,0xe4,0xf7,0xed,0xe4,0x78, +0xbe,0xdf,0xaa,0xc7,0x9c,0xc7,0x9f,0xdf,0x21,0xdf,0x7d,0xcf,0x60,0xd4,0x70,0xbb, +0xd4,0xca,0xa6,0x5b,0xb9,0xd7,0x0e,0x6e,0x94,0x55,0x76,0x2d,0x19,0x8c,0x95,0x3a, +0x26,0x2e,0x91,0x67,0x93,0x67,0x27,0xfe,0x94,0x0a,0x48,0x62,0x9d,0x8f,0x98,0xe1, +0x25,0x63,0x4b,0xbe,0x2b,0x92,0x36,0x4f,0x11,0x48,0x39,0x66,0xe1,0xb1,0x1c,0x26, +0x35,0x56,0xe9,0x3d,0xdb,0x8e,0xff,0x1f,0x6e,0x24,0x63,0x0f,0x75,0x75,0x53,0x17, +0x48,0x5c,0x30,0x8f,0xd0,0x04,0xba,0x5e,0xc3,0xe9,0xdb,0x2f,0x1d,0x18,0x06,0x16, +0x71,0xff,0x8a,0xf6,0x99,0xc1,0x79,0x5f,0x82,0xed,0xd8,0xa0,0x2f,0x46,0x06,0xa4, +0xeb,0x29,0xe6,0x8e,0xfd,0x52,0x8d,0xbd,0x83,0x57,0xd0,0x2f,0x71,0x15,0x0e,0xcc, +0x0b,0xf6,0x8e,0xfa,0xab,0x0e,0xfa,0xa0,0xac,0x68,0x97,0xad,0xfd,0x59,0xfc,0x19, +0x13,0x33,0x7b,0x0b,0x83,0x6a,0x90,0x63,0x55,0x26,0xe7,0x78,0x05,0x8a,0xb8,0x1c, +0xef,0x75,0xc1,0xc2,0x27,0x9f,0x4e,0x97,0x04,0x29,0xd0,0x97,0xc1,0x41,0xd8,0xbc, +0x0f,0x13,0xdc,0xa2,0x58,0xb9,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xbb,0x30, +0x82,0x01,0xb7,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30, +0x06,0x01,0x01,0xff,0x02,0x01,0x00,0x30,0x1d,0x06,0x03,0x55,0x1d,0x25,0x04,0x16, +0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06, +0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04, +0x14,0x30,0x43,0xdc,0x64,0xcd,0x19,0x5c,0xa9,0xf3,0x19,0xd2,0x37,0x09,0x96,0x91, +0x9e,0x0c,0xe8,0xd6,0x3d,0x30,0x82,0x01,0x18,0x06,0x03,0x55,0x1d,0x1f,0x04,0x82, +0x01,0x0f,0x30,0x82,0x01,0x0b,0x30,0x28,0xa0,0x26,0xa0,0x24,0x86,0x22,0x68,0x74, +0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x65,0x6e,0x74,0x72,0x75,0x73,0x74, +0x2e,0x6e,0x65,0x74,0x2f,0x73,0x65,0x72,0x76,0x65,0x72,0x31,0x2e,0x63,0x72,0x6c, +0x30,0x81,0xde,0xa0,0x81,0xdb,0xa0,0x81,0xd8,0xa4,0x81,0xd5,0x30,0x81,0xd2,0x31, +0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x14,0x30,0x12, +0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x45,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e, +0x65,0x74,0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04,0x0b,0x13,0x32,0x77,0x77,0x77, +0x2e,0x65,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x2f,0x43,0x50,0x53, +0x20,0x69,0x6e,0x63,0x6f,0x72,0x70,0x2e,0x20,0x62,0x79,0x20,0x72,0x65,0x66,0x2e, +0x20,0x28,0x6c,0x69,0x6d,0x69,0x74,0x73,0x20,0x6c,0x69,0x61,0x62,0x2e,0x29,0x31, +0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0b,0x13,0x1c,0x28,0x63,0x29,0x20,0x31,0x39, +0x39,0x39,0x20,0x45,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x20,0x4c, +0x69,0x6d,0x69,0x74,0x65,0x64,0x31,0x3a,0x30,0x38,0x06,0x03,0x55,0x04,0x03,0x13, +0x31,0x45,0x6e,0x74,0x72,0x75,0x73,0x74,0x2e,0x6e,0x65,0x74,0x20,0x53,0x65,0x63, +0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x69, +0x74,0x79,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x03,0x13,0x04,0x43,0x52,0x4c, +0x31,0x30,0x0b,0x06,0x03,0x55,0x1d,0x0f,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1f, +0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xf0,0x17,0x62,0x13,0x55, +0x3d,0xb3,0xff,0x0a,0x00,0x6b,0xfb,0x50,0x84,0x97,0xf3,0xed,0x62,0xd0,0x1a,0x30, +0x19,0x06,0x09,0x2a,0x86,0x48,0x86,0xf6,0x7d,0x07,0x41,0x00,0x04,0x0c,0x30,0x0a, +0x1b,0x04,0x56,0x37,0x2e,0x31,0x03,0x02,0x00,0x81,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x54,0x80,0x38, +0xb7,0xb0,0x67,0x2a,0xdd,0xe0,0x10,0xd9,0x0b,0x16,0x65,0xf3,0x96,0x6f,0x41,0x30, +0x3e,0xdf,0xde,0xbb,0xf8,0x5a,0x36,0x51,0x31,0xd7,0x2f,0x0f,0xfa,0x5d,0x23,0x96, +0x98,0xaa,0x45,0xa0,0x18,0x0a,0x82,0x9a,0x11,0x36,0x63,0x58,0x50,0x50,0xa5,0xc1, +0xc3,0x2a,0x3e,0x1d,0xe1,0x6d,0xf6,0x7e,0x3d,0x4a,0xd3,0x99,0xce,0xfe,0xa8,0xaf, +0x0b,0x45,0xc2,0xdb,0xc2,0xb8,0xe9,0x49,0xc5,0xa1,0x62,0xed,0x75,0x66,0xe6,0xde, +0x8b,0x5b,0x73,0x70,0xfa,0x9c,0x4b,0x90,0x51,0x13,0xd7,0x48,0x98,0xc6,0x54,0x12, +0xd4,0xee,0x89,0xc7,0xc9,0xcf,0x00,0x37,0xe7,0xb3,0xd3,0x65,0x8b,0x2c,0xe7,0xf8, +0x3f,0xf1,0x0b,0xe3,0x7a,0x06,0xf9,0x29,0x7e,0xcf,0xb9,0x14,0x76 +}; +static const BYTE cs_stanford_edu[] = { +0x30,0x82,0x05,0x4b,0x30,0x82,0x04,0x33,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x48, +0xdb,0xe2,0x6b,0x07,0xd2,0x79,0x67,0x28,0x23,0xaa,0xaf,0x71,0x4b,0xff,0xc9,0x30, +0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x7b, +0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1b,0x30, +0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20, +0x4d,0x61,0x6e,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0e,0x06,0x03, +0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6c,0x66,0x6f,0x72,0x64,0x31,0x1a,0x30,0x18, +0x06,0x03,0x55,0x04,0x0a,0x13,0x11,0x43,0x6f,0x6d,0x6f,0x64,0x6f,0x20,0x43,0x41, +0x20,0x4c,0x69,0x6d,0x69,0x74,0x65,0x64,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,0x04, +0x03,0x13,0x18,0x41,0x41,0x41,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, +0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x30,0x1e,0x17,0x0d,0x30, +0x39,0x30,0x37,0x31,0x37,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x31,0x32, +0x30,0x37,0x31,0x36,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x82,0x01,0x15,0x31, +0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x41,0x31,0x0e,0x30,0x0c, +0x06,0x03,0x55,0x04,0x11,0x13,0x05,0x39,0x34,0x33,0x30,0x35,0x31,0x14,0x30,0x12, +0x06,0x03,0x55,0x04,0x08,0x13,0x0b,0x53,0x61,0x6e,0x74,0x61,0x20,0x43,0x6c,0x61, +0x72,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13,0x09,0x50,0x61,0x6c, +0x6f,0x20,0x41,0x6c,0x74,0x6f,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13, +0x0e,0x50,0x6f,0x6c,0x79,0x61,0x20,0x48,0x61,0x6c,0x6c,0x20,0x32,0x35,0x31,0x31, +0x1c,0x30,0x1a,0x06,0x03,0x55,0x04,0x0a,0x13,0x13,0x53,0x74,0x61,0x6e,0x66,0x6f, +0x72,0x64,0x20,0x55,0x6e,0x69,0x76,0x65,0x72,0x73,0x69,0x74,0x79,0x31,0x24,0x30, +0x22,0x06,0x03,0x55,0x04,0x0b,0x13,0x1b,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72, +0x20,0x53,0x63,0x69,0x65,0x6e,0x63,0x65,0x20,0x44,0x65,0x70,0x61,0x72,0x74,0x6d, +0x65,0x6e,0x74,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x0b,0x13,0x30,0x49,0x73, +0x73,0x75,0x65,0x64,0x20,0x74,0x68,0x72,0x6f,0x75,0x67,0x68,0x20,0x53,0x74,0x61, +0x6e,0x66,0x6f,0x72,0x64,0x20,0x55,0x6e,0x69,0x76,0x65,0x72,0x73,0x69,0x74,0x79, +0x20,0x45,0x2d,0x50,0x4b,0x49,0x20,0x4d,0x61,0x6e,0x61,0x67,0x65,0x72,0x31,0x1a, +0x30,0x18,0x06,0x03,0x55,0x04,0x0b,0x13,0x11,0x43,0x6f,0x6d,0x6f,0x64,0x6f,0x20, +0x49,0x6e,0x73,0x74,0x61,0x6e,0x74,0x53,0x53,0x4c,0x31,0x18,0x30,0x16,0x06,0x03, +0x55,0x04,0x03,0x13,0x0f,0x63,0x73,0x2e,0x73,0x74,0x61,0x6e,0x66,0x6f,0x72,0x64, +0x2e,0x65,0x64,0x75,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81, +0x00,0xc6,0x3a,0x6d,0xf1,0x1e,0xe4,0x69,0xb8,0x32,0xab,0xdb,0xab,0x97,0xe6,0x48, +0xfb,0xba,0xbb,0xce,0xbf,0x34,0x51,0x1b,0xbb,0x17,0x4d,0xac,0x7f,0x46,0xa7,0xe4, +0xbd,0x95,0xb5,0xd1,0x02,0x01,0xcf,0x33,0x94,0xe3,0x42,0xfe,0x50,0x9b,0x20,0xb7, +0x3e,0x49,0x28,0xba,0x34,0x61,0x35,0xa7,0x34,0x44,0x31,0x8b,0xe9,0x6e,0x35,0xd8, +0x36,0xd7,0xd4,0x2e,0x35,0xe1,0x49,0xe7,0x71,0x1f,0x39,0xbf,0x30,0xc4,0x77,0x1b, +0xdf,0xe5,0x12,0x26,0x98,0xf0,0xb1,0x8b,0x3c,0x8f,0x2d,0x18,0x27,0x57,0x62,0x5b, +0x61,0xe0,0xba,0xb0,0xdb,0x43,0xdb,0x71,0x9e,0x43,0x4d,0xc9,0xca,0x35,0x8d,0x32, +0xb4,0x1d,0x26,0x79,0xea,0x6e,0xb2,0x9b,0xb9,0x5a,0x3a,0xd3,0x54,0x09,0xcf,0xbe, +0xf5,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xb1,0x30,0x82,0x01,0xad,0x30,0x1f, +0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x30,0x43,0xdc,0x64,0xcd, +0x19,0x5c,0xa9,0xf3,0x19,0xd2,0x37,0x09,0x96,0x91,0x9e,0x0c,0xe8,0xd6,0x3d,0x30, +0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0x40,0x81,0x69,0xb7,0x41,0xa2, +0xee,0x6d,0x86,0xd0,0x85,0xb8,0x98,0xfd,0x83,0xb8,0xde,0xe9,0xa4,0x36,0x30,0x0e, +0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,0xa0,0x30,0x0c, +0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03, +0x55,0x1d,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03, +0x01,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55, +0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,0x0c,0x2b,0x06,0x01,0x04,0x01,0xb2, +0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,0x06,0x01,0x05, +0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65, +0x63,0x75,0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f, +0x43,0x50,0x53,0x30,0x7f,0x06,0x03,0x55,0x1d,0x1f,0x04,0x78,0x30,0x76,0x30,0x3a, +0xa0,0x38,0xa0,0x36,0x86,0x34,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c, +0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x41,0x41, +0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76, +0x69,0x63,0x65,0x73,0x5f,0x32,0x2e,0x63,0x72,0x6c,0x30,0x38,0xa0,0x36,0xa0,0x34, +0x86,0x32,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d, +0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x41,0x41,0x41,0x43,0x65,0x72,0x74,0x69, +0x66,0x69,0x63,0x61,0x74,0x65,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x5f,0x32, +0x2e,0x63,0x72,0x6c,0x30,0x34,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01, +0x04,0x28,0x30,0x26,0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01, +0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f, +0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x2f,0x06,0x03,0x55,0x1d, +0x11,0x04,0x28,0x30,0x26,0x82,0x0f,0x63,0x73,0x2e,0x73,0x74,0x61,0x6e,0x66,0x6f, +0x72,0x64,0x2e,0x65,0x64,0x75,0x82,0x13,0x77,0x77,0x77,0x2e,0x63,0x73,0x2e,0x73, +0x74,0x61,0x6e,0x66,0x6f,0x72,0x64,0x2e,0x65,0x64,0x75,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x48, +0xe7,0x62,0x8a,0x27,0x72,0x28,0xb1,0x7f,0x7a,0x64,0x92,0xab,0xf9,0x23,0xb3,0xfa, +0x4c,0x3e,0x82,0xe2,0x90,0x20,0x34,0xef,0x6c,0xe7,0x2b,0x2f,0x10,0xc5,0x51,0x2c, +0x33,0xea,0x42,0x11,0xa8,0x79,0x1f,0xe1,0x93,0xc2,0xcf,0xde,0x90,0x49,0xe9,0x2f, +0x1d,0xf3,0x76,0xba,0xc5,0xbe,0x5a,0x69,0xd1,0xb6,0xa5,0xeb,0x8c,0x30,0x27,0xc4, +0x7f,0x07,0x05,0x05,0xa5,0x5c,0x4a,0xd8,0x0b,0x3b,0xdd,0x4e,0x2a,0xc8,0x44,0x40, +0xe7,0xf3,0x7f,0x94,0x73,0x2a,0x51,0x4f,0x89,0x68,0x3f,0xa4,0xd2,0xf4,0xb4,0x86, +0xba,0x0d,0x00,0x21,0xc4,0x0b,0xa6,0xe9,0x47,0x22,0x82,0x49,0xc1,0x87,0x38,0x4f, +0xd5,0x12,0x4f,0xe3,0xb4,0x08,0x49,0xd4,0x15,0xd7,0xb0,0xaa,0xd0,0xae,0xb4,0x9a, +0x9f,0x57,0xb0,0x4b,0x88,0x1d,0x5c,0xb5,0xec,0x66,0x11,0x3e,0x6c,0x11,0x85,0x66, +0x9f,0x71,0xd0,0xc0,0xbd,0x0b,0xbe,0x1a,0x35,0x6f,0x9a,0x9f,0x51,0xf2,0x3b,0xab, +0x1e,0x80,0xc1,0x9c,0x16,0xf7,0xb7,0x0c,0x1e,0xef,0x5f,0xb1,0x4a,0xbf,0x3a,0xfe, +0x48,0x99,0x7c,0x45,0x45,0x35,0x49,0xe1,0x32,0xec,0x55,0x0b,0x19,0xce,0x32,0x71, +0x0c,0x76,0x5a,0xcf,0x26,0x67,0x0d,0x72,0x95,0x32,0x3e,0x6a,0x74,0xf6,0xb1,0xb3, +0xc6,0x64,0x2b,0x20,0xe5,0x96,0x3b,0x7b,0x65,0xa2,0xeb,0xc4,0xff,0x52,0xb5,0x0b, +0x7b,0x47,0x37,0x08,0xdf,0xf7,0xcf,0x08,0x6b,0x9d,0x7c,0xee,0x35,0xdb,0x01,0xf1, +0xa1,0xfa,0x43,0x10,0xd0,0xb6,0x1c,0xfa,0x2a,0x3a,0xc8,0x24,0xab,0x49,0x30 +}; + +/* chain0_0 -> chain0_1: + * A simple, valid chain + */ +static const BYTE chain0_0[] = { +0x30,0x82,0x01,0xc2,0x30,0x82,0x01,0x2d,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x73,0x87,0xdb,0x32,0x3a,0x6c,0x89,0x74,0x0f,0xda,0x07,0xd4,0x6a,0x2c,0x81, +0x59,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x82,0xcd,0x5c,0x0a, +0x9d,0x0d,0x3f,0xd1,0xd8,0x74,0xfc,0x52,0x65,0x11,0x76,0x10,0x62,0xb0,0x9a, +0xc5,0x54,0x66,0xae,0xfa,0xd5,0x66,0x36,0xcb,0x1e,0xe7,0xad,0xb9,0xfa,0x2e, +0xbb,0xb9,0x0b,0x4b,0xbf,0xe7,0x26,0x75,0x2c,0xae,0x2d,0x14,0x84,0x92,0xae, +0x56,0xdf,0x55,0x56,0xf3,0xa6,0xc5,0x21,0xa8,0x5e,0xce,0x7a,0x9d,0xff,0x7f, +0x10,0xd9,0xc3,0x05,0x52,0x86,0xdc,0x9b,0x46,0xe7,0x69,0xfb,0x1e,0xf0,0x68, +0x7d,0x34,0xd7,0xf3,0x56,0xe3,0x0a,0xf3,0xe4,0xdc,0x0f,0xd6,0x4d,0xa8,0xc5, +0xb5,0x5b,0xbf,0x0b,0x5d,0xe7,0x76,0xa1,0x56,0xc1,0xa7,0x55,0xa0,0x88,0x7f, +0x57,0x8e,0x64,0xda,0x6f,0xaa,0x9c,0xca,0x47,0xf3,0x37,0x08,0x4b,0x9a,0xdc, +0xbc,0x65,0x4d,0x9a }; +static const BYTE chain0_1[] = { +0x30,0x82,0x01,0x98,0x30,0x82,0x01,0x01,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x31,0x31,0x32, +0x32,0x31,0x38,0x35,0x32,0x30,0x37,0x5a,0x18,0x0f,0x31,0x36,0x32,0x38,0x30, +0x38,0x32,0x36,0x30,0x35,0x32,0x30,0x35,0x37,0x5a,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81, +0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda, +0xc5,0x4b,0x3f,0xe5,0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33, +0xba,0xff,0xb4,0xc6,0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c, +0xce,0x30,0xc5,0xa7,0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60, +0x16,0xde,0xc6,0x8b,0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32, +0x3b,0xb9,0xcf,0x6b,0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f, +0xb7,0x82,0x40,0xfc,0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44, +0xcb,0x53,0xac,0x85,0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc, +0x8b,0xa2,0x23,0xb2,0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38, +0xcf,0x49,0x98,0x72,0xa3,0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x3c, +0x90,0x45,0x5b,0x81,0x25,0x9d,0x7a,0x10,0x9f,0x15,0x25,0x03,0x52,0x78,0x09, +0x6f,0x62,0x66,0x78,0x01,0x69,0x6a,0x7f,0x19,0x02,0x18,0xd8,0xc0,0x89,0x2f, +0x0f,0x47,0xa7,0x17,0xc2,0xd7,0xe2,0x81,0x7e,0xea,0x54,0xd4,0xe6,0xcc,0x8f, +0x88,0x1a,0xee,0x28,0x42,0x6c,0x77,0xf5,0xec,0x8c,0x05,0xa5,0x7f,0xee,0x2e, +0x0b,0xbc,0xde,0xb0,0x71,0x2c,0x83,0x32,0xcb,0x49,0x00,0x46,0x03,0x95,0x58, +0x6c,0x57,0x0c,0x5a,0x69,0x3c,0xfa,0xbf,0x46,0x7a,0x4d,0xd0,0x23,0x77,0x23, +0xac,0x1d,0x33,0xb7,0x87,0xb4,0xc6,0x6b,0x52,0xa1,0xed,0x9a,0xb8,0x8e,0x1a, +0xcb,0xc3,0xd3,0x50,0xe0,0x0d,0x12,0x5d,0x0e,0x84,0x52,0xa5,0x12,0x76,0x6b, +0xbf,0xb8,0xbe,0x51,0xc0,0xa6,0xae }; +/* chain0_0 -> chain1_1: + * A chain whose signature is bad + */ +static const BYTE chain1_1[] = { +0x30,0x82,0x01,0x98,0x30,0x82,0x01,0x01,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x31,0x31,0x32, +0x32,0x31,0x38,0x35,0x32,0x30,0x37,0x5a,0x18,0x0f,0x31,0x36,0x32,0x38,0x30, +0x38,0x32,0x36,0x30,0x35,0x32,0x30,0x35,0x37,0x5a,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81, +0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xad,0x7e,0xca, +0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82,0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d, +0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34,0x9e,0x07,0x78,0x08,0x11,0x12,0x2d, +0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7,0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25, +0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91,0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12, +0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5,0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76, +0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd,0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe, +0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c,0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37, +0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35,0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1, +0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0xad, +0x16,0xaa,0x77,0xab,0xd5,0x1a,0x6c,0x90,0x5d,0x4e,0x61,0x49,0x89,0x6e,0x9f, +0x03,0x7b,0x4a,0x49,0xb1,0x46,0x75,0xf3,0x69,0xeb,0x96,0x13,0x3c,0x35,0xb5, +0x37,0x3b,0xc2,0x84,0x5c,0xe5,0x7c,0x46,0xf6,0x6b,0xc7,0x4e,0x72,0x91,0xf4, +0xde,0xc5,0x66,0x0f,0x2d,0x39,0xc6,0x9e,0x8e,0x25,0x4d,0x3f,0x7b,0x45,0xe1, +0xc6,0x1a,0x7e,0x28,0x83,0xf8,0x87,0x30,0x4e,0xa5,0xfd,0x32,0x7a,0xed,0x53, +0x10,0x3b,0x14,0xe5,0xf1,0x32,0x77,0xf1,0x29,0x72,0x98,0x2b,0xa3,0x17,0xd6, +0x8c,0x65,0xaa,0x3b,0x6d,0xab,0xb3,0xbe,0xfa,0x72,0x38,0xf7,0xd0,0xb6,0x0f, +0x5c,0x0d,0xec,0x17,0x43,0x2a,0xfd,0xc1,0x01,0x43,0x98,0xd3,0x1b,0x84,0x3e, +0x32,0xcf,0xda,0x1d,0xc2,0xc9,0x61 }; +/* chain2_0 -> chain0_1: + * A chain whose time nesting is invalid. + */ +static const BYTE chain2_0[] = { +0x30,0x82,0x01,0xc2,0x30,0x82,0x01,0x2d,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x11,0x58,0x73,0x34,0x62,0x2b,0xa5,0xa5,0x54,0x4a,0x14,0x48,0x3c,0x90,0x4e, +0x86,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x36,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x36,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x88,0x44,0x83,0xfc, +0x38,0xa4,0x6e,0x53,0x24,0x8f,0xac,0xcf,0xc0,0xb9,0xaa,0xdc,0x5f,0x30,0xf3, +0xc3,0x5c,0xd5,0x10,0x4e,0xb7,0x30,0x24,0x80,0xb3,0x5e,0xcb,0x6a,0xec,0x88, +0xa6,0x02,0xbd,0x37,0x97,0xcc,0x60,0x04,0x03,0xdd,0xfa,0xb0,0x4e,0xd6,0x00, +0x22,0x41,0xaa,0x2b,0x3c,0x3e,0x1f,0xcd,0xe3,0xf0,0x88,0x84,0x1c,0x00,0xc4, +0x97,0x69,0x3d,0x40,0x6d,0x33,0x8c,0xb7,0xb4,0x41,0xf3,0x28,0x00,0xa8,0xa1, +0x81,0x76,0x50,0x69,0xb2,0x2c,0xc4,0x56,0xab,0x2b,0x4a,0x77,0x41,0x3e,0x6c, +0x78,0x0b,0xf9,0x6c,0x86,0x84,0x1a,0x5a,0x0e,0x8c,0x12,0x59,0xbd,0x74,0xf3, +0xb9,0x91,0xa1,0x70,0x91,0xf3,0xe8,0x8d,0x78,0x42,0xc3,0x4f,0xfa,0xef,0xe7, +0xca,0x09,0x5c,0x18 }; +/* chain3_0 -> chain0_1: + * A chain whose root cannot be a CA. + */ +static const BYTE chain3_0[] = { +0x30,0x82,0x01,0xad,0x30,0x82,0x01,0x1a,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x63,0x73,0xee,0x45,0x59,0x76,0x1a,0x9e,0x47,0xf1,0xfb,0xf0,0x42,0x44,0x26, +0xeb,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x10,0x30,0x0e,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01, +0xff,0x04,0x02,0x30,0x00,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05, +0x00,0x03,0x81,0x81,0x00,0x53,0xb7,0xa9,0x90,0xe0,0x88,0x36,0xc0,0x2d,0xb1, +0xa3,0x97,0xff,0x16,0x62,0x29,0xa2,0xfd,0x92,0x90,0xb7,0x8d,0xd9,0xdf,0x57, +0x94,0x5a,0xce,0x36,0x5c,0x95,0x24,0xab,0x4f,0x63,0x55,0xa7,0xea,0x8b,0xaf, +0xd9,0x41,0x6a,0x2f,0xd8,0x9e,0x1c,0x2d,0xc0,0x11,0x52,0x09,0x4b,0x31,0x1f, +0x5e,0x8f,0x4b,0xbf,0x20,0x73,0x2d,0x04,0x11,0x56,0x6d,0xb1,0xbe,0xb4,0x5d, +0x70,0x6b,0xb2,0xd0,0xd3,0xf5,0x5d,0x60,0x08,0x65,0x2c,0xe3,0x78,0x5a,0x05, +0x36,0xe1,0xf1,0x67,0x3a,0x25,0xf3,0x47,0x83,0xce,0x4f,0xb0,0x74,0x7a,0x35, +0xa0,0x7f,0x70,0x64,0x8a,0x14,0x66,0x03,0xf6,0xae,0xdf,0x1b,0xf5,0x80,0x87, +0x06,0x39,0x76,0x70,0x7b,0xd2,0x83,0xe9,0xce,0x1f,0xf8,0x66,0xc1 }; +/* chain4_0 -> chain4_1 -> chain4_2: + * A chain whose path length constraint is violated. + */ +static const BYTE chain4_0[] = { +0x30,0x82,0x01,0xc5,0x30,0x82,0x01,0x30,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x01,0xcd,0x67,0x9e,0xec,0xae,0x1e,0x69,0x16,0x3f,0x92,0x8a,0xed,0x6d,0x57, +0xac,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x26,0x30,0x24,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x00,0x30,0x0b,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x70, +0x60,0x8d,0x5f,0x29,0x8e,0x6b,0x48,0x79,0xaa,0xd1,0x7a,0xbb,0x6c,0x7c,0x54, +0x11,0x55,0x08,0xb9,0x2e,0x5e,0x53,0xd6,0x9b,0xb9,0xe4,0xc8,0x0e,0x48,0xe7, +0x20,0x9e,0xbd,0x7c,0x55,0xb8,0xf1,0x69,0x0c,0x08,0xd6,0x32,0x32,0xd9,0x05, +0x81,0x8a,0x33,0x4c,0x57,0x20,0xae,0xe8,0xde,0x61,0x63,0x85,0xc8,0xe1,0x1d, +0xef,0x4b,0xa4,0x42,0x4e,0x0a,0x25,0x48,0x2b,0xc2,0x06,0x79,0x90,0x45,0x90, +0x94,0x3d,0xb0,0x36,0xe6,0x60,0xe6,0xd2,0x1a,0x11,0x01,0x4b,0xaf,0x23,0x4d, +0x62,0x6b,0xdc,0x3a,0xae,0x61,0x93,0xce,0x7b,0xae,0x21,0xfe,0x42,0xd8,0x86, +0x36,0x19,0x00,0x18,0x13,0x4d,0xf9,0xd1,0x94,0xa2,0xb7,0xbd,0xb0,0x5c,0x9b, +0x5c,0x03,0xf5,0x86,0x85,0x07,0x1c }; +static const BYTE chain4_1[] = { +0x30,0x82,0x01,0xb3,0x30,0x82,0x01,0x1e,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33,0x0e,0x67,0x5f, +0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc,0xb6,0x17,0x8e, +0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48,0x9f,0x6e,0xfe, +0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47,0xd1,0x57,0x71, +0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05,0x72,0xa7,0x87, +0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a,0x80,0x83,0x68, +0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85,0xb5,0x46,0x36, +0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3,0x51,0x9a,0x22, +0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x26,0x56,0x31,0x53, +0x65,0xe3,0xd8,0x59,0xc8,0x6f,0xa3,0x5b,0x8a,0x11,0x53,0xde,0x8d,0x6f,0x6d, +0x8c,0xe1,0x79,0x25,0xb2,0xbf,0xc6,0x3b,0xa1,0x8b,0x6b,0xcd,0x99,0xcf,0x0c, +0x6f,0xaa,0xbc,0xd0,0x3d,0xb2,0xf8,0x1c,0x6f,0xb0,0x84,0x7b,0xb1,0x88,0xec, +0xd6,0x77,0xbe,0xb1,0x0b,0x8c,0x18,0x85,0xb7,0x38,0x81,0x12,0xc9,0xc7,0x4a, +0xf6,0x83,0xc4,0xd9,0xae,0xb6,0x1d,0xbb,0xd2,0x08,0x01,0x4a,0xe1,0xdc,0x8f, +0x67,0xa9,0xed,0xe2,0x3f,0x96,0xf6,0x72,0x7e,0x4a,0x63,0x46,0xc4,0x82,0x89, +0x0a,0x81,0xc8,0x3a,0x9c,0xe7,0x23,0x5f,0x8d,0xd9,0x6c,0xb2,0x5d,0x9a,0x40, +0x04,0x04,0xd5,0x4a,0x29,0x57,0xbd,0x18,0xd8,0xca,0x1f,0xf7,0xf8,0x23,0x07, +0x4b,0x03,0xa3,0xd9 }; +static const BYTE chain4_2[] = { +0x30,0x82,0x01,0x98,0x30,0x82,0x01,0x01,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x32,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x31,0x31,0x32, +0x32,0x31,0x38,0x35,0x32,0x30,0x37,0x5a,0x18,0x0f,0x31,0x36,0x32,0x38,0x30, +0x38,0x32,0x36,0x30,0x35,0x32,0x30,0x35,0x37,0x5a,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x33,0x30,0x81, +0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc3,0x31,0x35, +0xc3,0x9d,0x8a,0x87,0x20,0xc6,0x32,0xe9,0xb1,0xf6,0x8f,0xf9,0x05,0x73,0x1d, +0xa7,0xde,0xab,0x15,0x8a,0x9c,0x7f,0x11,0x7e,0x77,0xa0,0x42,0x80,0xf4,0x79, +0xda,0x98,0x7b,0x00,0xfa,0x8f,0x0c,0xd0,0xeb,0x8a,0x80,0xed,0x07,0xfc,0x64, +0x71,0x03,0xc1,0xd6,0x2f,0x9b,0xde,0x42,0x63,0xd9,0x79,0xea,0xdd,0x10,0xe8, +0x68,0xc8,0x69,0x4f,0x4a,0x39,0x23,0x87,0xca,0xd1,0xc9,0x77,0x14,0x30,0x85, +0x9e,0xf7,0x79,0xf9,0x07,0xb7,0x7c,0x55,0xcb,0xa7,0xd5,0xb8,0x44,0xb5,0x20, +0xb5,0x01,0x5c,0xa2,0xd1,0xd5,0xad,0x0f,0x87,0xaf,0x37,0xd1,0x39,0x0c,0x0d, +0xd5,0xde,0x26,0x7a,0xed,0xf9,0x2a,0xb1,0x60,0x65,0x2d,0x08,0x24,0x51,0x1d, +0xb0,0x0a,0xb5,0x13,0xc7,0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0xaa, +0x0e,0x17,0x8d,0x5b,0xca,0x11,0xda,0x5a,0xb5,0xd4,0xe8,0x63,0xce,0xa5,0x67, +0x11,0x2f,0xf8,0xb8,0x9f,0x89,0x46,0x7d,0x20,0x94,0x5f,0x0d,0x02,0x7e,0x5e, +0x8c,0x33,0xfc,0x24,0x56,0x08,0xe6,0xf1,0x4d,0x29,0xd5,0xef,0x03,0xe3,0x9a, +0xc6,0xcd,0x6e,0xe3,0xe6,0x45,0xaa,0xce,0x5a,0x2f,0x37,0x6c,0x07,0xd2,0x28, +0x63,0x8e,0x55,0x8a,0xad,0xe3,0x8a,0x58,0x3d,0x24,0x09,0x1e,0x9a,0x7d,0x5f, +0x05,0xc4,0x51,0x18,0x17,0x46,0x33,0x4d,0x72,0x05,0xc2,0x02,0xb6,0x05,0x22, +0x23,0xcc,0xf9,0x1f,0x87,0x6c,0x4a,0x3d,0x6f,0xdb,0x59,0xf6,0x79,0x81,0x02, +0x45,0x9f,0xc8,0xc3,0xf0,0x90,0x82,0xaf,0x58,0x80,0x18,0xea,0x73,0x50,0x29, +0x71,0x8d,0xc1,0x9e,0x53,0x19,0x5a }; +/* chain5_0 -> chain5_1: + * A chain whose name constraints aren't met. + */ +static const BYTE chain5_0[] = { +0x30,0x82,0x01,0xe0,0x30,0x82,0x01,0x4b,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0xed,0xb8,0x3b,0xf2,0x95,0xe6,0x8e,0xdf,0x75,0x6a,0x22,0xbc,0xca,0x51,0xb6, +0x83,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x41,0x30,0x3f,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1c,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x12,0x30,0x10,0xa0,0x0e,0x30,0x0c,0x82,0x0a,0x77, +0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x7f,0x98,0xd1,0x58, +0x70,0x36,0x2c,0x08,0x63,0x2c,0xf9,0xe0,0x16,0xda,0x59,0xd9,0x1b,0xa5,0xba, +0xe0,0xec,0xd9,0x0a,0x1b,0x78,0xd0,0xea,0x49,0xc7,0x01,0x06,0x78,0xe5,0xb3, +0x81,0x5a,0x53,0x3d,0x9b,0x0d,0xaf,0xc8,0x04,0x57,0x15,0xee,0xfd,0x05,0x80, +0x72,0x8a,0x54,0x51,0x6a,0x15,0xdc,0xbf,0xfc,0xe3,0x04,0xe4,0x6f,0x20,0xb2, +0xfd,0xa6,0x32,0x4c,0xbc,0x1b,0x60,0xf7,0xc3,0x9c,0x5f,0x17,0x94,0xc7,0xdf, +0x9f,0xae,0xdb,0x72,0x8a,0x98,0x28,0x9d,0x26,0x1f,0x14,0x76,0xb1,0x8e,0x26, +0xf6,0x97,0x96,0x57,0x14,0x9e,0x44,0x13,0xef,0x85,0xc1,0x6f,0x38,0xda,0xf2, +0x3a,0xf6,0xad,0x0b,0x35,0xcf,0xea,0xb0,0x5a,0x9c,0x36,0x80,0x45,0x1f,0x88, +0x2f,0xff,0xb4,0xb5 }; +static const BYTE chain5_1[] = { +0x30,0x82,0x01,0xb2,0x30,0x82,0x01,0x1b,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32, +0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x1c,0x30,0x1a,0x30,0x18,0x06,0x03,0x55, +0x1d,0x07,0x01,0x01,0xff,0x04,0x0e,0x30,0x0c,0x82,0x0a,0x77,0x69,0x6e,0x65, +0x68,0x71,0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x08,0x08,0xf5,0x1c,0xca, +0x3b,0x5a,0xd7,0x45,0xac,0x29,0x5c,0x10,0x9d,0xb0,0x4a,0xdb,0x36,0x0b,0x39, +0x14,0x87,0x3d,0x06,0xe8,0x0d,0x54,0xa7,0xb9,0x50,0x14,0x29,0x05,0xd2,0x75, +0xe4,0x88,0xd8,0x8e,0x7e,0xab,0x61,0xba,0x3c,0xb2,0x4f,0x8f,0xfd,0x00,0x6b, +0x94,0x69,0xf0,0x13,0x40,0x7d,0x4e,0x7c,0xac,0xf0,0x1b,0x07,0x2c,0x96,0x46, +0xf6,0x38,0x38,0xc6,0x65,0x2c,0x02,0x28,0x62,0x6f,0x7d,0xf9,0x4d,0xff,0xb1, +0x38,0x0e,0xce,0x89,0x0e,0xdd,0x22,0x51,0xd2,0x6b,0x0e,0x80,0x3c,0xa6,0x0c, +0xe7,0x8b,0x3b,0x2a,0x2f,0x46,0xed,0xda,0x96,0x1a,0xc1,0x5c,0xfe,0xe0,0xef, +0xdb,0xe0,0x11,0xc4,0x56,0x12,0xe2,0x4b,0x84,0xde,0xaf,0x7f,0x3c,0x9f,0xcb, +0xb6,0xac,0x92 }; +/* chain0_0 -> chain4_1: + * A chain whose end certificate is a CA. + */ +/* chain0_0 -> chain 7_1: + * A chain with a bad critical extension. + */ +static const BYTE chain7_1[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x9f,0x69,0xfd,0x26,0xd5,0x4b, +0xe0,0xab,0x12,0x21,0xb9,0xfc,0xf7,0xe0,0x0c,0x09,0x94,0xad,0x27,0xd7,0x9d, +0xa3,0xcc,0x46,0x2a,0x25,0x9a,0x24,0xa7,0x31,0x58,0x78,0xf5,0xfc,0x30,0xe1, +0x6d,0xfd,0x59,0xab,0xbe,0x69,0xa0,0xea,0xe3,0x7d,0x7a,0x7b,0xe5,0x85,0xeb, +0x86,0x6a,0x84,0x3c,0x96,0x01,0x1a,0x70,0xa7,0xb8,0xcb,0xf2,0x11,0xe7,0x52, +0x9c,0x58,0x2d,0xac,0x63,0xce,0x72,0x4b,0xad,0x62,0xa8,0x1d,0x75,0x96,0xe2, +0x27,0xf5,0x6f,0xba,0x91,0xf8,0xf1,0xb0,0xbf,0x90,0x24,0x6d,0xba,0x5d,0xd7, +0x39,0x63,0x3b,0x7c,0x04,0x5d,0x89,0x9d,0x1c,0xf2,0xf7,0xcc,0xdf,0x6e,0x8a, +0x43,0xa9,0xdd,0x86,0x05,0xa2,0xf3,0x22,0x2d,0x1e,0x70,0xa1,0x59,0xd7,0xa5, +0x94,0x7d }; +/* chain8_0 -> chain8_1 -> chain8_2: + * A chain whose root cert validity time doesn't overlap the end cert's + * validity time. + */ +static const BYTE chain8_0[] = { +0x30,0x82,0x01,0xc2,0x30,0x82,0x01,0x2d,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x76,0x09,0xeb,0xc1,0x06,0x61,0x69,0x50,0x0e,0x0c,0xaf,0xc9,0x0a,0x6b,0x93, +0x50,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x30,0x36,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x87,0x74,0x4a,0xb7, +0xbe,0xd4,0x21,0xa5,0x5f,0x51,0xd6,0xea,0x89,0x4c,0x68,0x16,0x38,0x09,0x49, +0xf5,0xef,0xac,0x0c,0x59,0x27,0xa3,0x0f,0x8f,0xb9,0x21,0x35,0x91,0xef,0x15, +0x91,0xe2,0xac,0xf2,0xad,0xfe,0x05,0x9a,0x9f,0x24,0x81,0x75,0x69,0x57,0x51, +0xe3,0x2f,0x29,0xad,0x55,0x8b,0xc7,0x25,0xbe,0xcd,0x38,0xa7,0xff,0xdb,0xb0, +0x85,0x4e,0x8d,0x56,0x5a,0x79,0xf7,0x7a,0xfb,0x64,0x3d,0x4e,0x04,0x34,0xf7, +0x2f,0x7f,0xe3,0x21,0xee,0x8d,0xd3,0xb0,0x26,0x7d,0xb8,0xc3,0xb6,0x0f,0xe2, +0x3f,0xb6,0x8a,0x53,0x27,0xc0,0xe1,0xfb,0xd8,0xea,0xfe,0xed,0x80,0x51,0xb6, +0x46,0x59,0x65,0x6c,0x34,0x01,0xcc,0x2e,0x50,0xc7,0x4e,0x37,0x83,0x54,0x3f, +0x7b,0xa2,0x1d,0x3a }; +static const BYTE chain8_1[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x22,0xf1,0x66,0x00,0x79,0xd2, +0xe6,0xb2,0xb2,0xf7,0x2f,0x98,0x92,0x7d,0x73,0xc3,0x6c,0x5c,0x77,0x20,0xe3, +0xbf,0x3e,0xe0,0xb3,0x5c,0x68,0xb4,0x9b,0x3a,0x41,0xae,0x94,0xa0,0x80,0x3a, +0xfe,0x5d,0x7a,0x56,0x87,0x85,0x44,0x45,0xcf,0xa6,0xd3,0x10,0xe7,0x73,0x41, +0xf2,0x7f,0x88,0x85,0x91,0x8e,0xe6,0xec,0xe2,0xce,0x08,0xbc,0xa5,0x76,0xe5, +0x4d,0x1d,0xb7,0x70,0x31,0xdd,0xc9,0x9a,0x15,0x32,0x11,0x5a,0x4e,0x62,0xc8, +0xd1,0xf8,0xec,0x46,0x39,0x5b,0xe7,0x67,0x1f,0x58,0xe8,0xa1,0xa0,0x5b,0xf7, +0x8a,0x6d,0x5f,0x91,0x18,0xd4,0x90,0x85,0xff,0x30,0xc7,0xca,0x9c,0xc6,0x92, +0xb0,0xca,0x16,0xc4,0xa4,0xc0,0xd6,0xe8,0xff,0x15,0x19,0xd1,0x30,0x61,0xf3, +0xef,0x9f }; +static const BYTE chain8_2[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x32,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x33,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc3,0x31,0x35,0xc3,0x9d,0x8a,0x87,0x20, +0xc6,0x32,0xe9,0xb1,0xf6,0x8f,0xf9,0x05,0x73,0x1d,0xa7,0xde,0xab,0x15,0x8a, +0x9c,0x7f,0x11,0x7e,0x77,0xa0,0x42,0x80,0xf4,0x79,0xda,0x98,0x7b,0x00,0xfa, +0x8f,0x0c,0xd0,0xeb,0x8a,0x80,0xed,0x07,0xfc,0x64,0x71,0x03,0xc1,0xd6,0x2f, +0x9b,0xde,0x42,0x63,0xd9,0x79,0xea,0xdd,0x10,0xe8,0x68,0xc8,0x69,0x4f,0x4a, +0x39,0x23,0x87,0xca,0xd1,0xc9,0x77,0x14,0x30,0x85,0x9e,0xf7,0x79,0xf9,0x07, +0xb7,0x7c,0x55,0xcb,0xa7,0xd5,0xb8,0x44,0xb5,0x20,0xb5,0x01,0x5c,0xa2,0xd1, +0xd5,0xad,0x0f,0x87,0xaf,0x37,0xd1,0x39,0x0c,0x0d,0xd5,0xde,0x26,0x7a,0xed, +0xf9,0x2a,0xb1,0x60,0x65,0x2d,0x08,0x24,0x51,0x1d,0xb0,0x0a,0xb5,0x13,0xc7, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x33,0x95,0x73,0x7c,0x7c,0xb0, +0xbb,0x2b,0xe0,0xc4,0x12,0xf0,0x26,0x85,0x97,0x0c,0x81,0xde,0xc5,0x52,0x04, +0xcb,0xee,0x11,0x9a,0x2e,0xa2,0xc4,0x76,0xd5,0x57,0xd1,0x2f,0x2d,0x6f,0x42, +0xbf,0x23,0x85,0x59,0x5c,0x96,0x8d,0xef,0xbc,0xb6,0xf5,0xd3,0x66,0x99,0x54, +0x95,0x09,0x28,0x0b,0x4f,0x05,0x5f,0x61,0x20,0xa8,0x0d,0x46,0x9a,0xab,0x29, +0x97,0x6b,0xa3,0xcd,0xd7,0x5a,0xda,0xaa,0x8e,0xad,0x5a,0x66,0x58,0xf6,0x63, +0x76,0x10,0xdc,0xb0,0xee,0x3f,0x82,0x6d,0x29,0xb9,0xcb,0x99,0x15,0xbb,0xb9, +0x74,0x73,0x00,0x14,0x74,0x79,0xad,0x89,0x73,0xaa,0xa2,0x0e,0x52,0xe8,0x28, +0x69,0xe6,0x8c,0x1e,0xce,0x3a,0x6d,0x85,0x33,0x1e,0x21,0xa3,0x42,0x61,0x3a, +0xeb,0x25 }; +/* chain9_0 -> chain7_1: + * A cyclic chain. + */ +static const BYTE chain9_0[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x32,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a, +0xca,0x50,0x82,0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde, +0xc5,0xc3,0x34,0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14, +0x03,0x7a,0xe7,0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f, +0xc1,0x33,0x91,0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98, +0x1b,0x99,0xc5,0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06, +0x49,0xba,0xcd,0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45, +0x72,0xb6,0x1c,0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5, +0x1f,0x2f,0x35,0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x2c,0xf5,0x25,0xaa,0xb4,0x63, +0x5a,0x5d,0xae,0x7b,0x42,0x79,0xbc,0x41,0x2f,0x8a,0x2a,0x70,0x9f,0x8e,0xb2, +0x14,0x1b,0x6f,0xb2,0xf3,0x3e,0xab,0x06,0x9c,0xa8,0x92,0x43,0xc4,0x57,0x63, +0xa4,0xee,0x83,0x04,0xab,0xa5,0x2c,0xd9,0x90,0xed,0xc9,0x4d,0xa8,0x7b,0xca, +0x3b,0x5f,0xdf,0x46,0xe1,0x3b,0x7f,0x72,0xb7,0x92,0x82,0xe6,0x05,0xc3,0x64, +0x38,0xfb,0x86,0x13,0xeb,0x19,0xb6,0x16,0x82,0x63,0x84,0x13,0x04,0x38,0x51, +0x4c,0x89,0x12,0xf1,0x13,0x46,0x75,0x4e,0x99,0x46,0xcb,0xc6,0x76,0x9f,0x97, +0x9c,0xda,0x63,0x01,0x6a,0x71,0x68,0xc4,0x21,0x67,0xa6,0x51,0x19,0x5e,0xc7, +0x8c,0x8d,0x63,0x5c,0xbe,0x04,0x8f,0xad,0xea,0xa5,0xcd,0xc3,0xd6,0x6b,0xc7, +0xb5,0x56 }; +/* chain0_0 -+ + * +-> chain7_1 + * chain10_1 -+ + * A chain with two issuers, only one of whose dates is valid. + */ +static const BYTE chain10_1[] = { +0x30,0x82,0x01,0x9b,0x30,0x82,0x01,0x08,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0xbf,0x99,0x4f,0x14,0x03,0x77,0x44,0xb8,0x49,0x02,0x70,0xa1,0xb8,0x9c,0xa7, +0x24,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81, +0x81,0x00,0xa8,0xec,0x8c,0x34,0xe7,0x2c,0xdf,0x75,0x87,0xc4,0xf7,0xda,0x71, +0x72,0x29,0xb2,0x48,0xa8,0x2a,0xec,0x7b,0x7d,0x19,0xb9,0x5f,0x1d,0xd9,0x91, +0x2b,0xc4,0x28,0x7e,0xd6,0xb5,0x91,0x69,0xa5,0x8a,0x1a,0x1f,0x97,0x98,0x46, +0x9d,0xdf,0x12,0xf6,0x45,0x62,0xad,0x60,0xb6,0xba,0xb0,0xfd,0xf5,0x9f,0xc6, +0x98,0x05,0x4f,0x4d,0x48,0xdc,0xee,0x69,0xbe,0xb8,0xc4,0xc4,0xd7,0x1b,0xb1, +0x1f,0x64,0xd6,0x45,0xa7,0xdb,0xb3,0x87,0x63,0x0f,0x54,0xe1,0x3a,0x6b,0x57, +0x36,0xd7,0x68,0x65,0xcf,0xda,0x57,0x8d,0xcd,0x84,0x75,0x47,0x26,0x2c,0xef, +0x1e,0x8f,0xc7,0x3b,0xee,0x5d,0x03,0xa6,0xdf,0x3a,0x20,0xb2,0xcc,0xc9,0x09, +0x2c,0xfe,0x2b,0x79,0xb0,0xca,0x2c,0x9a,0x81,0x6b }; +/* chain0_0 -+ + * +-> chain7_1 + * chain11_1 -+ + * A chain with two issuers, only one of whose public keys matches the + * signature. + */ +static const BYTE chain11_1[] = { +0x30,0x82,0x01,0x9b,0x30,0x82,0x01,0x08,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x72,0x41,0xa2,0x53,0xd2,0x33,0x0b,0xac,0x4a,0x30,0xfe,0x0a,0xe0,0x2e,0xd4, +0x03,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xc3,0x31,0x35,0xc3,0x9d,0x8a,0x87,0x20,0xc6,0x32,0xe9, +0xb1,0xf6,0x8f,0xf9,0x05,0x73,0x1d,0xa7,0xde,0xab,0x15,0x8a,0x9c,0x7f,0x11, +0x7e,0x77,0xa0,0x42,0x80,0xf4,0x79,0xda,0x98,0x7b,0x00,0xfa,0x8f,0x0c,0xd0, +0xeb,0x8a,0x80,0xed,0x07,0xfc,0x64,0x71,0x03,0xc1,0xd6,0x2f,0x9b,0xde,0x42, +0x63,0xd9,0x79,0xea,0xdd,0x10,0xe8,0x68,0xc8,0x69,0x4f,0x4a,0x39,0x23,0x87, +0xca,0xd1,0xc9,0x77,0x14,0x30,0x85,0x9e,0xf7,0x79,0xf9,0x07,0xb7,0x7c,0x55, +0xcb,0xa7,0xd5,0xb8,0x44,0xb5,0x20,0xb5,0x01,0x5c,0xa2,0xd1,0xd5,0xad,0x0f, +0x87,0xaf,0x37,0xd1,0x39,0x0c,0x0d,0xd5,0xde,0x26,0x7a,0xed,0xf9,0x2a,0xb1, +0x60,0x65,0x2d,0x08,0x24,0x51,0x1d,0xb0,0x0a,0xb5,0x13,0xc7,0x02,0x03,0x01, +0x00,0x01,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81, +0x81,0x00,0x51,0x17,0xfb,0x2a,0x69,0x31,0x36,0xa7,0x37,0x2c,0x1f,0x38,0xee, +0xe3,0xf1,0xae,0x63,0x61,0xac,0x63,0x13,0xc2,0x3b,0x29,0xca,0xb1,0x8e,0x27, +0x41,0xfa,0xb3,0x7d,0x42,0xbe,0xf0,0x9c,0xe0,0xc7,0x69,0xba,0x80,0xf4,0x87, +0x7c,0x6f,0x77,0x70,0x6b,0x77,0x7d,0x5c,0x58,0x95,0x07,0xbd,0xac,0xe2,0x5d, +0x65,0x12,0xb0,0xae,0xf4,0x01,0x14,0x01,0xba,0xf9,0xa0,0x32,0x10,0xea,0x09, +0x12,0xcf,0xf1,0xbc,0x37,0xc9,0x42,0xc3,0x8c,0x9e,0xa2,0xc3,0x5e,0x2e,0x56, +0xe9,0xa7,0xd8,0x1c,0x1c,0x8c,0x1c,0x2f,0xd8,0xfb,0x67,0x44,0xd4,0xa3,0x79, +0x6d,0x53,0x17,0x56,0x3c,0x3e,0xd0,0x67,0x36,0x0c,0x8b,0x77,0xab,0x40,0xc7, +0x27,0xd9,0x44,0x69,0x13,0xeb,0x09,0xec,0x06,0xe2 }; +/* chain12_0 -> chain7_1: + * A chain whose root has an invalid signature. + */ +static const BYTE chain12_0[] = { +0x30,0x82,0x01,0xc2,0x30,0x82,0x01,0x2d,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x73,0x87,0xdb,0x32,0x3a,0x6c,0x89,0x74,0x0f,0xda,0x07,0xd4,0x6a,0x2c,0x81, +0x59,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x82,0xcd,0x5c,0x0a, +0x9d,0x0d,0x3f,0xd1,0xd8,0x74,0xfc,0x52,0x65,0x11,0x76,0x10,0x62,0xb0,0x9a, +0xc5,0x54,0x66,0xae,0xfa,0xd5,0x66,0x36,0xcb,0x1e,0xe7,0xad,0xb9,0xfa,0x2e, +0xbb,0xb9,0x0b,0x4b,0xbf,0xe7,0x26,0x75,0x2c,0xae,0x2d,0x14,0x84,0x92,0xae, +0x56,0xdf,0x55,0x56,0xf3,0xa6,0xc5,0x21,0xa8,0x5e,0xce,0x7a,0x9d,0xff,0x7f, +0x10,0xd9,0xc3,0x05,0x52,0x86,0xdc,0x9b,0x46,0xe7,0x69,0xfb,0x1e,0xf0,0x68, +0x7d,0x34,0xd7,0xf3,0x56,0xe3,0x0a,0xf3,0xe4,0xdc,0x0f,0xd6,0x4d,0xa8,0xc5, +0xb5,0x5b,0xbf,0x0b,0x5d,0xe7,0x76,0xa1,0x56,0xc1,0xa7,0x55,0xa0,0x88,0x7f, +0x57,0x8e,0x64,0xda,0x6f,0xaa,0x9c,0xca,0x47,0xf3,0x37,0x08,0x4b,0x9a,0xdc, +0xbc,0x65,0x4d,0xff }; +/* chain0_0 -> chain13_1: + * A chain whose time validity nesting is invalid. + */ +static const BYTE chain13_1[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x36,0x30,0x31,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33, +0x35,0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x85,0xc9,0xc5,0x08,0x0b,0xb1, +0xff,0x58,0x8f,0xee,0x66,0x5f,0xa3,0x77,0x63,0x9f,0xd1,0x53,0x03,0xdc,0xf6, +0x59,0x08,0x02,0x1f,0xdc,0x52,0x5a,0x52,0x38,0xa4,0x0b,0x83,0x12,0x19,0xd6, +0xb5,0xb8,0x81,0x17,0xcd,0x10,0x5d,0x96,0x16,0x9d,0x51,0x5b,0xf9,0x31,0x3e, +0x36,0xac,0x30,0xd5,0xd6,0xa0,0x30,0x5c,0x9c,0xcb,0xe1,0x02,0xfd,0x73,0xc3, +0xa1,0x58,0xfe,0x12,0xb0,0xa6,0xbd,0x11,0x86,0xdb,0x20,0x17,0x29,0x1e,0x09, +0x63,0x4d,0x28,0xe4,0x55,0x2d,0xa1,0x78,0xde,0x28,0x0b,0x1b,0x35,0x40,0x4c, +0xf1,0xb0,0x6e,0x82,0x34,0x2b,0x7f,0x3b,0x2e,0x27,0x6b,0xf7,0xde,0x73,0x9a, +0x98,0xac,0x79,0x33,0x1a,0xdd,0x03,0x95,0x60,0x8a,0x08,0xba,0xcb,0x8a,0xbf, +0xea,0xe3 }; +/* chain14_0 -> chain14_1: + * A chain whose root is allowed to sign certificates. + */ +static const BYTE chain14_0[] = { +0x30,0x82,0x01,0xc2,0x30,0x82,0x01,0x2d,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0xe0,0x3a,0xae,0xb4,0x23,0x65,0x59,0x5c,0x05,0x85,0x76,0x8b,0x8e,0x7f,0xa4, +0x12,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x10,0xb9,0x5c,0x13, +0x7f,0xe9,0xf3,0x45,0xfb,0x40,0xa2,0x2b,0xe6,0x99,0x5e,0x74,0x9a,0x0b,0x15, +0xa0,0x16,0xf2,0xff,0x6e,0xfa,0x92,0x78,0x4f,0x05,0x02,0xbd,0x70,0x4f,0x28, +0x6f,0x43,0xc7,0xaa,0xaf,0xb6,0xd1,0x60,0x77,0xc6,0x8a,0x58,0x85,0xf0,0xac, +0x04,0x90,0x4a,0x06,0xf0,0x17,0x88,0x12,0x90,0x22,0x65,0x98,0xb1,0x67,0x93, +0x8a,0xe6,0x2d,0x54,0x79,0x99,0xd3,0x8c,0xe7,0x86,0xf4,0xec,0x08,0xae,0x18, +0xa3,0xa9,0x23,0x7b,0x4f,0x8d,0xde,0xe6,0xf9,0x11,0x92,0xcf,0xe0,0x45,0xc3, +0x42,0x72,0x43,0x64,0x07,0x8b,0x7f,0x28,0x11,0x0a,0xea,0xf2,0xbd,0x24,0x1b, +0x93,0x5c,0x6f,0xed,0x67,0xae,0xee,0x7e,0x40,0x88,0x8b,0x28,0x2c,0xe7,0xee, +0xec,0x34,0xe0,0x7b }; +static const BYTE chain14_1[] = { +0x30,0x82,0x01,0x8d,0x30,0x81,0xf9,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30,0x10, +0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74, +0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30, +0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39, +0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13, +0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02, +0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33,0x0e,0x67,0x5f,0x48, +0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc,0xb6,0x17,0x8e,0x20, +0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48,0x9f,0x6e,0xfe,0xb8, +0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47,0xd1,0x57,0x71,0x3c, +0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05,0x72,0xa7,0x87,0x8e, +0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a,0x80,0x83,0x68,0x28, +0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85,0xb5,0x46,0x36,0x98, +0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3,0x51,0x9a,0x22,0x4a, +0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3,0x02,0x03,0x01,0x00, +0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03, +0x81,0x81,0x00,0x63,0x67,0x7f,0x82,0x91,0xe2,0x42,0x45,0x98,0xbc,0xe5,0x03, +0x6c,0x7d,0xc9,0xab,0xdb,0x95,0xc4,0x96,0x86,0xfd,0xcf,0xe6,0x32,0x4a,0x0b, +0x7c,0x5b,0x76,0x39,0x71,0x26,0x54,0x60,0x1d,0xce,0x4f,0x29,0x22,0x9a,0xb7, +0x7d,0x8d,0xfa,0x2c,0x99,0x0d,0xa6,0xa4,0x2e,0xd3,0xf6,0x3e,0xaf,0xea,0x89, +0xa0,0x16,0x40,0x0f,0xf1,0x50,0xaa,0x98,0xdc,0xc2,0x69,0x90,0x6f,0xc6,0x4a, +0xee,0x26,0x9e,0x5e,0x7d,0x4b,0x06,0x65,0x54,0x15,0x67,0x9e,0xe5,0x1d,0x1c, +0x6f,0x0c,0x6e,0x84,0x29,0xf9,0x12,0xe9,0x71,0xdd,0xaf,0x9a,0x3d,0x2a,0xc1, +0x60,0xeb,0x27,0xed,0x7c,0xbf,0xc4,0x84,0x17,0xa5,0xa6,0x41,0x29,0x13,0x8d, +0x6c,0xdd,0x7c,0x3d,0x01,0x03,0xf8,0x70,0x97,0x3c,0x45 }; +/* chain15_0 -> chain14_1: + * A chain whose root is not allowed to sign certificates. + */ +static const BYTE chain15_0[] = { +0x30,0x82,0x01,0xc2,0x30,0x82,0x01,0x2d,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x10,0xb3,0x62,0xed,0xed,0x4a,0x92,0xda,0x74,0x62,0x74,0x48,0x99,0xa5,0xe9, +0x0d,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x00,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x51,0x48,0x43,0xc9, +0xe3,0xb4,0xbc,0xc1,0x1d,0x98,0x14,0x69,0xd9,0xec,0x83,0x4d,0x07,0x70,0x58, +0xe9,0x45,0x88,0xe5,0x11,0x4a,0xf0,0x58,0x2d,0x8d,0x08,0x35,0x76,0x0e,0x42, +0x9f,0x62,0xda,0xf9,0x71,0x51,0x58,0xc7,0xd3,0x7e,0x88,0x6a,0x92,0xd2,0xfe, +0x86,0x4f,0xa2,0x17,0xe3,0xdd,0x9b,0x55,0xe0,0xdc,0xa7,0xe7,0x08,0xe0,0x0a, +0xa6,0xf3,0x09,0x17,0x63,0x10,0x89,0xe6,0x07,0x00,0x8e,0x2c,0x44,0x79,0x3e, +0x6c,0x51,0x9a,0xa3,0x59,0x17,0x8b,0x90,0xa8,0x82,0x64,0x09,0x77,0x95,0x55, +0xd6,0x38,0x43,0x8c,0x66,0xe6,0x7b,0xb9,0xf4,0xe1,0x7b,0x86,0x9b,0x8e,0xe3, +0x56,0xc9,0x62,0x62,0x6e,0x3d,0x4d,0x67,0x8d,0x5e,0x20,0xe5,0xd0,0xfa,0xaa, +0xbe,0x91,0xa8,0xf1 }; +/* chain0_0 -> chain16_1: + * A chain whose end cert has a name constraints extension saying it can't + * be a CA, and which also has a key usage extension allowing it to sign + * certs. + */ +static const BYTE chain16_1[] = { +0x30,0x82,0x01,0xb0,0x30,0x82,0x01,0x1b,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33,0x0e,0x67,0x5f, +0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc,0xb6,0x17,0x8e, +0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48,0x9f,0x6e,0xfe, +0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47,0xd1,0x57,0x71, +0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05,0x72,0xa7,0x87, +0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a,0x80,0x83,0x68, +0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85,0xb5,0x46,0x36, +0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3,0x51,0x9a,0x22, +0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3,0x02,0x03,0x01, +0x00,0x01,0xa3,0x20,0x30,0x1e,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x47,0xdb,0xb4,0x95,0xb1,0xe2,0x5c, +0x03,0x3b,0x28,0x16,0x6b,0xed,0xe9,0x38,0xeb,0x74,0xe6,0xde,0xc5,0xaf,0x93, +0xad,0x2e,0xaa,0x29,0x14,0x21,0xae,0xe9,0x7d,0x46,0x18,0x05,0x67,0xad,0x2d, +0xaa,0xfa,0xf8,0x41,0xc8,0x8c,0xde,0xe0,0xd7,0x3e,0x9a,0x89,0x58,0x71,0x73, +0x57,0xc1,0xd9,0x42,0x51,0xfb,0xaa,0xb8,0x50,0x98,0x9b,0x87,0xb1,0x14,0xa2, +0x23,0xa7,0xfc,0x51,0x23,0x97,0x9f,0xef,0x06,0x83,0x63,0x91,0x14,0xc3,0xbe, +0xaa,0xc8,0x7c,0x03,0x0e,0x41,0x5a,0x23,0x9c,0x1d,0x32,0x3a,0xa5,0xf1,0x6a, +0x56,0x6c,0x36,0xe3,0x3d,0xa1,0xac,0x8e,0x1a,0x75,0x30,0x1c,0xd8,0xbc,0xae, +0x3e,0x4a,0x1a,0x05,0xf4,0x09,0x24,0xb2,0x89,0x75,0xa4,0x28,0x78,0x6b,0xfa, +0xcc }; +/* chain0_0 -> chain17_1 -> chain17_2: + * A root cert, an intermediate cert that's a CA and allowed to sign a cert, + * and an end cert. + */ +static const BYTE chain17_1[] = { +0x30,0x82,0x01,0xb3,0x30,0x82,0x01,0x1e,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33,0x0e,0x67,0x5f, +0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc,0xb6,0x17,0x8e, +0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48,0x9f,0x6e,0xfe, +0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47,0xd1,0x57,0x71, +0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05,0x72,0xa7,0x87, +0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a,0x80,0x83,0x68, +0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85,0xb5,0x46,0x36, +0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3,0x51,0x9a,0x22, +0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x26,0x56,0x31,0x53, +0x65,0xe3,0xd8,0x59,0xc8,0x6f,0xa3,0x5b,0x8a,0x11,0x53,0xde,0x8d,0x6f,0x6d, +0x8c,0xe1,0x79,0x25,0xb2,0xbf,0xc6,0x3b,0xa1,0x8b,0x6b,0xcd,0x99,0xcf,0x0c, +0x6f,0xaa,0xbc,0xd0,0x3d,0xb2,0xf8,0x1c,0x6f,0xb0,0x84,0x7b,0xb1,0x88,0xec, +0xd6,0x77,0xbe,0xb1,0x0b,0x8c,0x18,0x85,0xb7,0x38,0x81,0x12,0xc9,0xc7,0x4a, +0xf6,0x83,0xc4,0xd9,0xae,0xb6,0x1d,0xbb,0xd2,0x08,0x01,0x4a,0xe1,0xdc,0x8f, +0x67,0xa9,0xed,0xe2,0x3f,0x96,0xf6,0x72,0x7e,0x4a,0x63,0x46,0xc4,0x82,0x89, +0x0a,0x81,0xc8,0x3a,0x9c,0xe7,0x23,0x5f,0x8d,0xd9,0x6c,0xb2,0x5d,0x9a,0x40, +0x04,0x04,0xd5,0x4a,0x29,0x57,0xbd,0x18,0xd8,0xca,0x1f,0xf7,0xf8,0x23,0x07, +0x4b,0x03,0xa3,0xd9 }; +static const BYTE chain17_2[] = { +0x30,0x82,0x01,0x8d,0x30,0x81,0xf9,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30,0x10, +0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74, +0x32,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30, +0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39, +0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13, +0x05,0x43,0x65,0x72,0x74,0x33,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02, +0x81,0x81,0x00,0xc3,0x31,0x35,0xc3,0x9d,0x8a,0x87,0x20,0xc6,0x32,0xe9,0xb1, +0xf6,0x8f,0xf9,0x05,0x73,0x1d,0xa7,0xde,0xab,0x15,0x8a,0x9c,0x7f,0x11,0x7e, +0x77,0xa0,0x42,0x80,0xf4,0x79,0xda,0x98,0x7b,0x00,0xfa,0x8f,0x0c,0xd0,0xeb, +0x8a,0x80,0xed,0x07,0xfc,0x64,0x71,0x03,0xc1,0xd6,0x2f,0x9b,0xde,0x42,0x63, +0xd9,0x79,0xea,0xdd,0x10,0xe8,0x68,0xc8,0x69,0x4f,0x4a,0x39,0x23,0x87,0xca, +0xd1,0xc9,0x77,0x14,0x30,0x85,0x9e,0xf7,0x79,0xf9,0x07,0xb7,0x7c,0x55,0xcb, +0xa7,0xd5,0xb8,0x44,0xb5,0x20,0xb5,0x01,0x5c,0xa2,0xd1,0xd5,0xad,0x0f,0x87, +0xaf,0x37,0xd1,0x39,0x0c,0x0d,0xd5,0xde,0x26,0x7a,0xed,0xf9,0x2a,0xb1,0x60, +0x65,0x2d,0x08,0x24,0x51,0x1d,0xb0,0x0a,0xb5,0x13,0xc7,0x02,0x03,0x01,0x00, +0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03, +0x81,0x81,0x00,0x5c,0xb5,0x55,0xd7,0x2c,0x70,0xc5,0x6e,0xc0,0x8e,0x30,0x1f, +0xf2,0x8e,0x55,0xd6,0xf6,0x95,0xa4,0x51,0xd8,0xf0,0x39,0x98,0x12,0x57,0xa7, +0x6d,0x0c,0xfd,0xcb,0x25,0xf1,0xc4,0x73,0x85,0x78,0x82,0x15,0x12,0x08,0xb6, +0x05,0x85,0x4f,0x5a,0x59,0x1f,0x03,0xdf,0x04,0xef,0xc2,0xb0,0xee,0xd7,0x73, +0x09,0xca,0xbb,0xfb,0xd8,0xec,0x8b,0x39,0x01,0x14,0xc9,0x03,0xc9,0x08,0x4d, +0x97,0xc7,0xf2,0x0b,0x54,0x67,0xf7,0x7c,0xc6,0xee,0x74,0xd5,0xa2,0x10,0x3e, +0xd9,0x3a,0x7a,0x9d,0xeb,0xeb,0xd8,0x8e,0x43,0x74,0xc3,0xa5,0x3b,0x1a,0x4b, +0x8a,0xbc,0x6a,0x2c,0x15,0x4b,0x72,0x0b,0xac,0xa4,0x1a,0x97,0x80,0xf8,0xb1, +0xd3,0xd7,0x1a,0xf3,0xf5,0x9f,0x7c,0x4c,0x7d,0x7c,0xc7 }; +/* chain0_0 -> chain18_1 -> chain18_2: + * A root, an intermediate CA not allowed to sign certs, and an end cert. + */ +static const BYTE chain18_1[] = { +0x30,0x82,0x01,0xb3,0x30,0x82,0x01,0x1e,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30, +0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72, +0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35, +0x39,0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03, +0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33,0x0e,0x67,0x5f, +0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc,0xb6,0x17,0x8e, +0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48,0x9f,0x6e,0xfe, +0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47,0xd1,0x57,0x71, +0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05,0x72,0xa7,0x87, +0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a,0x80,0x83,0x68, +0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85,0xb5,0x46,0x36, +0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3,0x51,0x9a,0x22, +0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3,0x02,0x03,0x01, +0x00,0x01,0xa3,0x23,0x30,0x21,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x00,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03,0x81,0x81,0x00,0x2c,0x49,0x9f,0xc2, +0xce,0xf5,0x0d,0x59,0xaa,0xff,0xa0,0x72,0xa7,0xcf,0x4c,0x35,0xc5,0x5e,0x1b, +0x32,0xe6,0x46,0x53,0x3e,0x70,0xe6,0xbc,0xa2,0x37,0xe0,0x9d,0x41,0x40,0x12, +0x9e,0x81,0x2b,0xd9,0x46,0x3a,0xdc,0xd7,0x37,0xc4,0xbf,0x0f,0x0c,0xf8,0x74, +0x7a,0xf9,0x92,0x2d,0xf8,0xfe,0xec,0x17,0xfb,0x38,0x4f,0x83,0x02,0x6f,0x49, +0xb4,0xad,0xb2,0x84,0x41,0x13,0x71,0x32,0xee,0x34,0x8d,0xea,0x2b,0x64,0x9b, +0x26,0x76,0xe9,0xcc,0xdf,0x73,0xe0,0x84,0xc1,0x8b,0xea,0xfc,0x8c,0x18,0x93, +0xfd,0xa3,0x5f,0x8f,0xde,0x05,0x11,0x88,0x62,0x0b,0x03,0x35,0x1a,0xef,0x65, +0x82,0x06,0xc8,0xa5,0xf6,0xd2,0x1e,0x46,0xc2,0x86,0xe7,0x26,0x8e,0x9e,0x10, +0x33,0xe2,0x89,0x93 }; +static const BYTE chain18_2[] = { +0x30,0x82,0x01,0x8d,0x30,0x81,0xf9,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x30,0x10, +0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74, +0x32,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30, +0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39, +0x35,0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13, +0x05,0x43,0x65,0x72,0x74,0x33,0x30,0x81,0x9d,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02, +0x81,0x81,0x00,0xc3,0x31,0x35,0xc3,0x9d,0x8a,0x87,0x20,0xc6,0x32,0xe9,0xb1, +0xf6,0x8f,0xf9,0x05,0x73,0x1d,0xa7,0xde,0xab,0x15,0x8a,0x9c,0x7f,0x11,0x7e, +0x77,0xa0,0x42,0x80,0xf4,0x79,0xda,0x98,0x7b,0x00,0xfa,0x8f,0x0c,0xd0,0xeb, +0x8a,0x80,0xed,0x07,0xfc,0x64,0x71,0x03,0xc1,0xd6,0x2f,0x9b,0xde,0x42,0x63, +0xd9,0x79,0xea,0xdd,0x10,0xe8,0x68,0xc8,0x69,0x4f,0x4a,0x39,0x23,0x87,0xca, +0xd1,0xc9,0x77,0x14,0x30,0x85,0x9e,0xf7,0x79,0xf9,0x07,0xb7,0x7c,0x55,0xcb, +0xa7,0xd5,0xb8,0x44,0xb5,0x20,0xb5,0x01,0x5c,0xa2,0xd1,0xd5,0xad,0x0f,0x87, +0xaf,0x37,0xd1,0x39,0x0c,0x0d,0xd5,0xde,0x26,0x7a,0xed,0xf9,0x2a,0xb1,0x60, +0x65,0x2d,0x08,0x24,0x51,0x1d,0xb0,0x0a,0xb5,0x13,0xc7,0x02,0x03,0x01,0x00, +0x01,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x03, +0x81,0x81,0x00,0x5c,0xb5,0x55,0xd7,0x2c,0x70,0xc5,0x6e,0xc0,0x8e,0x30,0x1f, +0xf2,0x8e,0x55,0xd6,0xf6,0x95,0xa4,0x51,0xd8,0xf0,0x39,0x98,0x12,0x57,0xa7, +0x6d,0x0c,0xfd,0xcb,0x25,0xf1,0xc4,0x73,0x85,0x78,0x82,0x15,0x12,0x08,0xb6, +0x05,0x85,0x4f,0x5a,0x59,0x1f,0x03,0xdf,0x04,0xef,0xc2,0xb0,0xee,0xd7,0x73, +0x09,0xca,0xbb,0xfb,0xd8,0xec,0x8b,0x39,0x01,0x14,0xc9,0x03,0xc9,0x08,0x4d, +0x97,0xc7,0xf2,0x0b,0x54,0x67,0xf7,0x7c,0xc6,0xee,0x74,0xd5,0xa2,0x10,0x3e, +0xd9,0x3a,0x7a,0x9d,0xeb,0xeb,0xd8,0x8e,0x43,0x74,0xc3,0xa5,0x3b,0x1a,0x4b, +0x8a,0xbc,0x6a,0x2c,0x15,0x4b,0x72,0x0b,0xac,0xa4,0x1a,0x97,0x80,0xf8,0xb1, +0xd3,0xd7,0x1a,0xf3,0xf5,0x9f,0x7c,0x4c,0x7d,0x7c,0xc7 }; +/* A chain which allows a.com, where the end cert is issued to a.com */ +static const BYTE chain19_0[] = { +0x30,0x82,0x01,0xd9,0x30,0x82,0x01,0x46,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x22,0xf4,0xa5,0xbe,0xe7,0x5f,0x91,0x89,0x4b,0x10,0x5c,0x86,0x89,0x94,0x36, +0xab,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3c,0x30,0x3a,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x17,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0d,0x30,0x0b,0xa0,0x09,0x30,0x07,0x82,0x05,0x61, +0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00, +0x03,0x81,0x81,0x00,0x19,0x84,0xa8,0xed,0x39,0xb3,0xc0,0x7e,0xc1,0x50,0x50, +0xb7,0x4c,0xf2,0xf4,0x16,0xc8,0x2a,0x00,0xc9,0x9e,0x0a,0x77,0x7f,0x65,0xb0, +0xe9,0x46,0x88,0x39,0x03,0xd9,0xcc,0x83,0x27,0x22,0xd3,0xec,0x98,0xb3,0x0d, +0xf6,0x85,0xe2,0x3f,0x82,0x02,0x96,0xd2,0x9f,0x17,0xcb,0x7c,0x06,0xbb,0xe5, +0x58,0x0d,0x9e,0xc3,0x01,0xcd,0xba,0xee,0x26,0x7d,0xc6,0x2b,0x50,0xa7,0xf3, +0x9e,0x28,0x87,0xa8,0x9a,0x8b,0x1c,0x73,0x79,0x3e,0xed,0xa0,0xcf,0x70,0xf0, +0x53,0x89,0x1f,0xbf,0x0d,0x6b,0x30,0xb1,0x5e,0x16,0x6d,0x57,0x81,0xe9,0xad, +0x63,0xe5,0x03,0x50,0x99,0x3d,0xb3,0xad,0x1d,0x9c,0x6b,0x32,0xea,0xc3,0x7f, +0x54,0x22,0x89,0x69,0xbf,0x73,0xdc,0x87,0xff,0x4b,0xf1,0xf6 }; +static const BYTE chain19_1[] = { +0x30,0x82,0x01,0xaa,0x30,0x82,0x01,0x13,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x14,0x30,0x12,0x30,0x10,0x06,0x03,0x55, +0x1d,0x07,0x04,0x09,0x30,0x07,0x82,0x05,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81, +0x81,0x00,0x8e,0x1d,0xf5,0xac,0x59,0x8e,0x39,0x7a,0x4d,0x79,0x79,0x68,0xa9, +0x13,0x25,0xbf,0x71,0x62,0x73,0x55,0xb0,0x22,0xcb,0x8a,0x22,0xa2,0x4f,0xa3, +0xfc,0x22,0xa3,0x2c,0x4c,0xe3,0x95,0xc6,0x97,0xe1,0x97,0xf1,0xee,0xb0,0xb4, +0xac,0x7a,0x80,0xe3,0xdd,0x02,0x5a,0x42,0x30,0xe7,0x27,0x0e,0x69,0xff,0x6b, +0xb2,0x83,0x7a,0x4f,0xc7,0xaa,0x05,0x95,0xb5,0x18,0x5f,0xa8,0x29,0x97,0x3b, +0xf2,0xb8,0x35,0x06,0x1b,0xfe,0xfa,0xa8,0x91,0xc7,0xb7,0x1b,0x8b,0xaa,0xd5, +0x23,0x88,0x7f,0xd9,0x88,0x45,0xee,0xd4,0xb9,0xcd,0x36,0xd4,0x5a,0x28,0x86, +0x0d,0x92,0x5d,0xcb,0x8c,0xf1,0xd9,0xfb,0xcc,0xa4,0x65,0xda,0x8d,0x6e,0xfd, +0x99,0xed,0xf1,0xc6,0x45,0xdf,0x5b,0x1f,0xf5,0xa0 }; +/* A chain which allows a.com, where the end cert is issued to b.com */ +static const BYTE chain20_0[] = { +0x30,0x82,0x01,0xd9,0x30,0x82,0x01,0x46,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x5e,0xf5,0xbf,0x5a,0x8d,0x92,0xd9,0x8e,0x46,0x09,0xbf,0x50,0x27,0x2f,0xc1, +0x4b,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3c,0x30,0x3a,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x17,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0d,0x30,0x0b,0xa0,0x09,0x30,0x07,0x82,0x05,0x61, +0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00, +0x03,0x81,0x81,0x00,0x4e,0xd8,0x55,0xa5,0x18,0xa8,0xc3,0xc4,0xa2,0xed,0x11, +0xff,0x12,0x78,0xbe,0xa5,0xaf,0x6c,0x9f,0xa5,0x94,0x46,0xd3,0x74,0x8e,0x44, +0x45,0x9f,0xf2,0xf9,0x0b,0xbe,0x28,0x08,0xf2,0x28,0x4a,0xd5,0x00,0x71,0xb2, +0xa5,0x01,0x3b,0x86,0xd6,0x8f,0xb8,0x9a,0xbc,0x8e,0xe4,0x33,0x9e,0xc2,0x5d, +0xcc,0x5c,0x24,0x90,0x52,0xbc,0xe6,0x83,0x38,0x77,0xd6,0x25,0x1b,0xfa,0x37, +0xc1,0xf6,0x22,0xa7,0xff,0xc6,0x4b,0x16,0x73,0xf5,0xca,0x04,0xad,0xa5,0x71, +0xff,0x15,0x5b,0x34,0x84,0xd4,0x45,0xce,0xfb,0xd1,0x76,0x13,0x2f,0x53,0x3e, +0x82,0xba,0x2f,0x53,0x82,0x48,0xcb,0x3a,0x77,0xd4,0xb0,0x0f,0xb5,0x38,0x68, +0x73,0x3f,0x49,0x60,0x0f,0x61,0x58,0xae,0x25,0xd8,0xe6,0x73 }; +static const BYTE chain20_1[] = { +0x30,0x82,0x01,0xaa,0x30,0x82,0x01,0x13,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x14,0x30,0x12,0x30,0x10,0x06,0x03,0x55, +0x1d,0x07,0x04,0x09,0x30,0x07,0x82,0x05,0x62,0x2e,0x63,0x6f,0x6d,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81, +0x81,0x00,0x17,0xbb,0xec,0x37,0x4c,0xaf,0x0f,0xb0,0x57,0x04,0x01,0x67,0x69, +0x77,0xe4,0x73,0xc4,0x12,0x0a,0xa5,0xfe,0x0c,0x8b,0x89,0x90,0x98,0x0d,0x3b, +0x37,0xbe,0xe7,0x7e,0xba,0x84,0x27,0x5f,0xed,0x40,0xc9,0x57,0x91,0x6b,0x72, +0xe3,0x4c,0xfa,0x9f,0x6d,0xd5,0xe6,0xf8,0x33,0xa1,0x6e,0xbd,0x5f,0x8d,0xfb, +0x8f,0xe6,0xe1,0x6a,0x64,0x51,0x1e,0x3b,0x04,0xe4,0x3b,0xa2,0x49,0x15,0x23, +0x35,0x17,0x61,0x4a,0xa6,0x03,0xee,0xa2,0xa6,0x4f,0x42,0x13,0x75,0x14,0xd3, +0x87,0x3b,0x71,0x6a,0x2f,0x11,0xcd,0xe6,0xd0,0x63,0xce,0x62,0x8c,0xd9,0x64, +0xc0,0xaa,0x53,0x4e,0x5e,0xa2,0x4c,0x6e,0xd0,0x13,0x49,0x2e,0xdf,0x81,0x3a, +0x3c,0x67,0xcf,0x4e,0xde,0x95,0x14,0x74,0xa8,0x31 }; +/* A chain which allows A.com, where the end cert is issued to a.COM */ +static const BYTE chain21_0[] = { +0x30,0x82,0x01,0xd9,0x30,0x82,0x01,0x46,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x66,0xaf,0x57,0xcc,0x4b,0x41,0xd1,0x96,0x40,0xef,0xa4,0xc9,0xe0,0x96,0xad, +0x5c,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3c,0x30,0x3a,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x17,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0d,0x30,0x0b,0xa0,0x09,0x30,0x07,0x82,0x05,0x41, +0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00, +0x03,0x81,0x81,0x00,0x66,0x0e,0x8e,0x3d,0x1b,0xe8,0x51,0x2d,0x5f,0xfa,0xf5, +0x01,0xb1,0xf8,0x8e,0x65,0xf6,0xcf,0x63,0x40,0x27,0x20,0x41,0xfc,0xa2,0x97, +0x14,0x8d,0x46,0x33,0x3b,0x79,0xc7,0x3d,0xc8,0x1d,0xb3,0xf1,0xf3,0x52,0xfb, +0x76,0x55,0x00,0xb9,0x4d,0x89,0x4c,0xfd,0xa9,0xcc,0xa0,0x96,0x86,0x15,0x40, +0xfc,0xd2,0x5b,0x60,0xca,0x9c,0x00,0xf8,0x02,0x6a,0x56,0x1c,0x79,0x94,0x01, +0x8a,0x60,0x44,0x1a,0x2f,0x34,0x94,0xb6,0xfb,0x00,0xa7,0xd1,0x47,0xd8,0x8f, +0xf7,0xf5,0xfc,0xfd,0xeb,0xf7,0xa1,0xab,0xa7,0x38,0x13,0x16,0x50,0x04,0x8e, +0xf2,0x17,0x45,0xac,0x10,0x83,0x08,0x1c,0x0d,0xe9,0xa9,0xea,0x4e,0x0e,0x06, +0x09,0xca,0xb3,0x54,0xd1,0x44,0x10,0x47,0xac,0xaf,0xbc,0xbb }; +static const BYTE chain21_1[] = { +0x30,0x82,0x01,0xaa,0x30,0x82,0x01,0x13,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x14,0x30,0x12,0x30,0x10,0x06,0x03,0x55, +0x1d,0x07,0x04,0x09,0x30,0x07,0x82,0x05,0x61,0x2e,0x43,0x4f,0x4d,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81, +0x81,0x00,0x65,0xd5,0xaa,0x17,0x1f,0xa8,0xda,0x62,0x04,0x9d,0xf5,0xe0,0x82, +0xe4,0xed,0xc6,0x1b,0x54,0x8f,0xb7,0x46,0xac,0xcd,0xaf,0xaa,0xe3,0xd8,0x4a, +0x8b,0xd9,0xe6,0x87,0x4f,0x8c,0xa6,0x86,0x97,0x75,0x08,0x42,0xf1,0xed,0x3e, +0x70,0x99,0x13,0xf2,0x00,0xf8,0xcc,0xf4,0x55,0x36,0xf5,0x29,0x97,0x47,0x71, +0xb8,0x40,0x8d,0x47,0x03,0xe2,0x66,0x3c,0x00,0x01,0xcc,0xa7,0x39,0xf7,0xf9, +0x76,0xfc,0x14,0x31,0x1f,0x6f,0xf0,0x87,0xe0,0x43,0x8b,0xad,0x98,0xa2,0xe3, +0xfe,0x49,0xa3,0x1e,0x57,0x34,0xe8,0x61,0x97,0x23,0xc8,0x03,0x05,0xa4,0x2f, +0xab,0x49,0x97,0xff,0x3f,0xbf,0x6c,0x08,0x2c,0x6b,0x4d,0x6a,0x54,0x62,0x2e, +0x16,0x83,0xac,0xdd,0x21,0x8f,0xe7,0x71,0x12,0x5f }; +/* A chain which allows A.com, where the end cert is issued to b.COM */ +static const BYTE chain22_0[] = { +0x30,0x82,0x01,0xd9,0x30,0x82,0x01,0x46,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x75,0xff,0x32,0x4c,0x24,0xbb,0x4e,0xb9,0x45,0x70,0xc3,0x4a,0xe1,0xfd,0xdb, +0xdc,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3c,0x30,0x3a,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x17,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0d,0x30,0x0b,0xa0,0x09,0x30,0x07,0x82,0x05,0x41, +0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00, +0x03,0x81,0x81,0x00,0x43,0x9b,0xcf,0x0d,0x31,0x9a,0x33,0x9d,0x7a,0xf8,0x2b, +0x5a,0x6f,0x52,0x68,0x25,0x7e,0x14,0x04,0xb1,0x88,0x90,0xa3,0xa8,0x4e,0xa8, +0x0c,0xc2,0x06,0x35,0x6c,0xb9,0x07,0x9a,0x28,0xd0,0x54,0xad,0x5f,0xc7,0x5e, +0xbf,0x1d,0xde,0x3d,0x76,0x6d,0x32,0x6c,0xc2,0x95,0x26,0x8e,0x6a,0xc5,0xfd, +0x45,0x47,0x3a,0x2e,0x81,0x47,0x37,0xf9,0xe3,0xdb,0x57,0xd5,0x24,0xe9,0x10, +0x91,0x55,0xbf,0x48,0xaa,0x27,0x7a,0x32,0xc8,0x96,0xbc,0xd8,0x9d,0xb5,0x03, +0x6e,0x64,0x50,0xa6,0x9d,0xc2,0xd9,0xdb,0x67,0x8d,0xad,0x76,0x82,0x75,0x42, +0x78,0x38,0x3c,0x31,0x55,0x1e,0x8f,0xbb,0x18,0xc9,0xf3,0xa4,0x49,0xc7,0x24, +0x1a,0x9b,0xef,0x61,0x03,0x75,0xb7,0x2b,0x8b,0xd4,0x50,0x8b }; +static const BYTE chain22_1[] = { +0x30,0x82,0x01,0xaa,0x30,0x82,0x01,0x13,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x14,0x30,0x12,0x30,0x10,0x06,0x03,0x55, +0x1d,0x07,0x04,0x09,0x30,0x07,0x82,0x05,0x62,0x2e,0x43,0x4f,0x4d,0x30,0x0d, +0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81, +0x81,0x00,0x4b,0x4c,0x2f,0x68,0xd2,0x64,0x82,0x7d,0x95,0x1d,0xd0,0x2b,0xa4, +0xab,0xc3,0x9d,0xd8,0xc1,0x0f,0xaa,0x3e,0xc6,0xa3,0x11,0x9a,0xc6,0x58,0x40, +0x49,0xcc,0x92,0x8e,0xd4,0x0d,0x20,0x81,0x65,0x59,0xca,0x7d,0x54,0xce,0xd4, +0x43,0x95,0xb5,0xc3,0x8c,0x79,0x01,0xc6,0x17,0xf8,0x04,0x13,0xf7,0x7c,0xf7, +0x7f,0xd7,0xc6,0x62,0x2c,0x21,0x0d,0xab,0x79,0x82,0xd7,0x70,0x9f,0x38,0xba, +0x5f,0x2f,0xb4,0xfd,0xe8,0x62,0x40,0xe3,0x69,0xe7,0xc4,0xe5,0x5a,0xc1,0x71, +0xc0,0x9a,0xdc,0xcc,0xa6,0x0e,0x5e,0x84,0x27,0x70,0xc3,0x47,0x98,0x72,0x89, +0xf9,0x7c,0xe4,0x15,0x4b,0x4c,0xec,0x56,0x1b,0xbf,0x6c,0xf1,0xf7,0x5a,0x76, +0x80,0x1f,0x43,0x7c,0xae,0xdb,0xb3,0x49,0xbc,0xcb }; +/* A chain which allows *.com, where the end cert is issued to foo.com */ +static const BYTE chain23_0[] = { +0x30,0x82,0x01,0xd9,0x30,0x82,0x01,0x46,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x70,0x29,0x25,0xb2,0x21,0xd9,0x44,0x8a,0x4b,0x9d,0xf3,0x4e,0x6b,0xdb,0x7c, +0xa7,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3c,0x30,0x3a,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x17,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0d,0x30,0x0b,0xa0,0x09,0x30,0x07,0x82,0x05,0x2a, +0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00, +0x03,0x81,0x81,0x00,0x39,0x5b,0xf7,0xc9,0x4e,0xac,0x65,0x8b,0x56,0xf4,0xaf, +0x23,0xaa,0x1b,0x95,0x0a,0x6e,0x62,0xa8,0x39,0xa0,0xc7,0x86,0x6f,0xb2,0xac, +0x45,0xb6,0x99,0x21,0x66,0x48,0x1a,0x7d,0xe9,0xa9,0xfe,0x5c,0xc6,0xa7,0x25, +0x89,0x66,0x84,0xc4,0x8e,0x05,0x3b,0x53,0xcf,0xee,0x78,0x88,0x85,0xf1,0x8f, +0xce,0x6e,0x72,0xc6,0x0c,0x06,0x3d,0xa6,0x12,0xad,0x0a,0x07,0xbb,0x16,0x2f, +0x0c,0x96,0x0c,0x78,0x31,0xfa,0x93,0x5a,0x2d,0x8d,0x02,0xf5,0xb0,0x1c,0x83, +0x53,0x14,0xc6,0xa6,0x29,0xa6,0xfe,0xb1,0xc0,0x65,0x72,0x47,0xe9,0xf6,0x01, +0x09,0xa4,0xff,0xd2,0x60,0x87,0x81,0xc1,0xb4,0xe7,0xe8,0x3e,0x9a,0xba,0x25, +0xb2,0x36,0x50,0xc4,0xf8,0xb1,0x94,0x07,0xba,0xdd,0x6a,0x95 }; +static const BYTE chain23_1[] = { +0x30,0x82,0x01,0xac,0x30,0x82,0x01,0x15,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55, +0x1d,0x07,0x04,0x0b,0x30,0x09,0x82,0x07,0x66,0x6f,0x6f,0x2e,0x63,0x6f,0x6d, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x03,0x81,0x81,0x00,0xa5,0xc0,0xf6,0xb1,0x63,0x3a,0x23,0xc5,0xb0,0x07,0xb4, +0x83,0xcf,0x36,0xb4,0xfe,0x3c,0xcb,0xa6,0x6b,0xed,0xf7,0x4c,0x25,0x9f,0x2d, +0x88,0xcd,0x8a,0xe4,0x88,0xe3,0x33,0xbb,0x50,0x54,0xee,0xc9,0xad,0xed,0x8b, +0xec,0x1e,0x64,0x36,0xe8,0xb5,0x51,0xca,0xd3,0xa5,0xb9,0x7a,0x2d,0x4b,0xe7, +0xe8,0xc9,0xa5,0x1d,0x49,0xa1,0x31,0x0f,0x50,0x46,0xb0,0x0f,0xd0,0xf6,0xad, +0x51,0x18,0x93,0x25,0x8f,0x4f,0x57,0x12,0x72,0x1e,0xa7,0x44,0x37,0x9f,0xf2, +0xc0,0x28,0xe8,0xbe,0xb8,0x75,0x42,0xef,0x1d,0x7a,0xca,0x87,0x0c,0x11,0x25, +0xeb,0xab,0xcf,0xe0,0xe1,0x12,0x38,0xf6,0x68,0x31,0xfb,0x16,0xcb,0xef,0x67, +0x8c,0x4b,0x6b,0xfd,0x69,0xba,0x0b,0x69,0xee,0x74,0xe0,0x73 }; +/* A chain which allows *.com, where the end cert is issued to foo.bar.com */ +static const BYTE chain24_0[] = { +0x30,0x82,0x01,0xd9,0x30,0x82,0x01,0x46,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x57,0xa6,0x19,0xe0,0x2a,0x65,0x89,0x8d,0x4c,0xd9,0x58,0x8f,0xd0,0xe5,0x5a, +0x02,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3c,0x30,0x3a,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x17,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0d,0x30,0x0b,0xa0,0x09,0x30,0x07,0x82,0x05,0x2a, +0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00, +0x03,0x81,0x81,0x00,0x44,0xec,0x96,0x0c,0x82,0x70,0xd6,0x4f,0xa0,0xa0,0x9e, +0x6f,0xfc,0x93,0xcb,0xbb,0x9b,0xb7,0x34,0xf9,0x9c,0x00,0x00,0x7e,0x11,0xeb, +0x38,0x85,0x8d,0xc9,0xc5,0x69,0x05,0x8e,0xcd,0x82,0x6c,0xe4,0xe5,0xb8,0x63, +0xa6,0x8b,0xe5,0x17,0x9e,0x24,0x67,0x34,0xdd,0x4c,0x62,0xdd,0x08,0xfe,0xdc, +0x90,0xe1,0x8e,0x02,0xfe,0xe9,0xc4,0x19,0xfc,0x7d,0xef,0x24,0xcc,0x99,0x9f, +0x11,0x81,0x6a,0x4d,0x46,0xc8,0x48,0x73,0xc8,0x52,0x89,0xab,0xc7,0x0d,0x9b, +0x77,0xc0,0xbc,0xb5,0x57,0x51,0x2e,0x64,0xad,0x98,0x39,0xd3,0x6d,0xe9,0xe1, +0x58,0x32,0x01,0xfa,0xc7,0xa9,0x89,0x58,0x86,0x3c,0x34,0xc3,0x90,0xd6,0xed, +0x4a,0xdc,0x23,0x66,0xc5,0xab,0x76,0xb9,0x47,0xc8,0x00,0x4c }; +static const BYTE chain24_1[] = { +0x30,0x82,0x01,0xb0,0x30,0x82,0x01,0x19,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x1a,0x30,0x18,0x30,0x16,0x06,0x03,0x55, +0x1d,0x07,0x04,0x0f,0x30,0x0d,0x82,0x0b,0x66,0x6f,0x6f,0x2e,0x62,0x61,0x72, +0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x28,0x64,0x0b,0xad,0x9f,0x12,0xd4, +0x77,0xbe,0x1d,0x20,0x3b,0x69,0x74,0xce,0x91,0x69,0xbe,0x3f,0x76,0x1d,0xe7, +0x81,0x92,0x2b,0xdc,0xbb,0xf9,0xd9,0xba,0xf0,0xba,0x58,0x4a,0x9b,0x47,0x59, +0x34,0xf7,0x19,0xb5,0x15,0x31,0x35,0x4a,0x6d,0x7b,0x91,0x3d,0xc2,0x6c,0x8f, +0x58,0x27,0x0f,0x79,0x96,0x57,0xee,0x4e,0x66,0x3e,0xfa,0x5c,0x22,0xb9,0x57, +0xbf,0x8e,0x7e,0xce,0x98,0x62,0x28,0xb1,0x39,0x0e,0x2d,0x7b,0x5d,0x23,0x70, +0xf0,0x4a,0x63,0x11,0x66,0x80,0xf9,0x99,0x53,0x80,0xda,0x87,0x87,0xf7,0x3c, +0x44,0x76,0x66,0x26,0xa7,0x05,0x3c,0x68,0x66,0x1c,0x07,0x4d,0xcf,0x54,0xaa, +0x5d,0xba,0x7a,0x8f,0x06,0xa7,0x1e,0x86,0xf1,0x5a,0x4b,0x50,0x16,0xad,0x9f, +0x89 }; +/* A chain which allows f*.com, where the end cert is issued to foo.com */ +static const BYTE chain25_0[] = { +0x30,0x82,0x01,0xda,0x30,0x82,0x01,0x47,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x58,0x61,0x5e,0xb3,0x52,0x48,0xc2,0xa7,0x4a,0xa4,0x70,0x8a,0x64,0x96,0xac, +0xc6,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3d,0x30,0x3b,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x18,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0e,0x30,0x0c,0xa0,0x0a,0x30,0x08,0x82,0x06,0x66, +0x2a,0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05, +0x00,0x03,0x81,0x81,0x00,0x18,0xb1,0xb1,0x84,0x3c,0x55,0x29,0xfc,0xd0,0xa7, +0xcd,0x40,0x88,0x9b,0x35,0x9a,0x14,0xa1,0x34,0xd7,0x20,0xd9,0xfb,0x52,0x2f, +0xba,0x6c,0x19,0x5c,0xdc,0x0b,0x0b,0xa5,0x21,0xf9,0x0f,0x98,0x23,0xb6,0xcd, +0x36,0x3f,0xed,0xeb,0xf3,0x10,0xbf,0x62,0x33,0xbb,0xb1,0x94,0x79,0x45,0xe4, +0x42,0x2b,0x9e,0x32,0x53,0x18,0x19,0x59,0x4d,0xc9,0x2d,0x65,0xa4,0xcb,0xd4, +0x0b,0x90,0x2a,0xfe,0xea,0x7f,0x10,0xa9,0xb7,0x65,0xf8,0xc3,0xad,0x26,0x4c, +0x29,0x45,0x60,0xce,0x6a,0x63,0x3e,0xa4,0x6f,0x47,0xaf,0x96,0xea,0xc4,0x35, +0xb0,0x83,0xd7,0x52,0xa9,0x1a,0xd0,0x9a,0x6d,0xac,0xcf,0x6a,0xa6,0xe8,0x8e, +0x52,0x61,0x34,0x95,0xd2,0x22,0x83,0x1f,0x86,0x15,0xa0,0x91,0x2b }; +static const BYTE chain25_1[] = { +0x30,0x82,0x01,0xac,0x30,0x82,0x01,0x15,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55, +0x1d,0x07,0x04,0x0b,0x30,0x09,0x82,0x07,0x66,0x6f,0x6f,0x2e,0x63,0x6f,0x6d, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x03,0x81,0x81,0x00,0xa5,0xc0,0xf6,0xb1,0x63,0x3a,0x23,0xc5,0xb0,0x07,0xb4, +0x83,0xcf,0x36,0xb4,0xfe,0x3c,0xcb,0xa6,0x6b,0xed,0xf7,0x4c,0x25,0x9f,0x2d, +0x88,0xcd,0x8a,0xe4,0x88,0xe3,0x33,0xbb,0x50,0x54,0xee,0xc9,0xad,0xed,0x8b, +0xec,0x1e,0x64,0x36,0xe8,0xb5,0x51,0xca,0xd3,0xa5,0xb9,0x7a,0x2d,0x4b,0xe7, +0xe8,0xc9,0xa5,0x1d,0x49,0xa1,0x31,0x0f,0x50,0x46,0xb0,0x0f,0xd0,0xf6,0xad, +0x51,0x18,0x93,0x25,0x8f,0x4f,0x57,0x12,0x72,0x1e,0xa7,0x44,0x37,0x9f,0xf2, +0xc0,0x28,0xe8,0xbe,0xb8,0x75,0x42,0xef,0x1d,0x7a,0xca,0x87,0x0c,0x11,0x25, +0xeb,0xab,0xcf,0xe0,0xe1,0x12,0x38,0xf6,0x68,0x31,0xfb,0x16,0xcb,0xef,0x67, +0x8c,0x4b,0x6b,0xfd,0x69,0xba,0x0b,0x69,0xee,0x74,0xe0,0x73 }; +/* A chain which allows f*.com, where the end cert is issued to bar.com */ +static const BYTE chain26_0[] = { +0x30,0x82,0x01,0xda,0x30,0x82,0x01,0x47,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x6f,0x9d,0x2b,0x8a,0x6d,0xf2,0xd4,0x9f,0x42,0xea,0x3d,0x16,0xe8,0xa5,0x80, +0x7e,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3d,0x30,0x3b,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x18,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0e,0x30,0x0c,0xa0,0x0a,0x30,0x08,0x82,0x06,0x66, +0x2a,0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05, +0x00,0x03,0x81,0x81,0x00,0x6c,0x34,0x75,0x37,0xd9,0x65,0x9e,0x20,0x05,0x67, +0x16,0x2e,0xc9,0x53,0xc1,0x69,0x53,0xd6,0x00,0x2c,0x92,0x53,0x91,0xa2,0x2a, +0x94,0x2c,0xfa,0x6f,0xc1,0x7e,0xee,0x3c,0x22,0x06,0xcc,0xd1,0xdc,0xd7,0x21, +0x6a,0xf2,0xd3,0x1b,0xaf,0x34,0x20,0x97,0x0f,0xa1,0xec,0x7f,0x72,0x22,0xf2, +0x98,0x5d,0xf4,0x0b,0x83,0x23,0xa7,0x73,0xb2,0xde,0x12,0x56,0xc9,0x11,0xa6, +0x5d,0xbc,0x32,0x79,0x41,0x8b,0xe6,0x8c,0x9c,0xf9,0x78,0xd2,0x20,0x96,0x27, +0x85,0x41,0xc1,0xb8,0x8a,0x74,0x1e,0xbb,0x27,0xc1,0xf7,0xaf,0xe8,0x1c,0x21, +0xe4,0x10,0x64,0x6a,0xdf,0x79,0x30,0x29,0x0e,0x5a,0x04,0x48,0x18,0xdd,0xb0, +0xaa,0x43,0x08,0x71,0x2e,0x49,0x9f,0x9b,0xc1,0x1a,0xcc,0x5f,0xee }; +static const BYTE chain26_1[] = { +0x30,0x82,0x01,0xac,0x30,0x82,0x01,0x15,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55, +0x1d,0x07,0x04,0x0b,0x30,0x09,0x82,0x07,0x62,0x61,0x72,0x2e,0x63,0x6f,0x6d, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x03,0x81,0x81,0x00,0x47,0xa6,0x37,0x73,0x4f,0x19,0xf9,0xaf,0xa9,0xb5,0xa8, +0x41,0x99,0x31,0xa5,0xaa,0x0d,0x6c,0xb8,0x9d,0xe6,0xf6,0x59,0x4d,0xd8,0x12, +0x76,0xcc,0x0b,0xaa,0x2f,0x08,0x1c,0x75,0x54,0x5a,0xae,0x09,0x39,0x25,0xfc, +0x44,0xa1,0x00,0x24,0x5c,0xec,0x20,0x04,0xc7,0xe9,0x14,0xb0,0x71,0x4a,0x33, +0x41,0x7f,0x1d,0x47,0xe5,0x7c,0xe4,0x86,0xb1,0xeb,0xa4,0x9d,0x2a,0x89,0xeb, +0x1d,0x15,0xd6,0x42,0x39,0xe4,0x05,0x26,0xbf,0xc2,0x09,0x6c,0x5c,0xd1,0x56, +0xfd,0x18,0x42,0xd3,0xd5,0x7c,0x52,0xa8,0x4a,0x77,0xe8,0xc0,0x53,0x2b,0xa6, +0x01,0xf9,0x90,0x68,0x60,0x3f,0xcb,0xb8,0x24,0x16,0x0b,0x69,0x4b,0xd9,0xf8, +0x2c,0x92,0xed,0x89,0xa5,0xff,0x71,0xc5,0xed,0xe8,0xbc,0x70 }; +/* A chain which allows foo.com, where the end cert is issued to + * foo.com\0baddie + */ +static const BYTE chain27_0[] = { +0x30,0x82,0x01,0xdb,0x30,0x82,0x01,0x48,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x3d,0xd2,0x79,0xf1,0xa7,0x1a,0xac,0xb2,0x43,0x5e,0x53,0x67,0xc9,0xa1,0x8c, +0x53,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x3e,0x30,0x3c,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x19,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x0f,0x30,0x0d,0xa0,0x0b,0x30,0x09,0x82,0x07,0x66, +0x6f,0x6f,0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d, +0x05,0x00,0x03,0x81,0x81,0x00,0x18,0x5d,0xb0,0x42,0x96,0xf7,0x96,0x7b,0x23, +0x46,0xa9,0xf4,0x99,0x57,0x27,0x8e,0x24,0xae,0x29,0xb8,0x04,0xe3,0x1b,0x64, +0x22,0x8e,0x20,0xf1,0x45,0xb8,0x84,0x38,0x41,0x99,0x73,0xb2,0xbc,0xd9,0xcb, +0x9d,0x9f,0xf4,0x86,0xed,0x21,0x34,0x42,0x21,0xf4,0x8f,0xa7,0xcf,0x19,0xe5, +0xd3,0x4f,0x7c,0x4f,0xc7,0x9e,0x91,0x3a,0x16,0x0b,0x61,0x9e,0xfa,0x08,0x1b, +0x01,0xc0,0x19,0xeb,0xe8,0xd4,0x5a,0xe9,0xe0,0x71,0x04,0xaa,0x88,0x93,0x10, +0x3e,0xc5,0x23,0xbe,0x0b,0xab,0xa9,0x07,0x46,0x4d,0x4b,0xf2,0x95,0xeb,0x69, +0xf2,0x70,0x33,0x5c,0xf7,0xd1,0xa9,0x5b,0xd2,0x84,0x10,0xa6,0x00,0xbe,0xb5, +0xd4,0xe7,0xa3,0x54,0x63,0x3c,0xca,0xb0,0xbf,0x96,0xd1,0x6f,0x64,0xaf }; +static const BYTE chain27_1[] = { +0x30,0x82,0x01,0xb3,0x30,0x82,0x01,0x1c,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x1d,0x30,0x1b,0x30,0x19,0x06,0x03,0x55, +0x1d,0x07,0x04,0x12,0x30,0x10,0x82,0x0e,0x66,0x6f,0x6f,0x2e,0x63,0x6f,0x6d, +0x00,0x62,0x61,0x64,0x64,0x69,0x65,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x6f,0x06,0xc6,0xd0, +0xa1,0x8c,0xc6,0xed,0x33,0x04,0xf6,0x64,0x81,0xa1,0x0f,0x79,0x4d,0x9a,0xbd, +0xc0,0x8f,0x18,0xc2,0xb8,0x82,0xb9,0x70,0x6f,0xbe,0xaa,0xbb,0x43,0x95,0x79, +0x58,0xec,0xdf,0x94,0x8b,0x4d,0xe1,0xee,0x56,0xc4,0x57,0x7c,0xff,0xde,0x5f, +0x52,0xf9,0x3a,0x9e,0x33,0x99,0x6e,0xdf,0xf2,0xce,0x40,0xc7,0xd8,0xb5,0x86, +0xae,0xb7,0x52,0x8b,0xc5,0x62,0x17,0xce,0x03,0x06,0x29,0x5a,0xf6,0x5a,0x9a, +0x8e,0xb7,0xe3,0xb2,0xcd,0x3f,0xa7,0x61,0x2b,0xba,0xe6,0x68,0xa8,0x92,0x8a, +0xe5,0x32,0xe0,0x49,0xd4,0x42,0xc0,0x1a,0x92,0x72,0xb0,0x66,0x48,0x84,0x74, +0xd3,0x25,0xe3,0x66,0x2f,0x30,0xea,0x40,0x72,0x82,0xc4,0xc5,0x4a,0x4e,0xcc, +0x32,0xbc,0x36,0xa4 }; +/* A chain which allows foo.*.com, where the end cert is issued to foo.bar.com. + */ +static const BYTE chain28_0[] = { +0x30,0x82,0x01,0xdd,0x30,0x82,0x01,0x4a,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x72,0x7f,0x98,0xcd,0x99,0xa6,0x5f,0x89,0x4a,0x5c,0xd2,0x15,0xd0,0x68,0x25, +0xc8,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x40,0x30,0x3e,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x04,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1b,0x06,0x03,0x55,0x1d, +0x1e,0x01,0x01,0xff,0x04,0x11,0x30,0x0f,0xa0,0x0d,0x30,0x0b,0x82,0x09,0x66, +0x6f,0x6f,0x2e,0x2a,0x2e,0x63,0x6f,0x6d,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03, +0x02,0x1d,0x05,0x00,0x03,0x81,0x81,0x00,0x01,0x9a,0x8c,0x75,0x20,0x9f,0x91, +0xe9,0xde,0x28,0x3c,0x7a,0xd9,0xf1,0x2d,0xa3,0x0d,0x66,0x9f,0xd8,0x2a,0xb0, +0xb5,0x19,0x9a,0x29,0xc7,0xd5,0xe5,0xf6,0x75,0xee,0x06,0xe4,0xd2,0x71,0x77, +0x7e,0xbc,0x1a,0x5f,0xbe,0x28,0xba,0x6e,0x50,0x8e,0xe6,0xd9,0xd5,0x5a,0x21, +0xa6,0x29,0xff,0xb0,0xc7,0xfe,0x06,0xb6,0xde,0x51,0x5b,0xab,0xe4,0xbb,0xbf, +0xaa,0x03,0xa9,0xfe,0x71,0xb8,0x3f,0x65,0xe2,0x2c,0xa9,0x31,0x18,0x6d,0xe6, +0x54,0xd0,0x90,0x6b,0x7b,0x3a,0x9a,0x45,0xa9,0x1b,0x05,0x2e,0xca,0xd7,0x5f, +0x79,0x3d,0x1c,0xbf,0xdb,0xce,0x23,0x5d,0x0a,0x9b,0xb4,0x91,0xfe,0xd4,0x94, +0x92,0x76,0x36,0xae,0x03,0xb8,0x30,0x13,0x58,0x69,0x71,0xea,0xc2,0xbc,0x31, +0x83 }; +static const BYTE chain28_1[] = { +0x30,0x82,0x01,0xb0,0x30,0x82,0x01,0x19,0xa0,0x03,0x02,0x01,0x02,0x02,0x01, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43, +0x65,0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55, +0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5, +0x33,0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6, +0xdc,0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7, +0x48,0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b, +0x47,0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b, +0x05,0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc, +0x6a,0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85, +0x85,0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2, +0xd3,0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72, +0xa3,0x02,0x03,0x01,0x00,0x01,0xa3,0x1a,0x30,0x18,0x30,0x16,0x06,0x03,0x55, +0x1d,0x07,0x04,0x0f,0x30,0x0d,0x82,0x0b,0x66,0x6f,0x6f,0x2e,0x62,0x61,0x72, +0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x28,0x64,0x0b,0xad,0x9f,0x12,0xd4, +0x77,0xbe,0x1d,0x20,0x3b,0x69,0x74,0xce,0x91,0x69,0xbe,0x3f,0x76,0x1d,0xe7, +0x81,0x92,0x2b,0xdc,0xbb,0xf9,0xd9,0xba,0xf0,0xba,0x58,0x4a,0x9b,0x47,0x59, +0x34,0xf7,0x19,0xb5,0x15,0x31,0x35,0x4a,0x6d,0x7b,0x91,0x3d,0xc2,0x6c,0x8f, +0x58,0x27,0x0f,0x79,0x96,0x57,0xee,0x4e,0x66,0x3e,0xfa,0x5c,0x22,0xb9,0x57, +0xbf,0x8e,0x7e,0xce,0x98,0x62,0x28,0xb1,0x39,0x0e,0x2d,0x7b,0x5d,0x23,0x70, +0xf0,0x4a,0x63,0x11,0x66,0x80,0xf9,0x99,0x53,0x80,0xda,0x87,0x87,0xf7,0x3c, +0x44,0x76,0x66,0x26,0xa7,0x05,0x3c,0x68,0x66,0x1c,0x07,0x4d,0xcf,0x54,0xaa, +0x5d,0xba,0x7a,0x8f,0x06,0xa7,0x1e,0x86,0xf1,0x5a,0x4b,0x50,0x16,0xad,0x9f, +0x89 }; + +typedef struct _CONST_DATA_BLOB +{ + DWORD cbData; + const BYTE *pbData; +} CONST_DATA_BLOB; + +typedef struct _CONST_BLOB_ARRAY +{ + DWORD cBlob; + CONST_DATA_BLOB *rgBlob; +} CONST_BLOB_ARRAY; + +#define TODO_CHAIN 1 +#define TODO_ERROR 2 +#define TODO_INFO 4 +#define TODO_ELEMENTS 8 +#define TODO_CHAINS 16 +#define TODO_POLICY 32 + +/* Gets a certificate chain built from a store containing all the certs in + * certArray, where the last certificate in the chain is expected to be the + * end certificate (the one from which the chain is built.) + */ +static PCCERT_CHAIN_CONTEXT getChain(const CONST_BLOB_ARRAY *certArray, + DWORD flags, BOOL includeStore, LPSYSTEMTIME checkTime, DWORD todo, + DWORD testIndex) +{ + HCERTSTORE store; + PCCERT_CHAIN_CONTEXT chain = NULL; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (store) + { + BOOL ret; + PCCERT_CONTEXT endCert; + + if (certArray->cBlob > 1) + { + DWORD i; + + for (i = 0, ret = TRUE; ret && i < certArray->cBlob - 1; i++) + { + ret = CertAddEncodedCertificateToStore(store, + X509_ASN_ENCODING, certArray->rgBlob[i].pbData, + certArray->rgBlob[i].cbData, CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "Chain %d: adding cert %d failed: %08x\n", + testIndex, i, GetLastError()); + } + } + ret = CertAddEncodedCertificateToStore(store, + X509_ASN_ENCODING, certArray->rgBlob[certArray->cBlob - 1].pbData, + certArray->rgBlob[certArray->cBlob - 1].cbData, CERT_STORE_ADD_ALWAYS, + &endCert); + ok(ret, "Chain %d: adding end cert failed: %08x\n", + testIndex, GetLastError()); + if (ret) + { + /* FIXME: allow caller to specify usage matches? */ + CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; + FILETIME fileTime; + + SystemTimeToFileTime(checkTime, &fileTime); + ret = pCertGetCertificateChain(NULL, endCert, &fileTime, + includeStore ? store : NULL, &chainPara, flags, NULL, &chain); + if (todo & TODO_CHAIN) + todo_wine ok(ret, "Chain %d: CertGetCertificateChain failed: %08x\n", + testIndex, GetLastError()); + else + ok(ret, "Chain %d: CertGetCertificateChain failed: %08x\n", + testIndex, GetLastError()); + CertFreeCertificateContext(endCert); + } + CertCloseStore(store, 0); + } + return chain; +} + +typedef struct _SimpleChainStatusCheck +{ + DWORD cElement; + const CERT_TRUST_STATUS *rgElementStatus; +} SimpleChainStatusCheck; + +static void checkElementStatus(const CERT_TRUST_STATUS *expected, + const CERT_TRUST_STATUS *got, const CERT_TRUST_STATUS *ignore, + DWORD todo, DWORD testIndex, DWORD chainIndex, DWORD elementIndex) +{ + if (got->dwErrorStatus == expected->dwErrorStatus) + ok(got->dwErrorStatus == expected->dwErrorStatus, + "Chain %d, element [%d,%d]: expected error %08x, got %08x\n", + testIndex, chainIndex, elementIndex, expected->dwErrorStatus, + got->dwErrorStatus); + else if (todo & TODO_ERROR) + todo_wine + ok(got->dwErrorStatus == expected->dwErrorStatus || + broken((got->dwErrorStatus & ~ignore->dwErrorStatus) == + (expected->dwErrorStatus & ~ignore->dwErrorStatus)), + "Chain %d, element [%d,%d]: expected error %08x, got %08x\n", + testIndex, chainIndex, elementIndex, expected->dwErrorStatus, + got->dwErrorStatus); + else + ok(got->dwErrorStatus == expected->dwErrorStatus || + broken((got->dwErrorStatus & ~ignore->dwErrorStatus) == + (expected->dwErrorStatus & ~ignore->dwErrorStatus)), + "Chain %d, element [%d,%d]: expected error %08x, got %08x. %08x is " + "expected if no valid Verisign root certificate is available.\n", + testIndex, chainIndex, elementIndex, expected->dwErrorStatus, + got->dwErrorStatus, CERT_TRUST_IS_UNTRUSTED_ROOT); + if (got->dwInfoStatus == expected->dwInfoStatus) + ok(got->dwInfoStatus == expected->dwInfoStatus, + "Chain %d, element [%d,%d]: expected info %08x, got %08x\n", + testIndex, chainIndex, elementIndex, expected->dwInfoStatus, + got->dwInfoStatus); + else if (todo & TODO_INFO) + todo_wine + ok(got->dwInfoStatus == expected->dwInfoStatus || + broken((got->dwInfoStatus & ~ignore->dwInfoStatus) == + (expected->dwInfoStatus & ~ignore->dwInfoStatus)), + "Chain %d, element [%d,%d]: expected info %08x, got %08x\n", + testIndex, chainIndex, elementIndex, expected->dwInfoStatus, + got->dwInfoStatus); + else + ok(got->dwInfoStatus == expected->dwInfoStatus || + broken((got->dwInfoStatus & ~ignore->dwInfoStatus) == + (expected->dwInfoStatus & ~ignore->dwInfoStatus)), + "Chain %d, element [%d,%d]: expected info %08x, got %08x\n", + testIndex, chainIndex, elementIndex, expected->dwInfoStatus, + got->dwInfoStatus); +} + +static void checkSimpleChainStatus(const CERT_SIMPLE_CHAIN *simpleChain, + const SimpleChainStatusCheck *simpleChainStatus, + const CERT_TRUST_STATUS *ignore, DWORD todo, DWORD testIndex, DWORD chainIndex) +{ + if (todo & TODO_ELEMENTS) + todo_wine ok(simpleChain->cElement == simpleChainStatus->cElement, + "Chain %d: expected %d elements, got %d\n", testIndex, + simpleChainStatus->cElement, simpleChain->cElement); + else + ok(simpleChain->cElement == simpleChainStatus->cElement, + "Chain %d: expected %d elements, got %d\n", testIndex, + simpleChainStatus->cElement, simpleChain->cElement); + if (simpleChain->cElement == simpleChainStatus->cElement) + { + DWORD i; + + for (i = 0; i < simpleChain->cElement; i++) + checkElementStatus(&simpleChainStatus->rgElementStatus[i], + &simpleChain->rgpElement[i]->TrustStatus, ignore, todo, testIndex, + chainIndex, i); + } +} + +typedef struct _ChainStatusCheck +{ + CERT_TRUST_STATUS statusToIgnore; + CERT_TRUST_STATUS status; + DWORD cChain; + const SimpleChainStatusCheck *rgChainStatus; +} ChainStatusCheck; + +static void checkChainStatus(PCCERT_CHAIN_CONTEXT chain, + const ChainStatusCheck *chainStatus, DWORD todo, DWORD testIndex) +{ + ok(chain->cChain == chainStatus->cChain, + "Chain %d: expected %d simple chains, got %d\n", testIndex, + chainStatus->cChain, chain->cChain); + if (todo & TODO_ERROR && + chain->TrustStatus.dwErrorStatus != chainStatus->status.dwErrorStatus) + todo_wine ok(chain->TrustStatus.dwErrorStatus == + chainStatus->status.dwErrorStatus || + broken((chain->TrustStatus.dwErrorStatus & + ~chainStatus->statusToIgnore.dwErrorStatus) == + (chainStatus->status.dwErrorStatus & + ~chainStatus->statusToIgnore.dwErrorStatus)), + "Chain %d: expected error %08x, got %08x\n", + testIndex, chainStatus->status.dwErrorStatus, + chain->TrustStatus.dwErrorStatus); + else + ok(chain->TrustStatus.dwErrorStatus == + chainStatus->status.dwErrorStatus || + broken((chain->TrustStatus.dwErrorStatus & + ~chainStatus->statusToIgnore.dwErrorStatus) == + (chainStatus->status.dwErrorStatus & + ~chainStatus->statusToIgnore.dwErrorStatus)), + "Chain %d: expected error %08x, got %08x. %08x is expected if no valid " + "Verisign root certificate is available.\n", + testIndex, chainStatus->status.dwErrorStatus, + chain->TrustStatus.dwErrorStatus, CERT_TRUST_IS_UNTRUSTED_ROOT); + if (todo & TODO_INFO && + chain->TrustStatus.dwInfoStatus != chainStatus->status.dwInfoStatus) + todo_wine ok(chain->TrustStatus.dwInfoStatus == + chainStatus->status.dwInfoStatus || + broken((chain->TrustStatus.dwInfoStatus & + ~chainStatus->statusToIgnore.dwInfoStatus) == + (chainStatus->status.dwInfoStatus & + ~chainStatus->statusToIgnore.dwInfoStatus)), + "Chain %d: expected info %08x, got %08x\n", + testIndex, chainStatus->status.dwInfoStatus, + chain->TrustStatus.dwInfoStatus); + else + ok(chain->TrustStatus.dwInfoStatus == + chainStatus->status.dwInfoStatus || + broken((chain->TrustStatus.dwInfoStatus & + ~chainStatus->statusToIgnore.dwInfoStatus) == + (chainStatus->status.dwInfoStatus & + ~chainStatus->statusToIgnore.dwInfoStatus)), + "Chain %d: expected info %08x, got %08x\n", + testIndex, chainStatus->status.dwInfoStatus, + chain->TrustStatus.dwInfoStatus); + if (chain->cChain == chainStatus->cChain) + { + DWORD i; + + for (i = 0; i < chain->cChain; i++) + checkSimpleChainStatus(chain->rgpChain[i], + &chainStatus->rgChainStatus[i], &chainStatus->statusToIgnore, + todo, testIndex, i); + } +} + +typedef struct _ChainCheck +{ + CONST_BLOB_ARRAY certs; + ChainStatusCheck status; + DWORD todo; +} ChainCheck; + +static CONST_DATA_BLOB chain0[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain0_1), chain0_1 }, +}; +static const CERT_TRUST_STATUS elementStatus0[] = { + { CERT_TRUST_IS_NOT_TIME_VALID, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus0[] = { + { sizeof(elementStatus0) / sizeof(elementStatus0[0]), elementStatus0 }, +}; +static CONST_DATA_BLOB chain1[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain1_1), chain1_1 }, +}; +static const CERT_TRUST_STATUS elementStatus1[] = { + { CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_SIGNATURE_VALID, + CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus1[] = { + { sizeof(elementStatus1) / sizeof(elementStatus1[0]), elementStatus1 }, +}; +static CONST_DATA_BLOB chain2[] = { + { sizeof(chain2_0), chain2_0 }, + { sizeof(chain0_1), chain0_1 }, +}; +static const CERT_TRUST_STATUS elementStatus2[] = { + { CERT_TRUST_IS_NOT_TIME_VALID, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus2[] = { + { sizeof(elementStatus2) / sizeof(elementStatus2[0]), elementStatus2 }, +}; +static CONST_DATA_BLOB chain3[] = { + { sizeof(chain3_0), chain3_0 }, + { sizeof(chain0_1), chain0_1 }, +}; +static const CERT_TRUST_STATUS elementStatus3[] = { + { CERT_TRUST_IS_NOT_TIME_VALID, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus3[] = { + { sizeof(elementStatus3) / sizeof(elementStatus3[0]), elementStatus3 }, +}; +static CONST_DATA_BLOB chain4[] = { + { sizeof(chain4_0), chain4_0 }, + { sizeof(chain4_1), chain4_1 }, + { sizeof(chain4_2), chain4_2 }, +}; +static const CERT_TRUST_STATUS elementStatus4[] = { + { CERT_TRUST_IS_NOT_TIME_VALID, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus4[] = { + { sizeof(elementStatus4) / sizeof(elementStatus4[0]), elementStatus4 }, +}; +static CONST_DATA_BLOB chain5[] = { + { sizeof(chain5_0), chain5_0 }, + { sizeof(chain5_1), chain5_1 }, +}; +static const CERT_TRUST_STATUS elementStatus5[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT | + CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus5[] = { + { sizeof(elementStatus5) / sizeof(elementStatus5[0]), elementStatus5 }, +}; +static CONST_DATA_BLOB chain6[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain4_1), chain4_1 }, +}; +static const CERT_TRUST_STATUS elementStatus6[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus6[] = { + { sizeof(elementStatus6) / sizeof(elementStatus6[0]), elementStatus6 }, +}; +static CONST_DATA_BLOB chain7[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain7_1), chain7_1 }, +}; +static const CERT_TRUST_STATUS elementStatus7[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus7[] = { + { sizeof(elementStatus7) / sizeof(elementStatus7[0]), elementStatus7 }, +}; +static CONST_DATA_BLOB chain8[] = { + { sizeof(chain8_0), chain8_0 }, + { sizeof(chain8_1), chain8_1 }, + { sizeof(chain8_2), chain8_2 }, +}; +static const CERT_TRUST_STATUS elementStatus8[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_TIME_VALID, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck simpleStatus8[] = { + { sizeof(elementStatus8) / sizeof(elementStatus8[0]), elementStatus8 }, +}; +static CONST_DATA_BLOB chain9[] = { + { sizeof(chain9_0), chain9_0 }, + { sizeof(chain7_1), chain7_1 }, +}; +static const CERT_TRUST_STATUS elementStatus9[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_CYCLIC, + CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus9[] = { + { sizeof(elementStatus9) / sizeof(elementStatus9[0]), elementStatus9 }, +}; +static CONST_DATA_BLOB chain10[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain10_1), chain10_1 }, + { sizeof(chain7_1), chain7_1 }, +}; +static const CERT_TRUST_STATUS elementStatus10[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus10[] = { + { sizeof(elementStatus10) / sizeof(elementStatus10[0]), elementStatus10 }, +}; +static CONST_DATA_BLOB chain11[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain11_1), chain11_1 }, + { sizeof(chain7_1), chain7_1 }, +}; +static CONST_DATA_BLOB chain12[] = { + { sizeof(chain12_0), chain12_0 }, + { sizeof(chain7_1), chain7_1 }, +}; +static const CERT_TRUST_STATUS elementStatus12[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_NOT_SIGNATURE_VALID | CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus12[] = { + { sizeof(elementStatus12) / sizeof(elementStatus12[0]), elementStatus12 }, +}; +static CONST_DATA_BLOB chain13[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain13_1), chain13_1 }, +}; +static const CERT_TRUST_STATUS elementStatus13[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus13[] = { + { sizeof(elementStatus13) / sizeof(elementStatus13[0]), elementStatus13 }, +}; +static CONST_DATA_BLOB chain14[] = { + { sizeof(chain14_0), chain14_0 }, + { sizeof(chain14_1), chain14_1 }, +}; +static const CERT_TRUST_STATUS elementStatus14[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus14[] = { + { sizeof(elementStatus14) / sizeof(elementStatus14[0]), elementStatus14 }, +}; +static CONST_DATA_BLOB chain15[] = { + { sizeof(chain15_0), chain15_0 }, + { sizeof(chain14_1), chain14_1 }, +}; +static const CERT_TRUST_STATUS elementStatus15[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus15[] = { + { sizeof(elementStatus15) / sizeof(elementStatus15[0]), elementStatus15 }, +}; +static CONST_DATA_BLOB chain16[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain16_1), chain16_1 }, +}; +static const CERT_TRUST_STATUS elementStatus16[] = { + { CERT_TRUST_NO_ERROR | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus16[] = { + { sizeof(elementStatus16) / sizeof(elementStatus16[0]), elementStatus16 }, +}; +static CONST_DATA_BLOB chain17[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain17_1), chain17_1 }, + { sizeof(chain17_2), chain17_2 }, +}; +static const CERT_TRUST_STATUS elementStatus17[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus17[] = { + { sizeof(elementStatus17) / sizeof(elementStatus17[0]), elementStatus17 }, +}; +static CONST_DATA_BLOB chain18[] = { + { sizeof(chain0_0), chain0_0 }, + { sizeof(chain18_1), chain18_1 }, + { sizeof(chain18_2), chain18_2 }, +}; +static const CERT_TRUST_STATUS elementStatus18[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_NOT_VALID_FOR_USAGE, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus18[] = { + { sizeof(elementStatus18) / sizeof(elementStatus18[0]), elementStatus18 }, +}; +static CONST_DATA_BLOB chain19[] = { + { sizeof(chain19_0), chain19_0 }, + { sizeof(chain19_1), chain19_1 }, +}; +static const CERT_TRUST_STATUS elementStatus19[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER | + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, +}; +static const SimpleChainStatusCheck simpleStatus19[] = { + { sizeof(elementStatus19) / sizeof(elementStatus19[0]), elementStatus19 }, +}; +static CONST_DATA_BLOB chain20[] = { + { sizeof(chain20_0), chain20_0 }, + { sizeof(chain20_1), chain20_1 }, +}; +static const CERT_TRUST_STATUS elementStatus20[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus20[] = { + { sizeof(elementStatus20) / sizeof(elementStatus20[0]), elementStatus20 }, +}; +static CONST_DATA_BLOB chain21[] = { + { sizeof(chain21_0), chain21_0 }, + { sizeof(chain21_1), chain21_1 }, +}; +static const CERT_TRUST_STATUS elementStatus21[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER | + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, +}; +static const SimpleChainStatusCheck simpleStatus21[] = { + { sizeof(elementStatus21) / sizeof(elementStatus21[0]), elementStatus21 }, +}; +static CONST_DATA_BLOB chain22[] = { + { sizeof(chain22_0), chain22_0 }, + { sizeof(chain22_1), chain22_1 }, +}; +static const CERT_TRUST_STATUS elementStatus22[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus22[] = { + { sizeof(elementStatus22) / sizeof(elementStatus22[0]), elementStatus22 }, +}; +static CONST_DATA_BLOB chain23[] = { + { sizeof(chain23_0), chain23_0 }, + { sizeof(chain23_1), chain23_1 }, +}; +static const CERT_TRUST_STATUS elementStatus23[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus23[] = { + { sizeof(elementStatus23) / sizeof(elementStatus23[0]), elementStatus23 }, +}; +static CONST_DATA_BLOB chain24[] = { + { sizeof(chain24_0), chain24_0 }, + { sizeof(chain24_1), chain24_1 }, +}; +static const CERT_TRUST_STATUS elementStatus24[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus24[] = { + { sizeof(elementStatus24) / sizeof(elementStatus24[0]), elementStatus24 }, +}; +static CONST_DATA_BLOB chain25[] = { + { sizeof(chain25_0), chain25_0 }, + { sizeof(chain25_1), chain25_1 }, +}; +static const CERT_TRUST_STATUS elementStatus25[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus25[] = { + { sizeof(elementStatus25) / sizeof(elementStatus25[0]), elementStatus25 }, +}; +static CONST_DATA_BLOB chain26[] = { + { sizeof(chain26_0), chain26_0 }, + { sizeof(chain26_1), chain26_1 }, +}; +static const CERT_TRUST_STATUS elementStatus26[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus26[] = { + { sizeof(elementStatus26) / sizeof(elementStatus26[0]), elementStatus26 }, +}; +static CONST_DATA_BLOB chain27[] = { + { sizeof(chain27_0), chain27_0 }, + { sizeof(chain27_1), chain27_1 }, +}; +static const CERT_TRUST_STATUS elementStatus27[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_INVALID_NAME_CONSTRAINTS | + CERT_TRUST_INVALID_EXTENSION, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus27[] = { + { sizeof(elementStatus27) / sizeof(elementStatus27[0]), elementStatus27 }, +}; +static const CERT_TRUST_STATUS elementStatus27Broken[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER | + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, +}; +static const SimpleChainStatusCheck simpleStatus27Broken[] = { + { sizeof(elementStatus27Broken) / sizeof(elementStatus27Broken[0]), + elementStatus27Broken }, +}; +static CONST_DATA_BLOB chain28[] = { + { sizeof(chain28_0), chain28_0 }, + { sizeof(chain28_1), chain28_1 }, +}; +static const CERT_TRUST_STATUS elementStatus28[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus28[] = { + { sizeof(elementStatus28) / sizeof(elementStatus28[0]), elementStatus28 }, +}; +static CONST_DATA_BLOB selfSignedChain[] = { + { sizeof(selfSignedCert), selfSignedCert } +}; +static const CERT_TRUST_STATUS selfSignedElementStatus[] = { + { CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_UNTRUSTED_ROOT, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED }, +}; +static const SimpleChainStatusCheck selfSignedSimpleStatus[] = { + { sizeof(selfSignedElementStatus) / sizeof(selfSignedElementStatus[0]), + selfSignedElementStatus }, +}; +static CONST_DATA_BLOB iTunesChain[] = { + { sizeof(verisignCA), verisignCA }, + { sizeof(iTunesCert0), iTunesCert0 }, + { sizeof(iTunesCert1), iTunesCert1 }, +}; +static const CERT_TRUST_STATUS iTunesElementStatus[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_KEY_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_EXACT_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED}, +}; +static const SimpleChainStatusCheck iTunesSimpleStatus[] = { + { sizeof(iTunesElementStatus) / sizeof(iTunesElementStatus[0]), + iTunesElementStatus }, +}; +static CONST_DATA_BLOB googleChain[] = { + { sizeof(verisignCA), verisignCA }, + { sizeof(thawte_sgc_ca), thawte_sgc_ca }, + { sizeof(google), google }, +}; +/* The Google cert is only valid from 3/27/2009 to 3/27/2010, so with the date + * tested (October 2007) it's not time valid. + */ +static const CERT_TRUST_STATUS googleElementStatus[] = { + { CERT_TRUST_IS_NOT_TIME_VALID, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED}, +}; +static const SimpleChainStatusCheck googleSimpleStatus[] = { + { sizeof(googleElementStatus) / sizeof(googleElementStatus[0]), + googleElementStatus }, +}; +/* The openssl cert is only valid from 9/12/2008 to 9/13/2012, so with the date + * tested (October 2007) it's not time valid. + */ +static CONST_DATA_BLOB opensslChain[] = { + { sizeof(global_sign_root), global_sign_root }, + { sizeof(global_sign_ca), global_sign_ca }, + { sizeof(openssl_org), openssl_org }, +}; +static const CERT_TRUST_STATUS opensslElementStatus[] = { + { CERT_TRUST_IS_NOT_TIME_VALID, CERT_TRUST_HAS_KEY_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_KEY_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, + CERT_TRUST_HAS_NAME_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED}, +}; +static const SimpleChainStatusCheck opensslSimpleStatus[] = { + { sizeof(opensslElementStatus) / sizeof(opensslElementStatus[0]), + opensslElementStatus }, +}; +/* entrust_ca -> aaa_certificate_services -> cs_stanford_edu */ +/* cs.stanford.edu's cert is only valid from 7/16/2009 to 7/16/2012, so with + * the date tested (October 2007) it's not time valid. + */ +static CONST_DATA_BLOB stanfordChain[] = { + { sizeof(entrust_ca), entrust_ca }, + { sizeof(aaa_certificate_services), aaa_certificate_services }, + { sizeof(cs_stanford_edu), cs_stanford_edu }, +}; +static const CERT_TRUST_STATUS stanfordElementStatus[] = { + { CERT_TRUST_IS_NOT_TIME_VALID, CERT_TRUST_HAS_KEY_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_KEY_MATCH_ISSUER }, + { CERT_TRUST_NO_ERROR, + CERT_TRUST_HAS_KEY_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED}, +}; +static const SimpleChainStatusCheck stanfordSimpleStatus[] = { + { sizeof(stanfordElementStatus) / sizeof(stanfordElementStatus[0]), + stanfordElementStatus }, +}; +static ChainCheck chainCheck[] = { + /* Windows XP erroneously sets CERT_TRUST_HAS_PREFERRED_ISSUER on all + * elements, so ignore it. + * Windows 98/NT4 also set CERT_TRUST_IS_NOT_TIME_NESTED on chains they + * shouldn't, so ignore those too. + */ + { { sizeof(chain0) / sizeof(chain0[0]), chain0 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, simpleStatus0 }, 0 }, + { { sizeof(chain1) / sizeof(chain1[0]), chain1 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_SIGNATURE_VALID | + CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, simpleStatus1 }, 0 }, + { { sizeof(chain2) / sizeof(chain2[0]), chain2 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, simpleStatus2 }, 0 }, + /* Earlier versions of Windows incorrectly don't set + * CERT_TRUST_INVALID_BASIC_CONSTRAINTS on this chain. + */ + { { sizeof(chain3) / sizeof(chain3[0]), chain3 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_INVALID_BASIC_CONSTRAINTS, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, simpleStatus3 }, 0 }, + /* Earlier versions of Windows incorrectly don't set + * CERT_TRUST_INVALID_BASIC_CONSTRAINTS on this chain. + */ + { { sizeof(chain4) / sizeof(chain4[0]), chain4 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_INVALID_BASIC_CONSTRAINTS, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, simpleStatus4 }, 0 }, + /* Windows versions prior to Vista/2008 incorrectly set + * CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT on this chain, so ignore it. + * Similarly, some older versions of Windows incorrectly set + * CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, ignore that too. + */ + { { sizeof(chain5) / sizeof(chain5[0]), chain5 }, + { { CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT | + CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus5 }, 0 }, + { { sizeof(chain6) / sizeof(chain6[0]), chain6 }, + { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus6 }, 0 }, + { { sizeof(chain7) / sizeof(chain7[0]), chain7 }, + { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus7 }, 0 }, + /* Earlier versions of Windows incorrectly don't set + * CERT_TRUST_INVALID_BASIC_CONSTRAINTS on this chain. + */ + { { sizeof(chain8) / sizeof(chain8[0]), chain8 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_INVALID_BASIC_CONSTRAINTS, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, simpleStatus8 }, 0 }, + /* Earlier versions of Windows incorrectly don't set + * CERT_TRUST_INVALID_BASIC_CONSTRAINTS on this chain. + */ + { { sizeof(chain9) / sizeof(chain9[0]), chain9 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_INVALID_BASIC_CONSTRAINTS, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_PARTIAL_CHAIN | + CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_CYCLIC, 0 }, + 1, simpleStatus9 }, 0 }, + { { sizeof(chain10) / sizeof(chain10[0]), chain10 }, + { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus10 }, 0 }, + { { sizeof(chain11) / sizeof(chain11[0]), chain11 }, + { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus10 }, 0 }, + { { sizeof(chain12) / sizeof(chain12[0]), chain12 }, + { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_SIGNATURE_VALID, 0 }, + 1, simpleStatus12 }, 0 }, + { { sizeof(chain13) / sizeof(chain13[0]), chain13 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus13 }, + 0 }, + { { sizeof(chain14) / sizeof(chain14[0]), chain14 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus14 }, + 0 }, + /* Earlier versions of crypt32 incorrectly do not complain that the end cert's + * key usage is invalid, so ignore that error. + */ + { { sizeof(chain15) / sizeof(chain15[0]), chain15 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, 0 }, + 1, simpleStatus15 }, + 0 }, + { { sizeof(chain16) / sizeof(chain16[0]), chain16 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, 0 }, + 1, simpleStatus16 }, + 0 }, + { { sizeof(chain17) / sizeof(chain17[0]), chain17 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, 1, simpleStatus17 }, + 0 }, + { { sizeof(chain18) / sizeof(chain18[0]), chain18 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, 0 }, + 1, simpleStatus18 }, + 0 }, + /* Older versions of crypt32 set CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT + * even though the constraint and alt name match. + * They also do not set CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS, since they + * incorrectly find a name constraint error. + */ + { { sizeof(chain19) / sizeof(chain19[0]), chain19 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER | CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS + }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, + 1, simpleStatus19 }, + 0 }, + /* Older versions of crypt32 do not set + * CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, though they should. So + * ignore it (on Windows) but require it (on Wine.) + */ + { { sizeof(chain20) / sizeof(chain20[0]), chain20 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, 0 }, + 1, simpleStatus20 }, + 0 }, + { { sizeof(chain21) / sizeof(chain21[0]), chain21 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER | CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS + }, + { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, + 1, simpleStatus21 }, + 0 }, + { { sizeof(chain22) / sizeof(chain22[0]), chain22 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, 0 }, + 1, simpleStatus22 }, + 0 }, + { { sizeof(chain23) / sizeof(chain23[0]), chain23 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, 0 }, + 1, simpleStatus23 }, + 0 }, + { { sizeof(chain24) / sizeof(chain24[0]), chain24 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, 0 }, + 1, simpleStatus24 }, + 0 }, + { { sizeof(chain25) / sizeof(chain25[0]), chain25 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, 0 }, + 1, simpleStatus25 }, + 0 }, + { { sizeof(chain26) / sizeof(chain26[0]), chain26 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, 0 }, + 1, simpleStatus26 }, + 0 }, + /* chain27 is handled separately elsewhere */ + { { sizeof(chain28) / sizeof(chain28[0]), chain28 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, 0 }, + 1, simpleStatus28 }, + 0 }, + { { sizeof(selfSignedChain) / sizeof(selfSignedChain[0]), selfSignedChain }, + { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, + 1, selfSignedSimpleStatus }, 0 }, + /* The iTunes chain may or may not have its root trusted, so ignore the + * error + */ + { { sizeof(iTunesChain) / sizeof(iTunesChain[0]), iTunesChain }, + { { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { 0, 0 }, + 1, iTunesSimpleStatus }, 0 }, + /* The google chain may or may not have its root trusted, so ignore the error + */ + { { sizeof(googleChain) / sizeof(googleChain[0]), googleChain }, + { { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, googleSimpleStatus }, 0 }, + /* The openssl chain may or may not have its root trusted, so ignore the error + */ + { { sizeof(opensslChain) / sizeof(opensslChain[0]), opensslChain }, + { { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, opensslSimpleStatus }, 0 }, + /* The stanford chain may or may not have its root trusted, so ignore the error + */ + { { sizeof(stanfordChain) / sizeof(stanfordChain[0]), stanfordChain }, + { { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_NOT_TIME_VALID, 0 }, + 1, stanfordSimpleStatus }, TODO_INFO }, +}; + +static const CERT_TRUST_STATUS elementStatus8NoStore[] = { + { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER }, +}; +static const SimpleChainStatusCheck simpleStatus8NoStore[] = { + { sizeof(elementStatus8NoStore) / sizeof(elementStatus8NoStore[0]), + elementStatus8NoStore }, +}; +static ChainCheck chainCheckNoStore[] = { + { { sizeof(selfSignedChain) / sizeof(selfSignedChain[0]), selfSignedChain }, + { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_UNTRUSTED_ROOT, 0 }, + 1, selfSignedSimpleStatus }, + 0 }, + { { sizeof(chain8) / sizeof(chain8[0]), chain8 }, + { { 0, CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_PARTIAL_CHAIN, 0 }, + 1, simpleStatus8NoStore }, + 0 }, +}; + +/* Chain27 checks a certificate with a subject alternate name containing an + * embedded NULL. Newer crypt32 versions fail to decode such alternate names, + * correctly prohibiting them. Older crypt32 versions do not. Rather than + * ignoring the expected error bits, check each version separately depending + * on the chain's error status. + */ +static ChainCheck chainCheckEmbeddedNull = { + { sizeof(chain27) / sizeof(chain27[0]), chain27 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_INVALID_NAME_CONSTRAINTS | + CERT_TRUST_INVALID_EXTENSION, 0 }, + 1, simpleStatus27 }, + 0 }; +static ChainCheck chainCheckEmbeddedNullBroken = { + { sizeof(chain27) / sizeof(chain27[0]), chain27 }, + { { CERT_TRUST_IS_NOT_TIME_NESTED | CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS | CERT_TRUST_HAS_PREFERRED_ISSUER }, + { CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, + CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS }, + 1, simpleStatus27Broken }, + 0 }; + +/* Wednesday, Oct 1, 2007 */ +static SYSTEMTIME oct2007 = { 2007, 10, 1, 1, 0, 0, 0, 0 }; +/* Wednesday, Oct 28, 2009 */ +static SYSTEMTIME oct2009 = { 2009, 10, 3, 28, 0, 0, 0, 0 }; + +static void testGetCertChain(void) +{ + BOOL ret; + PCCERT_CONTEXT cert; + CERT_CHAIN_PARA para = { 0 }; + PCCERT_CHAIN_CONTEXT chain; + FILETIME fileTime; + DWORD i; + HCERTSTORE store; + static char one_two_three[] = "1.2.3"; + static char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH; + LPSTR oids[2]; + + /* Basic parameter checks */ + if (0) + { + /* Crash on Vista */ + ret = pCertGetCertificateChain(NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + ret = pCertGetCertificateChain(NULL, NULL, NULL, NULL, NULL, 0, NULL, + &chain); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Crash + ret = pCertGetCertificateChain(NULL, NULL, NULL, NULL, ¶, 0, NULL, NULL); + ret = pCertGetCertificateChain(NULL, NULL, NULL, NULL, ¶, 0, NULL, + &chain); + */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + if (0) + { + /* Crash on Vista */ + ret = pCertGetCertificateChain(NULL, cert, NULL, NULL, NULL, 0, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + /* Crash + ret = pCertGetCertificateChain(NULL, cert, NULL, NULL, ¶, 0, NULL, NULL); + */ + + /* Tests with an invalid cert (one whose signature is bad) */ + SetLastError(0xdeadbeef); + ret = pCertGetCertificateChain(NULL, cert, NULL, NULL, ¶, 0, NULL, + &chain); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_DATA || + GetLastError() == CRYPT_E_ASN1_BADTAG /* Vista */, + "Expected ERROR_INVALID_DATA or CRYPT_E_ASN1_BADTAG, got %d\n", GetLastError()); + para.cbSize = sizeof(para); + SetLastError(0xdeadbeef); + ret = pCertGetCertificateChain(NULL, cert, NULL, NULL, ¶, 0, NULL, + &chain); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_DATA || + GetLastError() == CRYPT_E_ASN1_BADTAG /* Vista */, + "Expected ERROR_INVALID_DATA or CRYPT_E_ASN1_BADTAG, got %d\n", GetLastError()); + + para.cbSize = 0; + SetLastError(0xdeadbeef); + ret = pCertGetCertificateChain(NULL, cert, NULL, NULL, ¶, 0, NULL, + &chain); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_DATA || + GetLastError() == CRYPT_E_ASN1_BADTAG, /* Vista and higher */ + "Expected ERROR_INVALID_DATA or CRYPT_E_ASN1_BADTAG, got %d\n", GetLastError()); + + CertFreeCertificateContext(cert); + + /* Test usage match with Google's cert */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + verisignCA, sizeof(verisignCA), CERT_STORE_ADD_ALWAYS, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + thawte_sgc_ca, sizeof(thawte_sgc_ca), CERT_STORE_ADD_ALWAYS, NULL); + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + google, sizeof(google)); + SystemTimeToFileTime(&oct2009, &fileTime); + memset(¶, 0, sizeof(para)); + para.cbSize = sizeof(para); + oids[0] = one_two_three; + para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; + para.RequestedUsage.Usage.rgpszUsageIdentifier = oids; + para.RequestedUsage.Usage.cUsageIdentifier = 1; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + ok(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + "expected CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + CertFreeCertificateChain(chain); + } + oids[0] = oid_server_auth; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + ok(!(chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_VALID_FOR_USAGE), + "didn't expect CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + CertFreeCertificateChain(chain); + } + oids[1] = one_two_three; + para.RequestedUsage.Usage.cUsageIdentifier = 2; + para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + ok(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE, + "expected CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + CertFreeCertificateChain(chain); + } + para.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, store, ¶, + 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed: %08x\n", GetLastError()); + if (ret) + { + ok(!(chain->TrustStatus.dwErrorStatus & + CERT_TRUST_IS_NOT_VALID_FOR_USAGE), + "didn't expect CERT_TRUST_IS_NOT_VALID_FOR_USAGE\n"); + CertFreeCertificateChain(chain); + } + CertCloseStore(store, 0); + CertFreeCertificateContext(cert); + + for (i = 0; i < sizeof(chainCheck) / sizeof(chainCheck[0]); i++) + { + chain = getChain(&chainCheck[i].certs, 0, TRUE, &oct2007, + chainCheck[i].todo, i); + if (chain) + { + checkChainStatus(chain, &chainCheck[i].status, chainCheck[i].todo, + i); + pCertFreeCertificateChain(chain); + } + } + for (i = 0; i < sizeof(chainCheckNoStore) / sizeof(chainCheckNoStore[0]); + i++) + { + chain = getChain(&chainCheckNoStore[i].certs, 0, FALSE, &oct2007, + chainCheckNoStore[i].todo, i); + if (chain) + { + checkChainStatus(chain, &chainCheckNoStore[i].status, + chainCheckNoStore[i].todo, i); + pCertFreeCertificateChain(chain); + } + } + chain = getChain(&chainCheckEmbeddedNull.certs, 0, TRUE, &oct2007, + chainCheckEmbeddedNull.todo, 0); + if (chain) + { + ok(chain->TrustStatus.dwErrorStatus == + chainCheckEmbeddedNull.status.status.dwErrorStatus || + broken((chain->TrustStatus.dwErrorStatus & + ~chainCheckEmbeddedNullBroken.status.statusToIgnore.dwErrorStatus) == + (chainCheckEmbeddedNullBroken.status.status.dwErrorStatus & + ~chainCheckEmbeddedNullBroken.status.statusToIgnore.dwErrorStatus)), + "unexpected chain error status %08x\n", + chain->TrustStatus.dwErrorStatus); + if (chainCheckEmbeddedNull.status.status.dwErrorStatus == + chain->TrustStatus.dwErrorStatus) + checkChainStatus(chain, &chainCheckEmbeddedNull.status, + chainCheckEmbeddedNull.todo, 0); + else + checkChainStatus(chain, &chainCheckEmbeddedNullBroken.status, + chainCheckEmbeddedNullBroken.todo, 0); + pCertFreeCertificateChain(chain); + } +} + +static void test_CERT_CHAIN_PARA_cbSize(void) +{ + BOOL ret; + PCCERT_CONTEXT cert; + CERT_CHAIN_PARA para = { 0 }; + PCCERT_CHAIN_CONTEXT chain; + HCERTSTORE store; + DWORD i; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + ret = CertAddEncodedCertificateToStore(store, + X509_ASN_ENCODING, chain0_0, sizeof(chain0_0), + CERT_STORE_ADD_ALWAYS, NULL); + ret = CertAddEncodedCertificateToStore(store, + X509_ASN_ENCODING, chain0_1, sizeof(chain0_1), + CERT_STORE_ADD_ALWAYS, &cert); + + for (i = 0; i < sizeof(CERT_CHAIN_PARA) + 2; i++) + { + FILETIME fileTime; + + SystemTimeToFileTime(&oct2007, &fileTime); + + para.cbSize = i; + ret = pCertGetCertificateChain(NULL, cert, &fileTime, + NULL, ¶, 0, NULL, &chain); + ok(ret, "CertGetCertificateChain failed %u\n", GetLastError()); + pCertFreeCertificateChain(chain); + } + + CertFreeCertificateContext(cert); + CertCloseStore(store, 0); +} + +typedef struct _ChainPolicyCheck +{ + CONST_BLOB_ARRAY certs; + CERT_CHAIN_POLICY_STATUS status; + const CERT_CHAIN_POLICY_STATUS *brokenStatus; + DWORD todo; +} ChainPolicyCheck; + +static const ChainPolicyCheck basePolicyCheck[] = { + { { sizeof(chain0) / sizeof(chain0[0]), chain0 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain1) / sizeof(chain1[0]), chain1 }, + { 0, TRUST_E_CERT_SIGNATURE, 0, 0, NULL }, NULL, 0 }, + { { sizeof(chain2) / sizeof(chain2[0]), chain2 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain3) / sizeof(chain3[0]), chain3 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain4) / sizeof(chain4[0]), chain4 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain5) / sizeof(chain5[0]), chain5 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain6) / sizeof(chain6[0]), chain6 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain7) / sizeof(chain7[0]), chain7 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain8) / sizeof(chain8[0]), chain8 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain9) / sizeof(chain9[0]), chain9 }, + { 0, CERT_E_CHAINING, 0, -1, NULL }, NULL, 0 }, + { { sizeof(chain10) / sizeof(chain10[0]), chain10 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain11) / sizeof(chain11[0]), chain11 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain12) / sizeof(chain12[0]), chain12 }, + { 0, TRUST_E_CERT_SIGNATURE, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain13) / sizeof(chain13[0]), chain13 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain14) / sizeof(chain14[0]), chain14 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain15) / sizeof(chain15[0]), chain15 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain16) / sizeof(chain16[0]), chain16 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain17) / sizeof(chain17[0]), chain17 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain18) / sizeof(chain18[0]), chain18 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(selfSignedChain) / sizeof(selfSignedChain[0]), selfSignedChain }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 0, NULL }, NULL, 0 }, +}; + +static const ChainPolicyCheck sslPolicyCheck[] = { + { { sizeof(chain0) / sizeof(chain0[0]), chain0 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain1) / sizeof(chain1[0]), chain1 }, + { 0, TRUST_E_CERT_SIGNATURE, 0, 0, NULL }, NULL, 0 }, + { { sizeof(chain2) / sizeof(chain2[0]), chain2 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain3) / sizeof(chain3[0]), chain3 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain4) / sizeof(chain4[0]), chain4 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain5) / sizeof(chain5[0]), chain5 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain6) / sizeof(chain6[0]), chain6 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain7) / sizeof(chain7[0]), chain7 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain8) / sizeof(chain8[0]), chain8 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain9) / sizeof(chain9[0]), chain9 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, -1, NULL }, NULL, 0 }, + { { sizeof(chain10) / sizeof(chain10[0]), chain10 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain11) / sizeof(chain11[0]), chain11 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain12) / sizeof(chain12[0]), chain12 }, + { 0, TRUST_E_CERT_SIGNATURE, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain13) / sizeof(chain13[0]), chain13 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain14) / sizeof(chain14[0]), chain14 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain15) / sizeof(chain15[0]), chain15 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain16) / sizeof(chain16[0]), chain16 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain17) / sizeof(chain17[0]), chain17 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain18) / sizeof(chain18[0]), chain18 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(selfSignedChain) / sizeof(selfSignedChain[0]), selfSignedChain }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 0, NULL }, NULL, 0 }, +}; + +static const ChainPolicyCheck googlePolicyCheckWithMatchingNameExpired = { + { sizeof(googleChain) / sizeof(googleChain[0]), googleChain }, + { 0, CERT_E_EXPIRED, 0, 0, NULL}, NULL, 0 +}; + +static const ChainPolicyCheck googlePolicyCheckWithMatchingName = { + { sizeof(googleChain) / sizeof(googleChain[0]), googleChain }, + { 0, 0, -1, -1, NULL}, NULL, 0 +}; + +/* Windows NT 4 has a different error code when the name doesn't match. */ +static const CERT_CHAIN_POLICY_STATUS noMatchingNameBrokenStatus = + { 0, CERT_E_ROLE, 0, 0, NULL }; + +static const ChainPolicyCheck iTunesPolicyCheckWithoutMatchingName = { + { sizeof(iTunesChain) / sizeof(iTunesChain[0]), iTunesChain }, + { 0, CERT_E_CN_NO_MATCH, 0, 0, NULL}, &noMatchingNameBrokenStatus, 0 +}; + +static const ChainPolicyCheck opensslPolicyCheckWithMatchingName = { + { sizeof(opensslChain) / sizeof(opensslChain[0]), opensslChain }, + { 0, 0, -1, -1, NULL}, NULL, 0 +}; + +static const ChainPolicyCheck opensslPolicyCheckWithoutMatchingName = { + { sizeof(opensslChain) / sizeof(opensslChain[0]), opensslChain }, + { 0, CERT_E_CN_NO_MATCH, 0, 0, NULL}, NULL, 0 +}; + +static const ChainPolicyCheck stanfordPolicyCheckWithMatchingName = { + { sizeof(stanfordChain) / sizeof(stanfordChain[0]), stanfordChain }, + { 0, 0, -1, -1, NULL}, NULL, 0 +}; + +static const ChainPolicyCheck stanfordPolicyCheckWithoutMatchingName = { + { sizeof(stanfordChain) / sizeof(stanfordChain[0]), stanfordChain }, + { 0, CERT_E_CN_NO_MATCH, 0, 0, NULL}, NULL, 0 +}; + +static const ChainPolicyCheck authenticodePolicyCheck[] = { + { { sizeof(chain0) / sizeof(chain0[0]), chain0 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain1) / sizeof(chain1[0]), chain1 }, + { 0, TRUST_E_CERT_SIGNATURE, 0, 0, NULL }, NULL, 0 }, + { { sizeof(chain2) / sizeof(chain2[0]), chain2 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain3) / sizeof(chain3[0]), chain3 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain4) / sizeof(chain4[0]), chain4 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain5) / sizeof(chain5[0]), chain5 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain6) / sizeof(chain6[0]), chain6 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain7) / sizeof(chain7[0]), chain7 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain8) / sizeof(chain8[0]), chain8 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain9) / sizeof(chain9[0]), chain9 }, + { 0, CERT_E_CHAINING, 0, -1, NULL }, NULL, 0 }, + { { sizeof(chain10) / sizeof(chain10[0]), chain10 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain11) / sizeof(chain11[0]), chain11 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain12) / sizeof(chain12[0]), chain12 }, + { 0, TRUST_E_CERT_SIGNATURE, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain13) / sizeof(chain13[0]), chain13 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain14) / sizeof(chain14[0]), chain14 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain15) / sizeof(chain15[0]), chain15 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain16) / sizeof(chain16[0]), chain16 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain17) / sizeof(chain17[0]), chain17 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(chain18) / sizeof(chain18[0]), chain18 }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 2, NULL }, NULL, 0 }, + { { sizeof(selfSignedChain) / sizeof(selfSignedChain[0]), selfSignedChain }, + { 0, CERT_E_UNTRUSTEDROOT, 0, 0, NULL }, NULL, 0 }, +}; + +/* On some older systems, the element index is set to 2 rather than 1 for + * chain 4, because they do not catch the basic constraints error in the + * chain, which occurs at element 1. + */ +static const CERT_CHAIN_POLICY_STATUS chain4BrokenStatus = + { 0, TRUST_E_BASIC_CONSTRAINTS, 0, 2, NULL }; + +static const ChainPolicyCheck basicConstraintsPolicyCheck[] = { + { { sizeof(chain0) / sizeof(chain0[0]), chain0 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain1) / sizeof(chain1[0]), chain1 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain2) / sizeof(chain2[0]), chain2 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain3) / sizeof(chain3[0]), chain3 }, + { 0, TRUST_E_BASIC_CONSTRAINTS, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain4) / sizeof(chain4[0]), chain4 }, + { 0, TRUST_E_BASIC_CONSTRAINTS, 0, 1, NULL }, &chain4BrokenStatus, 0 }, + { { sizeof(chain5) / sizeof(chain5[0]), chain5 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain6) / sizeof(chain6[0]), chain6 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain7) / sizeof(chain7[0]), chain7 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain8) / sizeof(chain8[0]), chain8 }, + { 0, TRUST_E_BASIC_CONSTRAINTS, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain9) / sizeof(chain9[0]), chain9 }, + { 0, TRUST_E_BASIC_CONSTRAINTS, 0, 1, NULL }, NULL, 0 }, + { { sizeof(chain10) / sizeof(chain10[0]), chain10 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain11) / sizeof(chain11[0]), chain11 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain12) / sizeof(chain12[0]), chain12 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain13) / sizeof(chain13[0]), chain13 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain14) / sizeof(chain14[0]), chain14 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain15) / sizeof(chain15[0]), chain15 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain16) / sizeof(chain16[0]), chain16 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain17) / sizeof(chain17[0]), chain17 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(chain18) / sizeof(chain18[0]), chain18 }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, + { { sizeof(selfSignedChain) / sizeof(selfSignedChain[0]), selfSignedChain }, + { 0, 0, -1, -1, NULL }, NULL, 0 }, +}; + +static const char *num_to_str(WORD num) +{ + static char buf[6]; + + sprintf(buf, "#%04X", num); + return buf; +} + +static void checkChainPolicyStatus(LPCSTR policy, const ChainPolicyCheck *check, + DWORD testIndex, SYSTEMTIME *sysTime, PCERT_CHAIN_POLICY_PARA para) + +{ + PCCERT_CHAIN_CONTEXT chain = getChain(&check->certs, 0, TRUE, sysTime, + check->todo, testIndex); + + if (chain) + { + CERT_CHAIN_POLICY_STATUS policyStatus = { 0 }; + BOOL ret = pCertVerifyCertificateChainPolicy(policy, chain, para, + &policyStatus); + + if (check->todo & TODO_POLICY) + todo_wine ok(ret, + "%s[%d]: CertVerifyCertificateChainPolicy failed: %08x\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), + testIndex, GetLastError()); + else + { + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("%d: missing policy %s, skipping test\n", testIndex, + HIWORD(policy) ? policy : num_to_str(LOWORD(policy))); + pCertFreeCertificateChain(chain); + return; + } + ok(ret, "%s[%d]: CertVerifyCertificateChainPolicy failed: %08x\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), testIndex, + GetLastError()); + } + if (ret) + { + if (check->todo & TODO_ERROR) + todo_wine ok(policyStatus.dwError == check->status.dwError || + broken(policyStatus.dwError == CERT_TRUST_NO_ERROR) || + (check->brokenStatus && broken(policyStatus.dwError == + check->brokenStatus->dwError)), + "%s[%d]: expected %08x, got %08x\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), + testIndex, check->status.dwError, policyStatus.dwError); + else + ok(policyStatus.dwError == check->status.dwError || + broken(policyStatus.dwError == CERT_TRUST_NO_ERROR) || + (check->brokenStatus && broken(policyStatus.dwError == + check->brokenStatus->dwError)), + "%s[%d]: expected %08x, got %08x\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), + testIndex, check->status.dwError, policyStatus.dwError); + if (policyStatus.dwError != check->status.dwError) + { + skip("%s[%d]: error %08x doesn't match expected %08x, not checking indexes\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), + testIndex, policyStatus.dwError, check->status.dwError); + pCertFreeCertificateChain(chain); + return; + } + if (check->todo & TODO_CHAINS) + todo_wine ok(policyStatus.lChainIndex == + check->status.lChainIndex || + (check->brokenStatus && broken(policyStatus.lChainIndex == + check->brokenStatus->lChainIndex)), + "%s[%d]: expected %d, got %d\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), + testIndex, check->status.lChainIndex, + policyStatus.lChainIndex); + else + ok(policyStatus.lChainIndex == check->status.lChainIndex || + (check->brokenStatus && broken(policyStatus.lChainIndex == + check->brokenStatus->lChainIndex)), + "%s[%d]: expected %d, got %d\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), + testIndex, + check->status.lChainIndex, policyStatus.lChainIndex); + if (check->todo & TODO_ELEMENTS) + todo_wine ok(policyStatus.lElementIndex == + check->status.lElementIndex || + (check->brokenStatus && broken(policyStatus.lElementIndex == + check->brokenStatus->lElementIndex)), + "%s[%d]: expected %d, got %d\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), + testIndex, + check->status.lElementIndex, policyStatus.lElementIndex); + else + ok(policyStatus.lElementIndex == check->status.lElementIndex || + (check->brokenStatus && broken(policyStatus.lElementIndex == + check->brokenStatus->lElementIndex)), + "%s[%d]: expected %d, got %d\n", + HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), + testIndex, + check->status.lElementIndex, policyStatus.lElementIndex); + } + pCertFreeCertificateChain(chain); + } +} + +static void check_ssl_policy(void) +{ + DWORD i; + CERT_CHAIN_POLICY_PARA policyPara = { 0 }; + SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslPolicyPara = { { 0 } }; + WCHAR winehq[] = { 'w','i','n','e','h','q','.','o','r','g',0 }; + WCHAR google_dot_com[] = { 'w','w','w','.','g','o','o','g','l','e','.', + 'c','o','m',0 }; + WCHAR a_dot_openssl_dot_org[] = { 'a','.','o','p','e','n','s','s','l','.', + 'o','r','g',0 }; + WCHAR openssl_dot_org[] = { 'o','p','e','n','s','s','l','.','o','r','g',0 }; + WCHAR fopenssl_dot_org[] = { 'f','o','p','e','n','s','s','l','.', + 'o','r','g',0 }; + WCHAR a_dot_b_dot_openssl_dot_org[] = { 'a','.','b','.', + 'o','p','e','n','s','s','l','.','o','r','g',0 }; + WCHAR cs_dot_stanford_dot_edu[] = { 'c','s','.', + 's','t','a','n','f','o','r','d','.','e','d','u',0 }; + WCHAR www_dot_cs_dot_stanford_dot_edu[] = { 'w','w','w','.','c','s','.', + 's','t','a','n','f','o','r','d','.','e','d','u',0 }; + WCHAR a_dot_cs_dot_stanford_dot_edu[] = { 'a','.','c','s','.', + 's','t','a','n','f','o','r','d','.','e','d','u',0 }; + + /* Check ssl policy with no parameter */ + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, NULL); + /* Check again with a policy parameter that specifies nothing */ + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, &policyPara); + /* Check yet again, but specify an empty SSL_EXTRA_CERT_CHAIN_POLICY_PARA + * argument. + */ + policyPara.pvExtraPolicyPara = &sslPolicyPara; + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, &policyPara); + /* And again, but specify the auth type as a client */ + sslPolicyPara.dwAuthType = AUTHTYPE_CLIENT; + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, &policyPara); + /* And again, but specify the auth type as a server */ + sslPolicyPara.dwAuthType = AUTHTYPE_SERVER; + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, &policyPara); + /* And again authenticating a client, but specify the size of the policy + * parameter. + */ + sslPolicyPara.cbSize = sizeof(sslPolicyCheck); + sslPolicyPara.dwAuthType = AUTHTYPE_CLIENT; + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, &policyPara); + /* One more time authenticating a client, but specify winehq.org as the + * server name. + */ + sslPolicyPara.pwszServerName = winehq; + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, &policyPara); + /* And again authenticating a server, still specifying winehq.org as the + * server name. + */ + sslPolicyPara.dwAuthType = AUTHTYPE_SERVER; + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, &policyPara); + /* And again authenticating a server, this time specifying the size of the + * policy param. + */ + policyPara.cbSize = sizeof(policyPara); + for (i = 0; + i < sizeof(sslPolicyCheck) / sizeof(sslPolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, &sslPolicyCheck[i], i, + &oct2007, &policyPara); + /* Yet again, but checking the iTunes chain, which contains a name + * extension. + */ + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &iTunesPolicyCheckWithoutMatchingName, 0, &oct2007, &policyPara); + /* And again, but checking the Google chain at a bad date */ + sslPolicyPara.pwszServerName = google_dot_com; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &googlePolicyCheckWithMatchingNameExpired, 0, &oct2007, &policyPara); + /* And again, but checking the Google chain at a good date */ + sslPolicyPara.pwszServerName = google_dot_com; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &googlePolicyCheckWithMatchingName, 0, &oct2009, &policyPara); + /* Check again with the openssl cert, which has a wildcard in its name, + * with various combinations of matching and non-matching names. + * With "a.openssl.org": match + */ + sslPolicyPara.pwszServerName = a_dot_openssl_dot_org; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &opensslPolicyCheckWithMatchingName, 0, &oct2009, &policyPara); + /* With "openssl.org": no match */ + sslPolicyPara.pwszServerName = openssl_dot_org; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &opensslPolicyCheckWithoutMatchingName, 0, &oct2009, &policyPara); + /* With "fopenssl.org": no match */ + sslPolicyPara.pwszServerName = fopenssl_dot_org; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &opensslPolicyCheckWithoutMatchingName, 0, &oct2009, &policyPara); + /* with "a.b.openssl.org": no match */ + sslPolicyPara.pwszServerName = a_dot_b_dot_openssl_dot_org; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &opensslPolicyCheckWithoutMatchingName, 0, &oct2009, &policyPara); + /* Check again with the cs.stanford.edu, which has both cs.stanford.edu + * and www.cs.stanford.edu in its subject alternative name. + * With "cs.stanford.edu": match + */ + sslPolicyPara.pwszServerName = cs_dot_stanford_dot_edu; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &stanfordPolicyCheckWithMatchingName, 0, &oct2009, &policyPara); + /* With "www.cs.stanford.edu": match */ + sslPolicyPara.pwszServerName = www_dot_cs_dot_stanford_dot_edu; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &stanfordPolicyCheckWithMatchingName, 0, &oct2009, &policyPara); + /* With "a.cs.stanford.edu": no match */ + sslPolicyPara.pwszServerName = a_dot_cs_dot_stanford_dot_edu; + checkChainPolicyStatus(CERT_CHAIN_POLICY_SSL, + &stanfordPolicyCheckWithoutMatchingName, 0, &oct2009, &policyPara); +} + +static void testVerifyCertChainPolicy(void) +{ + BOOL ret; + PCCERT_CONTEXT cert; + CERT_CHAIN_PARA chainPara = { sizeof(CERT_CHAIN_PARA), { 0 } }; + PCCERT_CHAIN_CONTEXT chain; + CERT_CHAIN_POLICY_STATUS policyStatus = { 0 }; + CERT_CHAIN_POLICY_PARA policyPara = { 0 }; + DWORD i; + + if (!pCertVerifyCertificateChainPolicy) + { + win_skip("CertVerifyCertificateChainPolicy() is not available\n"); + return; + } + + /* Crash + ret = pCertVerifyCertificateChainPolicy(NULL, NULL, NULL, NULL); + ret = pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, NULL, NULL, + NULL); + ret = pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, NULL, + &chainPara, NULL); + */ + SetLastError(0xdeadbeef); + ret = pCertVerifyCertificateChainPolicy(NULL, NULL, NULL, &policyStatus); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* Crashes + ret = pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, NULL, NULL, + &policyStatus); + */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert, + sizeof(selfSignedCert)); + pCertGetCertificateChain(NULL, cert, NULL, NULL, &chainPara, 0, NULL, + &chain); + /* Crash + ret = pCertVerifyCertificateChainPolicy(NULL, chain, NULL, NULL); + ret = pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, chain, NULL, + NULL); + ret = pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, chain, + &chainPara, NULL); + */ + /* Size of policy status is apparently ignored, as is pChainPolicyPara */ + ret = pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, chain, NULL, + &policyStatus); + ok(ret, "CertVerifyCertificateChainPolicy failed: %08x\n", GetLastError()); + ok(policyStatus.dwError == CERT_E_UNTRUSTEDROOT, + "Expected CERT_E_UNTRUSTEDROOT, got %08x\n", policyStatus.dwError); + ok(policyStatus.lChainIndex == 0 && policyStatus.lElementIndex == 0, + "Expected both indexes 0, got %d, %d\n", policyStatus.lChainIndex, + policyStatus.lElementIndex); + ret = pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, chain, + &policyPara, &policyStatus); + ok(ret, "CertVerifyCertificateChainPolicy failed: %08x\n", GetLastError()); + ok(policyStatus.dwError == CERT_E_UNTRUSTEDROOT, + "Expected CERT_E_UNTRUSTEDROOT, got %08x\n", policyStatus.dwError); + ok(policyStatus.lChainIndex == 0 && policyStatus.lElementIndex == 0, + "Expected both indexes 0, got %d, %d\n", policyStatus.lChainIndex, + policyStatus.lElementIndex); + pCertFreeCertificateChain(chain); + CertFreeCertificateContext(cert); + + for (i = 0; + i < sizeof(basePolicyCheck) / sizeof(basePolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_BASE, &basePolicyCheck[i], i, + &oct2007, NULL); + check_ssl_policy(); + /* The authenticode policy doesn't seem to check anything beyond the base + * policy. It might check for chains signed by the MS test cert, but none + * of these chains is. + */ + for (i = 0; i < + sizeof(authenticodePolicyCheck) / sizeof(authenticodePolicyCheck[0]); i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_AUTHENTICODE, + &authenticodePolicyCheck[i], i, &oct2007, NULL); + for (i = 0; i < + sizeof(basicConstraintsPolicyCheck) / sizeof(basicConstraintsPolicyCheck[0]); + i++) + checkChainPolicyStatus(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS, + &basicConstraintsPolicyCheck[i], i, &oct2007, NULL); +} + +START_TEST(chain) +{ + HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll"); + pCertCreateCertificateChainEngine = (void*)GetProcAddress(hCrypt32, "CertCreateCertificateChainEngine"); + pCertGetCertificateChain = (void*)GetProcAddress(hCrypt32, "CertGetCertificateChain"); + pCertFreeCertificateChain = (void*)GetProcAddress(hCrypt32, "CertFreeCertificateChain"); + pCertFreeCertificateChainEngine = (void*)GetProcAddress(hCrypt32, "CertFreeCertificateChainEngine"); + pCertVerifyCertificateChainPolicy = (void*)GetProcAddress(hCrypt32, "CertVerifyCertificateChainPolicy"); + + testCreateCertChainEngine(); + if (!pCertGetCertificateChain) + { + win_skip("CertGetCertificateChain() is not available\n"); + } + else + { + testVerifyCertChainPolicy(); + testGetCertChain(); + test_CERT_CHAIN_PARA_cbSize(); + } +} diff --git a/rostests/winetests/crypt32/crl.c b/rostests/winetests/crypt32/crl.c new file mode 100644 index 00000000000..bb622198aa7 --- /dev/null +++ b/rostests/winetests/crypt32/crl.c @@ -0,0 +1,1189 @@ +/* + * crypt32 CRL functions tests + * + * Copyright 2005-2006 Juan Lang + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + + +static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE bigCertWithDifferentIssuer[] = { 0x30, 0x7a, 0x02, 0x01, + 0x01, 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, + 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, + 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, + 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, + 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, + 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x01 }; +static const BYTE CRL[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00, + 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, + 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, + 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x5a }; +static const BYTE newerCRL[] = { 0x30, 0x2a, 0x30, 0x02, 0x06, 0x00, 0x30, + 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, + 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x17, 0x0d, 0x30, 0x36, + 0x30, 0x35, 0x31, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a }; +static const BYTE signedCRL[] = { 0x30, 0x45, 0x30, 0x2c, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, + 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; + +static BOOL (WINAPI *pCertFindCertificateInCRL)(PCCERT_CONTEXT,PCCRL_CONTEXT,DWORD,void*,PCRL_ENTRY*); +static PCCRL_CONTEXT (WINAPI *pCertFindCRLInStore)(HCERTSTORE,DWORD,DWORD,DWORD,const void*,PCCRL_CONTEXT); +static BOOL (WINAPI *pCertIsValidCRLForCertificate)(PCCERT_CONTEXT, PCCRL_CONTEXT, DWORD, void*); + +static void init_function_pointers(void) +{ + HMODULE hdll = GetModuleHandleA("crypt32.dll"); + pCertFindCertificateInCRL = (void*)GetProcAddress(hdll, "CertFindCertificateInCRL"); + pCertFindCRLInStore = (void*)GetProcAddress(hdll, "CertFindCRLInStore"); + pCertIsValidCRLForCertificate = (void*)GetProcAddress(hdll, "CertIsValidCRLForCertificate"); +} + +static void testCreateCRL(void) +{ + PCCRL_CONTEXT context; + DWORD GLE; + + context = CertCreateCRLContext(0, NULL, 0); + ok(!context && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + context = CertCreateCRLContext(X509_ASN_ENCODING, NULL, 0); + GLE = GetLastError(); + ok(!context && (GLE == CRYPT_E_ASN1_EOD || GLE == OSS_MORE_INPUT), + "Expected CRYPT_E_ASN1_EOD or OSS_MORE_INPUT, got %08x\n", GLE); + context = CertCreateCRLContext(X509_ASN_ENCODING, bigCert, sizeof(bigCert)); + GLE = GetLastError(); + ok(!context, "Expected failure\n"); + context = CertCreateCRLContext(X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL) - 1); + ok(!context, "Expected failure\n"); + context = CertCreateCRLContext(X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL)); + ok(context != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); + if (context) + CertFreeCRLContext(context); + context = CertCreateCRLContext(X509_ASN_ENCODING, CRL, sizeof(CRL)); + ok(context != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); + if (context) + CertFreeCRLContext(context); +} + +static void testDupCRL(void) +{ + PCCRL_CONTEXT context, dupContext; + + context = CertDuplicateCRLContext(NULL); + ok(context == NULL, "expected NULL\n"); + context = CertCreateCRLContext(X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL)); + dupContext = CertDuplicateCRLContext(context); + ok(dupContext != NULL, "expected a context\n"); + ok(dupContext == context, "expected identical context addresses\n"); + CertFreeCRLContext(dupContext); + CertFreeCRLContext(context); +} + +static void testAddCRL(void) +{ + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + PCCRL_CONTEXT context; + BOOL ret; + DWORD GLE; + + if (!store) return; + + /* Bad CRL encoding type */ + ret = CertAddEncodedCRLToStore(0, 0, NULL, 0, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(store, 0, NULL, 0, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(0, 0, signedCRL, sizeof(signedCRL), 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(store, 0, signedCRL, sizeof(signedCRL), 0, + NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(0, 0, signedCRL, sizeof(signedCRL), + CERT_STORE_ADD_ALWAYS, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(store, 0, signedCRL, sizeof(signedCRL), + CERT_STORE_ADD_ALWAYS, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + + /* No CRL */ + ret = CertAddEncodedCRLToStore(0, X509_ASN_ENCODING, NULL, 0, 0, NULL); + GLE = GetLastError(); + ok(!ret && (GLE == CRYPT_E_ASN1_EOD || GLE == OSS_MORE_INPUT), + "Expected CRYPT_E_ASN1_EOD or OSS_MORE_INPUT, got %08x\n", GLE); + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, NULL, 0, 0, NULL); + GLE = GetLastError(); + ok(!ret && (GLE == CRYPT_E_ASN1_EOD || GLE == OSS_MORE_INPUT), + "Expected CRYPT_E_ASN1_EOD or OSS_MORE_INPUT, got %08x\n", GLE); + + /* Weird--bad add disposition leads to an access violation in Windows. + * Both tests crash on some win9x boxes. + */ + if (0) + { + ret = CertAddEncodedCRLToStore(0, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), 0, NULL); + ok(!ret && (GetLastError() == STATUS_ACCESS_VIOLATION || + GetLastError() == E_INVALIDARG /* Vista */), + "Expected STATUS_ACCESS_VIOLATION or E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), 0, NULL); + ok(!ret && (GetLastError() == STATUS_ACCESS_VIOLATION || + GetLastError() == E_INVALIDARG /* Vista */), + "Expected STATUS_ACCESS_VIOLATION or E_INVALIDARG, got %08x\n", GetLastError()); + } + + /* Weird--can add a CRL to the NULL store (does this have special meaning?) + */ + context = NULL; + ret = CertAddEncodedCRLToStore(0, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, &context); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + if (context) + CertFreeCRLContext(context); + + /* Normal cases: a "signed" CRL is okay.. */ + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL); + /* and an unsigned one is too. */ + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, CRL, sizeof(CRL), + CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, newerCRL, + sizeof(newerCRL), CERT_STORE_ADD_NEW, NULL); + ok(!ret && GetLastError() == CRYPT_E_EXISTS, + "Expected CRYPT_E_EXISTS, got %08x\n", GetLastError()); + + /* This should replace (one of) the existing CRL(s). */ + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, newerCRL, + sizeof(newerCRL), CERT_STORE_ADD_NEWER, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + + CertCloseStore(store, 0); +} + +static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a }; +static const BYTE v2CRLWithIssuingDistPoint[] = { +0x30,0x70,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0xa0,0x27, +0x30,0x25,0x30,0x23,0x06,0x03,0x55,0x1d,0x1c,0x01,0x01,0xff,0x04,0x19,0x30, +0x17,0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77, +0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67 }; +static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01, + 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, + 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43, + 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33, + 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51, + 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99, + 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31, + 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0, + 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30, + 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30, + 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75, + 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88, + 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd, + 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf, + 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46, + 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f, + 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75, + 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f, + 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82, + 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07, + 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c, + 0xcd }; +static const BYTE verisignCommercialSoftPubCA[] = { +0x30,0x82,0x02,0x40,0x30,0x82,0x01,0xa9,0x02,0x10,0x03,0xc7,0x8f,0x37,0xdb,0x92, +0x28,0xdf,0x3c,0xbb,0x1a,0xad,0x82,0xfa,0x67,0x10,0x30,0x0d,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x01,0x02,0x05,0x00,0x30,0x61,0x31,0x11,0x30,0x0f,0x06, +0x03,0x55,0x04,0x07,0x13,0x08,0x49,0x6e,0x74,0x65,0x72,0x6e,0x65,0x74,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x33,0x30,0x31,0x06,0x03,0x55,0x04,0x0b, +0x13,0x2a,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6f,0x6d,0x6d,0x65, +0x72,0x63,0x69,0x61,0x6c,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x50, +0x75,0x62,0x6c,0x69,0x73,0x68,0x65,0x72,0x73,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d, +0x39,0x36,0x30,0x34,0x30,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30, +0x34,0x30,0x31,0x30,0x37,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x61,0x31,0x11, +0x30,0x0f,0x06,0x03,0x55,0x04,0x07,0x13,0x08,0x49,0x6e,0x74,0x65,0x72,0x6e,0x65, +0x74,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69, +0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x33,0x30,0x31,0x06,0x03, +0x55,0x04,0x0b,0x13,0x2a,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6f, +0x6d,0x6d,0x65,0x72,0x63,0x69,0x61,0x6c,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72, +0x65,0x20,0x50,0x75,0x62,0x6c,0x69,0x73,0x68,0x65,0x72,0x73,0x20,0x43,0x41,0x30, +0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc3,0xd3,0x69,0x65, +0x52,0x01,0x94,0x54,0xab,0x28,0xc6,0x62,0x18,0xb3,0x54,0x55,0xc5,0x44,0x87,0x45, +0x4a,0x3b,0xc2,0x7e,0xd8,0xd3,0xd7,0xc8,0x80,0x86,0x8d,0xd8,0x0c,0xf1,0x16,0x9c, +0xcc,0x6b,0xa9,0x29,0xb2,0x8f,0x76,0x73,0x92,0xc8,0xc5,0x62,0xa6,0x3c,0xed,0x1e, +0x05,0x75,0xf0,0x13,0x00,0x6c,0x14,0x4d,0xd4,0x98,0x90,0x07,0xbe,0x69,0x73,0x81, +0xb8,0x62,0x4e,0x31,0x1e,0xd1,0xfc,0xc9,0x0c,0xeb,0x7d,0x90,0xbf,0xae,0xb4,0x47, +0x51,0xec,0x6f,0xce,0x64,0x35,0x02,0xd6,0x7d,0x67,0x05,0x77,0xe2,0x8f,0xd9,0x51, +0xd7,0xfb,0x97,0x19,0xbc,0x3e,0xd7,0x77,0x81,0xc6,0x43,0xdd,0xf2,0xdd,0xdf,0xca, +0xa3,0x83,0x8b,0xcb,0x41,0xc1,0x3d,0x22,0x48,0x48,0xa6,0x19,0x02,0x03,0x01,0x00, +0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x02,0x05,0x00, +0x03,0x81,0x81,0x00,0xb5,0xbc,0xb0,0x75,0x6a,0x89,0xa2,0x86,0xbd,0x64,0x78,0xc3, +0xa7,0x32,0x75,0x72,0x11,0xaa,0x26,0x02,0x17,0x60,0x30,0x4c,0xe3,0x48,0x34,0x19, +0xb9,0x52,0x4a,0x51,0x18,0x80,0xfe,0x53,0x2d,0x7b,0xd5,0x31,0x8c,0xc5,0x65,0x99, +0x41,0x41,0x2f,0xf2,0xae,0x63,0x7a,0xe8,0x73,0x99,0x15,0x90,0x1a,0x1f,0x7a,0x8b, +0x41,0xd0,0x8e,0x3a,0xd0,0xcd,0x38,0x34,0x44,0xd0,0x75,0xf8,0xea,0x71,0xc4,0x81, +0x19,0x38,0x17,0x35,0x4a,0xae,0xc5,0x3e,0x32,0xe6,0x21,0xb8,0x05,0xc0,0x93,0xe1, +0xc7,0x38,0x5c,0xd8,0xf7,0x93,0x38,0x64,0x90,0xed,0x54,0xce,0xca,0xd3,0xd3,0xd0, +0x5f,0xef,0x04,0x9b,0xde,0x02,0x82,0xdd,0x88,0x29,0xb1,0xc3,0x4f,0xa5,0xcd,0x71, +0x64,0x31,0x3c,0x3c +}; +static const BYTE rootWithKeySignAndCRLSign[] = { +0x30,0x82,0x01,0xdf,0x30,0x82,0x01,0x4c,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x5b,0xc7,0x0b,0x27,0x99,0xbb,0x2e,0x99,0x47,0x9d,0x45,0x4e,0x7c,0x1a,0xca, +0xe8,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1d,0x05,0x00,0x30,0x10,0x31, +0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31, +0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05, +0x43,0x65,0x72,0x74,0x31,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89, +0x02,0x81,0x81,0x00,0xad,0x7e,0xca,0xf3,0xe5,0x99,0xc2,0x2a,0xca,0x50,0x82, +0x7c,0x2d,0xa4,0x81,0xcd,0x0d,0x0d,0x86,0xd7,0xd8,0xb2,0xde,0xc5,0xc3,0x34, +0x9e,0x07,0x78,0x08,0x11,0x12,0x2d,0x21,0x0a,0x09,0x07,0x14,0x03,0x7a,0xe7, +0x3b,0x58,0xf1,0xde,0x3e,0x01,0x25,0x93,0xab,0x8f,0xce,0x1f,0xc1,0x33,0x91, +0xfe,0x59,0xb9,0x3b,0x9e,0x95,0x12,0x89,0x8e,0xc3,0x4b,0x98,0x1b,0x99,0xc5, +0x07,0xe2,0xdf,0x15,0x4c,0x39,0x76,0x06,0xad,0xdb,0x16,0x06,0x49,0xba,0xcd, +0x0f,0x07,0xd6,0xea,0x27,0xa6,0xfe,0x3d,0x88,0xe5,0x97,0x45,0x72,0xb6,0x1c, +0xc0,0x1c,0xb1,0xa2,0x89,0xe8,0x37,0x9e,0xf6,0x2a,0xcf,0xd5,0x1f,0x2f,0x35, +0x5e,0x8f,0x3a,0x9c,0x61,0xb1,0xf1,0x6c,0xff,0x8c,0xb2,0x2f,0x02,0x03,0x01, +0x00,0x01,0xa3,0x42,0x30,0x40,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01, +0xff,0x04,0x04,0x03,0x02,0x00,0x06,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01, +0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1d,0x06,0x03,0x55,0x1d, +0x0e,0x04,0x16,0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0, +0x58,0xff,0x98,0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x09,0x06,0x05,0x2b, +0x0e,0x03,0x02,0x1d,0x05,0x00,0x03,0x81,0x81,0x00,0x74,0xcb,0x21,0xfd,0x2d, +0x25,0xdc,0xa5,0xaa,0xa1,0x26,0xdc,0x8b,0x40,0x11,0x64,0xae,0x5c,0x71,0x3c, +0x28,0xbc,0xf9,0xb3,0xcb,0xa5,0x94,0xb2,0x8d,0x4c,0x23,0x2b,0x9b,0xde,0x2c, +0x4c,0x30,0x04,0xc6,0x88,0x10,0x2f,0x53,0xfd,0x6c,0x82,0xf1,0x13,0xfb,0xda, +0x27,0x75,0x25,0x48,0xe4,0x72,0x09,0x2a,0xee,0xb4,0x1e,0xc9,0x55,0xf5,0xf7, +0x82,0x91,0xd8,0x4b,0xe4,0x3a,0xfe,0x97,0x87,0xdf,0xfb,0x15,0x5a,0x12,0x3e, +0x12,0xe6,0xad,0x40,0x0b,0xcf,0xee,0x1a,0x44,0xe0,0x83,0xb2,0x67,0x94,0xd4, +0x2e,0x7c,0xf2,0x06,0x9d,0xb3,0x3b,0x7e,0x2f,0xda,0x25,0x66,0x7e,0xa7,0x1f, +0x45,0xd4,0xf5,0xe3,0xdf,0x2a,0xf1,0x18,0x28,0x20,0xb5,0xf8,0xf5,0x8d,0x7a, +0x2e,0x84,0xee }; +static const BYTE eeCert[] = { +0x30,0x82,0x01,0x93,0x30,0x81,0xfd,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00, +0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65, +0x72,0x74,0x31,0x30,0x1e,0x17,0x0d,0x30,0x37,0x30,0x35,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x37,0x31,0x30,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x30,0x10,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04, +0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x32,0x30,0x81,0x9f,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d,0x00, +0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xb8,0x52,0xda,0xc5,0x4b,0x3f,0xe5,0x33, +0x0e,0x67,0x5f,0x48,0x21,0xdc,0x7e,0xef,0x37,0x33,0xba,0xff,0xb4,0xc6,0xdc, +0xb6,0x17,0x8e,0x20,0x55,0x07,0x12,0xd2,0x7b,0x3c,0xce,0x30,0xc5,0xa7,0x48, +0x9f,0x6e,0xfe,0xb8,0xbe,0xdb,0x9f,0x9b,0x17,0x60,0x16,0xde,0xc6,0x8b,0x47, +0xd1,0x57,0x71,0x3c,0x93,0xfc,0xbd,0xec,0x44,0x32,0x3b,0xb9,0xcf,0x6b,0x05, +0x72,0xa7,0x87,0x8e,0x7e,0xd4,0x9a,0x87,0x1c,0x2f,0xb7,0x82,0x40,0xfc,0x6a, +0x80,0x83,0x68,0x28,0xce,0x84,0xf4,0x0b,0x2e,0x44,0xcb,0x53,0xac,0x85,0x85, +0xb5,0x46,0x36,0x98,0x3c,0x10,0x02,0xaa,0x02,0xbc,0x8b,0xa2,0x23,0xb2,0xd3, +0x51,0x9a,0x22,0x4a,0xe3,0xaa,0x4e,0x7c,0xda,0x38,0xcf,0x49,0x98,0x72,0xa3, +0x02,0x03,0x01,0x00,0x01,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x22,0xf1,0x66,0x00,0x79,0xd2, +0xe6,0xb2,0xb2,0xf7,0x2f,0x98,0x92,0x7d,0x73,0xc3,0x6c,0x5c,0x77,0x20,0xe3, +0xbf,0x3e,0xe0,0xb3,0x5c,0x68,0xb4,0x9b,0x3a,0x41,0xae,0x94,0xa0,0x80,0x3a, +0xfe,0x5d,0x7a,0x56,0x87,0x85,0x44,0x45,0xcf,0xa6,0xd3,0x10,0xe7,0x73,0x41, +0xf2,0x7f,0x88,0x85,0x91,0x8e,0xe6,0xec,0xe2,0xce,0x08,0xbc,0xa5,0x76,0xe5, +0x4d,0x1d,0xb7,0x70,0x31,0xdd,0xc9,0x9a,0x15,0x32,0x11,0x5a,0x4e,0x62,0xc8, +0xd1,0xf8,0xec,0x46,0x39,0x5b,0xe7,0x67,0x1f,0x58,0xe8,0xa1,0xa0,0x5b,0xf7, +0x8a,0x6d,0x5f,0x91,0x18,0xd4,0x90,0x85,0xff,0x30,0xc7,0xca,0x9c,0xc6,0x92, +0xb0,0xca,0x16,0xc4,0xa4,0xc0,0xd6,0xe8,0xff,0x15,0x19,0xd1,0x30,0x61,0xf3, +0xef,0x9f }; +static const BYTE rootSignedCRL[] = { +0x30,0x82,0x01,0x1d,0x30,0x81,0x87,0x02,0x01,0x01,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x10,0x31,0x0e,0x30, +0x0c,0x06,0x03,0x55,0x04,0x03,0x13,0x05,0x43,0x65,0x72,0x74,0x31,0x17,0x0d, +0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x30,0x37,0x31,0x32,0x33,0x31,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x14, +0x30,0x12,0x02,0x01,0x01,0x17,0x0d,0x30,0x37,0x30,0x39,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0xa0,0x2d,0x30,0x2b,0x30,0x0a,0x06,0x03,0x55,0x1d, +0x14,0x04,0x03,0x02,0x01,0x01,0x30,0x1d,0x06,0x03,0x55,0x1d,0x23,0x04,0x16, +0x04,0x14,0x14,0x8c,0x16,0xbb,0xbe,0x70,0xa2,0x28,0x89,0xa0,0x58,0xff,0x98, +0xbd,0xa8,0x24,0x2b,0x8a,0xe9,0x9a,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0x9b,0x2b,0x99,0x0d, +0x16,0x83,0x93,0x54,0x29,0x3a,0xa6,0x53,0x5d,0xf8,0xa6,0x73,0x9f,0x2a,0x45, +0x39,0x91,0xff,0x91,0x1c,0x27,0x06,0xe8,0xdb,0x72,0x3f,0x66,0x89,0x15,0x68, +0x55,0xd5,0x49,0x63,0xa6,0x00,0xe9,0x66,0x9c,0x97,0xf9,0xb3,0xb3,0x2b,0x1b, +0xc7,0x79,0x46,0xa8,0xd8,0x2b,0x78,0x27,0xa0,0x70,0x02,0x81,0xc6,0x40,0xb3, +0x76,0x32,0x65,0x4c,0xf8,0xff,0x1d,0x41,0x6e,0x16,0x09,0xa2,0x8a,0x7b,0x0c, +0xd0,0xa6,0x9b,0x61,0xa3,0x7c,0x02,0x91,0x79,0xdf,0x6a,0x5e,0x88,0x95,0x66, +0x33,0x17,0xcb,0x5a,0xd2,0xdc,0x89,0x05,0x62,0x97,0x60,0x73,0x7b,0x2c,0x1a, +0x90,0x20,0x73,0x24,0x9f,0x45,0x22,0x4b,0xc1,0x33,0xd1,0xda,0xd8,0x7e,0x1b, +0x3d,0x74,0xd6,0x3b }; + +static void testFindCRL(void) +{ + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + PCCRL_CONTEXT context; + PCCERT_CONTEXT cert, endCert, rootCert; + CRL_FIND_ISSUED_FOR_PARA issuedForPara = { NULL, NULL }; + DWORD count, revoked_count; + BOOL ret; + + if (!store) return; + if (!pCertFindCRLInStore) + { + win_skip("CertFindCRLInStore() is not available\n"); + return; + } + + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + + /* Crashes + context = pCertFindCRLInStore(NULL, 0, 0, 0, NULL, NULL); + */ + + /* Find any context */ + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ANY, NULL, NULL); + ok(context != NULL, "Expected a context\n"); + if (context) + CertFreeCRLContext(context); + /* Bogus flags are ignored */ + context = pCertFindCRLInStore(store, 0, 1234, CRL_FIND_ANY, NULL, NULL); + ok(context != NULL, "Expected a context\n"); + if (context) + CertFreeCRLContext(context); + /* CRL encoding type is ignored too */ + context = pCertFindCRLInStore(store, 1234, 0, CRL_FIND_ANY, NULL, NULL); + ok(context != NULL, "Expected a context\n"); + if (context) + CertFreeCRLContext(context); + + /* This appears to match any cert */ + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_BY, NULL, NULL); + ok(context != NULL, "Expected a context\n"); + if (context) + CertFreeCRLContext(context); + + /* Try to match an issuer that isn't in the store */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2, + sizeof(bigCert2)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_BY, cert, NULL); + ok(context == NULL, "Expected no matching context\n"); + CertFreeCertificateContext(cert); + + /* Match an issuer that is in the store */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_BY, cert, NULL); + ok(context != NULL, "Expected a context\n"); + if (context) + CertFreeCRLContext(context); + + /* Try various find flags */ + context = pCertFindCRLInStore(store, 0, CRL_FIND_ISSUED_BY_SIGNATURE_FLAG, + CRL_FIND_ISSUED_BY, cert, NULL); + ok(!context || broken(context != NULL /* Win9x */), "unexpected context\n"); + /* The CRL doesn't have an AKI extension, so it matches any cert */ + context = pCertFindCRLInStore(store, 0, CRL_FIND_ISSUED_BY_AKI_FLAG, + CRL_FIND_ISSUED_BY, cert, NULL); + ok(context != NULL, "Expected a context\n"); + if (context) + CertFreeCRLContext(context); + + if (0) + { + /* Crash or return NULL/STATUS_ACCESS_VIOLATION */ + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, NULL, + NULL); + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, NULL); + } + /* Test whether the cert matches the CRL in the store */ + issuedForPara.pSubjectCert = cert; + issuedForPara.pIssuerCert = cert; + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, NULL); + ok(context != NULL || broken(!context /* Win9x, NT4 */), + "Expected a context\n"); + if (context) + { + ok(context->cbCrlEncoded == sizeof(signedCRL), + "unexpected CRL size %d\n", context->cbCrlEncoded); + ok(!memcmp(context->pbCrlEncoded, signedCRL, context->cbCrlEncoded), + "unexpected CRL data\n"); + CertFreeCRLContext(context); + } + + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + v1CRLWithIssuerAndEntry, sizeof(v1CRLWithIssuerAndEntry), + CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + v2CRLWithIssuingDistPoint, sizeof(v2CRLWithIssuingDistPoint), + CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + verisignCRL, sizeof(verisignCRL), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + issuedForPara.pSubjectCert = cert; + issuedForPara.pIssuerCert = cert; + context = NULL; + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(cert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + /* signedCRL, v1CRLWithIssuerAndEntry, and v2CRLWithIssuingDistPoint all + * match cert's issuer, but verisignCRL does not, so the expected count + * is 0. + */ + ok(count == 3 || broken(count == 0 /* NT4, Win9x */), + "expected 3 matching CRLs, got %d\n", count); + /* Only v1CRLWithIssuerAndEntry and v2CRLWithIssuingDistPoint contain + * entries, so the count of CRL entries that match cert is 2. + */ + ok(revoked_count == 2 || broken(revoked_count == 0 /* NT4, Win9x */), + "expected 2 matching CRL entries, got %d\n", revoked_count); + + CertFreeCertificateContext(cert); + + /* Try again with a cert that doesn't match any CRLs in the store */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + bigCertWithDifferentIssuer, sizeof(bigCertWithDifferentIssuer)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + issuedForPara.pSubjectCert = cert; + issuedForPara.pIssuerCert = cert; + context = NULL; + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(cert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0, "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + CertFreeCertificateContext(cert); + + /* Test again with a real certificate and CRL. The certificate wasn't + * revoked, but its issuer does have a CRL. + */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + verisignCommercialSoftPubCA, sizeof(verisignCommercialSoftPubCA)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + issuedForPara.pIssuerCert = cert; + issuedForPara.pSubjectCert = cert; + context = NULL; + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(cert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 1 || broken(count == 0 /* Win9x, NT4 */), + "expected 1 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + CertFreeCertificateContext(cert); + + CertCloseStore(store, 0); + + /* This test uses a synthesized chain (rootWithKeySignAndCRLSign -> + * eeCert) whose end certificate is in the CRL. + */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Add a CRL for the end certificate */ + CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + rootSignedCRL, sizeof(rootSignedCRL), CERT_STORE_ADD_ALWAYS, NULL); + /* Add another CRL unrelated to the tested chain */ + CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + verisignCRL, sizeof(verisignCRL), CERT_STORE_ADD_ALWAYS, NULL); + endCert = CertCreateCertificateContext(X509_ASN_ENCODING, + eeCert, sizeof(eeCert)); + rootCert = CertCreateCertificateContext(X509_ASN_ENCODING, + rootWithKeySignAndCRLSign, sizeof(rootWithKeySignAndCRLSign)); + issuedForPara.pSubjectCert = endCert; + issuedForPara.pIssuerCert = rootCert; + context = NULL; + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_FOR, + &issuedForPara, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 1 || broken(count == 0 /* Win9x, NT4 */), + "expected 1 matching CRLs, got %d\n", count); + ok(revoked_count == 1 || broken(revoked_count == 0 /* Win9x, NT4 */), + "expected 1 matching CRL entries, got %d\n", revoked_count); + + /* Test CRL_FIND_ISSUED_BY flags */ + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_BY, + endCert, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0, "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, 0, CRL_FIND_ISSUED_BY, + rootCert, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 1, "expected 1 matching CRLs, got %d\n", count); + ok(revoked_count == 1, "expected 1 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, CRL_FIND_ISSUED_BY_AKI_FLAG, + CRL_FIND_ISSUED_BY, endCert, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0, "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, CRL_FIND_ISSUED_BY_AKI_FLAG, + CRL_FIND_ISSUED_BY, rootCert, context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(rootCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0 || broken(count == 1 /* Win9x */), + "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, + CRL_FIND_ISSUED_BY_SIGNATURE_FLAG, CRL_FIND_ISSUED_BY, endCert, + context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 0, "expected 0 matching CRLs, got %d\n", count); + ok(revoked_count == 0, "expected 0 matching CRL entries, got %d\n", + revoked_count); + count = revoked_count = 0; + do { + context = pCertFindCRLInStore(store, 0, + CRL_FIND_ISSUED_BY_SIGNATURE_FLAG, CRL_FIND_ISSUED_BY, rootCert, + context); + if (context) + { + PCRL_ENTRY entry; + + count++; + if (CertFindCertificateInCRL(endCert, context, 0, NULL, &entry) && + entry) + revoked_count++; + } + } while (context); + ok(count == 1, "expected 1 matching CRLs, got %d\n", count); + ok(revoked_count == 1, "expected 1 matching CRL entries, got %d\n", + revoked_count); + CertFreeCertificateContext(rootCert); + CertFreeCertificateContext(endCert); + + CertCloseStore(store, 0); +} + +static void testGetCRLFromStore(void) +{ + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + PCCRL_CONTEXT context; + PCCERT_CONTEXT cert; + DWORD flags; + BOOL ret; + + if (!store) return; + + /* Crash + context = CertGetCRLFromStore(NULL, NULL, NULL, NULL); + context = CertGetCRLFromStore(store, NULL, NULL, NULL); + */ + + /* Bogus flags */ + flags = 0xffffffff; + context = CertGetCRLFromStore(store, NULL, NULL, &flags); + ok(!context && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + + /* Test an empty store */ + flags = 0; + context = CertGetCRLFromStore(store, NULL, NULL, &flags); + ok(context == NULL && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + + /* NULL matches any CRL */ + flags = 0; + context = CertGetCRLFromStore(store, NULL, NULL, &flags); + ok(context != NULL, "Expected a context\n"); + CertFreeCRLContext(context); + + /* This cert's issuer isn't in */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert2, + sizeof(bigCert2)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + context = CertGetCRLFromStore(store, cert, NULL, &flags); + ok(context == NULL && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + CertFreeCertificateContext(cert); + + /* But this one is */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + context = CertGetCRLFromStore(store, cert, NULL, &flags); + ok(context != NULL, "Expected a context\n"); + CertFreeCRLContext(context); + CertFreeCertificateContext(cert); + + CertCloseStore(store, 0); +} + +static void checkCRLHash(const BYTE *data, DWORD dataLen, ALG_ID algID, + PCCRL_CONTEXT context, DWORD propID) +{ + BYTE hash[20] = { 0 }, hashProperty[20]; + BOOL ret; + DWORD size; + + memset(hash, 0, sizeof(hash)); + memset(hashProperty, 0, sizeof(hashProperty)); + size = sizeof(hash); + ret = CryptHashCertificate(0, algID, 0, data, dataLen, hash, &size); + ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError()); + ret = CertGetCRLContextProperty(context, propID, hashProperty, &size); + ok(ret, "CertGetCRLContextProperty failed: %08x\n", GetLastError()); + ok(!memcmp(hash, hashProperty, size), "Unexpected hash for property %d\n", + propID); +} + +static void testCRLProperties(void) +{ + PCCRL_CONTEXT context = CertCreateCRLContext(X509_ASN_ENCODING, + CRL, sizeof(CRL)); + + ok(context != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); + if (context) + { + DWORD propID, numProps, access, size; + BOOL ret; + BYTE hash[20] = { 0 }, hashProperty[20]; + CRYPT_DATA_BLOB blob; + + /* This crashes + propID = CertEnumCRLContextProperties(NULL, 0); + */ + + propID = 0; + numProps = 0; + do { + propID = CertEnumCRLContextProperties(context, propID); + if (propID) + numProps++; + } while (propID != 0); + ok(numProps == 0, "Expected 0 properties, got %d\n", numProps); + + /* Tests with a NULL cert context. Prop ID 0 fails.. */ + ret = CertSetCRLContextProperty(NULL, 0, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* while this just crashes. + ret = CertSetCRLContextProperty(NULL, CERT_KEY_PROV_HANDLE_PROP_ID, 0, + NULL); + */ + + ret = CertSetCRLContextProperty(context, 0, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Can't set the cert property directly, this crashes. + ret = CertSetCRLContextProperty(context, CERT_CRL_PROP_ID, 0, CRL); + */ + + /* These all crash. + ret = CertGetCRLContextProperty(context, CERT_ACCESS_STATE_PROP_ID, 0, + NULL); + ret = CertGetCRLContextProperty(context, CERT_HASH_PROP_ID, NULL, NULL); + ret = CertGetCRLContextProperty(context, CERT_HASH_PROP_ID, + hashProperty, NULL); + */ + /* A missing prop */ + size = 0; + ret = CertGetCRLContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID, + NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* And, an implicit property */ + ret = CertGetCRLContextProperty(context, CERT_ACCESS_STATE_PROP_ID, + NULL, &size); + ok(ret, "CertGetCRLContextProperty failed: %08x\n", GetLastError()); + ret = CertGetCRLContextProperty(context, CERT_ACCESS_STATE_PROP_ID, + &access, &size); + ok(ret, "CertGetCRLContextProperty failed: %08x\n", GetLastError()); + ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG), + "Didn't expect a persisted crl\n"); + /* Trying to set this "read only" property crashes. + access |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG; + ret = CertSetCRLContextProperty(context, CERT_ACCESS_STATE_PROP_ID, 0, + &access); + */ + + /* Can I set the hash to an invalid hash? */ + blob.pbData = hash; + blob.cbData = sizeof(hash); + ret = CertSetCRLContextProperty(context, CERT_HASH_PROP_ID, 0, &blob); + ok(ret, "CertSetCRLContextProperty failed: %08x\n", + GetLastError()); + size = sizeof(hashProperty); + ret = CertGetCRLContextProperty(context, CERT_HASH_PROP_ID, + hashProperty, &size); + ok(!memcmp(hashProperty, hash, sizeof(hash)), "Unexpected hash\n"); + /* Delete the (bogus) hash, and get the real one */ + ret = CertSetCRLContextProperty(context, CERT_HASH_PROP_ID, 0, NULL); + ok(ret, "CertSetCRLContextProperty failed: %08x\n", GetLastError()); + checkCRLHash(CRL, sizeof(CRL), CALG_SHA1, context, CERT_HASH_PROP_ID); + + /* Now that the hash property is set, we should get one property when + * enumerating. + */ + propID = 0; + numProps = 0; + do { + propID = CertEnumCRLContextProperties(context, propID); + if (propID) + numProps++; + } while (propID != 0); + ok(numProps == 1, "Expected 1 properties, got %d\n", numProps); + + /* Check a few other implicit properties */ + checkCRLHash(CRL, sizeof(CRL), CALG_MD5, context, + CERT_MD5_HASH_PROP_ID); + + CertFreeCRLContext(context); + } +} + +static const BYTE bigCertWithCRLDistPoints[] = { +0x30,0x81,0xa5,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, +0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x26,0x30,0x24,0x30,0x22,0x06, +0x03,0x55,0x1d,0x1f,0x04,0x1b,0x30,0x19,0x30,0x17,0xa0,0x15,0xa0,0x13,0x86, +0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e, +0x6f,0x72,0x67 }; + +static void testIsValidCRLForCert(void) +{ + BOOL ret; + PCCERT_CONTEXT cert1, cert2, cert3; + PCCRL_CONTEXT crl; + HCERTSTORE store; + + if(!pCertIsValidCRLForCertificate) return; + + crl = CertCreateCRLContext(X509_ASN_ENCODING, v1CRLWithIssuerAndEntry, + sizeof(v1CRLWithIssuerAndEntry)); + ok(crl != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); + cert1 = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + ok(cert1 != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + + /* Crash + ret = CertIsValidCRLForCertificate(NULL, NULL, 0, NULL); + ret = CertIsValidCRLForCertificate(cert1, NULL, 0, NULL); + */ + + /* Curiously, any CRL is valid for the NULL certificate */ + ret = pCertIsValidCRLForCertificate(NULL, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + + /* Same issuer for both cert and CRL, this CRL is valid for that cert */ + ret = pCertIsValidCRLForCertificate(cert1, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + + cert2 = CertCreateCertificateContext(X509_ASN_ENCODING, + bigCertWithDifferentIssuer, sizeof(bigCertWithDifferentIssuer)); + ok(cert2 != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + + /* Yet more curious: different issuers for these, yet the CRL is valid for + * that cert. According to MSDN, the relevant bit to check is whether the + * CRL has a CRL_ISSUING_DIST_POINT extension. + */ + ret = pCertIsValidCRLForCertificate(cert2, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + + CertFreeCRLContext(crl); + + /* With a CRL_ISSUING_DIST_POINT in the CRL, it returns FALSE, since the + * cert doesn't have the same extension in it. + */ + crl = CertCreateCRLContext(X509_ASN_ENCODING, v2CRLWithIssuingDistPoint, + sizeof(v2CRLWithIssuingDistPoint)); + ok(crl != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); + + ret = pCertIsValidCRLForCertificate(cert1, crl, 0, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + ret = pCertIsValidCRLForCertificate(cert2, crl, 0, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + + /* With a CRL_ISSUING_DIST_POINT in the CRL, it matches the cert containing + * a CRL_DIST_POINTS_INFO extension. + */ + cert3 = CertCreateCertificateContext(X509_ASN_ENCODING, + bigCertWithCRLDistPoints, sizeof(bigCertWithCRLDistPoints)); + ok(cert3 != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + ret = pCertIsValidCRLForCertificate(cert3, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + + CertFreeCRLContext(crl); + + /* And again, with a real CRL, the CRL is valid for all three certs. */ + crl = CertCreateCRLContext(X509_ASN_ENCODING, verisignCRL, + sizeof(verisignCRL)); + ok(crl != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); + + ret = pCertIsValidCRLForCertificate(cert1, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + ret = pCertIsValidCRLForCertificate(cert2, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + ret = pCertIsValidCRLForCertificate(cert3, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + + CertFreeCRLContext(crl); + + /* One last test: a CRL in a different store than the cert is also valid + * for the cert. + */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, verisignCRL, + sizeof(verisignCRL), CERT_STORE_ADD_ALWAYS, &crl); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + + ret = pCertIsValidCRLForCertificate(cert1, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + ret = pCertIsValidCRLForCertificate(cert2, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + ret = pCertIsValidCRLForCertificate(cert3, crl, 0, NULL); + ok(ret, "CertIsValidCRLForCertificate failed: %08x\n", GetLastError()); + + CertFreeCRLContext(crl); + + CertCloseStore(store, 0); + + CertFreeCertificateContext(cert3); + CertFreeCertificateContext(cert2); + CertFreeCertificateContext(cert1); +} + +static const BYTE crlWithDifferentIssuer[] = { + 0x30,0x47,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, + 0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x41,0x6c,0x65,0x78,0x20,0x4c,0x61,0x6e, + 0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30, + 0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01,0x18,0x0f,0x31,0x36, + 0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a }; + +static void testFindCertInCRL(void) +{ + BOOL ret; + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + PCRL_ENTRY entry; + + if (!pCertFindCertificateInCRL) + { + win_skip("CertFindCertificateInCRL() is not available\n"); + return; + } + + cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + ok(cert != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + + /* Crash + ret = pCertFindCertificateInCRL(NULL, NULL, 0, NULL, NULL); + ret = pCertFindCertificateInCRL(NULL, crl, 0, NULL, NULL); + ret = pCertFindCertificateInCRL(cert, NULL, 0, NULL, NULL); + ret = pCertFindCertificateInCRL(cert, crl, 0, NULL, NULL); + ret = pCertFindCertificateInCRL(NULL, NULL, 0, NULL, &entry); + ret = pCertFindCertificateInCRL(NULL, crl, 0, NULL, &entry); + ret = pCertFindCertificateInCRL(cert, NULL, 0, NULL, &entry); + */ + + crl = CertCreateCRLContext(X509_ASN_ENCODING, verisignCRL, + sizeof(verisignCRL)); + ret = pCertFindCertificateInCRL(cert, crl, 0, NULL, &entry); + ok(ret, "CertFindCertificateInCRL failed: %08x\n", GetLastError()); + ok(entry == NULL, "Expected not to find an entry in CRL\n"); + CertFreeCRLContext(crl); + + crl = CertCreateCRLContext(X509_ASN_ENCODING, v1CRLWithIssuerAndEntry, + sizeof(v1CRLWithIssuerAndEntry)); + ret = pCertFindCertificateInCRL(cert, crl, 0, NULL, &entry); + ok(ret, "CertFindCertificateInCRL failed: %08x\n", GetLastError()); + ok(entry != NULL, "Expected to find an entry in CRL\n"); + CertFreeCRLContext(crl); + + /* Entry found even though CRL issuer doesn't match cert issuer */ + crl = CertCreateCRLContext(X509_ASN_ENCODING, crlWithDifferentIssuer, + sizeof(crlWithDifferentIssuer)); + ret = pCertFindCertificateInCRL(cert, crl, 0, NULL, &entry); + ok(ret, "CertFindCertificateInCRL failed: %08x\n", GetLastError()); + ok(entry != NULL, "Expected to find an entry in CRL\n"); + CertFreeCRLContext(crl); + + CertFreeCertificateContext(cert); +} + +static void testVerifyCRLRevocation(void) +{ + BOOL ret; + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + + ret = CertVerifyCRLRevocation(0, NULL, 0, NULL); + ok(ret, "CertVerifyCRLRevocation failed: %08x\n", GetLastError()); + ret = CertVerifyCRLRevocation(X509_ASN_ENCODING, NULL, 0, NULL); + ok(ret, "CertVerifyCRLRevocation failed: %08x\n", GetLastError()); + + cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + + /* Check against no CRL */ + ret = CertVerifyCRLRevocation(0, cert->pCertInfo, 0, NULL); + ok(ret, "CertVerifyCRLRevocation failed: %08x\n", GetLastError()); + ret = CertVerifyCRLRevocation(X509_ASN_ENCODING, cert->pCertInfo, 0, NULL); + ok(ret, "CertVerifyCRLRevocation failed: %08x\n", GetLastError()); + + /* Check against CRL with entry for the cert */ + crl = CertCreateCRLContext(X509_ASN_ENCODING, v1CRLWithIssuerAndEntry, + sizeof(v1CRLWithIssuerAndEntry)); + ret = CertVerifyCRLRevocation(0, cert->pCertInfo, 1, + (PCRL_INFO *)&crl->pCrlInfo); + ok(!ret, "CertVerifyCRLRevocation should have been revoked\n"); + ret = CertVerifyCRLRevocation(X509_ASN_ENCODING, cert->pCertInfo, 1, + (PCRL_INFO *)&crl->pCrlInfo); + ok(!ret, "CertVerifyCRLRevocation should have been revoked\n"); + CertFreeCRLContext(crl); + + /* Check against CRL with different issuer and entry for the cert */ + crl = CertCreateCRLContext(X509_ASN_ENCODING, crlWithDifferentIssuer, + sizeof(crlWithDifferentIssuer)); + ok(crl != NULL, "CertCreateCRLContext failed: %08x\n", GetLastError()); + ret = CertVerifyCRLRevocation(X509_ASN_ENCODING, cert->pCertInfo, 1, + (PCRL_INFO *)&crl->pCrlInfo); + ok(!ret, "CertVerifyCRLRevocation should have been revoked\n"); + CertFreeCRLContext(crl); + + /* Check against CRL without entry for the cert */ + crl = CertCreateCRLContext(X509_ASN_ENCODING, verisignCRL, + sizeof(verisignCRL)); + ret = CertVerifyCRLRevocation(0, cert->pCertInfo, 1, + (PCRL_INFO *)&crl->pCrlInfo); + ok(ret, "CertVerifyCRLRevocation failed: %08x\n", GetLastError()); + ret = CertVerifyCRLRevocation(X509_ASN_ENCODING, cert->pCertInfo, 1, + (PCRL_INFO *)&crl->pCrlInfo); + ok(ret, "CertVerifyCRLRevocation failed: %08x\n", GetLastError()); + CertFreeCRLContext(crl); + + CertFreeCertificateContext(cert); +} + +START_TEST(crl) +{ + init_function_pointers(); + + testCreateCRL(); + testDupCRL(); + testAddCRL(); + testFindCRL(); + testGetCRLFromStore(); + + testCRLProperties(); + + testIsValidCRLForCert(); + testFindCertInCRL(); + testVerifyCRLRevocation(); +} diff --git a/rostests/winetests/crypt32/crypt32.rbuild b/rostests/winetests/crypt32/crypt32.rbuild new file mode 100644 index 00000000000..91374248284 --- /dev/null +++ b/rostests/winetests/crypt32/crypt32.rbuild @@ -0,0 +1,28 @@ + + + + + . + + base64.c + cert.c + chain.c + crl.c + ctl.c + encode.c + main.c + message.c + msg.c + object.c + oid.c + protectdata.c + sip.c + store.c + str.c + testlist.c + wine + crypt32 + advapi32 + ntdll + + diff --git a/rostests/winetests/crypt32/ctl.c b/rostests/winetests/crypt32/ctl.c new file mode 100644 index 00000000000..8ee26526289 --- /dev/null +++ b/rostests/winetests/crypt32/ctl.c @@ -0,0 +1,465 @@ +/* + * crypt32 CTL functions tests + * + * Copyright 2008 Juan Lang + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static const BYTE emptyCTL[] = { +0x30,0x17,0x30,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00 }; +static const BYTE ctlWithOneEntry[] = { +0x30,0x2a,0x30,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00,0x30,0x11,0x30,0x0f,0x04, +0x01,0x01,0x31,0x0a,0x30,0x08,0x06,0x02,0x2a,0x03,0x31,0x02,0x30,0x00 }; +static const BYTE signedCTL[] = { +0x30,0x81,0xc7,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0xb9,0x30,0x81,0xb6,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x28,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x1b,0x04,0x19,0x30,0x17,0x30,0x00, +0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x30,0x02,0x06,0x00,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a, +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05, +0x00,0x04,0x40,0xca,0xd8,0x32,0xd1,0xbd,0x97,0x61,0x54,0xd6,0x80,0xcf,0x0d, +0xbd,0xa2,0x42,0xc7,0xca,0x37,0x91,0x7d,0x9d,0xac,0x8c,0xdf,0x05,0x8a,0x39, +0xc6,0x07,0xc1,0x37,0xe6,0xb9,0xd1,0x0d,0x26,0xec,0xa5,0xb0,0x8a,0x51,0x26, +0x2b,0x4f,0x73,0x44,0x86,0x83,0x5e,0x2b,0x6e,0xcc,0xf8,0x1b,0x85,0x53,0xe9, +0x7a,0x80,0x8f,0x6b,0x42,0x19,0x93 }; +static const BYTE signedCTLWithSubjectAlgorithm[] = { +0x30,0x81,0xd1,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0xc3,0x30,0x81,0xc0,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x32,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x25,0x04,0x23,0x30,0x21,0x30,0x00, +0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05, +0x00,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0xca,0x7a, +0xfa,0xbf,0x44,0x36,0xfd,0xb2,0x84,0x70,0x0f,0xf5,0x66,0xcb,0x68,0xdb,0x45, +0x74,0xa1,0xed,0xe3,0x30,0x4a,0x11,0xd2,0x7b,0xf5,0xa9,0x68,0x8d,0x36,0xe8, +0x79,0xff,0xa2,0xf2,0x4c,0x8a,0xa9,0x65,0x03,0xf8,0x77,0xa5,0x01,0xd3,0x46, +0x8a,0xcc,0x93,0x36,0x30,0xe1,0xa4,0x47,0x70,0x3d,0xb3,0x97,0xfc,0x6d,0x24, +0xe9,0xf9 }; +static const BYTE signedCTLWithCTLInnerContent[] = { +0x30,0x82,0x01,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x82,0x01,0x00,0x30,0x81,0xfd,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06, +0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x30,0x06,0x09, +0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0xa0,0x23,0x30,0x21,0x30,0x00, +0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05, +0x00,0x31,0x81,0xb5,0x30,0x81,0xb2,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31, +0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0xa0,0x3b,0x30,0x18,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31,0x0b,0x06,0x09,0x2b,0x06,0x01,0x04, +0x01,0x82,0x37,0x0a,0x01,0x30,0x1f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x09,0x04,0x31,0x12,0x04,0x10,0x54,0x71,0xbc,0xe1,0x56,0x31,0xa2,0xf9, +0x65,0x70,0x34,0xf8,0xe2,0xe9,0xb4,0xf4,0x30,0x04,0x06,0x00,0x05,0x00,0x04, +0x40,0x2f,0x1b,0x9f,0x5a,0x4a,0x15,0x73,0xfa,0xb1,0x93,0x3d,0x09,0x52,0xdf, +0x6b,0x98,0x4b,0x13,0x5e,0xe7,0xbf,0x65,0xf4,0x9c,0xc2,0xb1,0x77,0x09,0xb1, +0x66,0x4d,0x72,0x0d,0xb1,0x1a,0x50,0x20,0xe0,0x57,0xa2,0x39,0xc7,0xcd,0x7f, +0x8e,0xe7,0x5f,0x76,0x2b,0xd1,0x6a,0x82,0xb3,0x30,0x25,0x61,0xf6,0x25,0x23, +0x57,0x6c,0x0b,0x47,0xb8 }; +static const BYTE signedCTLWithCTLInnerContentAndBadSig[] = { +0x30,0x82,0x01,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x82,0x01,0x00,0x30,0x81,0xfd,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06, +0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x30,0x06,0x09, +0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0xa0,0x23,0x30,0x21,0x30,0x00, +0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05, +0x00,0x31,0x81,0xb5,0x30,0x81,0xb2,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31, +0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0xa0,0x3b,0x30,0x18,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31,0x0b,0x06,0x09,0x2b,0x06,0x01,0x04, +0x01,0x82,0x37,0x0a,0x01,0x30,0x1f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x09,0x04,0x31,0x12,0x04,0x10,0x54,0x71,0xbc,0xe1,0x56,0x31,0xa2,0xf9, +0x65,0x70,0x34,0xf8,0xe2,0xe9,0xb4,0xf4,0x30,0x04,0x06,0x00,0x05,0x00,0x04, +0x40,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff }; + +static void testCreateCTL(void) +{ + PCCTL_CONTEXT ctl; + + SetLastError(0xdeadbeef); + ctl = CertCreateCTLContext(0, NULL, 0); + ok(!ctl && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ctl = CertCreateCTLContext(X509_ASN_ENCODING, NULL, 0); + ok(!ctl && + (GetLastError() == ERROR_INVALID_DATA || + GetLastError() == OSS_MORE_INPUT), /* win9x */ + "expected ERROR_INVALID_DATA, got %d (0x%08x)\n", GetLastError(), + GetLastError()); + /* An empty CTL can't be created.. */ + SetLastError(0xdeadbeef); + ctl = CertCreateCTLContext(X509_ASN_ENCODING, emptyCTL, sizeof(emptyCTL)); + ok(!ctl && + (GetLastError() == ERROR_INVALID_DATA || + GetLastError() == OSS_DATA_ERROR), /* win9x */ + "expected ERROR_INVALID_DATA, got %d (0x%08x)\n", GetLastError(), + GetLastError()); + /* Nor can any of these "signed" CTLs whose inner content OID isn't + * szOID_CTL. + */ + SetLastError(0xdeadbeef); + ctl = CertCreateCTLContext(X509_ASN_ENCODING, signedCTL, sizeof(signedCTL)); + ok(!ctl && + (GetLastError() == ERROR_INVALID_DATA || + GetLastError() == CRYPT_E_UNEXPECTED_MSG_TYPE /* win9x */ || + GetLastError() == ERROR_SUCCESS /* some win98 */), + "expected ERROR_INVALID_DATA, CRYPT_E_UNEXPECTED_MSG_TYPE, or ERROR_SUCCESS, got %d (0x%08x)\n", GetLastError(), + GetLastError()); + SetLastError(0xdeadbeef); + ctl = CertCreateCTLContext(X509_ASN_ENCODING, ctlWithOneEntry, + sizeof(ctlWithOneEntry)); + ok(!ctl && + (GetLastError() == ERROR_INVALID_DATA || + GetLastError() == CRYPT_E_UNEXPECTED_MSG_TYPE /* win9x */ || + GetLastError() == OSS_DATA_ERROR /* some win98 */ || + GetLastError() == ERROR_SUCCESS /* some win98 */), + "expected ERROR_INVALID_DATA, CRYPT_E_UNEXPECTED_MSG_TYPE, OSS_DATA_ERROR, or ERROR_SUCCESS, got %d (0x%08x)\n", GetLastError(), + GetLastError()); + SetLastError(0xdeadbeef); + ctl = CertCreateCTLContext(X509_ASN_ENCODING, + signedCTLWithSubjectAlgorithm, sizeof(signedCTLWithSubjectAlgorithm)); + ok(!ctl && + (GetLastError() == ERROR_INVALID_DATA || + GetLastError() == CRYPT_E_UNEXPECTED_MSG_TYPE /* win9x */ || + GetLastError() == ERROR_SUCCESS /* some win98 */), + "expected ERROR_INVALID_DATA, got %d (0x%08x)\n", GetLastError(), + GetLastError()); + /* This signed CTL with the appropriate inner content type can be decoded. + */ + ctl = CertCreateCTLContext(X509_ASN_ENCODING, + signedCTLWithCTLInnerContent, sizeof(signedCTLWithCTLInnerContent)); + ok(ctl != NULL, "CertCreateCTLContext failed: %08x\n", GetLastError()); + if (ctl) + { + /* Even though the CTL was decoded with X509_ASN_ENCODING, the + * message encoding type is included in the CTL's encoding type. + */ + ok(ctl->dwMsgAndCertEncodingType == + (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING), + "expected X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, got %08x\n", + ctl->dwMsgAndCertEncodingType); + CertFreeCTLContext(ctl); + } + /* This CTL with a bad signature can also be decoded, so the sig isn't + * checked when loading the CTL. + */ + ctl = CertCreateCTLContext(X509_ASN_ENCODING, + signedCTLWithCTLInnerContentAndBadSig, + sizeof(signedCTLWithCTLInnerContentAndBadSig)); + ok(ctl != NULL, "CertCreateCTLContext failed: %08x\n", GetLastError()); + if (ctl) + CertFreeCTLContext(ctl); +} + +static void testDupCTL(void) +{ + PCCTL_CONTEXT context, dupContext; + + context = CertDuplicateCTLContext(NULL); + ok(context == NULL, "expected NULL\n"); + context = CertCreateCTLContext(X509_ASN_ENCODING, + signedCTLWithCTLInnerContent, sizeof(signedCTLWithCTLInnerContent)); + dupContext = CertDuplicateCTLContext(context); + ok(dupContext != NULL, "expected a context\n"); + ok(dupContext == context, "expected identical context addresses\n"); + CertFreeCTLContext(dupContext); + CertFreeCTLContext(context); +} + +static void checkHash(const BYTE *data, DWORD dataLen, ALG_ID algID, + PCCTL_CONTEXT context, DWORD propID) +{ + BYTE hash[20] = { 0 }, hashProperty[20]; + BOOL ret; + DWORD size; + + memset(hash, 0, sizeof(hash)); + memset(hashProperty, 0, sizeof(hashProperty)); + size = sizeof(hash); + ret = CryptHashCertificate(0, algID, 0, data, dataLen, hash, &size); + ret = CertGetCTLContextProperty(context, propID, hashProperty, &size); + ok(ret, "CertGetCTLContextProperty failed: %08x\n", GetLastError()); + if (ret) + ok(!memcmp(hash, hashProperty, size), + "Unexpected hash for property %d\n", propID); +} + +static void testCTLProperties(void) +{ + PCCTL_CONTEXT ctl; + BOOL ret; + DWORD propID, numProps, access, size; + + ctl = CertCreateCTLContext(X509_ASN_ENCODING, + signedCTLWithCTLInnerContent, sizeof(signedCTLWithCTLInnerContent)); + if (!ctl) + { + skip("CertCreateCTLContext failed: %08x\n", GetLastError()); + return; + } + + /* No properties as yet */ + propID = 0; + numProps = 0; + do { + propID = CertEnumCTLContextProperties(ctl, propID); + if (propID) + numProps++; + } while (propID != 0); + ok(numProps == 0, "Expected 0 properties, got %d\n", numProps); + + /* An implicit property */ + ret = CertGetCTLContextProperty(ctl, CERT_ACCESS_STATE_PROP_ID, NULL, + &size); + ok(ret || broken(GetLastError() == CRYPT_E_NOT_FOUND /* some win98 */), + "CertGetCTLContextProperty failed: %08x\n", GetLastError()); + ret = CertGetCTLContextProperty(ctl, CERT_ACCESS_STATE_PROP_ID, &access, + &size); + ok(ret || broken(GetLastError() == CRYPT_E_NOT_FOUND /* some win98 */), + "CertGetCTLContextProperty failed: %08x\n", GetLastError()); + if (ret) + ok(!(access & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG), + "Didn't expect a persisted cert\n"); + + checkHash(signedCTLWithCTLInnerContent, + sizeof(signedCTLWithCTLInnerContent), CALG_SHA1, ctl, CERT_HASH_PROP_ID); + + /* Now that the hash property is set, we should get one property when + * enumerating. + */ + propID = 0; + numProps = 0; + do { + propID = CertEnumCTLContextProperties(ctl, propID); + if (propID) + numProps++; + } while (propID != 0); + ok(numProps == 1, "Expected 1 properties, got %d\n", numProps); + + checkHash(signedCTLWithCTLInnerContent, + sizeof(signedCTLWithCTLInnerContent), CALG_MD5, ctl, + CERT_MD5_HASH_PROP_ID); + + CertFreeCTLContext(ctl); +} + +static const BYTE signedCTLWithUsage[] = { +0x30,0x82,0x01,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x82,0x01,0x00,0x30,0x81,0xfd,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06, +0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x30,0x06,0x09, +0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0xa0,0x23,0x30,0x21,0x30,0x0a, +0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x18,0x0f,0x31,0x36,0x30, +0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06, +0x00,0x31,0x81,0xb5,0x30,0x81,0xb2,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31, +0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0xa0,0x3b,0x30,0x18,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31,0x0b,0x06,0x09,0x2b,0x06,0x01,0x04, +0x01,0x82,0x37,0x0a,0x01,0x30,0x1f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x09,0x04,0x31,0x12,0x04,0x10,0xc4,0x3e,0x7e,0xc8,0xf9,0x85,0xf3,0x27, +0x7d,0xc0,0x38,0xb2,0x7f,0xc7,0x76,0x85,0x30,0x04,0x06,0x00,0x05,0x00,0x04, +0x40,0x90,0x33,0x1b,0xb4,0x88,0x35,0xe6,0xf7,0x7f,0x93,0x05,0xc9,0x1a,0x0e, +0x8f,0x21,0xc0,0xaa,0xb3,0xab,0x3e,0x4a,0xa6,0x63,0x74,0xfd,0xef,0x11,0xbd, +0x67,0x3a,0x1b,0x07,0x4b,0x88,0x59,0x31,0xd5,0x08,0xf9,0x09,0x2f,0x0b,0x85, +0x62,0x5a,0x67,0x3b,0x62,0x7e,0x81,0x31,0xea,0xa4,0x36,0x5f,0x9a,0x92,0xb6, +0x66,0xa5,0x00,0x60,0x96 }; +static const BYTE signedCTLWithListID1[] = { +0x30,0x82,0x01,0x07,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x81,0xf9,0x30,0x81,0xf6,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x29,0x06,0x09,0x2b, +0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0xa0,0x1c,0x30,0x1a,0x30,0x00,0x04, +0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00,0x31,0x81,0xb5,0x30,0x81,0xb2,0x02, +0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01, +0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0xa0, +0x3b,0x30,0x18,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31, +0x0b,0x06,0x09,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0x30,0x1f,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x04,0x31,0x12,0x04,0x10,0xbc, +0x13,0xde,0x17,0xc7,0x7c,0x67,0x5b,0xf9,0xa9,0x7c,0xb0,0xd9,0xf2,0x84,0xd5, +0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; +static const BYTE signedCTLWithListID2[] = { +0x30,0x82,0x01,0x07,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x81,0xf9,0x30,0x81,0xf6,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x29,0x06,0x09,0x2b, +0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0xa0,0x1c,0x30,0x1a,0x30,0x00,0x04, +0x01,0x02,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00,0x31,0x81,0xb5,0x30,0x81,0xb2,0x02, +0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01, +0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0xa0, +0x3b,0x30,0x18,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31, +0x0b,0x06,0x09,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0x30,0x1f,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x04,0x31,0x12,0x04,0x10,0x60, +0x6b,0x10,0xb6,0xb8,0x74,0xb8,0xf3,0x79,0xd5,0x42,0x15,0x4a,0x60,0x93,0x1f, +0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; + +static void testAddCTLToStore(void) +{ + HCERTSTORE store; + BOOL ret; + DWORD numCTLs, expectedCTLs; + PCCTL_CONTEXT ctl; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Add two CTLs */ + ret = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, + signedCTLWithCTLInnerContent, sizeof(signedCTLWithCTLInnerContent), + CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCTLToStore failed: %08x\n", GetLastError()); + ret = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, + signedCTLWithCTLInnerContentAndBadSig, + sizeof(signedCTLWithCTLInnerContentAndBadSig), CERT_STORE_ADD_ALWAYS, + NULL); + ok(ret, "CertAddEncodedCTLToStore failed: %08x\n", GetLastError()); + /* Check that two exist */ + numCTLs = 0; + ctl = NULL; + do { + ctl = CertEnumCTLsInStore(store, ctl); + if (ctl) + numCTLs++; + } while (ctl); + ok(numCTLs == 2, "expected 2 CTLs, got %d\n", numCTLs); + CertCloseStore(store, 0); + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Add the two CTLs again. They're identical except for the signature.. */ + ret = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, + signedCTLWithCTLInnerContent, sizeof(signedCTLWithCTLInnerContent), + CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCTLToStore failed: %08x\n", GetLastError()); + /* so adding the second CTL fails. */ + SetLastError(0xdeadbeef); + ret = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, + signedCTLWithCTLInnerContentAndBadSig, + sizeof(signedCTLWithCTLInnerContentAndBadSig), CERT_STORE_ADD_NEW, + NULL); + if (ret) + { + /* win9x */ + ok(GetLastError() == CRYPT_E_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR /* some win98 */, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + } + else + { + ok(!ret && (GetLastError() == CRYPT_E_EXISTS || + GetLastError() == OSS_DATA_ERROR), + "expected CRYPT_E_EXISTS or OSS_DATA_ERROR, got %d %08x\n", ret, + GetLastError()); + } + CertCloseStore(store, 0); + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Add two CTLs. These two have different usages, so they're considered + * different. + */ + ret = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, + signedCTLWithCTLInnerContent, sizeof(signedCTLWithCTLInnerContent), + CERT_STORE_ADD_NEW, NULL); + ok(ret, "CertAddEncodedCTLToStore failed: %08x\n", GetLastError()); + expectedCTLs = 1; + ret = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, + signedCTLWithUsage, sizeof(signedCTLWithUsage), CERT_STORE_ADD_NEW, + NULL); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* some win98 */), + "CertAddEncodedCTLToStore failed: %08x\n", GetLastError()); + if (ret) + expectedCTLs++; + /* Check that two exist */ + numCTLs = 0; + ctl = NULL; + do { + ctl = CertEnumCTLsInStore(store, ctl); + if (ctl) + numCTLs++; + } while (ctl); + ok(numCTLs == expectedCTLs, "expected %d CTLs, got %d\n", expectedCTLs, + numCTLs); + CertCloseStore(store, 0); + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Add two CTLs. Now they have the same (empty) usages and different list + * IDs, so they're different. + */ + ret = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, + signedCTLWithListID1, sizeof(signedCTLWithListID1), CERT_STORE_ADD_NEW, + NULL); + if (!ret) + { + skip("adding a CTL with an empty usage not supported\n"); + return; + } + ok(ret, "CertAddEncodedCTLToStore failed: %08x\n", GetLastError()); + ret = CertAddEncodedCTLToStore(store, X509_ASN_ENCODING, + signedCTLWithListID2, sizeof(signedCTLWithListID2), CERT_STORE_ADD_NEW, + NULL); + ok(ret, "CertAddEncodedCTLToStore failed: %08x\n", GetLastError()); + /* Check that two exist */ + numCTLs = 0; + ctl = NULL; + do { + ctl = CertEnumCTLsInStore(store, ctl); + if (ctl) + numCTLs++; + } while (ctl); + ok(numCTLs == 2, "expected 2 CTLs, got %d\n", numCTLs); + CertCloseStore(store, 0); +} + +START_TEST(ctl) +{ + testCreateCTL(); + testDupCTL(); + testCTLProperties(); + testAddCTLToStore(); +} diff --git a/rostests/winetests/crypt32/encode.c b/rostests/winetests/crypt32/encode.c new file mode 100644 index 00000000000..0f8ae7f6989 --- /dev/null +++ b/rostests/winetests/crypt32/encode.c @@ -0,0 +1,8069 @@ +/* + * Unit test suite for crypt32.dll's CryptEncodeObjectEx/CryptDecodeObjectEx + * + * Copyright 2005 Juan Lang + * + * 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 + */ +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + + +static BOOL (WINAPI *pCryptDecodeObjectEx)(DWORD,LPCSTR,const BYTE*,DWORD,DWORD,PCRYPT_DECODE_PARA,void*,DWORD*); +static BOOL (WINAPI *pCryptEncodeObjectEx)(DWORD,LPCSTR,const void*,DWORD,PCRYPT_ENCODE_PARA,void*,DWORD*); + +struct encodedInt +{ + int val; + const BYTE *encoded; +}; + +static const BYTE bin1[] = {0x02,0x01,0x01}; +static const BYTE bin2[] = {0x02,0x01,0x7f}; +static const BYTE bin3[] = {0x02,0x02,0x00,0x80}; +static const BYTE bin4[] = {0x02,0x02,0x01,0x00}; +static const BYTE bin5[] = {0x02,0x01,0x80}; +static const BYTE bin6[] = {0x02,0x02,0xff,0x7f}; +static const BYTE bin7[] = {0x02,0x04,0xba,0xdd,0xf0,0x0d}; + +static const struct encodedInt ints[] = { + { 1, bin1 }, + { 127, bin2 }, + { 128, bin3 }, + { 256, bin4 }, + { -128, bin5 }, + { -129, bin6 }, + { 0xbaddf00d, bin7 }, +}; + +struct encodedBigInt +{ + const BYTE *val; + const BYTE *encoded; + const BYTE *decoded; +}; + +static const BYTE bin8[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0}; +static const BYTE bin9[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0}; +static const BYTE bin10[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0}; + +static const BYTE bin11[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0}; +static const BYTE bin12[] = {0x02,0x09,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0}; +static const BYTE bin13[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0}; + +static const struct encodedBigInt bigInts[] = { + { bin8, bin9, bin10 }, + { bin11, bin12, bin13 }, +}; + +static const BYTE bin14[] = {0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0}; +static const BYTE bin15[] = {0x02,0x0a,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0}; +static const BYTE bin16[] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0xff,0xff,0xff,0}; +static const BYTE bin17[] = {0x02,0x0c,0x00,0xff,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0}; + +/* Decoded is the same as original, so don't bother storing a separate copy */ +static const struct encodedBigInt bigUInts[] = { + { bin14, bin15, NULL }, + { bin16, bin17, NULL }, +}; + +static void test_encodeInt(DWORD dwEncoding) +{ + DWORD bufSize = 0; + int i; + BOOL ret; + CRYPT_INTEGER_BLOB blob; + BYTE *buf = NULL; + + /* CryptEncodeObjectEx with NULL bufSize crashes.. + ret = pCryptEncodeObjectEx(3, X509_INTEGER, &ints[0].val, 0, NULL, NULL, + NULL); + */ + /* check bogus encoding */ + ret = pCryptEncodeObjectEx(0, X509_INTEGER, &ints[0].val, 0, NULL, NULL, + &bufSize); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + if (0) + { + /* check with NULL integer buffer. Windows XP incorrectly returns an + * NTSTATUS (crashes on win9x). + */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, NULL, NULL, + &bufSize); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++) + { + /* encode as normal integer */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, 0, + NULL, NULL, &bufSize); + ok(ret, "Expected success, got %d\n", GetLastError()); + ret = pCryptEncodeObjectEx(dwEncoding, X509_INTEGER, &ints[i].val, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError()); + if (buf) + { + ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n", + buf[0]); + ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n", + buf[1], ints[i].encoded[1]); + ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1), + "Encoded value of 0x%08x didn't match expected\n", ints[i].val); + LocalFree(buf); + } + /* encode as multibyte integer */ + blob.cbData = sizeof(ints[i].val); + blob.pbData = (BYTE *)&ints[i].val; + ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob, + 0, NULL, NULL, &bufSize); + ok(ret, "Expected success, got %d\n", GetLastError()); + ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError()); + if (buf) + { + ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n", + buf[0]); + ok(buf[1] == ints[i].encoded[1], "Got length %d, expected %d\n", + buf[1], ints[i].encoded[1]); + ok(!memcmp(buf + 1, ints[i].encoded + 1, ints[i].encoded[1] + 1), + "Encoded value of 0x%08x didn't match expected\n", ints[i].val); + LocalFree(buf); + } + } + /* encode a couple bigger ints, just to show it's little-endian and leading + * sign bytes are dropped + */ + for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++) + { + blob.cbData = strlen((const char*)bigInts[i].val); + blob.pbData = (BYTE *)bigInts[i].val; + ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob, + 0, NULL, NULL, &bufSize); + ok(ret, "Expected success, got %d\n", GetLastError()); + ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, &blob, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError()); + if (buf) + { + ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n", + buf[0]); + ok(buf[1] == bigInts[i].encoded[1], "Got length %d, expected %d\n", + buf[1], bigInts[i].encoded[1]); + ok(!memcmp(buf + 1, bigInts[i].encoded + 1, + bigInts[i].encoded[1] + 1), + "Encoded value didn't match expected\n"); + LocalFree(buf); + } + } + /* and, encode some uints */ + for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++) + { + blob.cbData = strlen((const char*)bigUInts[i].val); + blob.pbData = (BYTE*)bigUInts[i].val; + ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob, + 0, NULL, NULL, &bufSize); + ok(ret, "Expected success, got %d\n", GetLastError()); + ret = pCryptEncodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, &blob, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError()); + if (buf) + { + ok(buf[0] == 2, "Got unexpected type %d for integer (expected 2)\n", + buf[0]); + ok(buf[1] == bigUInts[i].encoded[1], "Got length %d, expected %d\n", + buf[1], bigUInts[i].encoded[1]); + ok(!memcmp(buf + 1, bigUInts[i].encoded + 1, + bigUInts[i].encoded[1] + 1), + "Encoded value didn't match expected\n"); + LocalFree(buf); + } + } +} + +static void test_decodeInt(DWORD dwEncoding) +{ + static const BYTE bigInt[] = { 2, 5, 0xff, 0xfe, 0xff, 0xfe, 0xff }; + static const BYTE testStr[] = { 0x16, 4, 't', 'e', 's', 't' }; + static const BYTE longForm[] = { 2, 0x81, 0x01, 0x01 }; + static const BYTE bigBogus[] = { 0x02, 0x84, 0x01, 0xff, 0xff, 0xf9 }; + static const BYTE extraBytes[] = { 2, 1, 1, 0, 0, 0, 0 }; + BYTE *buf = NULL; + DWORD bufSize = 0; + int i; + BOOL ret; + + /* CryptDecodeObjectEx with NULL bufSize crashes.. + ret = pCryptDecodeObjectEx(3, X509_INTEGER, &ints[0].encoded, + ints[0].encoded[1] + 2, 0, NULL, NULL, NULL); + */ + /* check bogus encoding */ + ret = pCryptDecodeObjectEx(3, X509_INTEGER, (BYTE *)&ints[0].encoded, + ints[0].encoded[1] + 2, 0, NULL, NULL, &bufSize); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + /* check with NULL integer buffer */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, NULL, 0, 0, NULL, NULL, + &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG /* Win9x */), + "Expected CRYPT_E_ASN1_EOD or OSS_BAD_ARG, got %08x\n", GetLastError()); + /* check with a valid, but too large, integer */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, bigInt, bigInt[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok((!ret && GetLastError() == CRYPT_E_ASN1_LARGE) || + broken(ret) /* Win9x */, + "Expected CRYPT_E_ASN1_LARGE, got %d\n", GetLastError()); + /* check with a DER-encoded string */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, testStr, testStr[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* Win9x */ ), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH, got %08x\n", + GetLastError()); + for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++) + { + /* When the output buffer is NULL, this always succeeds */ + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, + ints[i].encoded, ints[i].encoded[1] + 2, 0, NULL, NULL, + &bufSize); + ok(ret && GetLastError() == NOERROR, + "Expected success and NOERROR, got %d\n", GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, + ints[i].encoded, ints[i].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %d\n", GetLastError()); + ok(bufSize == sizeof(int), "Wrong size %d\n", bufSize); + ok(buf != NULL, "Expected allocated buffer\n"); + if (buf) + { + ok(!memcmp(buf, &ints[i].val, bufSize), "Expected %d, got %d\n", + ints[i].val, *(int *)buf); + LocalFree(buf); + } + } + for (i = 0; i < sizeof(bigInts) / sizeof(bigInts[0]); i++) + { + ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, + bigInts[i].encoded, bigInts[i].encoded[1] + 2, 0, NULL, NULL, + &bufSize); + ok(ret && GetLastError() == NOERROR, + "Expected success and NOERROR, got %d\n", GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, + bigInts[i].encoded, bigInts[i].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %d\n", GetLastError()); + ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %d\n", bufSize); + ok(buf != NULL, "Expected allocated buffer\n"); + if (buf) + { + CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf; + + ok(blob->cbData == strlen((const char*)bigInts[i].decoded), + "Expected len %d, got %d\n", lstrlenA((const char*)bigInts[i].decoded), + blob->cbData); + ok(!memcmp(blob->pbData, bigInts[i].decoded, blob->cbData), + "Unexpected value\n"); + LocalFree(buf); + } + } + for (i = 0; i < sizeof(bigUInts) / sizeof(bigUInts[0]); i++) + { + ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, + bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, 0, NULL, NULL, + &bufSize); + ok(ret && GetLastError() == NOERROR, + "Expected success and NOERROR, got %d\n", GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_UINT, + bigUInts[i].encoded, bigUInts[i].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %d\n", GetLastError()); + ok(bufSize >= sizeof(CRYPT_INTEGER_BLOB), "Wrong size %d\n", bufSize); + ok(buf != NULL, "Expected allocated buffer\n"); + if (buf) + { + CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf; + + ok(blob->cbData == strlen((const char*)bigUInts[i].val), + "Expected len %d, got %d\n", lstrlenA((const char*)bigUInts[i].val), + blob->cbData); + ok(!memcmp(blob->pbData, bigUInts[i].val, blob->cbData), + "Unexpected value\n"); + LocalFree(buf); + } + } + /* Decode the value 1 with long-form length */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, longForm, + sizeof(longForm), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf); + LocalFree(buf); + } + /* check with extra bytes at the end */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_INTEGER, extraBytes, + sizeof(extraBytes), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(*(int *)buf == 1, "Expected 1, got %d\n", *(int *)buf); + LocalFree(buf); + } + /* Try to decode some bogus large items */ + /* The buffer size is smaller than the encoded length, so this should fail + * with CRYPT_E_ASN1_EOD if it's being decoded. + * Under XP it fails with CRYPT_E_ASN1_LARGE, which means there's a limit + * on the size decoded, but in ME it fails with CRYPT_E_ASN1_EOD or crashes. + * So this test unfortunately isn't useful. + ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, tooBig, + 0x7fffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && GetLastError() == CRYPT_E_ASN1_LARGE, + "Expected CRYPT_E_ASN1_LARGE, got %08x\n", GetLastError()); + */ + /* This will try to decode the buffer and overflow it, check that it's + * caught. + */ + if (0) + { + /* a large buffer isn't guaranteed to crash, it depends on memory allocation order */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_MULTI_BYTE_INTEGER, bigBogus, + 0x01ffffff, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } +} + +static const BYTE bin18[] = {0x0a,0x01,0x01}; +static const BYTE bin19[] = {0x0a,0x05,0x00,0xff,0xff,0xff,0x80}; + +/* These are always encoded unsigned, and aren't constrained to be any + * particular value + */ +static const struct encodedInt enums[] = { + { 1, bin18 }, + { -128, bin19 }, +}; + +/* X509_CRL_REASON_CODE is also an enumerated type, but it's #defined to + * X509_ENUMERATED. + */ +static const LPCSTR enumeratedTypes[] = { X509_ENUMERATED, + szOID_CRL_REASON_CODE }; + +static void test_encodeEnumerated(DWORD dwEncoding) +{ + DWORD i, j; + + for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++) + { + for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++) + { + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + ret = pCryptEncodeObjectEx(dwEncoding, enumeratedTypes[i], + &enums[j].val, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, + &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError()); + if (buf) + { + ok(buf[0] == 0xa, + "Got unexpected type %d for enumerated (expected 0xa)\n", + buf[0]); + ok(buf[1] == enums[j].encoded[1], + "Got length %d, expected %d\n", buf[1], enums[j].encoded[1]); + ok(!memcmp(buf + 1, enums[j].encoded + 1, + enums[j].encoded[1] + 1), + "Encoded value of 0x%08x didn't match expected\n", + enums[j].val); + LocalFree(buf); + } + } + } +} + +static void test_decodeEnumerated(DWORD dwEncoding) +{ + DWORD i, j; + + for (i = 0; i < sizeof(enumeratedTypes) / sizeof(enumeratedTypes[0]); i++) + { + for (j = 0; j < sizeof(enums) / sizeof(enums[0]); j++) + { + BOOL ret; + DWORD bufSize = sizeof(int); + int val; + + ret = pCryptDecodeObjectEx(dwEncoding, enumeratedTypes[i], + enums[j].encoded, enums[j].encoded[1] + 2, 0, NULL, + &val, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + ok(bufSize == sizeof(int), + "Got unexpected size %d for enumerated\n", bufSize); + ok(val == enums[j].val, "Unexpected value %d, expected %d\n", + val, enums[j].val); + } + } +} + +struct encodedFiletime +{ + SYSTEMTIME sysTime; + const BYTE *encodedTime; +}; + +static void testTimeEncoding(DWORD dwEncoding, LPCSTR structType, + const struct encodedFiletime *time) +{ + FILETIME ft = { 0 }; + BYTE *buf = NULL; + DWORD bufSize = 0; + BOOL ret; + + ret = SystemTimeToFileTime(&time->sysTime, &ft); + ok(ret, "SystemTimeToFileTime failed: %d\n", GetLastError()); + ret = pCryptEncodeObjectEx(dwEncoding, structType, &ft, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + /* years other than 1950-2050 are not allowed for encodings other than + * X509_CHOICE_OF_TIME. + */ + if (structType == X509_CHOICE_OF_TIME || + (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050)) + { + ok(ret, "CryptEncodeObjectEx failed: %d (0x%08x)\n", GetLastError(), + GetLastError()); + ok(buf != NULL, "Expected an allocated buffer\n"); + if (buf) + { + ok(buf[0] == time->encodedTime[0], + "Expected type 0x%02x, got 0x%02x\n", time->encodedTime[0], + buf[0]); + ok(buf[1] == time->encodedTime[1], "Expected %d bytes, got %d\n", + time->encodedTime[1], bufSize); + ok(!memcmp(time->encodedTime + 2, buf + 2, time->encodedTime[1]), + "Got unexpected value for time encoding\n"); + LocalFree(buf); + } + } + else + ok((!ret && GetLastError() == CRYPT_E_BAD_ENCODE) || + broken(GetLastError() == ERROR_SUCCESS), + "Expected CRYPT_E_BAD_ENCODE, got 0x%08x\n", GetLastError()); +} + +static const char *printSystemTime(const SYSTEMTIME *st) +{ + static char buf[25]; + + sprintf(buf, "%02d-%02d-%04d %02d:%02d:%02d.%03d", st->wMonth, st->wDay, + st->wYear, st->wHour, st->wMinute, st->wSecond, st->wMilliseconds); + return buf; +} + +static const char *printFileTime(const FILETIME *ft) +{ + static char buf[25]; + SYSTEMTIME st; + + FileTimeToSystemTime(ft, &st); + sprintf(buf, "%02d-%02d-%04d %02d:%02d:%02d.%03d", st.wMonth, st.wDay, + st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); + return buf; +} + +static void compareTime(const SYSTEMTIME *expected, const FILETIME *got) +{ + SYSTEMTIME st; + + FileTimeToSystemTime(got, &st); + ok((expected->wYear == st.wYear && + expected->wMonth == st.wMonth && + expected->wDay == st.wDay && + expected->wHour == st.wHour && + expected->wMinute == st.wMinute && + expected->wSecond == st.wSecond && + abs(expected->wMilliseconds - st.wMilliseconds) <= 1) || + /* Some Windows systems only seem to be accurate in their time decoding to + * within about an hour. + */ + broken(expected->wYear == st.wYear && + expected->wMonth == st.wMonth && + expected->wDay == st.wDay && + abs(expected->wHour - st.wHour) <= 1), + "Got unexpected value for time decoding:\nexpected %s, got %s\n", + printSystemTime(expected), printFileTime(got)); +} + +static void testTimeDecoding(DWORD dwEncoding, LPCSTR structType, + const struct encodedFiletime *time) +{ + FILETIME ft = { 0 }; + DWORD size = sizeof(ft); + BOOL ret; + + ret = pCryptDecodeObjectEx(dwEncoding, structType, time->encodedTime, + time->encodedTime[1] + 2, 0, NULL, &ft, &size); + /* years other than 1950-2050 are not allowed for encodings other than + * X509_CHOICE_OF_TIME. + */ + if (structType == X509_CHOICE_OF_TIME || + (time->sysTime.wYear >= 1950 && time->sysTime.wYear <= 2050)) + { + ok(ret || broken(GetLastError() == OSS_DATA_ERROR), + "CryptDecodeObjectEx failed: %d (0x%08x)\n", GetLastError(), + GetLastError()); + if (ret) + compareTime(&time->sysTime, &ft); + } + else + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* Win9x */ ), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH, got %08x\n", + GetLastError()); +} + +static const BYTE bin20[] = { + 0x17,0x0d,'0','5','0','6','0','6','1','6','1','0','0','0','Z'}; +static const BYTE bin21[] = { + 0x18,0x0f,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','Z'}; +static const BYTE bin22[] = { + 0x18,0x0f,'2','1','4','5','0','6','0','6','1','6','1','0','0','0','Z'}; + +static const struct encodedFiletime times[] = { + { { 2005, 6, 1, 6, 16, 10, 0, 0 }, bin20 }, + { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin21 }, + { { 2145, 6, 1, 6, 16, 10, 0, 0 }, bin22 }, +}; + +static void test_encodeFiletime(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(times) / sizeof(times[0]); i++) + { + testTimeEncoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]); + testTimeEncoding(dwEncoding, PKCS_UTC_TIME, ×[i]); + testTimeEncoding(dwEncoding, szOID_RSA_signingTime, ×[i]); + } +} + +static const BYTE bin23[] = { + 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','0','0','0','Z'}; +static const BYTE bin24[] = { + 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','.','9','9','9','Z'}; +static const BYTE bin25[] = { + 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','+','0','1','0','0'}; +static const BYTE bin26[] = { + 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','0','0'}; +static const BYTE bin27[] = { + 0x18,0x13,'1','9','4','5','0','6','0','6','1','6','1','0','0','0','-','0','1','1','5'}; +static const BYTE bin28[] = { + 0x18,0x0a,'2','1','4','5','0','6','0','6','1','6'}; +static const BYTE bin29[] = { + 0x17,0x0a,'4','5','0','6','0','6','1','6','1','0'}; +static const BYTE bin30[] = { + 0x17,0x0b,'4','5','0','6','0','6','1','6','1','0','Z'}; +static const BYTE bin31[] = { + 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','+','0','1'}; +static const BYTE bin32[] = { + 0x17,0x0d,'4','5','0','6','0','6','1','6','1','0','-','0','1'}; +static const BYTE bin33[] = { + 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','+','0','1','0','0'}; +static const BYTE bin34[] = { + 0x17,0x0f,'4','5','0','6','0','6','1','6','1','0','-','0','1','0','0'}; +static const BYTE bin35[] = { + 0x17,0x08, '4','5','0','6','0','6','1','6'}; +static const BYTE bin36[] = { + 0x18,0x0f, 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','Z'}; +static const BYTE bin37[] = { + 0x18,0x04, '2','1','4','5'}; +static const BYTE bin38[] = { + 0x18,0x08, '2','1','4','5','0','6','0','6'}; + +static void test_decodeFiletime(DWORD dwEncoding) +{ + static const struct encodedFiletime otherTimes[] = { + { { 1945, 6, 1, 6, 16, 10, 0, 0 }, bin23 }, + { { 1945, 6, 1, 6, 16, 10, 0, 999 }, bin24 }, + { { 1945, 6, 1, 6, 17, 10, 0, 0 }, bin25 }, + { { 1945, 6, 1, 6, 15, 10, 0, 0 }, bin26 }, + { { 1945, 6, 1, 6, 14, 55, 0, 0 }, bin27 }, + { { 2145, 6, 1, 6, 16, 0, 0, 0 }, bin28 }, + { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin29 }, + { { 2045, 6, 1, 6, 16, 10, 0, 0 }, bin30 }, + { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin31 }, + { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin32 }, + { { 2045, 6, 1, 6, 17, 10, 0, 0 }, bin33 }, + { { 2045, 6, 1, 6, 15, 10, 0, 0 }, bin34 }, + }; + /* An oddball case that succeeds in Windows, but doesn't seem correct + { { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" }, + */ + static const unsigned char *bogusTimes[] = { + /* oddly, this succeeds on Windows, with year 2765 + "\x18" "\x0f" "21r50606161000Z", + */ + bin35, + bin36, + bin37, + bin38, + }; + DWORD i, size; + FILETIME ft1 = { 0 }, ft2 = { 0 }; + BOOL ret; + + /* Check bogus length with non-NULL buffer */ + ret = SystemTimeToFileTime(×[0].sysTime, &ft1); + ok(ret, "SystemTimeToFileTime failed: %d\n", GetLastError()); + size = 1; + ret = pCryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME, + times[0].encodedTime, times[0].encodedTime[1] + 2, 0, NULL, &ft2, &size); + ok(!ret && GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + /* Normal tests */ + for (i = 0; i < sizeof(times) / sizeof(times[0]); i++) + { + testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, ×[i]); + testTimeDecoding(dwEncoding, PKCS_UTC_TIME, ×[i]); + testTimeDecoding(dwEncoding, szOID_RSA_signingTime, ×[i]); + } + for (i = 0; i < sizeof(otherTimes) / sizeof(otherTimes[0]); i++) + { + testTimeDecoding(dwEncoding, X509_CHOICE_OF_TIME, &otherTimes[i]); + testTimeDecoding(dwEncoding, PKCS_UTC_TIME, &otherTimes[i]); + testTimeDecoding(dwEncoding, szOID_RSA_signingTime, &otherTimes[i]); + } + for (i = 0; i < sizeof(bogusTimes) / sizeof(bogusTimes[0]); i++) + { + size = sizeof(ft1); + ret = pCryptDecodeObjectEx(dwEncoding, X509_CHOICE_OF_TIME, + bogusTimes[i], bogusTimes[i][1] + 2, 0, NULL, &ft1, &size); + ok((!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR /* Win9x */)) || + broken(ret), /* Win9x and NT4 for bin38 */ + "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + } +} + +static const char commonName[] = "Juan Lang"; +static const char surName[] = "Lang"; + +static const BYTE emptySequence[] = { 0x30, 0 }; +static const BYTE emptyRDNs[] = { 0x30, 0x02, 0x31, 0 }; +static const BYTE twoRDNs[] = { + 0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04, + 0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03, + 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0}; +static const BYTE encodedTwoRDNs[] = { +0x30,0x2e,0x31,0x2c,0x30,0x2a,0x06,0x03,0x55,0x04,0x03,0x30,0x23,0x31,0x21, +0x30,0x0c,0x06,0x03,0x55,0x04,0x04,0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00, +}; + +static const BYTE us[] = { 0x55, 0x53 }; +static const BYTE minnesota[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f, + 0x74, 0x61 }; +static const BYTE minneapolis[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70, + 0x6f, 0x6c, 0x69, 0x73 }; +static const BYTE codeweavers[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61, + 0x76, 0x65, 0x72, 0x73 }; +static const BYTE wine[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76, + 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 }; +static const BYTE localhostAttr[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, + 0x73, 0x74 }; +static const BYTE aric[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64, + 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d }; + +#define RDNA(arr) oid_ ## arr, CERT_RDN_PRINTABLE_STRING, { sizeof(arr), (LPBYTE)arr } +#define RDNIA5(arr) oid_ ## arr, CERT_RDN_IA5_STRING, { sizeof(arr), (LPBYTE)arr } + +static CHAR oid_us[] = "2.5.4.6", + oid_minnesota[] = "2.5.4.8", + oid_minneapolis[] = "2.5.4.7", + oid_codeweavers[] = "2.5.4.10", + oid_wine[] = "2.5.4.11", + oid_localhostAttr[] = "2.5.4.3", + oid_aric[] = "1.2.840.113549.1.9.1"; +static CERT_RDN_ATTR rdnAttrs[] = { { RDNA(us) }, + { RDNA(minnesota) }, + { RDNA(minneapolis) }, + { RDNA(codeweavers) }, + { RDNA(wine) }, + { RDNA(localhostAttr) }, + { RDNIA5(aric) } }; +static CERT_RDN_ATTR decodedRdnAttrs[] = { { RDNA(us) }, + { RDNA(localhostAttr) }, + { RDNA(minnesota) }, + { RDNA(minneapolis) }, + { RDNA(codeweavers) }, + { RDNA(wine) }, + { RDNIA5(aric) } }; + +#undef RDNIA5 +#undef RDNA + +static const BYTE encodedRDNAttrs[] = { +0x30,0x81,0x96,0x31,0x81,0x93,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x6c,0x6f,0x63,0x61,0x6c,0x68, +0x6f,0x73,0x74,0x30,0x10,0x06,0x03,0x55,0x04,0x08,0x13,0x09,0x4d,0x69,0x6e,0x6e, +0x65,0x73,0x6f,0x74,0x61,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0b,0x4d,0x69, +0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x30,0x12,0x06,0x03,0x55,0x04,0x0a, +0x13,0x0b,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x30,0x17,0x06, +0x03,0x55,0x04,0x0b,0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c, +0x6f,0x70,0x6d,0x65,0x6e,0x74,0x30,0x21,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x09,0x01,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65, +0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d +}; + +static void test_encodeName(DWORD dwEncoding) +{ + CERT_RDN_ATTR attrs[2]; + CERT_RDN rdn; + CERT_NAME_INFO info; + static CHAR oid_common_name[] = szOID_COMMON_NAME, + oid_sur_name[] = szOID_SUR_NAME; + BYTE *buf = NULL; + DWORD size = 0; + BOOL ret; + + if (0) + { + /* Test with NULL pvStructInfo (crashes on win9x) */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, NULL, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* Test with empty CERT_NAME_INFO */ + info.cRDN = 0; + info.rgRDN = NULL; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(!memcmp(buf, emptySequence, sizeof(emptySequence)), + "Got unexpected encoding for empty name\n"); + LocalFree(buf); + } + if (0) + { + /* Test with bogus CERT_RDN (crashes on win9x) */ + info.cRDN = 1; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* Test with empty CERT_RDN */ + rdn.cRDNAttr = 0; + rdn.rgRDNAttr = NULL; + info.cRDN = 1; + info.rgRDN = &rdn; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(!memcmp(buf, emptyRDNs, sizeof(emptyRDNs)), + "Got unexpected encoding for empty RDN array\n"); + LocalFree(buf); + } + if (0) + { + /* Test with bogus attr array (crashes on win9x) */ + rdn.cRDNAttr = 1; + rdn.rgRDNAttr = NULL; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* oddly, a bogus OID is accepted by Windows XP; not testing. + attrs[0].pszObjId = "bogus"; + attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING; + attrs[0].Value.cbData = sizeof(commonName); + attrs[0].Value.pbData = commonName; + rdn.cRDNAttr = 1; + rdn.rgRDNAttr = attrs; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret, "Expected failure, got success\n"); + */ + /* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of + * the encoded attributes to be swapped. + */ + attrs[0].pszObjId = oid_common_name; + attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING; + attrs[0].Value.cbData = sizeof(commonName); + attrs[0].Value.pbData = (BYTE *)commonName; + attrs[1].pszObjId = oid_sur_name; + attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING; + attrs[1].Value.cbData = sizeof(surName); + attrs[1].Value.pbData = (BYTE *)surName; + rdn.cRDNAttr = 2; + rdn.rgRDNAttr = attrs; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(!memcmp(buf, twoRDNs, sizeof(twoRDNs)), + "Got unexpected encoding for two RDN array\n"); + LocalFree(buf); + } + /* A name can be "encoded" with previously encoded RDN attrs. */ + attrs[0].dwValueType = CERT_RDN_ENCODED_BLOB; + attrs[0].Value.pbData = (LPBYTE)twoRDNs; + attrs[0].Value.cbData = sizeof(twoRDNs); + rdn.cRDNAttr = 1; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(encodedTwoRDNs), "Unexpected size %d\n", size); + ok(!memcmp(buf, encodedTwoRDNs, size), + "Unexpected value for re-endoded two RDN array\n"); + LocalFree(buf); + } + /* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */ + rdn.cRDNAttr = 1; + attrs[0].dwValueType = CERT_RDN_ANY_TYPE; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Test a more complex name */ + rdn.cRDNAttr = sizeof(rdnAttrs) / sizeof(rdnAttrs[0]); + rdn.rgRDNAttr = rdnAttrs; + info.cRDN = 1; + info.rgRDN = &rdn; + buf = NULL; + size = 0; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, X509_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(encodedRDNAttrs), "Wrong size %d\n", size); + ok(!memcmp(buf, encodedRDNAttrs, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static WCHAR commonNameW[] = { 'J','u','a','n',' ','L','a','n','g',0 }; +static WCHAR surNameW[] = { 'L','a','n','g',0 }; + +static const BYTE twoRDNsNoNull[] = { + 0x30,0x21,0x31,0x1f,0x30,0x0b,0x06,0x03,0x55,0x04,0x04,0x13,0x04,0x4c,0x61, + 0x6e,0x67,0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e, + 0x20,0x4c,0x61,0x6e,0x67 }; +static const BYTE anyType[] = { + 0x30,0x2f,0x31,0x2d,0x30,0x2b,0x06,0x03,0x55,0x04,0x03,0x1e,0x24,0x23,0x30, + 0x21,0x31,0x0c,0x30,0x03,0x06,0x04,0x55,0x13,0x04,0x4c,0x05,0x6e,0x61,0x00, + 0x67,0x11,0x30,0x03,0x06,0x04,0x55,0x13,0x03,0x4a,0x0a,0x61,0x75,0x20,0x6e, + 0x61,0x4c,0x67,0x6e }; + +static void test_encodeUnicodeName(DWORD dwEncoding) +{ + CERT_RDN_ATTR attrs[2]; + CERT_RDN rdn; + CERT_NAME_INFO info; + static CHAR oid_common_name[] = szOID_COMMON_NAME, + oid_sur_name[] = szOID_SUR_NAME; + BYTE *buf = NULL; + DWORD size = 0; + BOOL ret; + + if (0) + { + /* Test with NULL pvStructInfo (crashes on win9x) */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, NULL, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* Test with empty CERT_NAME_INFO */ + info.cRDN = 0; + info.rgRDN = NULL; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(!memcmp(buf, emptySequence, sizeof(emptySequence)), + "Got unexpected encoding for empty name\n"); + LocalFree(buf); + } + /* Check with one CERT_RDN_ATTR, that has an invalid character for the + * encoding (the NULL). + */ + attrs[0].pszObjId = oid_common_name; + attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING; + attrs[0].Value.cbData = sizeof(commonNameW); + attrs[0].Value.pbData = (BYTE *)commonNameW; + rdn.cRDNAttr = 1; + rdn.rgRDNAttr = attrs; + info.cRDN = 1; + info.rgRDN = &rdn; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING, + "Expected CRYPT_E_INVALID_PRINTABLE_STRING, got %08x\n", GetLastError()); + ok(size == 9, "Unexpected error index %08x\n", size); + /* Check with two NULL-terminated CERT_RDN_ATTRs. Note DER encoding + * forces the order of the encoded attributes to be swapped. + */ + attrs[0].pszObjId = oid_common_name; + attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING; + attrs[0].Value.cbData = 0; + attrs[0].Value.pbData = (BYTE *)commonNameW; + attrs[1].pszObjId = oid_sur_name; + attrs[1].dwValueType = CERT_RDN_PRINTABLE_STRING; + attrs[1].Value.cbData = 0; + attrs[1].Value.pbData = (BYTE *)surNameW; + rdn.cRDNAttr = 2; + rdn.rgRDNAttr = attrs; + info.cRDN = 1; + info.rgRDN = &rdn; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(!memcmp(buf, twoRDNsNoNull, sizeof(twoRDNsNoNull)), + "Got unexpected encoding for two RDN array\n"); + LocalFree(buf); + } + /* A name can be "encoded" with previously encoded RDN attrs. */ + attrs[0].dwValueType = CERT_RDN_ENCODED_BLOB; + attrs[0].Value.pbData = (LPBYTE)twoRDNs; + attrs[0].Value.cbData = sizeof(twoRDNs); + rdn.cRDNAttr = 1; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(encodedTwoRDNs), "Unexpected size %d\n", size); + ok(!memcmp(buf, encodedTwoRDNs, size), + "Unexpected value for re-endoded two RDN array\n"); + LocalFree(buf); + } + /* Unicode names infer the type for CERT_RDN_ANY_TYPE */ + rdn.cRDNAttr = 1; + attrs[0].dwValueType = CERT_RDN_ANY_TYPE; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + todo_wine ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(anyType), "Unexpected size %d\n", size); + ok(!memcmp(buf, anyType, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void compareNameValues(const CERT_NAME_VALUE *expected, + const CERT_NAME_VALUE *got) +{ + if (expected->dwValueType == CERT_RDN_UTF8_STRING && + got->dwValueType == CERT_RDN_ENCODED_BLOB) + { + win_skip("Can't handle CERT_RDN_UTF8_STRING\n"); + return; + } + + ok(got->dwValueType == expected->dwValueType, + "Expected string type %d, got %d\n", expected->dwValueType, + got->dwValueType); + ok(got->Value.cbData == expected->Value.cbData, + "String type %d: unexpected data size, got %d, expected %d\n", + expected->dwValueType, got->Value.cbData, expected->Value.cbData); + if (got->Value.cbData && got->Value.pbData) + ok(!memcmp(got->Value.pbData, expected->Value.pbData, + min(got->Value.cbData, expected->Value.cbData)), + "String type %d: unexpected value\n", expected->dwValueType); +} + +static void compareRDNAttrs(const CERT_RDN_ATTR *expected, + const CERT_RDN_ATTR *got) +{ + if (expected->pszObjId && strlen(expected->pszObjId)) + { + ok(got->pszObjId != NULL, "Expected OID %s, got NULL\n", + expected->pszObjId); + if (got->pszObjId) + { + ok(!strcmp(got->pszObjId, expected->pszObjId), + "Got unexpected OID %s, expected %s\n", got->pszObjId, + expected->pszObjId); + } + } + compareNameValues((const CERT_NAME_VALUE *)&expected->dwValueType, + (const CERT_NAME_VALUE *)&got->dwValueType); +} + +static void compareRDNs(const CERT_RDN *expected, const CERT_RDN *got) +{ + ok(got->cRDNAttr == expected->cRDNAttr, + "Expected %d RDN attrs, got %d\n", expected->cRDNAttr, got->cRDNAttr); + if (got->cRDNAttr) + { + DWORD i; + + for (i = 0; i < got->cRDNAttr; i++) + compareRDNAttrs(&expected->rgRDNAttr[i], &got->rgRDNAttr[i]); + } +} + +static void compareNames(const CERT_NAME_INFO *expected, + const CERT_NAME_INFO *got) +{ + ok(got->cRDN == expected->cRDN, "Expected %d RDNs, got %d\n", + expected->cRDN, got->cRDN); + if (got->cRDN) + { + DWORD i; + + for (i = 0; i < got->cRDN; i++) + compareRDNs(&expected->rgRDN[i], &got->rgRDN[i]); + } +} + +static const BYTE emptyIndefiniteSequence[] = { 0x30,0x80,0x00,0x00 }; +static const BYTE twoRDNsExtraBytes[] = { + 0x30,0x23,0x31,0x21,0x30,0x0c,0x06,0x03,0x55,0x04,0x04, + 0x13,0x05,0x4c,0x61,0x6e,0x67,0x00,0x30,0x11,0x06,0x03,0x55,0x04,0x03, + 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0,0,0,0,0,0}; + +static void test_decodeName(DWORD dwEncoding) +{ + BYTE *buf = NULL; + DWORD bufSize = 0; + BOOL ret; + CERT_RDN rdn; + CERT_NAME_INFO info = { 1, &rdn }; + + /* test empty name */ + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, X509_NAME, emptySequence, + emptySequence[1] + 2, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + /* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My + * decoder works the same way, so only test the count. + */ + if (buf) + { + ok(bufSize == sizeof(CERT_NAME_INFO), "Wrong bufSize %d\n", bufSize); + ok(((CERT_NAME_INFO *)buf)->cRDN == 0, + "Expected 0 RDNs in empty info, got %d\n", + ((CERT_NAME_INFO *)buf)->cRDN); + LocalFree(buf); + } + /* test empty name with indefinite-length encoding */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_NAME, emptyIndefiniteSequence, + sizeof(emptyIndefiniteSequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(bufSize == sizeof(CERT_NAME_INFO), "Wrong bufSize %d\n", bufSize); + ok(((CERT_NAME_INFO *)buf)->cRDN == 0, + "Expected 0 RDNs in empty info, got %d\n", + ((CERT_NAME_INFO *)buf)->cRDN); + LocalFree(buf); + } + /* test empty RDN */ + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, X509_NAME, emptyRDNs, + emptyRDNs[1] + 2, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf; + + ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) && + info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0, + "Got unexpected value for empty RDN\n"); + LocalFree(buf); + } + /* test two RDN attrs */ + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNs, + twoRDNs[1] + 2, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + static CHAR oid_sur_name[] = szOID_SUR_NAME, + oid_common_name[] = szOID_COMMON_NAME; + + CERT_RDN_ATTR attrs[] = { + { oid_sur_name, CERT_RDN_PRINTABLE_STRING, { sizeof(surName), + (BYTE *)surName } }, + { oid_common_name, CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), + (BYTE *)commonName } }, + }; + + rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]); + rdn.rgRDNAttr = attrs; + compareNames(&info, (CERT_NAME_INFO *)buf); + LocalFree(buf); + } + /* test that two RDN attrs with extra bytes succeeds */ + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, X509_NAME, twoRDNsExtraBytes, + sizeof(twoRDNsExtraBytes), 0, NULL, NULL, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + /* And, a slightly more complicated name */ + buf = NULL; + bufSize = 0; + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, encodedRDNAttrs, + sizeof(encodedRDNAttrs), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + rdn.cRDNAttr = sizeof(decodedRdnAttrs) / sizeof(decodedRdnAttrs[0]); + rdn.rgRDNAttr = decodedRdnAttrs; + compareNames(&info, (CERT_NAME_INFO *)buf); + LocalFree(buf); + } +} + +static void test_decodeUnicodeName(DWORD dwEncoding) +{ + BYTE *buf = NULL; + DWORD bufSize = 0; + BOOL ret; + CERT_RDN rdn; + CERT_NAME_INFO info = { 1, &rdn }; + + /* test empty name */ + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, emptySequence, + emptySequence[1] + 2, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == sizeof(CERT_NAME_INFO), + "Got wrong bufSize %d\n", bufSize); + ok(((CERT_NAME_INFO *)buf)->cRDN == 0, + "Expected 0 RDNs in empty info, got %d\n", + ((CERT_NAME_INFO *)buf)->cRDN); + LocalFree(buf); + } + /* test empty RDN */ + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, emptyRDNs, + emptyRDNs[1] + 2, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_NAME_INFO *info = (CERT_NAME_INFO *)buf; + + ok(bufSize == sizeof(CERT_NAME_INFO) + sizeof(CERT_RDN) && + info->cRDN == 1 && info->rgRDN && info->rgRDN[0].cRDNAttr == 0, + "Got unexpected value for empty RDN\n"); + LocalFree(buf); + } + /* test two RDN attrs */ + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME, twoRDNsNoNull, + sizeof(twoRDNsNoNull), + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + static CHAR oid_sur_name[] = szOID_SUR_NAME, + oid_common_name[] = szOID_COMMON_NAME; + + CERT_RDN_ATTR attrs[] = { + { oid_sur_name, CERT_RDN_PRINTABLE_STRING, + { lstrlenW(surNameW) * sizeof(WCHAR), (BYTE *)surNameW } }, + { oid_common_name, CERT_RDN_PRINTABLE_STRING, + { lstrlenW(commonNameW) * sizeof(WCHAR), (BYTE *)commonNameW } }, + }; + + rdn.cRDNAttr = sizeof(attrs) / sizeof(attrs[0]); + rdn.rgRDNAttr = attrs; + compareNames(&info, (CERT_NAME_INFO *)buf); + LocalFree(buf); + } +} + +struct EncodedNameValue +{ + CERT_NAME_VALUE value; + const BYTE *encoded; + DWORD encodedSize; +}; + +static const char bogusIA5[] = "\x80"; +static const char bogusPrintable[] = "~"; +static const char bogusNumeric[] = "A"; +static const BYTE bin42[] = { 0x16,0x02,0x80,0x00 }; +static const BYTE bin43[] = { 0x13,0x02,0x7e,0x00 }; +static const BYTE bin44[] = { 0x12,0x02,0x41,0x00 }; +static BYTE octetCommonNameValue[] = { + 0x04,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE numericCommonNameValue[] = { + 0x12,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE printableCommonNameValue[] = { + 0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE t61CommonNameValue[] = { + 0x14,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE videotexCommonNameValue[] = { + 0x15,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE ia5CommonNameValue[] = { + 0x16,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE graphicCommonNameValue[] = { + 0x19,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE visibleCommonNameValue[] = { + 0x1a,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE generalCommonNameValue[] = { + 0x1b,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static BYTE bmpCommonNameValue[] = { + 0x1e,0x14,0x00,0x4a,0x00,0x75,0x00,0x61,0x00,0x6e,0x00,0x20,0x00,0x4c,0x00, + 0x61,0x00,0x6e,0x00,0x67,0x00,0x00 }; +static BYTE utf8CommonNameValue[] = { + 0x0c,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static char embedded_null[] = "foo\0com"; +static BYTE ia5EmbeddedNull[] = { + 0x16,0x07,0x66,0x6f,0x6f,0x00,0x63,0x6f,0x6d }; + +static struct EncodedNameValue nameValues[] = { + { { CERT_RDN_OCTET_STRING, { sizeof(commonName), (BYTE *)commonName } }, + octetCommonNameValue, sizeof(octetCommonNameValue) }, + { { CERT_RDN_NUMERIC_STRING, { sizeof(commonName), (BYTE *)commonName } }, + numericCommonNameValue, sizeof(numericCommonNameValue) }, + { { CERT_RDN_PRINTABLE_STRING, { sizeof(commonName), (BYTE *)commonName } }, + printableCommonNameValue, sizeof(printableCommonNameValue) }, + { { CERT_RDN_T61_STRING, { sizeof(commonName), (BYTE *)commonName } }, + t61CommonNameValue, sizeof(t61CommonNameValue) }, + { { CERT_RDN_VIDEOTEX_STRING, { sizeof(commonName), (BYTE *)commonName } }, + videotexCommonNameValue, sizeof(videotexCommonNameValue) }, + { { CERT_RDN_IA5_STRING, { sizeof(commonName), (BYTE *)commonName } }, + ia5CommonNameValue, sizeof(ia5CommonNameValue) }, + { { CERT_RDN_GRAPHIC_STRING, { sizeof(commonName), (BYTE *)commonName } }, + graphicCommonNameValue, sizeof(graphicCommonNameValue) }, + { { CERT_RDN_VISIBLE_STRING, { sizeof(commonName), (BYTE *)commonName } }, + visibleCommonNameValue, sizeof(visibleCommonNameValue) }, + { { CERT_RDN_GENERAL_STRING, { sizeof(commonName), (BYTE *)commonName } }, + generalCommonNameValue, sizeof(generalCommonNameValue) }, + { { CERT_RDN_BMP_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } }, + bmpCommonNameValue, sizeof(bmpCommonNameValue) }, + { { CERT_RDN_UTF8_STRING, { sizeof(commonNameW), (BYTE *)commonNameW } }, + utf8CommonNameValue, sizeof(utf8CommonNameValue) }, + /* The following tests succeed under Windows, but really should fail, + * they contain characters that are illegal for the encoding. I'm + * including them to justify my lazy encoding. + */ + { { CERT_RDN_IA5_STRING, { sizeof(bogusIA5), (BYTE *)bogusIA5 } }, bin42, + sizeof(bin42) }, + { { CERT_RDN_PRINTABLE_STRING, { sizeof(bogusPrintable), + (BYTE *)bogusPrintable } }, bin43, sizeof(bin43) }, + { { CERT_RDN_NUMERIC_STRING, { sizeof(bogusNumeric), (BYTE *)bogusNumeric } }, + bin44, sizeof(bin44) }, +}; +/* This is kept separate, because the decoding doesn't return to the original + * value. + */ +static struct EncodedNameValue embeddedNullNameValue = { + { CERT_RDN_IA5_STRING, { sizeof(embedded_null) - 1, (BYTE *)embedded_null } }, + ia5EmbeddedNull, sizeof(ia5EmbeddedNull) }; + +static void test_encodeNameValue(DWORD dwEncoding) +{ + BYTE *buf = NULL; + DWORD size = 0, i; + BOOL ret; + CERT_NAME_VALUE value = { 0, { 0, NULL } }; + + value.dwValueType = CERT_RDN_ENCODED_BLOB; + value.Value.pbData = printableCommonNameValue; + value.Value.cbData = sizeof(printableCommonNameValue); + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(printableCommonNameValue), "Unexpected size %d\n", + size); + ok(!memcmp(buf, printableCommonNameValue, size), + "Unexpected encoding\n"); + LocalFree(buf); + } + for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++) + { + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, + &nameValues[i].value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == OSS_PDU_MISMATCH) /* NT4/Win9x */, + "Type %d: CryptEncodeObjectEx failed: %08x\n", + nameValues[i].value.dwValueType, GetLastError()); + if (ret) + { + ok(size == nameValues[i].encodedSize, + "Expected size %d, got %d\n", nameValues[i].encodedSize, size); + ok(!memcmp(buf, nameValues[i].encoded, size), + "Got unexpected encoding\n"); + LocalFree(buf); + } + } + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_VALUE, + &embeddedNullNameValue.value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == OSS_PDU_MISMATCH) /* NT4/Win9x */, + "Type %d: CryptEncodeObjectEx failed: %08x\n", + embeddedNullNameValue.value.dwValueType, GetLastError()); + if (ret) + { + ok(size == embeddedNullNameValue.encodedSize, + "Expected size %d, got %d\n", embeddedNullNameValue.encodedSize, size); + ok(!memcmp(buf, embeddedNullNameValue.encoded, size), + "Got unexpected encoding\n"); + LocalFree(buf); + } +} + +static void test_decodeNameValue(DWORD dwEncoding) +{ + int i; + BYTE *buf = NULL; + DWORD bufSize = 0; + BOOL ret; + + for (i = 0; i < sizeof(nameValues) / sizeof(nameValues[0]); i++) + { + ret = pCryptDecodeObjectEx(dwEncoding, X509_NAME_VALUE, + nameValues[i].encoded, nameValues[i].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, + &buf, &bufSize); + ok(ret, "Value type %d: CryptDecodeObjectEx failed: %08x\n", + nameValues[i].value.dwValueType, GetLastError()); + if (ret) + { + compareNameValues(&nameValues[i].value, + (const CERT_NAME_VALUE *)buf); + LocalFree(buf); + } + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_NAME_VALUE, + embeddedNullNameValue.encoded, embeddedNullNameValue.encodedSize, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_SHARE_OID_STRING_FLAG, NULL, + &buf, &bufSize); + /* Some Windows versions disallow name values with embedded NULLs, so + * either success or failure is acceptable. + */ + if (ret) + { + CERT_NAME_VALUE rdnEncodedValue = { CERT_RDN_ENCODED_BLOB, + { sizeof(ia5EmbeddedNull), ia5EmbeddedNull } }; + CERT_NAME_VALUE embeddedNullValue = { CERT_RDN_IA5_STRING, + { sizeof(embedded_null) - 1, (BYTE *)embedded_null } }; + const CERT_NAME_VALUE *got = (const CERT_NAME_VALUE *)buf, + *expected = NULL; + + /* Some Windows versions decode name values with embedded NULLs, + * others leave them encoded, even with the same version of crypt32. + * Accept either. + */ + ok(got->dwValueType == CERT_RDN_ENCODED_BLOB || + got->dwValueType == CERT_RDN_IA5_STRING, + "Expected CERT_RDN_ENCODED_BLOB or CERT_RDN_IA5_STRING, got %d\n", + got->dwValueType); + if (got->dwValueType == CERT_RDN_ENCODED_BLOB) + expected = &rdnEncodedValue; + else if (got->dwValueType == CERT_RDN_IA5_STRING) + expected = &embeddedNullValue; + if (expected) + { + ok(got->Value.cbData == expected->Value.cbData, + "String type %d: unexpected data size, got %d, expected %d\n", + got->dwValueType, got->Value.cbData, expected->Value.cbData); + if (got->Value.cbData && got->Value.pbData) + ok(!memcmp(got->Value.pbData, expected->Value.pbData, + min(got->Value.cbData, expected->Value.cbData)), + "String type %d: unexpected value\n", expected->dwValueType); + } + LocalFree(buf); + } +} + +static const BYTE emptyURL[] = { 0x30, 0x02, 0x86, 0x00 }; +static const BYTE emptyURLExtraBytes[] = { 0x30, 0x02, 0x86, 0x00, 0, 0, 0 }; +static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e', + 'h','q','.','o','r','g',0 }; +static const BYTE encodedURL[] = { 0x30, 0x13, 0x86, 0x11, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, + 0x6f, 0x72, 0x67 }; +static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f, + 0x575b, 0 }; +static const WCHAR dnsName[] = { 'w','i','n','e','h','q','.','o','r','g',0 }; +static const BYTE encodedDnsName[] = { 0x30, 0x0c, 0x82, 0x0a, 0x77, 0x69, + 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 }; +static const BYTE localhost[] = { 127, 0, 0, 1 }; +static const BYTE encodedIPAddr[] = { 0x30, 0x06, 0x87, 0x04, 0x7f, 0x00, 0x00, + 0x01 }; +static const unsigned char encodedCommonName[] = { + 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,'J','u','a','n',' ','L','a','n','g',0}; +static const BYTE encodedOidName[] = { 0x30,0x04,0x88,0x02,0x2a,0x03 }; +static const BYTE encodedDirectoryName[] = { +0x30,0x19,0xa4,0x17,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; + +static void test_encodeAltName(DWORD dwEncoding) +{ + CERT_ALT_NAME_INFO info = { 0 }; + CERT_ALT_NAME_ENTRY entry = { 0 }; + BYTE *buf = NULL; + DWORD size = 0; + BOOL ret; + char oid[] = "1.2.3"; + + /* Test with empty info */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(emptySequence), "Wrong size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "Unexpected value\n"); + LocalFree(buf); + } + /* Test with an empty entry */ + info.cAltEntry = 1; + info.rgAltEntry = &entry; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Test with an empty pointer */ + entry.dwAltNameChoice = CERT_ALT_NAME_URL; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(emptyURL), "Wrong size %d\n", size); + ok(!memcmp(buf, emptyURL, size), "Unexpected value\n"); + LocalFree(buf); + } + /* Test with a real URL */ + U(entry).pwszURL = (LPWSTR)url; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(encodedURL), "Wrong size %d\n", size); + ok(!memcmp(buf, encodedURL, size), "Unexpected value\n"); + LocalFree(buf); + } + /* Now with the URL containing an invalid IA5 char */ + U(entry).pwszURL = (LPWSTR)nihongoURL; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING, + "Expected CRYPT_E_INVALID_IA5_STRING, got %08x\n", GetLastError()); + /* The first invalid character is at index 7 */ + ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7, + "Expected invalid char at index 7, got %d\n", + GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size)); + /* Now with the URL missing a scheme */ + U(entry).pwszURL = (LPWSTR)dnsName; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + /* This succeeds, but it shouldn't, so don't worry about conforming */ + LocalFree(buf); + } + /* Now with a DNS name */ + entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(encodedDnsName), "Wrong size %d\n", size); + ok(!memcmp(buf, encodedDnsName, size), "Unexpected value\n"); + LocalFree(buf); + } + /* Test with an IP address */ + entry.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS; + U(entry).IPAddress.cbData = sizeof(localhost); + U(entry).IPAddress.pbData = (LPBYTE)localhost; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(encodedIPAddr), "Wrong size %d\n", size); + ok(!memcmp(buf, encodedIPAddr, size), "Unexpected value\n"); + LocalFree(buf); + } + /* Test with OID */ + entry.dwAltNameChoice = CERT_ALT_NAME_REGISTERED_ID; + U(entry).pszRegisteredID = oid; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(encodedOidName), "Wrong size %d\n", size); + ok(!memcmp(buf, encodedOidName, size), "Unexpected value\n"); + LocalFree(buf); + } + /* Test with directory name */ + entry.dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME; + U(entry).DirectoryName.cbData = sizeof(encodedCommonName); + U(entry).DirectoryName.pbData = (LPBYTE)encodedCommonName; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(encodedDirectoryName), "Wrong size %d\n", size); + ok(!memcmp(buf, encodedDirectoryName, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeAltName(DWORD dwEncoding) +{ + static const BYTE unimplementedType[] = { 0x30, 0x06, 0x85, 0x04, 0x7f, + 0x00, 0x00, 0x01 }; + static const BYTE bogusType[] = { 0x30, 0x06, 0x89, 0x04, 0x7f, 0x00, 0x00, + 0x01 }; + static const BYTE dns_embedded_null[] = { 0x30,0x10,0x82,0x0e,0x66,0x6f, + 0x6f,0x2e,0x63,0x6f,0x6d,0x00,0x62,0x61,0x64,0x64,0x69,0x65 }; + static const BYTE dns_embedded_bell[] = { 0x30,0x10,0x82,0x0e,0x66,0x6f, + 0x6f,0x2e,0x63,0x6f,0x6d,0x07,0x62,0x61,0x64,0x64,0x69,0x65 }; + static const BYTE url_embedded_null[] = { 0x30,0x10,0x86,0x0e,0x66,0x6f, + 0x6f,0x2e,0x63,0x6f,0x6d,0x00,0x62,0x61,0x64,0x64,0x69,0x65 }; + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + CERT_ALT_NAME_INFO *info; + + /* Test some bogus ones first */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, + unimplementedType, sizeof(unimplementedType), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, + bogusType, sizeof(bogusType), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, + &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + /* Now expected cases */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptySequence, + emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + info = (CERT_ALT_NAME_INFO *)buf; + + ok(info->cAltEntry == 0, "Expected 0 entries, got %d\n", + info->cAltEntry); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, emptyURL, + emptyURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + info = (CERT_ALT_NAME_INFO *)buf; + + ok(info->cAltEntry == 1, "Expected 1 entries, got %d\n", + info->cAltEntry); + ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL, + "Expected CERT_ALT_NAME_URL, got %d\n", + info->rgAltEntry[0].dwAltNameChoice); + ok(U(info->rgAltEntry[0]).pwszURL == NULL || !*U(info->rgAltEntry[0]).pwszURL, + "Expected empty URL\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, + emptyURLExtraBytes, sizeof(emptyURLExtraBytes), 0, NULL, NULL, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedURL, + encodedURL[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + info = (CERT_ALT_NAME_INFO *)buf; + + ok(info->cAltEntry == 1, "Expected 1 entries, got %d\n", + info->cAltEntry); + ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_URL, + "Expected CERT_ALT_NAME_URL, got %d\n", + info->rgAltEntry[0].dwAltNameChoice); + ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszURL, url), "Unexpected URL\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedDnsName, + encodedDnsName[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + info = (CERT_ALT_NAME_INFO *)buf; + + ok(info->cAltEntry == 1, "Expected 1 entries, got %d\n", + info->cAltEntry); + ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME, + "Expected CERT_ALT_NAME_DNS_NAME, got %d\n", + info->rgAltEntry[0].dwAltNameChoice); + ok(!lstrcmpW(U(info->rgAltEntry[0]).pwszDNSName, dnsName), + "Unexpected DNS name\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedIPAddr, + encodedIPAddr[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + info = (CERT_ALT_NAME_INFO *)buf; + + ok(info->cAltEntry == 1, "Expected 1 entries, got %d\n", + info->cAltEntry); + ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS, + "Expected CERT_ALT_NAME_IP_ADDRESS, got %d\n", + info->rgAltEntry[0].dwAltNameChoice); + ok(U(info->rgAltEntry[0]).IPAddress.cbData == sizeof(localhost), + "Unexpected IP address length %d\n", + U(info->rgAltEntry[0]).IPAddress.cbData); + ok(!memcmp(U(info->rgAltEntry[0]).IPAddress.pbData, localhost, + sizeof(localhost)), "Unexpected IP address value\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, encodedOidName, + sizeof(encodedOidName), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + info = (CERT_ALT_NAME_INFO *)buf; + + ok(info->cAltEntry == 1, "Expected 1 entries, got %d\n", + info->cAltEntry); + ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_REGISTERED_ID, + "Expected CERT_ALT_NAME_REGISTERED_ID, got %d\n", + info->rgAltEntry[0].dwAltNameChoice); + ok(!strcmp(U(info->rgAltEntry[0]).pszRegisteredID, "1.2.3"), + "Expected OID 1.2.3, got %s\n", U(info->rgAltEntry[0]).pszRegisteredID); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, + encodedDirectoryName, sizeof(encodedDirectoryName), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + info = (CERT_ALT_NAME_INFO *)buf; + + ok(info->cAltEntry == 1, "Expected 1 entries, got %d\n", + info->cAltEntry); + ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME, + "Expected CERT_ALT_NAME_DIRECTORY_NAME, got %d\n", + info->rgAltEntry[0].dwAltNameChoice); + ok(U(info->rgAltEntry[0]).DirectoryName.cbData == + sizeof(encodedCommonName), "Unexpected directory name length %d\n", + U(info->rgAltEntry[0]).DirectoryName.cbData); + ok(!memcmp(U(info->rgAltEntry[0]).DirectoryName.pbData, + encodedCommonName, sizeof(encodedCommonName)), + "Unexpected directory name value\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, + dns_embedded_null, sizeof(dns_embedded_null), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &bufSize); + /* Fails on WinXP with CRYPT_E_ASN1_RULE. I'm not too concerned about the + * particular failure, just that it doesn't decode. + * It succeeds on (broken) Windows versions that haven't addressed + * embedded NULLs in alternate names. + */ + ok(!ret || broken(ret), "expected failure\n"); + /* An embedded bell character is allowed, however. */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, + dns_embedded_bell, sizeof(dns_embedded_bell), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + info = (CERT_ALT_NAME_INFO *)buf; + + ok(info->cAltEntry == 1, "Expected 1 entries, got %d\n", + info->cAltEntry); + ok(info->rgAltEntry[0].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME, + "Expected CERT_ALT_NAME_DNS_NAME, got %d\n", + info->rgAltEntry[0].dwAltNameChoice); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ALTERNATE_NAME, + url_embedded_null, sizeof(dns_embedded_null), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &bufSize); + /* Again, fails on WinXP with CRYPT_E_ASN1_RULE. I'm not too concerned + * about the particular failure, just that it doesn't decode. + * It succeeds on (broken) Windows versions that haven't addressed + * embedded NULLs in alternate names. + */ + ok(!ret || broken(ret), "expected failure\n"); +} + +struct UnicodeExpectedError +{ + DWORD valueType; + LPCWSTR str; + DWORD errorIndex; + DWORD error; +}; + +static const WCHAR oneW[] = { '1',0 }; +static const WCHAR aW[] = { 'a',0 }; +static const WCHAR quoteW[] = { '"', 0 }; + +static struct UnicodeExpectedError unicodeErrors[] = { + { CERT_RDN_ANY_TYPE, oneW, 0, CRYPT_E_NOT_CHAR_STRING }, + { CERT_RDN_ENCODED_BLOB, oneW, 0, CRYPT_E_NOT_CHAR_STRING }, + { CERT_RDN_OCTET_STRING, oneW, 0, CRYPT_E_NOT_CHAR_STRING }, + { CERT_RDN_NUMERIC_STRING, aW, 0, CRYPT_E_INVALID_NUMERIC_STRING }, + { CERT_RDN_PRINTABLE_STRING, quoteW, 0, CRYPT_E_INVALID_PRINTABLE_STRING }, + { CERT_RDN_IA5_STRING, nihongoURL, 7, CRYPT_E_INVALID_IA5_STRING }, +}; + +struct UnicodeExpectedResult +{ + DWORD valueType; + LPCWSTR str; + CRYPT_DATA_BLOB encoded; +}; + +static BYTE oneNumeric[] = { 0x12, 0x01, 0x31 }; +static BYTE onePrintable[] = { 0x13, 0x01, 0x31 }; +static BYTE oneTeletex[] = { 0x14, 0x01, 0x31 }; +static BYTE oneVideotex[] = { 0x15, 0x01, 0x31 }; +static BYTE oneIA5[] = { 0x16, 0x01, 0x31 }; +static BYTE oneGraphic[] = { 0x19, 0x01, 0x31 }; +static BYTE oneVisible[] = { 0x1a, 0x01, 0x31 }; +static BYTE oneUniversal[] = { 0x1c, 0x04, 0x00, 0x00, 0x00, 0x31 }; +static BYTE oneGeneral[] = { 0x1b, 0x01, 0x31 }; +static BYTE oneBMP[] = { 0x1e, 0x02, 0x00, 0x31 }; +static BYTE oneUTF8[] = { 0x0c, 0x01, 0x31 }; +static BYTE nihongoT61[] = { 0x14,0x09,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f, + 0x5b }; +static BYTE nihongoGeneral[] = { 0x1b,0x09,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, + 0x6f,0x5b }; +static BYTE nihongoBMP[] = { 0x1e,0x12,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70, + 0x00,0x3a,0x00,0x2f,0x00,0x2f,0x22,0x6f,0x57,0x5b }; +static BYTE nihongoUTF8[] = { 0x0c,0x0d,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, + 0xe2,0x89,0xaf,0xe5,0x9d,0x9b }; + +static struct UnicodeExpectedResult unicodeResults[] = { + { CERT_RDN_NUMERIC_STRING, oneW, { sizeof(oneNumeric), oneNumeric } }, + { CERT_RDN_PRINTABLE_STRING, oneW, { sizeof(onePrintable), onePrintable } }, + { CERT_RDN_TELETEX_STRING, oneW, { sizeof(oneTeletex), oneTeletex } }, + { CERT_RDN_VIDEOTEX_STRING, oneW, { sizeof(oneVideotex), oneVideotex } }, + { CERT_RDN_IA5_STRING, oneW, { sizeof(oneIA5), oneIA5 } }, + { CERT_RDN_GRAPHIC_STRING, oneW, { sizeof(oneGraphic), oneGraphic } }, + { CERT_RDN_VISIBLE_STRING, oneW, { sizeof(oneVisible), oneVisible } }, + { CERT_RDN_UNIVERSAL_STRING, oneW, { sizeof(oneUniversal), oneUniversal } }, + { CERT_RDN_GENERAL_STRING, oneW, { sizeof(oneGeneral), oneGeneral } }, + { CERT_RDN_BMP_STRING, oneW, { sizeof(oneBMP), oneBMP } }, + { CERT_RDN_UTF8_STRING, oneW, { sizeof(oneUTF8), oneUTF8 } }, + { CERT_RDN_BMP_STRING, nihongoURL, { sizeof(nihongoBMP), nihongoBMP } }, + { CERT_RDN_UTF8_STRING, nihongoURL, { sizeof(nihongoUTF8), nihongoUTF8 } }, +}; + +static struct UnicodeExpectedResult unicodeWeirdness[] = { + { CERT_RDN_TELETEX_STRING, nihongoURL, { sizeof(nihongoT61), nihongoT61 } }, + { CERT_RDN_GENERAL_STRING, nihongoURL, { sizeof(nihongoGeneral), nihongoGeneral } }, +}; + +static void test_encodeUnicodeNameValue(DWORD dwEncoding) +{ + BYTE *buf = NULL; + DWORD size = 0, i; + BOOL ret; + CERT_NAME_VALUE value; + + if (0) + { + /* Crashes on win9x */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, NULL, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* Have to have a string of some sort */ + value.dwValueType = 0; /* aka CERT_RDN_ANY_TYPE */ + value.Value.pbData = NULL; + value.Value.cbData = 0; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING, + "Expected CRYPT_E_NOT_CHAR_STRING, got %08x\n", GetLastError()); + value.dwValueType = CERT_RDN_ENCODED_BLOB; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING, + "Expected CRYPT_E_NOT_CHAR_STRING, got %08x\n", GetLastError()); + value.dwValueType = CERT_RDN_ANY_TYPE; + value.Value.pbData = (LPBYTE)oneW; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING, + "Expected CRYPT_E_NOT_CHAR_STRING, got %08x\n", GetLastError()); + value.Value.cbData = sizeof(oneW); + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING, + "Expected CRYPT_E_NOT_CHAR_STRING, got %08x\n", GetLastError()); + /* An encoded string with specified length isn't good enough either */ + value.dwValueType = CERT_RDN_ENCODED_BLOB; + value.Value.pbData = oneUniversal; + value.Value.cbData = sizeof(oneUniversal); + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_CHAR_STRING, + "Expected CRYPT_E_NOT_CHAR_STRING, got %08x\n", GetLastError()); + /* More failure checking */ + value.Value.cbData = 0; + for (i = 0; i < sizeof(unicodeErrors) / sizeof(unicodeErrors[0]); i++) + { + value.Value.pbData = (LPBYTE)unicodeErrors[i].str; + value.dwValueType = unicodeErrors[i].valueType; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == unicodeErrors[i].error, + "Value type %d: expected %08x, got %08x\n", value.dwValueType, + unicodeErrors[i].error, GetLastError()); + ok(size == unicodeErrors[i].errorIndex, + "Expected error index %d, got %d\n", unicodeErrors[i].errorIndex, + size); + } + /* cbData can be zero if the string is NULL-terminated */ + value.Value.cbData = 0; + for (i = 0; i < sizeof(unicodeResults) / sizeof(unicodeResults[0]); i++) + { + value.Value.pbData = (LPBYTE)unicodeResults[i].str; + value.dwValueType = unicodeResults[i].valueType; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == OSS_PDU_MISMATCH /* Win9x */), + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == unicodeResults[i].encoded.cbData, + "Value type %d: expected size %d, got %d\n", + value.dwValueType, unicodeResults[i].encoded.cbData, size); + ok(!memcmp(unicodeResults[i].encoded.pbData, buf, size), + "Value type %d: unexpected value\n", value.dwValueType); + LocalFree(buf); + } + } + /* These "encode," but they do so by truncating each unicode character + * rather than properly encoding it. Kept separate from the proper results, + * because the encoded forms won't decode to their original strings. + */ + for (i = 0; i < sizeof(unicodeWeirdness) / sizeof(unicodeWeirdness[0]); i++) + { + value.Value.pbData = (LPBYTE)unicodeWeirdness[i].str; + value.dwValueType = unicodeWeirdness[i].valueType; + ret = pCryptEncodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, &value, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == unicodeWeirdness[i].encoded.cbData, + "Value type %d: expected size %d, got %d\n", + value.dwValueType, unicodeWeirdness[i].encoded.cbData, size); + ok(!memcmp(unicodeWeirdness[i].encoded.pbData, buf, size), + "Value type %d: unexpected value\n", value.dwValueType); + LocalFree(buf); + } + } +} + +static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n ) +{ + if (n <= 0) return 0; + while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; } + return *str1 - *str2; +} + +static void test_decodeUnicodeNameValue(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(unicodeResults) / sizeof(unicodeResults[0]); i++) + { + BYTE *buf = NULL; + BOOL ret; + DWORD size = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_UNICODE_NAME_VALUE, + unicodeResults[i].encoded.pbData, unicodeResults[i].encoded.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == CRYPT_E_NOT_CHAR_STRING /* Win9x */), + "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret && buf) + { + PCERT_NAME_VALUE value = (PCERT_NAME_VALUE)buf; + + ok(value->dwValueType == unicodeResults[i].valueType, + "Expected value type %d, got %d\n", unicodeResults[i].valueType, + value->dwValueType); + ok(!strncmpW((LPWSTR)value->Value.pbData, unicodeResults[i].str, + value->Value.cbData / sizeof(WCHAR)), + "Unexpected decoded value for index %d (value type %d)\n", i, + unicodeResults[i].valueType); + LocalFree(buf); + } + } +} + +struct encodedOctets +{ + const BYTE *val; + const BYTE *encoded; +}; + +static const unsigned char bin46[] = { 'h','i',0 }; +static const unsigned char bin47[] = { 0x04,0x02,'h','i',0 }; +static const unsigned char bin48[] = { + 's','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 }; +static const unsigned char bin49[] = { + 0x04,0x0f,'s','o','m','e','l','o','n','g',0xff,'s','t','r','i','n','g',0 }; +static const unsigned char bin50[] = { 0 }; +static const unsigned char bin51[] = { 0x04,0x00,0 }; + +static const struct encodedOctets octets[] = { + { bin46, bin47 }, + { bin48, bin49 }, + { bin50, bin51 }, +}; + +static void test_encodeOctets(DWORD dwEncoding) +{ + CRYPT_DATA_BLOB blob; + DWORD i; + + for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++) + { + BYTE *buf = NULL; + BOOL ret; + DWORD bufSize = 0; + + blob.cbData = strlen((const char*)octets[i].val); + blob.pbData = (BYTE*)octets[i].val; + ret = pCryptEncodeObjectEx(dwEncoding, X509_OCTET_STRING, &blob, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %d\n", GetLastError()); + if (buf) + { + ok(buf[0] == 4, + "Got unexpected type %d for octet string (expected 4)\n", buf[0]); + ok(buf[1] == octets[i].encoded[1], "Got length %d, expected %d\n", + buf[1], octets[i].encoded[1]); + ok(!memcmp(buf + 1, octets[i].encoded + 1, + octets[i].encoded[1] + 1), "Got unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodeOctets(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(octets) / sizeof(octets[0]); i++) + { + BYTE *buf = NULL; + BOOL ret; + DWORD bufSize = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_OCTET_STRING, + octets[i].encoded, octets[i].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + ok(bufSize >= sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], + "Expected size >= %d, got %d\n", + (int)sizeof(CRYPT_DATA_BLOB) + octets[i].encoded[1], bufSize); + ok(buf != NULL, "Expected allocated buffer\n"); + if (buf) + { + CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)buf; + + if (blob->cbData) + ok(!memcmp(blob->pbData, octets[i].val, blob->cbData), + "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static const BYTE bytesToEncode[] = { 0xff, 0xff }; + +struct encodedBits +{ + DWORD cUnusedBits; + const BYTE *encoded; + DWORD cbDecoded; + const BYTE *decoded; +}; + +static const unsigned char bin52[] = { 0x03,0x03,0x00,0xff,0xff }; +static const unsigned char bin53[] = { 0xff,0xff }; +static const unsigned char bin54[] = { 0x03,0x03,0x01,0xff,0xfe }; +static const unsigned char bin55[] = { 0xff,0xfe }; +static const unsigned char bin56[] = { 0x03,0x02,0x01,0xfe }; +static const unsigned char bin57[] = { 0xfe }; +static const unsigned char bin58[] = { 0x03,0x01,0x00 }; + +static const struct encodedBits bits[] = { + /* normal test cases */ + { 0, bin52, 2, bin53 }, + { 1, bin54, 2, bin55 }, + /* strange test case, showing cUnusedBits >= 8 is allowed */ + { 9, bin56, 1, bin57 }, +}; + +static void test_encodeBits(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++) + { + CRYPT_BIT_BLOB blob; + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + blob.cbData = sizeof(bytesToEncode); + blob.pbData = (BYTE *)bytesToEncode; + blob.cUnusedBits = bits[i].cUnusedBits; + ret = pCryptEncodeObjectEx(dwEncoding, X509_BITS, &blob, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == bits[i].encoded[1] + 2, + "%d: Got unexpected size %d, expected %d\n", i, bufSize, + bits[i].encoded[1] + 2); + ok(!memcmp(buf, bits[i].encoded, bits[i].encoded[1] + 2), + "%d: Unexpected value\n", i); + LocalFree(buf); + } + } +} + +static void test_decodeBits(DWORD dwEncoding) +{ + static const BYTE ber[] = "\x03\x02\x01\xff"; + static const BYTE berDecoded = 0xfe; + DWORD i; + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + /* normal cases */ + for (i = 0; i < sizeof(bits) / sizeof(bits[0]); i++) + { + ret = pCryptDecodeObjectEx(dwEncoding, X509_BITS, bits[i].encoded, + bits[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, + &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRYPT_BIT_BLOB *blob; + + ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + bits[i].cbDecoded, + "Got unexpected size %d\n", bufSize); + blob = (CRYPT_BIT_BLOB *)buf; + ok(blob->cbData == bits[i].cbDecoded, + "Got unexpected length %d, expected %d\n", blob->cbData, + bits[i].cbDecoded); + if (blob->cbData && bits[i].cbDecoded) + ok(!memcmp(blob->pbData, bits[i].decoded, bits[i].cbDecoded), + "Unexpected value\n"); + LocalFree(buf); + } + } + /* special case: check that something that's valid in BER but not in DER + * decodes successfully + */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_BITS, ber, ber[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRYPT_BIT_BLOB *blob; + + ok(bufSize >= sizeof(CRYPT_BIT_BLOB) + sizeof(berDecoded), + "Got unexpected size %d\n", bufSize); + blob = (CRYPT_BIT_BLOB *)buf; + ok(blob->cbData == sizeof(berDecoded), + "Got unexpected length %d\n", blob->cbData); + if (blob->cbData) + ok(*blob->pbData == berDecoded, "Unexpected value\n"); + LocalFree(buf); + } +} + +struct Constraints2 +{ + CERT_BASIC_CONSTRAINTS2_INFO info; + const BYTE *encoded; +}; + +static const unsigned char bin59[] = { 0x30,0x00 }; +static const unsigned char bin60[] = { 0x30,0x03,0x01,0x01,0xff }; +static const unsigned char bin61[] = { 0x30,0x03,0x02,0x01,0x00 }; +static const unsigned char bin62[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static const struct Constraints2 constraints2[] = { + /* empty constraints */ + { { FALSE, FALSE, 0}, bin59 }, + /* can be a CA */ + { { TRUE, FALSE, 0}, bin60 }, + /* has path length constraints set (MSDN implies fCA needs to be TRUE as well, + * but that's not the case + */ + { { FALSE, TRUE, 0}, bin61 }, + /* can be a CA and has path length constraints set */ + { { TRUE, TRUE, 1}, bin62 }, +}; + +static const BYTE emptyConstraint[] = { 0x30, 0x03, 0x03, 0x01, 0x00 }; +static const BYTE encodedDomainName[] = { 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, + 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, + 0x03, 0x6f, 0x72, 0x67, 0x30, 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, + 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 }; +static const BYTE constraintWithDomainName[] = { 0x30, 0x32, 0x03, 0x01, 0x00, + 0x30, 0x2d, 0x30, 0x2b, 0x31, 0x29, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26, + 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6f, 0x72, 0x67, 0x30, + 0x14, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, + 0x16, 0x06, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71 }; + +static void test_encodeBasicConstraints(DWORD dwEncoding) +{ + DWORD i, bufSize = 0; + CERT_BASIC_CONSTRAINTS_INFO info = { { 0 } }; + CERT_NAME_BLOB nameBlob = { sizeof(encodedDomainName), + (LPBYTE)encodedDomainName }; + BOOL ret; + BYTE *buf = NULL; + + /* First test with the simpler info2 */ + for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++) + { + ret = pCryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2, + &constraints2[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, + &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == constraints2[i].encoded[1] + 2, + "Expected %d bytes, got %d\n", constraints2[i].encoded[1] + 2, + bufSize); + ok(!memcmp(buf, constraints2[i].encoded, + constraints2[i].encoded[1] + 2), "Unexpected value\n"); + LocalFree(buf); + } + } + /* Now test with more complex basic constraints */ + info.SubjectType.cbData = 0; + info.fPathLenConstraint = FALSE; + info.cSubtreesConstraint = 0; + ret = pCryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */, + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == sizeof(emptyConstraint), "Wrong size %d\n", bufSize); + ok(!memcmp(buf, emptyConstraint, sizeof(emptyConstraint)), + "Unexpected value\n"); + LocalFree(buf); + } + /* None of the certs I examined had any subtree constraint, but I test one + * anyway just in case. + */ + info.cSubtreesConstraint = 1; + info.rgSubtreesConstraint = &nameBlob; + ret = pCryptEncodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */, + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == sizeof(constraintWithDomainName), "Wrong size %d\n", bufSize); + ok(!memcmp(buf, constraintWithDomainName, + sizeof(constraintWithDomainName)), "Unexpected value\n"); + LocalFree(buf); + } + /* FIXME: test encoding with subject type. */ +} + +static const unsigned char bin63[] = { 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x01 }; + +static void test_decodeBasicConstraints(DWORD dwEncoding) +{ + static const BYTE inverted[] = { 0x30, 0x06, 0x02, 0x01, 0x01, 0x01, 0x01, + 0xff }; + static const struct Constraints2 badBool = { { TRUE, TRUE, 1 }, bin63 }; + DWORD i; + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + /* First test with simpler info2 */ + for (i = 0; i < sizeof(constraints2) / sizeof(constraints2[0]); i++) + { + ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2, + constraints2[i].encoded, constraints2[i].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed for item %d: %08x\n", i, + GetLastError()); + if (buf) + { + CERT_BASIC_CONSTRAINTS2_INFO *info = + (CERT_BASIC_CONSTRAINTS2_INFO *)buf; + + ok(!memcmp(info, &constraints2[i].info, sizeof(*info)), + "Unexpected value for item %d\n", i); + LocalFree(buf); + } + } + /* Check with the order of encoded elements inverted */ + buf = (PBYTE)1; + ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2, + inverted, inverted[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, + &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + ok(!buf, "Expected buf to be set to NULL\n"); + /* Check with a non-DER bool */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2, + badBool.encoded, badBool.encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_BASIC_CONSTRAINTS2_INFO *info = + (CERT_BASIC_CONSTRAINTS2_INFO *)buf; + + ok(!memcmp(info, &badBool.info, sizeof(*info)), "Unexpected value\n"); + LocalFree(buf); + } + /* Check with a non-basic constraints value */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS2, + encodedCommonName, encodedCommonName[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + /* Now check with the more complex CERT_BASIC_CONSTRAINTS_INFO */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, + emptyConstraint, sizeof(emptyConstraint), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf; + + ok(info->SubjectType.cbData == 0, "Expected no subject type\n"); + ok(!info->fPathLenConstraint, "Expected no path length constraint\n"); + ok(info->cSubtreesConstraint == 0, "Expected no subtree constraints\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_BASIC_CONSTRAINTS, + constraintWithDomainName, sizeof(constraintWithDomainName), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_BASIC_CONSTRAINTS_INFO *info = (CERT_BASIC_CONSTRAINTS_INFO *)buf; + + ok(info->SubjectType.cbData == 0, "Expected no subject type\n"); + ok(!info->fPathLenConstraint, "Expected no path length constraint\n"); + ok(info->cSubtreesConstraint == 1, "Expected a subtree constraint\n"); + if (info->cSubtreesConstraint && info->rgSubtreesConstraint) + { + ok(info->rgSubtreesConstraint[0].cbData == + sizeof(encodedDomainName), "Wrong size %d\n", + info->rgSubtreesConstraint[0].cbData); + ok(!memcmp(info->rgSubtreesConstraint[0].pbData, encodedDomainName, + sizeof(encodedDomainName)), "Unexpected value\n"); + } + LocalFree(buf); + } +} + +/* These are terrible public keys of course, I'm just testing encoding */ +static const BYTE modulus1[] = { 0,0,0,1,1,1,1,1 }; +static const BYTE modulus2[] = { 1,1,1,1,1,0,0,0 }; +static const BYTE modulus3[] = { 0x80,1,1,1,1,0,0,0 }; +static const BYTE modulus4[] = { 1,1,1,1,1,0,0,0x80 }; +static const BYTE mod1_encoded[] = { 0x30,0x0f,0x02,0x08,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x01 }; +static const BYTE mod2_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 }; +static const BYTE mod3_encoded[] = { 0x30,0x0c,0x02,0x05,0x01,0x01,0x01,0x01,0x80,0x02,0x03,0x01,0x00,0x01 }; +static const BYTE mod4_encoded[] = { 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03,0x01,0x00,0x01 }; + +struct EncodedRSAPubKey +{ + const BYTE *modulus; + size_t modulusLen; + const BYTE *encoded; + size_t decodedModulusLen; +}; + +struct EncodedRSAPubKey rsaPubKeys[] = { + { modulus1, sizeof(modulus1), mod1_encoded, sizeof(modulus1) }, + { modulus2, sizeof(modulus2), mod2_encoded, 5 }, + { modulus3, sizeof(modulus3), mod3_encoded, 5 }, + { modulus4, sizeof(modulus4), mod4_encoded, 8 }, +}; + +static void test_encodeRsaPublicKey(DWORD dwEncoding) +{ + BYTE toEncode[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + sizeof(modulus1)]; + BLOBHEADER *hdr = (BLOBHEADER *)toEncode; + RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(toEncode + sizeof(BLOBHEADER)); + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0, i; + + /* Try with a bogus blob type */ + hdr->bType = 2; + hdr->bVersion = CUR_BLOB_VERSION; + hdr->reserved = 0; + hdr->aiKeyAlg = CALG_RSA_KEYX; + rsaPubKey->magic = 0x31415352; + rsaPubKey->bitlen = sizeof(modulus1) * 8; + rsaPubKey->pubexp = 65537; + memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), modulus1, + sizeof(modulus1)); + + ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Now with a bogus reserved field */ + hdr->bType = PUBLICKEYBLOB; + hdr->reserved = 1; + ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + if (buf) + { + ok(bufSize == rsaPubKeys[0].encoded[1] + 2, + "Expected size %d, got %d\n", rsaPubKeys[0].encoded[1] + 2, bufSize); + ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n"); + LocalFree(buf); + } + /* Now with a bogus blob version */ + hdr->reserved = 0; + hdr->bVersion = 0; + ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + if (buf) + { + ok(bufSize == rsaPubKeys[0].encoded[1] + 2, + "Expected size %d, got %d\n", rsaPubKeys[0].encoded[1] + 2, bufSize); + ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n"); + LocalFree(buf); + } + /* And with a bogus alg ID */ + hdr->bVersion = CUR_BLOB_VERSION; + hdr->aiKeyAlg = CALG_DES; + ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + if (buf) + { + ok(bufSize == rsaPubKeys[0].encoded[1] + 2, + "Expected size %d, got %d\n", rsaPubKeys[0].encoded[1] + 2, bufSize); + ok(!memcmp(buf, rsaPubKeys[0].encoded, bufSize), "Unexpected value\n"); + LocalFree(buf); + } + /* Check a couple of RSA-related OIDs */ + hdr->aiKeyAlg = CALG_RSA_KEYX; + ret = pCryptEncodeObjectEx(dwEncoding, szOID_RSA_RSA, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = pCryptEncodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* Finally, all valid */ + hdr->aiKeyAlg = CALG_RSA_KEYX; + for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++) + { + memcpy(toEncode + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), + rsaPubKeys[i].modulus, rsaPubKeys[i].modulusLen); + ret = pCryptEncodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB, + toEncode, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == rsaPubKeys[i].encoded[1] + 2, + "Expected size %d, got %d\n", rsaPubKeys[i].encoded[1] + 2, + bufSize); + ok(!memcmp(buf, rsaPubKeys[i].encoded, bufSize), + "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodeRsaPublicKey(DWORD dwEncoding) +{ + DWORD i; + LPBYTE buf = NULL; + DWORD bufSize = 0; + BOOL ret; + + /* Try with a bad length */ + ret = pCryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB, + rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1], + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_MORE_INPUT /* Win9x/NT4 */), + "Expected CRYPT_E_ASN1_EOD or OSS_MORE_INPUT, got %08x\n", + GetLastError()); + /* Try with a couple of RSA-related OIDs */ + ret = pCryptDecodeObjectEx(dwEncoding, szOID_RSA_RSA, + rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, szOID_RSA_SHA1RSA, + rsaPubKeys[0].encoded, rsaPubKeys[0].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* Now try success cases */ + for (i = 0; i < sizeof(rsaPubKeys) / sizeof(rsaPubKeys[0]); i++) + { + bufSize = 0; + ret = pCryptDecodeObjectEx(dwEncoding, RSA_CSP_PUBLICKEYBLOB, + rsaPubKeys[i].encoded, rsaPubKeys[i].encoded[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + BLOBHEADER *hdr = (BLOBHEADER *)buf; + RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER)); + + ok(bufSize >= sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + + rsaPubKeys[i].decodedModulusLen, + "Wrong size %d\n", bufSize); + ok(hdr->bType == PUBLICKEYBLOB, + "Expected type PUBLICKEYBLOB (%d), got %d\n", PUBLICKEYBLOB, + hdr->bType); + ok(hdr->bVersion == CUR_BLOB_VERSION, + "Expected version CUR_BLOB_VERSION (%d), got %d\n", + CUR_BLOB_VERSION, hdr->bVersion); + ok(hdr->reserved == 0, "Expected reserved 0, got %d\n", + hdr->reserved); + ok(hdr->aiKeyAlg == CALG_RSA_KEYX, + "Expected CALG_RSA_KEYX, got %08x\n", hdr->aiKeyAlg); + ok(rsaPubKey->magic == 0x31415352, + "Expected magic RSA1, got %08x\n", rsaPubKey->magic); + ok(rsaPubKey->bitlen == rsaPubKeys[i].decodedModulusLen * 8, + "Wrong bit len %d\n", rsaPubKey->bitlen); + ok(rsaPubKey->pubexp == 65537, "Expected pubexp 65537, got %d\n", + rsaPubKey->pubexp); + ok(!memcmp(buf + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), + rsaPubKeys[i].modulus, rsaPubKeys[i].decodedModulusLen), + "Unexpected modulus\n"); + LocalFree(buf); + } + } +} + +static const BYTE intSequence[] = { 0x30, 0x1b, 0x02, 0x01, 0x01, 0x02, 0x01, + 0x7f, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, + 0x02, 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d }; + +static const BYTE mixedSequence[] = { 0x30, 0x27, 0x17, 0x0d, 0x30, 0x35, 0x30, + 0x36, 0x30, 0x36, 0x31, 0x36, 0x31, 0x30, 0x30, 0x30, 0x5a, 0x02, 0x01, 0x7f, + 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x01, 0x00, 0x02, 0x01, 0x80, 0x02, 0x02, + 0xff, 0x7f, 0x02, 0x04, 0xba, 0xdd, 0xf0, 0x0d }; + +static void test_encodeSequenceOfAny(DWORD dwEncoding) +{ + CRYPT_DER_BLOB blobs[sizeof(ints) / sizeof(ints[0])]; + CRYPT_SEQUENCE_OF_ANY seq; + DWORD i; + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + /* Encode a homogeneous sequence */ + for (i = 0; i < sizeof(ints) / sizeof(ints[0]); i++) + { + blobs[i].cbData = ints[i].encoded[1] + 2; + blobs[i].pbData = (BYTE *)ints[i].encoded; + } + seq.cValue = sizeof(ints) / sizeof(ints[0]); + seq.rgValue = blobs; + + ret = pCryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == sizeof(intSequence), "Wrong size %d\n", bufSize); + ok(!memcmp(buf, intSequence, intSequence[1] + 2), "Unexpected value\n"); + LocalFree(buf); + } + /* Change the type of the first element in the sequence, and give it + * another go + */ + blobs[0].cbData = times[0].encodedTime[1] + 2; + blobs[0].pbData = (BYTE *)times[0].encodedTime; + ret = pCryptEncodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, &seq, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == sizeof(mixedSequence), "Wrong size %d\n", bufSize); + ok(!memcmp(buf, mixedSequence, mixedSequence[1] + 2), + "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeSequenceOfAny(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, intSequence, + intSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf; + DWORD i; + + ok(seq->cValue == sizeof(ints) / sizeof(ints[0]), + "Wrong elements %d\n", seq->cValue); + for (i = 0; i < min(seq->cValue, sizeof(ints) / sizeof(ints[0])); i++) + { + ok(seq->rgValue[i].cbData == ints[i].encoded[1] + 2, + "Expected %d bytes, got %d\n", ints[i].encoded[1] + 2, + seq->rgValue[i].cbData); + ok(!memcmp(seq->rgValue[i].pbData, ints[i].encoded, + ints[i].encoded[1] + 2), "Unexpected value\n"); + } + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_SEQUENCE_OF_ANY, mixedSequence, + mixedSequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, + &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)buf; + + ok(seq->cValue == sizeof(ints) / sizeof(ints[0]), + "Wrong elements %d\n", seq->cValue); + /* Just check the first element since it's all that changed */ + ok(seq->rgValue[0].cbData == times[0].encodedTime[1] + 2, + "Expected %d bytes, got %d\n", times[0].encodedTime[1] + 2, + seq->rgValue[0].cbData); + ok(!memcmp(seq->rgValue[0].pbData, times[0].encodedTime, + times[0].encodedTime[1] + 2), "Unexpected value\n"); + LocalFree(buf); + } +} + +struct encodedExtensions +{ + CERT_EXTENSIONS exts; + const BYTE *encoded; +}; + +static BYTE crit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static BYTE noncrit_ext_data[] = { 0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static CHAR oid_basic_constraints2[] = szOID_BASIC_CONSTRAINTS2; +static CERT_EXTENSION criticalExt = + { oid_basic_constraints2, TRUE, { 8, crit_ext_data } }; +static CERT_EXTENSION nonCriticalExt = + { oid_basic_constraints2, FALSE, { 8, noncrit_ext_data } }; +static CHAR oid_short[] = "1.1"; +static CERT_EXTENSION extWithShortOid = + { oid_short, FALSE, { 0, NULL } }; + +static const BYTE ext0[] = { 0x30,0x00 }; +static const BYTE ext1[] = { 0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01, + 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static const BYTE ext2[] = { 0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x04, + 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static const BYTE ext3[] = { 0x30,0x07,0x30,0x05,0x06,0x01,0x29,0x04,0x00 }; + +static const struct encodedExtensions exts[] = { + { { 0, NULL }, ext0 }, + { { 1, &criticalExt }, ext1 }, + { { 1, &nonCriticalExt }, ext2 }, + { { 1, &extWithShortOid }, ext3 } +}; + +static void test_encodeExtensions(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++) + { + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + ret = pCryptEncodeObjectEx(dwEncoding, X509_EXTENSIONS, &exts[i].exts, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == exts[i].encoded[1] + 2, + "Expected %d bytes, got %d\n", exts[i].encoded[1] + 2, bufSize); + ok(!memcmp(buf, exts[i].encoded, exts[i].encoded[1] + 2), + "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodeExtensions(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(exts) / sizeof(exts[i]); i++) + { + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_EXTENSIONS, + exts[i].encoded, exts[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_EXTENSIONS *ext = (CERT_EXTENSIONS *)buf; + DWORD j; + + ok(ext->cExtension == exts[i].exts.cExtension, + "Expected %d extensions, see %d\n", exts[i].exts.cExtension, + ext->cExtension); + for (j = 0; j < min(ext->cExtension, exts[i].exts.cExtension); j++) + { + ok(!strcmp(ext->rgExtension[j].pszObjId, + exts[i].exts.rgExtension[j].pszObjId), + "Expected OID %s, got %s\n", + exts[i].exts.rgExtension[j].pszObjId, + ext->rgExtension[j].pszObjId); + ok(!memcmp(ext->rgExtension[j].Value.pbData, + exts[i].exts.rgExtension[j].Value.pbData, + exts[i].exts.rgExtension[j].Value.cbData), + "Unexpected value\n"); + } + LocalFree(buf); + } + } +} + +/* MS encodes public key info with a NULL if the algorithm identifier's + * parameters are empty. However, when encoding an algorithm in a CERT_INFO, + * it encodes them by omitting the algorithm parameters. It accepts either + * form for decoding. + */ +struct encodedPublicKey +{ + CERT_PUBLIC_KEY_INFO info; + const BYTE *encoded; + const BYTE *encodedNoNull; + CERT_PUBLIC_KEY_INFO decoded; +}; + +static const BYTE aKey[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, + 0xe, 0xf }; +static const BYTE params[] = { 0x02, 0x01, 0x01 }; + +static const unsigned char bin64[] = { + 0x30,0x0b,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x03,0x01,0x00}; +static const unsigned char bin65[] = { + 0x30,0x09,0x30,0x04,0x06,0x02,0x2a,0x03,0x03,0x01,0x00}; +static const unsigned char bin66[] = { + 0x30,0x0f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x01,0x00}; +static const unsigned char bin67[] = { + 0x30,0x0d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x01,0x00}; +static const unsigned char bin68[] = { + 0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03,0x11,0x00,0x00,0x01, + 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; +static const unsigned char bin69[] = { + 0x30,0x1d,0x30,0x08,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x03,0x11,0x00,0x00,0x01, + 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; +static const unsigned char bin70[] = { + 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01, + 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f}; +static const unsigned char bin71[] = { + 0x30,0x20,0x30,0x0b,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x01,0x01, + 0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f}; +static unsigned char bin72[] = { 0x05,0x00}; + +static CHAR oid_bogus[] = "1.2.3", + oid_rsa[] = szOID_RSA; + +static const struct encodedPublicKey pubKeys[] = { + /* with a bogus OID */ + { { { oid_bogus, { 0, NULL } }, { 0, NULL, 0 } }, + bin64, bin65, + { { oid_bogus, { 2, bin72 } }, { 0, NULL, 0 } } }, + /* some normal keys */ + { { { oid_rsa, { 0, NULL } }, { 0, NULL, 0} }, + bin66, bin67, + { { oid_rsa, { 2, bin72 } }, { 0, NULL, 0 } } }, + { { { oid_rsa, { 0, NULL } }, { sizeof(aKey), (BYTE *)aKey, 0} }, + bin68, bin69, + { { oid_rsa, { 2, bin72 } }, { sizeof(aKey), (BYTE *)aKey, 0} } }, + /* with add'l parameters--note they must be DER-encoded */ + { { { oid_rsa, { sizeof(params), (BYTE *)params } }, { sizeof(aKey), + (BYTE *)aKey, 0 } }, + bin70, bin71, + { { oid_rsa, { sizeof(params), (BYTE *)params } }, { sizeof(aKey), + (BYTE *)aKey, 0 } } }, +}; + +static void test_encodePublicKeyInfo(DWORD dwEncoding) +{ + DWORD i; + + for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++) + { + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + ret = pCryptEncodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO, + &pubKeys[i].info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, + &bufSize); + ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */, + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == pubKeys[i].encoded[1] + 2, + "Expected %d bytes, got %d\n", pubKeys[i].encoded[1] + 2, bufSize); + if (bufSize == pubKeys[i].encoded[1] + 2) + ok(!memcmp(buf, pubKeys[i].encoded, pubKeys[i].encoded[1] + 2), + "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static void comparePublicKeyInfo(const CERT_PUBLIC_KEY_INFO *expected, + const CERT_PUBLIC_KEY_INFO *got) +{ + ok(!strcmp(expected->Algorithm.pszObjId, got->Algorithm.pszObjId), + "Expected OID %s, got %s\n", expected->Algorithm.pszObjId, + got->Algorithm.pszObjId); + ok(expected->Algorithm.Parameters.cbData == + got->Algorithm.Parameters.cbData, + "Expected parameters of %d bytes, got %d\n", + expected->Algorithm.Parameters.cbData, got->Algorithm.Parameters.cbData); + if (expected->Algorithm.Parameters.cbData) + ok(!memcmp(expected->Algorithm.Parameters.pbData, + got->Algorithm.Parameters.pbData, got->Algorithm.Parameters.cbData), + "Unexpected algorithm parameters\n"); + ok(expected->PublicKey.cbData == got->PublicKey.cbData, + "Expected public key of %d bytes, got %d\n", + expected->PublicKey.cbData, got->PublicKey.cbData); + if (expected->PublicKey.cbData) + ok(!memcmp(expected->PublicKey.pbData, got->PublicKey.pbData, + got->PublicKey.cbData), "Unexpected public key value\n"); +} + +static void test_decodePublicKeyInfo(DWORD dwEncoding) +{ + static const BYTE bogusPubKeyInfo[] = { 0x30, 0x22, 0x30, 0x0d, 0x06, 0x06, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, + 0x11, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + DWORD i; + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + for (i = 0; i < sizeof(pubKeys) / sizeof(pubKeys[0]); i++) + { + /* The NULL form decodes to the decoded member */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO, + pubKeys[i].encoded, pubKeys[i].encoded[1] + 2, CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + comparePublicKeyInfo(&pubKeys[i].decoded, + (CERT_PUBLIC_KEY_INFO *)buf); + LocalFree(buf); + } + /* The non-NULL form decodes to the original */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO, + pubKeys[i].encodedNoNull, pubKeys[i].encodedNoNull[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + comparePublicKeyInfo(&pubKeys[i].info, (CERT_PUBLIC_KEY_INFO *)buf); + LocalFree(buf); + } + } + /* Test with bogus (not valid DER) parameters */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_PUBLIC_KEY_INFO, + bogusPubKeyInfo, bogusPubKeyInfo[1] + 2, CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &bufSize); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GetLastError()); +} + +static const BYTE v1Cert[] = { 0x30, 0x33, 0x02, 0x00, 0x30, 0x02, 0x06, 0x00, + 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x07, 0x30, + 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 }; +static const BYTE v2Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x01, 0x02, + 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 }; +static const BYTE v3Cert[] = { 0x30, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, + 0x00, 0x30, 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00 }; +static const BYTE v4Cert[] = { +0x30,0x38,0xa0,0x03,0x02,0x01,0x03,0x02,0x00,0x30,0x02,0x06,0x00,0x30,0x22, +0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00 }; +static const BYTE v1CertWithConstraints[] = { 0x30, 0x4b, 0x02, 0x00, 0x30, + 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, + 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE v1CertWithSerial[] = { 0x30, 0x4c, 0x02, 0x01, 0x01, 0x30, + 0x02, 0x06, 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, + 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, + 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE v1CertWithPubKey[] = { +0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, +0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06, +0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02, +0x01,0x01 }; +static const BYTE v1CertWithPubKeyNoNull[] = { +0x30,0x81,0x93,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x20,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, +0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55, +0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static const BYTE v1CertWithSubjectKeyId[] = { +0x30,0x7b,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67, +0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x17,0x30,0x15,0x30, +0x13,0x06,0x03,0x55,0x1d,0x0e,0x04,0x0c,0x04,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00 }; +static const BYTE v1CertWithIssuerUniqueId[] = { +0x30,0x38,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x22,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f, +0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a, +0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0x81,0x02,0x00,0x01 }; +static const BYTE v1CertWithSubjectIssuerSerialAndIssuerUniqueId[] = { +0x30,0x81,0x99,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, +0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x81,0x02,0x00,0x01,0xa3,0x16,0x30, +0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06, +0x01,0x01,0xff,0x02,0x01,0x01 }; +static const BYTE v1CertWithSubjectIssuerSerialAndIssuerUniqueIdNoNull[] = { +0x30,0x81,0x97,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x20,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, +0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x81,0x02,0x00,0x01,0xa3,0x16,0x30,0x14,0x30, +0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01, +0xff,0x02,0x01,0x01 }; + +static const BYTE serialNum[] = { 0x01 }; + +static void test_encodeCertToBeSigned(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CERT_INFO info = { 0 }; + static char oid_rsa_rsa[] = szOID_RSA_RSA; + static char oid_subject_key_identifier[] = szOID_SUBJECT_KEY_IDENTIFIER; + CERT_EXTENSION ext; + + if (0) + { + /* Test with NULL pvStructInfo (crashes on win9x) */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* Test with a V1 cert */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */, + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == v1Cert[1] + 2, "Expected size %d, got %d\n", + v1Cert[1] + 2, size); + ok(!memcmp(buf, v1Cert, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* Test v2 cert */ + info.dwVersion = CERT_V2; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */, + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v2Cert), "Wrong size %d\n", size); + ok(!memcmp(buf, v2Cert, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* Test v3 cert */ + info.dwVersion = CERT_V3; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */, + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v3Cert), "Wrong size %d\n", size); + ok(!memcmp(buf, v3Cert, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* A v4 cert? */ + info.dwVersion = 3; /* Not a typo, CERT_V3 is 2 */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(v4Cert), "Wrong size %d\n", size); + ok(!memcmp(buf, v4Cert, size), "Unexpected value\n"); + LocalFree(buf); + } + /* see if a V1 cert can have basic constraints set (RFC3280 says no, but + * API doesn't prevent it) + */ + info.dwVersion = CERT_V1; + info.cExtension = 1; + info.rgExtension = &criticalExt; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || GetLastError() == OSS_BAD_PTR /* Win9x */, + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v1CertWithConstraints), "Wrong size %d\n", size); + ok(!memcmp(buf, v1CertWithConstraints, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* test v1 cert with a serial number */ + info.SerialNumber.cbData = sizeof(serialNum); + info.SerialNumber.pbData = (BYTE *)serialNum; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(v1CertWithSerial), "Wrong size %d\n", size); + ok(!memcmp(buf, v1CertWithSerial, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* Test v1 cert with an issuer name, serial number, and issuer unique id */ + info.dwVersion = CERT_V1; + info.cExtension = 0; + info.IssuerUniqueId.cbData = sizeof(serialNum); + info.IssuerUniqueId.pbData = (BYTE *)serialNum; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == OSS_BAD_PTR /* Win98 */), + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v1CertWithIssuerUniqueId), "Wrong size %d\n", size); + ok(!memcmp(buf, v1CertWithIssuerUniqueId, size), + "Got unexpected value\n"); + LocalFree(buf); + } + /* Test v1 cert with an issuer name, a subject name, and a serial number */ + info.IssuerUniqueId.cbData = 0; + info.IssuerUniqueId.pbData = NULL; + info.cExtension = 1; + info.rgExtension = &criticalExt; + info.Issuer.cbData = sizeof(encodedCommonName); + info.Issuer.pbData = (BYTE *)encodedCommonName; + info.Subject.cbData = sizeof(encodedCommonName); + info.Subject.pbData = (BYTE *)encodedCommonName; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(bigCert), "Wrong size %d\n", size); + ok(!memcmp(buf, bigCert, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* Add a public key */ + info.SubjectPublicKeyInfo.Algorithm.pszObjId = oid_rsa_rsa; + info.SubjectPublicKeyInfo.PublicKey.cbData = sizeof(aKey); + info.SubjectPublicKeyInfo.PublicKey.pbData = (LPBYTE)aKey; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(v1CertWithPubKey) || + size == sizeof(v1CertWithPubKeyNoNull), "Wrong size %d\n", size); + if (size == sizeof(v1CertWithPubKey)) + ok(!memcmp(buf, v1CertWithPubKey, size), "Got unexpected value\n"); + else if (size == sizeof(v1CertWithPubKeyNoNull)) + ok(!memcmp(buf, v1CertWithPubKeyNoNull, size), + "Got unexpected value\n"); + LocalFree(buf); + } + /* Again add an issuer unique id */ + info.IssuerUniqueId.cbData = sizeof(serialNum); + info.IssuerUniqueId.pbData = (BYTE *)serialNum; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v1CertWithSubjectIssuerSerialAndIssuerUniqueId) || + size == sizeof(v1CertWithSubjectIssuerSerialAndIssuerUniqueIdNoNull), + "Wrong size %d\n", size); + if (size == sizeof(v1CertWithSubjectIssuerSerialAndIssuerUniqueId)) + ok(!memcmp(buf, v1CertWithSubjectIssuerSerialAndIssuerUniqueId, + size), "unexpected value\n"); + else if (size == + sizeof(v1CertWithSubjectIssuerSerialAndIssuerUniqueIdNoNull)) + ok(!memcmp(buf, + v1CertWithSubjectIssuerSerialAndIssuerUniqueIdNoNull, size), + "unexpected value\n"); + LocalFree(buf); + } + /* Remove the public key, and add a subject key identifier extension */ + info.IssuerUniqueId.cbData = 0; + info.IssuerUniqueId.pbData = NULL; + info.SubjectPublicKeyInfo.Algorithm.pszObjId = NULL; + info.SubjectPublicKeyInfo.PublicKey.cbData = 0; + info.SubjectPublicKeyInfo.PublicKey.pbData = NULL; + ext.pszObjId = oid_subject_key_identifier; + ext.fCritical = FALSE; + ext.Value.cbData = sizeof(octetCommonNameValue); + ext.Value.pbData = octetCommonNameValue; + info.cExtension = 1; + info.rgExtension = &ext; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(v1CertWithSubjectKeyId), "Wrong size %d\n", size); + ok(!memcmp(buf, v1CertWithSubjectKeyId, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeCertToBeSigned(DWORD dwEncoding) +{ + static const BYTE *corruptCerts[] = { v1Cert, v2Cert, v3Cert, v4Cert, + v1CertWithConstraints, v1CertWithSerial, v1CertWithIssuerUniqueId }; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0, i; + + /* Test with NULL pbEncoded */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 0, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG /* Win9x */), + "Expected CRYPT_E_ASN1_EOD or OSS_BAD_ARG, got %08x\n", GetLastError()); + if (0) + { + /* Crashes on win9x */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, NULL, 1, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* The following certs all fail with CRYPT_E_ASN1_CORRUPT or + * CRYPT_E_ASN1_BADTAG, because at a minimum a cert must have a non-zero + * serial number, an issuer, a subject, and a public key. + */ + for (i = 0; i < sizeof(corruptCerts) / sizeof(corruptCerts[0]); i++) + { + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, + corruptCerts[i], corruptCerts[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(!ret, "Expected failure\n"); + } + /* The following succeeds, even though v1 certs are not allowed to have + * extensions. + */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, + v1CertWithSubjectKeyId, sizeof(v1CertWithSubjectKeyId), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + CERT_INFO *info = (CERT_INFO *)buf; + + ok(size >= sizeof(CERT_INFO), "Wrong size %d\n", size); + ok(info->dwVersion == CERT_V1, "expected CERT_V1, got %d\n", + info->dwVersion); + ok(info->cExtension == 1, "expected 1 extension, got %d\n", + info->cExtension); + LocalFree(buf); + } + /* The following also succeeds, even though V1 certs are not allowed to + * have issuer unique ids. + */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, + v1CertWithSubjectIssuerSerialAndIssuerUniqueId, + sizeof(v1CertWithSubjectIssuerSerialAndIssuerUniqueId), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + CERT_INFO *info = (CERT_INFO *)buf; + + ok(size >= sizeof(CERT_INFO), "Wrong size %d\n", size); + ok(info->dwVersion == CERT_V1, "expected CERT_V1, got %d\n", + info->dwVersion); + ok(info->IssuerUniqueId.cbData == sizeof(serialNum), + "unexpected issuer unique id size %d\n", info->IssuerUniqueId.cbData); + ok(!memcmp(info->IssuerUniqueId.pbData, serialNum, sizeof(serialNum)), + "unexpected issuer unique id value\n"); + LocalFree(buf); + } + /* Now check with serial number, subject and issuer specified */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, bigCert, + sizeof(bigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_INFO *info = (CERT_INFO *)buf; + + ok(size >= sizeof(CERT_INFO), "Wrong size %d\n", size); + ok(info->SerialNumber.cbData == 1, + "Expected serial number size 1, got %d\n", info->SerialNumber.cbData); + ok(*info->SerialNumber.pbData == *serialNum, + "Expected serial number %d, got %d\n", *serialNum, + *info->SerialNumber.pbData); + ok(info->Issuer.cbData == sizeof(encodedCommonName), + "Wrong size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData), + "Unexpected issuer\n"); + ok(info->Subject.cbData == sizeof(encodedCommonName), + "Wrong size %d\n", info->Subject.cbData); + ok(!memcmp(info->Subject.pbData, encodedCommonName, + info->Subject.cbData), "Unexpected subject\n"); + LocalFree(buf); + } + /* Check again with pub key specified */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, + v1CertWithPubKey, sizeof(v1CertWithPubKey), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_INFO *info = (CERT_INFO *)buf; + + ok(size >= sizeof(CERT_INFO), "Wrong size %d\n", size); + ok(info->SerialNumber.cbData == 1, + "Expected serial number size 1, got %d\n", info->SerialNumber.cbData); + ok(*info->SerialNumber.pbData == *serialNum, + "Expected serial number %d, got %d\n", *serialNum, + *info->SerialNumber.pbData); + ok(info->Issuer.cbData == sizeof(encodedCommonName), + "Wrong size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData), + "Unexpected issuer\n"); + ok(info->Subject.cbData == sizeof(encodedCommonName), + "Wrong size %d\n", info->Subject.cbData); + ok(!memcmp(info->Subject.pbData, encodedCommonName, + info->Subject.cbData), "Unexpected subject\n"); + ok(!strcmp(info->SubjectPublicKeyInfo.Algorithm.pszObjId, + szOID_RSA_RSA), "Expected szOID_RSA_RSA, got %s\n", + info->SubjectPublicKeyInfo.Algorithm.pszObjId); + ok(info->SubjectPublicKeyInfo.PublicKey.cbData == sizeof(aKey), + "Wrong size %d\n", info->SubjectPublicKeyInfo.PublicKey.cbData); + ok(!memcmp(info->SubjectPublicKeyInfo.PublicKey.pbData, aKey, + sizeof(aKey)), "Unexpected public key\n"); + LocalFree(buf); + } +} + +static const BYTE hash[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, + 0xe, 0xf }; + +static const BYTE signedBigCert[] = { + 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30, + 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, + 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, + 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, + 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; + +static void test_encodeCert(DWORD dwEncoding) +{ + /* Note the SignatureAlgorithm must match that in the encoded cert. Note + * also that bigCert is a NULL-terminated string, so don't count its + * last byte (otherwise the signed cert won't decode.) + */ + CERT_SIGNED_CONTENT_INFO info = { { sizeof(bigCert), (BYTE *)bigCert }, + { NULL, { 0, NULL } }, { sizeof(hash), (BYTE *)hash, 0 } }; + BOOL ret; + BYTE *buf = NULL; + DWORD bufSize = 0; + + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &bufSize); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(bufSize == sizeof(signedBigCert), "Wrong size %d\n", bufSize); + ok(!memcmp(buf, signedBigCert, bufSize), "Unexpected cert\n"); + LocalFree(buf); + } +} + +static void test_decodeCert(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT, signedBigCert, + sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_SIGNED_CONTENT_INFO *info = (CERT_SIGNED_CONTENT_INFO *)buf; + + ok(info->ToBeSigned.cbData == sizeof(bigCert), + "Wrong cert size %d\n", info->ToBeSigned.cbData); + ok(!memcmp(info->ToBeSigned.pbData, bigCert, info->ToBeSigned.cbData), + "Unexpected cert\n"); + ok(info->Signature.cbData == sizeof(hash), + "Wrong signature size %d\n", info->Signature.cbData); + ok(!memcmp(info->Signature.pbData, hash, info->Signature.cbData), + "Unexpected signature\n"); + LocalFree(buf); + } + /* A signed cert decodes as a CERT_INFO too */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_TO_BE_SIGNED, signedBigCert, + sizeof(signedBigCert), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_INFO *info = (CERT_INFO *)buf; + + ok(size >= sizeof(CERT_INFO), "Wrong size %d\n", size); + ok(info->SerialNumber.cbData == 1, + "Expected serial number size 1, got %d\n", info->SerialNumber.cbData); + ok(*info->SerialNumber.pbData == *serialNum, + "Expected serial number %d, got %d\n", *serialNum, + *info->SerialNumber.pbData); + ok(info->Issuer.cbData == sizeof(encodedCommonName), + "Wrong size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData), + "Unexpected issuer\n"); + ok(info->Subject.cbData == sizeof(encodedCommonName), + "Wrong size %d\n", info->Subject.cbData); + ok(!memcmp(info->Subject.pbData, encodedCommonName, + info->Subject.cbData), "Unexpected subject\n"); + LocalFree(buf); + } +} + +static const BYTE emptyDistPoint[] = { 0x30, 0x02, 0x30, 0x00 }; +static const BYTE distPointWithUrl[] = { 0x30, 0x19, 0x30, 0x17, 0xa0, 0x15, + 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, + 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 }; +static const BYTE distPointWithReason[] = { 0x30, 0x06, 0x30, 0x04, 0x81, 0x02, + 0x00, 0x03 }; +static const BYTE distPointWithIssuer[] = { 0x30, 0x17, 0x30, 0x15, 0xa2, 0x13, + 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, + 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67 }; +static const BYTE distPointWithUrlAndIssuer[] = { 0x30, 0x2e, 0x30, 0x2c, 0xa0, + 0x15, 0xa0, 0x13, 0x86, 0x11, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x69, 0x6e, 0x65, 0x68, 0x71, 0x2e, 0x6f, 0x72, 0x67, 0xa2, 0x13, 0x86, 0x11, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x69, 0x6e, 0x65, 0x68, 0x71, + 0x2e, 0x6f, 0x72, 0x67 }; +static const BYTE crlReason = CRL_REASON_KEY_COMPROMISE | + CRL_REASON_AFFILIATION_CHANGED; + +static void test_encodeCRLDistPoints(DWORD dwEncoding) +{ + CRL_DIST_POINTS_INFO info = { 0 }; + CRL_DIST_POINT point = { { 0 } }; + CERT_ALT_NAME_ENTRY entry = { 0 }; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + + /* Test with an empty info */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Test with one empty dist point */ + info.cDistPoint = 1; + info.rgDistPoint = &point; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptyDistPoint), "Wrong size %d\n", size); + ok(!memcmp(buf, emptyDistPoint, size), "Unexpected value\n"); + LocalFree(buf); + } + /* A dist point with an invalid name */ + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; + entry.dwAltNameChoice = CERT_ALT_NAME_URL; + U(entry).pwszURL = (LPWSTR)nihongoURL; + U(point.DistPointName).FullName.cAltEntry = 1; + U(point.DistPointName).FullName.rgAltEntry = &entry; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING, + "Expected CRYPT_E_INVALID_IA5_STRING, got %08x\n", GetLastError()); + /* The first invalid character is at index 7 */ + ok(GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size) == 7, + "Expected invalid char at index 7, got %d\n", + GET_CERT_ALT_NAME_VALUE_ERR_INDEX(size)); + /* A dist point with (just) a valid name */ + U(entry).pwszURL = (LPWSTR)url; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(distPointWithUrl), "Wrong size %d\n", size); + ok(!memcmp(buf, distPointWithUrl, size), "Unexpected value\n"); + LocalFree(buf); + } + /* A dist point with (just) reason flags */ + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_NO_NAME; + point.ReasonFlags.cbData = sizeof(crlReason); + point.ReasonFlags.pbData = (LPBYTE)&crlReason; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(distPointWithReason), "Wrong size %d\n", size); + ok(!memcmp(buf, distPointWithReason, size), "Unexpected value\n"); + LocalFree(buf); + } + /* A dist point with just an issuer */ + point.ReasonFlags.cbData = 0; + point.CRLIssuer.cAltEntry = 1; + point.CRLIssuer.rgAltEntry = &entry; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(distPointWithIssuer), "Wrong size %d\n", size); + ok(!memcmp(buf, distPointWithIssuer, size), "Unexpected value\n"); + LocalFree(buf); + } + /* A dist point with both a name and an issuer */ + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(distPointWithUrlAndIssuer), + "Wrong size %d\n", size); + ok(!memcmp(buf, distPointWithUrlAndIssuer, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeCRLDistPoints(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + PCRL_DIST_POINTS_INFO info; + PCRL_DIST_POINT point; + PCERT_ALT_NAME_ENTRY entry; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, + emptyDistPoint, emptyDistPoint[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + info = (PCRL_DIST_POINTS_INFO)buf; + ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), + "Wrong size %d\n", size); + ok(info->cDistPoint == 1, "Expected 1 dist points, got %d\n", + info->cDistPoint); + point = info->rgDistPoint; + ok(point->DistPointName.dwDistPointNameChoice == CRL_DIST_POINT_NO_NAME, + "Expected CRL_DIST_POINT_NO_NAME, got %d\n", + point->DistPointName.dwDistPointNameChoice); + ok(point->ReasonFlags.cbData == 0, "Expected no reason\n"); + ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, + distPointWithUrl, distPointWithUrl[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + info = (PCRL_DIST_POINTS_INFO)buf; + ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), + "Wrong size %d\n", size); + ok(info->cDistPoint == 1, "Expected 1 dist points, got %d\n", + info->cDistPoint); + point = info->rgDistPoint; + ok(point->DistPointName.dwDistPointNameChoice == + CRL_DIST_POINT_FULL_NAME, + "Expected CRL_DIST_POINT_FULL_NAME, got %d\n", + point->DistPointName.dwDistPointNameChoice); + ok(U(point->DistPointName).FullName.cAltEntry == 1, + "Expected 1 name entry, got %d\n", + U(point->DistPointName).FullName.cAltEntry); + entry = U(point->DistPointName).FullName.rgAltEntry; + ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL, + "Expected CERT_ALT_NAME_URL, got %d\n", entry->dwAltNameChoice); + ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n"); + ok(point->ReasonFlags.cbData == 0, "Expected no reason\n"); + ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, + distPointWithReason, distPointWithReason[1] + 2, CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + info = (PCRL_DIST_POINTS_INFO)buf; + ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), + "Wrong size %d\n", size); + ok(info->cDistPoint == 1, "Expected 1 dist points, got %d\n", + info->cDistPoint); + point = info->rgDistPoint; + ok(point->DistPointName.dwDistPointNameChoice == + CRL_DIST_POINT_NO_NAME, + "Expected CRL_DIST_POINT_NO_NAME, got %d\n", + point->DistPointName.dwDistPointNameChoice); + ok(point->ReasonFlags.cbData == sizeof(crlReason), + "Expected reason length\n"); + ok(!memcmp(point->ReasonFlags.pbData, &crlReason, sizeof(crlReason)), + "Unexpected reason\n"); + ok(point->CRLIssuer.cAltEntry == 0, "Expected no issuer\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_CRL_DIST_POINTS, + distPointWithUrlAndIssuer, distPointWithUrlAndIssuer[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + info = (PCRL_DIST_POINTS_INFO)buf; + ok(size >= sizeof(CRL_DIST_POINTS_INFO) + sizeof(CRL_DIST_POINT), + "Wrong size %d\n", size); + ok(info->cDistPoint == 1, "Expected 1 dist points, got %d\n", + info->cDistPoint); + point = info->rgDistPoint; + ok(point->DistPointName.dwDistPointNameChoice == + CRL_DIST_POINT_FULL_NAME, + "Expected CRL_DIST_POINT_FULL_NAME, got %d\n", + point->DistPointName.dwDistPointNameChoice); + ok(U(point->DistPointName).FullName.cAltEntry == 1, + "Expected 1 name entry, got %d\n", + U(point->DistPointName).FullName.cAltEntry); + entry = U(point->DistPointName).FullName.rgAltEntry; + ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL, + "Expected CERT_ALT_NAME_URL, got %d\n", entry->dwAltNameChoice); + ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n"); + ok(point->ReasonFlags.cbData == 0, "Expected no reason\n"); + ok(point->CRLIssuer.cAltEntry == 1, + "Expected 1 issuer entry, got %d\n", point->CRLIssuer.cAltEntry); + entry = point->CRLIssuer.rgAltEntry; + ok(entry->dwAltNameChoice == CERT_ALT_NAME_URL, + "Expected CERT_ALT_NAME_URL, got %d\n", entry->dwAltNameChoice); + ok(!lstrcmpW(U(*entry).pwszURL, url), "Unexpected name\n"); + LocalFree(buf); + } +} + +static const BYTE badFlagsIDP[] = { 0x30,0x06,0x81,0x01,0xff,0x82,0x01,0xff }; +static const BYTE emptyNameIDP[] = { 0x30,0x04,0xa0,0x02,0xa0,0x00 }; +static const BYTE urlIDP[] = { 0x30,0x17,0xa0,0x15,0xa0,0x13,0x86,0x11,0x68, + 0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72, + 0x67 }; + +static void test_encodeCRLIssuingDistPoint(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CRL_ISSUING_DIST_POINT point = { { 0 } }; + CERT_ALT_NAME_ENTRY entry; + + ret = pCryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, NULL, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no X509_ISSUING_DIST_POINT encode support\n"); + return; + } + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + ret = pCryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptySequence), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "Unexpected value\n"); + LocalFree(buf); + } + /* nonsensical flags */ + point.fOnlyContainsUserCerts = TRUE; + point.fOnlyContainsCACerts = TRUE; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(badFlagsIDP), "Unexpected size %d\n", size); + ok(!memcmp(buf, badFlagsIDP, size), "Unexpected value\n"); + LocalFree(buf); + } + /* unimplemented name type */ + point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE; + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_ISSUER_RDN_NAME; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* empty name */ + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; + U(point.DistPointName).FullName.cAltEntry = 0; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptyNameIDP), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyNameIDP, size), "Unexpected value\n"); + LocalFree(buf); + } + /* name with URL entry */ + entry.dwAltNameChoice = CERT_ALT_NAME_URL; + U(entry).pwszURL = (LPWSTR)url; + U(point.DistPointName).FullName.cAltEntry = 1; + U(point.DistPointName).FullName.rgAltEntry = &entry; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, &point, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(urlIDP), "Unexpected size %d\n", size); + ok(!memcmp(buf, urlIDP, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void compareAltNameEntry(const CERT_ALT_NAME_ENTRY *expected, + const CERT_ALT_NAME_ENTRY *got) +{ + ok(expected->dwAltNameChoice == got->dwAltNameChoice, + "Expected name choice %d, got %d\n", expected->dwAltNameChoice, + got->dwAltNameChoice); + if (expected->dwAltNameChoice == got->dwAltNameChoice) + { + switch (got->dwAltNameChoice) + { + case CERT_ALT_NAME_RFC822_NAME: + case CERT_ALT_NAME_DNS_NAME: + case CERT_ALT_NAME_EDI_PARTY_NAME: + case CERT_ALT_NAME_URL: + case CERT_ALT_NAME_REGISTERED_ID: + ok((!U(*expected).pwszURL && !U(*got).pwszURL) || + (!U(*expected).pwszURL && !lstrlenW(U(*got).pwszURL)) || + (!U(*got).pwszURL && !lstrlenW(U(*expected).pwszURL)) || + !lstrcmpW(U(*expected).pwszURL, U(*got).pwszURL), + "Unexpected name\n"); + break; + case CERT_ALT_NAME_X400_ADDRESS: + case CERT_ALT_NAME_DIRECTORY_NAME: + case CERT_ALT_NAME_IP_ADDRESS: + ok(U(*got).IPAddress.cbData == U(*expected).IPAddress.cbData, + "Unexpected IP address length %d\n", U(*got).IPAddress.cbData); + ok(!memcmp(U(*got).IPAddress.pbData, U(*got).IPAddress.pbData, + U(*got).IPAddress.cbData), "Unexpected value\n"); + break; + } + } +} + +static void compareAltNameInfo(const CERT_ALT_NAME_INFO *expected, + const CERT_ALT_NAME_INFO *got) +{ + DWORD i; + + ok(expected->cAltEntry == got->cAltEntry, "Expected %d entries, got %d\n", + expected->cAltEntry, got->cAltEntry); + for (i = 0; i < min(expected->cAltEntry, got->cAltEntry); i++) + compareAltNameEntry(&expected->rgAltEntry[i], &got->rgAltEntry[i]); +} + +static void compareDistPointName(const CRL_DIST_POINT_NAME *expected, + const CRL_DIST_POINT_NAME *got) +{ + ok(got->dwDistPointNameChoice == expected->dwDistPointNameChoice, + "Unexpected name choice %d\n", got->dwDistPointNameChoice); + if (got->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME) + compareAltNameInfo(&(U(*expected).FullName), &(U(*got).FullName)); +} + +static void compareCRLIssuingDistPoints(const CRL_ISSUING_DIST_POINT *expected, + const CRL_ISSUING_DIST_POINT *got) +{ + compareDistPointName(&expected->DistPointName, &got->DistPointName); + ok(got->fOnlyContainsUserCerts == expected->fOnlyContainsUserCerts, + "Unexpected fOnlyContainsUserCerts\n"); + ok(got->fOnlyContainsCACerts == expected->fOnlyContainsCACerts, + "Unexpected fOnlyContainsCACerts\n"); + ok(got->OnlySomeReasonFlags.cbData == expected->OnlySomeReasonFlags.cbData, + "Unexpected reason flags\n"); + ok(got->fIndirectCRL == expected->fIndirectCRL, + "Unexpected fIndirectCRL\n"); +} + +static void test_decodeCRLIssuingDistPoint(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CRL_ISSUING_DIST_POINT point = { { 0 } }; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, + emptySequence, emptySequence[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no X509_ISSUING_DIST_POINT decode support\n"); + return; + } + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, + badFlagsIDP, badFlagsIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + point.fOnlyContainsUserCerts = point.fOnlyContainsCACerts = TRUE; + compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, + emptyNameIDP, emptyNameIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + point.fOnlyContainsCACerts = point.fOnlyContainsUserCerts = FALSE; + point.DistPointName.dwDistPointNameChoice = CRL_DIST_POINT_FULL_NAME; + U(point.DistPointName).FullName.cAltEntry = 0; + compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ISSUING_DIST_POINT, + urlIDP, urlIDP[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + CERT_ALT_NAME_ENTRY entry; + + entry.dwAltNameChoice = CERT_ALT_NAME_URL; + U(entry).pwszURL = (LPWSTR)url; + U(point.DistPointName).FullName.cAltEntry = 1; + U(point.DistPointName).FullName.rgAltEntry = &entry; + compareCRLIssuingDistPoints(&point, (PCRL_ISSUING_DIST_POINT)buf); + LocalFree(buf); + } +} + +static const BYTE v1CRL[] = { 0x30, 0x15, 0x30, 0x02, 0x06, 0x00, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a }; +static const BYTE v2CRL[] = { 0x30, 0x18, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x5a }; +static const BYTE v1CRLWithIssuer[] = { 0x30, 0x2c, 0x30, 0x02, 0x06, 0x00, + 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, + 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, 0x31, + 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x5a }; +static const BYTE v1CRLWithIssuerAndEmptyEntry[] = { 0x30, 0x43, 0x30, 0x02, + 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, + 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x00, 0x18, 0x0f, 0x31, 0x36, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a }; +static const BYTE v1CRLWithIssuerAndEntry[] = { 0x30, 0x44, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x16, 0x30, 0x14, 0x02, 0x01, 0x01, 0x18, 0x0f, 0x31, 0x36, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a }; +static const BYTE v1CRLWithEntryExt[] = { 0x30,0x5a,0x30,0x02,0x06,0x00,0x30, + 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, + 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, + 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x2c,0x30,0x2a,0x02,0x01, + 0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30, + 0x30,0x30,0x5a,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff, + 0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static const BYTE v1CRLWithExt[] = { 0x30,0x5c,0x30,0x02,0x06,0x00,0x30,0x15, + 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, + 0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, + 0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14,0x02,0x01,0x01, + 0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, + 0x30,0x5a,0xa0,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01, + 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static const BYTE v2CRLWithExt[] = { 0x30,0x5c,0x02,0x01,0x01,0x30,0x02,0x06, + 0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a, + 0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31, + 0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x16,0x30,0x14, + 0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30, + 0x30,0x30,0x30,0x30,0x5a,0xa0,0x13,0x30,0x11,0x30,0x0f,0x06,0x03,0x55,0x1d, + 0x13,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; + +static void test_encodeCRLToBeSigned(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CRL_INFO info = { 0 }; + CRL_ENTRY entry = { { 0 }, { 0 }, 0, 0 }; + + /* Test with a V1 CRL */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v1CRL), "Wrong size %d\n", size); + ok(!memcmp(buf, v1CRL, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* Test v2 CRL */ + info.dwVersion = CRL_V2; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == v2CRL[1] + 2, "Expected size %d, got %d\n", + v2CRL[1] + 2, size); + ok(!memcmp(buf, v2CRL, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* v1 CRL with a name */ + info.dwVersion = CRL_V1; + info.Issuer.cbData = sizeof(encodedCommonName); + info.Issuer.pbData = (BYTE *)encodedCommonName; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v1CRLWithIssuer), "Wrong size %d\n", size); + ok(!memcmp(buf, v1CRLWithIssuer, size), "Got unexpected value\n"); + LocalFree(buf); + } + if (0) + { + /* v1 CRL with a name and a NULL entry pointer (crashes on win9x) */ + info.cCRLEntry = 1; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + } + /* now set an empty entry */ + info.cCRLEntry = 1; + info.rgCRLEntry = &entry; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(v1CRLWithIssuerAndEmptyEntry), + "Wrong size %d\n", size); + ok(!memcmp(buf, v1CRLWithIssuerAndEmptyEntry, size), + "Got unexpected value\n"); + LocalFree(buf); + } + /* an entry with a serial number */ + entry.SerialNumber.cbData = sizeof(serialNum); + entry.SerialNumber.pbData = (BYTE *)serialNum; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(v1CRLWithIssuerAndEntry), + "Wrong size %d\n", size); + ok(!memcmp(buf, v1CRLWithIssuerAndEntry, size), + "Got unexpected value\n"); + LocalFree(buf); + } + /* an entry with an extension */ + entry.cExtension = 1; + entry.rgExtension = &criticalExt; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v1CRLWithEntryExt), "Wrong size %d\n", size); + ok(!memcmp(buf, v1CRLWithEntryExt, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* a CRL with an extension */ + entry.cExtension = 0; + info.cExtension = 1; + info.rgExtension = &criticalExt; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v1CRLWithExt), "Wrong size %d\n", size); + ok(!memcmp(buf, v1CRLWithExt, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* a v2 CRL with an extension, this time non-critical */ + info.dwVersion = CRL_V2; + info.rgExtension = &nonCriticalExt; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(v2CRLWithExt), "Wrong size %d\n", size); + ok(!memcmp(buf, v2CRLWithExt, size), "Got unexpected value\n"); + LocalFree(buf); + } +} + +static const BYTE verisignCRL[] = { 0x30, 0x82, 0x01, 0xb1, 0x30, 0x82, 0x01, + 0x1a, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x30, 0x61, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, + 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x56, 0x65, + 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, + 0x63, 0x69, 0x61, 0x6c, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, + 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x73, 0x20, 0x43, + 0x41, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x33, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x32, 0x33, + 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x30, 0x21, 0x02, 0x10, 0x1b, 0x51, + 0x90, 0xf7, 0x37, 0x24, 0x39, 0x9c, 0x92, 0x54, 0xcd, 0x42, 0x46, 0x37, 0x99, + 0x6a, 0x17, 0x0d, 0x30, 0x31, 0x30, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x31, + 0x32, 0x34, 0x5a, 0x30, 0x21, 0x02, 0x10, 0x75, 0x0e, 0x40, 0xff, 0x97, 0xf0, + 0x47, 0xed, 0xf5, 0x56, 0xc7, 0x08, 0x4e, 0xb1, 0xab, 0xfd, 0x17, 0x0d, 0x30, + 0x31, 0x30, 0x31, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x34, 0x39, 0x5a, 0x30, + 0x21, 0x02, 0x10, 0x77, 0xe6, 0x5a, 0x43, 0x59, 0x93, 0x5d, 0x5f, 0x7a, 0x75, + 0x80, 0x1a, 0xcd, 0xad, 0xc2, 0x22, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x38, 0x33, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x35, 0x36, 0x5a, 0xa0, 0x1a, 0x30, 0x18, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0x18, 0x2c, 0xe8, 0xfc, 0x16, 0x6d, 0x91, 0x4a, 0x3d, 0x88, + 0x54, 0x48, 0x5d, 0xb8, 0x11, 0xbf, 0x64, 0xbb, 0xf9, 0xda, 0x59, 0x19, 0xdd, + 0x0e, 0x65, 0xab, 0xc0, 0x0c, 0xfa, 0x67, 0x7e, 0x21, 0x1e, 0x83, 0x0e, 0xcf, + 0x9b, 0x89, 0x8a, 0xcf, 0x0c, 0x4b, 0xc1, 0x39, 0x9d, 0xe7, 0x6a, 0xac, 0x46, + 0x74, 0x6a, 0x91, 0x62, 0x22, 0x0d, 0xc4, 0x08, 0xbd, 0xf5, 0x0a, 0x90, 0x7f, + 0x06, 0x21, 0x3d, 0x7e, 0xa7, 0xaa, 0x5e, 0xcd, 0x22, 0x15, 0xe6, 0x0c, 0x75, + 0x8e, 0x6e, 0xad, 0xf1, 0x84, 0xe4, 0x22, 0xb4, 0x30, 0x6f, 0xfb, 0x64, 0x8f, + 0xd7, 0x80, 0x43, 0xf5, 0x19, 0x18, 0x66, 0x1d, 0x72, 0xa3, 0xe3, 0x94, 0x82, + 0x28, 0x52, 0xa0, 0x06, 0x4e, 0xb1, 0xc8, 0x92, 0x0c, 0x97, 0xbe, 0x15, 0x07, + 0xab, 0x7a, 0xc9, 0xea, 0x08, 0x67, 0x43, 0x4d, 0x51, 0x63, 0x3b, 0x9c, 0x9c, + 0xcd }; +static const BYTE verisignCRLWithLotsOfEntries[] = { +0x30,0x82,0x1d,0xbd,0x30,0x82,0x1d,0x26,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x04,0x05,0x00,0x30,0x61,0x31,0x11,0x30,0x0f,0x06, +0x03,0x55,0x04,0x07,0x13,0x08,0x49,0x6e,0x74,0x65,0x72,0x6e,0x65,0x74,0x31, +0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53, +0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x33,0x30,0x31,0x06,0x03, +0x55,0x04,0x0b,0x13,0x2a,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x43, +0x6f,0x6d,0x6d,0x65,0x72,0x63,0x69,0x61,0x6c,0x20,0x53,0x6f,0x66,0x74,0x77, +0x61,0x72,0x65,0x20,0x50,0x75,0x62,0x6c,0x69,0x73,0x68,0x65,0x72,0x73,0x20, +0x43,0x41,0x17,0x0d,0x30,0x34,0x30,0x33,0x33,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x17,0x0d,0x30,0x34,0x30,0x35,0x33,0x31,0x32,0x33,0x35,0x39,0x35, +0x39,0x5a,0x30,0x82,0x1c,0x92,0x30,0x21,0x02,0x10,0x01,0x22,0xb8,0xb2,0xf3, +0x76,0x42,0xcc,0x48,0x71,0xb6,0x11,0xbf,0xd1,0xcf,0xda,0x17,0x0d,0x30,0x32, +0x30,0x34,0x31,0x35,0x31,0x35,0x34,0x30,0x32,0x34,0x5a,0x30,0x21,0x02,0x10, +0x01,0x83,0x93,0xfb,0x96,0xde,0x1d,0x89,0x4e,0xc3,0x47,0x9c,0xe1,0x60,0x13, +0x63,0x17,0x0d,0x30,0x32,0x30,0x35,0x30,0x39,0x31,0x33,0x35,0x37,0x35,0x38, +0x5a,0x30,0x21,0x02,0x10,0x01,0xdc,0xdb,0x63,0xd4,0xc9,0x9f,0x31,0xb8,0x16, +0xf9,0x2c,0xf5,0xb1,0x08,0x8e,0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x38,0x31, +0x37,0x34,0x36,0x31,0x34,0x5a,0x30,0x21,0x02,0x10,0x02,0x1a,0xa6,0xaf,0x94, +0x71,0xf0,0x07,0x6e,0xf1,0x17,0xe4,0xd4,0x17,0x82,0xdb,0x17,0x0d,0x30,0x32, +0x30,0x37,0x31,0x39,0x32,0x31,0x32,0x38,0x33,0x31,0x5a,0x30,0x21,0x02,0x10, +0x02,0x4c,0xe8,0x9d,0xfd,0x5f,0x77,0x4d,0x4b,0xf5,0x79,0x8b,0xb1,0x08,0x67, +0xac,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x32,0x30,0x36,0x31,0x36,0x35,0x30, +0x5a,0x30,0x21,0x02,0x10,0x02,0x59,0xae,0x6c,0x4c,0x21,0xf1,0x59,0x49,0x87, +0xb0,0x95,0xf9,0x65,0xf3,0x20,0x17,0x0d,0x30,0x33,0x30,0x36,0x31,0x39,0x30, +0x38,0x30,0x34,0x34,0x37,0x5a,0x30,0x21,0x02,0x10,0x03,0x3c,0x41,0x0e,0x2f, +0x42,0x5c,0x32,0x2c,0xb1,0x35,0xfe,0xe7,0x61,0x97,0xa5,0x17,0x0d,0x30,0x32, +0x30,0x34,0x32,0x34,0x31,0x39,0x34,0x37,0x30,0x32,0x5a,0x30,0x21,0x02,0x10, +0x03,0x4e,0x68,0xfa,0x8b,0xb2,0x8e,0xb9,0x72,0xea,0x72,0xe5,0x3b,0x15,0xac, +0x8b,0x17,0x0d,0x30,0x32,0x30,0x39,0x32,0x36,0x32,0x31,0x35,0x31,0x35,0x31, +0x5a,0x30,0x21,0x02,0x10,0x03,0xc9,0xa8,0xe3,0x48,0xb0,0x5f,0xcf,0x08,0xee, +0xb9,0x93,0xf9,0xe9,0xaf,0x0c,0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x38,0x31, +0x33,0x34,0x39,0x32,0x32,0x5a,0x30,0x21,0x02,0x10,0x04,0x9b,0x23,0x6a,0x37, +0x5c,0x06,0x98,0x0a,0x31,0xc8,0x86,0xdc,0x3a,0x95,0xcc,0x17,0x0d,0x30,0x32, +0x31,0x30,0x30,0x31,0x32,0x32,0x31,0x30,0x35,0x36,0x5a,0x30,0x21,0x02,0x10, +0x06,0x08,0xba,0xc7,0xac,0xf8,0x5a,0x7c,0xa1,0xf4,0x25,0x85,0xbb,0x4e,0x8c, +0x4f,0x17,0x0d,0x30,0x33,0x30,0x31,0x30,0x33,0x30,0x37,0x35,0x37,0x31,0x34, +0x5a,0x30,0x21,0x02,0x10,0x07,0x66,0x22,0x4a,0x4a,0x9d,0xff,0x6e,0xb5,0x11, +0x0b,0xa9,0x94,0xfc,0x68,0x20,0x17,0x0d,0x30,0x32,0x30,0x38,0x32,0x32,0x30, +0x31,0x34,0x30,0x31,0x32,0x5a,0x30,0x21,0x02,0x10,0x07,0x8f,0xa1,0x4d,0xb5, +0xfc,0x0c,0xc6,0x42,0x72,0x88,0x37,0x76,0x29,0x44,0x31,0x17,0x0d,0x30,0x32, +0x30,0x33,0x31,0x35,0x32,0x30,0x31,0x39,0x34,0x39,0x5a,0x30,0x21,0x02,0x10, +0x07,0xb9,0xd9,0x42,0x19,0x81,0xc4,0xfd,0x49,0x4f,0x72,0xce,0xf2,0xf8,0x6d, +0x76,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x35,0x31,0x35,0x33,0x37,0x31,0x39, +0x5a,0x30,0x21,0x02,0x10,0x08,0x6e,0xf9,0x6c,0x7f,0xbf,0xbc,0xc8,0x86,0x70, +0x62,0x3f,0xe9,0xc4,0x2f,0x2b,0x17,0x0d,0x30,0x32,0x31,0x31,0x32,0x38,0x30, +0x30,0x32,0x38,0x31,0x34,0x5a,0x30,0x21,0x02,0x10,0x09,0x08,0xe4,0xaa,0xf5, +0x2d,0x2b,0xc0,0x15,0x9e,0x00,0x8b,0x3f,0x97,0x93,0xf9,0x17,0x0d,0x30,0x33, +0x30,0x32,0x31,0x32,0x32,0x32,0x30,0x30,0x32,0x33,0x5a,0x30,0x21,0x02,0x10, +0x09,0x13,0x0a,0x4f,0x0f,0x88,0xe5,0x50,0x05,0xc3,0x5f,0xf4,0xff,0x15,0x39, +0xdd,0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x36,0x30,0x38,0x31,0x31,0x33,0x30, +0x5a,0x30,0x21,0x02,0x10,0x09,0x8d,0xdd,0x37,0xda,0xe7,0x84,0x03,0x9d,0x98, +0x96,0xf8,0x88,0x3a,0x55,0xca,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x31,0x32, +0x33,0x33,0x35,0x32,0x36,0x5a,0x30,0x21,0x02,0x10,0x0a,0x35,0x0c,0xd7,0xf4, +0x53,0xe6,0xc1,0x4e,0xf2,0x2a,0xd3,0xce,0xf8,0x7c,0xe7,0x17,0x0d,0x30,0x32, +0x30,0x38,0x30,0x32,0x32,0x32,0x32,0x34,0x32,0x38,0x5a,0x30,0x21,0x02,0x10, +0x0b,0x9c,0xb8,0xf8,0xfb,0x35,0x38,0xf2,0x91,0xfd,0xa1,0xe9,0x69,0x4a,0xb1, +0x24,0x17,0x0d,0x30,0x33,0x30,0x34,0x30,0x38,0x30,0x31,0x30,0x32,0x32,0x32, +0x5a,0x30,0x21,0x02,0x10,0x0c,0x2f,0x7f,0x32,0x15,0xe0,0x2f,0x74,0xfa,0x05, +0x22,0x67,0xbc,0x8a,0x2d,0xd0,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x36,0x31, +0x39,0x30,0x37,0x35,0x34,0x5a,0x30,0x21,0x02,0x10,0x0c,0x32,0x5b,0x78,0x32, +0xc6,0x7c,0xd8,0xdd,0x25,0x91,0x22,0x4d,0x84,0x0a,0x94,0x17,0x0d,0x30,0x32, +0x30,0x33,0x31,0x38,0x31,0x32,0x33,0x39,0x30,0x33,0x5a,0x30,0x21,0x02,0x10, +0x0d,0x76,0x36,0xb9,0x1c,0x72,0xb7,0x9d,0xdf,0xa5,0x35,0x82,0xc5,0xa8,0xf7, +0xbb,0x17,0x0d,0x30,0x32,0x30,0x38,0x32,0x37,0x32,0x31,0x34,0x32,0x31,0x31, +0x5a,0x30,0x21,0x02,0x10,0x0f,0x28,0x79,0x98,0x56,0xb8,0xa5,0x5e,0xeb,0x79, +0x5f,0x1b,0xed,0x0b,0x86,0x76,0x17,0x0d,0x30,0x32,0x30,0x33,0x31,0x33,0x30, +0x31,0x31,0x30,0x34,0x37,0x5a,0x30,0x21,0x02,0x10,0x0f,0x80,0x3c,0x24,0xf4, +0x62,0x27,0x24,0xbe,0x6a,0x74,0x9c,0x18,0x8e,0x4b,0x3b,0x17,0x0d,0x30,0x32, +0x31,0x31,0x32,0x30,0x31,0x37,0x31,0x31,0x33,0x35,0x5a,0x30,0x21,0x02,0x10, +0x0f,0xf2,0xa7,0x8c,0x80,0x9c,0xbe,0x2f,0xc8,0xa9,0xeb,0xfe,0x94,0x86,0x5a, +0x5c,0x17,0x0d,0x30,0x32,0x30,0x36,0x32,0x30,0x31,0x39,0x35,0x38,0x34,0x35, +0x5a,0x30,0x21,0x02,0x10,0x10,0x45,0x13,0x35,0x45,0xf3,0xc6,0x02,0x8d,0x8d, +0x18,0xb1,0xc4,0x0a,0x7a,0x18,0x17,0x0d,0x30,0x32,0x30,0x34,0x32,0x36,0x31, +0x37,0x33,0x32,0x35,0x39,0x5a,0x30,0x21,0x02,0x10,0x10,0x79,0xb1,0x71,0x1b, +0x26,0x98,0x92,0x08,0x1e,0x3c,0xe4,0x8b,0x29,0x37,0xf9,0x17,0x0d,0x30,0x32, +0x30,0x33,0x32,0x38,0x31,0x36,0x33,0x32,0x35,0x35,0x5a,0x30,0x21,0x02,0x10, +0x11,0x38,0x80,0x77,0xcb,0x6b,0xe5,0xd6,0xa7,0xf2,0x99,0xa1,0xc8,0xe9,0x40, +0x25,0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x39,0x31,0x32,0x32,0x34,0x31,0x37, +0x5a,0x30,0x21,0x02,0x10,0x11,0x7a,0xc3,0x82,0xfe,0x74,0x36,0x11,0x21,0xd6, +0x92,0x86,0x09,0xdf,0xe6,0xf3,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x39,0x31, +0x35,0x31,0x31,0x33,0x36,0x5a,0x30,0x21,0x02,0x10,0x11,0xab,0x8e,0x21,0x28, +0x7f,0x6d,0xf2,0xc1,0xc8,0x40,0x3e,0xa5,0xde,0x98,0xd3,0x17,0x0d,0x30,0x32, +0x30,0x35,0x30,0x32,0x31,0x38,0x34,0x34,0x33,0x31,0x5a,0x30,0x21,0x02,0x10, +0x12,0x3c,0x38,0xae,0x3f,0x64,0x53,0x3a,0xf7,0xbc,0x6c,0x27,0xe2,0x9c,0x65, +0x75,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x33,0x32,0x33,0x30,0x38,0x35,0x39, +0x5a,0x30,0x21,0x02,0x10,0x12,0x88,0xb6,0x6c,0x9b,0xcf,0xe7,0x50,0x92,0xd2, +0x87,0x63,0x8f,0xb7,0xa6,0xe3,0x17,0x0d,0x30,0x32,0x30,0x37,0x30,0x32,0x32, +0x30,0x35,0x35,0x30,0x33,0x5a,0x30,0x21,0x02,0x10,0x12,0x95,0x4e,0xb6,0x8f, +0x3a,0x19,0x6a,0x16,0x73,0x4f,0x6e,0x15,0xba,0xa5,0xe7,0x17,0x0d,0x30,0x32, +0x30,0x36,0x31,0x37,0x31,0x38,0x35,0x36,0x30,0x31,0x5a,0x30,0x21,0x02,0x10, +0x13,0x37,0x0b,0x41,0x8c,0x31,0x43,0x1c,0x27,0xaa,0xe1,0x83,0x0f,0x99,0x21, +0xcd,0x17,0x0d,0x30,0x32,0x30,0x37,0x32,0x32,0x31,0x32,0x31,0x37,0x31,0x36, +0x5a,0x30,0x21,0x02,0x10,0x14,0x7a,0x29,0x0a,0x09,0x38,0xf4,0x53,0x28,0x33, +0x6f,0x37,0x07,0x23,0x12,0x10,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x32,0x30, +0x32,0x30,0x30,0x31,0x34,0x5a,0x30,0x21,0x02,0x10,0x15,0x04,0x81,0x1e,0xe2, +0x6f,0xf0,0xd8,0xdd,0x12,0x55,0x05,0x66,0x51,0x6e,0x1a,0x17,0x0d,0x30,0x32, +0x30,0x33,0x31,0x33,0x31,0x30,0x35,0x33,0x30,0x38,0x5a,0x30,0x21,0x02,0x10, +0x15,0x30,0x0d,0x8a,0xbd,0x0e,0x89,0x0e,0x66,0x4f,0x49,0x93,0xa2,0x8f,0xbc, +0x2e,0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x34,0x30,0x36,0x34,0x32,0x32,0x33, +0x5a,0x30,0x21,0x02,0x10,0x16,0xbe,0x64,0xd6,0x4f,0x90,0xf4,0xf7,0x2b,0xc8, +0xca,0x67,0x5c,0x82,0x13,0xe8,0x17,0x0d,0x30,0x32,0x30,0x36,0x30,0x36,0x31, +0x39,0x30,0x39,0x30,0x37,0x5a,0x30,0x21,0x02,0x10,0x18,0x51,0x9c,0xe4,0x48, +0x62,0x06,0xfe,0xb8,0x2d,0x93,0xb7,0xc9,0xc9,0x1b,0x4e,0x17,0x0d,0x30,0x32, +0x30,0x34,0x31,0x37,0x30,0x35,0x30,0x30,0x34,0x34,0x5a,0x30,0x21,0x02,0x10, +0x19,0x82,0xdb,0x39,0x74,0x00,0x38,0x36,0x59,0xf6,0xcc,0xc1,0x23,0x8d,0x40, +0xe9,0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x36,0x30,0x37,0x35,0x34,0x35,0x34, +0x5a,0x30,0x21,0x02,0x10,0x1b,0x51,0x90,0xf7,0x37,0x24,0x39,0x9c,0x92,0x54, +0xcd,0x42,0x46,0x37,0x99,0x6a,0x17,0x0d,0x30,0x31,0x30,0x31,0x33,0x30,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x21,0x02,0x10,0x1b,0xe4,0xb2,0xbb,0xb6, +0x74,0x5d,0x6b,0x8b,0x04,0xb6,0xa0,0x1b,0x35,0xeb,0x29,0x17,0x0d,0x30,0x32, +0x30,0x39,0x32,0x35,0x32,0x30,0x31,0x34,0x35,0x36,0x5a,0x30,0x21,0x02,0x10, +0x1c,0x1d,0xd5,0x2a,0xf6,0xaa,0xfd,0xbb,0x47,0xc2,0x73,0x36,0xcf,0x53,0xbd, +0x81,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x33,0x31,0x39,0x30,0x33,0x34,0x32, +0x5a,0x30,0x21,0x02,0x10,0x1c,0xb0,0x5a,0x1f,0xfd,0xa6,0x98,0xf6,0x46,0xf9, +0x32,0x10,0x9e,0xef,0x52,0x8e,0x17,0x0d,0x30,0x32,0x30,0x36,0x32,0x37,0x31, +0x33,0x30,0x33,0x32,0x32,0x5a,0x30,0x21,0x02,0x10,0x1d,0x01,0xfc,0xa7,0xdd, +0xb4,0x0c,0x64,0xbd,0x65,0x45,0xe6,0xbf,0x1c,0x7e,0x90,0x17,0x0d,0x30,0x32, +0x30,0x32,0x32,0x31,0x30,0x34,0x32,0x30,0x30,0x36,0x5a,0x30,0x21,0x02,0x10, +0x1e,0x4d,0xc9,0xc6,0x6e,0x57,0xda,0x8a,0x07,0x97,0x70,0xfa,0xee,0x9c,0xc5, +0x58,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x39,0x32,0x32,0x33,0x34,0x32,0x31, +0x5a,0x30,0x21,0x02,0x10,0x1e,0xbb,0x9b,0x28,0x61,0x50,0x7f,0x12,0x30,0xfb, +0x02,0xb5,0xe1,0xb0,0x7e,0x9d,0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x36,0x30, +0x30,0x30,0x34,0x32,0x30,0x5a,0x30,0x21,0x02,0x10,0x1f,0x5a,0x64,0xc9,0xa5, +0x51,0x8c,0xe2,0x2d,0x50,0x83,0xc2,0x4c,0x7c,0xe7,0x85,0x17,0x0d,0x30,0x32, +0x30,0x38,0x32,0x34,0x30,0x36,0x33,0x31,0x32,0x38,0x5a,0x30,0x21,0x02,0x10, +0x1f,0xc2,0x4e,0xd0,0xac,0x52,0xd3,0x39,0x18,0x6d,0xd0,0x0f,0x23,0xd7,0x45, +0x72,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x38,0x31,0x39,0x31,0x35,0x34,0x32, +0x5a,0x30,0x20,0x02,0x0f,0x24,0x60,0x7a,0x8e,0x0e,0x86,0xa4,0x88,0x68,0xaf, +0xd9,0x0c,0x6b,0xba,0xff,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x38,0x30,0x35, +0x31,0x38,0x32,0x34,0x5a,0x30,0x21,0x02,0x10,0x20,0x41,0x73,0xbb,0x72,0x88, +0x6e,0x4b,0x1c,0xb6,0x70,0x02,0x67,0xaa,0x3b,0x3d,0x17,0x0d,0x30,0x32,0x30, +0x39,0x30,0x33,0x31,0x37,0x30,0x36,0x32,0x31,0x5a,0x30,0x21,0x02,0x10,0x20, +0x6e,0x0d,0xdc,0x8c,0xa4,0xac,0xf7,0x08,0x77,0x5c,0x80,0xf9,0xa3,0x68,0x92, +0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x30,0x32,0x30,0x35,0x37,0x31,0x36,0x5a, +0x30,0x21,0x02,0x10,0x21,0xe4,0x6b,0x98,0x47,0x91,0xe6,0x02,0xdf,0xb2,0x45, +0xbc,0x31,0x37,0xa0,0x7c,0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x38,0x32,0x33, +0x32,0x33,0x31,0x33,0x5a,0x30,0x21,0x02,0x10,0x22,0x00,0x95,0x70,0x79,0xf9, +0x9c,0x34,0x91,0xbb,0x84,0xb9,0x91,0xde,0x22,0x55,0x17,0x0d,0x30,0x32,0x30, +0x32,0x31,0x33,0x30,0x36,0x35,0x39,0x33,0x39,0x5a,0x30,0x21,0x02,0x10,0x22, +0xf9,0x67,0x4f,0xcd,0x29,0xc6,0xdc,0xc8,0x22,0x6e,0xe9,0x0a,0xa1,0x48,0x5a, +0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x33,0x30,0x30,0x34,0x33,0x32,0x36,0x5a, +0x30,0x21,0x02,0x10,0x24,0xa3,0xa7,0xd0,0xb8,0x1d,0x1c,0xf7,0xe6,0x1f,0x6e, +0xba,0xc9,0x98,0x59,0xed,0x17,0x0d,0x30,0x33,0x30,0x37,0x32,0x34,0x32,0x30, +0x35,0x38,0x30,0x32,0x5a,0x30,0x21,0x02,0x10,0x24,0xef,0x89,0xa1,0x30,0x4f, +0x51,0x63,0xfe,0xdb,0xdb,0x64,0x6e,0x4c,0x5a,0x81,0x17,0x0d,0x30,0x32,0x30, +0x37,0x30,0x33,0x30,0x39,0x32,0x31,0x31,0x37,0x5a,0x30,0x21,0x02,0x10,0x25, +0x08,0xe5,0xac,0xdd,0x6f,0x74,0x44,0x51,0x1a,0xf5,0xdb,0xf8,0xba,0x25,0xe0, +0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x39,0x30,0x34,0x31,0x36,0x32,0x32,0x5a, +0x30,0x21,0x02,0x10,0x25,0x81,0xe8,0x18,0x60,0x88,0xbc,0x1a,0xe9,0x14,0x84, +0xed,0xd4,0x62,0xf5,0x47,0x17,0x0d,0x30,0x32,0x30,0x38,0x32,0x33,0x30,0x31, +0x35,0x37,0x31,0x39,0x5a,0x30,0x21,0x02,0x10,0x26,0xe5,0x5c,0xab,0x16,0xec, +0x61,0x38,0x49,0x2c,0xd2,0xb1,0x48,0x89,0xd5,0x47,0x17,0x0d,0x30,0x32,0x30, +0x33,0x31,0x33,0x31,0x38,0x30,0x30,0x33,0x38,0x5a,0x30,0x21,0x02,0x10,0x27, +0xbe,0xda,0x7f,0x4f,0x1f,0x6c,0x76,0x09,0xc0,0x9a,0xaf,0xd4,0x68,0xe2,0x16, +0x17,0x0d,0x30,0x32,0x30,0x35,0x31,0x30,0x31,0x38,0x33,0x32,0x33,0x30,0x5a, +0x30,0x21,0x02,0x10,0x28,0x89,0xd0,0xb3,0xb5,0xc4,0x56,0x36,0x9b,0x3e,0x81, +0x1a,0x21,0x56,0xaa,0x42,0x17,0x0d,0x30,0x32,0x31,0x31,0x30,0x34,0x31,0x31, +0x30,0x33,0x30,0x38,0x5a,0x30,0x21,0x02,0x10,0x28,0xab,0x93,0x06,0xb1,0x1e, +0x05,0xe0,0xe1,0x25,0x75,0xc7,0x74,0xcb,0x55,0xa6,0x17,0x0d,0x30,0x33,0x30, +0x31,0x32,0x34,0x31,0x39,0x34,0x38,0x32,0x33,0x5a,0x30,0x21,0x02,0x10,0x29, +0xe9,0x3b,0x44,0x8d,0xc3,0x4b,0x80,0x17,0xda,0xe4,0x1c,0x43,0x96,0x83,0x59, +0x17,0x0d,0x30,0x32,0x30,0x36,0x30,0x37,0x32,0x31,0x34,0x33,0x33,0x39,0x5a, +0x30,0x21,0x02,0x10,0x2a,0x08,0x64,0x2b,0x48,0xe2,0x17,0x89,0x6a,0x0c,0xf9, +0x7e,0x10,0x66,0x8f,0xe7,0x17,0x0d,0x30,0x32,0x30,0x38,0x31,0x39,0x31,0x38, +0x33,0x35,0x32,0x39,0x5a,0x30,0x21,0x02,0x10,0x2a,0x44,0xee,0x91,0x5d,0xe3, +0xa5,0x2b,0x09,0xf3,0x56,0x59,0xe0,0x8f,0x25,0x22,0x17,0x0d,0x30,0x32,0x30, +0x32,0x32,0x31,0x31,0x39,0x33,0x31,0x32,0x34,0x5a,0x30,0x21,0x02,0x10,0x2a, +0x8b,0x4e,0xa5,0xb6,0x06,0xc8,0x48,0x3b,0x0e,0x71,0x1e,0x6b,0xf4,0x16,0xc1, +0x17,0x0d,0x30,0x32,0x30,0x34,0x33,0x30,0x30,0x39,0x32,0x31,0x31,0x38,0x5a, +0x30,0x21,0x02,0x10,0x2b,0x03,0xfc,0x2f,0xc2,0x8e,0x38,0x29,0x6f,0xa1,0x0f, +0xe9,0x47,0x1b,0x35,0xd7,0x17,0x0d,0x30,0x32,0x31,0x31,0x31,0x34,0x32,0x30, +0x31,0x38,0x33,0x33,0x5a,0x30,0x21,0x02,0x10,0x2c,0x48,0xf7,0xd6,0xd5,0x71, +0xc0,0xd1,0xbd,0x6a,0x00,0x65,0x1d,0x2d,0xa9,0xdd,0x17,0x0d,0x30,0x32,0x30, +0x33,0x30,0x36,0x31,0x37,0x32,0x30,0x34,0x33,0x5a,0x30,0x21,0x02,0x10,0x2c, +0xbf,0x84,0x1d,0xe4,0x58,0x32,0x79,0x32,0x10,0x37,0xde,0xd7,0x94,0xff,0x85, +0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x32,0x31,0x39,0x30,0x32,0x32,0x35,0x5a, +0x30,0x21,0x02,0x10,0x2d,0x03,0x54,0x35,0x54,0x45,0x2c,0x6d,0x39,0xf0,0x1b, +0x74,0x68,0xde,0xcf,0x93,0x17,0x0d,0x30,0x32,0x30,0x39,0x32,0x33,0x31,0x33, +0x32,0x33,0x33,0x37,0x5a,0x30,0x21,0x02,0x10,0x2d,0x24,0x94,0x34,0x19,0x92, +0xb1,0xf2,0x37,0x9d,0x6e,0xc5,0x35,0x93,0xdd,0xf0,0x17,0x0d,0x30,0x32,0x30, +0x33,0x31,0x35,0x31,0x37,0x31,0x37,0x32,0x37,0x5a,0x30,0x21,0x02,0x10,0x2d, +0x47,0x24,0x61,0x87,0x91,0xba,0x2e,0xf2,0xf7,0x92,0x21,0xf3,0x1b,0x8b,0x1e, +0x17,0x0d,0x30,0x32,0x30,0x35,0x31,0x34,0x32,0x33,0x30,0x38,0x32,0x32,0x5a, +0x30,0x21,0x02,0x10,0x2d,0x84,0xc2,0xb1,0x01,0xa1,0x3a,0x6f,0xb0,0x30,0x13, +0x76,0x5a,0x69,0xec,0x41,0x17,0x0d,0x30,0x32,0x30,0x37,0x31,0x35,0x31,0x37, +0x32,0x39,0x32,0x33,0x5a,0x30,0x21,0x02,0x10,0x2d,0xd5,0x26,0xc3,0xcd,0x01, +0xce,0xfd,0x67,0xb8,0x08,0xac,0x5a,0x70,0xc4,0x34,0x17,0x0d,0x30,0x32,0x30, +0x32,0x32,0x37,0x30,0x34,0x34,0x36,0x31,0x34,0x5a,0x30,0x21,0x02,0x10,0x2e, +0x2b,0x0a,0x94,0x4d,0xf1,0xa4,0x37,0xb7,0xa3,0x9b,0x4b,0x96,0x26,0xa8,0xe3, +0x17,0x0d,0x30,0x33,0x30,0x31,0x30,0x39,0x30,0x36,0x32,0x38,0x32,0x38,0x5a, +0x30,0x21,0x02,0x10,0x2e,0x31,0x30,0xc1,0x2e,0x16,0x31,0xd9,0x2b,0x0a,0x70, +0xca,0x3f,0x31,0x73,0x62,0x17,0x0d,0x30,0x33,0x30,0x31,0x32,0x39,0x30,0x31, +0x34,0x39,0x32,0x37,0x5a,0x30,0x21,0x02,0x10,0x2e,0xbd,0x6d,0xdf,0xce,0x20, +0x6f,0xe7,0xa8,0xf4,0xf3,0x25,0x9c,0xc3,0xc1,0x12,0x17,0x0d,0x30,0x32,0x30, +0x39,0x32,0x30,0x31,0x33,0x35,0x34,0x34,0x32,0x5a,0x30,0x21,0x02,0x10,0x2f, +0x56,0x16,0x22,0xba,0x87,0xd5,0xfd,0xff,0xe6,0xb0,0xdd,0x3c,0x08,0x26,0x2c, +0x17,0x0d,0x30,0x32,0x30,0x33,0x31,0x33,0x31,0x37,0x35,0x33,0x31,0x31,0x5a, +0x30,0x21,0x02,0x10,0x30,0x3e,0x77,0x7b,0xec,0xcb,0x89,0x2c,0x15,0x55,0x7f, +0x20,0xf2,0x33,0xc1,0x1e,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x31,0x32,0x33, +0x35,0x30,0x34,0x39,0x5a,0x30,0x21,0x02,0x10,0x30,0x59,0x6c,0xaa,0x5f,0xd3, +0xac,0x50,0x86,0x2c,0xc4,0xfa,0x3c,0x48,0x50,0xd1,0x17,0x0d,0x30,0x32,0x30, +0x32,0x32,0x31,0x30,0x34,0x31,0x39,0x33,0x35,0x5a,0x30,0x21,0x02,0x10,0x30, +0xce,0x9a,0xf1,0xfa,0x17,0xfa,0xf5,0x4c,0xbc,0x52,0x8a,0xf4,0x26,0x2b,0x7b, +0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x31,0x31,0x39,0x31,0x32,0x33,0x39,0x5a, +0x30,0x21,0x02,0x10,0x31,0x16,0x4a,0x6a,0x2e,0x6d,0x34,0x4d,0xd2,0x40,0xf0, +0x5f,0x47,0xe6,0x5b,0x47,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x32,0x31,0x37, +0x33,0x38,0x35,0x32,0x5a,0x30,0x21,0x02,0x10,0x31,0xdb,0x97,0x5b,0x06,0x63, +0x0b,0xd8,0xfe,0x06,0xb3,0xf5,0xf9,0x64,0x0a,0x59,0x17,0x0d,0x30,0x32,0x30, +0x32,0x31,0x32,0x31,0x35,0x35,0x39,0x32,0x33,0x5a,0x30,0x21,0x02,0x10,0x32, +0xbc,0xeb,0x0c,0xca,0x65,0x06,0x3f,0xa4,0xd5,0x4a,0x56,0x46,0x7c,0x22,0x09, +0x17,0x0d,0x30,0x32,0x30,0x38,0x31,0x36,0x30,0x37,0x33,0x33,0x35,0x35,0x5a, +0x30,0x21,0x02,0x10,0x33,0x17,0xef,0xe1,0x89,0xec,0x11,0x25,0x15,0x8f,0x3b, +0x67,0x7a,0x64,0x0b,0x50,0x17,0x0d,0x30,0x32,0x30,0x39,0x31,0x38,0x31,0x37, +0x30,0x33,0x34,0x36,0x5a,0x30,0x21,0x02,0x10,0x34,0x24,0xa0,0xd2,0x00,0x61, +0xeb,0xd3,0x9a,0xa7,0x2a,0x66,0xb4,0x82,0x23,0x77,0x17,0x0d,0x30,0x32,0x30, +0x33,0x31,0x35,0x32,0x32,0x34,0x33,0x33,0x39,0x5a,0x30,0x21,0x02,0x10,0x34, +0xa8,0x16,0x67,0xa5,0x1b,0xa3,0x31,0x11,0x5e,0x26,0xc8,0x3f,0x21,0x38,0xbe, +0x17,0x0d,0x30,0x32,0x30,0x33,0x32,0x31,0x32,0x31,0x31,0x36,0x32,0x31,0x5a, +0x30,0x21,0x02,0x10,0x36,0x3a,0xbe,0x05,0x55,0x52,0x93,0x4f,0x32,0x5f,0x30, +0x63,0xc0,0xd4,0x50,0xdf,0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x38,0x31,0x31, +0x34,0x36,0x31,0x34,0x5a,0x30,0x21,0x02,0x10,0x37,0x19,0xcc,0xa5,0x9d,0x85, +0x05,0x56,0xe1,0x63,0x42,0x4b,0x0d,0x3c,0xbf,0xd6,0x17,0x0d,0x30,0x33,0x30, +0x31,0x30,0x38,0x31,0x38,0x35,0x38,0x32,0x34,0x5a,0x30,0x21,0x02,0x10,0x37, +0x2f,0xfd,0x2b,0xec,0x4d,0x94,0x35,0x51,0xf4,0x07,0x2a,0xf5,0x0b,0x97,0xc4, +0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x33,0x31,0x39,0x31,0x38,0x30,0x31,0x5a, +0x30,0x21,0x02,0x10,0x37,0x83,0xf5,0x1e,0x7e,0xf4,0x5f,0xad,0x1f,0x0c,0x55, +0x86,0x30,0x02,0x54,0xc1,0x17,0x0d,0x30,0x33,0x30,0x31,0x30,0x38,0x32,0x30, +0x30,0x33,0x34,0x34,0x5a,0x30,0x21,0x02,0x10,0x38,0x32,0x3e,0x50,0x2b,0x36, +0x93,0x01,0x32,0x0a,0x59,0x8c,0xce,0xad,0xa0,0xeb,0x17,0x0d,0x30,0x32,0x30, +0x34,0x33,0x30,0x32,0x31,0x32,0x34,0x30,0x38,0x5a,0x30,0x21,0x02,0x10,0x3a, +0x62,0xd8,0x64,0xd3,0x85,0xd5,0x61,0x1d,0x9d,0x3f,0x61,0x25,0xe9,0x3a,0x1d, +0x17,0x0d,0x30,0x32,0x30,0x36,0x31,0x37,0x31,0x35,0x31,0x39,0x31,0x36,0x5a, +0x30,0x21,0x02,0x10,0x3a,0x97,0x36,0xb1,0x26,0x14,0x73,0x50,0xa3,0xcc,0x3f, +0xd0,0x3b,0x83,0x99,0xc9,0x17,0x0d,0x30,0x32,0x30,0x39,0x31,0x31,0x30,0x33, +0x32,0x39,0x33,0x30,0x5a,0x30,0x21,0x02,0x10,0x3b,0x87,0x3e,0x20,0xbe,0x97, +0xff,0xa7,0x6b,0x2b,0x5f,0xff,0x9a,0x7f,0x4c,0x95,0x17,0x0d,0x30,0x32,0x30, +0x37,0x30,0x33,0x30,0x30,0x33,0x31,0x34,0x37,0x5a,0x30,0x21,0x02,0x10,0x3b, +0xba,0xe5,0xf2,0x23,0x99,0xc6,0xd7,0xae,0xe2,0x98,0x0d,0xa4,0x13,0x5c,0xd4, +0x17,0x0d,0x30,0x32,0x30,0x35,0x32,0x34,0x31,0x39,0x32,0x38,0x34,0x35,0x5a, +0x30,0x21,0x02,0x10,0x3b,0xc2,0x7c,0xf0,0xbd,0xd2,0x9a,0x6f,0x97,0xdd,0x76, +0xbc,0xa9,0x6c,0x45,0x0d,0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x38,0x31,0x30, +0x34,0x32,0x30,0x33,0x5a,0x30,0x21,0x02,0x10,0x3b,0xc5,0xda,0x41,0x64,0x7a, +0x37,0x8e,0x9f,0x7f,0x1f,0x9b,0x25,0x0a,0xb4,0xda,0x17,0x0d,0x30,0x32,0x30, +0x33,0x30,0x36,0x31,0x33,0x32,0x34,0x34,0x38,0x5a,0x30,0x21,0x02,0x10,0x3c, +0x1b,0xf1,0x9a,0x48,0xb0,0xb8,0xa0,0x45,0xd5,0x8f,0x0f,0x57,0x90,0xc2,0xcd, +0x17,0x0d,0x30,0x32,0x30,0x33,0x31,0x38,0x30,0x36,0x34,0x33,0x32,0x33,0x5a, +0x30,0x21,0x02,0x10,0x3d,0x15,0x48,0x80,0xb4,0xfe,0x51,0x7e,0xed,0x46,0xae, +0x51,0xfd,0x47,0x73,0xde,0x17,0x0d,0x30,0x32,0x30,0x38,0x32,0x37,0x30,0x39, +0x32,0x30,0x30,0x38,0x5a,0x30,0x21,0x02,0x10,0x3d,0x61,0x4e,0x87,0xea,0x39, +0x02,0xf3,0x1e,0x3e,0x56,0x5c,0x0e,0x3b,0xa7,0xe3,0x17,0x0d,0x30,0x32,0x31, +0x30,0x32,0x39,0x31,0x39,0x35,0x34,0x31,0x32,0x5a,0x30,0x21,0x02,0x10,0x3d, +0xdd,0x61,0x92,0x82,0x69,0x6b,0x01,0x79,0x0e,0xef,0x96,0x12,0xa3,0x76,0x80, +0x17,0x0d,0x30,0x32,0x30,0x35,0x30,0x31,0x32,0x32,0x32,0x34,0x31,0x36,0x5a, +0x30,0x21,0x02,0x10,0x3e,0x0e,0x14,0x71,0x55,0xf3,0x48,0x09,0x1b,0x56,0x3b, +0x91,0x7a,0x7d,0xec,0xc9,0x17,0x0d,0x30,0x32,0x30,0x33,0x31,0x31,0x32,0x31, +0x34,0x35,0x35,0x31,0x5a,0x30,0x21,0x02,0x10,0x3e,0x23,0x00,0x1f,0x9b,0xbd, +0xe8,0xb1,0xf0,0x06,0x67,0xa6,0x70,0x42,0x2e,0xc3,0x17,0x0d,0x30,0x32,0x30, +0x38,0x30,0x38,0x31,0x32,0x32,0x31,0x33,0x32,0x5a,0x30,0x21,0x02,0x10,0x41, +0x91,0x1a,0x8c,0xde,0x2d,0xb3,0xeb,0x79,0x1d,0xc7,0x99,0x99,0xbe,0x0c,0x0e, +0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x35,0x31,0x39,0x31,0x38,0x35,0x34,0x5a, +0x30,0x21,0x02,0x10,0x41,0xa8,0xd7,0x9c,0x10,0x5e,0x5a,0xac,0x16,0x7f,0x93, +0xaa,0xd1,0x83,0x34,0x55,0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x30,0x31,0x32, +0x35,0x33,0x34,0x30,0x5a,0x30,0x21,0x02,0x10,0x42,0x88,0x96,0xb0,0x7b,0x28, +0xa2,0xfa,0x2f,0x91,0x73,0x58,0xa7,0x1e,0x53,0x7c,0x17,0x0d,0x30,0x33,0x30, +0x33,0x30,0x31,0x30,0x39,0x34,0x33,0x33,0x31,0x5a,0x30,0x21,0x02,0x10,0x42, +0x93,0x2f,0xd2,0x54,0xd3,0x94,0xd0,0x41,0x6a,0x2e,0x33,0x8b,0x81,0xb4,0x3c, +0x17,0x0d,0x30,0x32,0x30,0x38,0x30,0x38,0x30,0x30,0x34,0x38,0x34,0x36,0x5a, +0x30,0x21,0x02,0x10,0x44,0x24,0xdd,0xba,0x85,0xfd,0x3e,0xb2,0xb8,0x17,0x74, +0xfd,0x9d,0x5c,0x0c,0xbd,0x17,0x0d,0x30,0x32,0x30,0x39,0x32,0x31,0x31,0x36, +0x30,0x39,0x31,0x32,0x5a,0x30,0x21,0x02,0x10,0x45,0x02,0x18,0x7d,0x39,0x9c, +0xb9,0x14,0xfb,0x10,0x37,0x96,0xf4,0xc1,0xdd,0x2f,0x17,0x0d,0x30,0x32,0x30, +0x32,0x31,0x31,0x31,0x31,0x31,0x31,0x30,0x36,0x5a,0x30,0x21,0x02,0x10,0x45, +0x16,0xbc,0x31,0x0b,0x4e,0x87,0x0a,0xcc,0xe3,0xd5,0x14,0x16,0x33,0x11,0x83, +0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x32,0x30,0x32,0x32,0x30,0x31,0x37,0x5a, +0x30,0x21,0x02,0x10,0x46,0x16,0x36,0xde,0x3f,0xef,0x8c,0xfa,0x67,0x53,0x12, +0xcc,0x76,0x63,0xd6,0xdd,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x34,0x31,0x36, +0x35,0x39,0x34,0x33,0x5a,0x30,0x21,0x02,0x10,0x46,0x5f,0x85,0xa3,0xa4,0x98, +0x3c,0x40,0x63,0xf6,0x1c,0xf7,0xc2,0xbe,0xfd,0x0e,0x17,0x0d,0x30,0x32,0x30, +0x34,0x30,0x39,0x31,0x35,0x33,0x30,0x30,0x35,0x5a,0x30,0x21,0x02,0x10,0x47, +0x20,0xc2,0xd8,0x85,0x85,0x54,0x39,0xcd,0xf2,0x10,0xf0,0xa7,0x88,0x52,0x75, +0x17,0x0d,0x30,0x32,0x30,0x39,0x31,0x30,0x32,0x32,0x32,0x35,0x32,0x37,0x5a, +0x30,0x21,0x02,0x10,0x47,0x42,0x6e,0xa2,0xab,0xc5,0x33,0x5d,0x50,0x44,0x0b, +0x88,0x97,0x84,0x59,0x4c,0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x35,0x31,0x34, +0x30,0x35,0x31,0x39,0x5a,0x30,0x21,0x02,0x10,0x49,0x20,0x3f,0xa8,0x6e,0x81, +0xc8,0x3b,0x26,0x05,0xf4,0xa7,0x9b,0x5a,0x81,0x60,0x17,0x0d,0x30,0x32,0x30, +0x37,0x31,0x31,0x31,0x37,0x35,0x30,0x34,0x38,0x5a,0x30,0x21,0x02,0x10,0x49, +0x8b,0x6f,0x05,0xfb,0xcb,0xf4,0x5a,0xaf,0x09,0x47,0xb1,0x04,0xc5,0xe3,0x51, +0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x32,0x31,0x37,0x34,0x38,0x30,0x38,0x5a, +0x30,0x21,0x02,0x10,0x49,0xb2,0xc3,0x7a,0xbf,0x75,0x2a,0xb3,0x13,0xae,0x53, +0xc6,0xcb,0x45,0x5a,0x3e,0x17,0x0d,0x30,0x32,0x31,0x31,0x31,0x35,0x32,0x31, +0x33,0x35,0x33,0x37,0x5a,0x30,0x21,0x02,0x10,0x4b,0xca,0xc3,0xab,0x0a,0xc5, +0xcd,0x90,0xa2,0xbe,0x43,0xfe,0xdd,0x06,0xe1,0x45,0x17,0x0d,0x30,0x32,0x30, +0x37,0x32,0x30,0x31,0x37,0x33,0x32,0x31,0x32,0x5a,0x30,0x21,0x02,0x10,0x4c, +0x00,0xcc,0x73,0xd5,0x74,0x61,0x62,0x92,0x52,0xff,0xde,0x5b,0xc1,0x55,0xbd, +0x17,0x0d,0x30,0x32,0x30,0x38,0x32,0x36,0x31,0x34,0x30,0x31,0x35,0x31,0x5a, +0x30,0x21,0x02,0x10,0x4c,0x59,0xc1,0xc3,0x56,0x40,0x27,0xd4,0x22,0x0e,0x37, +0xf6,0x5f,0x26,0x50,0xc5,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x36,0x30,0x39, +0x35,0x37,0x34,0x34,0x5a,0x30,0x21,0x02,0x10,0x4c,0xca,0x12,0x59,0x46,0xf9, +0x2b,0xc6,0x7d,0x33,0x78,0x40,0x2c,0x3b,0x7a,0x0c,0x17,0x0d,0x30,0x32,0x30, +0x35,0x33,0x30,0x32,0x30,0x32,0x34,0x35,0x38,0x5a,0x30,0x21,0x02,0x10,0x4d, +0x57,0x51,0x35,0x9b,0xe5,0x41,0x2c,0x69,0x66,0xc7,0x21,0xec,0xc6,0x29,0x32, +0x17,0x0d,0x30,0x32,0x30,0x39,0x32,0x36,0x30,0x34,0x33,0x35,0x35,0x36,0x5a, +0x30,0x21,0x02,0x10,0x4e,0x85,0xab,0x9e,0x17,0x54,0xe7,0x42,0x0f,0x8c,0xa1, +0x65,0x96,0x88,0x53,0x54,0x17,0x0d,0x30,0x32,0x30,0x33,0x32,0x38,0x30,0x30, +0x31,0x38,0x35,0x33,0x5a,0x30,0x21,0x02,0x10,0x50,0x3d,0xed,0xac,0x21,0x86, +0x66,0x5d,0xa5,0x1a,0x13,0xee,0xfc,0xa7,0x0b,0xc6,0x17,0x0d,0x30,0x32,0x30, +0x32,0x31,0x38,0x31,0x33,0x35,0x35,0x34,0x39,0x5a,0x30,0x21,0x02,0x10,0x50, +0xa3,0x81,0x9c,0xcb,0x22,0xe4,0x0f,0x80,0xcb,0x7a,0xec,0x35,0xf8,0x73,0x82, +0x17,0x0d,0x30,0x32,0x31,0x30,0x30,0x35,0x31,0x36,0x35,0x39,0x35,0x39,0x5a, +0x30,0x21,0x02,0x10,0x51,0x28,0x73,0x26,0x17,0xcf,0x10,0x6e,0xeb,0x4a,0x03, +0x74,0xa3,0x35,0xe5,0x60,0x17,0x0d,0x30,0x33,0x30,0x36,0x31,0x33,0x31,0x30, +0x30,0x39,0x32,0x39,0x5a,0x30,0x21,0x02,0x10,0x51,0x52,0xff,0xdc,0x69,0x6b, +0x1f,0x1f,0xff,0x7c,0xb1,0x7f,0x03,0x90,0xa9,0x6b,0x17,0x0d,0x30,0x32,0x30, +0x36,0x31,0x34,0x31,0x36,0x30,0x34,0x30,0x32,0x5a,0x30,0x21,0x02,0x10,0x52, +0xd9,0x53,0x69,0x9f,0xec,0xab,0xdd,0x5d,0x2a,0x2f,0xaa,0x57,0x86,0xb9,0x1f, +0x17,0x0d,0x30,0x32,0x30,0x38,0x33,0x30,0x32,0x33,0x34,0x36,0x34,0x33,0x5a, +0x30,0x21,0x02,0x10,0x54,0x46,0xa8,0x8f,0x69,0x2e,0x02,0xf4,0xb4,0xb2,0x69, +0xda,0xbd,0x40,0x02,0xe0,0x17,0x0d,0x30,0x32,0x30,0x33,0x32,0x36,0x30,0x31, +0x35,0x36,0x35,0x38,0x5a,0x30,0x21,0x02,0x10,0x54,0xb5,0x81,0x73,0xb5,0x7c, +0x6d,0xba,0x5c,0x99,0x0d,0xff,0x0a,0x4d,0xee,0xef,0x17,0x0d,0x30,0x32,0x30, +0x37,0x32,0x34,0x31,0x36,0x33,0x39,0x35,0x31,0x5a,0x30,0x21,0x02,0x10,0x57, +0x91,0x41,0x20,0x9f,0x57,0x6f,0x42,0x53,0x4e,0x19,0xcc,0xe4,0xc8,0x52,0x4a, +0x17,0x0d,0x30,0x32,0x30,0x35,0x32,0x38,0x32,0x33,0x32,0x34,0x30,0x30,0x5a, +0x30,0x21,0x02,0x10,0x57,0xc6,0xdc,0xa0,0xed,0xbf,0x77,0xdd,0x7e,0x18,0x68, +0x83,0x57,0x0c,0x2a,0x4f,0x17,0x0d,0x30,0x32,0x30,0x35,0x32,0x31,0x31,0x34, +0x30,0x36,0x31,0x31,0x5a,0x30,0x21,0x02,0x10,0x57,0xed,0xe2,0x5b,0xe2,0x62, +0x3f,0x98,0xe1,0xf5,0x4d,0x30,0xa4,0x0e,0xdf,0xdf,0x17,0x0d,0x30,0x32,0x30, +0x36,0x30,0x39,0x30,0x31,0x34,0x37,0x31,0x38,0x5a,0x30,0x21,0x02,0x10,0x58, +0x47,0xd9,0xbd,0x83,0x1a,0x63,0x6f,0xb7,0x63,0x7f,0x4a,0x56,0x5e,0x8e,0x4d, +0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x35,0x31,0x37,0x32,0x33,0x30,0x33,0x5a, +0x30,0x21,0x02,0x10,0x58,0xc6,0x62,0x99,0x80,0xe6,0x0c,0x4f,0x00,0x8b,0x25, +0x38,0x93,0xe6,0x18,0x10,0x17,0x0d,0x30,0x32,0x30,0x36,0x30,0x36,0x30,0x37, +0x30,0x39,0x34,0x37,0x5a,0x30,0x21,0x02,0x10,0x59,0x52,0x09,0x0e,0x99,0xf3, +0xa9,0xe5,0x2f,0xed,0xa9,0xb2,0xd8,0x61,0xe7,0xea,0x17,0x0d,0x30,0x32,0x30, +0x36,0x32,0x36,0x31,0x34,0x31,0x38,0x33,0x36,0x5a,0x30,0x21,0x02,0x10,0x59, +0x5c,0xaa,0xfb,0xbe,0xfb,0x73,0xd1,0xf4,0xab,0xc8,0xe3,0x3d,0x01,0x04,0xdd, +0x17,0x0d,0x30,0x32,0x30,0x39,0x32,0x37,0x32,0x32,0x32,0x30,0x31,0x30,0x5a, +0x30,0x21,0x02,0x10,0x59,0x97,0x59,0xa7,0x3d,0xb0,0xd9,0x7e,0xff,0x2a,0xcb, +0x31,0xcc,0x66,0xf3,0x85,0x17,0x0d,0x30,0x32,0x30,0x38,0x32,0x32,0x30,0x30, +0x35,0x35,0x35,0x38,0x5a,0x30,0x21,0x02,0x10,0x59,0xdd,0x45,0x36,0x61,0xd9, +0x3e,0xe9,0xff,0xbd,0xad,0x2e,0xbf,0x9a,0x5d,0x98,0x17,0x0d,0x30,0x32,0x30, +0x37,0x30,0x32,0x32,0x30,0x34,0x30,0x30,0x33,0x5a,0x30,0x21,0x02,0x10,0x5a, +0x4b,0x48,0x18,0xa9,0x2a,0x9c,0xd5,0x91,0x2f,0x4f,0xa4,0xf8,0xb3,0x1b,0x4d, +0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x34,0x32,0x33,0x33,0x33,0x31,0x32,0x5a, +0x30,0x21,0x02,0x10,0x5a,0xdf,0x32,0x0d,0x64,0xeb,0x9b,0xd2,0x11,0xe2,0x58, +0x50,0xbe,0x93,0x0c,0x65,0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x35,0x31,0x37, +0x30,0x37,0x32,0x31,0x5a,0x30,0x21,0x02,0x10,0x5b,0x23,0xbf,0xbb,0xc4,0xb3, +0xf4,0x02,0xe9,0xcb,0x10,0x9e,0xee,0xa5,0x3f,0xcd,0x17,0x0d,0x30,0x32,0x30, +0x33,0x32,0x39,0x31,0x36,0x32,0x36,0x35,0x39,0x5a,0x30,0x21,0x02,0x10,0x5b, +0x51,0xbc,0x38,0xbf,0xaf,0x9f,0x27,0xa9,0xc7,0xed,0x25,0xd0,0x8d,0xec,0x2e, +0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x38,0x31,0x30,0x32,0x35,0x32,0x30,0x5a, +0x30,0x21,0x02,0x10,0x5c,0x29,0x7f,0x46,0x61,0xdd,0x47,0x90,0x82,0x91,0xbd, +0x79,0x22,0x6a,0x98,0x38,0x17,0x0d,0x30,0x32,0x31,0x31,0x30,0x38,0x31,0x35, +0x35,0x34,0x32,0x36,0x5a,0x30,0x21,0x02,0x10,0x5e,0x38,0xf7,0x5b,0x00,0xf1, +0xef,0x1c,0xb6,0xff,0xd5,0x5c,0x74,0xfb,0x95,0x5d,0x17,0x0d,0x30,0x32,0x31, +0x31,0x32,0x33,0x30,0x31,0x34,0x39,0x32,0x39,0x5a,0x30,0x21,0x02,0x10,0x5e, +0x88,0xbe,0xb6,0xb4,0xb2,0xaa,0xb0,0x92,0xf3,0xf6,0xc2,0xbc,0x72,0x21,0xca, +0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x34,0x30,0x37,0x31,0x32,0x31,0x30,0x5a, +0x30,0x21,0x02,0x10,0x5f,0x59,0xa0,0xbb,0xaf,0x26,0xc8,0xc1,0xb4,0x04,0x3a, +0xbb,0xfc,0x4c,0x75,0xa5,0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x36,0x31,0x35, +0x35,0x31,0x32,0x33,0x5a,0x30,0x21,0x02,0x10,0x5f,0x81,0x08,0x0f,0xa0,0xcd, +0x44,0x73,0x23,0x58,0x8e,0x49,0x9f,0xb5,0x08,0x35,0x17,0x0d,0x30,0x32,0x30, +0x36,0x31,0x39,0x31,0x34,0x31,0x37,0x34,0x33,0x5a,0x30,0x21,0x02,0x10,0x5f, +0xba,0x1f,0x8f,0xb2,0x23,0x56,0xdd,0xbc,0xa6,0x72,0xb0,0x99,0x13,0xb5,0xb2, +0x17,0x0d,0x30,0x32,0x30,0x35,0x30,0x36,0x30,0x38,0x34,0x37,0x31,0x30,0x5a, +0x30,0x21,0x02,0x10,0x60,0x09,0xd5,0xb7,0x6b,0xf1,0x16,0x4a,0xfa,0xd0,0xa5, +0x4c,0x8e,0xdd,0x02,0xcb,0x17,0x0d,0x30,0x32,0x30,0x36,0x31,0x37,0x31,0x36, +0x31,0x32,0x32,0x39,0x5a,0x30,0x21,0x02,0x10,0x60,0x1d,0x19,0xd8,0x55,0xd5, +0x14,0xd5,0xff,0x03,0x0d,0xad,0x5c,0x07,0x4c,0xe7,0x17,0x0d,0x30,0x32,0x30, +0x37,0x31,0x35,0x32,0x33,0x30,0x31,0x31,0x31,0x5a,0x30,0x21,0x02,0x10,0x60, +0x24,0x67,0xc3,0x0b,0xad,0x53,0x8f,0xce,0x89,0x05,0xb5,0x87,0xaf,0x7c,0xe4, +0x17,0x0d,0x30,0x32,0x31,0x30,0x30,0x38,0x32,0x30,0x33,0x38,0x35,0x32,0x5a, +0x30,0x21,0x02,0x10,0x60,0x5c,0xf3,0x3d,0x22,0x23,0x39,0x3f,0xe6,0x21,0x09, +0xfd,0xdd,0x77,0xc2,0x8f,0x17,0x0d,0x30,0x32,0x30,0x37,0x30,0x32,0x31,0x37, +0x32,0x37,0x35,0x38,0x5a,0x30,0x21,0x02,0x10,0x60,0xa2,0x5e,0xbf,0x07,0x83, +0xa3,0x18,0x56,0x18,0x48,0x63,0xa7,0xfd,0xc7,0x63,0x17,0x0d,0x30,0x32,0x30, +0x35,0x30,0x39,0x31,0x39,0x35,0x32,0x32,0x37,0x5a,0x30,0x21,0x02,0x10,0x60, +0xc2,0xad,0xa8,0x0e,0xf9,0x9a,0x66,0x5d,0xa2,0x75,0x04,0x5e,0x5c,0x71,0xc2, +0x17,0x0d,0x30,0x32,0x31,0x31,0x31,0x32,0x31,0x33,0x33,0x36,0x31,0x37,0x5a, +0x30,0x21,0x02,0x10,0x60,0xdb,0x1d,0x37,0x34,0xf6,0x02,0x9d,0x68,0x1b,0x70, +0xf1,0x13,0x00,0x2f,0x80,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x38,0x30,0x39, +0x35,0x35,0x33,0x33,0x5a,0x30,0x21,0x02,0x10,0x61,0xf0,0x38,0xea,0xbc,0x17, +0x0d,0x11,0xd2,0x89,0xee,0x87,0x50,0x57,0xa0,0xed,0x17,0x0d,0x30,0x33,0x30, +0x31,0x32,0x39,0x31,0x37,0x34,0x31,0x34,0x34,0x5a,0x30,0x21,0x02,0x10,0x61, +0xfa,0x9b,0xeb,0x58,0xf9,0xe5,0xa5,0x9e,0x79,0xa8,0x3d,0x79,0xac,0x35,0x97, +0x17,0x0d,0x30,0x32,0x31,0x30,0x31,0x30,0x32,0x30,0x31,0x36,0x33,0x37,0x5a, +0x30,0x21,0x02,0x10,0x62,0x44,0x57,0x24,0x41,0xc0,0x89,0x3f,0x5b,0xd2,0xbd, +0xe7,0x2f,0x75,0x41,0xfa,0x17,0x0d,0x30,0x32,0x30,0x38,0x30,0x38,0x31,0x38, +0x33,0x30,0x31,0x35,0x5a,0x30,0x21,0x02,0x10,0x62,0x51,0x3a,0x2d,0x8d,0x82, +0x39,0x65,0xfe,0xf6,0x8a,0xc8,0x4e,0x29,0x91,0xfd,0x17,0x0d,0x30,0x32,0x30, +0x39,0x32,0x36,0x30,0x30,0x35,0x34,0x33,0x34,0x5a,0x30,0x21,0x02,0x10,0x62, +0x52,0x49,0x49,0xf2,0x51,0x67,0x7a,0xe2,0xee,0xc9,0x0c,0x23,0x11,0x3d,0xb2, +0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x37,0x31,0x38,0x30,0x36,0x35,0x35,0x5a, +0x30,0x21,0x02,0x10,0x63,0x52,0xbd,0xdc,0xb7,0xbf,0xbb,0x90,0x6c,0x82,0xee, +0xb5,0xa3,0x9f,0xd8,0xc9,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x31,0x31,0x36, +0x33,0x30,0x35,0x38,0x5a,0x30,0x21,0x02,0x10,0x63,0x5e,0x6b,0xe9,0xea,0x3d, +0xd6,0x3b,0xc3,0x4d,0x09,0xc3,0x13,0xdb,0xdd,0xbc,0x17,0x0d,0x30,0x33,0x30, +0x36,0x30,0x32,0x31,0x34,0x34,0x37,0x33,0x36,0x5a,0x30,0x21,0x02,0x10,0x63, +0xda,0x0b,0xd5,0x13,0x1e,0x98,0x83,0x32,0xa2,0x3a,0x4b,0xdf,0x8c,0x89,0x86, +0x17,0x0d,0x30,0x32,0x30,0x39,0x32,0x35,0x30,0x38,0x30,0x38,0x31,0x33,0x5a, +0x30,0x21,0x02,0x10,0x64,0xfe,0xf0,0x1a,0x3a,0xed,0x89,0xf8,0xb5,0x34,0xd3, +0x1e,0x0f,0xce,0x0d,0xce,0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x38,0x32,0x31, +0x30,0x36,0x32,0x34,0x5a,0x30,0x21,0x02,0x10,0x65,0xa7,0x49,0xd8,0x37,0x22, +0x4b,0x4a,0xe5,0xcf,0xa3,0xfe,0xd6,0x3b,0xc0,0x67,0x17,0x0d,0x30,0x32,0x31, +0x32,0x30,0x34,0x31,0x37,0x31,0x34,0x31,0x36,0x5a,0x30,0x21,0x02,0x10,0x65, +0xc9,0x9e,0x47,0x76,0x98,0x0d,0x9e,0x57,0xe4,0xae,0xc5,0x1c,0x3e,0xf2,0xe7, +0x17,0x0d,0x30,0x32,0x30,0x39,0x32,0x33,0x31,0x34,0x30,0x38,0x31,0x38,0x5a, +0x30,0x21,0x02,0x10,0x65,0xe0,0x7b,0xc5,0x74,0xe4,0xab,0x01,0x4f,0xa3,0x5e, +0xd6,0xeb,0xcd,0xd5,0x69,0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x33,0x31,0x37, +0x32,0x34,0x30,0x36,0x5a,0x30,0x21,0x02,0x10,0x66,0x51,0xb7,0xe5,0x62,0xb7, +0xe3,0x31,0xc0,0xee,0xf2,0xe8,0xfe,0x84,0x6a,0x4e,0x17,0x0d,0x30,0x32,0x30, +0x39,0x30,0x36,0x31,0x33,0x32,0x33,0x33,0x33,0x5a,0x30,0x21,0x02,0x10,0x67, +0x7c,0x76,0xac,0x66,0x5a,0x6b,0x41,0x5c,0x07,0x83,0x02,0xd6,0xd9,0x63,0xc0, +0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x38,0x31,0x33,0x35,0x35,0x31,0x30,0x5a, +0x30,0x21,0x02,0x10,0x68,0x67,0xde,0xb3,0xaa,0x20,0xcf,0x4b,0x34,0xa5,0xe0, +0xc8,0xc0,0xc5,0xc9,0xa4,0x17,0x0d,0x30,0x32,0x30,0x33,0x31,0x32,0x30,0x31, +0x30,0x39,0x32,0x36,0x5a,0x30,0x21,0x02,0x10,0x69,0x23,0x34,0x5d,0x75,0x04, +0xdc,0x99,0xbd,0xce,0x8d,0x21,0xb4,0x6b,0x10,0xfc,0x17,0x0d,0x30,0x32,0x30, +0x39,0x30,0x33,0x31,0x33,0x31,0x39,0x32,0x30,0x5a,0x30,0x21,0x02,0x10,0x69, +0x9f,0x20,0x31,0xd1,0x3f,0xfa,0x1e,0x70,0x2e,0x37,0xd5,0x9a,0x8c,0x0a,0x16, +0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x30,0x30,0x39,0x30,0x31,0x33,0x35,0x5a, +0x30,0x21,0x02,0x10,0x6a,0x94,0xd6,0x25,0xd0,0x67,0xe4,0x4d,0x79,0x2b,0xc6, +0xd5,0xc9,0x4a,0x7f,0xc6,0x17,0x0d,0x30,0x32,0x30,0x32,0x31,0x31,0x31,0x39, +0x31,0x35,0x34,0x30,0x5a,0x30,0x21,0x02,0x10,0x6b,0x5c,0xa4,0x45,0x5b,0xe9, +0xcf,0xe7,0x3b,0x29,0xb1,0x32,0xd7,0xa1,0x04,0x3d,0x17,0x0d,0x30,0x32,0x31, +0x30,0x31,0x38,0x31,0x35,0x34,0x33,0x34,0x38,0x5a,0x30,0x21,0x02,0x10,0x6b, +0xc0,0x7d,0x4f,0x18,0xfe,0xb7,0x07,0xe8,0x56,0x9a,0x6c,0x40,0x0f,0x36,0x53, +0x17,0x0d,0x30,0x32,0x30,0x39,0x32,0x36,0x32,0x31,0x30,0x31,0x32,0x36,0x5a, +0x30,0x21,0x02,0x10,0x6b,0xe1,0xdd,0x36,0x3b,0xec,0xe0,0xa9,0xf5,0x92,0x7e, +0x33,0xbf,0xed,0x48,0x46,0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x37,0x31,0x34, +0x34,0x32,0x33,0x31,0x5a,0x30,0x21,0x02,0x10,0x6c,0xac,0xeb,0x37,0x2b,0x6a, +0x42,0xe2,0xca,0xc8,0xd2,0xda,0xb8,0xb9,0x82,0x6a,0x17,0x0d,0x30,0x32,0x30, +0x33,0x30,0x31,0x31,0x34,0x32,0x38,0x33,0x34,0x5a,0x30,0x21,0x02,0x10,0x6d, +0x98,0x1b,0xb4,0x76,0xd1,0x62,0x59,0xa1,0x3c,0xee,0xd2,0x21,0xd8,0xdf,0x4c, +0x17,0x0d,0x30,0x32,0x30,0x35,0x31,0x34,0x31,0x37,0x35,0x36,0x31,0x32,0x5a, +0x30,0x21,0x02,0x10,0x6d,0xdd,0x0b,0x5a,0x3c,0x9c,0xab,0xd3,0x3b,0xd9,0x16, +0xec,0x69,0x74,0xfb,0x9a,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x32,0x31,0x32, +0x32,0x36,0x33,0x38,0x5a,0x30,0x21,0x02,0x10,0x6e,0xde,0xfd,0x89,0x36,0xae, +0xa0,0x41,0x8d,0x5c,0xec,0x2e,0x90,0x31,0xf8,0x9a,0x17,0x0d,0x30,0x32,0x30, +0x34,0x30,0x38,0x32,0x32,0x33,0x36,0x31,0x32,0x5a,0x30,0x21,0x02,0x10,0x6f, +0xb2,0x6b,0x4c,0x48,0xca,0xfe,0xe6,0x69,0x9a,0x06,0x63,0xc4,0x32,0x96,0xc1, +0x17,0x0d,0x30,0x33,0x30,0x31,0x31,0x37,0x31,0x37,0x32,0x37,0x32,0x35,0x5a, +0x30,0x21,0x02,0x10,0x70,0x0b,0xe1,0xee,0x44,0x89,0x51,0x52,0x65,0x27,0x2c, +0x2d,0x34,0x7c,0xe0,0x8d,0x17,0x0d,0x30,0x32,0x30,0x39,0x31,0x38,0x30,0x30, +0x33,0x36,0x30,0x30,0x5a,0x30,0x21,0x02,0x10,0x70,0x2d,0xc0,0xa6,0xb8,0xa5, +0xa0,0xda,0x48,0x59,0xb3,0x96,0x34,0x80,0xc8,0x25,0x17,0x0d,0x30,0x32,0x30, +0x38,0x33,0x30,0x31,0x34,0x30,0x31,0x30,0x31,0x5a,0x30,0x21,0x02,0x10,0x70, +0xe1,0xd9,0x92,0xcd,0x76,0x42,0x63,0x51,0x6e,0xcd,0x8c,0x09,0x29,0x17,0x48, +0x17,0x0d,0x30,0x32,0x30,0x35,0x31,0x37,0x31,0x31,0x31,0x30,0x34,0x31,0x5a, +0x30,0x21,0x02,0x10,0x72,0x38,0xe4,0x91,0x6a,0x7a,0x8a,0xf3,0xbf,0xf0,0xd8, +0xe0,0xa4,0x70,0x8d,0xa8,0x17,0x0d,0x30,0x32,0x30,0x33,0x30,0x34,0x31,0x39, +0x30,0x36,0x34,0x30,0x5a,0x30,0x21,0x02,0x10,0x72,0x97,0xa1,0xd8,0x9c,0x3b, +0x00,0xc2,0xc4,0x26,0x2d,0x06,0x2b,0x29,0x76,0x4e,0x17,0x0d,0x30,0x32,0x30, +0x36,0x31,0x38,0x31,0x35,0x30,0x39,0x34,0x37,0x5a,0x30,0x21,0x02,0x10,0x72, +0xd2,0x23,0x9b,0xf2,0x33,0xe9,0x7c,0xcf,0xb6,0xa9,0x41,0xd5,0x0e,0x5c,0x39, +0x17,0x0d,0x30,0x33,0x30,0x34,0x30,0x39,0x31,0x37,0x30,0x32,0x32,0x39,0x5a, +0x30,0x21,0x02,0x10,0x74,0x5c,0x9c,0xf9,0xaa,0xc3,0xfa,0x94,0x3c,0x25,0x39, +0x65,0x44,0x95,0x13,0xf1,0x17,0x0d,0x30,0x32,0x30,0x37,0x30,0x39,0x32,0x33, +0x35,0x33,0x32,0x30,0x5a,0x30,0x21,0x02,0x10,0x74,0x98,0x7f,0x68,0xad,0x17, +0x92,0x93,0xf2,0x65,0x94,0x0c,0x33,0xe6,0xbd,0x49,0x17,0x0d,0x30,0x32,0x30, +0x34,0x32,0x33,0x30,0x37,0x34,0x34,0x31,0x38,0x5a,0x30,0x21,0x02,0x10,0x75, +0x0e,0x40,0xff,0x97,0xf0,0x47,0xed,0xf5,0x56,0xc7,0x08,0x4e,0xb1,0xab,0xfd, +0x17,0x0d,0x30,0x31,0x30,0x31,0x33,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a, +0x30,0x21,0x02,0x10,0x75,0x26,0x51,0x59,0x65,0xb7,0x33,0x32,0x5f,0xe6,0xcd, +0xaa,0x30,0x65,0x78,0xe0,0x17,0x0d,0x30,0x32,0x30,0x35,0x31,0x36,0x31,0x38, +0x32,0x34,0x35,0x36,0x5a,0x30,0x21,0x02,0x10,0x76,0x13,0x6f,0xbf,0xc8,0xde, +0xd9,0x36,0x30,0x39,0xcc,0x85,0x8f,0x00,0x2f,0x19,0x17,0x0d,0x30,0x32,0x30, +0x33,0x31,0x34,0x30,0x39,0x34,0x38,0x32,0x34,0x5a,0x30,0x21,0x02,0x10,0x76, +0x52,0x78,0x89,0x44,0xfa,0xc1,0xb3,0xd7,0xc9,0x4c,0xb3,0x32,0x95,0xaf,0x03, +0x17,0x0d,0x30,0x32,0x31,0x31,0x31,0x34,0x31,0x39,0x31,0x35,0x34,0x33,0x5a, +0x30,0x21,0x02,0x10,0x77,0x5d,0x4c,0x40,0xd9,0x8d,0xfa,0xc8,0x9a,0x24,0x8d, +0x47,0x10,0x90,0x4a,0x0a,0x17,0x0d,0x30,0x32,0x30,0x35,0x30,0x39,0x30,0x31, +0x31,0x33,0x30,0x32,0x5a,0x30,0x21,0x02,0x10,0x77,0xe6,0x5a,0x43,0x59,0x93, +0x5d,0x5f,0x7a,0x75,0x80,0x1a,0xcd,0xad,0xc2,0x22,0x17,0x0d,0x30,0x30,0x30, +0x38,0x33,0x31,0x31,0x38,0x32,0x32,0x35,0x30,0x5a,0x30,0x21,0x02,0x10,0x78, +0x19,0xf1,0xb6,0x87,0x83,0xaf,0xdf,0x60,0x8d,0x9a,0x64,0x0d,0xec,0xe0,0x51, +0x17,0x0d,0x30,0x32,0x30,0x35,0x32,0x30,0x31,0x37,0x32,0x38,0x31,0x36,0x5a, +0x30,0x21,0x02,0x10,0x78,0x64,0x65,0x8f,0x82,0x79,0xdb,0xa5,0x1c,0x47,0x10, +0x1d,0x72,0x23,0x66,0x52,0x17,0x0d,0x30,0x33,0x30,0x31,0x32,0x34,0x31,0x38, +0x34,0x35,0x34,0x37,0x5a,0x30,0x21,0x02,0x10,0x78,0x64,0xe1,0xc0,0x69,0x8f, +0x3a,0xc7,0x8b,0x23,0xe3,0x29,0xb1,0xee,0xa9,0x41,0x17,0x0d,0x30,0x32,0x30, +0x35,0x30,0x38,0x31,0x37,0x34,0x36,0x32,0x36,0x5a,0x30,0x21,0x02,0x10,0x78, +0x79,0x89,0x61,0x12,0x67,0x64,0x14,0xfd,0x08,0xcc,0xb3,0x05,0x55,0xc0,0x67, +0x17,0x0d,0x30,0x32,0x30,0x34,0x30,0x32,0x31,0x33,0x31,0x38,0x35,0x33,0x5a, +0x30,0x21,0x02,0x10,0x78,0x8a,0x56,0x22,0x08,0xce,0x42,0xee,0xd1,0xa3,0x79, +0x10,0x14,0xfd,0x3a,0x36,0x17,0x0d,0x30,0x33,0x30,0x32,0x30,0x35,0x31,0x36, +0x35,0x33,0x32,0x39,0x5a,0x30,0x21,0x02,0x10,0x7a,0xa0,0x6c,0xba,0x33,0x02, +0xac,0x5f,0xf5,0x0b,0xb6,0x77,0x61,0xef,0x77,0x09,0x17,0x0d,0x30,0x32,0x30, +0x32,0x32,0x38,0x31,0x37,0x35,0x35,0x31,0x31,0x5a,0x30,0x21,0x02,0x10,0x7b, +0x91,0x33,0x66,0x6c,0xf0,0xd4,0xe3,0x9d,0xf6,0x88,0x29,0x9b,0xf7,0xd0,0xea, +0x17,0x0d,0x30,0x32,0x31,0x31,0x32,0x30,0x32,0x32,0x31,0x36,0x34,0x39,0x5a, +0x30,0x21,0x02,0x10,0x7c,0xef,0xf2,0x0a,0x08,0xae,0x10,0x57,0x1e,0xde,0xdc, +0xd6,0x63,0x76,0xb0,0x5d,0x17,0x0d,0x30,0x32,0x30,0x32,0x32,0x36,0x31,0x30, +0x32,0x32,0x33,0x30,0x5a,0x30,0x21,0x02,0x10,0x7f,0x76,0xef,0x69,0xeb,0xf5, +0x3f,0x53,0x2e,0xaa,0xa5,0xed,0xde,0xc0,0xb4,0x06,0x17,0x0d,0x30,0x32,0x30, +0x35,0x30,0x31,0x30,0x33,0x33,0x33,0x30,0x37,0x5a,0x30,0x21,0x02,0x10,0x7f, +0xcb,0x6b,0x99,0x91,0xd0,0x76,0xe1,0x3c,0x0e,0x67,0x15,0xc4,0xd4,0x4d,0x7b, +0x17,0x0d,0x30,0x32,0x30,0x34,0x31,0x30,0x32,0x31,0x31,0x38,0x34,0x30,0x5a, +0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x04,0x05,0x00, +0x03,0x81,0x81,0x00,0x5c,0xb9,0xb3,0xbe,0xd3,0xd6,0x73,0xa3,0xfe,0x4a,0xb2, +0x21,0x80,0xea,0xaa,0x05,0x61,0x14,0x1d,0x67,0xb1,0xdf,0xa6,0xf9,0x42,0x08, +0x0d,0x59,0x62,0x9c,0x11,0x5f,0x0e,0x92,0xc5,0xc6,0xae,0x74,0x64,0xc7,0x84, +0x3e,0x64,0x43,0xd2,0xec,0xbb,0xe1,0x9b,0x52,0x74,0x57,0xcf,0x96,0xef,0x68, +0x02,0x7a,0x7b,0x36,0xb7,0xc6,0x9a,0x5f,0xca,0x9c,0x37,0x47,0xc8,0x3a,0x5c, +0x34,0x35,0x3b,0x4b,0xca,0x20,0x77,0x44,0x68,0x07,0x02,0x34,0x46,0xaa,0x0f, +0xd0,0x4d,0xd9,0x47,0xf4,0xb3,0x2d,0xb1,0x44,0xa5,0x69,0xa9,0x85,0x13,0x43, +0xcd,0xcc,0x1d,0x9a,0xe6,0x2d,0xfd,0x9f,0xdc,0x2f,0x83,0xbb,0x8c,0xe2,0x8c, +0x61,0xc0,0x99,0x16,0x71,0x05,0xb6,0x25,0x14,0x64,0x4f,0x30 }; + +static void test_decodeCRLToBeSigned(DWORD dwEncoding) +{ + static const BYTE *corruptCRLs[] = { v1CRL, v2CRL }; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0, i; + + for (i = 0; i < sizeof(corruptCRLs) / sizeof(corruptCRLs[0]); i++) + { + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, + corruptCRLs[i], corruptCRLs[i][1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + } + /* at a minimum, a CRL must contain an issuer: */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, + v1CRLWithIssuer, v1CRLWithIssuer[1] + 2, CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRL_INFO *info = (CRL_INFO *)buf; + + ok(size >= sizeof(CRL_INFO), "Wrong size %d\n", size); + ok(info->cCRLEntry == 0, "Expected 0 CRL entries, got %d\n", + info->cCRLEntry); + ok(info->Issuer.cbData == sizeof(encodedCommonName), + "Wrong issuer size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData), + "Unexpected issuer\n"); + LocalFree(buf); + } + /* check decoding with an empty CRL entry */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, + v1CRLWithIssuerAndEmptyEntry, v1CRLWithIssuerAndEmptyEntry[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + /* with a real CRL entry */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, + v1CRLWithIssuerAndEntry, v1CRLWithIssuerAndEntry[1] + 2, + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRL_INFO *info = (CRL_INFO *)buf; + CRL_ENTRY *entry; + + ok(size >= sizeof(CRL_INFO), "Wrong size %d\n", size); + ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %d\n", + info->cCRLEntry); + ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n"); + entry = info->rgCRLEntry; + ok(entry->SerialNumber.cbData == 1, + "Expected serial number size 1, got %d\n", + entry->SerialNumber.cbData); + ok(*entry->SerialNumber.pbData == *serialNum, + "Expected serial number %d, got %d\n", *serialNum, + *entry->SerialNumber.pbData); + ok(info->Issuer.cbData == sizeof(encodedCommonName), + "Wrong issuer size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData), + "Unexpected issuer\n"); + LocalFree(buf); + } + /* a real CRL from verisign that has extensions */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, + verisignCRL, sizeof(verisignCRL), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRL_INFO *info = (CRL_INFO *)buf; + CRL_ENTRY *entry; + + ok(size >= sizeof(CRL_INFO), "Wrong size %d\n", size); + ok(info->cCRLEntry == 3, "Expected 3 CRL entries, got %d\n", + info->cCRLEntry); + ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n"); + entry = info->rgCRLEntry; + ok(info->cExtension == 2, "Expected 2 extensions, got %d\n", + info->cExtension); + LocalFree(buf); + } + /* another real CRL from verisign that has lots of entries */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, + verisignCRLWithLotsOfEntries, sizeof(verisignCRLWithLotsOfEntries), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRL_INFO *info = (CRL_INFO *)buf; + + ok(size >= sizeof(CRL_INFO), "Got size %d\n", size); + ok(info->cCRLEntry == 209, "Expected 209 CRL entries, got %d\n", + info->cCRLEntry); + ok(info->cExtension == 0, "Expected 0 extensions, got %d\n", + info->cExtension); + LocalFree(buf); + } + /* and finally, with an extension */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, + v1CRLWithExt, sizeof(v1CRLWithExt), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRL_INFO *info = (CRL_INFO *)buf; + CRL_ENTRY *entry; + + ok(size >= sizeof(CRL_INFO), "Wrong size %d\n", size); + ok(info->cCRLEntry == 1, "Expected 1 CRL entries, got %d\n", + info->cCRLEntry); + ok(info->rgCRLEntry != NULL, "Expected a valid CRL entry array\n"); + entry = info->rgCRLEntry; + ok(entry->SerialNumber.cbData == 1, + "Expected serial number size 1, got %d\n", + entry->SerialNumber.cbData); + ok(*entry->SerialNumber.pbData == *serialNum, + "Expected serial number %d, got %d\n", *serialNum, + *entry->SerialNumber.pbData); + ok(info->Issuer.cbData == sizeof(encodedCommonName), + "Wrong issuer size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonName, info->Issuer.cbData), + "Unexpected issuer\n"); + ok(info->cExtension == 1, "Expected 1 extensions, got %d\n", + info->cExtension); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_CRL_TO_BE_SIGNED, + v2CRLWithExt, sizeof(v2CRLWithExt), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CRL_INFO *info = (CRL_INFO *)buf; + + ok(info->cExtension == 1, "Expected 1 extensions, got %d\n", + info->cExtension); + LocalFree(buf); + } +} + +static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING, + szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA }; +static const BYTE encodedUsage[] = { + 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 }; + +static void test_encodeEnhancedKeyUsage(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CERT_ENHKEY_USAGE usage; + + /* Test with empty usage */ + usage.cUsageIdentifier = 0; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptySequence), "Wrong size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "Got unexpected value\n"); + LocalFree(buf); + } + /* Test with a few usages */ + usage.cUsageIdentifier = sizeof(keyUsages) / sizeof(keyUsages[0]); + usage.rgpszUsageIdentifier = (LPSTR *)keyUsages; + ret = pCryptEncodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, &usage, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(encodedUsage), "Wrong size %d\n", size); + ok(!memcmp(buf, encodedUsage, size), "Got unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeEnhancedKeyUsage(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf; + + ok(size >= sizeof(CERT_ENHKEY_USAGE), + "Wrong size %d\n", size); + ok(usage->cUsageIdentifier == 0, "Expected 0 CRL entries, got %d\n", + usage->cUsageIdentifier); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_ENHANCED_KEY_USAGE, + encodedUsage, sizeof(encodedUsage), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_ENHKEY_USAGE *usage = (CERT_ENHKEY_USAGE *)buf; + DWORD i; + + ok(size >= sizeof(CERT_ENHKEY_USAGE), + "Wrong size %d\n", size); + ok(usage->cUsageIdentifier == sizeof(keyUsages) / sizeof(keyUsages[0]), + "Wrong CRL entries count %d\n", usage->cUsageIdentifier); + for (i = 0; i < usage->cUsageIdentifier; i++) + ok(!strcmp(usage->rgpszUsageIdentifier[i], keyUsages[i]), + "Expected OID %s, got %s\n", keyUsages[i], + usage->rgpszUsageIdentifier[i]); + LocalFree(buf); + } +} + +static BYTE keyId[] = { 1,2,3,4 }; +static const BYTE authorityKeyIdWithId[] = { + 0x30,0x06,0x80,0x04,0x01,0x02,0x03,0x04 }; +static const BYTE authorityKeyIdWithIssuer[] = { 0x30,0x19,0xa1,0x17,0x30,0x15, + 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, + 0x20,0x4c,0x61,0x6e,0x67,0x00 }; +static const BYTE authorityKeyIdWithSerial[] = { 0x30,0x03,0x82,0x01,0x01 }; + +static void test_encodeAuthorityKeyId(DWORD dwEncoding) +{ + CERT_AUTHORITY_KEY_ID_INFO info = { { 0 } }; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + + /* Test with empty id */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptySequence), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "Unexpected value\n"); + LocalFree(buf); + } + /* With just a key id */ + info.KeyId.cbData = sizeof(keyId); + info.KeyId.pbData = keyId; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithId), "Unexpected size %d\n", size); + ok(!memcmp(buf, authorityKeyIdWithId, size), "Unexpected value\n"); + LocalFree(buf); + } + /* With just an issuer */ + info.KeyId.cbData = 0; + info.CertIssuer.cbData = sizeof(encodedCommonName); + info.CertIssuer.pbData = (BYTE *)encodedCommonName; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithIssuer), "Unexpected size %d\n", + size); + ok(!memcmp(buf, authorityKeyIdWithIssuer, size), "Unexpected value\n"); + LocalFree(buf); + } + /* With just a serial number */ + info.CertIssuer.cbData = 0; + info.CertSerialNumber.cbData = sizeof(serialNum); + info.CertSerialNumber.pbData = (BYTE *)serialNum; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithSerial), "Unexpected size %d\n", + size); + ok(!memcmp(buf, authorityKeyIdWithSerial, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeAuthorityKeyId(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID_INFO *info = (CERT_AUTHORITY_KEY_ID_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->CertIssuer.cbData == 0, "Expected no issuer name\n"); + ok(info->CertSerialNumber.cbData == 0, "Expected no serial number\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, + authorityKeyIdWithId, sizeof(authorityKeyIdWithId), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID_INFO *info = (CERT_AUTHORITY_KEY_ID_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == sizeof(keyId), "Unexpected key id len\n"); + ok(!memcmp(info->KeyId.pbData, keyId, sizeof(keyId)), + "Unexpected key id\n"); + ok(info->CertIssuer.cbData == 0, "Expected no issuer name\n"); + ok(info->CertSerialNumber.cbData == 0, "Expected no serial number\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, + authorityKeyIdWithIssuer, sizeof(authorityKeyIdWithIssuer), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID_INFO *info = (CERT_AUTHORITY_KEY_ID_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->CertIssuer.cbData == sizeof(encodedCommonName), + "Unexpected issuer len\n"); + ok(!memcmp(info->CertIssuer.pbData, encodedCommonName, + sizeof(encodedCommonName)), "Unexpected issuer\n"); + ok(info->CertSerialNumber.cbData == 0, "Expected no serial number\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID, + authorityKeyIdWithSerial, sizeof(authorityKeyIdWithSerial), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID_INFO *info = (CERT_AUTHORITY_KEY_ID_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->CertIssuer.cbData == 0, "Expected no issuer name\n"); + ok(info->CertSerialNumber.cbData == sizeof(serialNum), + "Unexpected serial number len\n"); + ok(!memcmp(info->CertSerialNumber.pbData, serialNum, sizeof(serialNum)), + "Unexpected serial number\n"); + LocalFree(buf); + } +} + +static const BYTE authorityKeyIdWithIssuerUrl[] = { 0x30,0x15,0xa1,0x13,0x86, + 0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e, + 0x6f,0x72,0x67 }; + +static void test_encodeAuthorityKeyId2(DWORD dwEncoding) +{ + CERT_AUTHORITY_KEY_ID2_INFO info = { { 0 } }; + CERT_ALT_NAME_ENTRY entry = { 0 }; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + + /* Test with empty id */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptySequence), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "Unexpected value\n"); + LocalFree(buf); + } + /* With just a key id */ + info.KeyId.cbData = sizeof(keyId); + info.KeyId.pbData = keyId; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithId), "Unexpected size %d\n", + size); + ok(!memcmp(buf, authorityKeyIdWithId, size), "Unexpected value\n"); + LocalFree(buf); + } + /* With a bogus issuer name */ + info.KeyId.cbData = 0; + info.AuthorityCertIssuer.cAltEntry = 1; + info.AuthorityCertIssuer.rgAltEntry = &entry; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* With an issuer name */ + entry.dwAltNameChoice = CERT_ALT_NAME_URL; + U(entry).pwszURL = (LPWSTR)url; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithIssuerUrl), "Unexpected size %d\n", + size); + ok(!memcmp(buf, authorityKeyIdWithIssuerUrl, size), + "Unexpected value\n"); + LocalFree(buf); + } + /* With just a serial number */ + info.AuthorityCertIssuer.cAltEntry = 0; + info.AuthorityCertSerialNumber.cbData = sizeof(serialNum); + info.AuthorityCertSerialNumber.pbData = (BYTE *)serialNum; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityKeyIdWithSerial), "Unexpected size %d\n", + size); + ok(!memcmp(buf, authorityKeyIdWithSerial, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeAuthorityKeyId2(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID2_INFO *info = (CERT_AUTHORITY_KEY_ID2_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID2_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->AuthorityCertIssuer.cAltEntry == 0, + "Expected no issuer name entries\n"); + ok(info->AuthorityCertSerialNumber.cbData == 0, + "Expected no serial number\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, + authorityKeyIdWithId, sizeof(authorityKeyIdWithId), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID2_INFO *info = (CERT_AUTHORITY_KEY_ID2_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID2_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == sizeof(keyId), "Unexpected key id len\n"); + ok(!memcmp(info->KeyId.pbData, keyId, sizeof(keyId)), + "Unexpected key id\n"); + ok(info->AuthorityCertIssuer.cAltEntry == 0, + "Expected no issuer name entries\n"); + ok(info->AuthorityCertSerialNumber.cbData == 0, + "Expected no serial number\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, + authorityKeyIdWithIssuerUrl, sizeof(authorityKeyIdWithIssuerUrl), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID2_INFO *info = (CERT_AUTHORITY_KEY_ID2_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID2_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->AuthorityCertIssuer.cAltEntry == 1, + "Expected 1 issuer entry, got %d\n", + info->AuthorityCertIssuer.cAltEntry); + ok(info->AuthorityCertIssuer.rgAltEntry[0].dwAltNameChoice == + CERT_ALT_NAME_URL, "Expected CERT_ALT_NAME_URL, got %d\n", + info->AuthorityCertIssuer.rgAltEntry[0].dwAltNameChoice); + ok(!lstrcmpW(U(info->AuthorityCertIssuer.rgAltEntry[0]).pwszURL, + url), "Unexpected URL\n"); + ok(info->AuthorityCertSerialNumber.cbData == 0, + "Expected no serial number\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_KEY_ID2, + authorityKeyIdWithSerial, sizeof(authorityKeyIdWithSerial), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_KEY_ID2_INFO *info = (CERT_AUTHORITY_KEY_ID2_INFO *)buf; + + ok(size >= sizeof(CERT_AUTHORITY_KEY_ID2_INFO), "Unexpected size %d\n", + size); + ok(info->KeyId.cbData == 0, "Expected no key id\n"); + ok(info->AuthorityCertIssuer.cAltEntry == 0, + "Expected no issuer name entries\n"); + ok(info->AuthorityCertSerialNumber.cbData == sizeof(serialNum), + "Unexpected serial number len\n"); + ok(!memcmp(info->AuthorityCertSerialNumber.pbData, serialNum, + sizeof(serialNum)), "Unexpected serial number\n"); + LocalFree(buf); + } +} + +static const BYTE authorityInfoAccessWithUrl[] = { +0x30,0x19,0x30,0x17,0x06,0x02,0x2a,0x03,0x86,0x11,0x68,0x74,0x74,0x70,0x3a, +0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67 }; +static const BYTE authorityInfoAccessWithUrlAndIPAddr[] = { +0x30,0x29,0x30,0x17,0x06,0x02,0x2a,0x03,0x86,0x11,0x68,0x74,0x74,0x70,0x3a, +0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67,0x30,0x0e,0x06, +0x02,0x2d,0x06,0x87,0x08,0x30,0x06,0x87,0x04,0x7f,0x00,0x00,0x01 }; + +static void test_encodeAuthorityInfoAccess(DWORD dwEncoding) +{ + static char oid1[] = "1.2.3"; + static char oid2[] = "1.5.6"; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CERT_ACCESS_DESCRIPTION accessDescription[2]; + CERT_AUTHORITY_INFO_ACCESS aia; + + memset(accessDescription, 0, sizeof(accessDescription)); + aia.cAccDescr = 0; + aia.rgAccDescr = NULL; + /* Having no access descriptions is allowed */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS, &aia, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptySequence), "unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + /* It can't have an empty access method */ + aia.cAccDescr = 1; + aia.rgAccDescr = accessDescription; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS, &aia, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x */), + "expected E_INVALIDARG or OSS_LIMITED, got %08x\n", GetLastError()); + /* It can't have an empty location */ + accessDescription[0].pszAccessMethod = oid1; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS, &aia, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + accessDescription[0].AccessLocation.dwAltNameChoice = CERT_ALT_NAME_URL; + U(accessDescription[0].AccessLocation).pwszURL = (LPWSTR)url; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS, &aia, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityInfoAccessWithUrl), "unexpected size %d\n", + size); + ok(!memcmp(buf, authorityInfoAccessWithUrl, size), + "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + accessDescription[1].pszAccessMethod = oid2; + accessDescription[1].AccessLocation.dwAltNameChoice = + CERT_ALT_NAME_IP_ADDRESS; + U(accessDescription[1].AccessLocation).IPAddress.cbData = + sizeof(encodedIPAddr); + U(accessDescription[1].AccessLocation).IPAddress.pbData = + (LPBYTE)encodedIPAddr; + aia.cAccDescr = 2; + ret = pCryptEncodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS, &aia, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(authorityInfoAccessWithUrlAndIPAddr), + "unexpected size %d\n", size); + ok(!memcmp(buf, authorityInfoAccessWithUrlAndIPAddr, size), + "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } +} + +static void compareAuthorityInfoAccess(LPCSTR header, + const CERT_AUTHORITY_INFO_ACCESS *expected, + const CERT_AUTHORITY_INFO_ACCESS *got) +{ + DWORD i; + + ok(expected->cAccDescr == got->cAccDescr, + "%s: expected %d access descriptions, got %d\n", header, + expected->cAccDescr, got->cAccDescr); + for (i = 0; i < expected->cAccDescr; i++) + { + ok(!strcmp(expected->rgAccDescr[i].pszAccessMethod, + got->rgAccDescr[i].pszAccessMethod), "%s[%d]: expected %s, got %s\n", + header, i, expected->rgAccDescr[i].pszAccessMethod, + got->rgAccDescr[i].pszAccessMethod); + compareAltNameEntry(&expected->rgAccDescr[i].AccessLocation, + &got->rgAccDescr[i].AccessLocation); + } +} + +static void test_decodeAuthorityInfoAccess(DWORD dwEncoding) +{ + static char oid1[] = "1.2.3"; + static char oid2[] = "1.5.6"; + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + CERT_AUTHORITY_INFO_ACCESS aia = { 0, NULL }; + + compareAuthorityInfoAccess("empty AIA", &aia, + (CERT_AUTHORITY_INFO_ACCESS *)buf); + LocalFree(buf); + buf = NULL; + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS, + authorityInfoAccessWithUrl, sizeof(authorityInfoAccessWithUrl), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + CERT_ACCESS_DESCRIPTION accessDescription; + CERT_AUTHORITY_INFO_ACCESS aia; + + accessDescription.pszAccessMethod = oid1; + accessDescription.AccessLocation.dwAltNameChoice = CERT_ALT_NAME_URL; + U(accessDescription.AccessLocation).pwszURL = (LPWSTR)url; + aia.cAccDescr = 1; + aia.rgAccDescr = &accessDescription; + compareAuthorityInfoAccess("AIA with URL", &aia, + (CERT_AUTHORITY_INFO_ACCESS *)buf); + LocalFree(buf); + buf = NULL; + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_AUTHORITY_INFO_ACCESS, + authorityInfoAccessWithUrlAndIPAddr, + sizeof(authorityInfoAccessWithUrlAndIPAddr), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + CERT_ACCESS_DESCRIPTION accessDescription[2]; + CERT_AUTHORITY_INFO_ACCESS aia; + + accessDescription[0].pszAccessMethod = oid1; + accessDescription[0].AccessLocation.dwAltNameChoice = CERT_ALT_NAME_URL; + U(accessDescription[0].AccessLocation).pwszURL = (LPWSTR)url; + accessDescription[1].pszAccessMethod = oid2; + accessDescription[1].AccessLocation.dwAltNameChoice = + CERT_ALT_NAME_IP_ADDRESS; + U(accessDescription[1].AccessLocation).IPAddress.cbData = + sizeof(encodedIPAddr); + U(accessDescription[1].AccessLocation).IPAddress.pbData = + (LPBYTE)encodedIPAddr; + aia.cAccDescr = 2; + aia.rgAccDescr = accessDescription; + compareAuthorityInfoAccess("AIA with URL and IP addr", &aia, + (CERT_AUTHORITY_INFO_ACCESS *)buf); + LocalFree(buf); + buf = NULL; + } +} + +static const BYTE emptyCTL[] = { +0x30,0x17,0x30,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00 }; +static const BYTE emptyCTLWithVersion1[] = { +0x30,0x1a,0x02,0x01,0x01,0x30,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00 }; +static const BYTE ctlWithUsageIdentifier[] = { +0x30,0x1b,0x30,0x04,0x06,0x02,0x2a,0x03,0x18,0x0f,0x31,0x36,0x30,0x31,0x30, +0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00 }; +static const BYTE ctlWithListIdentifier[] = { +0x30,0x1a,0x30,0x00,0x04,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00 }; +static const BYTE ctlWithSequenceNumber[] = { +0x30,0x1a,0x30,0x00,0x02,0x01,0x01,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00 }; +static const BYTE ctlWithThisUpdate[] = { +0x30,0x15,0x30,0x00,0x17,0x0d,0x30,0x35,0x30,0x36,0x30,0x36,0x31,0x36,0x31, +0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00 }; +static const BYTE ctlWithThisAndNextUpdate[] = { +0x30,0x24,0x30,0x00,0x17,0x0d,0x30,0x35,0x30,0x36,0x30,0x36,0x31,0x36,0x31, +0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x35,0x30,0x36,0x30,0x36,0x31,0x36,0x31, +0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00 }; +static const BYTE ctlWithAlgId[] = { +0x30,0x1b,0x30,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x06,0x06,0x02,0x2d,0x06,0x05,0x00 }; +static const BYTE ctlWithBogusEntry[] = { +0x30,0x29,0x30,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00,0x30,0x10,0x30,0x0e,0x04, +0x01,0x01,0x31,0x09,0x30,0x07,0x06,0x02,0x2a,0x03,0x31,0x01,0x01 }; +static const BYTE ctlWithOneEntry[] = { +0x30,0x2a,0x30,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00,0x30,0x11,0x30,0x0f,0x04, +0x01,0x01,0x31,0x0a,0x30,0x08,0x06,0x02,0x2a,0x03,0x31,0x02,0x30,0x00 }; +static const BYTE ctlWithTwoEntries[] = { +0x30,0x41,0x30,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00,0x30,0x28,0x30,0x0f,0x04, +0x01,0x01,0x31,0x0a,0x30,0x08,0x06,0x02,0x2a,0x03,0x31,0x02,0x30,0x00,0x30, +0x15,0x04,0x01,0x01,0x31,0x10,0x30,0x0e,0x06,0x02,0x2d,0x06,0x31,0x08,0x30, +0x06,0x87,0x04,0x7f,0x00,0x00,0x01 }; + +static void test_encodeCTL(DWORD dwEncoding) +{ + static char oid1[] = "1.2.3"; + static char oid2[] = "1.5.6"; + char *pOid1 = oid1; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CTL_INFO info; + SYSTEMTIME thisUpdate = { 2005, 6, 1, 6, 16, 10, 0, 0 }; + CTL_ENTRY ctlEntry[2]; + CRYPT_ATTRIBUTE attr1, attr2; + CRYPT_ATTR_BLOB value1, value2; + + memset(&info, 0, sizeof(info)); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptyCTL), "unexpected size %d\n", size); + ok(!memcmp(buf, emptyCTL, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + info.dwVersion = 1; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptyCTLWithVersion1), "unexpected size %d\n", size); + ok(!memcmp(buf, emptyCTLWithVersion1, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + info.dwVersion = 0; + info.SubjectUsage.cUsageIdentifier = 1; + info.SubjectUsage.rgpszUsageIdentifier = &pOid1; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithUsageIdentifier), "unexpected size %d\n", + size); + ok(!memcmp(buf, ctlWithUsageIdentifier, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + info.SubjectUsage.cUsageIdentifier = 0; + info.ListIdentifier.cbData = sizeof(serialNum); + info.ListIdentifier.pbData = (LPBYTE)serialNum; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithListIdentifier), "unexpected size %d\n", size); + ok(!memcmp(buf, ctlWithListIdentifier, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + info.ListIdentifier.cbData = 0; + info.SequenceNumber.cbData = sizeof(serialNum); + info.SequenceNumber.pbData = (LPBYTE)serialNum; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithSequenceNumber), "unexpected size %d\n", + size); + ok(!memcmp(buf, ctlWithSequenceNumber, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + info.SequenceNumber.cbData = 0; + SystemTimeToFileTime(&thisUpdate, &info.ThisUpdate); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithThisUpdate), "unexpected size %d\n", size); + ok(!memcmp(buf, ctlWithThisUpdate, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + SystemTimeToFileTime(&thisUpdate, &info.NextUpdate); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithThisAndNextUpdate), "unexpected size %d\n", + size); + ok(!memcmp(buf, ctlWithThisAndNextUpdate, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + info.ThisUpdate.dwLowDateTime = info.ThisUpdate.dwHighDateTime = 0; + info.NextUpdate.dwLowDateTime = info.NextUpdate.dwHighDateTime = 0; + info.SubjectAlgorithm.pszObjId = oid2; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithAlgId), "unexpected size %d\n", size); + ok(!memcmp(buf, ctlWithAlgId, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + /* The value is supposed to be asn.1 encoded, so this'll fail to decode + * (see tests below) but it'll encode fine. + */ + info.SubjectAlgorithm.pszObjId = NULL; + value1.cbData = sizeof(serialNum); + value1.pbData = (LPBYTE)serialNum; + attr1.pszObjId = oid1; + attr1.cValue = 1; + attr1.rgValue = &value1; + ctlEntry[0].SubjectIdentifier.cbData = sizeof(serialNum); + ctlEntry[0].SubjectIdentifier.pbData = (LPBYTE)serialNum; + ctlEntry[0].cAttribute = 1; + ctlEntry[0].rgAttribute = &attr1; + info.cCTLEntry = 1; + info.rgCTLEntry = ctlEntry; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithBogusEntry), "unexpected size %d\n", size); + ok(!memcmp(buf, ctlWithBogusEntry, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + value1.cbData = sizeof(emptySequence); + value1.pbData = (LPBYTE)emptySequence; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithOneEntry), "unexpected size %d\n", size); + ok(!memcmp(buf, ctlWithOneEntry, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } + value2.cbData = sizeof(encodedIPAddr); + value2.pbData = (LPBYTE)encodedIPAddr; + attr2.pszObjId = oid2; + attr2.cValue = 1; + attr2.rgValue = &value2; + ctlEntry[1].SubjectIdentifier.cbData = sizeof(serialNum); + ctlEntry[1].SubjectIdentifier.pbData = (LPBYTE)serialNum; + ctlEntry[1].cAttribute = 1; + ctlEntry[1].rgAttribute = &attr2; + info.cCTLEntry = 2; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CTL, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(ctlWithTwoEntries), "unexpected size %d\n", size); + ok(!memcmp(buf, ctlWithTwoEntries, size), "unexpected value\n"); + LocalFree(buf); + buf = NULL; + } +} + +static void compareCTLInfo(LPCSTR header, const CTL_INFO *expected, + const CTL_INFO *got) +{ + DWORD i, j, k; + + ok(expected->dwVersion == got->dwVersion, + "%s: expected version %d, got %d\n", header, expected->dwVersion, + got->dwVersion); + ok(expected->SubjectUsage.cUsageIdentifier == + got->SubjectUsage.cUsageIdentifier, + "%s: expected %d usage identifiers, got %d\n", header, + expected->SubjectUsage.cUsageIdentifier, + got->SubjectUsage.cUsageIdentifier); + for (i = 0; i < expected->SubjectUsage.cUsageIdentifier; i++) + ok(!strcmp(expected->SubjectUsage.rgpszUsageIdentifier[i], + got->SubjectUsage.rgpszUsageIdentifier[i]), + "%s[%d]: expected %s, got %s\n", header, i, + expected->SubjectUsage.rgpszUsageIdentifier[i], + got->SubjectUsage.rgpszUsageIdentifier[i]); + ok(expected->ListIdentifier.cbData == got->ListIdentifier.cbData, + "%s: expected list identifier of %d bytes, got %d\n", header, + expected->ListIdentifier.cbData, got->ListIdentifier.cbData); + if (expected->ListIdentifier.cbData) + ok(!memcmp(expected->ListIdentifier.pbData, got->ListIdentifier.pbData, + expected->ListIdentifier.cbData), + "%s: unexpected list identifier value\n", header); + ok(expected->SequenceNumber.cbData == got->SequenceNumber.cbData, + "%s: expected sequence number of %d bytes, got %d\n", header, + expected->SequenceNumber.cbData, got->SequenceNumber.cbData); + if (expected->SequenceNumber.cbData) + ok(!memcmp(expected->SequenceNumber.pbData, got->SequenceNumber.pbData, + expected->SequenceNumber.cbData), + "%s: unexpected sequence number value\n", header); + ok(!memcmp(&expected->ThisUpdate, &got->ThisUpdate, sizeof(FILETIME)), + "%s: expected this update = (%d, %d), got (%d, %d)\n", header, + expected->ThisUpdate.dwLowDateTime, expected->ThisUpdate.dwHighDateTime, + got->ThisUpdate.dwLowDateTime, got->ThisUpdate.dwHighDateTime); + ok(!memcmp(&expected->NextUpdate, &got->NextUpdate, sizeof(FILETIME)), + "%s: expected next update = (%d, %d), got (%d, %d)\n", header, + expected->NextUpdate.dwLowDateTime, expected->NextUpdate.dwHighDateTime, + got->NextUpdate.dwLowDateTime, got->NextUpdate.dwHighDateTime); + if (expected->SubjectAlgorithm.pszObjId && + *expected->SubjectAlgorithm.pszObjId && !got->SubjectAlgorithm.pszObjId) + ok(0, "%s: expected subject algorithm %s, got NULL\n", header, + expected->SubjectAlgorithm.pszObjId); + if (expected->SubjectAlgorithm.pszObjId && got->SubjectAlgorithm.pszObjId) + ok(!strcmp(expected->SubjectAlgorithm.pszObjId, + got->SubjectAlgorithm.pszObjId), + "%s: expected subject algorithm %s, got %s\n", header, + expected->SubjectAlgorithm.pszObjId, got->SubjectAlgorithm.pszObjId); + ok(expected->SubjectAlgorithm.Parameters.cbData == + got->SubjectAlgorithm.Parameters.cbData, + "%s: expected subject algorithm parameters of %d bytes, got %d\n", header, + expected->SubjectAlgorithm.Parameters.cbData, + got->SubjectAlgorithm.Parameters.cbData); + if (expected->SubjectAlgorithm.Parameters.cbData) + ok(!memcmp(expected->SubjectAlgorithm.Parameters.pbData, + got->SubjectAlgorithm.Parameters.pbData, + expected->SubjectAlgorithm.Parameters.cbData), + "%s: unexpected subject algorithm parameter value\n", header); + ok(expected->cCTLEntry == got->cCTLEntry, + "%s: expected %d CTL entries, got %d\n", header, expected->cCTLEntry, + got->cCTLEntry); + for (i = 0; i < expected->cCTLEntry; i++) + { + ok(expected->rgCTLEntry[i].SubjectIdentifier.cbData == + got->rgCTLEntry[i].SubjectIdentifier.cbData, + "%s[%d]: expected subject identifier of %d bytes, got %d\n", + header, i, expected->rgCTLEntry[i].SubjectIdentifier.cbData, + got->rgCTLEntry[i].SubjectIdentifier.cbData); + if (expected->rgCTLEntry[i].SubjectIdentifier.cbData) + ok(!memcmp(expected->rgCTLEntry[i].SubjectIdentifier.pbData, + got->rgCTLEntry[i].SubjectIdentifier.pbData, + expected->rgCTLEntry[i].SubjectIdentifier.cbData), + "%s[%d]: unexpected subject identifier value\n", + header, i); + for (j = 0; j < expected->rgCTLEntry[i].cAttribute; j++) + { + ok(!strcmp(expected->rgCTLEntry[i].rgAttribute[j].pszObjId, + got->rgCTLEntry[i].rgAttribute[j].pszObjId), + "%s[%d][%d]: expected attribute OID %s, got %s\n", header, i, j, + expected->rgCTLEntry[i].rgAttribute[j].pszObjId, + got->rgCTLEntry[i].rgAttribute[j].pszObjId); + for (k = 0; k < expected->rgCTLEntry[i].rgAttribute[j].cValue; k++) + { + ok(expected->rgCTLEntry[i].rgAttribute[j].rgValue[k].cbData == + got->rgCTLEntry[i].rgAttribute[j].rgValue[k].cbData, + "%s[%d][%d][%d]: expected value of %d bytes, got %d\n", + header, i, j, k, + expected->rgCTLEntry[i].rgAttribute[j].rgValue[k].cbData, + got->rgCTLEntry[i].rgAttribute[j].rgValue[k].cbData); + if (expected->rgCTLEntry[i].rgAttribute[j].rgValue[k].cbData) + ok(!memcmp( + expected->rgCTLEntry[i].rgAttribute[j].rgValue[k].pbData, + got->rgCTLEntry[i].rgAttribute[j].rgValue[k].pbData, + expected->rgCTLEntry[i].rgAttribute[j].rgValue[k].cbData), + "%s[%d][%d][%d]: unexpected value\n", + header, i, j, k); + } + } + } + ok(expected->cExtension == got->cExtension, + "%s: expected %d extensions, got %d\n", header, expected->cExtension, + got->cExtension); + for (i = 0; i < expected->cExtension; i++) + { + ok(!strcmp(expected->rgExtension[i].pszObjId, + got->rgExtension[i].pszObjId), "%s[%d]: expected %s, got %s\n", + header, i, expected->rgExtension[i].pszObjId, + got->rgExtension[i].pszObjId); + ok(expected->rgExtension[i].fCritical == got->rgExtension[i].fCritical, + "%s[%d]: expected fCritical = %d, got %d\n", header, i, + expected->rgExtension[i].fCritical, got->rgExtension[i].fCritical); + ok(expected->rgExtension[i].Value.cbData == + got->rgExtension[i].Value.cbData, + "%s[%d]: expected extension value to have %d bytes, got %d\n", + header, i, expected->rgExtension[i].Value.cbData, + got->rgExtension[i].Value.cbData); + if (expected->rgExtension[i].Value.cbData) + ok(!memcmp(expected->rgExtension[i].Value.pbData, + got->rgExtension[i].Value.pbData, + expected->rgExtension[i].Value.cbData), + "%s[%d]: unexpected extension value\n", header, i); + } +} + +static const BYTE signedCTL[] = { +0x30,0x81,0xc7,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0xb9,0x30,0x81,0xb6,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x28,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x1b,0x04,0x19,0x30,0x17,0x30,0x00, +0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x30,0x02,0x06,0x00,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a, +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05, +0x00,0x04,0x40,0xca,0xd8,0x32,0xd1,0xbd,0x97,0x61,0x54,0xd6,0x80,0xcf,0x0d, +0xbd,0xa2,0x42,0xc7,0xca,0x37,0x91,0x7d,0x9d,0xac,0x8c,0xdf,0x05,0x8a,0x39, +0xc6,0x07,0xc1,0x37,0xe6,0xb9,0xd1,0x0d,0x26,0xec,0xa5,0xb0,0x8a,0x51,0x26, +0x2b,0x4f,0x73,0x44,0x86,0x83,0x5e,0x2b,0x6e,0xcc,0xf8,0x1b,0x85,0x53,0xe9, +0x7a,0x80,0x8f,0x6b,0x42,0x19,0x93 }; +static const BYTE signedCTLWithCTLInnerContent[] = { +0x30,0x82,0x01,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x82,0x01,0x00,0x30,0x81,0xfd,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06, +0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x30,0x06,0x09, +0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x0a,0x01,0xa0,0x23,0x30,0x21,0x30,0x00, +0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30, +0x30,0x5a,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05, +0x00,0x31,0x81,0xb5,0x30,0x81,0xb2,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31, +0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0xa0,0x3b,0x30,0x18,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x09,0x03,0x31,0x0b,0x06,0x09,0x2b,0x06,0x01,0x04, +0x01,0x82,0x37,0x0a,0x01,0x30,0x1f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x09,0x04,0x31,0x12,0x04,0x10,0x54,0x71,0xbc,0xe1,0x56,0x31,0xa2,0xf9, +0x65,0x70,0x34,0xf8,0xe2,0xe9,0xb4,0xf4,0x30,0x04,0x06,0x00,0x05,0x00,0x04, +0x40,0x2f,0x1b,0x9f,0x5a,0x4a,0x15,0x73,0xfa,0xb1,0x93,0x3d,0x09,0x52,0xdf, +0x6b,0x98,0x4b,0x13,0x5e,0xe7,0xbf,0x65,0xf4,0x9c,0xc2,0xb1,0x77,0x09,0xb1, +0x66,0x4d,0x72,0x0d,0xb1,0x1a,0x50,0x20,0xe0,0x57,0xa2,0x39,0xc7,0xcd,0x7f, +0x8e,0xe7,0x5f,0x76,0x2b,0xd1,0x6a,0x82,0xb3,0x30,0x25,0x61,0xf6,0x25,0x23, +0x57,0x6c,0x0b,0x47,0xb8 }; + +static void test_decodeCTL(DWORD dwEncoding) +{ + static char oid1[] = "1.2.3"; + static char oid2[] = "1.5.6"; + static BYTE nullData[] = { 5,0 }; + char *pOid1 = oid1; + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CTL_INFO info; + SYSTEMTIME thisUpdate = { 2005, 6, 1, 6, 16, 10, 0, 0 }; + CTL_ENTRY ctlEntry[2]; + CRYPT_ATTRIBUTE attr1, attr2; + CRYPT_ATTR_BLOB value1, value2; + + memset(&info, 0, sizeof(info)); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, emptyCTL, sizeof(emptyCTL), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("empty CTL", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + info.dwVersion = 1; + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, emptyCTLWithVersion1, + sizeof(emptyCTLWithVersion1), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, + &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("v1 CTL", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + info.dwVersion = 0; + info.SubjectUsage.cUsageIdentifier = 1; + info.SubjectUsage.rgpszUsageIdentifier = &pOid1; + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithUsageIdentifier, + sizeof(ctlWithUsageIdentifier), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("CTL with usage identifier", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + info.SubjectUsage.cUsageIdentifier = 0; + info.ListIdentifier.cbData = sizeof(serialNum); + info.ListIdentifier.pbData = (LPBYTE)serialNum; + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithListIdentifier, + sizeof(ctlWithListIdentifier), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("CTL with list identifier", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + info.ListIdentifier.cbData = 0; + info.SequenceNumber.cbData = sizeof(serialNum); + info.SequenceNumber.pbData = (LPBYTE)serialNum; + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithSequenceNumber, + sizeof(ctlWithSequenceNumber), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("CTL with sequence number", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + info.SequenceNumber.cbData = 0; + SystemTimeToFileTime(&thisUpdate, &info.ThisUpdate); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithThisUpdate, + sizeof(ctlWithThisUpdate), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("CTL with this update", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + SystemTimeToFileTime(&thisUpdate, &info.NextUpdate); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithThisAndNextUpdate, + sizeof(ctlWithThisAndNextUpdate), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("CTL with this and next update", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + info.ThisUpdate.dwLowDateTime = info.ThisUpdate.dwHighDateTime = 0; + info.NextUpdate.dwLowDateTime = info.NextUpdate.dwHighDateTime = 0; + info.SubjectAlgorithm.pszObjId = oid2; + info.SubjectAlgorithm.Parameters.cbData = sizeof(nullData); + info.SubjectAlgorithm.Parameters.pbData = nullData; + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithAlgId, + sizeof(ctlWithAlgId), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("CTL with algorithm identifier", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithBogusEntry, + sizeof(ctlWithBogusEntry), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_MORE_INPUT), /* Win9x */ + "expected CRYPT_E_ASN1_EOD or CRYPT_E_ASN1_CORRUPT, got %08x\n", + GetLastError()); + info.SubjectAlgorithm.Parameters.cbData = 0; + info.ThisUpdate.dwLowDateTime = info.ThisUpdate.dwHighDateTime = 0; + info.NextUpdate.dwLowDateTime = info.NextUpdate.dwHighDateTime = 0; + info.SubjectAlgorithm.pszObjId = oid2; + info.SubjectAlgorithm.pszObjId = NULL; + value1.cbData = sizeof(emptySequence); + value1.pbData = (LPBYTE)emptySequence; + attr1.pszObjId = oid1; + attr1.cValue = 1; + attr1.rgValue = &value1; + ctlEntry[0].SubjectIdentifier.cbData = sizeof(serialNum); + ctlEntry[0].SubjectIdentifier.pbData = (LPBYTE)serialNum; + ctlEntry[0].cAttribute = 1; + ctlEntry[0].rgAttribute = &attr1; + info.cCTLEntry = 1; + info.rgCTLEntry = ctlEntry; + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithOneEntry, + sizeof(ctlWithOneEntry), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("CTL with one entry", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + value2.cbData = sizeof(encodedIPAddr); + value2.pbData = (LPBYTE)encodedIPAddr; + attr2.pszObjId = oid2; + attr2.cValue = 1; + attr2.rgValue = &value2; + ctlEntry[1].SubjectIdentifier.cbData = sizeof(serialNum); + ctlEntry[1].SubjectIdentifier.pbData = (LPBYTE)serialNum; + ctlEntry[1].cAttribute = 1; + ctlEntry[1].rgAttribute = &attr2; + info.cCTLEntry = 2; + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, ctlWithTwoEntries, + sizeof(ctlWithTwoEntries), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + compareCTLInfo("CTL with two entries", &info, (CTL_INFO *)buf); + LocalFree(buf); + buf = NULL; + } + /* A signed CTL isn't decodable, even if the inner content is a CTL */ + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, signedCTL, + sizeof(signedCTL), CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "expected CRYPT_E_ASN1_BADTAG or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CTL, + signedCTLWithCTLInnerContent, sizeof(signedCTLWithCTLInnerContent), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "expected CRYPT_E_ASN1_BADTAG or OSS_DATA_ERROR, got %08x\n", + GetLastError()); +} + +static const BYTE emptyPKCSContentInfo[] = { 0x30,0x04,0x06,0x02,0x2a,0x03 }; +static const BYTE emptyPKCSContentInfoExtraBytes[] = { 0x30,0x04,0x06,0x02,0x2a, + 0x03,0,0,0,0,0,0 }; +static const BYTE bogusPKCSContentInfo[] = { 0x30,0x07,0x06,0x02,0x2a,0x03, + 0xa0,0x01,0x01 }; +static const BYTE intPKCSContentInfo[] = { 0x30,0x09,0x06,0x02,0x2a,0x03,0xa0, + 0x03,0x02,0x01,0x01 }; +static BYTE bogusDER[] = { 1 }; + +static void test_encodePKCSContentInfo(DWORD dwEncoding) +{ + BOOL ret; + BYTE *buf = NULL; + DWORD size = 0; + CRYPT_CONTENT_INFO info = { 0 }; + char oid1[] = "1.2.3"; + + if (0) + { + /* Crashes on win9x */ + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, NULL, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError()); + } + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x */), + "Expected E_INVALIDARG or OSS_LIMITED, got %x\n", GetLastError()); + info.pszObjId = oid1; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptyPKCSContentInfo), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyPKCSContentInfo, size), "Unexpected value\n"); + LocalFree(buf); + } + info.Content.pbData = bogusDER; + info.Content.cbData = sizeof(bogusDER); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed; %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(bogusPKCSContentInfo), "Unexpected size %d\n", size); + ok(!memcmp(buf, bogusPKCSContentInfo, size), "Unexpected value\n"); + LocalFree(buf); + } + info.Content.pbData = (BYTE *)ints[0].encoded; + info.Content.cbData = ints[0].encoded[1] + 2; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(intPKCSContentInfo), "Unexpected size %d\n", size); + ok(!memcmp(buf, intPKCSContentInfo, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static const BYTE indefiniteSignedPKCSContent[] = { +0x30,0x80,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,0x80, +0x30,0x80,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x80,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80,0x04,0x04,0x01,0x02,0x03,0x04,0x04, +0x04,0x01,0x02,0x03,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x81,0xd2,0x30, +0x81,0xcf,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67, +0x00,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01, +0x01,0x05,0x00,0x03,0x4b,0x00,0x30,0x48,0x02,0x41,0x00,0xe2,0x54,0x3a,0xa7, +0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb,0xb4,0x53,0xe6,0x1f,0xe7,0x5d,0xf1,0x21, +0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb,0x65,0x97,0x03,0x86,0x60,0xde,0xf3, +0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc,0x62,0x17,0xa9,0xcd,0x79,0x3f,0x21, +0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30,0x18,0x10,0x6b,0xd0,0x1c,0x10,0x79, +0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d, +0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x31, +0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67, +0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02, +0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x57,0xba,0xe0,0xad, +0xfe,0x36,0x8d,0xb3,0x88,0xa2,0x8d,0x84,0x82,0x52,0x09,0x09,0xd9,0xf0,0xb8, +0x04,0xfa,0xb5,0x51,0x0b,0x2b,0x2e,0xd5,0x72,0x3e,0x3d,0x13,0x8a,0x51,0xc3, +0x71,0x65,0x9a,0x52,0xf2,0x8f,0xb2,0x5b,0x39,0x28,0xb3,0x29,0x36,0xa5,0x8d, +0xe3,0x55,0x71,0x91,0xf9,0x2a,0xd1,0xb8,0xaa,0x52,0xb8,0x22,0x3a,0xeb,0x61, +0x00,0x00,0x00,0x00,0x00,0x00 }; + +static void test_decodePKCSContentInfo(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CRYPT_CONTENT_INFO *info; + + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, + emptyPKCSContentInfo, sizeof(emptyPKCSContentInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CRYPT_CONTENT_INFO *)buf; + + ok(!strcmp(info->pszObjId, "1.2.3"), "Expected 1.2.3, got %s\n", + info->pszObjId); + ok(info->Content.cbData == 0, "Expected no data, got %d\n", + info->Content.cbData); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, + emptyPKCSContentInfoExtraBytes, sizeof(emptyPKCSContentInfoExtraBytes), + 0, NULL, NULL, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, + bogusPKCSContentInfo, sizeof(bogusPKCSContentInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + /* Native fails with CRYPT_E_ASN1_EOD, accept also CRYPT_E_ASN1_CORRUPT as + * I doubt an app depends on that. + */ + ok((!ret && (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == CRYPT_E_ASN1_CORRUPT)) || broken(ret), + "Expected CRYPT_E_ASN1_EOD or CRYPT_E_ASN1_CORRUPT, got %x\n", + GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, + intPKCSContentInfo, sizeof(intPKCSContentInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CRYPT_CONTENT_INFO *)buf; + + ok(!strcmp(info->pszObjId, "1.2.3"), "Expected 1.2.3, got %s\n", + info->pszObjId); + ok(info->Content.cbData == ints[0].encoded[1] + 2, + "Unexpected size %d\n", info->Content.cbData); + ok(!memcmp(info->Content.pbData, ints[0].encoded, + info->Content.cbData), "Unexpected value\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_CONTENT_INFO, + indefiniteSignedPKCSContent, sizeof(indefiniteSignedPKCSContent), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CRYPT_CONTENT_INFO *)buf; + + ok(!strcmp(info->pszObjId, szOID_RSA_signedData), + "Expected %s, got %s\n", szOID_RSA_signedData, info->pszObjId); + ok(info->Content.cbData == 392, "Expected 392, got %d\n", + info->Content.cbData); + LocalFree(buf); + } +} + +static const BYTE emptyPKCSAttr[] = { 0x30,0x06,0x06,0x02,0x2a,0x03,0x31, + 0x00 }; +static const BYTE bogusPKCSAttr[] = { 0x30,0x07,0x06,0x02,0x2a,0x03,0x31,0x01, + 0x01 }; +static const BYTE intPKCSAttr[] = { 0x30,0x09,0x06,0x02,0x2a,0x03,0x31,0x03, + 0x02,0x01,0x01 }; + +static void test_encodePKCSAttribute(DWORD dwEncoding) +{ + CRYPT_ATTRIBUTE attr = { 0 }; + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CRYPT_ATTR_BLOB blob; + char oid[] = "1.2.3"; + + if (0) + { + /* Crashes on win9x */ + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTE, NULL, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %x\n", GetLastError()); + } + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTE, &attr, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x */), + "Expected E_INVALIDARG or OSS_LIMITED, got %x\n", GetLastError()); + attr.pszObjId = oid; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTE, &attr, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptyPKCSAttr), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyPKCSAttr, size), "Unexpected value\n"); + LocalFree(buf); + } + blob.cbData = sizeof(bogusDER); + blob.pbData = bogusDER; + attr.cValue = 1; + attr.rgValue = &blob; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTE, &attr, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(bogusPKCSAttr), "Unexpected size %d\n", size); + ok(!memcmp(buf, bogusPKCSAttr, size), "Unexpected value\n"); + LocalFree(buf); + } + blob.pbData = (BYTE *)ints[0].encoded; + blob.cbData = ints[0].encoded[1] + 2; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTE, &attr, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(intPKCSAttr), "Unexpected size %d\n", size); + ok(!memcmp(buf, intPKCSAttr, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodePKCSAttribute(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CRYPT_ATTRIBUTE *attr; + + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_ATTRIBUTE, + emptyPKCSAttr, sizeof(emptyPKCSAttr), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + attr = (CRYPT_ATTRIBUTE *)buf; + + ok(!strcmp(attr->pszObjId, "1.2.3"), "Expected 1.2.3, got %s\n", + attr->pszObjId); + ok(attr->cValue == 0, "Expected no value, got %d\n", attr->cValue); + LocalFree(buf); + } + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_ATTRIBUTE, + bogusPKCSAttr, sizeof(bogusPKCSAttr), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + /* Native fails with CRYPT_E_ASN1_EOD, accept also CRYPT_E_ASN1_CORRUPT as + * I doubt an app depends on that. + */ + ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_MORE_INPUT /* Win9x */), + "Expected CRYPT_E_ASN1_EOD, CRYPT_E_ASN1_CORRUPT, or OSS_MORE_INPUT, got %x\n", + GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_ATTRIBUTE, + intPKCSAttr, sizeof(intPKCSAttr), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + attr = (CRYPT_ATTRIBUTE *)buf; + + ok(!strcmp(attr->pszObjId, "1.2.3"), "Expected 1.2.3, got %s\n", + attr->pszObjId); + ok(attr->cValue == 1, "Expected 1 value, got %d\n", attr->cValue); + ok(attr->rgValue[0].cbData == ints[0].encoded[1] + 2, + "Unexpected size %d\n", attr->rgValue[0].cbData); + ok(!memcmp(attr->rgValue[0].pbData, ints[0].encoded, + attr->rgValue[0].cbData), "Unexpected value\n"); + LocalFree(buf); + } +} + +static const BYTE emptyPKCSAttributes[] = { 0x31,0x00 }; +static const BYTE singlePKCSAttributes[] = { 0x31,0x08,0x30,0x06,0x06,0x02, + 0x2a,0x03,0x31,0x00 }; +static const BYTE doublePKCSAttributes[] = { 0x31,0x13,0x30,0x06,0x06,0x02, + 0x2a,0x03,0x31,0x00,0x30,0x09,0x06,0x02,0x2d,0x06,0x31,0x03,0x02,0x01,0x01 }; + +static void test_encodePKCSAttributes(DWORD dwEncoding) +{ + CRYPT_ATTRIBUTES attributes = { 0 }; + CRYPT_ATTRIBUTE attr[2] = { { 0 } }; + CRYPT_ATTR_BLOB blob; + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + char oid1[] = "1.2.3", oid2[] = "1.5.6"; + + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTES, &attributes, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptyPKCSAttributes), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyPKCSAttributes, size), "Unexpected value\n"); + LocalFree(buf); + } + attributes.cAttr = 1; + attributes.rgAttr = attr; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTES, &attributes, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x */), + "Expected E_INVALIDARG or OSS_LIMITED, got %08x\n", GetLastError()); + attr[0].pszObjId = oid1; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTES, &attributes, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + ok(size == sizeof(singlePKCSAttributes), "Unexpected size %d\n", size); + ok(!memcmp(buf, singlePKCSAttributes, size), "Unexpected value\n"); + LocalFree(buf); + } + attr[1].pszObjId = oid2; + attr[1].cValue = 1; + attr[1].rgValue = &blob; + blob.pbData = (BYTE *)ints[0].encoded; + blob.cbData = ints[0].encoded[1] + 2; + attributes.cAttr = 2; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_ATTRIBUTES, &attributes, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(doublePKCSAttributes), "Unexpected size %d\n", size); + ok(!memcmp(buf, doublePKCSAttributes, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodePKCSAttributes(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CRYPT_ATTRIBUTES *attributes; + + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_ATTRIBUTES, + emptyPKCSAttributes, sizeof(emptyPKCSAttributes), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + attributes = (CRYPT_ATTRIBUTES *)buf; + ok(attributes->cAttr == 0, "Expected no attributes, got %d\n", + attributes->cAttr); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_ATTRIBUTES, + singlePKCSAttributes, sizeof(singlePKCSAttributes), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + attributes = (CRYPT_ATTRIBUTES *)buf; + ok(attributes->cAttr == 1, "Expected 1 attribute, got %d\n", + attributes->cAttr); + ok(!strcmp(attributes->rgAttr[0].pszObjId, "1.2.3"), + "Expected 1.2.3, got %s\n", attributes->rgAttr[0].pszObjId); + ok(attributes->rgAttr[0].cValue == 0, + "Expected no attributes, got %d\n", attributes->rgAttr[0].cValue); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_ATTRIBUTES, + doublePKCSAttributes, sizeof(doublePKCSAttributes), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + attributes = (CRYPT_ATTRIBUTES *)buf; + ok(attributes->cAttr == 2, "Expected 2 attributes, got %d\n", + attributes->cAttr); + ok(!strcmp(attributes->rgAttr[0].pszObjId, "1.2.3"), + "Expected 1.2.3, got %s\n", attributes->rgAttr[0].pszObjId); + ok(attributes->rgAttr[0].cValue == 0, + "Expected no attributes, got %d\n", attributes->rgAttr[0].cValue); + ok(!strcmp(attributes->rgAttr[1].pszObjId, "1.5.6"), + "Expected 1.5.6, got %s\n", attributes->rgAttr[1].pszObjId); + ok(attributes->rgAttr[1].cValue == 1, + "Expected 1 attribute, got %d\n", attributes->rgAttr[1].cValue); + ok(attributes->rgAttr[1].rgValue[0].cbData == ints[0].encoded[1] + 2, + "Unexpected size %d\n", attributes->rgAttr[1].rgValue[0].cbData); + ok(!memcmp(attributes->rgAttr[1].rgValue[0].pbData, ints[0].encoded, + attributes->rgAttr[1].rgValue[0].cbData), "Unexpected value\n"); + LocalFree(buf); + } +} + +static const BYTE singleCapability[] = { +0x30,0x06,0x30,0x04,0x06,0x02,0x2d,0x06 }; +static const BYTE twoCapabilities[] = { +0x30,0x0c,0x30,0x04,0x06,0x02,0x2d,0x06,0x30,0x04,0x06,0x02,0x2a,0x03 }; +static const BYTE singleCapabilitywithNULL[] = { +0x30,0x08,0x30,0x06,0x06,0x02,0x2d,0x06,0x05,0x00 }; + +static void test_encodePKCSSMimeCapabilities(DWORD dwEncoding) +{ + static char oid1[] = "1.5.6", oid2[] = "1.2.3"; + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CRYPT_SMIME_CAPABILITY capability[2]; + CRYPT_SMIME_CAPABILITIES capabilities; + + /* An empty capabilities is allowed */ + capabilities.cCapability = 0; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES, + &capabilities, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(emptySequence), "unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "unexpected value\n"); + LocalFree(buf); + } + /* A non-empty capabilities with an empty capability (lacking an OID) is + * not allowed + */ + capability[0].pszObjId = NULL; + capability[0].Parameters.cbData = 0; + capabilities.cCapability = 1; + capabilities.rgCapability = capability; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES, + &capabilities, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x */), + "Expected E_INVALIDARG or OSS_LIMITED, got %08x\n", GetLastError()); + capability[0].pszObjId = oid1; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES, + &capabilities, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(singleCapability), "unexpected size %d\n", size); + ok(!memcmp(buf, singleCapability, size), "unexpected value\n"); + LocalFree(buf); + } + capability[1].pszObjId = oid2; + capability[1].Parameters.cbData = 0; + capabilities.cCapability = 2; + ret = pCryptEncodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES, + &capabilities, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(twoCapabilities), "unexpected size %d\n", size); + ok(!memcmp(buf, twoCapabilities, size), "unexpected value\n"); + LocalFree(buf); + } +} + +static void compareSMimeCapabilities(LPCSTR header, + const CRYPT_SMIME_CAPABILITIES *expected, const CRYPT_SMIME_CAPABILITIES *got) +{ + DWORD i; + + ok(got->cCapability == expected->cCapability, + "%s: expected %d capabilities, got %d\n", header, expected->cCapability, + got->cCapability); + for (i = 0; i < expected->cCapability; i++) + { + ok(!strcmp(expected->rgCapability[i].pszObjId, + got->rgCapability[i].pszObjId), "%s[%d]: expected %s, got %s\n", + header, i, expected->rgCapability[i].pszObjId, + got->rgCapability[i].pszObjId); + ok(expected->rgCapability[i].Parameters.cbData == + got->rgCapability[i].Parameters.cbData, + "%s[%d]: expected %d bytes, got %d\n", header, i, + expected->rgCapability[i].Parameters.cbData, + got->rgCapability[i].Parameters.cbData); + if (expected->rgCapability[i].Parameters.cbData) + ok(!memcmp(expected->rgCapability[i].Parameters.pbData, + got->rgCapability[i].Parameters.pbData, + expected->rgCapability[i].Parameters.cbData), + "%s[%d]: unexpected value\n", header, i); + } +} + +static void test_decodePKCSSMimeCapabilities(DWORD dwEncoding) +{ + static char oid1[] = "1.5.6", oid2[] = "1.2.3"; + BOOL ret; + DWORD size = 0; + CRYPT_SMIME_CAPABILITY capability[2]; + CRYPT_SMIME_CAPABILITIES capabilities, *ptr; + + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES, + emptySequence, sizeof(emptySequence), + CRYPT_DECODE_ALLOC_FLAG, NULL, &ptr, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + capabilities.cCapability = 0; + compareSMimeCapabilities("empty capabilities", &capabilities, ptr); + LocalFree(ptr); + } + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES, + singleCapability, sizeof(singleCapability), CRYPT_DECODE_ALLOC_FLAG, NULL, + &ptr, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + capability[0].pszObjId = oid1; + capability[0].Parameters.cbData = 0; + capabilities.cCapability = 1; + capabilities.rgCapability = capability; + compareSMimeCapabilities("single capability", &capabilities, ptr); + LocalFree(ptr); + } + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES, + singleCapabilitywithNULL, sizeof(singleCapabilitywithNULL), + CRYPT_DECODE_ALLOC_FLAG, NULL, &ptr, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + BYTE NULLparam[] = {0x05, 0x00}; + capability[0].pszObjId = oid1; + capability[0].Parameters.cbData = 2; + capability[0].Parameters.pbData = NULLparam; + capabilities.cCapability = 1; + capabilities.rgCapability = capability; + compareSMimeCapabilities("single capability with NULL", &capabilities, + ptr); + LocalFree(ptr); + } + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS_SMIME_CAPABILITIES, + twoCapabilities, sizeof(twoCapabilities), CRYPT_DECODE_ALLOC_FLAG, NULL, + &ptr, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + capability[0].Parameters.cbData = 0; + capability[1].pszObjId = oid2; + capability[1].Parameters.cbData = 0; + capabilities.cCapability = 2; + compareSMimeCapabilities("two capabilities", &capabilities, ptr); + LocalFree(ptr); + } +} + +static BYTE encodedCommonNameNoNull[] = { 0x30,0x14,0x31,0x12,0x30,0x10, + 0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, + 0x67 }; +static const BYTE minimalPKCSSigner[] = { + 0x30,0x2b,0x02,0x01,0x00,0x30,0x18,0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03, + 0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x02, + 0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; +static const BYTE PKCSSignerWithSerial[] = { + 0x30,0x2c,0x02,0x01,0x00,0x30,0x19,0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03, + 0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x02, + 0x01,0x01,0x30,0x04,0x06,0x00,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04, + 0x00 }; +static const BYTE PKCSSignerWithHashAlgo[] = { + 0x30,0x2e,0x02,0x01,0x00,0x30,0x19,0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03, + 0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x02, + 0x01,0x01,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x30,0x04,0x06,0x00,0x05, + 0x00,0x04,0x00 }; +static const BYTE PKCSSignerWithHashAndEncryptionAlgo[] = { + 0x30,0x30,0x02,0x01,0x00,0x30,0x19,0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03, + 0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x02, + 0x01,0x01,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x30,0x06,0x06,0x02,0x2d, + 0x06,0x05,0x00,0x04,0x00 }; +static const BYTE PKCSSignerWithHash[] = { + 0x30,0x40,0x02,0x01,0x00,0x30,0x19,0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03, + 0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x02, + 0x01,0x01,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0x30,0x06,0x06,0x02,0x2d, + 0x06,0x05,0x00,0x04,0x10,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, + 0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; +static const BYTE PKCSSignerWithAuthAttr[] = { +0x30,0x62,0x02,0x01,0x00,0x30,0x19,0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03, +0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x02, +0x01,0x01,0x30,0x06,0x06,0x02,0x2a,0x03,0x05,0x00,0xa0,0x20,0x30,0x1e,0x06, +0x03,0x55,0x04,0x03,0x31,0x17,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30, +0x06,0x06,0x02,0x2d,0x06,0x05,0x00,0x04,0x10,0x00,0x01,0x02,0x03,0x04,0x05, +0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; + +static void test_encodePKCSSignerInfo(DWORD dwEncoding) +{ + static char oid1[] = "1.2.3", oid2[] = "1.5.6"; + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CMSG_SIGNER_INFO info = { 0 }; + char oid_common_name[] = szOID_COMMON_NAME; + CRYPT_ATTR_BLOB commonName = { sizeof(encodedCommonName), + (LPBYTE)encodedCommonName }; + CRYPT_ATTRIBUTE attr = { oid_common_name, 1, &commonName }; + + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no PKCS7_SIGNER_INFO encode support\n"); + return; + } + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x */), + "Expected E_INVALIDARG or OSS_LIMITED, got %08x\n", GetLastError()); + /* To be encoded, a signer must have an issuer at least, and the encoding + * must include PKCS_7_ASN_ENCODING. (That isn't enough to be decoded, + * see decoding tests.) + */ + info.Issuer.cbData = sizeof(encodedCommonNameNoNull); + info.Issuer.pbData = encodedCommonNameNoNull; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret || broken(GetLastError() == OSS_LIMITED /* Win9x */), + "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(minimalPKCSSigner), "Unexpected size %d\n", size); + if (size == sizeof(minimalPKCSSigner)) + ok(!memcmp(buf, minimalPKCSSigner, size), "Unexpected value\n"); + else + ok(0, "Unexpected value\n"); + LocalFree(buf); + } + } + info.SerialNumber.cbData = sizeof(serialNum); + info.SerialNumber.pbData = (BYTE *)serialNum; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret || broken(GetLastError() == OSS_LIMITED /* Win9x */), + "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithSerial), "Unexpected size %d\n", + size); + if (size == sizeof(PKCSSignerWithSerial)) + ok(!memcmp(buf, PKCSSignerWithSerial, size), + "Unexpected value\n"); + else + ok(0, "Unexpected value\n"); + LocalFree(buf); + } + } + info.HashAlgorithm.pszObjId = oid1; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret || broken(GetLastError() == OSS_LIMITED /* Win9x */), + "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHashAlgo), "Unexpected size %d\n", + size); + if (size == sizeof(PKCSSignerWithHashAlgo)) + ok(!memcmp(buf, PKCSSignerWithHashAlgo, size), + "Unexpected value\n"); + else + ok(0, "Unexpected value\n"); + LocalFree(buf); + } + } + info.HashEncryptionAlgorithm.pszObjId = oid2; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHashAndEncryptionAlgo), + "Unexpected size %d\n", size); + if (size == sizeof(PKCSSignerWithHashAndEncryptionAlgo)) + ok(!memcmp(buf, PKCSSignerWithHashAndEncryptionAlgo, size), + "Unexpected value\n"); + else + ok(0, "Unexpected value\n"); + LocalFree(buf); + } + } + info.EncryptedHash.cbData = sizeof(hash); + info.EncryptedHash.pbData = (BYTE *)hash; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHash), "Unexpected size %d\n", + size); + if (size == sizeof(PKCSSignerWithHash)) + ok(!memcmp(buf, PKCSSignerWithHash, size), + "Unexpected value\n"); + else + ok(0, "Unexpected value\n"); + LocalFree(buf); + } + } + info.AuthAttrs.cAttr = 1; + info.AuthAttrs.rgAttr = &attr; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithAuthAttr), "Unexpected size %d\n", + size); + if (size == sizeof(PKCSSignerWithAuthAttr)) + ok(!memcmp(buf, PKCSSignerWithAuthAttr, size), + "Unexpected value\n"); + else + ok(0, "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodePKCSSignerInfo(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CMSG_SIGNER_INFO *info; + + /* A PKCS signer can't be decoded without a serial number. */ + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, + minimalPKCSSigner, sizeof(minimalPKCSSigner), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_CORRUPT || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %x\n", + GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, + PKCSSignerWithSerial, sizeof(PKCSSignerWithSerial), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR), + "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->Issuer.cbData == sizeof(encodedCommonNameNoNull), + "Unexpected size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonNameNoNull, + info->Issuer.cbData), "Unexpected value\n"); + ok(info->SerialNumber.cbData == sizeof(serialNum), + "Unexpected size %d\n", info->SerialNumber.cbData); + ok(!memcmp(info->SerialNumber.pbData, serialNum, sizeof(serialNum)), + "Unexpected value\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, + PKCSSignerWithHashAlgo, sizeof(PKCSSignerWithHashAlgo), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + info = (CMSG_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->Issuer.cbData == sizeof(encodedCommonNameNoNull), + "Unexpected size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonNameNoNull, + info->Issuer.cbData), "Unexpected value\n"); + ok(info->SerialNumber.cbData == sizeof(serialNum), + "Unexpected size %d\n", info->SerialNumber.cbData); + ok(!memcmp(info->SerialNumber.pbData, serialNum, sizeof(serialNum)), + "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, "1.2.3"), + "Expected 1.2.3, got %s\n", info->HashAlgorithm.pszObjId); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, + PKCSSignerWithHashAndEncryptionAlgo, + sizeof(PKCSSignerWithHashAndEncryptionAlgo), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + if (buf) + { + info = (CMSG_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->Issuer.cbData == sizeof(encodedCommonNameNoNull), + "Unexpected size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonNameNoNull, + info->Issuer.cbData), "Unexpected value\n"); + ok(info->SerialNumber.cbData == sizeof(serialNum), + "Unexpected size %d\n", info->SerialNumber.cbData); + ok(!memcmp(info->SerialNumber.pbData, serialNum, sizeof(serialNum)), + "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, "1.2.3"), + "Expected 1.2.3, got %s\n", info->HashAlgorithm.pszObjId); + ok(!strcmp(info->HashEncryptionAlgorithm.pszObjId, "1.5.6"), + "Expected 1.5.6, got %s\n", info->HashEncryptionAlgorithm.pszObjId); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, + PKCSSignerWithHash, sizeof(PKCSSignerWithHash), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + info = (CMSG_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->Issuer.cbData == sizeof(encodedCommonNameNoNull), + "Unexpected size %d\n", info->Issuer.cbData); + ok(!memcmp(info->Issuer.pbData, encodedCommonNameNoNull, + info->Issuer.cbData), "Unexpected value\n"); + ok(info->SerialNumber.cbData == sizeof(serialNum), + "Unexpected size %d\n", info->SerialNumber.cbData); + ok(!memcmp(info->SerialNumber.pbData, serialNum, sizeof(serialNum)), + "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, "1.2.3"), + "Expected 1.2.3, got %s\n", info->HashAlgorithm.pszObjId); + ok(!strcmp(info->HashEncryptionAlgorithm.pszObjId, "1.5.6"), + "Expected 1.5.6, got %s\n", info->HashEncryptionAlgorithm.pszObjId); + ok(info->EncryptedHash.cbData == sizeof(hash), "Unexpected size %d\n", + info->EncryptedHash.cbData); + ok(!memcmp(info->EncryptedHash.pbData, hash, sizeof(hash)), + "Unexpected value\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, PKCS7_SIGNER_INFO, + PKCSSignerWithAuthAttr, sizeof(PKCSSignerWithAuthAttr), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + if (buf) + { + info = (CMSG_SIGNER_INFO *)buf; + ok(info->AuthAttrs.cAttr == 1, "Expected 1 attribute, got %d\n", + info->AuthAttrs.cAttr); + ok(!strcmp(info->AuthAttrs.rgAttr[0].pszObjId, szOID_COMMON_NAME), + "Expected %s, got %s\n", szOID_COMMON_NAME, + info->AuthAttrs.rgAttr[0].pszObjId); + ok(info->AuthAttrs.rgAttr[0].cValue == 1, "Expected 1 value, got %d\n", + info->AuthAttrs.rgAttr[0].cValue); + ok(info->AuthAttrs.rgAttr[0].rgValue[0].cbData == + sizeof(encodedCommonName), "Unexpected size %d\n", + info->AuthAttrs.rgAttr[0].rgValue[0].cbData); + ok(!memcmp(info->AuthAttrs.rgAttr[0].rgValue[0].pbData, + encodedCommonName, sizeof(encodedCommonName)), "Unexpected value\n"); + LocalFree(buf); + } +} + +static const BYTE CMSSignerWithKeyId[] = { +0x30,0x14,0x02,0x01,0x00,0x80,0x01,0x01,0x30,0x04,0x06,0x00,0x05,0x00,0x30, +0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; + +static void test_encodeCMSSignerInfo(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CMSG_CMS_SIGNER_INFO info = { 0 }; + static char oid1[] = "1.2.3", oid2[] = "1.5.6"; + + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret, "Expected failure, got %d\n", ret); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no CMS_SIGNER_INFO encode support\n"); + return; + } + ok(GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + info.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret, "Expected failure, got %d\n", ret); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no CMS_SIGNER_INFO encode support\n"); + return; + } + ok(GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* To be encoded, a signer must have a valid cert ID, where a valid ID may + * be a key id or a issuer serial number with at least the issuer set, and + * the encoding must include PKCS_7_ASN_ENCODING. + * (That isn't enough to be decoded, see decoding tests.) + */ + U(info.SignerId).IssuerSerialNumber.Issuer.cbData = + sizeof(encodedCommonNameNoNull); + U(info.SignerId).IssuerSerialNumber.Issuer.pbData = encodedCommonNameNoNull; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(minimalPKCSSigner), "Unexpected size %d\n", size); + ok(!memcmp(buf, minimalPKCSSigner, size), "Unexpected value\n"); + LocalFree(buf); + } + } + U(info.SignerId).IssuerSerialNumber.SerialNumber.cbData = sizeof(serialNum); + U(info.SignerId).IssuerSerialNumber.SerialNumber.pbData = (BYTE *)serialNum; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithSerial), "Unexpected size %d\n", + size); + ok(!memcmp(buf, PKCSSignerWithSerial, size), "Unexpected value\n"); + LocalFree(buf); + } + } + info.SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + U(info.SignerId).KeyId.cbData = sizeof(serialNum); + U(info.SignerId).KeyId.pbData = (BYTE *)serialNum; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(CMSSignerWithKeyId), "Unexpected size %d\n", + size); + ok(!memcmp(buf, CMSSignerWithKeyId, size), "Unexpected value\n"); + LocalFree(buf); + } + } + /* While a CERT_ID can have a hash type, that's not allowed in CMS, where + * only the IssuerAndSerialNumber and SubjectKeyIdentifier types are allowed + * (see RFC 3852, section 5.3.) + */ + info.SignerId.dwIdChoice = CERT_ID_SHA1_HASH; + U(info.SignerId).HashId.cbData = sizeof(hash); + U(info.SignerId).HashId.pbData = (BYTE *)hash; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Now with a hash algo */ + info.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + U(info.SignerId).IssuerSerialNumber.Issuer.cbData = + sizeof(encodedCommonNameNoNull); + U(info.SignerId).IssuerSerialNumber.Issuer.pbData = encodedCommonNameNoNull; + info.HashAlgorithm.pszObjId = oid1; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHashAlgo), "Unexpected size %d\n", + size); + ok(!memcmp(buf, PKCSSignerWithHashAlgo, size), + "Unexpected value\n"); + LocalFree(buf); + } + } + info.HashEncryptionAlgorithm.pszObjId = oid2; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHashAndEncryptionAlgo), + "Unexpected size %d\n", size); + ok(!memcmp(buf, PKCSSignerWithHashAndEncryptionAlgo, size), + "Unexpected value\n"); + LocalFree(buf); + } + } + info.EncryptedHash.cbData = sizeof(hash); + info.EncryptedHash.pbData = (BYTE *)hash; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, CMS_SIGNER_INFO, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!(dwEncoding & PKCS_7_ASN_ENCODING)) + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + else + { + ok(ret, "CryptEncodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + ok(size == sizeof(PKCSSignerWithHash), "Unexpected size %d\n", + size); + ok(!memcmp(buf, PKCSSignerWithHash, size), "Unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodeCMSSignerInfo(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + CMSG_CMS_SIGNER_INFO *info; + static char oid1[] = "1.2.3", oid2[] = "1.5.6"; + + /* A CMS signer can't be decoded without a serial number. */ + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + minimalPKCSSigner, sizeof(minimalPKCSSigner), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret, "expected failure\n"); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no CMS_SIGNER_INFO decode support\n"); + return; + } + ok(GetLastError() == CRYPT_E_ASN1_CORRUPT, + "Expected CRYPT_E_ASN1_CORRUPT, got %x\n", GetLastError()); + ret = pCryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + PKCSSignerWithSerial, sizeof(PKCSSignerWithSerial), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER, + "Expected CERT_ID_ISSUER_SERIAL_NUMBER, got %d\n", + info->SignerId.dwIdChoice); + ok(U(info->SignerId).IssuerSerialNumber.Issuer.cbData == + sizeof(encodedCommonNameNoNull), "Unexpected size %d\n", + U(info->SignerId).IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(U(info->SignerId).IssuerSerialNumber.Issuer.pbData, + encodedCommonNameNoNull, + U(info->SignerId).IssuerSerialNumber.Issuer.cbData), + "Unexpected value\n"); + ok(U(info->SignerId).IssuerSerialNumber.SerialNumber.cbData == + sizeof(serialNum), "Unexpected size %d\n", + U(info->SignerId).IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(U(info->SignerId).IssuerSerialNumber.SerialNumber.pbData, + serialNum, sizeof(serialNum)), "Unexpected value\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + PKCSSignerWithHashAlgo, sizeof(PKCSSignerWithHashAlgo), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER, + "Expected CERT_ID_ISSUER_SERIAL_NUMBER, got %d\n", + info->SignerId.dwIdChoice); + ok(U(info->SignerId).IssuerSerialNumber.Issuer.cbData == + sizeof(encodedCommonNameNoNull), "Unexpected size %d\n", + U(info->SignerId).IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(U(info->SignerId).IssuerSerialNumber.Issuer.pbData, + encodedCommonNameNoNull, + U(info->SignerId).IssuerSerialNumber.Issuer.cbData), + "Unexpected value\n"); + ok(U(info->SignerId).IssuerSerialNumber.SerialNumber.cbData == + sizeof(serialNum), "Unexpected size %d\n", + U(info->SignerId).IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(U(info->SignerId).IssuerSerialNumber.SerialNumber.pbData, + serialNum, sizeof(serialNum)), "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, oid1), + "Expected %s, got %s\n", oid1, info->HashAlgorithm.pszObjId); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + PKCSSignerWithHashAndEncryptionAlgo, + sizeof(PKCSSignerWithHashAndEncryptionAlgo), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER, + "Expected CERT_ID_ISSUER_SERIAL_NUMBER, got %d\n", + info->SignerId.dwIdChoice); + ok(U(info->SignerId).IssuerSerialNumber.Issuer.cbData == + sizeof(encodedCommonNameNoNull), "Unexpected size %d\n", + U(info->SignerId).IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(U(info->SignerId).IssuerSerialNumber.Issuer.pbData, + encodedCommonNameNoNull, + U(info->SignerId).IssuerSerialNumber.Issuer.cbData), + "Unexpected value\n"); + ok(U(info->SignerId).IssuerSerialNumber.SerialNumber.cbData == + sizeof(serialNum), "Unexpected size %d\n", + U(info->SignerId).IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(U(info->SignerId).IssuerSerialNumber.SerialNumber.pbData, + serialNum, sizeof(serialNum)), "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, oid1), + "Expected %s, got %s\n", oid1, info->HashAlgorithm.pszObjId); + ok(!strcmp(info->HashEncryptionAlgorithm.pszObjId, oid2), + "Expected %s, got %s\n", oid2, info->HashEncryptionAlgorithm.pszObjId); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + PKCSSignerWithHash, sizeof(PKCSSignerWithHash), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER, + "Expected CERT_ID_ISSUER_SERIAL_NUMBER, got %d\n", + info->SignerId.dwIdChoice); + ok(U(info->SignerId).IssuerSerialNumber.Issuer.cbData == + sizeof(encodedCommonNameNoNull), "Unexpected size %d\n", + U(info->SignerId).IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(U(info->SignerId).IssuerSerialNumber.Issuer.pbData, + encodedCommonNameNoNull, + U(info->SignerId).IssuerSerialNumber.Issuer.cbData), + "Unexpected value\n"); + ok(U(info->SignerId).IssuerSerialNumber.SerialNumber.cbData == + sizeof(serialNum), "Unexpected size %d\n", + U(info->SignerId).IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(U(info->SignerId).IssuerSerialNumber.SerialNumber.pbData, + serialNum, sizeof(serialNum)), "Unexpected value\n"); + ok(!strcmp(info->HashAlgorithm.pszObjId, oid1), + "Expected %s, got %s\n", oid1, info->HashAlgorithm.pszObjId); + ok(!strcmp(info->HashEncryptionAlgorithm.pszObjId, oid2), + "Expected %s, got %s\n", oid2, info->HashEncryptionAlgorithm.pszObjId); + ok(info->EncryptedHash.cbData == sizeof(hash), "Unexpected size %d\n", + info->EncryptedHash.cbData); + ok(!memcmp(info->EncryptedHash.pbData, hash, sizeof(hash)), + "Unexpected value\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(dwEncoding, CMS_SIGNER_INFO, + CMSSignerWithKeyId, sizeof(CMSSignerWithKeyId), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %x\n", GetLastError()); + if (buf) + { + info = (CMSG_CMS_SIGNER_INFO *)buf; + ok(info->dwVersion == 0, "Expected version 0, got %d\n", + info->dwVersion); + ok(info->SignerId.dwIdChoice == CERT_ID_KEY_IDENTIFIER, + "Expected CERT_ID_KEY_IDENTIFIER, got %d\n", + info->SignerId.dwIdChoice); + ok(U(info->SignerId).KeyId.cbData == sizeof(serialNum), + "Unexpected size %d\n", U(info->SignerId).KeyId.cbData); + ok(!memcmp(U(info->SignerId).KeyId.pbData, serialNum, sizeof(serialNum)), + "Unexpected value\n"); + LocalFree(buf); + } +} + +static BYTE emptyDNSPermittedConstraints[] = { +0x30,0x06,0xa0,0x04,0x30,0x02,0x82,0x00 }; +static BYTE emptyDNSExcludedConstraints[] = { +0x30,0x06,0xa1,0x04,0x30,0x02,0x82,0x00 }; +static BYTE DNSExcludedConstraints[] = { +0x30,0x17,0xa1,0x15,0x30,0x13,0x82,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, +0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67 }; +static BYTE permittedAndExcludedConstraints[] = { +0x30,0x25,0xa0,0x0c,0x30,0x0a,0x87,0x08,0x30,0x06,0x87,0x04,0x7f,0x00,0x00, +0x01,0xa1,0x15,0x30,0x13,0x82,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77, +0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67 }; +static BYTE permittedAndExcludedWithMinConstraints[] = { +0x30,0x28,0xa0,0x0f,0x30,0x0d,0x87,0x08,0x30,0x06,0x87,0x04,0x7f,0x00,0x00, +0x01,0x80,0x01,0x05,0xa1,0x15,0x30,0x13,0x82,0x11,0x68,0x74,0x74,0x70,0x3a, +0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67 }; +static BYTE permittedAndExcludedWithMinMaxConstraints[] = { +0x30,0x2b,0xa0,0x12,0x30,0x10,0x87,0x08,0x30,0x06,0x87,0x04,0x7f,0x00,0x00, +0x01,0x80,0x01,0x05,0x81,0x01,0x03,0xa1,0x15,0x30,0x13,0x82,0x11,0x68,0x74, +0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67 }; + +static void test_encodeNameConstraints(DWORD dwEncoding) +{ + BOOL ret; + CERT_NAME_CONSTRAINTS_INFO constraints = { 0 }; + CERT_GENERAL_SUBTREE permitted = { { 0 } }; + CERT_GENERAL_SUBTREE excluded = { { 0 } }; + LPBYTE buf; + DWORD size; + + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, &constraints, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no X509_NAME_CONSTRAINTS encode support\n"); + return; + } + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptySequence), "Unexpected size\n"); + ok(!memcmp(buf, emptySequence, size), "Unexpected value\n"); + LocalFree(buf); + } + constraints.cPermittedSubtree = 1; + constraints.rgPermittedSubtree = &permitted; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, &constraints, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + permitted.Base.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, &constraints, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptyDNSPermittedConstraints), "Unexpected size\n"); + ok(!memcmp(buf, emptyDNSPermittedConstraints, size), + "Unexpected value\n"); + LocalFree(buf); + } + constraints.cPermittedSubtree = 0; + constraints.cExcludedSubtree = 1; + constraints.rgExcludedSubtree = &excluded; + excluded.Base.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, &constraints, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptyDNSExcludedConstraints), "Unexpected size\n"); + ok(!memcmp(buf, emptyDNSExcludedConstraints, size), + "Unexpected value\n"); + LocalFree(buf); + } + U(excluded.Base).pwszURL = (LPWSTR)url; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, &constraints, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(DNSExcludedConstraints), "Unexpected size\n"); + ok(!memcmp(buf, DNSExcludedConstraints, size), + "Unexpected value\n"); + LocalFree(buf); + } + permitted.Base.dwAltNameChoice = CERT_ALT_NAME_IP_ADDRESS; + U(permitted.Base).IPAddress.cbData = sizeof(encodedIPAddr); + U(permitted.Base).IPAddress.pbData = (LPBYTE)encodedIPAddr; + constraints.cPermittedSubtree = 1; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, &constraints, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(permittedAndExcludedConstraints), + "Unexpected size\n"); + ok(!memcmp(buf, permittedAndExcludedConstraints, size), + "Unexpected value\n"); + LocalFree(buf); + } + permitted.dwMinimum = 5; + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, &constraints, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(permittedAndExcludedWithMinConstraints), + "Unexpected size\n"); + ok(!memcmp(buf, permittedAndExcludedWithMinConstraints, size), + "Unexpected value\n"); + LocalFree(buf); + } + permitted.fMaximum = TRUE; + permitted.dwMaximum = 3; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, &constraints, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(permittedAndExcludedWithMinMaxConstraints), + "Unexpected size\n"); + ok(!memcmp(buf, permittedAndExcludedWithMinMaxConstraints, size), + "Unexpected value\n"); + LocalFree(buf); + } +} + +struct EncodedNameConstraints +{ + CRYPT_DATA_BLOB encoded; + CERT_NAME_CONSTRAINTS_INFO constraints; +}; + +static CERT_GENERAL_SUBTREE emptyDNSSubtree = { + { CERT_ALT_NAME_DNS_NAME, { 0 } }, 0 }; +static CERT_GENERAL_SUBTREE DNSSubtree = { + { CERT_ALT_NAME_DNS_NAME, { 0 } }, 0 }; +static CERT_GENERAL_SUBTREE IPAddressSubtree = { + { CERT_ALT_NAME_IP_ADDRESS, { 0 } }, 0 }; +static CERT_GENERAL_SUBTREE IPAddressWithMinSubtree = { + { CERT_ALT_NAME_IP_ADDRESS, { 0 } }, 5, 0 }; +static CERT_GENERAL_SUBTREE IPAddressWithMinMaxSubtree = { + { CERT_ALT_NAME_IP_ADDRESS, { 0 } }, 5, TRUE, 3 }; + +struct EncodedNameConstraints encodedNameConstraints[] = { + { { sizeof(emptySequence), (LPBYTE)emptySequence }, { 0 } }, + { { sizeof(emptyDNSPermittedConstraints), emptyDNSPermittedConstraints }, + { 1, &emptyDNSSubtree, 0, NULL } }, + { { sizeof(emptyDNSExcludedConstraints), emptyDNSExcludedConstraints }, + { 0, NULL, 1, &emptyDNSSubtree } }, + { { sizeof(DNSExcludedConstraints), DNSExcludedConstraints }, + { 0, NULL, 1, &DNSSubtree } }, + { { sizeof(permittedAndExcludedConstraints), permittedAndExcludedConstraints }, + { 1, &IPAddressSubtree, 1, &DNSSubtree } }, + { { sizeof(permittedAndExcludedWithMinConstraints), + permittedAndExcludedWithMinConstraints }, + { 1, &IPAddressWithMinSubtree, 1, &DNSSubtree } }, + { { sizeof(permittedAndExcludedWithMinMaxConstraints), + permittedAndExcludedWithMinMaxConstraints }, + { 1, &IPAddressWithMinMaxSubtree, 1, &DNSSubtree } }, +}; + +static void test_decodeNameConstraints(DWORD dwEncoding) +{ + BOOL ret; + DWORD i; + CERT_NAME_CONSTRAINTS_INFO *constraints; + + U(DNSSubtree.Base).pwszURL = (LPWSTR)url; + U(IPAddressSubtree.Base).IPAddress.cbData = sizeof(encodedIPAddr); + U(IPAddressSubtree.Base).IPAddress.pbData = (LPBYTE)encodedIPAddr; + U(IPAddressWithMinSubtree.Base).IPAddress.cbData = sizeof(encodedIPAddr); + U(IPAddressWithMinSubtree.Base).IPAddress.pbData = (LPBYTE)encodedIPAddr; + U(IPAddressWithMinMaxSubtree.Base).IPAddress.cbData = sizeof(encodedIPAddr); + U(IPAddressWithMinMaxSubtree.Base).IPAddress.pbData = (LPBYTE)encodedIPAddr; + for (i = 0; + i < sizeof(encodedNameConstraints) / sizeof(encodedNameConstraints[0]); + i++) + { + DWORD size; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_NAME_CONSTRAINTS, + encodedNameConstraints[i].encoded.pbData, + encodedNameConstraints[i].encoded.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &constraints, &size); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no X509_NAME_CONSTRAINTS decode support\n"); + return; + } + ok(ret, "%d: CryptDecodeObjectEx failed: %08x\n", i, GetLastError()); + if (ret) + { + DWORD j; + + if (constraints->cPermittedSubtree != + encodedNameConstraints[i].constraints.cPermittedSubtree) + fprintf(stderr, "%d: expected %d permitted, got %d\n", i, + encodedNameConstraints[i].constraints.cPermittedSubtree, + constraints->cPermittedSubtree); + if (constraints->cPermittedSubtree == + encodedNameConstraints[i].constraints.cPermittedSubtree) + { + for (j = 0; j < constraints->cPermittedSubtree; j++) + { + compareAltNameEntry(&constraints->rgPermittedSubtree[j].Base, + &encodedNameConstraints[i].constraints.rgPermittedSubtree[j].Base); + } + } + if (constraints->cExcludedSubtree != + encodedNameConstraints[i].constraints.cExcludedSubtree) + fprintf(stderr, "%d: expected %d excluded, got %d\n", i, + encodedNameConstraints[i].constraints.cExcludedSubtree, + constraints->cExcludedSubtree); + if (constraints->cExcludedSubtree == + encodedNameConstraints[i].constraints.cExcludedSubtree) + { + for (j = 0; j < constraints->cExcludedSubtree; j++) + { + compareAltNameEntry(&constraints->rgExcludedSubtree[j].Base, + &encodedNameConstraints[i].constraints.rgExcludedSubtree[j].Base); + } + } + LocalFree(constraints); + } + } +} + +static WCHAR noticeText[] = { 'T','h','i','s',' ','i','s',' ','a',' ', + 'n','o','t','i','c','e',0 }; +static const BYTE noticeWithDisplayText[] = { + 0x30,0x22,0x1e,0x20,0x00,0x54,0x00,0x68,0x00,0x69,0x00,0x73,0x00,0x20,0x00, + 0x69,0x00,0x73,0x00,0x20,0x00,0x61,0x00,0x20,0x00,0x6e,0x00,0x6f,0x00,0x74, + 0x00,0x69,0x00,0x63,0x00,0x65 +}; +static char org[] = "Wine"; +static int noticeNumbers[] = { 2,3 }; +static BYTE noticeWithReference[] = { + 0x30,0x32,0x30,0x0e,0x16,0x04,0x57,0x69,0x6e,0x65,0x30,0x06,0x02,0x01,0x02, + 0x02,0x01,0x03,0x1e,0x20,0x00,0x54,0x00,0x68,0x00,0x69,0x00,0x73,0x00,0x20, + 0x00,0x69,0x00,0x73,0x00,0x20,0x00,0x61,0x00,0x20,0x00,0x6e,0x00,0x6f,0x00, + 0x74,0x00,0x69,0x00,0x63,0x00,0x65 +}; + +static void test_encodePolicyQualifierUserNotice(DWORD dwEncoding) +{ + BOOL ret; + LPBYTE buf; + DWORD size; + CERT_POLICY_QUALIFIER_USER_NOTICE notice; + CERT_POLICY_QUALIFIER_NOTICE_REFERENCE reference; + + memset(¬ice, 0, sizeof(notice)); + ret = pCryptEncodeObjectEx(dwEncoding, + X509_PKIX_POLICY_QUALIFIER_USERNOTICE, ¬ice, CRYPT_ENCODE_ALLOC_FLAG, + NULL, &buf, &size); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no X509_PKIX_POLICY_QUALIFIER_USERNOTICE encode support\n"); + return; + } + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(sizeof(emptySequence) == size, "unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "unexpected value\n"); + LocalFree(buf); + } + notice.pszDisplayText = noticeText; + ret = pCryptEncodeObjectEx(dwEncoding, + X509_PKIX_POLICY_QUALIFIER_USERNOTICE, ¬ice, CRYPT_ENCODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(sizeof(noticeWithDisplayText) == size, "unexpected size %d\n", size); + ok(!memcmp(buf, noticeWithDisplayText, size), "unexpected value\n"); + LocalFree(buf); + } + reference.pszOrganization = org; + reference.cNoticeNumbers = 2; + reference.rgNoticeNumbers = noticeNumbers; + notice.pNoticeReference = &reference; + ret = pCryptEncodeObjectEx(dwEncoding, + X509_PKIX_POLICY_QUALIFIER_USERNOTICE, ¬ice, CRYPT_ENCODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(sizeof(noticeWithReference) == size, "unexpected size %d\n", size); + ok(!memcmp(buf, noticeWithReference, size), "unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodePolicyQualifierUserNotice(DWORD dwEncoding) +{ + BOOL ret; + CERT_POLICY_QUALIFIER_USER_NOTICE *notice; + DWORD size; + + ret = pCryptDecodeObjectEx(dwEncoding, + X509_PKIX_POLICY_QUALIFIER_USERNOTICE, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + ¬ice, &size); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + skip("no X509_PKIX_POLICY_QUALIFIER_USERNOTICE decode support\n"); + return; + } + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(notice->pszDisplayText == NULL, "unexpected display text\n"); + ok(notice->pNoticeReference == NULL, "unexpected notice reference\n"); + LocalFree(notice); + } + ret = pCryptDecodeObjectEx(dwEncoding, + X509_PKIX_POLICY_QUALIFIER_USERNOTICE, + noticeWithDisplayText, sizeof(noticeWithDisplayText), + CRYPT_DECODE_ALLOC_FLAG, NULL, ¬ice, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(!lstrcmpW(notice->pszDisplayText, noticeText), + "unexpected display text\n"); + ok(notice->pNoticeReference == NULL, "unexpected notice reference\n"); + LocalFree(notice); + } + ret = pCryptDecodeObjectEx(dwEncoding, + X509_PKIX_POLICY_QUALIFIER_USERNOTICE, + noticeWithReference, sizeof(noticeWithReference), + CRYPT_DECODE_ALLOC_FLAG, NULL, ¬ice, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(!lstrcmpW(notice->pszDisplayText, noticeText), + "unexpected display text\n"); + ok(notice->pNoticeReference != NULL, "expected a notice reference\n"); + if (notice->pNoticeReference) + { + ok(!strcmp(notice->pNoticeReference->pszOrganization, org), + "unexpected organization %s\n", + notice->pNoticeReference->pszOrganization); + ok(notice->pNoticeReference->cNoticeNumbers == 2, + "expected 2 notice numbers, got %d\n", + notice->pNoticeReference->cNoticeNumbers); + ok(notice->pNoticeReference->rgNoticeNumbers[0] == noticeNumbers[0], + "unexpected notice number %d\n", + notice->pNoticeReference->rgNoticeNumbers[0]); + ok(notice->pNoticeReference->rgNoticeNumbers[1] == noticeNumbers[1], + "unexpected notice number %d\n", + notice->pNoticeReference->rgNoticeNumbers[1]); + } + LocalFree(notice); + } +} + +static char oid_any_policy[] = "2.5.29.32.0"; +static const BYTE policiesWithAnyPolicy[] = { + 0x30,0x08,0x30,0x06,0x06,0x04,0x55,0x1d,0x20,0x00 +}; +static char oid1[] = "1.2.3"; +static char oid_user_notice[] = "1.3.6.1.5.5.7.2.2"; +static const BYTE twoPolicies[] = { + 0x30,0x50,0x30,0x06,0x06,0x04,0x55,0x1d,0x20,0x00,0x30,0x46,0x06,0x02,0x2a, + 0x03,0x30,0x40,0x30,0x3e,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x02, + 0x30,0x32,0x30,0x0e,0x16,0x04,0x57,0x69,0x6e,0x65,0x30,0x06,0x02,0x01,0x02, + 0x02,0x01,0x03,0x1e,0x20,0x00,0x54,0x00,0x68,0x00,0x69,0x00,0x73,0x00,0x20, + 0x00,0x69,0x00,0x73,0x00,0x20,0x00,0x61,0x00,0x20,0x00,0x6e,0x00,0x6f,0x00, + 0x74,0x00,0x69,0x00,0x63,0x00,0x65 +}; + +static void test_encodeCertPolicies(DWORD dwEncoding) +{ + BOOL ret; + CERT_POLICIES_INFO info; + CERT_POLICY_INFO policy[2]; + CERT_POLICY_QUALIFIER_INFO qualifier; + LPBYTE buf; + DWORD size; + + memset(&info, 0, sizeof(info)); + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_POLICIES, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(sizeof(emptySequence) == size, "unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "unexpected value\n"); + LocalFree(buf); + } + memset(policy, 0, sizeof(policy)); + info.cPolicyInfo = 1; + info.rgPolicyInfo = policy; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_POLICIES, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x/NT4 */), + "expected E_INVALIDARG or OSS_LIMITED, got %08x\n", GetLastError()); + policy[0].pszPolicyIdentifier = oid_any_policy; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_POLICIES, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(sizeof(policiesWithAnyPolicy) == size, "unexpected size %d\n", size); + ok(!memcmp(buf, policiesWithAnyPolicy, size), "unexpected value\n"); + LocalFree(buf); + } + policy[1].pszPolicyIdentifier = oid1; + memset(&qualifier, 0, sizeof(qualifier)); + qualifier.pszPolicyQualifierId = oid_user_notice; + qualifier.Qualifier.cbData = sizeof(noticeWithReference); + qualifier.Qualifier.pbData = noticeWithReference; + policy[1].cPolicyQualifier = 1; + policy[1].rgPolicyQualifier = &qualifier; + info.cPolicyInfo = 2; + ret = pCryptEncodeObjectEx(dwEncoding, X509_CERT_POLICIES, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(sizeof(twoPolicies) == size, "unexpected size %d\n", size); + ok(!memcmp(buf, twoPolicies, size), "unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeCertPolicies(DWORD dwEncoding) +{ + BOOL ret; + CERT_POLICIES_INFO *info; + DWORD size; + + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_POLICIES, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->cPolicyInfo == 0, "unexpected policy info %d\n", + info->cPolicyInfo); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_POLICIES, + policiesWithAnyPolicy, sizeof(policiesWithAnyPolicy), + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->cPolicyInfo == 1, "unexpected policy info %d\n", + info->cPolicyInfo); + ok(!strcmp(info->rgPolicyInfo[0].pszPolicyIdentifier, oid_any_policy), + "unexpected policy id %s\n", + info->rgPolicyInfo[0].pszPolicyIdentifier); + ok(info->rgPolicyInfo[0].cPolicyQualifier == 0, + "unexpected policy qualifier count %d\n", + info->rgPolicyInfo[0].cPolicyQualifier); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_CERT_POLICIES, + twoPolicies, sizeof(twoPolicies), + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->cPolicyInfo == 2, "unexpected policy info %d\n", + info->cPolicyInfo); + ok(!strcmp(info->rgPolicyInfo[0].pszPolicyIdentifier, oid_any_policy), + "unexpected policy id %s\n", + info->rgPolicyInfo[0].pszPolicyIdentifier); + ok(info->rgPolicyInfo[0].cPolicyQualifier == 0, + "unexpected policy qualifier count %d\n", + info->rgPolicyInfo[0].cPolicyQualifier); + ok(!strcmp(info->rgPolicyInfo[1].pszPolicyIdentifier, oid1), + "unexpected policy id %s\n", + info->rgPolicyInfo[1].pszPolicyIdentifier); + ok(info->rgPolicyInfo[1].cPolicyQualifier == 1, + "unexpected policy qualifier count %d\n", + info->rgPolicyInfo[1].cPolicyQualifier); + ok(!strcmp( + info->rgPolicyInfo[1].rgPolicyQualifier[0].pszPolicyQualifierId, + oid_user_notice), "unexpected policy qualifier id %s\n", + info->rgPolicyInfo[1].rgPolicyQualifier[0].pszPolicyQualifierId); + ok(info->rgPolicyInfo[1].rgPolicyQualifier[0].Qualifier.cbData == + sizeof(noticeWithReference), "unexpected qualifier size %d\n", + info->rgPolicyInfo[1].rgPolicyQualifier[0].Qualifier.cbData); + ok(!memcmp( + info->rgPolicyInfo[1].rgPolicyQualifier[0].Qualifier.pbData, + noticeWithReference, sizeof(noticeWithReference)), + "unexpected qualifier value\n"); + LocalFree(info); + } +} + +static const BYTE policyMappingWithOneMapping[] = { +0x30,0x0a,0x30,0x08,0x06,0x02,0x2a,0x03,0x06,0x02,0x53,0x04 }; +static const BYTE policyMappingWithTwoMappings[] = { +0x30,0x14,0x30,0x08,0x06,0x02,0x2a,0x03,0x06,0x02,0x53,0x04,0x30,0x08,0x06, +0x02,0x2b,0x04,0x06,0x02,0x55,0x06 }; +static const LPCSTR mappingOids[] = { X509_POLICY_MAPPINGS, + szOID_POLICY_MAPPINGS, szOID_LEGACY_POLICY_MAPPINGS }; + +static void test_encodeCertPolicyMappings(DWORD dwEncoding) +{ + static char oid2[] = "2.3.4"; + static char oid3[] = "1.3.4"; + static char oid4[] = "2.5.6"; + BOOL ret; + CERT_POLICY_MAPPINGS_INFO info = { 0 }; + CERT_POLICY_MAPPING mapping[2]; + LPBYTE buf; + DWORD size, i; + + /* Each of the mapping OIDs is equivalent, so check with all of them */ + for (i = 0; i < sizeof(mappingOids) / sizeof(mappingOids[0]); i++) + { + memset(&info, 0, sizeof(info)); + ret = pCryptEncodeObjectEx(dwEncoding, mappingOids[i], &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND), + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + win_skip("no policy mappings support\n"); + return; + } + if (ret) + { + ok(size == sizeof(emptySequence), "unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, sizeof(emptySequence)), + "unexpected value\n"); + LocalFree(buf); + } + mapping[0].pszIssuerDomainPolicy = NULL; + mapping[0].pszSubjectDomainPolicy = NULL; + info.cPolicyMapping = 1; + info.rgPolicyMapping = mapping; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(dwEncoding, mappingOids[i], &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + mapping[0].pszIssuerDomainPolicy = oid1; + mapping[0].pszSubjectDomainPolicy = oid2; + ret = pCryptEncodeObjectEx(dwEncoding, mappingOids[i], &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(policyMappingWithOneMapping), + "unexpected size %d\n", size); + ok(!memcmp(buf, policyMappingWithOneMapping, size), + "unexpected value\n"); + LocalFree(buf); + } + mapping[1].pszIssuerDomainPolicy = oid3; + mapping[1].pszSubjectDomainPolicy = oid4; + info.cPolicyMapping = 2; + ret = pCryptEncodeObjectEx(dwEncoding, mappingOids[i], &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(policyMappingWithTwoMappings), + "unexpected size %d\n", size); + ok(!memcmp(buf, policyMappingWithTwoMappings, size), + "unexpected value\n"); + LocalFree(buf); + } + } +} + +static void test_decodeCertPolicyMappings(DWORD dwEncoding) +{ + DWORD size, i; + CERT_POLICY_MAPPINGS_INFO *info; + BOOL ret; + + /* Each of the mapping OIDs is equivalent, so check with all of them */ + for (i = 0; i < sizeof(mappingOids) / sizeof(mappingOids[0]); i++) + { + ret = pCryptDecodeObjectEx(dwEncoding, mappingOids[i], + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &info, &size); + ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND), + "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + win_skip("no policy mappings support\n"); + return; + } + if (ret) + { + ok(info->cPolicyMapping == 0, + "expected 0 policy mappings, got %d\n", info->cPolicyMapping); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(dwEncoding, mappingOids[i], + policyMappingWithOneMapping, sizeof(policyMappingWithOneMapping), + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->cPolicyMapping == 1, + "expected 1 policy mappings, got %d\n", info->cPolicyMapping); + ok(!strcmp(info->rgPolicyMapping[0].pszIssuerDomainPolicy, "1.2.3"), + "unexpected issuer policy %s\n", + info->rgPolicyMapping[0].pszIssuerDomainPolicy); + ok(!strcmp(info->rgPolicyMapping[0].pszSubjectDomainPolicy, + "2.3.4"), "unexpected subject policy %s\n", + info->rgPolicyMapping[0].pszSubjectDomainPolicy); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(dwEncoding, mappingOids[i], + policyMappingWithTwoMappings, sizeof(policyMappingWithTwoMappings), + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->cPolicyMapping == 2, + "expected 2 policy mappings, got %d\n", info->cPolicyMapping); + ok(!strcmp(info->rgPolicyMapping[0].pszIssuerDomainPolicy, "1.2.3"), + "unexpected issuer policy %s\n", + info->rgPolicyMapping[0].pszIssuerDomainPolicy); + ok(!strcmp(info->rgPolicyMapping[0].pszSubjectDomainPolicy, + "2.3.4"), "unexpected subject policy %s\n", + info->rgPolicyMapping[0].pszSubjectDomainPolicy); + ok(!strcmp(info->rgPolicyMapping[1].pszIssuerDomainPolicy, "1.3.4"), + "unexpected issuer policy %s\n", + info->rgPolicyMapping[1].pszIssuerDomainPolicy); + ok(!strcmp(info->rgPolicyMapping[1].pszSubjectDomainPolicy, + "2.5.6"), "unexpected subject policy %s\n", + info->rgPolicyMapping[1].pszSubjectDomainPolicy); + LocalFree(info); + } + } +} + +static const BYTE policyConstraintsWithRequireExplicit[] = { +0x30,0x03,0x80,0x01,0x00 }; +static const BYTE policyConstraintsWithInhibitMapping[] = { +0x30,0x03,0x81,0x01,0x01 }; +static const BYTE policyConstraintsWithBoth[] = { +0x30,0x06,0x80,0x01,0x01,0x81,0x01,0x01 }; + +static void test_encodeCertPolicyConstraints(DWORD dwEncoding) +{ + CERT_POLICY_CONSTRAINTS_INFO info = { 0 }; + LPBYTE buf; + DWORD size; + BOOL ret; + + /* Even though RFC 5280 explicitly states CAs must not issue empty + * policy constraints (section 4.2.1.11), the API doesn't prevent it. + */ + ret = pCryptEncodeObjectEx(dwEncoding, X509_POLICY_CONSTRAINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND), + "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + win_skip("no policy constraints support\n"); + return; + } + if (ret) + { + ok(size == sizeof(emptySequence), "unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, sizeof(emptySequence)), + "unexpected value\n"); + LocalFree(buf); + } + /* If fRequireExplicitPolicy is set but dwRequireExplicitPolicySkipCerts + * is not, then a skip of 0 is encoded. + */ + info.fRequireExplicitPolicy = TRUE; + ret = pCryptEncodeObjectEx(dwEncoding, X509_POLICY_CONSTRAINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(policyConstraintsWithRequireExplicit), + "unexpected size %d\n", size); + ok(!memcmp(buf, policyConstraintsWithRequireExplicit, + sizeof(policyConstraintsWithRequireExplicit)), "unexpected value\n"); + LocalFree(buf); + } + /* With inhibit policy mapping */ + info.fRequireExplicitPolicy = FALSE; + info.dwRequireExplicitPolicySkipCerts = 0; + info.fInhibitPolicyMapping = TRUE; + info.dwInhibitPolicyMappingSkipCerts = 1; + ret = pCryptEncodeObjectEx(dwEncoding, X509_POLICY_CONSTRAINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(policyConstraintsWithInhibitMapping), + "unexpected size %d\n", size); + ok(!memcmp(buf, policyConstraintsWithInhibitMapping, + sizeof(policyConstraintsWithInhibitMapping)), "unexpected value\n"); + LocalFree(buf); + } + /* And with both */ + info.fRequireExplicitPolicy = TRUE; + info.dwRequireExplicitPolicySkipCerts = 1; + ret = pCryptEncodeObjectEx(dwEncoding, X509_POLICY_CONSTRAINTS, &info, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(policyConstraintsWithBoth), "unexpected size %d\n", + size); + ok(!memcmp(buf, policyConstraintsWithBoth, + sizeof(policyConstraintsWithBoth)), "unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeCertPolicyConstraints(DWORD dwEncoding) +{ + CERT_POLICY_CONSTRAINTS_INFO *info; + DWORD size; + BOOL ret; + + /* Again, even though CAs must not issue such constraints, they can be + * decoded. + */ + ret = pCryptDecodeObjectEx(dwEncoding, X509_POLICY_CONSTRAINTS, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &info, &size); + ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND), + "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + { + win_skip("no policy mappings support\n"); + return; + } + if (ret) + { + ok(!info->fRequireExplicitPolicy, + "expected require explicit = FALSE\n"); + ok(!info->fInhibitPolicyMapping, + "expected implicit mapping = FALSE\n"); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_POLICY_CONSTRAINTS, + policyConstraintsWithRequireExplicit, + sizeof(policyConstraintsWithRequireExplicit), CRYPT_DECODE_ALLOC_FLAG, + NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->fRequireExplicitPolicy, + "expected require explicit = TRUE\n"); + ok(info->dwRequireExplicitPolicySkipCerts == 0, "expected 0, got %d\n", + info->dwRequireExplicitPolicySkipCerts); + ok(!info->fInhibitPolicyMapping, + "expected implicit mapping = FALSE\n"); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_POLICY_CONSTRAINTS, + policyConstraintsWithInhibitMapping, + sizeof(policyConstraintsWithInhibitMapping), CRYPT_DECODE_ALLOC_FLAG, + NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(!info->fRequireExplicitPolicy, + "expected require explicit = FALSE\n"); + ok(info->fInhibitPolicyMapping, + "expected implicit mapping = TRUE\n"); + ok(info->dwInhibitPolicyMappingSkipCerts == 1, "expected 1, got %d\n", + info->dwInhibitPolicyMappingSkipCerts); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(dwEncoding, X509_POLICY_CONSTRAINTS, + policyConstraintsWithBoth, sizeof(policyConstraintsWithBoth), + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->fRequireExplicitPolicy, + "expected require explicit = TRUE\n"); + ok(info->dwRequireExplicitPolicySkipCerts == 1, "expected 1, got %d\n", + info->dwRequireExplicitPolicySkipCerts); + ok(info->fInhibitPolicyMapping, + "expected implicit mapping = TRUE\n"); + ok(info->dwInhibitPolicyMappingSkipCerts == 1, "expected 1, got %d\n", + info->dwInhibitPolicyMappingSkipCerts); + LocalFree(info); + } +} + +/* Free *pInfo with HeapFree */ +static void testExportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO *pInfo) +{ + BOOL ret; + DWORD size = 0; + HCRYPTKEY key; + + /* This crashes + ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, NULL); + */ + ret = CryptExportPublicKeyInfoEx(0, 0, 0, NULL, 0, NULL, NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, 0, NULL, 0, NULL, NULL, + &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ret = CryptExportPublicKeyInfoEx(0, 0, X509_ASN_ENCODING, NULL, 0, NULL, + NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ret = CryptExportPublicKeyInfoEx(0, AT_SIGNATURE, X509_ASN_ENCODING, NULL, + 0, NULL, NULL, &size); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + /* Test with no key */ + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, NULL, + 0, NULL, NULL, &size); + ok(!ret && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08x\n", + GetLastError()); + ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key); + ok(ret, "CryptGenKey failed: %08x\n", GetLastError()); + if (ret) + { + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING, + NULL, 0, NULL, NULL, &size); + ok(ret, "CryptExportPublicKeyInfoEx failed: %08x\n", GetLastError()); + *pInfo = HeapAlloc(GetProcessHeap(), 0, size); + if (*pInfo) + { + ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, + X509_ASN_ENCODING, NULL, 0, NULL, *pInfo, &size); + ok(ret, "CryptExportPublicKeyInfoEx failed: %08x\n", + GetLastError()); + if (ret) + { + /* By default (we passed NULL as the OID) the OID is + * szOID_RSA_RSA. + */ + ok(!strcmp((*pInfo)->Algorithm.pszObjId, szOID_RSA_RSA), + "Expected %s, got %s\n", szOID_RSA_RSA, + (*pInfo)->Algorithm.pszObjId); + } + } + } + CryptDestroyKey(key); +} + +static const BYTE expiredCert[] = { 0x30, 0x82, 0x01, 0x33, 0x30, 0x81, 0xe2, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xc4, 0xd7, 0x7f, 0x0e, 0x6f, 0xa6, + 0x8c, 0xaa, 0x47, 0x47, 0x40, 0xe7, 0xb7, 0x0b, 0x4a, 0x7f, 0x30, 0x09, 0x06, + 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x1f, 0x31, 0x1d, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40, + 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x36, 0x39, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x1f, 0x31, 0x1d, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x14, 0x61, 0x72, 0x69, 0x63, 0x40, + 0x63, 0x6f, 0x64, 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, + 0x00, 0xa1, 0xaf, 0x4a, 0xea, 0xa7, 0x83, 0x57, 0xc0, 0x37, 0x33, 0x7e, 0x29, + 0x5e, 0x0d, 0xfc, 0x44, 0x74, 0x3a, 0x1d, 0xc3, 0x1b, 0x1d, 0x96, 0xed, 0x4e, + 0xf4, 0x1b, 0x98, 0xec, 0x69, 0x1b, 0x04, 0xea, 0x25, 0xcf, 0xb3, 0x2a, 0xf5, + 0xd9, 0x22, 0xd9, 0x8d, 0x08, 0x39, 0x81, 0xc6, 0xe0, 0x4f, 0x12, 0x37, 0x2a, + 0x3f, 0x80, 0xa6, 0x6c, 0x67, 0x43, 0x3a, 0xdd, 0x95, 0x0c, 0xbb, 0x2f, 0x6b, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, + 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x8f, 0xa2, 0x5b, 0xd6, 0xdf, 0x34, 0xd0, + 0xa2, 0xa7, 0x47, 0xf1, 0x13, 0x79, 0xd3, 0xf3, 0x39, 0xbd, 0x4e, 0x2b, 0xa3, + 0xf4, 0x63, 0x37, 0xac, 0x5a, 0x0c, 0x5e, 0x4d, 0x0d, 0x54, 0x87, 0x4f, 0x31, + 0xfb, 0xa0, 0xce, 0x8f, 0x9a, 0x2f, 0x4d, 0x48, 0xc6, 0x84, 0x8d, 0xf5, 0x70, + 0x74, 0x17, 0xa5, 0xf3, 0x66, 0x47, 0x06, 0xd6, 0x64, 0x45, 0xbc, 0x52, 0xef, + 0x49, 0xe5, 0xf9, 0x65, 0xf3 }; + +static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info) +{ + BOOL ret; + HCRYPTKEY key; + PCCERT_CONTEXT context; + DWORD dwSize; + ALG_ID ai; + + /* These crash + ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, NULL); + ret = CryptImportPublicKeyInfoEx(0, 0, NULL, 0, 0, NULL, &key); + ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, NULL); + ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL, + NULL); + */ + ret = CryptImportPublicKeyInfoEx(0, 0, info, 0, 0, NULL, &key); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = CryptImportPublicKeyInfoEx(csp, 0, info, 0, 0, NULL, &key); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = CryptImportPublicKeyInfoEx(0, X509_ASN_ENCODING, info, 0, 0, NULL, + &key); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + + /* Export key with standard algorithm (CALG_RSA_KEYX) */ + ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, 0, 0, NULL, + &key); + ok(ret, "CryptImportPublicKeyInfoEx failed: %08x\n", GetLastError()); + + dwSize = sizeof(ai); + CryptGetKeyParam(key, KP_ALGID, (LPVOID)&ai, &dwSize, 0); + ok(ret, "CryptGetKeyParam failed: %08x\n", GetLastError()); + if(ret) + { + ok(dwSize == sizeof(ai), "CryptGetKeyParam returned size %d\n",dwSize); + ok(ai == CALG_RSA_KEYX, "Default ALG_ID is %04x (expected CALG_RSA_KEYX)\n", ai); + } + + CryptDestroyKey(key); + + /* Repeat with forced algorithm */ + ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, info, CALG_RSA_SIGN, 0, NULL, + &key); + ok(ret, "CryptImportPublicKeyInfoEx failed: %08x\n", GetLastError()); + + dwSize = sizeof(ai); + CryptGetKeyParam(key, KP_ALGID, (LPVOID)&ai, &dwSize, 0); + ok(ret, "CryptGetKeyParam failed: %08x\n", GetLastError()); + if(ret) + { + ok(dwSize == sizeof(ai), "CryptGetKeyParam returned size %d\n",dwSize); + ok(ai == CALG_RSA_SIGN, "ALG_ID is %04x (expected CALG_RSA_SIGN)\n", ai); + } + + CryptDestroyKey(key); + + /* Test importing a public key from a certificate context */ + context = CertCreateCertificateContext(X509_ASN_ENCODING, expiredCert, + sizeof(expiredCert)); + ok(context != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + if (context) + { + ok(!strcmp(szOID_RSA_RSA, + context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId), + "Expected %s, got %s\n", szOID_RSA_RSA, + context->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); + ret = CryptImportPublicKeyInfoEx(csp, X509_ASN_ENCODING, + &context->pCertInfo->SubjectPublicKeyInfo, 0, 0, NULL, &key); + ok(ret, "CryptImportPublicKeyInfoEx failed: %08x\n", GetLastError()); + CryptDestroyKey(key); + CertFreeCertificateContext(context); + } +} + +static const char cspName[] = "WineCryptTemp"; + +static void testPortPublicKeyInfo(void) +{ + HCRYPTPROV csp; + BOOL ret; + PCERT_PUBLIC_KEY_INFO info = NULL; + + /* Just in case a previous run failed, delete this thing */ + CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_NEWKEYSET); + + testExportPublicKey(csp, &info); + testImportPublicKey(csp, info); + + HeapFree(GetProcessHeap(), 0, info); + CryptReleaseContext(csp, 0); + ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); +} + +START_TEST(encode) +{ + static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING }; + HMODULE hCrypt32; + DWORD i; + + hCrypt32 = GetModuleHandleA("crypt32.dll"); + pCryptDecodeObjectEx = (void*)GetProcAddress(hCrypt32, "CryptDecodeObjectEx"); + pCryptEncodeObjectEx = (void*)GetProcAddress(hCrypt32, "CryptEncodeObjectEx"); + if (!pCryptDecodeObjectEx || !pCryptEncodeObjectEx) + { + win_skip("CryptDecodeObjectEx() is not available\n"); + return; + } + + for (i = 0; i < sizeof(encodings) / sizeof(encodings[0]); i++) + { + test_encodeInt(encodings[i]); + test_decodeInt(encodings[i]); + test_encodeEnumerated(encodings[i]); + test_decodeEnumerated(encodings[i]); + test_encodeFiletime(encodings[i]); + test_decodeFiletime(encodings[i]); + test_encodeName(encodings[i]); + test_decodeName(encodings[i]); + test_encodeUnicodeName(encodings[i]); + test_decodeUnicodeName(encodings[i]); + test_encodeNameValue(encodings[i]); + test_decodeNameValue(encodings[i]); + test_encodeUnicodeNameValue(encodings[i]); + test_decodeUnicodeNameValue(encodings[i]); + test_encodeAltName(encodings[i]); + test_decodeAltName(encodings[i]); + test_encodeOctets(encodings[i]); + test_decodeOctets(encodings[i]); + test_encodeBits(encodings[i]); + test_decodeBits(encodings[i]); + test_encodeBasicConstraints(encodings[i]); + test_decodeBasicConstraints(encodings[i]); + test_encodeRsaPublicKey(encodings[i]); + test_decodeRsaPublicKey(encodings[i]); + test_encodeSequenceOfAny(encodings[i]); + test_decodeSequenceOfAny(encodings[i]); + test_encodeExtensions(encodings[i]); + test_decodeExtensions(encodings[i]); + test_encodePublicKeyInfo(encodings[i]); + test_decodePublicKeyInfo(encodings[i]); + test_encodeCertToBeSigned(encodings[i]); + test_decodeCertToBeSigned(encodings[i]); + test_encodeCert(encodings[i]); + test_decodeCert(encodings[i]); + test_encodeCRLDistPoints(encodings[i]); + test_decodeCRLDistPoints(encodings[i]); + test_encodeCRLIssuingDistPoint(encodings[i]); + test_decodeCRLIssuingDistPoint(encodings[i]); + test_encodeCRLToBeSigned(encodings[i]); + test_decodeCRLToBeSigned(encodings[i]); + test_encodeEnhancedKeyUsage(encodings[i]); + test_decodeEnhancedKeyUsage(encodings[i]); + test_encodeAuthorityKeyId(encodings[i]); + test_decodeAuthorityKeyId(encodings[i]); + test_encodeAuthorityKeyId2(encodings[i]); + test_decodeAuthorityKeyId2(encodings[i]); + test_encodeAuthorityInfoAccess(encodings[i]); + test_decodeAuthorityInfoAccess(encodings[i]); + test_encodeCTL(encodings[i]); + test_decodeCTL(encodings[i]); + test_encodePKCSContentInfo(encodings[i]); + test_decodePKCSContentInfo(encodings[i]); + test_encodePKCSAttribute(encodings[i]); + test_decodePKCSAttribute(encodings[i]); + test_encodePKCSAttributes(encodings[i]); + test_decodePKCSAttributes(encodings[i]); + test_encodePKCSSMimeCapabilities(encodings[i]); + test_decodePKCSSMimeCapabilities(encodings[i]); + test_encodePKCSSignerInfo(encodings[i]); + test_decodePKCSSignerInfo(encodings[i]); + test_encodeCMSSignerInfo(encodings[i]); + test_decodeCMSSignerInfo(encodings[i]); + test_encodeNameConstraints(encodings[i]); + test_decodeNameConstraints(encodings[i]); + test_encodePolicyQualifierUserNotice(encodings[i]); + test_decodePolicyQualifierUserNotice(encodings[i]); + test_encodeCertPolicies(encodings[i]); + test_decodeCertPolicies(encodings[i]); + test_encodeCertPolicyMappings(encodings[i]); + test_decodeCertPolicyMappings(encodings[i]); + test_encodeCertPolicyConstraints(encodings[i]); + test_decodeCertPolicyConstraints(encodings[i]); + } + testPortPublicKeyInfo(); +} diff --git a/rostests/winetests/crypt32/main.c b/rostests/winetests/crypt32/main.c new file mode 100644 index 00000000000..9b622bbbd08 --- /dev/null +++ b/rostests/winetests/crypt32/main.c @@ -0,0 +1,498 @@ +/* + * Miscellaneous crypt32 tests + * + * Copyright 2005 Juan Lang + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +HMODULE hCrypt; + +static void test_findAttribute(void) +{ + PCRYPT_ATTRIBUTE ret; + BYTE blobbin[] = {0x02,0x01,0x01}; + static CHAR oid[] = "1.2.3"; + CRYPT_ATTR_BLOB blobs[] = { { sizeof blobbin, blobbin }, }; + CRYPT_ATTRIBUTE attr = { oid, sizeof(blobs) / sizeof(blobs[0]), blobs }; + + /* returns NULL, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindAttribute(NULL, 0, NULL); + ok(ret == NULL, "Expected failure\n"); + ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", + GetLastError()); + if (0) + { + /* crashes */ + SetLastError(0xdeadbeef); + ret = CertFindAttribute(NULL, 1, NULL); + /* returns NULL, last error is ERROR_INVALID_PARAMETER + * crashes on Vista + */ + SetLastError(0xdeadbeef); + ret = CertFindAttribute(NULL, 1, &attr); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d (%08x)\n", GetLastError(), + GetLastError()); + } + /* returns NULL, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindAttribute("bogus", 1, &attr); + ok(ret == NULL, "Expected failure\n"); + ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", + GetLastError()); + /* returns NULL, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindAttribute("1.2.4", 1, &attr); + ok(ret == NULL, "Expected failure\n"); + ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", + GetLastError()); + /* succeeds, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindAttribute("1.2.3", 1, &attr); + ok(ret != NULL, "CertFindAttribute failed: %08x\n", GetLastError()); +} + +static void test_findExtension(void) +{ + PCERT_EXTENSION ret; + static CHAR oid[] = "1.2.3"; + BYTE blobbin[] = {0x02,0x01,0x01}; + CERT_EXTENSION ext = { oid, TRUE, { sizeof blobbin, blobbin } }; + + /* returns NULL, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindExtension(NULL, 0, NULL); + ok(ret == NULL, "Expected failure\n"); + ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", + GetLastError()); + if (0) + { + /* crashes */ + SetLastError(0xdeadbeef); + ret = CertFindExtension(NULL, 1, NULL); + /* returns NULL, last error is ERROR_INVALID_PARAMETER + * crashes on Vista + */ + SetLastError(0xdeadbeef); + ret = CertFindExtension(NULL, 1, &ext); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d (%08x)\n", GetLastError(), + GetLastError()); + } + /* returns NULL, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindExtension("bogus", 1, &ext); + ok(ret == NULL, "Expected failure\n"); + ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", + GetLastError()); + /* returns NULL, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindExtension("1.2.4", 1, &ext); + ok(ret == NULL, "Expected failure\n"); + ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", + GetLastError()); + /* succeeds, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindExtension("1.2.3", 1, &ext); + ok(ret != NULL, "CertFindExtension failed: %08x\n", GetLastError()); +} + +static void test_findRDNAttr(void) +{ + PCERT_RDN_ATTR ret; + static CHAR oid[] = "1.2.3"; + BYTE bin[] = { 0x16,0x09,'J','u','a','n',' ','L','a','n','g' }; + CERT_RDN_ATTR attrs[] = { + { oid, CERT_RDN_IA5_STRING, { sizeof bin, bin } }, + }; + CERT_RDN rdns[] = { + { sizeof(attrs) / sizeof(attrs[0]), attrs }, + }; + CERT_NAME_INFO nameInfo = { sizeof(rdns) / sizeof(rdns[0]), rdns }; + + if (0) + { + /* crashes */ + SetLastError(0xdeadbeef); + ret = CertFindRDNAttr(NULL, NULL); + /* returns NULL, last error is ERROR_INVALID_PARAMETER + * crashes on Vista + */ + SetLastError(0xdeadbeef); + ret = CertFindRDNAttr(NULL, &nameInfo); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d (%08x)\n", GetLastError(), + GetLastError()); + } + /* returns NULL, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindRDNAttr("bogus", &nameInfo); + ok(ret == NULL, "Expected failure\n"); + ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", + GetLastError()); + /* returns NULL, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindRDNAttr("1.2.4", &nameInfo); + ok(ret == NULL, "Expected failure\n"); + ok(GetLastError() == 0xdeadbeef, "Last error was set to %08x\n", + GetLastError()); + /* succeeds, last error not set */ + SetLastError(0xdeadbeef); + ret = CertFindRDNAttr("1.2.3", &nameInfo); + ok(ret != NULL, "CertFindRDNAttr failed: %08x\n", GetLastError()); +} + +static void test_verifyTimeValidity(void) +{ + SYSTEMTIME sysTime; + FILETIME fileTime; + CERT_INFO info = { 0 }; + LONG ret; + + GetSystemTime(&sysTime); + SystemTimeToFileTime(&sysTime, &fileTime); + /* crashes + ret = CertVerifyTimeValidity(NULL, NULL); + ret = CertVerifyTimeValidity(&fileTime, NULL); + */ + /* Check with 0 NotBefore and NotAfter */ + ret = CertVerifyTimeValidity(&fileTime, &info); + ok(ret == 1, "Expected 1, got %d\n", ret); + memcpy(&info.NotAfter, &fileTime, sizeof(info.NotAfter)); + /* Check with NotAfter equal to comparison time */ + ret = CertVerifyTimeValidity(&fileTime, &info); + ok(ret == 0, "Expected 0, got %d\n", ret); + /* Check with NotBefore after comparison time */ + memcpy(&info.NotBefore, &fileTime, sizeof(info.NotBefore)); + info.NotBefore.dwLowDateTime += 5000; + ret = CertVerifyTimeValidity(&fileTime, &info); + ok(ret == -1, "Expected -1, got %d\n", ret); +} + +static void test_cryptAllocate(void) +{ + LPVOID buf; + + buf = CryptMemAlloc(0); + ok(buf != NULL, "CryptMemAlloc failed: %08x\n", GetLastError()); + CryptMemFree(buf); + /* CryptMemRealloc(NULL, 0) fails pre-Vista */ + buf = CryptMemAlloc(0); + buf = CryptMemRealloc(buf, 1); + ok(buf != NULL, "CryptMemRealloc failed: %08x\n", GetLastError()); + CryptMemFree(buf); +} + +typedef DWORD (WINAPI *I_CryptAllocTlsFunc)(void); +typedef LPVOID (WINAPI *I_CryptDetachTlsFunc)(DWORD dwTlsIndex); +typedef LPVOID (WINAPI *I_CryptGetTlsFunc)(DWORD dwTlsIndex); +typedef BOOL (WINAPI *I_CryptSetTlsFunc)(DWORD dwTlsIndex, LPVOID lpTlsValue); +typedef BOOL (WINAPI *I_CryptFreeTlsFunc)(DWORD dwTlsIndex, DWORD unknown); + +static I_CryptAllocTlsFunc pI_CryptAllocTls; +static I_CryptDetachTlsFunc pI_CryptDetachTls; +static I_CryptGetTlsFunc pI_CryptGetTls; +static I_CryptSetTlsFunc pI_CryptSetTls; +static I_CryptFreeTlsFunc pI_CryptFreeTls; + +static void test_cryptTls(void) +{ + DWORD index; + BOOL ret; + + pI_CryptAllocTls = (I_CryptAllocTlsFunc)GetProcAddress(hCrypt, + "I_CryptAllocTls"); + pI_CryptDetachTls = (I_CryptDetachTlsFunc)GetProcAddress(hCrypt, + "I_CryptDetachTls"); + pI_CryptGetTls = (I_CryptGetTlsFunc)GetProcAddress(hCrypt, + "I_CryptGetTls"); + pI_CryptSetTls = (I_CryptSetTlsFunc)GetProcAddress(hCrypt, + "I_CryptSetTls"); + pI_CryptFreeTls = (I_CryptFreeTlsFunc)GetProcAddress(hCrypt, + "I_CryptFreeTls"); + + /* One normal pass */ + index = pI_CryptAllocTls(); + ok(index, "I_CryptAllocTls failed: %08x\n", GetLastError()); + if (index) + { + LPVOID ptr; + + ptr = pI_CryptGetTls(index); + ok(!ptr, "Expected NULL\n"); + ret = pI_CryptSetTls(index, (LPVOID)0xdeadbeef); + ok(ret, "I_CryptSetTls failed: %08x\n", GetLastError()); + ptr = pI_CryptGetTls(index); + ok(ptr == (LPVOID)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", ptr); + /* This crashes + ret = pI_CryptFreeTls(index, 1); + */ + ret = pI_CryptFreeTls(index, 0); + ok(ret, "I_CryptFreeTls failed: %08x\n", GetLastError()); + ret = pI_CryptFreeTls(index, 0); + /* Not sure if this fails because TlsFree should fail, so leave as + * todo for now. + */ + todo_wine ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + /* Similar pass, check I_CryptDetachTls */ + index = pI_CryptAllocTls(); + ok(index, "I_CryptAllocTls failed: %08x\n", GetLastError()); + if (index) + { + LPVOID ptr; + + ptr = pI_CryptGetTls(index); + ok(!ptr, "Expected NULL\n"); + ret = pI_CryptSetTls(index, (LPVOID)0xdeadbeef); + ok(ret, "I_CryptSetTls failed: %08x\n", GetLastError()); + ptr = pI_CryptGetTls(index); + ok(ptr == (LPVOID)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", ptr); + ptr = pI_CryptDetachTls(index); + ok(ptr == (LPVOID)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", ptr); + ptr = pI_CryptGetTls(index); + ok(!ptr, "Expected NULL\n"); + } +} + +typedef BOOL (WINAPI *I_CryptReadTrustedPublisherDWORDValueFromRegistryFunc) + (LPCWSTR, DWORD *); + +static void test_readTrustedPublisherDWORD(void) +{ + I_CryptReadTrustedPublisherDWORDValueFromRegistryFunc pReadDWORD; + + pReadDWORD = + (I_CryptReadTrustedPublisherDWORDValueFromRegistryFunc)GetProcAddress( + hCrypt, "I_CryptReadTrustedPublisherDWORDValueFromRegistry"); + if (pReadDWORD) + { + static const WCHAR safer[] = { + 'S','o','f','t','w','a','r','e','\\', + 'P','o','l','i','c','i','e','s','\\', + 'M','i','c','r','o','s','o','f','t','\\','S','y','s','t','e','m', + 'C','e','r','t','i','f','i','c','a','t','e','s','\\', + 'T','r','u','s','t','e','d','P','u','b','l','i','s','h','e','r', + '\\','S','a','f','e','r',0 }; + static const WCHAR authenticodeFlags[] = { 'A','u','t','h','e','n', + 't','i','c','o','d','e','F','l','a','g','s',0 }; + BOOL ret, exists = FALSE; + DWORD size, readFlags = 0, returnedFlags; + HKEY key; + LONG rc; + + rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, safer, &key); + if (rc == ERROR_SUCCESS) + { + size = sizeof(readFlags); + rc = RegQueryValueExW(key, authenticodeFlags, NULL, NULL, + (LPBYTE)&readFlags, &size); + if (rc == ERROR_SUCCESS) + exists = TRUE; + } + returnedFlags = 0xdeadbeef; + ret = pReadDWORD(authenticodeFlags, &returnedFlags); + ok(ret == exists, "Unexpected return value\n"); + ok(readFlags == returnedFlags, + "Expected flags %08x, got %08x\n", readFlags, returnedFlags); + } +} + +typedef HCRYPTPROV (WINAPI *I_CryptGetDefaultCryptProvFunc)(DWORD w); + +static void test_getDefaultCryptProv(void) +{ + I_CryptGetDefaultCryptProvFunc pI_CryptGetDefaultCryptProv; + HCRYPTPROV prov; + + pI_CryptGetDefaultCryptProv = (I_CryptGetDefaultCryptProvFunc) + GetProcAddress(hCrypt, "I_CryptGetDefaultCryptProv"); + if (!pI_CryptGetDefaultCryptProv) return; + + prov = pI_CryptGetDefaultCryptProv(0xdeadbeef); + ok(prov == 0 && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + prov = pI_CryptGetDefaultCryptProv(PROV_RSA_FULL); + ok(prov == 0 && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + prov = pI_CryptGetDefaultCryptProv(1); + ok(prov == 0 && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + prov = pI_CryptGetDefaultCryptProv(0); + ok(prov != 0, "I_CryptGetDefaultCryptProv failed: %08x\n", GetLastError()); + CryptReleaseContext(prov, 0); +} + +typedef int (WINAPI *I_CryptInstallOssGlobal)(DWORD,DWORD,DWORD); + +static void test_CryptInstallOssGlobal(void) +{ + int ret,i; + I_CryptInstallOssGlobal pI_CryptInstallOssGlobal; + + pI_CryptInstallOssGlobal= (I_CryptInstallOssGlobal)GetProcAddress(hCrypt,"I_CryptInstallOssGlobal"); + /* passing in some random values to I_CryptInstallOssGlobal, it always returns 9 the first time, then 10, 11 etc.*/ + for(i=0;i<30;i++) + { + ret = pI_CryptInstallOssGlobal(rand(),rand(),rand()); + ok((9+i) == ret || + ret == 0, /* Vista */ + "Expected %d or 0, got %d\n",(9+i),ret); + } +} + +static BOOL (WINAPI *pCryptFormatObject)(DWORD dwEncoding, DWORD dwFormatType, + DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType, + const BYTE *pbEncoded, DWORD dwEncoded, void *pbFormat, DWORD *pcbFormat); + +static const BYTE encodedInt[] = { 0x02,0x01,0x01 }; +static const WCHAR encodedIntStr[] = { '0','2',' ','0','1',' ','0','1',0 }; +static const BYTE encodedBigInt[] = { 0x02,0x1f,0x01,0x02,0x03,0x04,0x05,0x06, + 0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15, + 0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f }; +static const WCHAR encodedBigIntStr[] = { '0','2',' ','1','f',' ','0','1',' ', + '0','2',' ','0','3',' ','0','4',' ','0','5',' ','0','6',' ','0','7',' ','0', + '8',' ','0','9',' ','0','a',' ','0','b',' ','0','c',' ','0','d',' ','0','e', + ' ','0','f',' ','1','0',' ','1','1',' ','1','2',' ','1','3',' ','1','4',' ', + '1','5',' ','1','6',' ','1','7',' ','1','8',' ','1','9',' ','1','a',' ','1', + 'b',' ','1','c',' ','1','d',' ','1','e',' ','1','f',0 }; + +static void test_format_object(void) +{ + BOOL ret; + DWORD size; + LPWSTR str; + + pCryptFormatObject = (void *)GetProcAddress(hCrypt, "CryptFormatObject"); + if (!pCryptFormatObject) + { + skip("No CryptFormatObject\n"); + return; + } + /* Crash */ + if (0) + { + ret = pCryptFormatObject(0, 0, 0, NULL, NULL, NULL, 0, NULL, NULL); + } + /* When called with any but the default encoding, it fails to find a + * formatting function. + */ + SetLastError(0xdeadbeef); + ret = pCryptFormatObject(0, 0, 0, NULL, NULL, NULL, 0, NULL, &size); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + /* When called with the default encoding type for any undefined struct type + * (including none), it succeeds: the default encoding is a hex string + * encoding. + */ + SetLastError(0xdeadbeef); + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, NULL, NULL, 0, + NULL, &size); + ok(ret, "CryptFormatObject failed: %d\n", GetLastError()); + if (ret) + { + if (size == 0 && GetLastError() == ERROR_FILE_NOT_FOUND) + { + win_skip("CryptFormatObject has no default implementation\n"); + return; + } + ok(size == sizeof(WCHAR), "unexpected size %d\n", size); + str = HeapAlloc(GetProcessHeap(), 0, size); + SetLastError(0xdeadbeef); + size = 0; + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, NULL, NULL, 0, + str, &size); + ok(!ret && GetLastError() == ERROR_MORE_DATA, + "expected ERROR_MORE_DATA, got %d\n", GetLastError()); + size = sizeof(WCHAR); + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, NULL, NULL, 0, + str, &size); + ok(ret, "CryptFormatObject failed: %d\n", GetLastError()); + ok(!str[0], "expected empty string\n"); + HeapFree(GetProcessHeap(), 0, str); + } + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, NULL, encodedInt, + sizeof(encodedInt), NULL, &size); + ok(ret, "CryptFormatObject failed: %d\n", GetLastError()); + if (ret) + { + str = HeapAlloc(GetProcessHeap(), 0, size); + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, NULL, + encodedInt, sizeof(encodedInt), str, &size); + ok(ret, "CryptFormatObject failed: %d\n", GetLastError()); + ok(!lstrcmpW(str, encodedIntStr), "unexpected format string\n"); + HeapFree(GetProcessHeap(), 0, str); + } + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, NULL, + encodedBigInt, sizeof(encodedBigInt), NULL, &size); + ok(ret, "CryptFormatObject failed: %d\n", GetLastError()); + if (ret) + { + str = HeapAlloc(GetProcessHeap(), 0, size); + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, NULL, + encodedBigInt, sizeof(encodedBigInt), str, &size); + ok(ret, "CryptFormatObject failed: %d\n", GetLastError()); + ok(!lstrcmpiW(str, encodedBigIntStr), "unexpected format string\n"); + HeapFree(GetProcessHeap(), 0, str); + } + /* When called with the default encoding type for any undefined struct + * type but CRYPT_FORMAT_STR_NO_HEX specified, it fails to find a + * formatting function. + */ + SetLastError(0xdeadbeef); + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, CRYPT_FORMAT_STR_NO_HEX, + NULL, NULL, NULL, 0, NULL, &size); + ok(!ret, "CryptFormatObject succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == 0xdeadbeef, /* Vista, W2K8 */ + "expected ERROR_FILE_NOT_FOUND or no change, got %d\n", GetLastError()); + /* When called to format an AUTHORITY_KEY_ID2_INFO, it fails when no + * data are given. + */ + SetLastError(0xdeadbeef); + ret = pCryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, + szOID_AUTHORITY_KEY_IDENTIFIER2, NULL, 0, NULL, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %d\n", GetLastError()); +} + +START_TEST(main) +{ + hCrypt = GetModuleHandleA("crypt32.dll"); + + test_findAttribute(); + test_findExtension(); + test_findRDNAttr(); + test_verifyTimeValidity(); + test_cryptAllocate(); + test_cryptTls(); + test_readTrustedPublisherDWORD(); + test_getDefaultCryptProv(); + test_CryptInstallOssGlobal(); + test_format_object(); +} diff --git a/rostests/winetests/crypt32/message.c b/rostests/winetests/crypt32/message.c new file mode 100644 index 00000000000..fa8df0e5951 --- /dev/null +++ b/rostests/winetests/crypt32/message.c @@ -0,0 +1,721 @@ +/* + * Unit test suite for crypt32.dll's Crypt*Message functions + * + * Copyright 2007-2008 Juan Lang + * + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static const BYTE dataEmptyBareContent[] = { 0x04,0x00 }; +static const BYTE dataEmptyContent[] = { +0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x02, +0x04,0x00 }; +static const BYTE signedEmptyBareContent[] = { +0x30,0x50,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x31,0x37,0x30,0x35,0x02, +0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01, +0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30, +0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; +static const BYTE signedEmptyContent[] = { +0x30,0x5f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,0x52, +0x30,0x50,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x31,0x37,0x30,0x35,0x02, +0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01, +0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30, +0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; + +static void test_msg_get_signer_count(void) +{ + LONG count; + + SetLastError(0xdeadbeef); + count = CryptGetMessageSignerCount(0, NULL, 0); + ok(count == -1, "Expected -1, got %d\n", count); + ok(GetLastError() == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", + GetLastError()); + SetLastError(0xdeadbeef); + count = CryptGetMessageSignerCount(PKCS_7_ASN_ENCODING, NULL, 0); + ok(count == -1, "Expected -1, got %d\n", count); + ok(GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG, /* win9x */ + "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + count = CryptGetMessageSignerCount(PKCS_7_ASN_ENCODING, + dataEmptyBareContent, sizeof(dataEmptyBareContent)); + ok(count == -1, "Expected -1, got %d\n", count); + ok(GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH, /* win9x */ + "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + count = CryptGetMessageSignerCount(PKCS_7_ASN_ENCODING, + dataEmptyContent, sizeof(dataEmptyContent)); + ok(count == -1, "Expected -1, got %d\n", count); + ok(GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + count = CryptGetMessageSignerCount(PKCS_7_ASN_ENCODING, + signedEmptyBareContent, sizeof(signedEmptyBareContent)); + ok(count == -1, "Expected -1, got %d\n", count); + ok(GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_DATA_ERROR, /* win9x */ + "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); + count = CryptGetMessageSignerCount(PKCS_7_ASN_ENCODING, + signedEmptyContent, sizeof(signedEmptyContent)); + ok(count == 1 || + broken(count == -1), /* win9x */ + "Expected 1, got %d\n", count); +} + +static BYTE detachedHashContent[] = { +0x30,0x3f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x32, +0x30,0x30,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb, +0x9d,0x2a,0x8f,0x26,0x2f }; +static const BYTE msgData[] = { 1, 2, 3, 4 }; + +static void test_verify_detached_message_hash(void) +{ + BOOL ret; + CRYPT_HASH_MESSAGE_PARA para; + DWORD size, hashSize; + const BYTE *pMsgData = msgData; + BYTE hash[16]; + + if (0) + { + ret = CryptVerifyDetachedMessageHash(NULL, NULL, 0, 0, NULL, NULL, NULL, + NULL); + } + memset(¶, 0, sizeof(para)); + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageHash(¶, NULL, 0, 0, NULL, NULL, NULL, + NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + para.cbSize = sizeof(para); + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageHash(¶, NULL, 0, 0, NULL, NULL, NULL, + NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + para.dwMsgEncodingType = PKCS_7_ASN_ENCODING; + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageHash(¶, NULL, 0, 0, NULL, NULL, NULL, + NULL); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG), /* win9x */ + "expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); + para.dwMsgEncodingType = X509_ASN_ENCODING; + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageHash(¶, NULL, 0, 0, NULL, NULL, NULL, + NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + para.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageHash(¶, NULL, 0, 0, NULL, NULL, NULL, + NULL); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG), /* win9x */ + "expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); + /* Curiously, passing no data to hash succeeds.. */ + ret = CryptVerifyDetachedMessageHash(¶, detachedHashContent, + sizeof(detachedHashContent), 0, NULL, NULL, NULL, NULL); + todo_wine + ok(ret, "CryptVerifyDetachedMessageHash failed: %08x\n", GetLastError()); + /* as does passing the actual content of the message to hash.. */ + size = sizeof(msgData); + pMsgData = msgData; + ret = CryptVerifyDetachedMessageHash(¶, detachedHashContent, + sizeof(detachedHashContent), 1, &pMsgData, &size, NULL, NULL); + ok(ret, "CryptVerifyDetachedMessageHash failed: %08x\n", GetLastError()); + /* while passing data to hash that isn't the content of the message fails. + */ + size = sizeof(detachedHashContent); + pMsgData = detachedHashContent; + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageHash(¶, detachedHashContent, + sizeof(detachedHashContent), 1, &pMsgData, &size, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_HASH_VALUE, + "expected CRYPT_E_HASH_VALUE, got %08x\n", GetLastError()); + /* Getting the size of the hash while passing no hash data causes the + * hash to be checked (and fail.) + */ + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageHash(¶, detachedHashContent, + sizeof(detachedHashContent), 0, NULL, NULL, NULL, &hashSize); + ok(!ret && GetLastError() == CRYPT_E_HASH_VALUE, + "expected CRYPT_E_HASH_VALUE, got %08x\n", GetLastError()); + size = sizeof(msgData); + pMsgData = msgData; + ret = CryptVerifyDetachedMessageHash(¶, detachedHashContent, + sizeof(detachedHashContent), 1, &pMsgData, &size, NULL, &hashSize); + ok(ret, "CryptVerifyDetachedMessageHash failed: %08x\n", GetLastError()); + ok(hashSize == sizeof(hash), "unexpected size %d\n", hashSize); + hashSize = 1; + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageHash(¶, detachedHashContent, + sizeof(detachedHashContent), 1, &pMsgData, &size, hash, &hashSize); + ok(!ret && GetLastError() == ERROR_MORE_DATA, + "expected ERROR_MORE_DATA, got %08x\n", GetLastError()); + hashSize = sizeof(hash); + ret = CryptVerifyDetachedMessageHash(¶, detachedHashContent, + sizeof(detachedHashContent), 1, &pMsgData, &size, hash, &hashSize); + ok(ret, "CryptVerifyDetachedMessageHash failed: %08x\n", GetLastError()); +} + +static BYTE hashContent[] = { +0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a, +0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0, +0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f }; + +static void test_verify_message_hash(void) +{ + BOOL ret; + CRYPT_HASH_MESSAGE_PARA para; + DWORD size; + BYTE *buf = NULL; + + memset(¶, 0, sizeof(para)); + /* Crash */ + if (0) + ret = CryptVerifyMessageHash(NULL, NULL, 0, NULL, NULL, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageHash(¶, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + para.cbSize = sizeof(para); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageHash(¶, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + para.dwMsgEncodingType = PKCS_7_ASN_ENCODING; + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageHash(¶, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected 0, got %d\n", ret); + ok(GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG, /* win98 */ + "Expected CRYPT_E_ASN1_EOD or OSS_BAD_ARG, got %08x\n", GetLastError()); + /* Verifying the hash of a detached message succeeds? */ + ret = CryptVerifyMessageHash(¶, detachedHashContent, + sizeof(detachedHashContent), NULL, NULL, NULL, NULL); + todo_wine + ok(ret, "CryptVerifyMessageHash failed: %08x\n", GetLastError()); + /* As does verifying the hash of a regular message. */ + ret = CryptVerifyMessageHash(¶, hashContent, sizeof(hashContent), + NULL, NULL, NULL, NULL); + ok(ret, "CryptVerifyMessageHash failed: %08x\n", GetLastError()); + ret = CryptVerifyMessageHash(¶, hashContent, sizeof(hashContent), + NULL, &size, NULL, NULL); + ok(ret, "CryptVerifyMessageHash failed: %08x\n", GetLastError()); + if (ret) + buf = CryptMemAlloc(size); + if (buf) + { + size = 1; + ret = CryptVerifyMessageHash(¶, hashContent, sizeof(hashContent), + buf, &size, NULL, NULL); + ok(!ret && GetLastError() == ERROR_MORE_DATA, + "expected ERROR_MORE_DATA, got %08x\n", GetLastError()); + ret = CryptVerifyMessageHash(¶, hashContent, sizeof(hashContent), + buf, &size, NULL, NULL); + ok(ret, "CryptVerifyMessageHash failed: %08x\n", GetLastError()); + ok(size == sizeof(msgData), "unexpected size %d\n", size); + ok(!memcmp(buf, msgData, size), "unexpected value\n"); + CryptMemFree(buf); + } +} + +static const BYTE signedWithCertContent[] = { +0x30,0x82,0x01,0x32,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x82,0x01,0x23,0x30,0x82,0x01,0x1f,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c, +0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01, +0x02,0x03,0x04,0xa0,0x7c,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30, +0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, +0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31, +0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, +0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00, +0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04, +0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x31,0x77,0x30,0x75,0x02,0x01, +0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13, +0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30, +0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04, +0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1, +0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9, +0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11, +0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19, +0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE signedContent[] = { +0x30,0x81,0xb2,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0xa4,0x30,0x81,0xa1,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04, +0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70, +0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d, +0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe, +0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29, +0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8, +0x0d }; +static const BYTE detachedSignedContent[] = { +0x30,0x81,0xaa,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0x9c,0x30,0x81,0x99,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30, +0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a, +0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06, +0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00, +0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0, +0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0, +0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23, +0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51, +0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE v1CertWithValidPubKey[] = { +0x30,0x81,0xcf,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x4b,0x00,0x30,0x48,0x02,0x41,0x00,0xe2,0x54,0x3a, +0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb,0xb4,0x53,0xe6,0x1f,0xe7,0x5d,0xf1, +0x21,0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb,0x65,0x97,0x03,0x86,0x60,0xde, +0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc,0x62,0x17,0xa9,0xcd,0x79,0x3f, +0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30,0x18,0x10,0x6b,0xd0,0x1c,0x10, +0x79,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55, +0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; + +static PCCERT_CONTEXT WINAPI msg_get_signer_callback(void *pvArg, + DWORD certEncodingType, PCERT_INFO signerId, HCERTSTORE store) +{ + return CertCreateCertificateContext(X509_ASN_ENCODING, + v1CertWithValidPubKey, sizeof(v1CertWithValidPubKey)); +} + +static void test_verify_detached_message_signature(void) +{ + CRYPT_VERIFY_MESSAGE_PARA para; + BOOL ret; + const BYTE *pContent; + DWORD cbContent; + + memset(¶, 0, sizeof(para)); + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(NULL, 0, NULL, 0, 0, NULL, + NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(¶, 0, NULL, 0, 0, NULL, + NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + para.cbSize = sizeof(para); + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(¶, 0, NULL, 0, 0, NULL, + NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + para.dwMsgAndCertEncodingType = X509_ASN_ENCODING; + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(¶, 0, NULL, 0, 0, NULL, + NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + para.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING; + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(¶, 0, NULL, 0, 0, NULL, + NULL, NULL); + ok(!ret, "Expected 0, got %d\n", ret); + ok(GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG, /* win98 */ + "Expected CRYPT_E_ASN1_EOD or OSS_BAD_ARG, got %08x\n", GetLastError()); + /* None of these messages contains a cert in the message itself, so the + * default callback isn't able to verify their signature. + */ + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(¶, 0, signedWithCertContent, + sizeof(signedWithCertContent), 0, NULL, NULL, NULL); + ok(!ret, "Expected 0, got %d\n", ret); + todo_wine + ok(GetLastError() == CRYPT_E_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR, /* win98 */ + "Expected CRYPT_E_NOT_FOUND or OSS_DATA_ERROR, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(¶, 0, signedContent, + sizeof(signedContent), 0, NULL, NULL, NULL); + ok(!ret, "Expected 0, got %d\n", ret); + ok(GetLastError() == CRYPT_E_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR, /* win98 */ + "Expected CRYPT_E_NOT_FOUND or OSS_DATA_ERROR, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(¶, 0, detachedSignedContent, + sizeof(detachedSignedContent), 0, NULL, NULL, NULL); + ok(!ret, "Expected 0, got %d\n", ret); + ok(GetLastError() == CRYPT_E_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR, /* win98 */ + "Expected CRYPT_E_NOT_FOUND or OSS_DATA_ERROR, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + pContent = msgData; + cbContent = sizeof(msgData); + ret = CryptVerifyDetachedMessageSignature(¶, 0, detachedSignedContent, + sizeof(detachedSignedContent), 1, &pContent, &cbContent, NULL); + ok(!ret, "Expected 0, got %d\n", ret); + ok(GetLastError() == CRYPT_E_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR, /* win98 */ + "Expected CRYPT_E_NOT_FOUND or OSS_DATA_ERROR, got %08x\n", GetLastError()); + /* Passing the correct callback results in success */ + para.pfnGetSignerCertificate = msg_get_signer_callback; + ret = CryptVerifyDetachedMessageSignature(¶, 0, detachedSignedContent, + sizeof(detachedSignedContent), 1, &pContent, &cbContent, NULL); + ok(ret || + broken(!ret), /* win98 */ + "CryptVerifyDetachedMessageSignature failed: %08x\n", + GetLastError()); + /* Not passing the correct data to be signed results in the signature not + * matching. + */ + SetLastError(0xdeadbeef); + ret = CryptVerifyDetachedMessageSignature(¶, 0, detachedSignedContent, + sizeof(detachedSignedContent), 0, NULL, NULL, NULL); + ok(!ret, "Expected 0, got %d\n", ret); + ok(GetLastError() == NTE_BAD_SIGNATURE || + GetLastError() == OSS_DATA_ERROR, /* win98 */ + "Expected NTE_BAD_SIGNATURE or OSS_DATA_ERROR, got %08x\n", GetLastError()); +} + +static const BYTE signedWithCertEmptyContent[] = { +0x30,0x81,0xdf,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0xd1,0x30,0x81,0xce,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x7c, +0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67, +0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30, +0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01, +0xff,0x02,0x01,0x01,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, +0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04, +0x00 }; +static const BYTE signedWithCertWithPubKeyContent[] = { +0x30,0x81,0xfc,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0xee,0x30,0x81,0xeb,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x81, +0x98,0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13, +0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c, +0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30, +0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06, +0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12, +0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff, +0x02,0x01,0x01,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31, +0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; + +static void test_verify_message_signature(void) +{ + BOOL ret; + CRYPT_VERIFY_MESSAGE_PARA para = { 0 }; + PCCERT_CONTEXT cert; + DWORD cbDecoded; + + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(NULL, 0, NULL, 0, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + para.cbSize = sizeof(para); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + para.cbSize = 0; + para.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING; + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + para.cbSize = sizeof(para); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, NULL); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_BAD_ARG), /* win9x */ + "Expected CRYPT_E_ASN1_EOD, got %08x\n", GetLastError()); + /* Check whether cert is set on error */ + cert = (PCCERT_CONTEXT)0xdeadbeef; + ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, 0, &cert); + ok(cert == NULL, "Expected NULL cert\n"); + /* Check whether cbDecoded is set on error */ + cbDecoded = 0xdeadbeef; + ret = CryptVerifyMessageSignature(¶, 0, NULL, 0, NULL, &cbDecoded, + NULL); + ok(!cbDecoded, "Expected 0\n"); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, dataEmptyBareContent, + sizeof(dataEmptyBareContent), NULL, 0, NULL); + ok(GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH, /* win9x */ + "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, dataEmptyContent, + sizeof(dataEmptyContent), NULL, 0, NULL); + ok(!ret && GetLastError() == CRYPT_E_UNEXPECTED_MSG_TYPE, + "Expected CRYPT_E_UNEXPECTED_MSG_TYPE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, signedEmptyBareContent, + sizeof(signedEmptyBareContent), NULL, 0, NULL); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_DATA_ERROR), /* win9x */ + "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, signedEmptyContent, + sizeof(signedEmptyContent), NULL, 0, NULL); + ok(!ret && + (GetLastError() == CRYPT_E_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR), /* win9x */ + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptVerifyMessageSignature(¶, 0, signedContent, + sizeof(signedContent), NULL, 0, NULL); + ok(!ret && + (GetLastError() == CRYPT_E_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR), /* win9x */ + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* FIXME: Windows fails with CRYPT_E_NOT_FOUND for these messages, but + * their signer certs have invalid public keys that fail to decode. In + * Wine therefore the failure is an ASN error. Need some messages with + * valid public keys and invalid signatures to check against. + */ + ret = CryptVerifyMessageSignature(¶, 0, signedWithCertEmptyContent, + sizeof(signedWithCertEmptyContent), NULL, 0, NULL); + ok(!ret, "Expected failure\n"); + ret = CryptVerifyMessageSignature(¶, 0, signedWithCertContent, + sizeof(signedWithCertContent), NULL, 0, NULL); + ok(!ret, "Expected failure\n"); + ret = CryptVerifyMessageSignature(¶, 0, signedWithCertWithPubKeyContent, + sizeof(signedWithCertWithPubKeyContent), NULL, 0, NULL); + ok(!ret, "Expected failure\n"); +} + +static const BYTE detachedHashBlob[] = { +0x30,0x3f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x32, +0x30,0x30,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0x04,0x10,0x2d,0x1b,0xbc,0x1f,0xc7,0xab,0x36,0x8d,0xdb,0x95,0xe6, +0x24,0xb9,0x66,0x7c,0x21 }; +static const BYTE hashBlob[] = { +0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a, +0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0xa0,0x06,0x04,0x04,0xde,0xad,0xbe,0xef,0x04,0x10,0x2f,0x24,0x92, +0x30,0xa8,0xe7,0xc2,0xbf,0x60,0x05,0xcc,0xd2,0x67,0x92,0x59,0xec }; +static const BYTE hashVal[] = { +0x2d,0x1b,0xbc,0x1f,0xc7,0xab,0x36,0x8d,0xdb,0x95,0xe6,0x24,0xb9,0x66,0x7c, +0x21 }; + +static void test_hash_message(void) +{ + BOOL ret; + CRYPT_HASH_MESSAGE_PARA para; + static const BYTE blob1[] = { 0xde, 0xad, 0xbe, 0xef }; + static const BYTE blob2[] = { 0xba, 0xad, 0xf0, 0x0d }; + const BYTE *toHash[] = { blob1, blob2 }; + DWORD hashSize[] = { sizeof(blob1), sizeof(blob2) }; + DWORD hashedBlobSize, computedHashSize; + static char oid_rsa_md5[] = szOID_RSA_MD5; + LPBYTE hashedBlob, computedHash; + + /* Crash + ret = CryptHashMessage(NULL, FALSE, 0, NULL, 0, NULL, NULL, NULL, NULL); + */ + memset(¶, 0, sizeof(para)); + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 0, NULL, NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got 0x%08x\n", GetLastError()); + para.cbSize = sizeof(para); + /* Not quite sure what "success" means in this case, but it does succeed */ + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 0, NULL, NULL, NULL, NULL, NULL, NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + /* With a bogus encoding type it "succeeds" */ + para.dwMsgEncodingType = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 0, NULL, NULL, NULL, NULL, NULL, NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + /* According to MSDN, the third parameter (cToBeHashed) must be 1 if the + * second parameter (fDetached) is FALSE, but again it "succeeds." + */ + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 2, NULL, NULL, NULL, NULL, NULL, NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + /* Even passing parameters to hash results in "success." */ + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 2, toHash, hashSize, NULL, NULL, NULL, + NULL); + /* Try again with a valid encoding type */ + para.dwMsgEncodingType = PKCS_7_ASN_ENCODING; + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 2, NULL, NULL, NULL, NULL, NULL, NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + /* And with valid data to hash */ + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 2, toHash, hashSize, NULL, NULL, NULL, + NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + /* But requesting the size of the hashed blob and indicating there's data + * to hash results in a crash + */ + if (0) + { + ret = CryptHashMessage(¶, FALSE, 2, NULL, NULL, NULL, + &hashedBlobSize, NULL, NULL); + } + /* Passing a valid pointer for the data to hash fails, as the hash + * algorithm is finally checked. + */ + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 2, toHash, hashSize, NULL, + &hashedBlobSize, NULL, NULL); + ok(!ret && + (GetLastError() == CRYPT_E_UNKNOWN_ALGO || + GetLastError() == CRYPT_E_OID_FORMAT), /* Vista */ + "expected CRYPT_E_UNKNOWN_ALGO or CRYPT_E_OID_FORMAT, got 0x%08x (%d)\n", + GetLastError(), GetLastError()); + para.HashAlgorithm.pszObjId = oid_rsa_md5; + /* With a valid hash algorithm, this succeeds, even though fDetached is + * FALSE. + */ + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 2, toHash, hashSize, NULL, + &hashedBlobSize, NULL, NULL); + todo_wine + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + if (ret) + { + /* Actually attempting to get the hashed data fails, perhaps because + * detached is FALSE. + */ + hashedBlob = HeapAlloc(GetProcessHeap(), 0, hashedBlobSize); + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 2, toHash, hashSize, hashedBlob, + &hashedBlobSize, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "expected CRYPT_E_MSG_ERROR, got 0x%08x (%d)\n", GetLastError(), + GetLastError()); + HeapFree(GetProcessHeap(), 0, hashedBlob); + } + /* Repeating tests with fDetached = TRUE results in success */ + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, TRUE, 2, toHash, hashSize, NULL, + &hashedBlobSize, NULL, NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + if (ret) + { + hashedBlob = HeapAlloc(GetProcessHeap(), 0, hashedBlobSize); + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, TRUE, 2, toHash, hashSize, hashedBlob, + &hashedBlobSize, NULL, NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + ok(hashedBlobSize == sizeof(detachedHashBlob), + "unexpected size of detached blob %d\n", hashedBlobSize); + ok(!memcmp(hashedBlob, detachedHashBlob, hashedBlobSize), + "unexpected detached blob value\n"); + HeapFree(GetProcessHeap(), 0, hashedBlob); + } + /* Hashing a single item with fDetached = FALSE also succeeds */ + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, FALSE, 1, toHash, hashSize, NULL, + &hashedBlobSize, NULL, NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + if (ret) + { + hashedBlob = HeapAlloc(GetProcessHeap(), 0, hashedBlobSize); + ret = CryptHashMessage(¶, FALSE, 1, toHash, hashSize, hashedBlob, + &hashedBlobSize, NULL, NULL); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + ok(hashedBlobSize == sizeof(hashBlob), + "unexpected size of detached blob %d\n", hashedBlobSize); + ok(!memcmp(hashedBlob, hashBlob, hashedBlobSize), + "unexpected detached blob value\n"); + HeapFree(GetProcessHeap(), 0, hashedBlob); + } + /* Check the computed hash value too. You don't need to get the encoded + * blob to get it. + */ + computedHashSize = 0xdeadbeef; + ret = CryptHashMessage(¶, TRUE, 2, toHash, hashSize, NULL, + &hashedBlobSize, NULL, &computedHashSize); + ok(ret, "CryptHashMessage failed: 0x%08x\n", GetLastError()); + ok(computedHashSize == 16, "expected hash size of 16, got %d\n", + computedHashSize); + if (ret) + { + computedHash = HeapAlloc(GetProcessHeap(), 0, computedHashSize); + SetLastError(0xdeadbeef); + ret = CryptHashMessage(¶, TRUE, 2, toHash, hashSize, NULL, + &hashedBlobSize, computedHash, &computedHashSize); + ok(computedHashSize == sizeof(hashVal), + "unexpected size of hash value %d\n", computedHashSize); + ok(!memcmp(computedHash, hashVal, computedHashSize), + "unexpected value\n"); + HeapFree(GetProcessHeap(), 0, computedHash); + } +} + +START_TEST(message) +{ + test_msg_get_signer_count(); + test_verify_detached_message_hash(); + test_verify_message_hash(); + test_verify_detached_message_signature(); + test_verify_message_signature(); + test_hash_message(); +} diff --git a/rostests/winetests/crypt32/msg.c b/rostests/winetests/crypt32/msg.c new file mode 100644 index 00000000000..8ab5625fd8e --- /dev/null +++ b/rostests/winetests/crypt32/msg.c @@ -0,0 +1,3198 @@ +/* + * Unit test suite for crypt32.dll's CryptMsg functions + * + * Copyright 2007 Juan Lang + * + * 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 + */ + +#include +#include +#include +#include +#include +#define CMSG_SIGNER_ENCODE_INFO_HAS_CMS_FIELDS +#define CMSG_SIGNED_ENCODE_INFO_HAS_CMS_FIELDS +#include + +#include "wine/test.h" + +static BOOL have_nt = TRUE; +static BOOL old_crypt32 = FALSE; +static char oid_rsa_md5[] = szOID_RSA_MD5; + +static BOOL (WINAPI * pCryptAcquireContextA) + (HCRYPTPROV *, LPCSTR, LPCSTR, DWORD, DWORD); +static BOOL (WINAPI * pCryptAcquireContextW) + (HCRYPTPROV *, LPCWSTR, LPCWSTR, DWORD, DWORD); + +static void init_function_pointers(void) +{ + HMODULE hAdvapi32 = GetModuleHandleA("advapi32.dll"); + +#define GET_PROC(dll, func) \ + p ## func = (void *)GetProcAddress(dll, #func); \ + if(!p ## func) \ + trace("GetProcAddress(%s) failed\n", #func); + + GET_PROC(hAdvapi32, CryptAcquireContextA) + GET_PROC(hAdvapi32, CryptAcquireContextW) + +#undef GET_PROC +} + +static void test_msg_open_to_encode(void) +{ + HCRYPTMSG msg; + + /* Crash + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, NULL, + NULL, NULL); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, NULL, NULL, + NULL); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, NULL, NULL, + NULL); + */ + + /* Bad encodings */ + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(0, 0, 0, NULL, NULL, NULL); + ok(!msg && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(X509_ASN_ENCODING, 0, 0, NULL, NULL, NULL); + ok(!msg && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + + /* Bad message types */ + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL); + ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, + NULL, NULL, NULL); + ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, + CMSG_SIGNED_AND_ENVELOPED, NULL, NULL, NULL); + ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, NULL, + NULL, NULL); + ok(!msg && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); +} + +static void test_msg_open_to_decode(void) +{ + HCRYPTMSG msg; + CMSG_STREAM_INFO streamInfo = { 0 }; + + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToDecode(0, 0, 0, 0, NULL, NULL); + ok(!msg && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + + /* Bad encodings */ + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToDecode(X509_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ok(!msg && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToDecode(X509_ASN_ENCODING, 0, CMSG_DATA, 0, NULL, NULL); + ok(!msg && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + + /* The message type can be explicit... */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, + CMSG_SIGNED_AND_ENVELOPED, 0, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + /* or implicit.. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + /* or even invalid. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 1000, 0, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + /* And even though the stream info parameter "must be set to NULL" for + * CMSG_HASHED, it's still accepted. + */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + &streamInfo); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + CryptMsgClose(msg); +} + +static void test_msg_get_param(void) +{ + BOOL ret; + HCRYPTMSG msg; + DWORD size, i, value; + CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 }; + CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 }; + + /* Crash + ret = CryptMsgGetParam(NULL, 0, 0, NULL, NULL); + ret = CryptMsgGetParam(NULL, 0, 0, NULL, &size); + ret = CryptMsgGetParam(msg, 0, 0, NULL, NULL); + */ + + /* Decoded messages */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + /* For decoded messages, the type is always available */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + /* For this (empty) message, the type isn't set */ + ok(value == 0, "Expected type 0, got %d\n", value); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + /* For explicitly typed messages, the type is known. */ + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + ok(value == CMSG_DATA, "Expected CMSG_DATA, got %d\n", value); + for (i = CMSG_CONTENT_PARAM; !old_crypt32 && (i <= CMSG_CMS_SIGNER_INFO_PARAM); i++) + { + size = 0; + ret = CryptMsgGetParam(msg, i, 0, NULL, &size); + ok(!ret, "Parameter %d: expected failure\n", i); + } + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENVELOPED, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + ok(value == CMSG_ENVELOPED, "Expected CMSG_ENVELOPED, got %d\n", value); + for (i = CMSG_CONTENT_PARAM; !old_crypt32 && (i <= CMSG_CMS_SIGNER_INFO_PARAM); i++) + { + size = 0; + ret = CryptMsgGetParam(msg, i, 0, NULL, &size); + ok(!ret, "Parameter %d: expected failure\n", i); + } + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + ok(value == CMSG_HASHED, "Expected CMSG_HASHED, got %d\n", value); + for (i = CMSG_CONTENT_PARAM; !old_crypt32 && (i <= CMSG_CMS_SIGNER_INFO_PARAM); i++) + { + size = 0; + ret = CryptMsgGetParam(msg, i, 0, NULL, &size); + ok(!ret, "Parameter %d: expected failure\n", i); + } + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + ok(value == CMSG_SIGNED, "Expected CMSG_SIGNED, got %d\n", value); + for (i = CMSG_CONTENT_PARAM; !old_crypt32 && (i <= CMSG_CMS_SIGNER_INFO_PARAM); i++) + { + size = 0; + ret = CryptMsgGetParam(msg, i, 0, NULL, &size); + ok(!ret, "Parameter %d: expected failure\n", i); + } + CryptMsgClose(msg); + + /* Explicitly typed messages get their types set, even if they're invalid */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_ENCRYPTED, 0, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + ok(value == CMSG_ENCRYPTED, "Expected CMSG_ENCRYPTED, got %d\n", value); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 1000, 0, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToDecode failed: %x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + ok(value == 1000, "Expected 1000, got %d\n", value); + CryptMsgClose(msg); +} + +static void test_msg_close(void) +{ + BOOL ret; + HCRYPTMSG msg; + + /* NULL succeeds.. */ + ret = CryptMsgClose(NULL); + ok(ret, "CryptMsgClose failed: %x\n", GetLastError()); + /* but an arbitrary pointer crashes. */ + if (0) + ret = CryptMsgClose((HCRYPTMSG)1); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + ret = CryptMsgClose(msg); + ok(ret, "CryptMsgClose failed: %x\n", GetLastError()); +} + +static void check_param(LPCSTR test, HCRYPTMSG msg, DWORD param, + const BYTE *expected, DWORD expectedSize) +{ + DWORD size; + LPBYTE buf; + BOOL ret; + + size = 0xdeadbeef; + ret = CryptMsgGetParam(msg, param, 0, NULL, &size); + ok(ret || broken(GetLastError() == OSS_LIMITED /* Win9x */ || + GetLastError() == CRYPT_E_INVALID_MSG_TYPE /* Win9x, for some params */), + "%s: CryptMsgGetParam failed: %08x\n", test, GetLastError()); + if (!ret) + { + win_skip("parameter %d not supported, skipping tests\n", param); + return; + } + buf = HeapAlloc(GetProcessHeap(), 0, size); + ret = CryptMsgGetParam(msg, param, 0, buf, &size); + ok(ret, "%s: CryptMsgGetParam failed: %08x\n", test, GetLastError()); + ok(size == expectedSize, "%s: expected size %d, got %d\n", test, + expectedSize, size); + if (size == expectedSize && size) + ok(!memcmp(buf, expected, size), "%s: unexpected data\n", test); + HeapFree(GetProcessHeap(), 0, buf); +} + +static void test_data_msg_open(void) +{ + HCRYPTMSG msg; + CMSG_HASHED_ENCODE_INFO hashInfo = { 0 }; + CMSG_STREAM_INFO streamInfo = { 0 }; + char oid[] = "1.2.3"; + + /* The data message type takes no additional info */ + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, &hashInfo, + NULL, NULL); + ok(!msg && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + /* An empty stream info is allowed. */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + &streamInfo); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + /* Passing a bogus inner OID succeeds for a non-streamed message.. */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, oid, + NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + /* and still succeeds when CMSG_DETACHED_FLAG is passed.. */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, + CMSG_DATA, NULL, oid, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + /* and when a stream info is given, even though you're not supposed to be + * able to use anything but szOID_RSA_data when streaming is being used. + */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, + CMSG_DATA, NULL, oid, &streamInfo); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); +} + +static const BYTE msgData[] = { 1, 2, 3, 4 }; + +static BOOL WINAPI nop_stream_output(const void *pvArg, BYTE *pb, DWORD cb, + BOOL final) +{ + return TRUE; +} + +static void test_data_msg_update(void) +{ + HCRYPTMSG msg; + BOOL ret; + CMSG_STREAM_INFO streamInfo = { 0 }; + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + NULL); + /* Can't update a message that wasn't opened detached with final = FALSE */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + /* Updating it with final = TRUE succeeds */ + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* Any subsequent update will fail, as the last was final */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + NULL); + /* Can't update a message with no data */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + /* This test returns FALSE on XP and earlier but TRUE on Vista, so can't be tested. + * GetLastError is either E_INVALIDARG (NT) or unset (9x/Vista), so it doesn't + * make sense to test this. + */ + + /* Curiously, a valid update will now fail as well, presumably because of + * the last (invalid, but final) update. + */ + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, + CMSG_DATA, NULL, NULL, NULL); + if (have_nt) + { + /* Doesn't appear to be able to update CMSG-DATA with non-final updates. + * On Win9x, this sometimes succeeds, sometimes fails with + * GetLastError() == 0, so it's not worth checking there. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(!ret && + (GetLastError() == E_INVALIDARG || + broken(GetLastError() == ERROR_SUCCESS)), /* Older NT4 */ + "Expected E_INVALIDARG, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(!ret && + (GetLastError() == E_INVALIDARG || + broken(GetLastError() == ERROR_SUCCESS)), /* Older NT4 */ + "Expected E_INVALIDARG, got %x\n", GetLastError()); + } + else + skip("not updating CMSG_DATA with a non-final update\n"); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + if (!old_crypt32) + { + /* Calling update after opening with an empty stream info (with a bogus + * output function) yields an error: + */ + /* Crashes on some Win9x */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + &streamInfo); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(!ret && (GetLastError() == STATUS_ACCESS_VIOLATION || + GetLastError() == STATUS_ILLEGAL_INSTRUCTION /* WinME */), + "Expected STATUS_ACCESS_VIOLATION or STATUS_ILLEGAL_INSTRUCTION, got %x\n", + GetLastError()); + CryptMsgClose(msg); + } + /* Calling update with a valid output function succeeds, even if the data + * exceeds the size specified in the stream info. + */ + streamInfo.pfnStreamOutput = nop_stream_output; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + &streamInfo); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); +} + +static void test_data_msg_get_param(void) +{ + HCRYPTMSG msg; + DWORD size; + BOOL ret; + CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL }; + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + NULL); + + /* Content and bare content are always gettable when not streaming */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + size = 0; + ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + /* But for this type of message, the signer and hash aren't applicable, + * and the type isn't available. + */ + size = 0; + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + CryptMsgClose(msg); + + /* Can't get content or bare content when streaming */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, + NULL, &streamInfo); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size); + ok((!ret && GetLastError() == E_INVALIDARG) || broken(ret /* Win9x */), + "Expected E_INVALIDARG, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size); + ok((!ret && GetLastError() == E_INVALIDARG) || broken(ret /* Win9x */), + "Expected E_INVALIDARG, got %x\n", GetLastError()); + CryptMsgClose(msg); +} + +static const BYTE dataEmptyBareContent[] = { 0x04,0x00 }; +static const BYTE dataEmptyContent[] = { +0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x02, +0x04,0x00 }; +static const BYTE dataBareContent[] = { 0x04,0x04,0x01,0x02,0x03,0x04 }; +static const BYTE dataContent[] = { +0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06, +0x04,0x04,0x01,0x02,0x03,0x04 }; + +struct update_accum +{ + DWORD cUpdates; + CRYPT_DATA_BLOB *updates; +}; + +static BOOL WINAPI accumulating_stream_output(const void *pvArg, BYTE *pb, + DWORD cb, BOOL final) +{ + struct update_accum *accum = (struct update_accum *)pvArg; + BOOL ret = FALSE; + + if (accum->cUpdates) + accum->updates = CryptMemRealloc(accum->updates, + (accum->cUpdates + 1) * sizeof(CRYPT_DATA_BLOB)); + else + accum->updates = CryptMemAlloc(sizeof(CRYPT_DATA_BLOB)); + if (accum->updates) + { + CRYPT_DATA_BLOB *blob = &accum->updates[accum->cUpdates]; + + blob->pbData = CryptMemAlloc(cb); + if (blob->pbData) + { + memcpy(blob->pbData, pb, cb); + blob->cbData = cb; + ret = TRUE; + } + accum->cUpdates++; + } + return ret; +} + +/* The updates of a (bogus) definite-length encoded message */ +static BYTE u1[] = { 0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, + 0x07,0x01,0xa0,0x02,0x04,0x00 }; +static BYTE u2[] = { 0x01,0x02,0x03,0x04 }; +static CRYPT_DATA_BLOB b1[] = { + { sizeof(u1), u1 }, + { sizeof(u2), u2 }, + { sizeof(u2), u2 }, +}; +static const struct update_accum a1 = { sizeof(b1) / sizeof(b1[0]), b1 }; +/* The updates of a definite-length encoded message */ +static BYTE u3[] = { 0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, + 0x07,0x01,0xa0,0x06,0x04,0x04 }; +static CRYPT_DATA_BLOB b2[] = { + { sizeof(u3), u3 }, + { sizeof(u2), u2 }, +}; +static const struct update_accum a2 = { sizeof(b2) / sizeof(b2[0]), b2 }; +/* The updates of an indefinite-length encoded message */ +static BYTE u4[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, + 0x07,0x01,0xa0,0x80,0x24,0x80 }; +static BYTE u5[] = { 0x04,0x04 }; +static BYTE u6[] = { 0x00,0x00,0x00,0x00,0x00,0x00 }; +static CRYPT_DATA_BLOB b3[] = { + { sizeof(u4), u4 }, + { sizeof(u5), u5 }, + { sizeof(u2), u2 }, + { sizeof(u5), u5 }, + { sizeof(u2), u2 }, + { sizeof(u6), u6 }, +}; +static const struct update_accum a3 = { sizeof(b3) / sizeof(b3[0]), b3 }; + +static void check_updates(LPCSTR header, const struct update_accum *expected, + const struct update_accum *got) +{ + DWORD i; + + ok(expected->cUpdates == got->cUpdates, + "%s: expected %d updates, got %d\n", header, expected->cUpdates, + got->cUpdates); + if (expected->cUpdates == got->cUpdates) + for (i = 0; i < min(expected->cUpdates, got->cUpdates); i++) + { + ok(expected->updates[i].cbData == got->updates[i].cbData, + "%s, update %d: expected %d bytes, got %d\n", header, i, + expected->updates[i].cbData, got->updates[i].cbData); + if (expected->updates[i].cbData && expected->updates[i].cbData == + got->updates[i].cbData) + ok(!memcmp(expected->updates[i].pbData, got->updates[i].pbData, + got->updates[i].cbData), "%s, update %d: unexpected value\n", + header, i); + } +} + +/* Frees the updates stored in accum */ +static void free_updates(struct update_accum *accum) +{ + DWORD i; + + for (i = 0; i < accum->cUpdates; i++) + CryptMemFree(accum->updates[i].pbData); + CryptMemFree(accum->updates); + accum->updates = NULL; + accum->cUpdates = 0; +} + +static void test_data_msg_encoding(void) +{ + HCRYPTMSG msg; + BOOL ret; + static char oid[] = "1.2.3"; + struct update_accum accum = { 0, NULL }; + CMSG_STREAM_INFO streamInfo = { 0, accumulating_stream_output, &accum }; + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + NULL); + check_param("data empty bare content", msg, CMSG_BARE_CONTENT_PARAM, + dataEmptyBareContent, sizeof(dataEmptyBareContent)); + check_param("data empty content", msg, CMSG_CONTENT_PARAM, dataEmptyContent, + sizeof(dataEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM, + dataBareContent, sizeof(dataBareContent)); + check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent, + sizeof(dataContent)); + CryptMsgClose(msg); + /* Same test, but with CMSG_BARE_CONTENT_FLAG set */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_BARE_CONTENT_FLAG, + CMSG_DATA, NULL, NULL, NULL); + check_param("data empty bare content", msg, CMSG_BARE_CONTENT_PARAM, + dataEmptyBareContent, sizeof(dataEmptyBareContent)); + check_param("data empty content", msg, CMSG_CONTENT_PARAM, dataEmptyContent, + sizeof(dataEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM, + dataBareContent, sizeof(dataBareContent)); + check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent, + sizeof(dataContent)); + CryptMsgClose(msg); + /* The inner OID is apparently ignored */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, oid, + NULL); + check_param("data bogus oid bare content", msg, CMSG_BARE_CONTENT_PARAM, + dataEmptyBareContent, sizeof(dataEmptyBareContent)); + check_param("data bogus oid content", msg, CMSG_CONTENT_PARAM, + dataEmptyContent, sizeof(dataEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("data bare content", msg, CMSG_BARE_CONTENT_PARAM, + dataBareContent, sizeof(dataBareContent)); + check_param("data content", msg, CMSG_CONTENT_PARAM, dataContent, + sizeof(dataContent)); + CryptMsgClose(msg); + /* A streaming message is DER encoded if the length is not 0xffffffff, but + * curiously, updates aren't validated to make sure they don't exceed the + * stated length. (The resulting output will of course fail to decode.) + */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, + NULL, &streamInfo); + CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + CryptMsgClose(msg); + check_updates("bogus data message with definite length", &a1, &accum); + free_updates(&accum); + /* A valid definite-length encoding: */ + streamInfo.cbContent = sizeof(msgData); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, + NULL, &streamInfo); + CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + CryptMsgClose(msg); + check_updates("data message with definite length", &a2, &accum); + free_updates(&accum); + /* An indefinite-length encoding: */ + streamInfo.cbContent = 0xffffffff; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, + NULL, &streamInfo); + CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + CryptMsgClose(msg); + check_updates("data message with indefinite length", &a3, &accum); + free_updates(&accum); +} + +static void test_data_msg(void) +{ + test_data_msg_open(); + test_data_msg_update(); + test_data_msg_get_param(); + test_data_msg_encoding(); +} + +static void test_hash_msg_open(void) +{ + HCRYPTMSG msg; + CMSG_HASHED_ENCODE_INFO hashInfo = { 0 }; + CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL }; + + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, NULL); + ok(!msg && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + hashInfo.cbSize = sizeof(hashInfo); + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, NULL); + ok(!msg && GetLastError() == CRYPT_E_UNKNOWN_ALGO, + "Expected CRYPT_E_UNKNOWN_ALGO, got %x\n", GetLastError()); + hashInfo.HashAlgorithm.pszObjId = oid_rsa_md5; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, + CMSG_HASHED, &hashInfo, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, + CMSG_HASHED, &hashInfo, NULL, &streamInfo); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); +} + +static void test_hash_msg_update(void) +{ + HCRYPTMSG msg; + BOOL ret; + CMSG_HASHED_ENCODE_INFO hashInfo = { sizeof(hashInfo), 0, + { oid_rsa_md5, { 0, NULL } }, NULL }; + CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL }; + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, + CMSG_HASHED, &hashInfo, NULL, NULL); + /* Detached hashed messages opened in non-streaming mode allow non-final + * updates.. + */ + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* including non-final updates with no data.. */ + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* and final updates with no data. */ + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* But no updates are allowed after the final update. */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + CryptMsgClose(msg); + /* Non-detached messages, in contrast, don't allow non-final updates in + * non-streaming mode. + */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + /* Final updates (including empty ones) are allowed. */ + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + /* And, of course, streaming mode allows non-final updates */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, &streamInfo); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + /* Setting pfnStreamOutput to NULL results in no error. (In what appears + * to be a bug, it isn't actually used - see encoding tests.) + */ + streamInfo.pfnStreamOutput = NULL; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, &streamInfo); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + CryptMsgClose(msg); +} + +static const BYTE emptyHashParam[] = { +0xd4,0x1d,0x8c,0xd9,0x8f,0x00,0xb2,0x04,0xe9,0x80,0x09,0x98,0xec,0xf8,0x42, +0x7e }; + +static void test_hash_msg_get_param(void) +{ + HCRYPTMSG msg; + BOOL ret; + CMSG_HASHED_ENCODE_INFO hashInfo = { sizeof(hashInfo), 0, + { oid_rsa_md5, { 0, NULL } }, NULL }; + DWORD size, value; + CMSG_STREAM_INFO streamInfo = { 0, nop_stream_output, NULL }; + BYTE buf[16]; + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, NULL); + /* Content and bare content are always gettable for non-streamed messages */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size); + ok(ret || broken(GetLastError() == OSS_LIMITED /* Win9x */), + "CryptMsgGetParam failed: %08x\n", GetLastError()); + size = 0; + ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size); + ok(ret || broken(GetLastError() == OSS_LIMITED /* Win9x */), + "CryptMsgGetParam failed: %08x\n", GetLastError()); + /* For an encoded hash message, the hash data aren't available */ + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_HASH_DATA_PARAM, 0, NULL, &size); + ok(!ret && (GetLastError() == CRYPT_E_INVALID_MSG_TYPE || + GetLastError() == OSS_LIMITED /* Win9x */), + "Expected CRYPT_E_INVALID_MSG_TYPE or OSS_LIMITED, got %08x\n", + GetLastError()); + /* The hash is also available. */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(size == sizeof(buf), "Unexpected size %d\n", size); + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size); + if (size == sizeof(buf)) + ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n"); + /* By getting the hash, further updates are not allowed */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(!ret && + (GetLastError() == NTE_BAD_HASH_STATE /* NT */ || + GetLastError() == NTE_BAD_ALGID /* 9x */ || + GetLastError() == CRYPT_E_MSG_ERROR /* Vista */ || + broken(GetLastError() == ERROR_SUCCESS) /* Some Win9x */), + "Expected NTE_BAD_HASH_STATE or NTE_BAD_ALGID or CRYPT_E_MSG_ERROR, got 0x%x\n", GetLastError()); + + /* Even after a final update, the hash data aren't available */ + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_HASH_DATA_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + /* The version is also available, and should be zero for this message. */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, NULL, &size); + ok(ret || broken(GetLastError() == CRYPT_E_INVALID_MSG_TYPE /* Win9x */), + "CryptMsgGetParam failed: %08x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, &value, &size); + ok(ret || broken(GetLastError() == CRYPT_E_INVALID_MSG_TYPE /* Win9x */), + "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (ret) + ok(value == 0, "Expected version 0, got %d\n", value); + /* As usual, the type isn't available. */ + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size); + ok(!ret, "Expected failure\n"); + CryptMsgClose(msg); + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, &streamInfo); + /* Streamed messages don't allow you to get the content or bare content. */ + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size); + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x */), + "Expected E_INVALIDARG or OSS_LIMITED, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size); + ok(!ret && (GetLastError() == E_INVALIDARG || + GetLastError() == OSS_LIMITED /* Win9x */), + "Expected E_INVALIDARG or OSS_LIMITED, got %x\n", GetLastError()); + /* The hash is still available. */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(size == sizeof(buf), "Unexpected size %d\n", size); + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, buf, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (size == sizeof(buf)) + ok(!memcmp(buf, emptyHashParam, size), "Unexpected value\n"); + /* After updating the hash, further updates aren't allowed on streamed + * messages either. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(!ret && + (GetLastError() == NTE_BAD_HASH_STATE /* NT */ || + GetLastError() == NTE_BAD_ALGID /* 9x */ || + GetLastError() == CRYPT_E_MSG_ERROR /* Vista */ || + broken(GetLastError() == ERROR_SUCCESS) /* Some Win9x */), + "Expected NTE_BAD_HASH_STATE or NTE_BAD_ALGID or CRYPT_E_MSG_ERROR, got 0x%x\n", GetLastError()); + + CryptMsgClose(msg); +} + +static const BYTE hashEmptyBareContent[] = { +0x30,0x17,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x04,0x00 }; +static const BYTE hashEmptyContent[] = { +0x30,0x26,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x19, +0x30,0x17,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x04,0x00 }; +static const BYTE hashBareContent[] = { +0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0, +0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f }; +static const BYTE hashContent[] = { +0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a, +0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0, +0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f }; + +static const BYTE detachedHashNonFinalBareContent[] = { +0x30,0x20,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0x04,0x00 }; +static const BYTE detachedHashNonFinalContent[] = { +0x30,0x2f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x22, +0x30,0x20,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0x04,0x00 }; +static const BYTE detachedHashBareContent[] = { +0x30,0x30,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb, +0x9d,0x2a,0x8f,0x26,0x2f }; +static const BYTE detachedHashContent[] = { +0x30,0x3f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x32, +0x30,0x30,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb, +0x9d,0x2a,0x8f,0x26,0x2f }; + +static void test_hash_msg_encoding(void) +{ + HCRYPTMSG msg; + CMSG_HASHED_ENCODE_INFO hashInfo = { sizeof(hashInfo), 0 }; + BOOL ret; + struct update_accum accum = { 0, NULL }, empty_accum = { 0, NULL }; + CMSG_STREAM_INFO streamInfo = { 0, accumulating_stream_output, &accum }; + + hashInfo.HashAlgorithm.pszObjId = oid_rsa_md5; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, NULL); + check_param("hash empty bare content", msg, CMSG_BARE_CONTENT_PARAM, + hashEmptyBareContent, sizeof(hashEmptyBareContent)); + check_param("hash empty content", msg, CMSG_CONTENT_PARAM, + hashEmptyContent, sizeof(hashEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("hash bare content", msg, CMSG_BARE_CONTENT_PARAM, + hashBareContent, sizeof(hashBareContent)); + check_param("hash content", msg, CMSG_CONTENT_PARAM, + hashContent, sizeof(hashContent)); + CryptMsgClose(msg); + /* Same test, but with CMSG_BARE_CONTENT_FLAG set */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_BARE_CONTENT_FLAG, + CMSG_HASHED, &hashInfo, NULL, NULL); + check_param("hash empty bare content", msg, CMSG_BARE_CONTENT_PARAM, + hashEmptyBareContent, sizeof(hashEmptyBareContent)); + check_param("hash empty content", msg, CMSG_CONTENT_PARAM, + hashEmptyContent, sizeof(hashEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("hash bare content", msg, CMSG_BARE_CONTENT_PARAM, + hashBareContent, sizeof(hashBareContent)); + check_param("hash content", msg, CMSG_CONTENT_PARAM, + hashContent, sizeof(hashContent)); + CryptMsgClose(msg); + /* Same test, but with CMSG_DETACHED_FLAG set */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, + CMSG_HASHED, &hashInfo, NULL, NULL); + check_param("detached hash empty bare content", msg, + CMSG_BARE_CONTENT_PARAM, hashEmptyBareContent, + sizeof(hashEmptyBareContent)); + check_param("detached hash empty content", msg, CMSG_CONTENT_PARAM, + hashEmptyContent, sizeof(hashEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("detached hash not final bare content", msg, + CMSG_BARE_CONTENT_PARAM, detachedHashNonFinalBareContent, + sizeof(detachedHashNonFinalBareContent)); + check_param("detached hash not final content", msg, CMSG_CONTENT_PARAM, + detachedHashNonFinalContent, sizeof(detachedHashNonFinalContent)); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + check_param("detached hash bare content", msg, CMSG_BARE_CONTENT_PARAM, + detachedHashBareContent, sizeof(detachedHashBareContent)); + check_param("detached hash content", msg, CMSG_CONTENT_PARAM, + detachedHashContent, sizeof(detachedHashContent)); + check_param("detached hash bare content", msg, CMSG_BARE_CONTENT_PARAM, + detachedHashBareContent, sizeof(detachedHashBareContent)); + check_param("detached hash content", msg, CMSG_CONTENT_PARAM, + detachedHashContent, sizeof(detachedHashContent)); + CryptMsgClose(msg); + /* In what appears to be a bug, streamed updates to hash messages don't + * call the output function. + */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, &streamInfo); + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + check_updates("empty hash message", &empty_accum, &accum); + free_updates(&accum); + + streamInfo.cbContent = sizeof(msgData); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, &streamInfo); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + check_updates("hash message", &empty_accum, &accum); + free_updates(&accum); + + streamInfo.cbContent = sizeof(msgData); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, + CMSG_HASHED, &hashInfo, NULL, &streamInfo); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + check_updates("detached hash message", &empty_accum, &accum); + free_updates(&accum); +} + +static void test_hash_msg(void) +{ + test_hash_msg_open(); + test_hash_msg_update(); + test_hash_msg_get_param(); + test_hash_msg_encoding(); +} + +static const CHAR cspNameA[] = { 'W','i','n','e','C','r','y','p','t','T','e', + 'm','p',0 }; +static const WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e', + 'm','p',0 }; +static BYTE serialNum[] = { 1 }; +static BYTE encodedCommonName[] = { 0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03, + 0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00 }; + +static void test_signed_msg_open(void) +{ + HCRYPTMSG msg; + BOOL ret; + CMSG_SIGNED_ENCODE_INFO signInfo = { 0 }; + CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 }; + CERT_INFO certInfo = { 0 }; + + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(!msg && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %x\n", GetLastError()); + signInfo.cbSize = sizeof(signInfo); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + signInfo.cSigners = 1; + signInfo.rgSigners = &signer; + /* With signer.pCertInfo unset, attempting to open this message this + * crashes. + */ + signer.pCertInfo = &certInfo; + /* The cert info must contain a serial number and an issuer. */ + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + /* NT: E_INVALIDARG, 9x: unchanged or CRYPT_E_UNKNOWN_ALGO */ + ok(!msg && (GetLastError() == E_INVALIDARG || GetLastError() == 0xdeadbeef + || GetLastError() == CRYPT_E_UNKNOWN_ALGO), + "Expected E_INVALIDARG or 0xdeadbeef or CRYPT_E_UNKNOWN_ALGO, got 0x%x\n", + GetLastError()); + + certInfo.SerialNumber.cbData = sizeof(serialNum); + certInfo.SerialNumber.pbData = serialNum; + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + /* NT: E_INVALIDARG, 9x: unchanged or CRYPT_E_UNKNOWN_ALGO */ + ok(!msg && (GetLastError() == E_INVALIDARG || GetLastError() == 0xdeadbeef + || GetLastError() == CRYPT_E_UNKNOWN_ALGO), + "Expected E_INVALIDARG or 0xdeadbeef or CRYPT_E_UNKNOWN_ALGO, got 0x%x\n", + GetLastError()); + + certInfo.Issuer.cbData = sizeof(encodedCommonName); + certInfo.Issuer.pbData = encodedCommonName; + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(!msg && (GetLastError() == E_INVALIDARG || + GetLastError() == CRYPT_E_UNKNOWN_ALGO), + "Expected E_INVALIDARG or CRYPT_E_UNKNOWN_ALGO, got %x\n", GetLastError()); + + /* The signer's hCryptProv must be set to something. Whether it's usable + * or not will be checked after the hash algorithm is checked (see next + * test.) + */ + signer.hCryptProv = 1; + SetLastError(0xdeadbeef); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(!msg && GetLastError() == CRYPT_E_UNKNOWN_ALGO, + "Expected CRYPT_E_UNKNOWN_ALGO, got %x\n", GetLastError()); + /* The signer's hash algorithm must also be set. */ + signer.HashAlgorithm.pszObjId = oid_rsa_md5; + SetLastError(0xdeadbeef); + /* Crashes in advapi32 in wine, don't do it */ + if (0) { + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, + &signInfo, NULL, NULL); + ok(!msg && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError()); + } + /* The signer's hCryptProv must also be valid. */ + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + if (!ret && GetLastError() == NTE_EXISTS) { + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, 0); + } + ok(ret, "CryptAcquireContext failed: 0x%x\n", GetLastError()); + + if (ret) { + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + } + + /* pCertInfo must still be set, but can be empty if the SignerId's issuer + * and serial number are set. + */ + certInfo.Issuer.cbData = 0; + certInfo.SerialNumber.cbData = 0; + signer.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + U(signer.SignerId).IssuerSerialNumber.Issuer.cbData = + sizeof(encodedCommonName); + U(signer.SignerId).IssuerSerialNumber.Issuer.pbData = encodedCommonName; + U(signer.SignerId).IssuerSerialNumber.SerialNumber.cbData = + sizeof(serialNum); + U(signer.SignerId).IssuerSerialNumber.SerialNumber.pbData = serialNum; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + CryptReleaseContext(signer.hCryptProv, 0); + pCryptAcquireContextA(&signer.hCryptProv, cspNameA, MS_DEF_PROV_A, + PROV_RSA_FULL, CRYPT_DELETEKEYSET); +} + +static const BYTE privKey[] = { + 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, + 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10, + 0x18, 0x30, 0x94, 0x61, 0xdc, 0x0e, 0xcb, 0x96, 0x4e, 0x21, 0x3f, 0x79, 0xcd, + 0xa9, 0x17, 0x62, 0xbc, 0xbb, 0x61, 0x4c, 0xe0, 0x75, 0x38, 0x6c, 0xf3, 0xde, + 0x60, 0x86, 0x03, 0x97, 0x65, 0xeb, 0x1e, 0x6b, 0xdb, 0x53, 0x85, 0xad, 0x68, + 0x21, 0xf1, 0x5d, 0xe7, 0x1f, 0xe6, 0x53, 0xb4, 0xbb, 0x59, 0x3e, 0x14, 0x27, + 0xb1, 0x83, 0xa7, 0x3a, 0x54, 0xe2, 0x8f, 0x65, 0x8e, 0x6a, 0x4a, 0xcf, 0x3b, + 0x1f, 0x65, 0xff, 0xfe, 0xf1, 0x31, 0x3a, 0x37, 0x7a, 0x8b, 0xcb, 0xc6, 0xd4, + 0x98, 0x50, 0x36, 0x67, 0xe4, 0xa1, 0xe8, 0x7e, 0x8a, 0xc5, 0x23, 0xf2, 0x77, + 0xf5, 0x37, 0x61, 0x49, 0x72, 0x59, 0xe8, 0x3d, 0xf7, 0x60, 0xb2, 0x77, 0xca, + 0x78, 0x54, 0x6d, 0x65, 0x9e, 0x03, 0x97, 0x1b, 0x61, 0xbd, 0x0c, 0xd8, 0x06, + 0x63, 0xe2, 0xc5, 0x48, 0xef, 0xb3, 0xe2, 0x6e, 0x98, 0x7d, 0xbd, 0x4e, 0x72, + 0x91, 0xdb, 0x31, 0x57, 0xe3, 0x65, 0x3a, 0x49, 0xca, 0xec, 0xd2, 0x02, 0x4e, + 0x22, 0x7e, 0x72, 0x8e, 0xf9, 0x79, 0x84, 0x82, 0xdf, 0x7b, 0x92, 0x2d, 0xaf, + 0xc9, 0xe4, 0x33, 0xef, 0x89, 0x5c, 0x66, 0x99, 0xd8, 0x80, 0x81, 0x47, 0x2b, + 0xb1, 0x66, 0x02, 0x84, 0x59, 0x7b, 0xc3, 0xbe, 0x98, 0x45, 0x4a, 0x3d, 0xdd, + 0xea, 0x2b, 0xdf, 0x4e, 0xb4, 0x24, 0x6b, 0xec, 0xe7, 0xd9, 0x0c, 0x45, 0xb8, + 0xbe, 0xca, 0x69, 0x37, 0x92, 0x4c, 0x38, 0x6b, 0x96, 0x6d, 0xcd, 0x86, 0x67, + 0x5c, 0xea, 0x54, 0x94, 0xa4, 0xca, 0xa4, 0x02, 0xa5, 0x21, 0x4d, 0xae, 0x40, + 0x8f, 0x9d, 0x51, 0x83, 0xf2, 0x3f, 0x33, 0xc1, 0x72, 0xb4, 0x1d, 0x94, 0x6e, + 0x7d, 0xe4, 0x27, 0x3f, 0xea, 0xff, 0xe5, 0x9b, 0xa7, 0x5e, 0x55, 0x8e, 0x0d, + 0x69, 0x1c, 0x7a, 0xff, 0x81, 0x9d, 0x53, 0x52, 0x97, 0x9a, 0x76, 0x79, 0xda, + 0x93, 0x32, 0x16, 0xec, 0x69, 0x51, 0x1a, 0x4e, 0xc3, 0xf1, 0x72, 0x80, 0x78, + 0x5e, 0x66, 0x4a, 0x8d, 0x85, 0x2f, 0x3f, 0xb2, 0xa7 }; +static BYTE pubKey[] = { +0x30,0x48,0x02,0x41,0x00,0xe2,0x54,0x3a,0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59, +0xbb,0xb4,0x53,0xe6,0x1f,0xe7,0x5d,0xf1,0x21,0x68,0xad,0x85,0x53,0xdb,0x6b, +0x1e,0xeb,0x65,0x97,0x03,0x86,0x60,0xde,0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61, +0xbb,0xbc,0x62,0x17,0xa9,0xcd,0x79,0x3f,0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61, +0x94,0x30,0x18,0x10,0x6b,0xd0,0x1c,0x10,0x79,0x02,0x03,0x01,0x00,0x01 }; + +static void test_signed_msg_update(void) +{ + HCRYPTMSG msg; + BOOL ret; + CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 }; + CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 }; + CERT_INFO certInfo = { 0 }; + HCRYPTKEY key; + + certInfo.SerialNumber.cbData = sizeof(serialNum); + certInfo.SerialNumber.pbData = serialNum; + certInfo.Issuer.cbData = sizeof(encodedCommonName); + certInfo.Issuer.pbData = encodedCommonName; + signer.pCertInfo = &certInfo; + signer.HashAlgorithm.pszObjId = oid_rsa_md5; + signInfo.cSigners = 1; + signInfo.rgSigners = &signer; + + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + if (!ret && GetLastError() == NTE_EXISTS) { + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, 0); + } + ok(ret, "CryptAcquireContext failed: 0x%x\n", GetLastError()); + + if (!ret) { + skip("No context for tests\n"); + return; + } + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, + CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + /* Detached CMSG_SIGNED allows non-final updates. */ + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* Detached CMSG_SIGNED also allows non-final updates with no data. */ + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* The final update requires a private key in the hCryptProv, in order to + * generate the signature. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(!ret && + (GetLastError() == NTE_BAD_KEYSET || + GetLastError() == NTE_NO_KEY || + broken(GetLastError() == ERROR_SUCCESS)), /* Some Win9x */ + "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %x\n", GetLastError()); + ret = CryptImportKey(signer.hCryptProv, privKey, sizeof(privKey), + 0, 0, &key); + ok(ret, "CryptImportKey failed: %08x\n", GetLastError()); + /* The final update should be able to succeed now that a key exists, but + * the previous (invalid) final update prevents it. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, + CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + /* Detached CMSG_SIGNED allows non-final updates. */ + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* Detached CMSG_SIGNED also allows non-final updates with no data. */ + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* Now that the private key exists, the final update can succeed (even + * with no data.) + */ + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* But no updates are allowed after the final update. */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + /* Non-detached messages don't allow non-final updates.. */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + /* but they do allow final ones. */ + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + /* They also allow final updates with no data. */ + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + + CryptDestroyKey(key); + CryptReleaseContext(signer.hCryptProv, 0); + pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); +} + +static const BYTE signedEmptyBareContent[] = { +0x30,0x50,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x31,0x37,0x30,0x35,0x02, +0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01, +0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30, +0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; +static const BYTE signedEmptyContent[] = { +0x30,0x5f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,0x52, +0x30,0x50,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x31,0x37,0x30,0x35,0x02, +0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01, +0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30, +0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; +static const BYTE detachedSignedBareContent[] = { +0x30,0x81,0x99,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x07,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30, +0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, +0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00, +0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6, +0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee, +0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92, +0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44, +0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE detachedSignedContent[] = { +0x30,0x81,0xaa,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0x9c,0x30,0x81,0x99,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x0b,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30, +0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a, +0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06, +0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00, +0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0, +0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0, +0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23, +0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51, +0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE signedBareContent[] = { +0x30,0x81,0xa1,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x31,0x77, +0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03, +0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00, +0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05, +0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef, +0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59, +0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63, +0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf, +0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE signedContent[] = { +0x30,0x81,0xb2,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0xa4,0x30,0x81,0xa1,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04, +0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70, +0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d, +0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe, +0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29, +0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8, +0x0d }; +static const BYTE signedHash[] = { +0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26, +0x2f }; +static const BYTE signedKeyIdEmptyContent[] = { +0x30,0x46,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0,0x39, +0x30,0x37,0x02,0x01,0x03,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0x31,0x1e,0x30,0x1c,0x02, +0x01,0x03,0x80,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; +static const BYTE signedEncodedSigner[] = { +0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03, +0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00, +0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05, +0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef, +0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59, +0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63, +0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf, +0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE signedWithAuthAttrsBareContent[] = { +0x30,0x82,0x01,0x00,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x31, +0x81,0xd5,0x30,0x81,0xd2,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x02,0x05,0x05,0x00,0xa0,0x5b,0x30,0x18,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x09,0x03,0x31,0x0b,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x07,0x01,0x30,0x1e,0x06,0x03,0x55,0x04,0x03,0x31,0x17,0x30,0x15,0x31, +0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20, +0x4c,0x61,0x6e,0x67,0x00,0x30,0x1f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x01,0x09,0x04,0x31,0x12,0x04,0x10,0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79, +0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f,0x30,0x04,0x06,0x00,0x05,0x00,0x04, +0x40,0xbf,0x65,0xde,0x7a,0x3e,0xa2,0x19,0x59,0xc3,0xc7,0x02,0x53,0xc9,0x72, +0xcd,0x74,0x96,0x70,0x0b,0x3b,0xcf,0x8b,0xd9,0x17,0x5c,0xc5,0xd1,0x83,0x41, +0x32,0x93,0xa6,0xf3,0x52,0x83,0x94,0xa9,0x6b,0x0a,0x92,0xcf,0xaf,0x12,0xfa, +0x40,0x53,0x12,0x84,0x03,0xab,0x10,0xa2,0x3d,0xe6,0x9f,0x5a,0xbf,0xc5,0xb8, +0xff,0xc6,0x33,0x63,0x34 }; +static BYTE cert[] = { +0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67, +0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30, +0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01, +0xff,0x02,0x01,0x01 }; +static BYTE v1CertWithPubKey[] = { +0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, +0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06, +0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02, +0x01,0x01 }; +static const BYTE signedWithCertEmptyBareContent[] = { +0x30,0x81,0xce,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x7c,0x30,0x7a, +0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03, +0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00, +0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30, +0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,0x12,0x06, +0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02, +0x01,0x01,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13, +0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c, +0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; +static const BYTE signedWithCertBareContent[] = { +0x30,0x82,0x01,0x1f,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0xa0, +0x7c,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14, +0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01, +0x01,0xff,0x02,0x01,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30, +0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, +0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00, +0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6, +0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee, +0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92, +0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44, +0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static BYTE crl[] = { 0x30,0x2c,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a }; +static const BYTE signedWithCrlEmptyBareContent[] = { +0x30,0x81,0x80,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa1,0x2e,0x30,0x2c, +0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03, +0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31, +0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x31, +0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67, +0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02, +0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; +static const BYTE signedWithCrlBareContent[] = { +0x30,0x81,0xd1,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0xa1,0x2e, +0x30,0x2c,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18, +0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30, +0x5a,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6, +0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f, +0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59, +0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57, +0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4, +0xa8,0x0d }; +static const BYTE signedWithCertAndCrlEmptyBareContent[] = { +0x30,0x81,0xfe,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x7c,0x30,0x7a, +0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03, +0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00, +0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30, +0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55, +0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30, +0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,0x12,0x06, +0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02, +0x01,0x01,0xa1,0x2e,0x30,0x2c,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30, +0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, +0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00, +0x04,0x00 }; +static const BYTE signedWithCertAndCrlBareContent[] = { +0x30,0x82,0x01,0x4f,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0xa0, +0x7c,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14, +0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01, +0x01,0xff,0x02,0x01,0x01,0xa1,0x2e,0x30,0x2c,0x30,0x02,0x06,0x00,0x30,0x15, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, +0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x31,0x77,0x30,0x75,0x02,0x01,0x01, +0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a, +0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c, +0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06, +0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b, +0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c, +0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d, +0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39, +0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE signedWithCertWithPubKeyBareContent[] = { +0x30,0x81,0xeb,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06,0x00,0xa0,0x81,0x98,0x30, +0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,0x06, +0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67, +0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01, +0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, +0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03, +0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01, +0x01,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x00 }; +static BYTE v1CertWithValidPubKey[] = { +0x30,0x81,0xcf,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x4b,0x00,0x30,0x48,0x02,0x41,0x00,0xe2,0x54,0x3a, +0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb,0xb4,0x53,0xe6,0x1f,0xe7,0x5d,0xf1, +0x21,0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb,0x65,0x97,0x03,0x86,0x60,0xde, +0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc,0x62,0x17,0xa9,0xcd,0x79,0x3f, +0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30,0x18,0x10,0x6b,0xd0,0x1c,0x10, +0x79,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55, +0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static const BYTE signedWithCertWithValidPubKeyEmptyContent[] = { +0x30,0x82,0x01,0x38,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x82,0x01,0x29,0x30,0x82,0x01,0x25,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c, +0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x02,0x06, +0x00,0xa0,0x81,0xd2,0x30,0x81,0xcf,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30, +0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, +0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31, +0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, +0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x4b,0x00,0x30,0x48,0x02,0x41, +0x00,0xe2,0x54,0x3a,0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb,0xb4,0x53,0xe6, +0x1f,0xe7,0x5d,0xf1,0x21,0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb,0x65,0x97, +0x03,0x86,0x60,0xde,0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc,0x62,0x17, +0xa9,0xcd,0x79,0x3f,0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30,0x18,0x10, +0x6b,0xd0,0x1c,0x10,0x79,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30,0x14,0x30, +0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01, +0xff,0x02,0x01,0x01,0x31,0x37,0x30,0x35,0x02,0x01,0x01,0x30,0x1a,0x30,0x15, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, +0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04, +0x00 }; +static const BYTE signedWithCertWithValidPubKeyContent[] = { +0x30,0x82,0x01,0x89,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x82,0x01,0x7a,0x30,0x82,0x01,0x76,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c, +0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01, +0x02,0x03,0x04,0xa0,0x81,0xd2,0x30,0x81,0xcf,0x02,0x01,0x01,0x30,0x02,0x06, +0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a, +0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f, +0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a, +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x4b,0x00,0x30,0x48, +0x02,0x41,0x00,0xe2,0x54,0x3a,0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb,0xb4, +0x53,0xe6,0x1f,0xe7,0x5d,0xf1,0x21,0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb, +0x65,0x97,0x03,0x86,0x60,0xde,0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc, +0x62,0x17,0xa9,0xcd,0x79,0x3f,0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30, +0x18,0x10,0x6b,0xd0,0x1c,0x10,0x79,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30, +0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06, +0x01,0x01,0xff,0x02,0x01,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a, +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05, +0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a, +0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e, +0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64, +0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4, +0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; + +static void test_signed_msg_encoding(void) +{ + HCRYPTMSG msg; + CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 }; + CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 }; + CERT_INFO certInfo = { 0 }; + CERT_BLOB encodedCert = { sizeof(cert), cert }; + CRL_BLOB encodedCrl = { sizeof(crl), crl }; + char oid_common_name[] = szOID_COMMON_NAME; + CRYPT_ATTR_BLOB commonName = { sizeof(encodedCommonName), + encodedCommonName }; + CRYPT_ATTRIBUTE attr = { oid_common_name, 1, &commonName }; + BOOL ret; + HCRYPTKEY key; + DWORD size; + + certInfo.SerialNumber.cbData = sizeof(serialNum); + certInfo.SerialNumber.pbData = serialNum; + certInfo.Issuer.cbData = sizeof(encodedCommonName); + certInfo.Issuer.pbData = encodedCommonName; + signer.pCertInfo = &certInfo; + signer.HashAlgorithm.pszObjId = oid_rsa_md5; + signInfo.cSigners = 1; + signInfo.rgSigners = &signer; + + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + if (!ret && GetLastError() == NTE_EXISTS) { + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, 0); + } + ok(ret, "CryptAcquireContext failed: 0x%x\n", GetLastError()); + + if (!ret) { + skip("No context for tests\n"); + return; + } + + ret = CryptImportKey(signer.hCryptProv, privKey, sizeof(privKey), + 0, 0, &key); + ok(ret, "CryptImportKey failed: %08x\n", GetLastError()); + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, + CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + check_param("detached signed empty bare content", msg, + CMSG_BARE_CONTENT_PARAM, signedEmptyBareContent, + sizeof(signedEmptyBareContent)); + check_param("detached signed empty content", msg, CMSG_CONTENT_PARAM, + signedEmptyContent, sizeof(signedEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("detached signed hash", msg, CMSG_COMPUTED_HASH_PARAM, + signedHash, sizeof(signedHash)); + check_param("detached signed bare content", msg, CMSG_BARE_CONTENT_PARAM, + detachedSignedBareContent, sizeof(detachedSignedBareContent)); + check_param("detached signed content", msg, CMSG_CONTENT_PARAM, + detachedSignedContent, sizeof(detachedSignedContent)); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 1, NULL, &size); + ok(!ret && (GetLastError() == CRYPT_E_INVALID_INDEX || + broken(GetLastError() == CRYPT_E_INVALID_MSG_TYPE /* Win9x */)), + "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError()); + check_param("detached signed encoded signer", msg, CMSG_ENCODED_SIGNER, + signedEncodedSigner, sizeof(signedEncodedSigner)); + + CryptMsgClose(msg); + + certInfo.SerialNumber.cbData = 0; + certInfo.Issuer.cbData = 0; + signer.SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + U(signer.SignerId).KeyId.cbData = sizeof(serialNum); + U(signer.SignerId).KeyId.pbData = serialNum; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + check_param("signed key id empty content", msg, CMSG_CONTENT_PARAM, + signedKeyIdEmptyContent, sizeof(signedKeyIdEmptyContent)); + CryptMsgClose(msg); + + certInfo.SerialNumber.cbData = sizeof(serialNum); + certInfo.SerialNumber.pbData = serialNum; + certInfo.Issuer.cbData = sizeof(encodedCommonName); + certInfo.Issuer.pbData = encodedCommonName; + signer.SignerId.dwIdChoice = 0; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + check_param("signed empty bare content", msg, CMSG_BARE_CONTENT_PARAM, + signedEmptyBareContent, sizeof(signedEmptyBareContent)); + check_param("signed empty content", msg, CMSG_CONTENT_PARAM, + signedEmptyContent, sizeof(signedEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("signed bare content", msg, CMSG_BARE_CONTENT_PARAM, + signedBareContent, sizeof(signedBareContent)); + check_param("signed content", msg, CMSG_CONTENT_PARAM, + signedContent, sizeof(signedContent)); + + CryptMsgClose(msg); + + signer.cAuthAttr = 1; + signer.rgAuthAttr = &attr; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + check_param("signed with auth attrs bare content", msg, + CMSG_BARE_CONTENT_PARAM, signedWithAuthAttrsBareContent, + sizeof(signedWithAuthAttrsBareContent)); + + CryptMsgClose(msg); + + signer.cAuthAttr = 0; + signInfo.rgCertEncoded = &encodedCert; + signInfo.cCertEncoded = 1; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + check_param("signed with cert empty bare content", msg, + CMSG_BARE_CONTENT_PARAM, signedWithCertEmptyBareContent, + sizeof(signedWithCertEmptyBareContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("signed with cert bare content", msg, CMSG_BARE_CONTENT_PARAM, + signedWithCertBareContent, sizeof(signedWithCertBareContent)); + + CryptMsgClose(msg); + + signInfo.cCertEncoded = 0; + signInfo.rgCrlEncoded = &encodedCrl; + signInfo.cCrlEncoded = 1; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + check_param("signed with crl empty bare content", msg, + CMSG_BARE_CONTENT_PARAM, signedWithCrlEmptyBareContent, + sizeof(signedWithCrlEmptyBareContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("signed with crl bare content", msg, CMSG_BARE_CONTENT_PARAM, + signedWithCrlBareContent, sizeof(signedWithCrlBareContent)); + + CryptMsgClose(msg); + + signInfo.cCertEncoded = 1; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + check_param("signed with cert and crl empty bare content", msg, + CMSG_BARE_CONTENT_PARAM, signedWithCertAndCrlEmptyBareContent, + sizeof(signedWithCertAndCrlEmptyBareContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + check_param("signed with cert and crl bare content", msg, + CMSG_BARE_CONTENT_PARAM, signedWithCertAndCrlBareContent, + sizeof(signedWithCertAndCrlBareContent)); + + CryptMsgClose(msg); + + /* Test with a cert with a (bogus) public key */ + signInfo.cCrlEncoded = 0; + encodedCert.cbData = sizeof(v1CertWithPubKey); + encodedCert.pbData = v1CertWithPubKey; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + check_param("signedWithCertWithPubKeyBareContent", msg, + CMSG_BARE_CONTENT_PARAM, signedWithCertWithPubKeyBareContent, + sizeof(signedWithCertWithPubKeyBareContent)); + CryptMsgClose(msg); + + encodedCert.cbData = sizeof(v1CertWithValidPubKey); + encodedCert.pbData = v1CertWithValidPubKey; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + check_param("signedWithCertWithValidPubKeyEmptyContent", msg, + CMSG_CONTENT_PARAM, signedWithCertWithValidPubKeyEmptyContent, + sizeof(signedWithCertWithValidPubKeyEmptyContent)); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + check_param("signedWithCertWithValidPubKeyContent", msg, + CMSG_CONTENT_PARAM, signedWithCertWithValidPubKeyContent, + sizeof(signedWithCertWithValidPubKeyContent)); + CryptMsgClose(msg); + + CryptDestroyKey(key); + CryptReleaseContext(signer.hCryptProv, 0); + pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); +} + +static void test_signed_msg_get_param(void) +{ + BOOL ret; + HCRYPTMSG msg; + DWORD size, value = 0; + CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 }; + CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 }; + CERT_INFO certInfo = { 0 }; + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + /* Content and bare content are always gettable */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size); + ok(ret || broken(!ret /* Win9x */), "CryptMsgGetParam failed: %08x\n", + GetLastError()); + if (!ret) + { + skip("message parameters are broken, skipping tests\n"); + return; + } + size = 0; + ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + /* For "signed" messages, so is the version. */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(value == CMSG_SIGNED_DATA_V1, "Expected version 1, got %d\n", value); + /* But for this message, with no signers, the hash and signer aren't + * available. + */ + size = 0; + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX, + "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX, + "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError()); + /* As usual, the type isn't available. */ + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + + CryptMsgClose(msg); + + certInfo.SerialNumber.cbData = sizeof(serialNum); + certInfo.SerialNumber.pbData = serialNum; + certInfo.Issuer.cbData = sizeof(encodedCommonName); + certInfo.Issuer.pbData = encodedCommonName; + signer.pCertInfo = &certInfo; + signer.HashAlgorithm.pszObjId = oid_rsa_md5; + signInfo.cSigners = 1; + signInfo.rgSigners = &signer; + + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + if (!ret && GetLastError() == NTE_EXISTS) { + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, 0); + } + ok(ret, "CryptAcquireContext failed: 0x%x\n", GetLastError()); + + if (!ret) { + skip("No context for tests\n"); + return; + } + + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + + /* This message, with one signer, has the hash and signer for index 0 + * available, but not for other indexes. + */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %x\n", GetLastError()); + size = 0; + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 1, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX, + "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 1, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX, + "Expected CRYPT_E_INVALID_INDEX, got %x\n", GetLastError()); + /* As usual, the type isn't available. */ + ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + + CryptMsgClose(msg); + + /* Opening the message using the CMS fields.. */ + certInfo.SerialNumber.cbData = 0; + certInfo.Issuer.cbData = 0; + signer.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + U(signer.SignerId).IssuerSerialNumber.Issuer.cbData = + sizeof(encodedCommonName); + U(signer.SignerId).IssuerSerialNumber.Issuer.pbData = encodedCommonName; + U(signer.SignerId).IssuerSerialNumber.SerialNumber.cbData = + sizeof(serialNum); + U(signer.SignerId).IssuerSerialNumber.SerialNumber.pbData = serialNum; + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + if (!ret && GetLastError() == NTE_EXISTS) + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, 0); + ok(ret, "CryptAcquireContextA failed: %x\n", GetLastError()); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, + CMSG_CRYPT_RELEASE_CONTEXT_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + /* still results in the version being 1 when the issuer and serial number + * are used and no additional CMS fields are used. + */ + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, &value, &size); + ok(ret || broken(GetLastError() == CRYPT_E_INVALID_MSG_TYPE), + "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (ret) + ok(value == CMSG_SIGNED_DATA_V1, "expected version 1, got %d\n", value); + /* Apparently the encoded signer can be retrieved.. */ + ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + /* but the signer info, CMS signer info, and cert ID can't be. */ + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_SIGNER_CERT_ID_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + CryptMsgClose(msg); + + /* Using the KeyId field of the SignerId results in the version becoming + * the CMS version. + */ + signer.SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + U(signer.SignerId).KeyId.cbData = sizeof(serialNum); + U(signer.SignerId).KeyId.pbData = serialNum; + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + if (!ret && GetLastError() == NTE_EXISTS) + ret = pCryptAcquireContextA(&signer.hCryptProv, cspNameA, NULL, + PROV_RSA_FULL, 0); + ok(ret, "CryptAcquireContextA failed: %x\n", GetLastError()); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, + CMSG_CRYPT_RELEASE_CONTEXT_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL); + ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_VERSION_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (ret) + ok(value == CMSG_SIGNED_DATA_V3, "expected version 3, got %d\n", value); + /* Even for a CMS message, the signer can be retrieved.. */ + ret = CryptMsgGetParam(msg, CMSG_ENCODED_SIGNER, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + /* but the signer info, CMS signer info, and cert ID can't be. */ + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_SIGNER_CERT_ID_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + CryptMsgClose(msg); + + CryptReleaseContext(signer.hCryptProv, 0); + pCryptAcquireContextA(&signer.hCryptProv, cspNameA, MS_DEF_PROV_A, + PROV_RSA_FULL, CRYPT_DELETEKEYSET); +} + +static void test_signed_msg(void) +{ + test_signed_msg_open(); + test_signed_msg_update(); + test_signed_msg_encoding(); + test_signed_msg_get_param(); +} + +static CRYPT_DATA_BLOB b4 = { 0, NULL }; +static const struct update_accum a4 = { 1, &b4 }; + +static const BYTE bogusOIDContent[] = { +0x30,0x0f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x07,0xa0,0x02, +0x04,0x00 }; +static const BYTE bogusHashContent[] = { +0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a, +0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x00,0xd6,0xc0, +0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f }; + +static void test_decode_msg_update(void) +{ + HCRYPTMSG msg; + BOOL ret; + CMSG_STREAM_INFO streamInfo = { 0 }; + DWORD i; + struct update_accum accum = { 0, NULL }; + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + /* Update with a full message in a final update */ + ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* Can't update after a final update */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + /* Can't send a non-final update without streaming */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), + FALSE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "Expected CRYPT_E_MSG_ERROR, got %x\n", GetLastError()); + /* A subsequent final update succeeds */ + ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + if (!old_crypt32) + { + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo); + /* Updating a message that has a NULL stream callback fails */ + SetLastError(0xdeadbeef); + /* Crashes on some Win9x */ + ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), + FALSE); + todo_wine + ok(!ret && (GetLastError() == STATUS_ACCESS_VIOLATION || + GetLastError() == STATUS_ILLEGAL_INSTRUCTION /* WinME */), + "Expected STATUS_ACCESS_VIOLATION or STATUS_ILLEGAL_INSTRUCTION, got %x\n", + GetLastError()); + /* Changing the callback pointer after the fact yields the same error (so + * the message must copy the stream info, not just store a pointer to it) + */ + streamInfo.pfnStreamOutput = nop_stream_output; + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), + FALSE); + todo_wine + ok(!ret && (GetLastError() == STATUS_ACCESS_VIOLATION || + GetLastError() == STATUS_ILLEGAL_INSTRUCTION /* WinME */), + "Expected STATUS_ACCESS_VIOLATION or STATUS_ILLEGAL_INSTRUCTION, got %x\n", + GetLastError()); + CryptMsgClose(msg); + } + + /* Empty non-final updates are allowed when streaming.. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo); + ret = CryptMsgUpdate(msg, NULL, 0, FALSE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + /* but final updates aren't when not enough data has been received. */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + todo_wine + ok(!ret && GetLastError() == CRYPT_E_STREAM_INSUFFICIENT_DATA, + "Expected CRYPT_E_STREAM_INSUFFICIENT_DATA, got %x\n", GetLastError()); + CryptMsgClose(msg); + + /* Updating the message byte by byte is legal */ + streamInfo.pfnStreamOutput = accumulating_stream_output; + streamInfo.pvArg = &accum; + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo); + for (i = 0, ret = TRUE; ret && i < sizeof(dataEmptyContent); i++) + ret = CryptMsgUpdate(msg, &dataEmptyContent[i], 1, FALSE); + ok(ret, "CryptMsgUpdate failed on byte %d: %x\n", i, GetLastError()); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed on byte %d: %x\n", i, GetLastError()); + CryptMsgClose(msg); + todo_wine + check_updates("byte-by-byte empty content", &a4, &accum); + free_updates(&accum); + + /* Decoding bogus content fails in non-streaming mode.. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH, got %x\n", + GetLastError()); + CryptMsgClose(msg); + /* and as the final update in streaming mode.. */ + streamInfo.pfnStreamOutput = nop_stream_output; + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH, got %x\n", + GetLastError()); + CryptMsgClose(msg); + /* and even as a non-final update in streaming mode. */ + streamInfo.pfnStreamOutput = nop_stream_output; + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, &streamInfo); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE); + todo_wine + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH, got %x\n", + GetLastError()); + CryptMsgClose(msg); + + /* An empty message can be opened with undetermined type.. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), + TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + /* but decoding it as an explicitly typed message fails. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL, + NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, dataEmptyContent, sizeof(dataEmptyContent), + TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH, got %x\n", + GetLastError()); + CryptMsgClose(msg); + /* On the other hand, decoding the bare content of an empty message fails + * with unspecified type.. + */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, dataEmptyBareContent, + sizeof(dataEmptyBareContent), TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH, got %x\n", + GetLastError()); + CryptMsgClose(msg); + /* but succeeds with explicit type. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, 0, NULL, + NULL); + ret = CryptMsgUpdate(msg, dataEmptyBareContent, + sizeof(dataEmptyBareContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + /* Decoding valid content with an unsupported OID fails */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, bogusOIDContent, sizeof(bogusOIDContent), TRUE); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + CryptMsgClose(msg); + + /* Similarly, opening an empty hash with unspecified type succeeds.. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptMsgUpdate failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + /* while with specified type it fails. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* some Win9x */ || + GetLastError() == OSS_DATA_ERROR /* some Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH or OSS_DATA_ERROR, got %x\n", + GetLastError()); + CryptMsgClose(msg); + /* On the other hand, decoding the bare content of an empty hash message + * fails with unspecified type.. + */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, hashEmptyBareContent, + sizeof(hashEmptyBareContent), TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* some Win9x */ || + GetLastError() == OSS_DATA_ERROR /* some Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH or OSS_DATA_ERROR, got %x\n", + GetLastError()); + CryptMsgClose(msg); + /* but succeeds with explicit type. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + NULL); + ret = CryptMsgUpdate(msg, hashEmptyBareContent, + sizeof(hashEmptyBareContent), TRUE); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* win9x */), + "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + /* And again, opening a (non-empty) hash message with unspecified type + * succeeds.. + */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + /* while with specified type it fails.. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* some Win9x */ || + GetLastError() == OSS_DATA_ERROR /* some Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH or OSS_DATA_ERROR, got %x\n", + GetLastError()); + CryptMsgClose(msg); + /* and decoding the bare content of a non-empty hash message fails with + * unspecified type.. + */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, hashBareContent, sizeof(hashBareContent), TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_PDU_MISMATCH /* some Win9x */ || + GetLastError() == OSS_DATA_ERROR /* some Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_PDU_MISMATCH or OSS_DATA_ERROR, got %x\n", + GetLastError()); + CryptMsgClose(msg); + /* but succeeds with explicit type. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + NULL); + ret = CryptMsgUpdate(msg, hashBareContent, sizeof(hashBareContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError()); + CryptMsgClose(msg); + + /* Opening a (non-empty) hash message with unspecified type and a bogus + * hash value succeeds.. + */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, bogusHashContent, sizeof(bogusHashContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ret = CryptMsgUpdate(msg, signedContent, sizeof(signedContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, signedWithCertAndCrlBareContent, + sizeof(signedWithCertAndCrlBareContent), TRUE); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_BADTAG or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL, + NULL); + ret = CryptMsgUpdate(msg, signedWithCertAndCrlBareContent, + sizeof(signedWithCertAndCrlBareContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, 0, 0, + NULL, NULL); + /* The first update succeeds.. */ + ret = CryptMsgUpdate(msg, detachedSignedContent, + sizeof(detachedSignedContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + /* as does a second (probably to update the detached portion).. */ + ret = CryptMsgUpdate(msg, detachedSignedContent, + sizeof(detachedSignedContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + /* while a third fails. */ + ret = CryptMsgUpdate(msg, detachedSignedContent, + sizeof(detachedSignedContent), TRUE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "expected CRYPT_E_MSG_ERROR, got %08x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, 0, 0, NULL, &streamInfo); + ret = CryptMsgUpdate(msg, detachedSignedContent, sizeof(detachedSignedContent), FALSE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + ret = CryptMsgUpdate(msg, detachedSignedContent, sizeof(detachedSignedContent), FALSE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + + ret = CryptMsgUpdate(msg, detachedSignedContent, sizeof(detachedSignedContent), TRUE); + ok(!ret && GetLastError() == CRYPT_E_MSG_ERROR, + "expected CRYPT_E_MSG_ERROR, got %08x\n", GetLastError()); + CryptMsgClose(msg); +} + +static const BYTE hashParam[] = { 0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1, + 0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f }; + +static void compare_signer_info(const CMSG_SIGNER_INFO *got, + const CMSG_SIGNER_INFO *expected) +{ + ok(got->dwVersion == expected->dwVersion, "Expected version %d, got %d\n", + expected->dwVersion, got->dwVersion); + ok(got->Issuer.cbData == expected->Issuer.cbData, + "Expected issuer size %d, got %d\n", expected->Issuer.cbData, + got->Issuer.cbData); + ok(!memcmp(got->Issuer.pbData, got->Issuer.pbData, got->Issuer.cbData), + "Unexpected issuer\n"); + ok(got->SerialNumber.cbData == expected->SerialNumber.cbData, + "Expected serial number size %d, got %d\n", expected->SerialNumber.cbData, + got->SerialNumber.cbData); + ok(!memcmp(got->SerialNumber.pbData, got->SerialNumber.pbData, + got->SerialNumber.cbData), "Unexpected serial number\n"); + /* FIXME: check more things */ +} + +static void compare_cms_signer_info(const CMSG_CMS_SIGNER_INFO *got, + const CMSG_CMS_SIGNER_INFO *expected) +{ + ok(got->dwVersion == expected->dwVersion, "Expected version %d, got %d\n", + expected->dwVersion, got->dwVersion); + ok(got->SignerId.dwIdChoice == expected->SignerId.dwIdChoice, + "Expected id choice %d, got %d\n", expected->SignerId.dwIdChoice, + got->SignerId.dwIdChoice); + if (got->SignerId.dwIdChoice == expected->SignerId.dwIdChoice) + { + if (got->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) + { + ok(U(got->SignerId).IssuerSerialNumber.Issuer.cbData == + U(expected->SignerId).IssuerSerialNumber.Issuer.cbData, + "Expected issuer size %d, got %d\n", + U(expected->SignerId).IssuerSerialNumber.Issuer.cbData, + U(got->SignerId).IssuerSerialNumber.Issuer.cbData); + ok(!memcmp(U(got->SignerId).IssuerSerialNumber.Issuer.pbData, + U(expected->SignerId).IssuerSerialNumber.Issuer.pbData, + U(got->SignerId).IssuerSerialNumber.Issuer.cbData), + "Unexpected issuer\n"); + ok(U(got->SignerId).IssuerSerialNumber.SerialNumber.cbData == + U(expected->SignerId).IssuerSerialNumber.SerialNumber.cbData, + "Expected serial number size %d, got %d\n", + U(expected->SignerId).IssuerSerialNumber.SerialNumber.cbData, + U(got->SignerId).IssuerSerialNumber.SerialNumber.cbData); + ok(!memcmp(U(got->SignerId).IssuerSerialNumber.SerialNumber.pbData, + U(expected->SignerId).IssuerSerialNumber.SerialNumber.pbData, + U(got->SignerId).IssuerSerialNumber.SerialNumber.cbData), + "Unexpected serial number\n"); + } + else + { + ok(U(got->SignerId).KeyId.cbData == U(expected->SignerId).KeyId.cbData, + "expected key id size %d, got %d\n", + U(expected->SignerId).KeyId.cbData, U(got->SignerId).KeyId.cbData); + ok(!memcmp(U(expected->SignerId).KeyId.pbData, + U(got->SignerId).KeyId.pbData, U(got->SignerId).KeyId.cbData), + "unexpected key id\n"); + } + } + /* FIXME: check more things */ +} + +static const BYTE signedWithCertAndCrlComputedHash[] = { +0x08,0xd6,0xc0,0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26, +0x2f }; +static BYTE keyIdIssuer[] = { +0x30,0x13,0x31,0x11,0x30,0x0f,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37, +0x0a,0x07,0x01,0x04,0x01,0x01 }; + +static void test_decode_msg_get_param(void) +{ + HCRYPTMSG msg; + BOOL ret; + DWORD size = 0, value; + LPBYTE buf; + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %x\n", GetLastError()); + ret = CryptMsgUpdate(msg, dataContent, sizeof(dataContent), TRUE); + check_param("data content", msg, CMSG_CONTENT_PARAM, msgData, + sizeof(msgData)); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ret = CryptMsgUpdate(msg, hashEmptyContent, sizeof(hashEmptyContent), TRUE); + if (ret) + { + /* Crashes on some Win9x */ + check_param("empty hash content", msg, CMSG_CONTENT_PARAM, NULL, 0); + check_param("empty hash hash data", msg, CMSG_HASH_DATA_PARAM, NULL, 0); + check_param("empty hash computed hash", msg, CMSG_COMPUTED_HASH_PARAM, + emptyHashParam, sizeof(emptyHashParam)); + } + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ret = CryptMsgUpdate(msg, hashContent, sizeof(hashContent), TRUE); + check_param("hash content", msg, CMSG_CONTENT_PARAM, msgData, + sizeof(msgData)); + check_param("hash hash data", msg, CMSG_HASH_DATA_PARAM, hashParam, + sizeof(hashParam)); + check_param("hash computed hash", msg, CMSG_COMPUTED_HASH_PARAM, + hashParam, sizeof(hashParam)); + /* Curiously, on NT-like systems, getting the hash of index 1 succeeds, + * even though there's only one hash. + */ + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 1, NULL, &size); + ok(ret || GetLastError() == OSS_DATA_ERROR /* Win9x */, + "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (ret) + buf = CryptMemAlloc(size); + else + buf = NULL; + if (buf) + { + ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 1, buf, &size); + ok(size == sizeof(hashParam), "Unexpected size %d\n", size); + ok(!memcmp(buf, hashParam, size), "Unexpected value\n"); + CryptMemFree(buf); + } + check_param("hash inner OID", msg, CMSG_INNER_CONTENT_TYPE_PARAM, + (const BYTE *)szOID_RSA_data, strlen(szOID_RSA_data) + 1); + value = CMSG_HASHED_DATA_V0; + check_param("hash version", msg, CMSG_VERSION_PARAM, (const BYTE *)&value, + sizeof(value)); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ret = CryptMsgUpdate(msg, signedContent, sizeof(signedContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + check_param("signed content", msg, CMSG_CONTENT_PARAM, msgData, + sizeof(msgData)); + check_param("inner content", msg, CMSG_INNER_CONTENT_TYPE_PARAM, + (const BYTE *)szOID_RSA_data, strlen(szOID_RSA_data) + 1); + size = sizeof(value); + value = 2112; + ret = CryptMsgGetParam(msg, CMSG_SIGNER_COUNT_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(value == 1, "Expected 1 signer, got %d\n", value); + size = 0; + ret = CryptMsgGetParam(msg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (ret) + buf = CryptMemAlloc(size); + else + buf = NULL; + if (buf) + { + CMSG_SIGNER_INFO signer = { 0 }; + + signer.dwVersion = 1; + signer.Issuer.cbData = sizeof(encodedCommonName); + signer.Issuer.pbData = encodedCommonName; + signer.SerialNumber.cbData = sizeof(serialNum); + signer.SerialNumber.pbData = serialNum; + signer.HashAlgorithm.pszObjId = oid_rsa_md5; + CryptMsgGetParam(msg, CMSG_SIGNER_INFO_PARAM, 0, buf, &size); + compare_signer_info((CMSG_SIGNER_INFO *)buf, &signer); + CryptMemFree(buf); + } + /* Getting the CMS signer info of a PKCS7 message is possible. */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(ret || broken(GetLastError() == CRYPT_E_INVALID_MSG_TYPE /* Win9x */), + "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (ret) + buf = CryptMemAlloc(size); + else + buf = NULL; + if (buf) + { + CMSG_CMS_SIGNER_INFO signer = { 0 }; + + signer.dwVersion = 1; + signer.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + U(signer.SignerId).IssuerSerialNumber.Issuer.cbData = + sizeof(encodedCommonName); + U(signer.SignerId).IssuerSerialNumber.Issuer.pbData = encodedCommonName; + U(signer.SignerId).IssuerSerialNumber.SerialNumber.cbData = + sizeof(serialNum); + U(signer.SignerId).IssuerSerialNumber.SerialNumber.pbData = serialNum; + signer.HashAlgorithm.pszObjId = oid_rsa_md5; + CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, buf, &size); + compare_cms_signer_info((CMSG_CMS_SIGNER_INFO *)buf, &signer); + CryptMemFree(buf); + } + /* index is ignored when getting signer count */ + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_SIGNER_COUNT_PARAM, 1, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(value == 1, "Expected 1 signer, got %d\n", value); + ret = CryptMsgGetParam(msg, CMSG_CERT_COUNT_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(value == 0, "Expected 0 certs, got %d\n", value); + ret = CryptMsgGetParam(msg, CMSG_CRL_COUNT_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(value == 0, "Expected 0 CRLs, got %d\n", value); + CryptMsgClose(msg); + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL, + NULL); + ret = CryptMsgUpdate(msg, signedWithCertAndCrlBareContent, + sizeof(signedWithCertAndCrlBareContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + ret = CryptMsgGetParam(msg, CMSG_CERT_COUNT_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(value == 1, "Expected 1 cert, got %d\n", value); + check_param("cert", msg, CMSG_CERT_PARAM, cert, sizeof(cert)); + ret = CryptMsgGetParam(msg, CMSG_CRL_COUNT_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(value == 1, "Expected 1 CRL, got %d\n", value); + check_param("crl", msg, CMSG_CRL_PARAM, crl, sizeof(crl)); + check_param("signed with cert and CRL computed hash", msg, + CMSG_COMPUTED_HASH_PARAM, signedWithCertAndCrlComputedHash, + sizeof(signedWithCertAndCrlComputedHash)); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ret = CryptMsgUpdate(msg, signedKeyIdEmptyContent, + sizeof(signedKeyIdEmptyContent), TRUE); + if (!ret && GetLastError() == OSS_DATA_ERROR) + { + /* Subsequent tests crashes on some Win9x, so bail out */ + CryptMsgClose(msg); + return; + } + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + size = sizeof(value); + ret = CryptMsgGetParam(msg, CMSG_SIGNER_COUNT_PARAM, 0, &value, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(value == 1, "Expected 1 signer, got %d\n", value); + /* Getting the regular (non-CMS) signer info from a CMS message is also + * possible.. + */ + size = 0; + ret = CryptMsgGetParam(msg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (ret) + buf = CryptMemAlloc(size); + else + buf = NULL; + if (buf) + { + CMSG_SIGNER_INFO signer; + BYTE zero = 0; + + /* and here's the little oddity: for a CMS message using the key id + * variant of a SignerId, retrieving the CMSG_SIGNER_INFO param yields + * a signer with a zero (not empty) serial number, and whose issuer is + * an RDN with OID szOID_KEYID_RDN, value type CERT_RDN_OCTET_STRING, + * and value of the key id. + */ + signer.dwVersion = CMSG_SIGNED_DATA_V3; + signer.Issuer.cbData = sizeof(keyIdIssuer); + signer.Issuer.pbData = keyIdIssuer; + signer.SerialNumber.cbData = 1; + signer.SerialNumber.pbData = &zero; + CryptMsgGetParam(msg, CMSG_SIGNER_INFO_PARAM, 0, buf, &size); + compare_signer_info((CMSG_SIGNER_INFO *)buf, &signer); + CryptMemFree(buf); + } + size = 0; + ret = CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + if (ret) + buf = CryptMemAlloc(size); + else + buf = NULL; + if (buf) + { + CMSG_CMS_SIGNER_INFO signer = { 0 }; + + signer.dwVersion = CMSG_SIGNED_DATA_V3; + signer.SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER; + U(signer.SignerId).KeyId.cbData = sizeof(serialNum); + U(signer.SignerId).KeyId.pbData = serialNum; + signer.HashAlgorithm.pszObjId = oid_rsa_md5; + CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, buf, &size); + compare_cms_signer_info((CMSG_CMS_SIGNER_INFO *)buf, &signer); + CryptMemFree(buf); + } + CryptMsgClose(msg); +} + +static void test_decode_msg(void) +{ + test_decode_msg_update(); + test_decode_msg_get_param(); +} + +static BYTE aKey[] = { 0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf }; +/* aKey encoded as a X509_PUBLIC_KEY_INFO */ +static BYTE encodedPubKey[] = { +0x30,0x1f,0x30,0x0a,0x06,0x06,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x05,0x00,0x03, +0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c, +0x0d,0x0e,0x0f }; +/* a weird modulus encoded as RSA_CSP_PUBLICKEYBLOB */ +static BYTE mod_encoded[] = { + 0x30,0x10,0x02,0x09,0x00,0x80,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x03, + 0x01,0x00,0x01 }; + +static void test_msg_control(void) +{ + static char oid_rsa_rsa[] = szOID_RSA_RSA; + BOOL ret; + HCRYPTMSG msg; + DWORD i; + CERT_INFO certInfo = { 0 }; + CMSG_HASHED_ENCODE_INFO hashInfo = { 0 }; + CMSG_SIGNED_ENCODE_INFO signInfo = { sizeof(signInfo), 0 }; + CMSG_CTRL_DECRYPT_PARA decryptPara = { sizeof(decryptPara), 0 }; + + /* Crashes + ret = CryptMsgControl(NULL, 0, 0, NULL); + */ + + /* Data encode messages don't allow any sort of control.. */ + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_DATA, NULL, NULL, + NULL); + /* either with no prior update.. */ + for (i = 1; !old_crypt32 && (i <= CMSG_CTRL_ADD_CMS_SIGNER_INFO); i++) + { + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, i, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + /* or after an update. */ + for (i = 1; !old_crypt32 && (i <= CMSG_CTRL_ADD_CMS_SIGNER_INFO); i++) + { + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, i, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + CryptMsgClose(msg); + + /* Hash encode messages don't allow any sort of control.. */ + hashInfo.cbSize = sizeof(hashInfo); + hashInfo.HashAlgorithm.pszObjId = oid_rsa_md5; + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo, + NULL, NULL); + /* either with no prior update.. */ + for (i = 1; !old_crypt32 && (i <= CMSG_CTRL_ADD_CMS_SIGNER_INFO); i++) + { + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, i, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + /* or after an update. */ + for (i = 1; !old_crypt32 && (i <= CMSG_CTRL_ADD_CMS_SIGNER_INFO); i++) + { + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, i, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + CryptMsgClose(msg); + + /* Signed encode messages likewise don't allow any sort of control.. */ + signInfo.cbSize = sizeof(signInfo); + msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, &signInfo, + NULL, NULL); + /* either before an update.. */ + for (i = 1; !old_crypt32 && (i <= CMSG_CTRL_ADD_CMS_SIGNER_INFO); i++) + { + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, i, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + ret = CryptMsgUpdate(msg, NULL, 0, TRUE); + /* or after an update. */ + for (i = 1; !old_crypt32 && (i <= CMSG_CTRL_ADD_CMS_SIGNER_INFO); i++) + { + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, i, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + CryptMsgClose(msg); + + /* Decode messages behave a bit differently. */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + /* Bad control type */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, 0, NULL); + ok(!ret && GetLastError() == CRYPT_E_CONTROL_TYPE, + "Expected CRYPT_E_CONTROL_TYPE, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 1, 0, NULL); + ok(!ret && GetLastError() == CRYPT_E_CONTROL_TYPE, + "Expected CRYPT_E_CONTROL_TYPE, got %08x\n", GetLastError()); + /* Can't verify the hash of an indeterminate-type message */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + /* Crashes + ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, NULL); + */ + /* Can't decrypt an indeterminate-type message */ + ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + CryptMsgClose(msg); + + if (!old_crypt32) + { + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + NULL); + /* Can't verify the hash of an empty message */ + SetLastError(0xdeadbeef); + /* Crashes on some Win9x */ + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL); + todo_wine + ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", GetLastError()); + /* Crashes + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, NULL); + */ + /* Can't verify the signature of a hash message */ + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + CryptMsgUpdate(msg, hashEmptyBareContent, sizeof(hashEmptyBareContent), + TRUE); + /* Oddly enough, this fails, crashes on some Win9x */ + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL); + ok(!ret, "Expected failure\n"); + CryptMsgClose(msg); + } + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, 0, NULL, + NULL); + CryptMsgUpdate(msg, hashBareContent, sizeof(hashBareContent), TRUE); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL); + ok(ret, "CryptMsgControl failed: %08x\n", GetLastError()); + /* Can't decrypt an indeterminate-type message */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, 0, 0, + NULL, NULL); + /* Can't verify the hash of a detached message before it's been updated. */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + ret = CryptMsgUpdate(msg, detachedHashContent, sizeof(detachedHashContent), + TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + /* Still can't verify the hash of a detached message with the content + * of the detached hash given.. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL); + ok(!ret && GetLastError() == CRYPT_E_HASH_VALUE, + "Expected CRYPT_E_HASH_VALUE, got %08x\n", GetLastError()); + /* and giving the content of the message after attempting to verify the + * hash fails. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + todo_wine + ok(!ret && + (GetLastError() == NTE_BAD_HASH_STATE || + GetLastError() == NTE_BAD_ALGID || /* Win9x */ + GetLastError() == CRYPT_E_MSG_ERROR), /* Vista */ + "Expected NTE_BAD_HASH_STATE or NTE_BAD_ALGID or CRYPT_E_MSG_ERROR, " + "got %08x\n", GetLastError()); + CryptMsgClose(msg); + + /* Finally, verifying the hash of a detached message in the correct order: + * 1. Update with the detached hash message + * 2. Update with the content of the message + * 3. Verifying the hash of the message + * succeeds. + */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, 0, 0, + NULL, NULL); + ret = CryptMsgUpdate(msg, detachedHashContent, sizeof(detachedHashContent), + TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL); + ok(ret, "CryptMsgControl failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL, + NULL); + /* Can't verify the hash of a signed message */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + /* Can't decrypt a signed message */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_DECRYPT, &decryptPara); + ok(!ret && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + /* Crash + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, NULL); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + */ + CryptMsgUpdate(msg, signedWithCertBareContent, + sizeof(signedWithCertBareContent), TRUE); + /* With an empty cert info, the signer can't be found in the message (and + * the signature can't be verified. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(!ret && (GetLastError() == CRYPT_E_SIGNER_NOT_FOUND || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_SIGNER_NOT_FOUND or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + /* The cert info is expected to have an issuer, serial number, and public + * key info set. + */ + certInfo.SerialNumber.cbData = sizeof(serialNum); + certInfo.SerialNumber.pbData = serialNum; + certInfo.Issuer.cbData = sizeof(encodedCommonName); + certInfo.Issuer.pbData = encodedCommonName; + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(!ret && (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_ASN1_EOD or OSS_DATA_ERROR, got %08x\n", GetLastError()); + CryptMsgClose(msg); + /* This cert has a public key, but it's not in a usable form */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, CMSG_SIGNED, 0, NULL, + NULL); + ret = CryptMsgUpdate(msg, signedWithCertWithPubKeyBareContent, + sizeof(signedWithCertWithPubKeyBareContent), TRUE); + if (ret) + { + /* Crashes on some Win9x */ + /* Again, cert info needs to have a public key set */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_EOD || + GetLastError() == TRUST_E_NOSIGNATURE /* Vista */), + "Expected CRYPT_E_ASN1_EOD or TRUST_E_NOSIGNATURE, got %08x\n", GetLastError()); + /* The public key is supposed to be in encoded form.. */ + certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId = oid_rsa_rsa; + certInfo.SubjectPublicKeyInfo.PublicKey.cbData = sizeof(aKey); + certInfo.SubjectPublicKeyInfo.PublicKey.pbData = aKey; + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == TRUST_E_NOSIGNATURE /* Vista */), + "Expected CRYPT_E_ASN1_BADTAG or TRUST_E_NOSIGNATURE, got %08x\n", GetLastError()); + /* but not as a X509_PUBLIC_KEY_INFO.. */ + certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId = NULL; + certInfo.SubjectPublicKeyInfo.PublicKey.cbData = sizeof(encodedPubKey); + certInfo.SubjectPublicKeyInfo.PublicKey.pbData = encodedPubKey; + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(!ret && + (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == TRUST_E_NOSIGNATURE /* Vista */), + "Expected CRYPT_E_ASN1_BADTAG or TRUST_E_NOSIGNATURE, got %08x\n", GetLastError()); + /* This decodes successfully, but it doesn't match any key in the message */ + certInfo.SubjectPublicKeyInfo.PublicKey.cbData = sizeof(mod_encoded); + certInfo.SubjectPublicKeyInfo.PublicKey.pbData = mod_encoded; + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + /* In Wine's rsaenh, this fails to decode because the key length is too + * small. Not sure if that's a bug in rsaenh, so leaving todo_wine for + * now. + */ + todo_wine + ok(!ret && + (GetLastError() == NTE_BAD_SIGNATURE || + GetLastError() == TRUST_E_NOSIGNATURE /* Vista */), + "Expected NTE_BAD_SIGNATURE or TRUST_E_NOSIGNATURE, got %08x\n", GetLastError()); + } + CryptMsgClose(msg); + /* A message with no data doesn't have a valid signature */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ret = CryptMsgUpdate(msg, signedWithCertWithValidPubKeyEmptyContent, + sizeof(signedWithCertWithValidPubKeyEmptyContent), TRUE); + if (ret) + { + certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId = oid_rsa_rsa; + certInfo.SubjectPublicKeyInfo.PublicKey.cbData = sizeof(pubKey); + certInfo.SubjectPublicKeyInfo.PublicKey.pbData = pubKey; + SetLastError(0xdeadbeef); + /* Crashes on some Win9x */ + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(!ret && + (GetLastError() == NTE_BAD_SIGNATURE || + GetLastError() == TRUST_E_NOSIGNATURE /* Vista */), + "Expected NTE_BAD_SIGNATURE or TRUST_E_NOSIGNATURE, got %08x\n", GetLastError()); + } + CryptMsgClose(msg); + /* Finally, this succeeds */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + CryptMsgUpdate(msg, signedWithCertWithValidPubKeyContent, + sizeof(signedWithCertWithValidPubKeyContent), TRUE); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptMsgControl failed: %08x\n", GetLastError()); + CryptMsgClose(msg); + + /* Test verifying signature of a detached signed message */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, 0, 0, + NULL, NULL); + ret = CryptMsgUpdate(msg, detachedSignedContent, + sizeof(detachedSignedContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + /* Can't verify the sig without having updated the data */ + SetLastError(0xdeadbeef); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(!ret && (GetLastError() == NTE_BAD_SIGNATURE || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "expected NTE_BAD_SIGNATURE or OSS_DATA_ERROR, got %08x\n", + GetLastError()); + /* Now that the signature's been checked, can't do the final update */ + SetLastError(0xdeadbeef); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + todo_wine + ok((!ret && + (GetLastError() == NTE_BAD_HASH_STATE || + GetLastError() == NTE_BAD_ALGID || /* Win9x */ + GetLastError() == CRYPT_E_MSG_ERROR)) || /* Vista */ + broken(ret), /* Win9x */ + "expected NTE_BAD_HASH_STATE or NTE_BAD_ALGID or CRYPT_E_MSG_ERROR, " + "got %08x\n", GetLastError()); + CryptMsgClose(msg); + /* Updating with the detached portion of the message and the data of the + * the message allows the sig to be verified. + */ + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, 0, 0, + NULL, NULL); + ret = CryptMsgUpdate(msg, detachedSignedContent, + sizeof(detachedSignedContent), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError()); + ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, &certInfo); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptMsgControl failed: %08x\n", GetLastError()); + CryptMsgClose(msg); +} + +/* win9x has much less parameter checks and will crash on many tests + * this code is from test_signed_msg_update() + */ +static BOOL detect_nt(void) +{ + BOOL ret; + CMSG_SIGNER_ENCODE_INFO signer = { sizeof(signer), 0 }; + CERT_INFO certInfo = { 0 }; + + if (!pCryptAcquireContextW) + return FALSE; + + certInfo.SerialNumber.cbData = sizeof(serialNum); + certInfo.SerialNumber.pbData = serialNum; + certInfo.Issuer.cbData = sizeof(encodedCommonName); + certInfo.Issuer.pbData = encodedCommonName; + signer.pCertInfo = &certInfo; + signer.HashAlgorithm.pszObjId = oid_rsa_md5; + + ret = pCryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL, + PROV_RSA_FULL, CRYPT_NEWKEYSET); + if (!ret && GetLastError() == NTE_EXISTS) { + ret = pCryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL, + PROV_RSA_FULL, 0); + } + + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) return FALSE; + + /* cleanup */ + CryptReleaseContext(signer.hCryptProv, 0); + pCryptAcquireContextW(&signer.hCryptProv, cspNameW, NULL, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + + return TRUE; +} + +static void test_msg_get_and_verify_signer(void) +{ + BOOL ret; + HCRYPTMSG msg; + PCCERT_CONTEXT signer; + DWORD signerIndex; + HCERTSTORE store; + + /* Crash */ + if (0) + { + ret = CryptMsgGetAndVerifySigner(NULL, 0, NULL, 0, NULL, NULL); + ret = CryptMsgGetAndVerifySigner(NULL, 0, NULL, 0, NULL, &signerIndex); + } + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + /* An empty message has no signer */ + SetLastError(0xdeadbeef); + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, 0, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_TRUSTED_SIGNER, + "expected CRYPT_E_NO_TRUSTED_SIGNER, got 0x%08x\n", GetLastError()); + /* The signer is cleared on error */ + signer = (PCCERT_CONTEXT)0xdeadbeef; + SetLastError(0xdeadbeef); + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, 0, &signer, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_TRUSTED_SIGNER, + "expected CRYPT_E_NO_TRUSTED_SIGNER, got 0x%08x\n", GetLastError()); + ok(!signer, "expected signer to be NULL\n"); + /* The signer index is also cleared on error */ + signerIndex = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, 0, NULL, &signerIndex); + ok(!ret && GetLastError() == CRYPT_E_NO_TRUSTED_SIGNER, + "expected CRYPT_E_NO_TRUSTED_SIGNER, got 0x%08x\n", GetLastError()); + ok(!signerIndex, "expected 0, got %d\n", signerIndex); + /* An unsigned message (msgData isn't a signed message at all) + * likewise has no signer. + */ + CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE); + SetLastError(0xdeadbeef); + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, 0, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_TRUSTED_SIGNER, + "expected CRYPT_E_NO_TRUSTED_SIGNER, got 0x%08x\n", GetLastError()); + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + /* A "signed" message created with no signer cert likewise has no signer */ + ret = CryptMsgUpdate(msg, signedEmptyContent, sizeof(signedEmptyContent), TRUE); + if (ret) + { + /* Crashes on most Win9x */ + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, 0, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_TRUSTED_SIGNER, + "expected CRYPT_E_NO_TRUSTED_SIGNER, got 0x%08x\n", GetLastError()); + } + CryptMsgClose(msg); + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + /* A signed message succeeds, .. */ + CryptMsgUpdate(msg, signedWithCertWithValidPubKeyContent, + sizeof(signedWithCertWithValidPubKeyContent), TRUE); + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, 0, NULL, NULL); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptMsgGetAndVerifySigner failed: 0x%08x\n", GetLastError()); + /* the signer index can be retrieved, .. */ + signerIndex = 0xdeadbeef; + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, 0, NULL, &signerIndex); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptMsgGetAndVerifySigner failed: 0x%08x\n", GetLastError()); + if (ret) + ok(signerIndex == 0, "expected 0, got %d\n", signerIndex); + /* as can the signer cert. */ + signer = (PCCERT_CONTEXT)0xdeadbeef; + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, 0, &signer, NULL); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptMsgGetAndVerifySigner failed: 0x%08x\n", GetLastError()); + if (ret) + ok(signer != NULL && signer != (PCCERT_CONTEXT)0xdeadbeef, + "expected a valid signer\n"); + if (signer && signer != (PCCERT_CONTEXT)0xdeadbeef) + CertFreeCertificateContext(signer); + /* Specifying CMSG_USE_SIGNER_INDEX_FLAG and an invalid signer index fails + */ + signerIndex = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, CMSG_USE_SIGNER_INDEX_FLAG, + NULL, &signerIndex); + ok(!ret && GetLastError() == CRYPT_E_INVALID_INDEX, + "expected CRYPT_E_INVALID_INDEX, got 0x%08x\n", GetLastError()); + /* Specifying CMSG_TRUSTED_SIGNER_FLAG and no cert stores causes the + * message signer not to be found. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgGetAndVerifySigner(msg, 0, NULL, CMSG_TRUSTED_SIGNER_FLAG, + NULL, NULL); + ok(!ret && (GetLastError() == CRYPT_E_NO_TRUSTED_SIGNER || + broken(GetLastError() == OSS_DATA_ERROR /* Win9x */)), + "expected CRYPT_E_NO_TRUSTED_SIGNER, got 0x%08x\n", GetLastError()); + /* Specifying CMSG_TRUSTED_SIGNER_FLAG and an empty cert store also causes + * the message signer not to be found. + */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + SetLastError(0xdeadbeef); + ret = CryptMsgGetAndVerifySigner(msg, 1, &store, CMSG_TRUSTED_SIGNER_FLAG, + NULL, NULL); + ok(!ret && (GetLastError() == CRYPT_E_NO_TRUSTED_SIGNER || + broken(GetLastError() == OSS_DATA_ERROR /* Win9x */)), + "expected CRYPT_E_NO_TRUSTED_SIGNER, got 0x%08x\n", GetLastError()); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + v1CertWithValidPubKey, sizeof(v1CertWithValidPubKey), + CERT_STORE_ADD_ALWAYS, NULL); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win98 */), + "CertAddEncodedCertificateToStore failed: 0x%08x\n", GetLastError()); + /* Specifying CMSG_TRUSTED_SIGNER_FLAG with a cert store that contains + * the signer succeeds. + */ + SetLastError(0xdeadbeef); + ret = CryptMsgGetAndVerifySigner(msg, 1, &store, CMSG_TRUSTED_SIGNER_FLAG, + NULL, NULL); + ok(ret || broken(GetLastError() == OSS_DATA_ERROR /* Win9x */), + "CryptMsgGetAndVerifySigner failed: 0x%08x\n", GetLastError()); + CertCloseStore(store, 0); + CryptMsgClose(msg); +} + +START_TEST(msg) +{ + init_function_pointers(); + have_nt = detect_nt(); + if (!have_nt) + win_skip("Win9x crashes on some parameter checks\n"); + + /* I_CertUpdateStore can be used for verification if crypt32 is new enough */ + if (!GetProcAddress(GetModuleHandleA("crypt32.dll"), "I_CertUpdateStore")) + { + win_skip("Some tests will crash on older crypt32 implementations\n"); + old_crypt32 = TRUE; + } + + /* Basic parameter checking tests */ + test_msg_open_to_encode(); + test_msg_open_to_decode(); + test_msg_get_param(); + test_msg_close(); + test_msg_control(); + + /* Message-type specific tests */ + test_data_msg(); + test_hash_msg(); + test_signed_msg(); + test_decode_msg(); + + test_msg_get_and_verify_signer(); +} diff --git a/rostests/winetests/crypt32/object.c b/rostests/winetests/crypt32/object.c new file mode 100644 index 00000000000..211b5423e01 --- /dev/null +++ b/rostests/winetests/crypt32/object.c @@ -0,0 +1,235 @@ +/* + * Unit test suite for crypt32.dll's Crypt*Object functions + * + * Copyright 2008 Juan Lang + * + * 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 + */ +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static BOOL (WINAPI * pCryptQueryObject)(DWORD, const void *, DWORD, DWORD, + DWORD, DWORD *, DWORD *, DWORD *, HCERTSTORE *, HCRYPTMSG *, const void **); + +static BYTE bigCert[] = { +0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31, +0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f, +0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30, +0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13, +0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, +0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x07,0x30,0x02,0x06, +0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03, +0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01, +0xff,0x02,0x01,0x01 }; +static char bigCertBase64[] = +"MHoCAQEwAgYAMBUxEzARBgNVBAMTCkp1YW4gTGFuZwAwIhgPMTYwMTAxMDEwMDAw\n" +"MDBaGA8xNjAxMDEwMTAwMDAwMFowFTETMBEGA1UEAxMKSnVhbiBMYW5nADAHMAIG\n" +"AAMBAKMWMBQwEgYDVR0TAQH/BAgwBgEB/wIBAQ==\n"; +static WCHAR bigCertBase64W[] = { +'M','H','o','C','A','Q','E','w','A','g','Y','A','M','B','U','x','E','z','A', +'R','B','g','N','V','B','A','M','T','C','k','p','1','Y','W','4','g','T','G', +'F','u','Z','w','A','w','I','h','g','P','M','T','Y','w','M','T','A','x','M', +'D','E','w',',','D','A','w','\n', +'M','D','B','a','G','A','8','x','N','j','A','x','M','D','E','w','M','T','A', +'w','M','D','A','w','M','F','o','w','F','T','E','T','M','B','E','G','A','1', +'U','E','A','x','M','K','S','n','V','h','b','i','B','M','Y','W','5','n','A', +'D','A','H','M','A','I','G','\n', +'A','A','M','B','A','K','M','W','M','B','Q','w','E','g','Y','D','V','R','0', +'T','A','Q','H','/','B','A','g','w','B','g','E','B','/','w','I','B','A','Q', +'=','=','\n',0 }; +static BYTE signedWithCertWithValidPubKeyContent[] = { +0x30,0x82,0x01,0x89,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02, +0xa0,0x82,0x01,0x7a,0x30,0x82,0x01,0x76,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c, +0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01, +0x02,0x03,0x04,0xa0,0x81,0xd2,0x30,0x81,0xcf,0x02,0x01,0x01,0x30,0x02,0x06, +0x00,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a, +0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36, +0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f, +0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a, +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x4b,0x00,0x30,0x48, +0x02,0x41,0x00,0xe2,0x54,0x3a,0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb,0xb4, +0x53,0xe6,0x1f,0xe7,0x5d,0xf1,0x21,0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb, +0x65,0x97,0x03,0x86,0x60,0xde,0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc, +0x62,0x17,0xa9,0xcd,0x79,0x3f,0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30, +0x18,0x10,0x6b,0xd0,0x1c,0x10,0x79,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30, +0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06, +0x01,0x01,0xff,0x02,0x01,0x01,0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a, +0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75, +0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05, +0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a, +0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e, +0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64, +0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4, +0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static char signedWithCertWithValidPubKeyContentBase64[] = +"MIIBiQYJKoZIhvcNAQcCoIIBejCCAXYCAQExDjAMBggqhkiG9w0CBQUAMBMGCSqG" +"SIb3DQEHAaAGBAQBAgMEoIHSMIHPAgEBMAIGADAVMRMwEQYDVQQDEwpKdWFuIExh" +"bmcAMCIYDzE2MDEwMTAxMDAwMDAwWhgPMTYwMTAxMDEwMDAwMDBaMBUxEzARBgNV" +"BAMTCkp1YW4gTGFuZwAwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA4lQ6p4OxJxQ+" +"Wbu0U+Yf513xIWithVPbax7rZZcDhmDe82w4deBMYbu8YhepzXk/IU6Wyw7cYZQw" +"GBBr0BwQeQIDAQABoxYwFDASBgNVHRMBAf8ECDAGAQH/AgEBMXcwdQIBATAaMBUx" +"EzARBgNVBAMTCkp1YW4gTGFuZwACAQEwDAYIKoZIhvcNAgUFADAEBgAFAARAgaZw" +"s+9Z0WbRm8CatppebW9tDVmpqm7pLKAe7sJgvFm+P2MGjckRHSNkku8u/FcppK/g" +"7pMZOVHkRLgLKPSoDQ=="; +static WCHAR signedWithCertWithValidPubKeyContentBase64W[] = { +'M','I','I','B','i','Q','Y','J','K','o','Z','I','h','v','c','N','A','Q','c','C', +'o','I','I','B','e','j','C','C','A','X','Y','C','A','Q','E','x','D','j','A','M', +'B','g','g','q','h','k','i','G','9','w','0','C','B','Q','U','A','M','B','M','G', +'C','S','q','G','S','I','b','3','D','Q','E','H','A','a','A','G','B','A','Q','B', +'A','g','M','E','o','I','H','S','M','I','H','P','A','g','E','B','M','A','I','G', +'A','D','A','V','M','R','M','w','E','Q','Y','D','V','Q','Q','D','E','w','p','K', +'d','W','F','u','I','E','x','h','b','m','c','A','M','C','I','Y','D','z','E','2', +'M','D','E','w','M','T','A','x','M','D','A','w','M','D','A','w','W','h','g','P', +'M','T','Y','w','M','T','A','x','M','D','E','w','M','D','A','w','M','D','B','a', +'M','B','U','x','E','z','A','R','B','g','N','V','B','A','M','T','C','k','p','1', +'Y','W','4','g','T','G','F','u','Z','w','A','w','X','D','A','N','B','g','k','q', +'h','k','i','G','9','w','0','B','A','Q','E','F','A','A','N','L','A','D','B','I', +'A','k','E','A','4','l','Q','6','p','4','O','x','J','x','Q','+','W','b','u','0', +'U','+','Y','f','5','1','3','x','I','W','i','t','h','V','P','b','a','x','7','r', +'Z','Z','c','D','h','m','D','e','8','2','w','4','d','e','B','M','Y','b','u','8', +'Y','h','e','p','z','X','k','/','I','U','6','W','y','w','7','c','Y','Z','Q','w', +'G','B','B','r','0','B','w','Q','e','Q','I','D','A','Q','A','B','o','x','Y','w', +'F','D','A','S','B','g','N','V','H','R','M','B','A','f','8','E','C','D','A','G', +'A','Q','H','/','A','g','E','B','M','X','c','w','d','Q','I','B','A','T','A','a', +'M','B','U','x','E','z','A','R','B','g','N','V','B','A','M','T','C','k','p','1', +'Y','W','4','g','T','G','F','u','Z','w','A','C','A','Q','E','w','D','A','Y','I', +'K','o','Z','I','h','v','c','N','A','g','U','F','A','D','A','E','B','g','A','F', +'A','A','R','A','g','a','Z','w','s','+','9','Z','0','W','b','R','m','8','C','a', +'t','p','p','e','b','W','9','t','D','V','m','p','q','m','7','p','L','K','A','e', +'7','s','J','g','v','F','m','+','P','2','M','G','j','c','k','R','H','S','N','k', +'k','u','8','u','/','F','c','p','p','K','/','g','7','p','M','Z','O','V','H','k', +'R','L','g','L','K','P','S','o','D','Q','=','=',0 }; + +static void test_query_object(void) +{ + BOOL ret; + CRYPT_DATA_BLOB blob; + + /* Test the usual invalid arguments */ + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(0, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, + NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, NULL, 0, 0, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Test with a simple cert */ + blob.pbData = bigCert; + blob.cbData = sizeof(bigCert); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(ret, "CryptQueryObject failed: %08x\n", GetLastError()); + /* The same cert, base64-encoded */ + blob.pbData = (BYTE *)bigCertBase64; + blob.cbData = sizeof(bigCertBase64); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(ret, "CryptQueryObject failed: %08x\n", GetLastError()); + /* The same base64-encoded cert, restricting the format types */ + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + ok(ret, "CryptQueryObject failed: %08x\n", GetLastError()); + /* The same cert, base64-encoded but as a wide character string */ + blob.pbData = (BYTE *)bigCertBase64W; + blob.cbData = sizeof(bigCertBase64W); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + /* For brevity, not tested here, but tested on Windows: same failure + * (CRYPT_E_NO_MATCH) when the wide character base64-encoded cert + * is written to a file and queried. + */ + /* Test with a valid signed message */ + blob.pbData = signedWithCertWithValidPubKeyContent; + blob.cbData = sizeof(signedWithCertWithValidPubKeyContent); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(ret, "CryptQueryObject failed: %08x\n", GetLastError()); + blob.pbData = (BYTE *)signedWithCertWithValidPubKeyContentBase64; + blob.cbData = sizeof(signedWithCertWithValidPubKeyContentBase64); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(ret, "CryptQueryObject failed: %08x\n", GetLastError()); + /* A valid signed message, encoded as a wide character base64 string, can + * be queried successfully. + */ + blob.pbData = (BYTE *)signedWithCertWithValidPubKeyContentBase64W; + blob.cbData = sizeof(signedWithCertWithValidPubKeyContentBase64W); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(ret, "CryptQueryObject failed: %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NO_MATCH, + "expected CRYPT_E_NO_MATCH, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, + CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + ok(ret, "CryptQueryObject failed: %08x\n", GetLastError()); +} + +START_TEST(object) +{ + HMODULE mod = GetModuleHandleA("crypt32.dll"); + + pCryptQueryObject = (void *)GetProcAddress(mod, "CryptQueryObject"); + + if (!pCryptQueryObject) + { + win_skip("CryptQueryObject is not available\n"); + return; + } + + test_query_object(); +} diff --git a/rostests/winetests/crypt32/oid.c b/rostests/winetests/crypt32/oid.c new file mode 100644 index 00000000000..030a548ac1a --- /dev/null +++ b/rostests/winetests/crypt32/oid.c @@ -0,0 +1,603 @@ +/* + * Unit test suite for crypt32.dll's OID support functions. + * + * Copyright 2005 Juan Lang + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + + +static BOOL (WINAPI *pCryptEnumOIDInfo)(DWORD,DWORD,void*,PFN_CRYPT_ENUM_OID_INFO); + + +struct OIDToAlgID +{ + LPCSTR oid; + LPCSTR altOid; + DWORD algID; +}; + +static const struct OIDToAlgID oidToAlgID[] = { + { szOID_RSA_RSA, NULL, CALG_RSA_KEYX }, + { szOID_RSA_MD2RSA, NULL, CALG_MD2 }, + { szOID_RSA_MD4RSA, NULL, CALG_MD4 }, + { szOID_RSA_MD5RSA, NULL, CALG_MD5 }, + { szOID_RSA_SHA1RSA, NULL, CALG_SHA }, + { szOID_RSA_DH, NULL, CALG_DH_SF }, + { szOID_RSA_SMIMEalgESDH, NULL, CALG_DH_EPHEM }, + { szOID_RSA_SMIMEalgCMS3DESwrap, NULL, CALG_3DES }, + { szOID_RSA_SMIMEalgCMSRC2wrap, NULL, CALG_RC2 }, + { szOID_RSA_MD2, NULL, CALG_MD2 }, + { szOID_RSA_MD4, NULL, CALG_MD4 }, + { szOID_RSA_MD5, NULL, CALG_MD5 }, + { szOID_RSA_RC2CBC, NULL, CALG_RC2 }, + { szOID_RSA_RC4, NULL, CALG_RC4 }, + { szOID_RSA_DES_EDE3_CBC, NULL, CALG_3DES }, + { szOID_ANSI_X942_DH, NULL, CALG_DH_SF }, + { szOID_X957_DSA, NULL, CALG_DSS_SIGN }, + { szOID_X957_SHA1DSA, NULL, CALG_SHA }, + { szOID_OIWSEC_md4RSA, NULL, CALG_MD4 }, + { szOID_OIWSEC_md5RSA, NULL, CALG_MD5 }, + { szOID_OIWSEC_md4RSA2, NULL, CALG_MD4 }, + { szOID_OIWSEC_desCBC, NULL, CALG_DES }, + { szOID_OIWSEC_dsa, NULL, CALG_DSS_SIGN }, + { szOID_OIWSEC_shaDSA, NULL, CALG_SHA }, + { szOID_OIWSEC_shaRSA, NULL, CALG_SHA }, + { szOID_OIWSEC_sha, NULL, CALG_SHA }, + { szOID_OIWSEC_rsaXchg, NULL, CALG_RSA_KEYX }, + { szOID_OIWSEC_sha1, NULL, CALG_SHA }, + { szOID_OIWSEC_dsaSHA1, NULL, CALG_SHA }, + { szOID_OIWSEC_sha1RSASign, NULL, CALG_SHA }, + { szOID_OIWDIR_md2RSA, NULL, CALG_MD2 }, + { szOID_INFOSEC_mosaicUpdatedSig, NULL, CALG_SHA }, + { szOID_INFOSEC_mosaicKMandUpdSig, NULL, CALG_DSS_SIGN }, +}; + +static const struct OIDToAlgID algIDToOID[] = { + { szOID_RSA_RSA, NULL, CALG_RSA_KEYX }, + { szOID_RSA_SMIMEalgESDH, NULL, CALG_DH_EPHEM }, + { szOID_RSA_MD2, NULL, CALG_MD2 }, + { szOID_RSA_MD4, NULL, CALG_MD4 }, + { szOID_RSA_MD5, NULL, CALG_MD5 }, + { szOID_RSA_RC2CBC, NULL, CALG_RC2 }, + { szOID_RSA_RC4, NULL, CALG_RC4 }, + { szOID_RSA_DES_EDE3_CBC, NULL, CALG_3DES }, + { szOID_ANSI_X942_DH, NULL, CALG_DH_SF }, + { szOID_X957_DSA, szOID_OIWSEC_dsa /* some Win98 */, CALG_DSS_SIGN }, + { szOID_OIWSEC_desCBC, NULL, CALG_DES }, + { szOID_OIWSEC_sha1, NULL, CALG_SHA }, +}; + +static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 }; +static const WCHAR bogus2Dll[] = { 'b','o','g','u','s','2','.','d','l','l',0 }; + +static void testOIDToAlgID(void) +{ + int i; + DWORD alg; + + /* Test with a bogus one */ + alg = CertOIDToAlgId("1.2.3"); + ok(!alg, "Expected failure, got %d\n", alg); + + for (i = 0; i < sizeof(oidToAlgID) / sizeof(oidToAlgID[0]); i++) + { + alg = CertOIDToAlgId(oidToAlgID[i].oid); + /* Not all Windows installations support all these, so make sure it's + * at least not the wrong one. + */ + ok(alg == 0 || alg == oidToAlgID[i].algID, + "Expected %d, got %d\n", oidToAlgID[i].algID, alg); + } +} + +static void testAlgIDToOID(void) +{ + int i; + LPCSTR oid; + + /* Test with a bogus one */ + SetLastError(0xdeadbeef); + oid = CertAlgIdToOID(ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | 80); + ok(!oid && GetLastError() == 0xdeadbeef, + "Didn't expect last error (%08x) to be set\n", GetLastError()); + for (i = 0; i < sizeof(algIDToOID) / sizeof(algIDToOID[0]); i++) + { + oid = CertAlgIdToOID(algIDToOID[i].algID); + /* Allow failure, not every version of Windows supports every algo */ + if (oid) + { + if (strcmp(oid, algIDToOID[i].oid)) + { + if (algIDToOID[i].altOid) + ok(!strcmp(oid, algIDToOID[i].altOid), + "Expected %s or %s, got %s\n", algIDToOID[i].oid, + algIDToOID[i].altOid, oid); + else + { + /* No need to rerun the test, we already know it failed. */ + ok(0, "Expected %s, got %s\n", algIDToOID[i].oid, oid); + } + } + else + { + /* No need to rerun the test, we already know it succeeded. */ + ok(1, "Expected %s, got %s\n", algIDToOID[i].oid, oid); + } + } + } +} + +static void test_oidFunctionSet(void) +{ + HCRYPTOIDFUNCSET set1, set2; + BOOL ret; + LPWSTR buf = NULL; + DWORD size; + + /* This crashes + set = CryptInitOIDFunctionSet(NULL, 0); + */ + + /* The name doesn't mean much */ + set1 = CryptInitOIDFunctionSet("funky", 0); + ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); + if (set1) + { + /* These crash + ret = CryptGetDefaultOIDDllList(NULL, 0, NULL, NULL); + ret = CryptGetDefaultOIDDllList(NULL, 0, NULL, &size); + */ + size = 0; + ret = CryptGetDefaultOIDDllList(set1, 0, NULL, &size); + ok(ret, "CryptGetDefaultOIDDllList failed: %08x\n", GetLastError()); + if (ret) + { + buf = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + if (buf) + { + ret = CryptGetDefaultOIDDllList(set1, 0, buf, &size); + ok(ret, "CryptGetDefaultOIDDllList failed: %08x\n", + GetLastError()); + ok(!*buf, "Expected empty DLL list\n"); + HeapFree(GetProcessHeap(), 0, buf); + } + } + } + + /* MSDN says flags must be 0, but it's not checked */ + set1 = CryptInitOIDFunctionSet("", 1); + ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); + set2 = CryptInitOIDFunctionSet("", 0); + ok(set2 != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); + /* There isn't a free function, so there must be only one set per name to + * limit leaks. (I guess the sets are freed when crypt32 is unloaded.) + */ + ok(set1 == set2, "Expected identical sets\n"); + if (set1) + { + /* The empty name function set used here seems to correspond to + * DEFAULT. + */ + } + + /* There's no installed function for a built-in encoding. */ + set1 = CryptInitOIDFunctionSet("CryptDllEncodeObject", 0); + ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); + if (set1) + { + void *funcAddr; + HCRYPTOIDFUNCADDR hFuncAddr; + + ret = CryptGetOIDFunctionAddress(set1, X509_ASN_ENCODING, X509_CERT, 0, + &funcAddr, &hFuncAddr); + ok((!ret && GetLastError() == ERROR_FILE_NOT_FOUND) || + broken(ret) /* some Win98 */, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + } +} + +typedef int (*funcY)(int); + +static int funky(int x) +{ + return x; +} + +static void test_installOIDFunctionAddress(void) +{ + BOOL ret; + CRYPT_OID_FUNC_ENTRY entry = { CRYPT_DEFAULT_OID, funky }; + HCRYPTOIDFUNCSET set; + + /* This crashes + ret = CryptInstallOIDFunctionAddress(NULL, 0, NULL, 0, NULL, 0); + */ + + /* Installing zero functions should work */ + SetLastError(0xdeadbeef); + ret = CryptInstallOIDFunctionAddress(NULL, 0, "CryptDllEncodeObject", 0, + NULL, 0); + ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08x\n", + GetLastError()); + + /* The function name doesn't much matter */ + SetLastError(0xdeadbeef); + ret = CryptInstallOIDFunctionAddress(NULL, 0, "OhSoFunky", 0, NULL, 0); + ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08x\n", + GetLastError()); + SetLastError(0xdeadbeef); + entry.pszOID = X509_CERT; + ret = CryptInstallOIDFunctionAddress(NULL, 0, "OhSoFunky", 1, &entry, 0); + ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08x\n", + GetLastError()); + set = CryptInitOIDFunctionSet("OhSoFunky", 0); + ok(set != 0, "CryptInitOIDFunctionSet failed: %08x\n", GetLastError()); + if (set) + { + funcY funcAddr = NULL; + HCRYPTOIDFUNCADDR hFuncAddr = NULL; + + /* This crashes + ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, 0, 0, NULL, + NULL); + */ + ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, 0, 0, + (void **)&funcAddr, &hFuncAddr); + ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == E_INVALIDARG /* some Win98 */), + "Expected ERROR_FILE_NOT_FOUND or E_INVALIDARG, got %d\n", + GetLastError()); + ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, X509_CERT, 0, + (void **)&funcAddr, &hFuncAddr); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ret = CryptGetOIDFunctionAddress(set, 0, X509_CERT, 0, + (void **)&funcAddr, &hFuncAddr); + ok(ret, "CryptGetOIDFunctionAddress failed: %d\n", GetLastError()); + if (funcAddr) + { + int y = funcAddr(0xabadc0da); + + ok(y == 0xabadc0da, "Unexpected return (%d) from function\n", y); + CryptFreeOIDFunctionAddress(hFuncAddr, 0); + } + } +} + +static void test_registerOIDFunction(void) +{ + BOOL ret; + + /* oddly, this succeeds under WinXP; the function name key is merely + * omitted. This may be a side effect of the registry code, I don't know. + * I don't check it because I doubt anyone would depend on it. + ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL, + "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); + */ + /* On windows XP, GetLastError is incorrectly being set with an HRESULT, + * E_INVALIDARG + */ + ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll, + NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG: %d\n", GetLastError()); + /* This has no effect, but "succeeds" on XP */ + ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", + "1.2.3.4.5.6.7.8.9.10", NULL, NULL); + ok(ret, "Expected pseudo-success, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject", + "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + skip("Need admin rights\n"); + return; + } + ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); + ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject", + "1.2.3.4.5.6.7.8.9.10"); + ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); + ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus", + "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); + ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); + ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus", + "1.2.3.4.5.6.7.8.9.10"); + ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); + /* Unwanted Cryptography\OID\EncodingType 1\bogus\ will still be there */ + ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, + "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 1\\bogus"), + "Could not delete bogus key\n"); + /* Shouldn't have effect but registry keys are created */ + ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject", + "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); + ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); + ret = CryptUnregisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject", + "1.2.3.4.5.6.7.8.9.10"); + ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); + /* Check with bogus encoding type. Registry keys are still created */ + ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject", + "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); + ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); + ret = CryptUnregisterOIDFunction(0, "CryptDllEncodeObject", + "1.2.3.4.5.6.7.8.9.10"); + ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); + /* Unwanted Cryptography\OID\EncodingType 0\CryptDllEncodeObject\ + * will still be there + */ + ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, + "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllEncodeObject"), + "Could not delete CryptDllEncodeObject key\n"); + /* This is written with value 3 verbatim. Thus, the encoding type isn't + * (for now) treated as a mask. Registry keys are created. + */ + ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject", + "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL); + ok(ret, "CryptRegisterOIDFunction failed: %d\n", GetLastError()); + ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject", + "1.2.3.4.5.6.7.8.9.10"); + ok(ret, "CryptUnregisterOIDFunction failed: %d\n", GetLastError()); + /* Unwanted Cryptography\OID\EncodingType 3\CryptDllEncodeObject + * will still be there. + */ + ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, + "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 3\\CryptDllEncodeObject"), + "Could not delete CryptDllEncodeObject key\n"); + ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, + "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 3"), + "Could not delete 'EncodingType 3' key\n"); +} + +static void test_registerDefaultOIDFunction(void) +{ + static const char fmt[] = + "Software\\Microsoft\\Cryptography\\OID\\EncodingType %d\\%s\\DEFAULT"; + static const char func[] = "CertDllOpenStoreProv"; + char buf[MAX_PATH]; + BOOL ret; + LSTATUS rc; + HKEY key; + + ret = CryptRegisterDefaultOIDFunction(0, NULL, 0, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* This succeeds on WinXP, although the bogus entry is unusable. + ret = CryptRegisterDefaultOIDFunction(0, NULL, 0, bogusDll); + */ + /* Register one at index 0 */ + SetLastError(0xdeadbeef); + ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 0, + bogusDll); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + skip("Need admin rights\n"); + return; + } + ok(ret, "CryptRegisterDefaultOIDFunction failed: %08x\n", GetLastError()); + /* Reregistering should fail */ + ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 0, + bogusDll); + ok(!ret && GetLastError() == ERROR_FILE_EXISTS, + "Expected ERROR_FILE_EXISTS, got %08x\n", GetLastError()); + /* Registering the same one at index 1 should also fail */ + ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 1, + bogusDll); + ok(!ret && GetLastError() == ERROR_FILE_EXISTS, + "Expected ERROR_FILE_EXISTS, got %08x\n", GetLastError()); + /* Registering a different one at index 1 succeeds */ + ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 1, + bogus2Dll); + ok(ret, "CryptRegisterDefaultOIDFunction failed: %08x\n", GetLastError()); + sprintf(buf, fmt, 0, func); + rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, buf, &key); + ok(rc == 0, "Expected key to exist, RegOpenKeyA failed: %d\n", rc); + if (rc == 0) + { + static const CHAR dllA[] = "Dll"; + static const CHAR bogusDll_A[] = "bogus.dll"; + static const CHAR bogus2Dll_A[] = "bogus2.dll"; + CHAR dllBuf[MAX_PATH]; + DWORD type, size; + LPSTR ptr; + + size = sizeof(dllBuf) / sizeof(dllBuf[0]); + rc = RegQueryValueExA(key, dllA, NULL, &type, (LPBYTE)dllBuf, &size); + ok(rc == 0, + "Expected Dll value to exist, RegQueryValueExA failed: %d\n", rc); + ok(type == REG_MULTI_SZ, "Expected type REG_MULTI_SZ, got %d\n", type); + /* bogusDll was registered first, so that should be first */ + ptr = dllBuf; + ok(!lstrcmpiA(ptr, bogusDll_A), "Unexpected dll\n"); + ptr += lstrlenA(ptr) + 1; + ok(!lstrcmpiA(ptr, bogus2Dll_A), "Unexpected dll\n"); + RegCloseKey(key); + } + /* Unregister both of them */ + ret = CryptUnregisterDefaultOIDFunction(0, "CertDllOpenStoreProv", + bogusDll); + ok(ret, "CryptUnregisterDefaultOIDFunction failed: %08x\n", + GetLastError()); + ret = CryptUnregisterDefaultOIDFunction(0, "CertDllOpenStoreProv", + bogus2Dll); + ok(ret, "CryptUnregisterDefaultOIDFunction failed: %08x\n", + GetLastError()); + /* Now that they're both unregistered, unregistering should fail */ + ret = CryptUnregisterDefaultOIDFunction(0, "CertDllOpenStoreProv", + bogusDll); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + /* Repeat a few tests on the normal encoding type */ + ret = CryptRegisterDefaultOIDFunction(X509_ASN_ENCODING, + "CertDllOpenStoreProv", 0, bogusDll); + ret = CryptUnregisterDefaultOIDFunction(X509_ASN_ENCODING, + "CertDllOpenStoreProv", bogusDll); + ok(ret, "CryptUnregisterDefaultOIDFunction failed\n"); + ret = CryptUnregisterDefaultOIDFunction(X509_ASN_ENCODING, + "CertDllOpenStoreProv", bogusDll); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); +} + +static void test_getDefaultOIDFunctionAddress(void) +{ + BOOL ret; + HCRYPTOIDFUNCSET set; + void *funcAddr; + HCRYPTOIDFUNCADDR hFuncAddr; + + /* Crash + ret = CryptGetDefaultOIDFunctionAddress(0, 0, NULL, 0, NULL, NULL); + ret = CryptGetDefaultOIDFunctionAddress(0, 0, NULL, 0, &funcAddr, NULL); + ret = CryptGetDefaultOIDFunctionAddress(0, 0, NULL, 0, NULL, &hFuncAddr); + ret = CryptGetDefaultOIDFunctionAddress(0, 0, NULL, 0, &funcAddr, + &hFuncAddr); + */ + set = CryptInitOIDFunctionSet("CertDllOpenStoreProv", 0); + ok(set != 0, "CryptInitOIDFunctionSet failed: %d\n", GetLastError()); + /* This crashes if hFuncAddr is not 0 to begin with */ + hFuncAddr = 0; + ret = CryptGetDefaultOIDFunctionAddress(set, 0, NULL, 0, &funcAddr, + &hFuncAddr); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + /* This fails with the normal encoding too, so built-in functions aren't + * returned. + */ + ret = CryptGetDefaultOIDFunctionAddress(set, X509_ASN_ENCODING, NULL, 0, + &funcAddr, &hFuncAddr); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + /* Even with a registered dll, this fails (since the dll doesn't exist) */ + SetLastError(0xdeadbeef); + ret = CryptRegisterDefaultOIDFunction(0, "CertDllOpenStoreProv", 0, + bogusDll); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + skip("Need admin rights\n"); + else + ok(ret, "CryptRegisterDefaultOIDFunction failed: %08x\n", GetLastError()); + ret = CryptGetDefaultOIDFunctionAddress(set, 0, NULL, 0, &funcAddr, + &hFuncAddr); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + CryptUnregisterDefaultOIDFunction(0, "CertDllOpenStoreProv", bogusDll); +} + +static BOOL WINAPI countOidInfo(PCCRYPT_OID_INFO pInfo, void *pvArg) +{ + (*(DWORD *)pvArg)++; + return TRUE; +} + +static BOOL WINAPI noOidInfo(PCCRYPT_OID_INFO pInfo, void *pvArg) +{ + return FALSE; +} + +static void test_enumOIDInfo(void) +{ + BOOL ret; + DWORD count = 0; + + if (!pCryptEnumOIDInfo) + { + win_skip("CryptEnumOIDInfo() is not available\n"); + return; + } + + /* This crashes + ret = pCryptEnumOIDInfo(7, 0, NULL, NULL); + */ + + /* Silly tests, check that more than one thing is enumerated */ + ret = pCryptEnumOIDInfo(0, 0, &count, countOidInfo); + ok(ret && count > 0, "Expected more than item enumerated\n"); + ret = pCryptEnumOIDInfo(0, 0, NULL, noOidInfo); + ok(!ret, "Expected FALSE\n"); +} + +static void test_findOIDInfo(void) +{ + static WCHAR sha1[] = { 's','h','a','1',0 }; + static CHAR oid_rsa_md5[] = szOID_RSA_MD5; + ALG_ID alg = CALG_SHA1; + ALG_ID algs[2] = { CALG_MD5, CALG_RSA_SIGN }; + PCCRYPT_OID_INFO info; + + info = CryptFindOIDInfo(0, NULL, 0); + ok(info == NULL, "Expected NULL\n"); + info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid_rsa_md5, 0); + ok(info != NULL, "Expected to find szOID_RSA_MD5\n"); + if (info) + { + ok(!strcmp(info->pszOID, szOID_RSA_MD5), "Expected %s, got %s\n", + szOID_RSA_MD5, info->pszOID); + ok(U(*info).Algid == CALG_MD5, "Expected CALG_MD5, got %d\n", + U(*info).Algid); + } + info = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, sha1, 0); + ok(info != NULL, "Expected to find sha1\n"); + if (info) + { + ok(!strcmp(info->pszOID, szOID_OIWSEC_sha1), "Expected %s, got %s\n", + szOID_OIWSEC_sha1, info->pszOID); + ok(U(*info).Algid == CALG_SHA1, "Expected CALG_SHA1, got %d\n", + U(*info).Algid); + } + info = CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY, &alg, 0); + ok(info != NULL, "Expected to find sha1\n"); + if (info) + { + ok(!strcmp(info->pszOID, szOID_OIWSEC_sha1), "Expected %s, got %s\n", + szOID_OIWSEC_sha1, info->pszOID); + ok(U(*info).Algid == CALG_SHA1, "Expected CALG_SHA1, got %d\n", + U(*info).Algid); + } + info = CryptFindOIDInfo(CRYPT_OID_INFO_SIGN_KEY, algs, 0); + ok(info != NULL, "Expected to find md5RSA\n"); + if (info) + { + ok(!strcmp(info->pszOID, szOID_RSA_MD5RSA), "Expected %s, got %s\n", + szOID_RSA_MD5RSA, info->pszOID); + ok(U(*info).Algid == CALG_MD5, "Expected CALG_MD5, got %d\n", + U(*info).Algid); + } +} + +START_TEST(oid) +{ + HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll"); + pCryptEnumOIDInfo = (void*)GetProcAddress(hCrypt32, "CryptEnumOIDInfo"); + + testOIDToAlgID(); + testAlgIDToOID(); + test_enumOIDInfo(); + test_findOIDInfo(); + test_oidFunctionSet(); + test_installOIDFunctionAddress(); + test_registerOIDFunction(); + test_registerDefaultOIDFunction(); + test_getDefaultOIDFunctionAddress(); +} diff --git a/rostests/winetests/crypt32/protectdata.c b/rostests/winetests/crypt32/protectdata.c new file mode 100644 index 00000000000..91bad8e43c6 --- /dev/null +++ b/rostests/winetests/crypt32/protectdata.c @@ -0,0 +1,264 @@ +/* + * Unit test suite for crypt32.dll's CryptProtectData/CryptUnprotectData + * + * Copyright 2005 Kees Cook + * + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static BOOL (WINAPI *pCryptProtectData)(DATA_BLOB*,LPCWSTR,DATA_BLOB*,PVOID,CRYPTPROTECT_PROMPTSTRUCT*,DWORD,DATA_BLOB*); +static BOOL (WINAPI *pCryptUnprotectData)(DATA_BLOB*,LPWSTR*,DATA_BLOB*,PVOID,CRYPTPROTECT_PROMPTSTRUCT*,DWORD,DATA_BLOB*); + +static char secret[] = "I am a super secret string that no one can see!"; +static char secret2[] = "I am a super secret string indescribable string"; +static char key[] = "Wibble wibble wibble"; +static const WCHAR desc[] = {'U','l','t','r','a',' ','s','e','c','r','e','t',' ','t','e','s','t',' ','m','e','s','s','a','g','e',0}; +static BOOL protected = FALSE; /* if true, the unprotect tests can run */ +static DATA_BLOB cipher; +static DATA_BLOB cipher_entropy; +static DATA_BLOB cipher_no_desc; + +static void test_cryptprotectdata(void) +{ + LONG r; + DATA_BLOB plain; + DATA_BLOB entropy; + + plain.pbData=(void*)secret; + plain.cbData=strlen(secret)+1; + + entropy.pbData=(void*)key; + entropy.cbData=strlen(key)+1; + + SetLastError(0xDEADBEEF); + protected = pCryptProtectData(NULL,desc,NULL,NULL,NULL,0,&cipher); + ok(!protected, "Encrypting without plain data source.\n"); + r = GetLastError(); + ok(r == ERROR_INVALID_PARAMETER, "Wrong (%u) GetLastError seen\n",r); + + SetLastError(0xDEADBEEF); + protected = pCryptProtectData(&plain,desc,NULL,NULL,NULL,0,NULL); + ok(!protected, "Encrypting without cipher destination.\n"); + r = GetLastError(); + ok(r == ERROR_INVALID_PARAMETER, "Wrong (%u) GetLastError seen\n",r); + + cipher.pbData=NULL; + cipher.cbData=0; + + /* without entropy */ + SetLastError(0xDEADBEEF); + protected = pCryptProtectData(&plain,desc,NULL,NULL,NULL,0,&cipher); + ok(protected || + broken(!protected), /* Win9x/NT4 */ + "Encrypting without entropy.\n"); + if (protected) + { + r = GetLastError(); + ok(r == ERROR_SUCCESS || + r == ERROR_IO_PENDING, /* win2k */ + "Expected ERROR_SUCCESS or ERROR_IO_PENDING, got %d\n",r); + } + + cipher_entropy.pbData=NULL; + cipher_entropy.cbData=0; + + /* with entropy */ + SetLastError(0xDEADBEEF); + protected = pCryptProtectData(&plain,desc,&entropy,NULL,NULL,0,&cipher_entropy); + ok(protected || + broken(!protected), /* Win9x/NT4 */ + "Encrypting with entropy.\n"); + + cipher_no_desc.pbData=NULL; + cipher_no_desc.cbData=0; + + /* with entropy but no description */ + plain.pbData=(void*)secret2; + plain.cbData=strlen(secret2)+1; + SetLastError(0xDEADBEEF); + protected = pCryptProtectData(&plain,NULL,&entropy,NULL,NULL,0,&cipher_no_desc); + if (!protected) + { + /* fails in win2k */ + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } +} + +static void test_cryptunprotectdata(void) +{ + LONG r; + DATA_BLOB plain; + DATA_BLOB entropy; + BOOL okay; + WCHAR * data_desc; + + entropy.pbData=(void*)key; + entropy.cbData=strlen(key)+1; + + /* fails in win2k */ + if (!protected) + { + skip("CryptProtectData failed to run\n"); + return; + } + + plain.pbData=NULL; + plain.cbData=0; + + SetLastError(0xDEADBEEF); + okay = pCryptUnprotectData(&cipher,NULL,NULL,NULL,NULL,0,NULL); + ok(!okay,"Decrypting without destination\n"); + r = GetLastError(); + ok(r == ERROR_INVALID_PARAMETER, "Wrong (%u) GetLastError seen\n",r); + + SetLastError(0xDEADBEEF); + okay = pCryptUnprotectData(NULL,NULL,NULL,NULL,NULL,0,&plain); + ok(!okay,"Decrypting without source\n"); + r = GetLastError(); + ok(r == ERROR_INVALID_PARAMETER, "Wrong (%u) GetLastError seen\n",r); + + plain.pbData=NULL; + plain.cbData=0; + + SetLastError(0xDEADBEEF); + okay = pCryptUnprotectData(&cipher_entropy,NULL,NULL,NULL,NULL,0,&plain); + ok(!okay,"Decrypting without needed entropy\n"); + r = GetLastError(); + ok(r == ERROR_INVALID_DATA, "Wrong (%u) GetLastError seen\n", r); + + plain.pbData=NULL; + plain.cbData=0; + data_desc=NULL; + + /* without entropy */ + SetLastError(0xDEADBEEF); + okay = pCryptUnprotectData(&cipher,&data_desc,NULL,NULL,NULL,0,&plain); + ok(okay,"Decrypting without entropy\n"); + + ok(plain.pbData!=NULL,"Plain DATA_BLOB missing data\n"); + ok(plain.cbData==strlen(secret)+1,"Plain DATA_BLOB wrong length\n"); + ok(!strcmp((const char*)plain.pbData,secret),"Plain does not match secret\n"); + ok(data_desc!=NULL,"Description not allocated\n"); + ok(!lstrcmpW(data_desc,desc),"Description does not match\n"); + + LocalFree(plain.pbData); + LocalFree(data_desc); + + plain.pbData=NULL; + plain.cbData=0; + data_desc=NULL; + + /* with wrong entropy */ + SetLastError(0xDEADBEEF); + okay = pCryptUnprotectData(&cipher_entropy,&data_desc,&cipher_entropy,NULL,NULL,0,&plain); + ok(!okay,"Decrypting with wrong entropy\n"); + r = GetLastError(); + ok(r == ERROR_INVALID_DATA, "Wrong (%u) GetLastError seen\n",r); + + /* with entropy */ + SetLastError(0xDEADBEEF); + okay = pCryptUnprotectData(&cipher_entropy,&data_desc,&entropy,NULL,NULL,0,&plain); + ok(okay,"Decrypting with entropy\n"); + + ok(plain.pbData!=NULL,"Plain DATA_BLOB missing data\n"); + ok(plain.cbData==strlen(secret)+1,"Plain DATA_BLOB wrong length\n"); + ok(!strcmp((const char*)plain.pbData,secret),"Plain does not match secret\n"); + ok(data_desc!=NULL,"Description not allocated\n"); + ok(!lstrcmpW(data_desc,desc),"Description does not match\n"); + + LocalFree(plain.pbData); + LocalFree(data_desc); + + plain.pbData=NULL; + plain.cbData=0; + data_desc=NULL; + + /* with entropy but no description */ + SetLastError(0xDEADBEEF); + okay = pCryptUnprotectData(&cipher_no_desc,&data_desc,&entropy,NULL,NULL,0,&plain); + ok(okay,"Decrypting with entropy and no description\n"); + + ok(plain.pbData!=NULL,"Plain DATA_BLOB missing data\n"); + ok(plain.cbData==strlen(secret2)+1,"Plain DATA_BLOB wrong length\n"); + ok(!strcmp((const char*)plain.pbData,secret2),"Plain does not match secret\n"); + ok(data_desc!=NULL,"Description not allocated\n"); + ok(data_desc[0]=='\0',"Description not empty\n"); + + LocalFree(data_desc); + LocalFree(plain.pbData); + + plain.pbData=NULL; + plain.cbData=0; +} + +static void test_simpleroundtrip(const char *plaintext) +{ + DATA_BLOB input; + DATA_BLOB encrypted; + DATA_BLOB output; + int res; + WCHAR emptyW[1]; + + emptyW[0] = 0; + input.pbData = (unsigned char *)plaintext; + input.cbData = strlen(plaintext); + res = pCryptProtectData(&input, emptyW, NULL, NULL, NULL, 0, &encrypted); + ok(res != 0 || broken(!res), "can't protect\n"); + if (!res) + { + /* Fails on Win9x, NT4 */ + win_skip("CryptProtectData failed\n"); + return; + } + + res = pCryptUnprotectData(&encrypted, NULL, NULL, NULL, NULL, 0, &output); + ok(res != 0, "can't unprotect; last error %u\n", GetLastError()); + ok(output.cbData == strlen(plaintext), "output wrong length %d for input '%s', wanted %d\n", output.cbData, plaintext, strlen(plaintext)); + ok(!memcmp(plaintext, (char *)output.pbData, output.cbData), "output wrong contents for input '%s'\n", plaintext); +} + +START_TEST(protectdata) +{ + HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll"); + hCrypt32 = GetModuleHandleA("crypt32.dll"); + pCryptProtectData = (void*)GetProcAddress(hCrypt32, "CryptProtectData"); + pCryptUnprotectData = (void*)GetProcAddress(hCrypt32, "CryptUnprotectData"); + if (!pCryptProtectData || !pCryptUnprotectData) + { + win_skip("Crypt(Un)ProtectData() is not available\n"); + return; + } + + protected=FALSE; + test_cryptprotectdata(); + test_cryptunprotectdata(); + test_simpleroundtrip(""); + test_simpleroundtrip("hello"); + + /* deinit globals here */ + if (cipher.pbData) LocalFree(cipher.pbData); + if (cipher_entropy.pbData) LocalFree(cipher_entropy.pbData); + if (cipher_no_desc.pbData) LocalFree(cipher_no_desc.pbData); +} diff --git a/rostests/winetests/crypt32/sip.c b/rostests/winetests/crypt32/sip.c new file mode 100644 index 00000000000..8d9af75a73c --- /dev/null +++ b/rostests/winetests/crypt32/sip.c @@ -0,0 +1,458 @@ +/* + * Subject Interface Package tests + * + * Copyright 2006 Paul Vriens + * Copyright 2008 Juan Lang + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static BOOL (WINAPI * funcCryptSIPGetSignedDataMsg)(SIP_SUBJECTINFO *,DWORD *,DWORD,DWORD *,BYTE *); +static BOOL (WINAPI * funcCryptSIPPutSignedDataMsg)(SIP_SUBJECTINFO *,DWORD,DWORD *,DWORD,BYTE *); +static BOOL (WINAPI * funcCryptSIPCreateIndirectData)(SIP_SUBJECTINFO *,DWORD *,SIP_INDIRECT_DATA *); +static BOOL (WINAPI * funcCryptSIPVerifyIndirectData)(SIP_SUBJECTINFO *,SIP_INDIRECT_DATA *); +static BOOL (WINAPI * funcCryptSIPRemoveSignedDataMsg)(SIP_SUBJECTINFO *,DWORD); + +static char *show_guid(const GUID *guid, char *buf) +{ + sprintf(buf, + "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); + + return buf; +} + +static void test_AddRemoveProvider(void) +{ + BOOL ret; + SIP_ADD_NEWPROVIDER newprov; + GUID actionid = { 0xdeadbe, 0xefde, 0xadbe, { 0xef,0xde,0xad,0xbe,0xef,0xde,0xad,0xbe }}; + static WCHAR dummydll[] = {'d','e','a','d','b','e','e','f','.','d','l','l',0 }; + static WCHAR dummyfunction[] = {'d','u','m','m','y','f','u','n','c','t','i','o','n',0 }; + + /* NULL check */ + SetLastError(0xdeadbeef); + ret = CryptSIPRemoveProvider(NULL); + ok (!ret, "Expected CryptSIPRemoveProvider to fail.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d.\n", GetLastError()); + + /* nonexistent provider should result in a registry error */ + SetLastError(0xdeadbeef); + ret = CryptSIPRemoveProvider(&actionid); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + /* Apparently the needed rights are checked before the existence of the provider */ + skip("Need admin rights\n"); + } + else + { + /* On some Win98 systems, CryptSIPRemoveProvider always succeeds if + * the arguments are correct, whether or not the registry key is + * present, so don't test ret, just check the last error if it does + * return FALSE. + */ + if (!ret) + ok (GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d.\n", GetLastError()); + } + + /* Everything OK, pwszIsFunctionName and pwszIsFunctionNameFmt2 are left NULL + * as allowed */ + + memset(&newprov, 0, sizeof(SIP_ADD_NEWPROVIDER)); + newprov.cbStruct = sizeof(SIP_ADD_NEWPROVIDER); + newprov.pgSubject = &actionid; + newprov.pwszDLLFileName = dummydll; + newprov.pwszGetFuncName = dummyfunction; + newprov.pwszPutFuncName = dummyfunction; + newprov.pwszCreateFuncName = dummyfunction; + newprov.pwszVerifyFuncName = dummyfunction; + newprov.pwszRemoveFuncName = dummyfunction; + SetLastError(0xdeadbeef); + ret = CryptSIPAddProvider(&newprov); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + skip("Need admin rights\n"); + return; + } + ok ( ret, "CryptSIPAddProvider should have succeeded\n"); + + /* Dummy provider will be deleted, but the function still fails because + * pwszIsFunctionName and pwszIsFunctionNameFmt2 are not present in the + * registry. + */ + SetLastError(0xdeadbeef); + ret = CryptSIPRemoveProvider(&actionid); + /* On some Win98 systems, CryptSIPRemoveProvider always succeeds if + * the arguments are correct, whether or not the registry key is + * present, so don't test ret, just check the last error if it does + * return FALSE. + */ + if (!ret) + ok (GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d.\n", GetLastError()); + + /* Everything OK */ + memset(&newprov, 0, sizeof(SIP_ADD_NEWPROVIDER)); + newprov.cbStruct = sizeof(SIP_ADD_NEWPROVIDER); + newprov.pgSubject = &actionid; + newprov.pwszDLLFileName = dummydll; + newprov.pwszGetFuncName = dummyfunction; + newprov.pwszPutFuncName = dummyfunction; + newprov.pwszCreateFuncName = dummyfunction; + newprov.pwszVerifyFuncName = dummyfunction; + newprov.pwszRemoveFuncName = dummyfunction; + newprov.pwszIsFunctionNameFmt2 = dummyfunction; + newprov.pwszIsFunctionName = dummyfunction; + SetLastError(0xdeadbeef); + ret = CryptSIPAddProvider(&newprov); + ok ( ret, "CryptSIPAddProvider should have succeeded\n"); + + /* Dummy provider should be deleted */ + SetLastError(0xdeadbeef); + ret = CryptSIPRemoveProvider(&actionid); + ok ( ret, "CryptSIPRemoveProvider should have succeeded\n"); +} + +static const BYTE cabFileData[] = { +0x4d,0x53,0x43,0x46,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x2c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x01,0x01,0x00,0x01,0x00,0x00,0x00, +0xef,0xbe,0xff,0xff,0x42,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xf7,0x38,0x4b,0xac,0x00,0x00,0x61,0x2e,0x74,0x78, +0x74,0x00,0x6d,0x5a,0x72,0x78,0x06,0x00,0x06,0x00,0x61,0x2e,0x74,0x78,0x74,0x0a, +}; + +static void test_SIPRetrieveSubjectGUID(void) +{ + BOOL ret; + GUID subject; + HANDLE file; + static const CHAR windir[] = "windir"; + static const CHAR regeditExe[] = "regedit.exe"; + static const GUID nullSubject = { 0x0, 0x0, 0x0, { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }}; + static const WCHAR deadbeef[] = { 'c',':','\\','d','e','a','d','b','e','e','f','.','d','b','f',0 }; + /* Couldn't find a name for this GUID, it's the one used for 95% of the files */ + static const GUID unknownGUID = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; + static const GUID cabGUID = { 0xc689aaba, 0x8e78, 0x11d0, {0x8c,0x47,0x00,0xc0,0x4f,0xc2,0x95,0xee }}; + static CHAR regeditPath[MAX_PATH]; + static WCHAR regeditPathW[MAX_PATH]; + static CHAR path[MAX_PATH]; + static CHAR tempfile[MAX_PATH]; + static WCHAR tempfileW[MAX_PATH]; + static char guid1[39], guid2[39]; + DWORD written; + + /* NULL check */ + SetLastError(0xdeadbeef); + ret = CryptSIPRetrieveSubjectGuid(NULL, NULL, NULL); + ok ( !ret, "Expected CryptSIPRetrieveSubjectGuid to fail\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d.\n", GetLastError()); + + /* Test with a nonexistent file (hopefully) */ + SetLastError(0xdeadbeef); + /* Set subject to something other than zeros */ + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(deadbeef, NULL, &subject); + ok ( !ret, "Expected CryptSIPRetrieveSubjectGuid to fail\n"); + ok (GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_PATH_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND, got %d.\n", + GetLastError()); + ok ( !memcmp(&subject, &nullSubject, sizeof(GUID)), + "Expected a NULL GUID for c:\\deadbeef.dbf, not %s\n", show_guid(&subject, guid1)); + + /* Now with an executable that should exist + * + * Use A-functions where possible as that should be available on all platforms + */ + ret = GetEnvironmentVariableA(windir, regeditPath, MAX_PATH); + ok (ret > 0, "expected GEVA(windir) to succeed, last error %d\n", GetLastError()); + strcat(regeditPath, "\\"); + strcat(regeditPath, regeditExe); + MultiByteToWideChar( CP_ACP, 0, regeditPath, + strlen(regeditPath)+1, regeditPathW, + sizeof(regeditPathW)/sizeof(regeditPathW[0]) ); + + SetLastError(0xdeadbeef); + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(regeditPathW, NULL, &subject); + ok ( ret, "Expected CryptSIPRetrieveSubjectGuid to succeed\n"); + ok ( !memcmp(&subject, &unknownGUID, sizeof(GUID)), + "Expected (%s), got (%s).\n", show_guid(&unknownGUID, guid1), show_guid(&subject, guid2)); + + /* The same thing but now with a handle instead of a filename */ + file = CreateFileA(regeditPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + SetLastError(0xdeadbeef); + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(NULL, file, &subject); + ok ( ret, "Expected CryptSIPRetrieveSubjectGuid to succeed\n"); + ok ( !memcmp(&subject, &unknownGUID, sizeof(GUID)), + "Expected (%s), got (%s).\n", show_guid(&unknownGUID, guid1), show_guid(&subject, guid2)); + CloseHandle(file); + + /* And both */ + file = CreateFileA(regeditPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + SetLastError(0xdeadbeef); + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(regeditPathW, file, &subject); + ok ( ret, "Expected CryptSIPRetrieveSubjectGuid to succeed\n"); + ok ( !memcmp(&subject, &unknownGUID, sizeof(GUID)), + "Expected (%s), got (%s).\n", show_guid(&unknownGUID, guid1), show_guid(&subject, guid2)); + CloseHandle(file); + + /* Now with an empty file */ + GetTempPathA(sizeof(path), path); + GetTempFileNameA(path, "sip", 0 , tempfile); + MultiByteToWideChar( CP_ACP, 0, tempfile, + strlen(tempfile)+1, tempfileW, + sizeof(tempfileW)/sizeof(tempfileW[0]) ); + + SetLastError(0xdeadbeef); + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(tempfileW, NULL, &subject); + ok ( !ret, "Expected CryptSIPRetrieveSubjectGuid to fail\n"); + ok ( GetLastError() == ERROR_FILE_INVALID || + GetLastError() == ERROR_INVALID_PARAMETER /* Vista */ || + GetLastError() == ERROR_SUCCESS /* most Win98 */ || + GetLastError() == TRUST_E_SUBJECT_FORM_UNKNOWN /* some Win98 */, + "Expected ERROR_FILE_INVALID, ERROR_INVALID_PARAMETER, ERROR_SUCCESS or TRUST_E_SUBJECT_FORM_UNKNOWN, got 0x%08x\n", GetLastError()); + ok ( !memcmp(&subject, &nullSubject, sizeof(GUID)), + "Expected a NULL GUID for empty file %s, not %s\n", tempfile, show_guid(&subject, guid1)); + + /* Use a file with a size of 3 (at least < 4) */ + file = CreateFileA(tempfile, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + WriteFile(file, "123", 3, &written, NULL); + CloseHandle(file); + + SetLastError(0xdeadbeef); + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(tempfileW, NULL, &subject); + ok ( !ret, "Expected CryptSIPRetrieveSubjectGuid to fail\n"); + ok ( GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_SUCCESS /* most Win98 */ || + GetLastError() == TRUST_E_SUBJECT_FORM_UNKNOWN /* some Win98 */, + "Expected ERROR_INVALID_PARAMETER, ERROR_SUCCESS or TRUST_E_SUBJECT_FORM_UNKNOWN, got 0x%08x\n", GetLastError()); + ok ( !memcmp(&subject, &nullSubject, sizeof(GUID)), + "Expected a NULL GUID for empty file %s, not %s\n", tempfile, show_guid(&subject, guid1)); + + /* And now >= 4 */ + file = CreateFileA(tempfile, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + WriteFile(file, "1234", 4, &written, NULL); + CloseHandle(file); + + SetLastError(0xdeadbeef); + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(tempfileW, NULL, &subject); + ok ( !ret, "Expected CryptSIPRetrieveSubjectGuid to fail\n"); + ok ( GetLastError() == TRUST_E_SUBJECT_FORM_UNKNOWN || + GetLastError() == ERROR_SUCCESS /* Win98 */, + "Expected TRUST_E_SUBJECT_FORM_UNKNOWN or ERROR_SUCCESS, got 0x%08x\n", GetLastError()); + ok ( !memcmp(&subject, &nullSubject, sizeof(GUID)), + "Expected a NULL GUID for empty file %s, not %s\n", tempfile, show_guid(&subject, guid1)); + + /* Clean up */ + DeleteFileA(tempfile); + + /* Create a file with just the .cab header 'MSCF' */ + SetLastError(0xdeadbeef); + file = CreateFileA(tempfile, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "failed with %u\n", GetLastError()); + WriteFile(file, cabFileData, 4, &written, NULL); + CloseHandle(file); + + SetLastError(0xdeadbeef); + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(tempfileW, NULL, &subject); + ok( ret, "CryptSIPRetrieveSubjectGuid failed: %d (0x%08x)\n", + GetLastError(), GetLastError() ); + ok ( !memcmp(&subject, &cabGUID, sizeof(GUID)), + "Expected GUID %s for cabinet file, not %s\n", show_guid(&cabGUID, guid1), show_guid(&subject, guid2)); + + /* Clean up */ + DeleteFileA(tempfile); + + /* Create a .cab file */ + SetLastError(0xdeadbeef); + file = CreateFileA(tempfile, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "failed with %u\n", GetLastError()); + WriteFile(file, cabFileData, sizeof(cabFileData), &written, NULL); + CloseHandle(file); + + SetLastError(0xdeadbeef); + memset(&subject, 1, sizeof(GUID)); + ret = CryptSIPRetrieveSubjectGuid(tempfileW, NULL, &subject); + ok( ret, "CryptSIPRetrieveSubjectGuid failed: %d (0x%08x)\n", + GetLastError(), GetLastError() ); + ok ( !memcmp(&subject, &cabGUID, sizeof(GUID)), + "Expected GUID %s for cabinet file, not %s\n", show_guid(&cabGUID, guid1), show_guid(&subject, guid2)); + + /* Clean up */ + DeleteFileA(tempfile); +} + +static void test_SIPLoad(void) +{ + BOOL ret; + GUID subject; + static GUID dummySubject = { 0xdeadbeef, 0xdead, 0xbeef, { 0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef }}; + static GUID unknown = { 0xC689AABA, 0x8E78, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; /* WINTRUST.DLL */ + static GUID unknown2 = { 0xDE351A43, 0x8E59, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; /* WINTRUST.DLL */ + /* The next SIP is available on Windows and on Wine */ + static GUID unknown3 = { 0x000C10F1, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 }}; /* MSISIP.DLL */ + SIP_DISPATCH_INFO sdi; + HMODULE hCrypt; + + /* All NULL */ + SetLastError(0xdeadbeef); + ret = CryptSIPLoad(NULL, 0, NULL); + ok ( !ret, "Expected CryptSIPLoad to fail\n"); + ok ( GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got 0x%08x\n", GetLastError()); + + /* Only pSipDispatch NULL */ + SetLastError(0xdeadbeef); + ret = CryptSIPLoad(&subject, 0, NULL); + ok ( !ret, "Expected CryptSIPLoad to fail\n"); + ok ( GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got 0x%08x\n", GetLastError()); + + /* No NULLs, but nonexistent pgSubject */ + SetLastError(0xdeadbeef); + memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); + sdi.cbSize = sizeof(SIP_DISPATCH_INFO); + sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; + ret = CryptSIPLoad(&dummySubject, 0, &sdi); + ok ( !ret, "Expected CryptSIPLoad to fail\n"); + ok ( GetLastError() == TRUST_E_SUBJECT_FORM_UNKNOWN, + "Expected TRUST_E_SUBJECT_FORM_UNKNOWN, got 0x%08x\n", GetLastError()); + ok( sdi.pfGet == (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected no change to the function pointer\n"); + + hCrypt = GetModuleHandleA("crypt32.dll"); + funcCryptSIPGetSignedDataMsg = (void*)GetProcAddress(hCrypt, "CryptSIPGetSignedDataMsg"); + funcCryptSIPPutSignedDataMsg = (void*)GetProcAddress(hCrypt, "CryptSIPPutSignedDataMsg"); + funcCryptSIPCreateIndirectData = (void*)GetProcAddress(hCrypt, "CryptSIPCreateIndirectData"); + funcCryptSIPVerifyIndirectData = (void*)GetProcAddress(hCrypt, "CryptSIPVerifyIndirectData"); + funcCryptSIPRemoveSignedDataMsg = (void*)GetProcAddress(hCrypt, "CryptSIPRemoveSignedDataMsg"); + + /* All OK */ + SetLastError(0xdeadbeef); + memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); + sdi.cbSize = sizeof(SIP_DISPATCH_INFO); + sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; + ret = CryptSIPLoad(&unknown, 0, &sdi); + ok ( ret, "Expected CryptSIPLoad to succeed\n"); + /* On native the last error will always be ERROR_PROC_NOT_FOUND as native searches for the function DllCanUnloadNow + * in WINTRUST.DLL (in this case). This function is not available in WINTRUST.DLL. + * For now there's no need to implement this is Wine as I doubt any program will rely on + * this last error when the call succeeded. + */ + ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n"); + + /* The function addresses returned by CryptSIPLoad are actually the addresses of + * crypt32's own functions. A function calling these addresses will end up first + * calling crypt32 functions which in its turn call the equivalent in the SIP + * as dictated by the given GUID. + */ + if (funcCryptSIPGetSignedDataMsg && funcCryptSIPPutSignedDataMsg && funcCryptSIPCreateIndirectData && + funcCryptSIPVerifyIndirectData && funcCryptSIPRemoveSignedDataMsg) + ok (sdi.pfGet == funcCryptSIPGetSignedDataMsg && + sdi.pfPut == funcCryptSIPPutSignedDataMsg && + sdi.pfCreate == funcCryptSIPCreateIndirectData && + sdi.pfVerify == funcCryptSIPVerifyIndirectData && + sdi.pfRemove == funcCryptSIPRemoveSignedDataMsg, + "Expected function addresses to be from crypt32\n"); + else + trace("Couldn't load function pointers\n"); + + /* All OK, but different GUID (same SIP though) */ + SetLastError(0xdeadbeef); + memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); + sdi.cbSize = sizeof(SIP_DISPATCH_INFO); + sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; + ret = CryptSIPLoad(&unknown2, 0, &sdi); + ok ( ret, "Expected CryptSIPLoad to succeed\n"); + /* This call on its own would have resulted in an ERROR_PROC_NOT_FOUND, but the previous + * call to CryptSIPLoad already loaded wintrust.dll. As this information is cached, + * CryptSIPLoad will not try to search for the already mentioned DllCanUnloadNow. + */ + ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n"); + + /* All OK, but other SIP */ + SetLastError(0xdeadbeef); + memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); + sdi.cbSize = sizeof(SIP_DISPATCH_INFO); + sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; + ret = CryptSIPLoad(&unknown3, 0, &sdi); + if (ret) + { + /* The SIP is known so we can safely assume that the next tests can be done */ + + /* As msisip.dll is not checked yet by any of the previous calls, the + * function DllCanUnloadNow will be checked again in msisip.dll (it's not present) + */ + ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n"); + + /* This is another SIP but this test proves the function addresses are the same as + * in the previous test. + */ + if (funcCryptSIPGetSignedDataMsg && funcCryptSIPPutSignedDataMsg && funcCryptSIPCreateIndirectData && + funcCryptSIPVerifyIndirectData && funcCryptSIPRemoveSignedDataMsg) + ok (sdi.pfGet == funcCryptSIPGetSignedDataMsg && + sdi.pfPut == funcCryptSIPPutSignedDataMsg && + sdi.pfCreate == funcCryptSIPCreateIndirectData && + sdi.pfVerify == funcCryptSIPVerifyIndirectData && + sdi.pfRemove == funcCryptSIPRemoveSignedDataMsg, + "Expected function addresses to be from crypt32\n"); + else + trace("Couldn't load function pointers\n"); + } + + /* Reserved parameter not 0 */ + SetLastError(0xdeadbeef); + memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); + sdi.cbSize = sizeof(SIP_DISPATCH_INFO); + sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; + ret = CryptSIPLoad(&unknown, 1, &sdi); + ok ( !ret, "Expected CryptSIPLoad to fail\n"); + ok ( GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got 0x%08x\n", GetLastError()); + ok( sdi.pfGet == (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected no change to the function pointer\n"); +} + +START_TEST(sip) +{ + test_AddRemoveProvider(); + /* It seems that the caching for loaded dlls is shared between CryptSIPRetrieveSubjectGUID + * and CryptSIPLoad. The tests have to be in this order to succeed. This is because in the last + * test for CryptSIPRetrieveSubjectGUID, several SIPs will be loaded (on Windows). + */ + test_SIPLoad(); + test_SIPRetrieveSubjectGUID(); +} diff --git a/rostests/winetests/crypt32/store.c b/rostests/winetests/crypt32/store.c new file mode 100644 index 00000000000..ee91e73b77d --- /dev/null +++ b/rostests/winetests/crypt32/store.c @@ -0,0 +1,2196 @@ +/* + * crypt32 cert store function tests + * + * Copyright 2005-2006 Juan Lang + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +/* The following aren't defined in wincrypt.h, as they're "reserved" */ +#define CERT_CERT_PROP_ID 32 +#define CERT_CRL_PROP_ID 33 +#define CERT_CTL_PROP_ID 34 + +struct CertPropIDHeader +{ + DWORD propID; + DWORD unknown1; + DWORD cb; +}; + +static const BYTE emptyCert[] = { 0x30, 0x00 }; +static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static const BYTE signedBigCert[] = { + 0x30, 0x81, 0x93, 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, 0x00, 0x30, + 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, + 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, + 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, 0x00, 0xa3, + 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; +static const BYTE serializedCert[] = { 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x7a, 0x02, 0x01, 0x01, + 0x30, 0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, + 0x00, 0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, + 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, + 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, + 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, + 0x00, 0x03, 0x01, 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x01 }; +static const BYTE signedCRL[] = { 0x30, 0x45, 0x30, 0x2c, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, + 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; +static const BYTE bigCert2[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x41, 0x6c, 0x65, 0x78, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; + + +static BOOL (WINAPI *pCertAddStoreToCollection)(HCERTSTORE,HCERTSTORE,DWORD,DWORD); +static BOOL (WINAPI *pCertControlStore)(HCERTSTORE,DWORD,DWORD,void const*); +static PCCRL_CONTEXT (WINAPI *pCertEnumCRLsInStore)(HCERTSTORE,PCCRL_CONTEXT); +static BOOL (WINAPI *pCertEnumSystemStore)(DWORD,void*,void*,PFN_CERT_ENUM_SYSTEM_STORE); +static BOOL (WINAPI *pCertGetStoreProperty)(HCERTSTORE,DWORD,void*,DWORD*); +static void (WINAPI *pCertRemoveStoreFromCollection)(HCERTSTORE,HCERTSTORE); +static BOOL (WINAPI *pCertSetStoreProperty)(HCERTSTORE,DWORD,DWORD,const void*); + +static void testMemStore(void) +{ + HCERTSTORE store1, store2; + PCCERT_CONTEXT context; + BOOL ret; + DWORD GLE; + + /* NULL provider */ + store1 = CertOpenStore(0, 0, 0, 0, NULL); + ok(!store1 && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + /* weird flags */ + store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_DELETE_FLAG, NULL); + ok(!store1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, + "Expected ERROR_CALL_NOT_IMPLEMENTED, got %d\n", GetLastError()); + + /* normal */ + store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store1 != NULL, "CertOpenStore failed: %d\n", GetLastError()); + /* open existing doesn't */ + store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_OPEN_EXISTING_FLAG, NULL); + ok(store2 != NULL, "CertOpenStore failed: %d\n", GetLastError()); + ok(store1 != store2, "Expected different stores\n"); + + /* add a bogus (empty) cert */ + context = NULL; + ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, emptyCert, + sizeof(emptyCert), CERT_STORE_ADD_ALWAYS, &context); + /* Windows returns CRYPT_E_ASN1_EOD or OSS_DATA_ERROR, but accept + * CRYPT_E_ASN1_CORRUPT as well (because matching errors is tough in this + * case) + */ + GLE = GetLastError(); + ok(!ret && (GLE == CRYPT_E_ASN1_EOD || GLE == CRYPT_E_ASN1_CORRUPT || + GLE == OSS_DATA_ERROR), + "Expected CRYPT_E_ASN1_EOD or CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GLE); + /* add a "signed" cert--the signature isn't a real signature, so this adds + * without any check of the signature's validity + */ + ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, + signedBigCert, sizeof(signedBigCert), CERT_STORE_ADD_ALWAYS, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + ok(context != NULL, "Expected a valid cert context\n"); + if (context) + { + ok(context->cbCertEncoded == sizeof(signedBigCert), + "Wrong cert size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, signedBigCert, + sizeof(signedBigCert)), "Unexpected encoded cert in context\n"); + /* remove it, the rest of the tests will work on an unsigned cert */ + ret = CertDeleteCertificateFromStore(context); + ok(ret, "CertDeleteCertificateFromStore failed: %08x\n", + GetLastError()); + } + /* try adding a "signed" CRL as a cert */ + ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, + signedCRL, sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, &context); + GLE = GetLastError(); + ok(!ret && (GLE == CRYPT_E_ASN1_BADTAG || GLE == CRYPT_E_ASN1_CORRUPT || + GLE == OSS_DATA_ERROR), + "Expected CRYPT_E_ASN1_BADTAG or CRYPT_E_ASN1_CORRUPT or OSS_DATA_ERROR, got %08x\n", + GLE); + /* add a cert to store1 */ + ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert, + sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + ok(context != NULL, "Expected a valid cert context\n"); + if (context) + { + DWORD size; + BYTE *buf; + + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong cert size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)), + "Unexpected encoded cert in context\n"); + ok(context->hCertStore == store1, "Unexpected store\n"); + + /* check serializing this element */ + /* These crash + ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, NULL); + ret = CertSerializeCertificateStoreElement(context, 0, NULL, NULL); + ret = CertSerializeCertificateStoreElement(NULL, 0, NULL, &size); + */ + /* apparently flags are ignored */ + ret = CertSerializeCertificateStoreElement(context, 1, NULL, &size); + ok(ret, "CertSerializeCertificateStoreElement failed: %08x\n", + GetLastError()); + buf = HeapAlloc(GetProcessHeap(), 0, size); + if (buf) + { + ret = CertSerializeCertificateStoreElement(context, 0, buf, &size); + ok(size == sizeof(serializedCert), "Wrong size %d\n", size); + ok(!memcmp(serializedCert, buf, size), + "Unexpected serialized cert\n"); + HeapFree(GetProcessHeap(), 0, buf); + } + + ret = CertFreeCertificateContext(context); + ok(ret, "CertFreeCertificateContext failed: %08x\n", GetLastError()); + } + /* verify the cert's in store1 */ + context = CertEnumCertificatesInStore(store1, NULL); + ok(context != NULL, "Expected a valid context\n"); + context = CertEnumCertificatesInStore(store1, context); + ok(!context && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* verify store2 (the "open existing" mem store) is still empty */ + context = CertEnumCertificatesInStore(store2, NULL); + ok(!context, "Expected an empty store\n"); + /* delete the cert from store1, and check it's empty */ + context = CertEnumCertificatesInStore(store1, NULL); + if (context) + { + /* Deleting a bitwise copy crashes with an access to an uninitialized + * pointer, so a cert context has some special data out there in memory + * someplace + CERT_CONTEXT copy; + memcpy(©, context, sizeof(copy)); + ret = CertDeleteCertificateFromStore(©); + */ + PCCERT_CONTEXT copy = CertDuplicateCertificateContext(context); + + ok(copy != NULL, "CertDuplicateCertificateContext failed: %08x\n", + GetLastError()); + ret = CertDeleteCertificateFromStore(context); + ok(ret, "CertDeleteCertificateFromStore failed: %08x\n", + GetLastError()); + /* try deleting a copy */ + ret = CertDeleteCertificateFromStore(copy); + ok(ret, "CertDeleteCertificateFromStore failed: %08x\n", + GetLastError()); + /* check that the store is empty */ + context = CertEnumCertificatesInStore(store1, NULL); + ok(!context, "Expected an empty store\n"); + } + + /* close an empty store */ + ret = CertCloseStore(NULL, 0); + ok(ret, "CertCloseStore failed: %d\n", GetLastError()); + ret = CertCloseStore(store1, 0); + ok(ret, "CertCloseStore failed: %d\n", GetLastError()); + ret = CertCloseStore(store2, 0); + ok(ret, "CertCloseStore failed: %d\n", GetLastError()); + + /* This seems nonsensical, but you can open a read-only mem store, only + * it isn't read-only + */ + store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_READONLY_FLAG, NULL); + ok(store1 != NULL, "CertOpenStore failed: %d\n", GetLastError()); + /* yep, this succeeds */ + ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, bigCert, + sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + ok(context != NULL, "Expected a valid cert context\n"); + if (context) + { + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong cert size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, sizeof(bigCert)), + "Unexpected encoded cert in context\n"); + ok(context->hCertStore == store1, "Unexpected store\n"); + ret = CertDeleteCertificateFromStore(context); + ok(ret, "CertDeleteCertificateFromStore failed: %08x\n", + GetLastError()); + } + CertCloseStore(store1, 0); +} + +static void compareFile(LPCWSTR filename, const BYTE *pb, DWORD cb) +{ + HANDLE h; + BYTE buf[200]; + BOOL ret; + DWORD cbRead = 0, totalRead = 0; + + h = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return; + do { + ret = ReadFile(h, buf, sizeof(buf), &cbRead, NULL); + if (ret && cbRead) + { + ok(totalRead + cbRead <= cb, "Expected total count %d, see %d\n", + cb, totalRead + cbRead); + ok(!memcmp(pb + totalRead, buf, cbRead), + "Unexpected data in file\n"); + totalRead += cbRead; + } + } while (ret && cbRead); + CloseHandle(h); +} + +static const BYTE serializedStoreWithCert[] = { + 0x00,0x00,0x00,0x00,0x43,0x45,0x52,0x54,0x20,0x00,0x00,0x00,0x01,0x00,0x00, + 0x00,0x7c,0x00,0x00,0x00,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30, + 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, + 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31, + 0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36, + 0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15, + 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, + 0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00, + 0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04, + 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00 }; + +static void testCollectionStore(void) +{ + HCERTSTORE store1, store2, collection, collection2; + PCCERT_CONTEXT context; + BOOL ret; + static const WCHAR szPrefix[] = { 'c','e','r',0 }; + static const WCHAR szDot[] = { '.',0 }; + WCHAR filename[MAX_PATH]; + HANDLE file; + + if (!pCertAddStoreToCollection) + { + win_skip("CertAddStoreToCollection() is not available\n"); + return; + } + + collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + /* Try adding a cert to any empty collection */ + ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(!ret && GetLastError() == E_ACCESSDENIED, + "Expected E_ACCESSDENIED, got %08x\n", GetLastError()); + + /* Create and add a cert to a memory store */ + store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + /* Add the memory store to the collection, without allowing adding */ + ret = pCertAddStoreToCollection(collection, store1, 0, 0); + ok(ret, "CertAddStoreToCollection failed: %08x\n", GetLastError()); + /* Verify the cert is in the collection */ + context = CertEnumCertificatesInStore(collection, NULL); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection, "Unexpected store\n"); + CertFreeCertificateContext(context); + } + /* Check that adding to the collection isn't allowed */ + ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING, + bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL); + ok(!ret && GetLastError() == E_ACCESSDENIED, + "Expected E_ACCESSDENIED, got %08x\n", GetLastError()); + + /* Create a new memory store */ + store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Try adding a store to a non-collection store */ + ret = pCertAddStoreToCollection(store1, store2, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Try adding some bogus stores */ + /* This crashes in Windows + ret = pCertAddStoreToCollection(0, store2, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + */ + /* This "succeeds"... */ + ret = pCertAddStoreToCollection(collection, 0, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + ok(ret, "CertAddStoreToCollection failed: %08x\n", GetLastError()); + /* while this crashes. + ret = pCertAddStoreToCollection(collection, 1, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + */ + + /* Add it to the collection, this time allowing adding */ + ret = pCertAddStoreToCollection(collection, store2, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + ok(ret, "CertAddStoreToCollection failed: %08x\n", GetLastError()); + /* Check that adding to the collection is allowed */ + ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING, + bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + /* Now check that it was actually added to store2 */ + context = CertEnumCertificatesInStore(store2, NULL); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == store2, "Unexpected store\n"); + CertFreeCertificateContext(context); + } + /* Check that the collection has both bigCert and bigCert2. bigCert comes + * first because store1 was added first. + */ + context = CertEnumCertificatesInStore(collection, NULL); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded), + "Unexpected cert\n"); + context = CertEnumCertificatesInStore(collection, context); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert2), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert2, + context->cbCertEncoded), "Unexpected cert\n"); + context = CertEnumCertificatesInStore(collection, context); + ok(!context, "Unexpected cert\n"); + } + } + /* close store2, and check that the collection is unmodified */ + CertCloseStore(store2, 0); + context = CertEnumCertificatesInStore(collection, NULL); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded), + "Unexpected cert\n"); + context = CertEnumCertificatesInStore(collection, context); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert2), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert2, + context->cbCertEncoded), "Unexpected cert\n"); + context = CertEnumCertificatesInStore(collection, context); + ok(!context, "Unexpected cert\n"); + } + } + + /* Adding a collection to a collection is legal */ + collection2 = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ret = pCertAddStoreToCollection(collection2, collection, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + ok(ret, "CertAddStoreToCollection failed: %08x\n", GetLastError()); + /* check the contents of collection2 */ + context = CertEnumCertificatesInStore(collection2, NULL); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection2, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded), + "Unexpected cert\n"); + context = CertEnumCertificatesInStore(collection2, context); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection2, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert2), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert2, + context->cbCertEncoded), "Unexpected cert\n"); + context = CertEnumCertificatesInStore(collection2, context); + ok(!context, "Unexpected cert\n"); + } + } + + /* I'd like to test closing the collection in the middle of enumeration, + * but my tests have been inconsistent. The first time calling + * CertEnumCertificatesInStore on a closed collection succeeded, while the + * second crashed. So anything appears to be fair game. + * I'd also like to test removing a store from a collection in the middle + * of an enumeration, but my tests in Windows have been inconclusive. + * In one scenario it worked. In another scenario, about a third of the + * time this leads to "random" crashes elsewhere in the code. This + * probably means this is not allowed. + */ + + CertCloseStore(store1, 0); + CertCloseStore(collection, 0); + CertCloseStore(collection2, 0); + + /* Add the same cert to two memory stores, then put them in a collection */ + store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store1 != 0, "CertOpenStore failed: %08x\n", GetLastError()); + store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store2 != 0, "CertOpenStore failed: %08x\n", GetLastError()); + + ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + ret = CertAddEncodedCertificateToStore(store2, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(collection != 0, "CertOpenStore failed: %08x\n", GetLastError()); + + ret = pCertAddStoreToCollection(collection, store1, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + ok(ret, "CertAddStoreToCollection failed: %08x\n", GetLastError()); + ret = pCertAddStoreToCollection(collection, store2, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + ok(ret, "CertAddStoreToCollection failed: %08x\n", GetLastError()); + + /* Check that the collection has two copies of the same cert */ + context = CertEnumCertificatesInStore(collection, NULL); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded), + "Unexpected cert\n"); + context = CertEnumCertificatesInStore(collection, context); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + ok(context->hCertStore == collection, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded), + "Unexpected cert\n"); + context = CertEnumCertificatesInStore(collection, context); + ok(context == NULL, "Unexpected cert\n"); + } + } + + /* The following would check whether I can delete an identical cert, rather + * than one enumerated from the store. It crashes, so that means I must + * only call CertDeleteCertificateFromStore with contexts enumerated from + * the store. + context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + ok(context != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + if (context) + { + ret = CertDeleteCertificateFromStore(collection, context); + printf("ret is %d, GetLastError is %08x\n", ret, GetLastError()); + CertFreeCertificateContext(context); + } + */ + + /* Now check deleting from the collection. */ + context = CertEnumCertificatesInStore(collection, NULL); + ok(context != NULL, "Expected a valid context\n"); + if (context) + { + CertDeleteCertificateFromStore(context); + /* store1 should now be empty */ + context = CertEnumCertificatesInStore(store1, NULL); + ok(!context, "Unexpected cert\n"); + /* and there should be one certificate in the collection */ + context = CertEnumCertificatesInStore(collection, NULL); + ok(context != NULL, "Expected a valid cert\n"); + if (context) + { + ok(context->hCertStore == collection, "Unexpected store\n"); + ok(context->cbCertEncoded == sizeof(bigCert), + "Wrong size %d\n", context->cbCertEncoded); + ok(!memcmp(context->pbCertEncoded, bigCert, context->cbCertEncoded), + "Unexpected cert\n"); + } + context = CertEnumCertificatesInStore(collection, context); + ok(context == NULL, "Unexpected cert\n"); + } + + if (!pCertRemoveStoreFromCollection) + { + win_skip("CertRemoveStoreFromCollection() is not available\n"); + } + else + { + /* Finally, test removing stores from the collection. No return + * value, so it's a bit funny to test. + */ + /* This crashes + * pCertRemoveStoreFromCollection(NULL, NULL); + */ + /* This "succeeds," no crash, no last error set */ + SetLastError(0xdeadbeef); + pCertRemoveStoreFromCollection(store2, collection); + ok(GetLastError() == 0xdeadbeef, + "Didn't expect an error to be set: %08x\n", GetLastError()); + + /* After removing store2, the collection should be empty */ + SetLastError(0xdeadbeef); + pCertRemoveStoreFromCollection(collection, store2); + ok(GetLastError() == 0xdeadbeef, + "Didn't expect an error to be set: %08x\n", GetLastError()); + context = CertEnumCertificatesInStore(collection, NULL); + ok(!context, "Unexpected cert\n"); + } + + CertCloseStore(collection, 0); + CertCloseStore(store2, 0); + CertCloseStore(store1, 0); + + /* Test adding certificates to and deleting certificates from collections. + */ + store1 = CertOpenSystemStoreA(0, "My"); + collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + ret = CertAddEncodedCertificateToStore(store1, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + CertDeleteCertificateFromStore(context); + + CertAddStoreToCollection(collection, store1, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + + ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &context); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", GetLastError()); + CertDeleteCertificateFromStore(context); + + CertCloseStore(collection, 0); + CertCloseStore(store1, 0); + + /* Test whether a collection store can be committed */ + if (!pCertControlStore) + { + win_skip("CertControlStore() is not available\n"); + return; + } + collection = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + SetLastError(0xdeadbeef); + ret = pCertControlStore(collection, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(ret, "CertControlStore failed: %08x\n", GetLastError()); + + /* Adding a mem store that can't be committed prevents a successful commit. + */ + store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + pCertAddStoreToCollection(collection, store1, 0, 0); + SetLastError(0xdeadbeef); + ret = pCertControlStore(collection, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, + "expected ERROR_CALL_NOT_IMPLEMENTED, got %d\n", GetLastError()); + pCertRemoveStoreFromCollection(collection, store1); + CertCloseStore(store1, 0); + + /* Test adding a cert to a collection with a file store, committing the + * change to the collection, and comparing the resulting file. + */ + if (!GetTempFileNameW(szDot, szPrefix, 0, filename)) + return; + + DeleteFileW(filename); + file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return; + + store1 = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, + CERT_FILE_STORE_COMMIT_ENABLE_FLAG, file); + ok(store1 != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + CloseHandle(file); + pCertAddStoreToCollection(collection, store1, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0); + CertCloseStore(store1, 0); + + ret = CertAddEncodedCertificateToStore(collection, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + ret = pCertControlStore(collection, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(ret, "CertControlStore failed: %d\n", ret); + + CertCloseStore(collection, 0); + + compareFile(filename, serializedStoreWithCert, + sizeof(serializedStoreWithCert)); + DeleteFileW(filename); +} + +/* Looks for the property with ID propID in the buffer buf. Returns a pointer + * to its header if found, NULL if not. + */ +static const struct CertPropIDHeader *findPropID(const BYTE *buf, DWORD size, + DWORD propID) +{ + const struct CertPropIDHeader *ret = NULL; + BOOL failed = FALSE; + + while (size && !ret && !failed) + { + if (size < sizeof(struct CertPropIDHeader)) + failed = TRUE; + else + { + const struct CertPropIDHeader *hdr = + (const struct CertPropIDHeader *)buf; + + size -= sizeof(struct CertPropIDHeader); + buf += sizeof(struct CertPropIDHeader); + if (size < hdr->cb) + failed = TRUE; + else if (hdr->propID == propID) + ret = hdr; + else + { + buf += hdr->cb; + size -= hdr->cb; + } + } + } + return ret; +} + +typedef DWORD (WINAPI *SHDeleteKeyAFunc)(HKEY, LPCSTR); + +static void testRegStore(void) +{ + static const char tempKey[] = "Software\\Wine\\CryptTemp"; + HCERTSTORE store; + LONG rc; + HKEY key = NULL; + DWORD disp, GLE; + + store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, NULL); + GLE = GetLastError(); + ok(!store && (GLE == ERROR_INVALID_HANDLE || GLE == ERROR_BADKEY), + "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", GLE); + store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key); + GLE = GetLastError(); + ok(!store && (GLE == ERROR_INVALID_HANDLE || GLE == ERROR_BADKEY), + "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", GLE); + + /* Opening up any old key works.. */ + key = HKEY_CURRENT_USER; + store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key); + /* Not sure if this is a bug in DuplicateHandle, marking todo_wine for now + */ + todo_wine ok(store != 0, "CertOpenStore failed: %08x\n", GetLastError()); + CertCloseStore(store, 0); + + /* It looks like the remainder pretty much needs CertControlStore() */ + if (!pCertControlStore) + { + win_skip("CertControlStore() is not available\n"); + return; + } + + rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS, + NULL, &key, NULL); + ok(!rc, "RegCreateKeyExA failed: %d\n", rc); + if (key) + { + BOOL ret; + BYTE hash[20]; + DWORD size, i; + static const char certificates[] = "Certificates\\"; + char subKeyName[sizeof(certificates) + 20 * 2 + 1], *ptr; + HKEY subKey; + PCCERT_CONTEXT context; + + store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, 0, key); + ok(store != 0, "CertOpenStore failed: %08x\n", GetLastError()); + /* Add a certificate. It isn't persisted right away, since it's only + * added to the cache.. + */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert2, sizeof(bigCert2), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + /* so flush the cache to force a commit.. */ + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(ret, "CertControlStore failed: %08x\n", GetLastError()); + /* and check that the expected subkey was written. */ + size = sizeof(hash); + ret = CryptHashCertificate(0, 0, 0, bigCert2, sizeof(bigCert2), + hash, &size); + ok(ret, "CryptHashCertificate failed: %d\n", GetLastError()); + strcpy(subKeyName, certificates); + for (i = 0, ptr = subKeyName + sizeof(certificates) - 1; i < size; + i++, ptr += 2) + sprintf(ptr, "%02X", hash[i]); + rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, + &subKey, NULL); + ok(!rc, "RegCreateKeyExA failed: %d\n", rc); + if (subKey) + { + LPBYTE buf; + + size = 0; + RegQueryValueExA(subKey, "Blob", NULL, NULL, NULL, &size); + buf = HeapAlloc(GetProcessHeap(), 0, size); + if (buf) + { + rc = RegQueryValueExA(subKey, "Blob", NULL, NULL, buf, &size); + ok(!rc, "RegQueryValueExA failed: %d\n", rc); + if (!rc) + { + const struct CertPropIDHeader *hdr; + + /* Both the hash and the cert should be present */ + hdr = findPropID(buf, size, CERT_CERT_PROP_ID); + ok(hdr != NULL, "Expected to find a cert property\n"); + if (hdr) + { + ok(hdr->cb == sizeof(bigCert2), + "Wrong size %d of cert property\n", hdr->cb); + ok(!memcmp((const BYTE *)hdr + sizeof(*hdr), bigCert2, + hdr->cb), "Unexpected cert in cert property\n"); + } + hdr = findPropID(buf, size, CERT_HASH_PROP_ID); + ok(hdr != NULL, "Expected to find a hash property\n"); + if (hdr) + { + ok(hdr->cb == sizeof(hash), + "Wrong size %d of hash property\n", hdr->cb); + ok(!memcmp((const BYTE *)hdr + sizeof(*hdr), hash, + hdr->cb), "Unexpected hash in cert property\n"); + } + } + HeapFree(GetProcessHeap(), 0, buf); + } + RegCloseKey(subKey); + } + + /* Remove the existing context */ + context = CertEnumCertificatesInStore(store, NULL); + ok(context != NULL, "Expected a cert context\n"); + if (context) + CertDeleteCertificateFromStore(context); + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(ret, "CertControlStore failed: %08x\n", GetLastError()); + + /* Add a serialized cert with a bogus hash directly to the registry */ + memset(hash, 0, sizeof(hash)); + strcpy(subKeyName, certificates); + for (i = 0, ptr = subKeyName + sizeof(certificates) - 1; + i < sizeof(hash); i++, ptr += 2) + sprintf(ptr, "%02X", hash[i]); + rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, + &subKey, NULL); + ok(!rc, "RegCreateKeyExA failed: %d\n", rc); + if (subKey) + { + BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) + + sizeof(bigCert)], *ptr; + DWORD certCount = 0; + struct CertPropIDHeader *hdr; + + hdr = (struct CertPropIDHeader *)buf; + hdr->propID = CERT_HASH_PROP_ID; + hdr->unknown1 = 1; + hdr->cb = sizeof(hash); + ptr = buf + sizeof(*hdr); + memcpy(ptr, hash, sizeof(hash)); + ptr += sizeof(hash); + hdr = (struct CertPropIDHeader *)ptr; + hdr->propID = CERT_CERT_PROP_ID; + hdr->unknown1 = 1; + hdr->cb = sizeof(bigCert); + ptr += sizeof(*hdr); + memcpy(ptr, bigCert, sizeof(bigCert)); + + rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf, + sizeof(buf)); + ok(!rc, "RegSetValueExA failed: %d\n", rc); + + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL); + ok(ret, "CertControlStore failed: %08x\n", GetLastError()); + + /* Make sure the bogus hash cert gets loaded. */ + certCount = 0; + context = NULL; + do { + context = CertEnumCertificatesInStore(store, context); + if (context) + certCount++; + } while (context != NULL); + ok(certCount == 1, "Expected 1 certificates, got %d\n", certCount); + + RegCloseKey(subKey); + } + + /* Add another serialized cert directly to the registry, this time + * under the correct key name (named with the correct hash value). + */ + size = sizeof(hash); + ret = CryptHashCertificate(0, 0, 0, bigCert2, + sizeof(bigCert2), hash, &size); + ok(ret, "CryptHashCertificate failed: %d\n", GetLastError()); + strcpy(subKeyName, certificates); + for (i = 0, ptr = subKeyName + sizeof(certificates) - 1; + i < sizeof(hash); i++, ptr += 2) + sprintf(ptr, "%02X", hash[i]); + rc = RegCreateKeyExA(key, subKeyName, 0, NULL, 0, KEY_ALL_ACCESS, NULL, + &subKey, NULL); + ok(!rc, "RegCreateKeyExA failed: %d\n", rc); + if (subKey) + { + BYTE buf[sizeof(struct CertPropIDHeader) * 2 + sizeof(hash) + + sizeof(bigCert2)], *ptr; + DWORD certCount = 0; + PCCERT_CONTEXT context; + struct CertPropIDHeader *hdr; + + /* First try with a bogus hash... */ + hdr = (struct CertPropIDHeader *)buf; + hdr->propID = CERT_HASH_PROP_ID; + hdr->unknown1 = 1; + hdr->cb = sizeof(hash); + ptr = buf + sizeof(*hdr); + memset(ptr, 0, sizeof(hash)); + ptr += sizeof(hash); + hdr = (struct CertPropIDHeader *)ptr; + hdr->propID = CERT_CERT_PROP_ID; + hdr->unknown1 = 1; + hdr->cb = sizeof(bigCert2); + ptr += sizeof(*hdr); + memcpy(ptr, bigCert2, sizeof(bigCert2)); + + rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf, + sizeof(buf)); + ok(!rc, "RegSetValueExA failed: %d\n", rc); + + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL); + ok(ret, "CertControlStore failed: %08x\n", GetLastError()); + + /* and make sure just one cert still gets loaded. */ + certCount = 0; + context = NULL; + do { + context = CertEnumCertificatesInStore(store, context); + if (context) + certCount++; + } while (context != NULL); + ok(certCount == 1 || + broken(certCount == 2), /* win9x */ + "Expected 1 certificates, got %d\n", certCount); + + /* Try again with the correct hash... */ + ptr = buf + sizeof(*hdr); + memcpy(ptr, hash, sizeof(hash)); + + rc = RegSetValueExA(subKey, "Blob", 0, REG_BINARY, buf, + sizeof(buf)); + ok(!rc, "RegSetValueExA failed: %d\n", rc); + + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_RESYNC, NULL); + ok(ret, "CertControlStore failed: %08x\n", GetLastError()); + + /* and make sure two certs get loaded. */ + certCount = 0; + context = NULL; + do { + context = CertEnumCertificatesInStore(store, context); + if (context) + certCount++; + } while (context != NULL); + ok(certCount == 2, "Expected 2 certificates, got %d\n", certCount); + + RegCloseKey(subKey); + } + CertCloseStore(store, 0); + /* Is delete allowed on a reg store? */ + store = CertOpenStore(CERT_STORE_PROV_REG, 0, 0, + CERT_STORE_DELETE_FLAG, key); + ok(store == NULL, "Expected NULL return from CERT_STORE_DELETE_FLAG\n"); + ok(GetLastError() == 0, "CertOpenStore failed: %08x\n", + GetLastError()); + + RegCloseKey(key); + } + /* The CertOpenStore with CERT_STORE_DELETE_FLAG above will delete the + * contents of the key, but not the key itself. + */ + rc = RegCreateKeyExA(HKEY_CURRENT_USER, tempKey, 0, NULL, 0, KEY_ALL_ACCESS, + NULL, &key, &disp); + ok(!rc, "RegCreateKeyExA failed: %d\n", rc); + ok(disp == REG_OPENED_EXISTING_KEY, + "Expected REG_OPENED_EXISTING_KEY, got %d\n", disp); + if (!rc) + { + RegCloseKey(key); + rc = RegDeleteKeyA(HKEY_CURRENT_USER, tempKey); + if (rc) + { + HMODULE shlwapi = LoadLibraryA("shlwapi"); + + /* Use shlwapi's SHDeleteKeyA to _really_ blow away the key, + * otherwise subsequent tests will fail. + */ + if (shlwapi) + { + SHDeleteKeyAFunc pSHDeleteKeyA = + (SHDeleteKeyAFunc)GetProcAddress(shlwapi, "SHDeleteKeyA"); + + if (pSHDeleteKeyA) + pSHDeleteKeyA(HKEY_CURRENT_USER, tempKey); + FreeLibrary(shlwapi); + } + } + } +} + +static const char MyA[] = { 'M','y',0,0 }; +static const WCHAR MyW[] = { 'M','y',0 }; +static const WCHAR BogusW[] = { 'B','o','g','u','s',0 }; +static const WCHAR BogusPathW[] = { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\','S','y','s','t','e','m','C','e','r', + 't','i','f','i','c','a','t','e','s','\\','B','o','g','u','s',0 }; + +static void testSystemRegStore(void) +{ + HCERTSTORE store, memStore; + + /* Check with a UNICODE name */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW); + /* Not all OSes support CERT_STORE_PROV_SYSTEM_REGISTRY, so don't continue + * testing if they don't. + */ + if (!store) + return; + + /* Check that it isn't a collection store */ + memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (memStore) + { + if (pCertAddStoreToCollection) + { + BOOL ret = pCertAddStoreToCollection(store, memStore, 0, 0); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + } + CertCloseStore(memStore, 0); + } + CertCloseStore(store, 0); + + /* Check opening a bogus store */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW); + ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER, BogusW); + ok(store != 0, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + CertCloseStore(store, 0); + /* Now check whether deleting is allowed */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW); + RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW); + + store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, 0, NULL); + ok(!store && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, + CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA); + ok(!store && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, + CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW); + ok(!store && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* The name is expected to be UNICODE, check with an ASCII name */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA); + ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); +} + +static void testSystemStore(void) +{ + static const WCHAR baskslashW[] = { '\\',0 }; + HCERTSTORE store; + WCHAR keyName[MAX_PATH]; + HKEY key; + LONG rc; + + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, 0, NULL); + ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyA); + ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_SYSTEM_STORE_CURRENT_USER, MyW); + ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* The name is expected to be UNICODE, first check with an ASCII name */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyA); + ok(!store && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* Create the expected key */ + lstrcpyW(keyName, CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH); + lstrcatW(keyName, baskslashW); + lstrcatW(keyName, MyW); + rc = RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_READ, + NULL, &key, NULL); + ok(!rc, "RegCreateKeyEx failed: %d\n", rc); + if (!rc) + RegCloseKey(key); + /* Check opening with a UNICODE name, specifying the create new flag */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_CREATE_NEW_FLAG, MyW); + ok(!store && GetLastError() == ERROR_FILE_EXISTS, + "Expected ERROR_FILE_EXISTS, got %08x\n", GetLastError()); + /* Now check opening with a UNICODE name, this time opening existing */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, MyW); + ok(store != 0, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + /* Check that it's a collection store */ + if (memStore) + { + if (pCertAddStoreToCollection) + { + BOOL ret = pCertAddStoreToCollection(store, memStore, 0, 0); + /* FIXME: this'll fail on NT4, but what error will it give? */ + ok(ret, "CertAddStoreToCollection failed: %08x\n", GetLastError()); + } + CertCloseStore(memStore, 0); + } + CertCloseStore(store, 0); + } + + /* Check opening a bogus store */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, BogusW); + ok((!store || + broken(store != 0)) && /* win9x */ + GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER, BogusW); + ok(store != 0, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + CertCloseStore(store, 0); + /* Now check whether deleting is allowed */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW); + RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW); +} + +static const BYTE serializedStoreWithCertAndCRL[] = { + 0x00,0x00,0x00,0x00,0x43,0x45,0x52,0x54,0x20,0x00,0x00,0x00,0x01,0x00,0x00, + 0x00,0x7c,0x00,0x00,0x00,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30, + 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, + 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31, + 0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36, + 0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15, + 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, + 0x20,0x4c,0x61,0x6e,0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00, + 0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04, + 0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x21,0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x47,0x00,0x00,0x00,0x30,0x45,0x30,0x2c,0x30,0x02,0x06,0x00,0x30, + 0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61, + 0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, + 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x02,0x06,0x00,0x03,0x11, + 0x00,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + +static void testFileStore(void) +{ + static const WCHAR szPrefix[] = { 'c','e','r',0 }; + static const WCHAR szDot[] = { '.',0 }; + WCHAR filename[MAX_PATH]; + HCERTSTORE store; + BOOL ret; + PCCERT_CONTEXT cert; + HANDLE file; + + if (!pCertControlStore) + { + win_skip("CertControlStore() is not available\n"); + return; + } + + store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, 0, NULL); + ok(!store && GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError()); + + if (!GetTempFileNameW(szDot, szPrefix, 0, filename)) + return; + + DeleteFileW(filename); + file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return; + + store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, CERT_STORE_DELETE_FLAG, + file); + ok(!store && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, + CERT_FILE_STORE_COMMIT_ENABLE_FLAG | CERT_STORE_READONLY_FLAG, file); + ok(!store && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + + /* A "read-only" file store.. */ + store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, + CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, file); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + DWORD size; + + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + /* apparently allows adding certificates.. */ + ok(ret, "CertAddEncodedCertificateToStore failed: %d\n", ret); + /* but not commits.. */ + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, + "Expected ERROR_CALL_NOT_IMPLEMENTED, got %08x\n", GetLastError()); + /* It still has certs in memory.. */ + cert = CertEnumCertificatesInStore(store, NULL); + ok(cert != NULL, "CertEnumCertificatesInStore failed: %08x\n", + GetLastError()); + CertFreeCertificateContext(cert); + /* but the file size is still 0. */ + size = GetFileSize(file, NULL); + ok(size == 0, "Expected size 0, got %d\n", size); + CertCloseStore(store, 0); + } + + /* The create new flag is allowed.. */ + store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, file); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + /* but without the commit enable flag, commits don't happen. */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %d\n", ret); + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, + "Expected ERROR_CALL_NOT_IMPLEMENTED, got %08x\n", GetLastError()); + CertCloseStore(store, 0); + } + /* as is the open existing flag. */ + store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, + CERT_STORE_OPEN_EXISTING_FLAG, file); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + /* but without the commit enable flag, commits don't happen. */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %d\n", ret); + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, + "Expected ERROR_CALL_NOT_IMPLEMENTED, got %08x\n", GetLastError()); + CertCloseStore(store, 0); + } + store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, + CERT_FILE_STORE_COMMIT_ENABLE_FLAG, file); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + CloseHandle(file); + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + /* with commits enabled, commit is allowed */ + ret = pCertControlStore(store, 0, CERT_STORE_CTRL_COMMIT, NULL); + ok(ret, "CertControlStore failed: %d\n", ret); + compareFile(filename, serializedStoreWithCert, + sizeof(serializedStoreWithCert)); + CertCloseStore(store, 0); + } + file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return; + store = CertOpenStore(CERT_STORE_PROV_FILE, 0, 0, + CERT_FILE_STORE_COMMIT_ENABLE_FLAG, file); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + CloseHandle(file); + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + CertCloseStore(store, 0); + compareFile(filename, serializedStoreWithCertAndCRL, + sizeof(serializedStoreWithCertAndCRL)); + } + + DeleteFileW(filename); +} + +static BOOL initFileFromData(LPCWSTR filename, const BYTE *pb, DWORD cb) +{ + HANDLE file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + BOOL ret; + + if (file != INVALID_HANDLE_VALUE) + { + DWORD written; + + ret = WriteFile(file, pb, cb, &written, NULL); + CloseHandle(file); + } + else + ret = FALSE; + return ret; +} + +static const BYTE base64SPC[] = +"MIICJQYJKoZIhvcNAQcCoIICFjCCAhICAQExADALBgkqhkiG9w0BBwGgggH6MIIB" +"9jCCAV+gAwIBAgIQnP8+EF4opr9OxH7h4uBPWTANBgkqhkiG9w0BAQQFADAUMRIw" +"EAYDVQQDEwlKdWFuIExhbmcwHhcNMDgxMjEyMTcxMDE0WhcNMzkxMjMxMjM1OTU5" +"WjAUMRIwEAYDVQQDEwlKdWFuIExhbmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ" +"AoGBALCgNjyNvOic0FOfjxvi43HbM+D5joDkhiGSXe+gbZlf8f16k07kkObFEunz" +"mdB5coscmA7gyqiWNN4ZUyr2cA3lCbnpGPA/0IblyyOcuGIFmmCzeZaVa5ZG6xZP" +"K7L7o+73Qo6jXVbGhBGnMZ7Q9sAn6s2933olnStnejnqwV0NAgMBAAGjSTBHMEUG" +"A1UdAQQ+MDyAEFKbKEdXYyx+CWKcV6vxM6ShFjAUMRIwEAYDVQQDEwlKdWFuIExh" +"bmeCEJz/PhBeKKa/TsR+4eLgT1kwDQYJKoZIhvcNAQEEBQADgYEALpkgLgW3mEaK" +"idPQ3iPJYLG0Ub1wraqEl9bd42hrhzIdcDzlQgxnm8/5cHYVxIF/C20x/HJplb1R" +"G6U1ipFe/q8byWD/9JpiBKMGPi9YlUTgXHfS9d4S/QWO1h9Z7KeipBYhoslQpHXu" +"y9bUr8Adqi6SzgHpCnMu53dxgxUD1r4xAA=="; +/* Same as base64SPC, but as a wide-char string */ +static const WCHAR utf16Base64SPC[] = { +'M','I','I','C','J','Q','Y','J','K','o','Z','I','h','v','c','N','A', +'Q','c','C','o','I','I','C','F','j','C','C','A','h','I','C','A','Q', +'E','x','A','D','A','L','B','g','k','q','h','k','i','G','9','w','0', +'B','B','w','G','g','g','g','H','6','M','I','I','B','9','j','C','C', +'A','V','+','g','A','w','I','B','A','g','I','Q','n','P','8','+','E', +'F','4','o','p','r','9','O','x','H','7','h','4','u','B','P','W','T', +'A','N','B','g','k','q','h','k','i','G','9','w','0','B','A','Q','Q', +'F','A','D','A','U','M','R','I','w','E','A','Y','D','V','Q','Q','D', +'E','w','l','K','d','W','F','u','I','E','x','h','b','m','c','w','H', +'h','c','N','M','D','g','x','M','j','E','y','M','T','c','x','M','D', +'E','0','W','h','c','N','M','z','k','x','M','j','M','x','M','j','M', +'1','O','T','U','5','W','j','A','U','M','R','I','w','E','A','Y','D', +'V','Q','Q','D','E','w','l','K','d','W','F','u','I','E','x','h','b', +'m','c','w','g','Z','8','w','D','Q','Y','J','K','o','Z','I','h','v', +'c','N','A','Q','E','B','B','Q','A','D','g','Y','0','A','M','I','G', +'J','A','o','G','B','A','L','C','g','N','j','y','N','v','O','i','c', +'0','F','O','f','j','x','v','i','4','3','H','b','M','+','D','5','j', +'o','D','k','h','i','G','S','X','e','+','g','b','Z','l','f','8','f', +'1','6','k','0','7','k','k','O','b','F','E','u','n','z','m','d','B', +'5','c','o','s','c','m','A','7','g','y','q','i','W','N','N','4','Z', +'U','y','r','2','c','A','3','l','C','b','n','p','G','P','A','/','0', +'I','b','l','y','y','O','c','u','G','I','F','m','m','C','z','e','Z', +'a','V','a','5','Z','G','6','x','Z','P','K','7','L','7','o','+','7', +'3','Q','o','6','j','X','V','b','G','h','B','G','n','M','Z','7','Q', +'9','s','A','n','6','s','2','9','3','3','o','l','n','S','t','n','e', +'j','n','q','w','V','0','N','A','g','M','B','A','A','G','j','S','T', +'B','H','M','E','U','G','A','1','U','d','A','Q','Q','+','M','D','y', +'A','E','F','K','b','K','E','d','X','Y','y','x','+','C','W','K','c', +'V','6','v','x','M','6','S','h','F','j','A','U','M','R','I','w','E', +'A','Y','D','V','Q','Q','D','E','w','l','K','d','W','F','u','I','E', +'x','h','b','m','e','C','E','J','z','/','P','h','B','e','K','K','a', +'/','T','s','R','+','4','e','L','g','T','1','k','w','D','Q','Y','J', +'K','o','Z','I','h','v','c','N','A','Q','E','E','B','Q','A','D','g', +'Y','E','A','L','p','k','g','L','g','W','3','m','E','a','K','i','d', +'P','Q','3','i','P','J','Y','L','G','0','U','b','1','w','r','a','q', +'E','l','9','b','d','4','2','h','r','h','z','I','d','c','D','z','l', +'Q','g','x','n','m','8','/','5','c','H','Y','V','x','I','F','/','C', +'2','0','x','/','H','J','p','l','b','1','R','G','6','U','1','i','p', +'F','e','/','q','8','b','y','W','D','/','9','J','p','i','B','K','M', +'G','P','i','9','Y','l','U','T','g','X','H','f','S','9','d','4','S', +'/','Q','W','O','1','h','9','Z','7','K','e','i','p','B','Y','h','o', +'s','l','Q','p','H','X','u','y','9','b','U','r','8','A','d','q','i', +'6','S','z','g','H','p','C','n','M','u','5','3','d','x','g','x','U', +'D','1','r','4','x','A','A','=','=',0 }; + +static void testFileNameStore(void) +{ + static const WCHAR szPrefix[] = { 'c','e','r',0 }; + static const WCHAR spcPrefix[] = { 's','p','c',0 }; + static const WCHAR szDot[] = { '.',0 }; + WCHAR filename[MAX_PATH]; + HCERTSTORE store; + BOOL ret; + DWORD GLE; + + if (0) + { + /* Crashes on NT4 */ + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, 0, NULL); + GLE = GetLastError(); + ok(!store && (GLE == ERROR_PATH_NOT_FOUND || GLE == ERROR_INVALID_PARAMETER), + "Expected ERROR_PATH_NOT_FOUND or ERROR_INVALID_PARAMETER, got %08x\n", + GLE); + } + + if (!GetTempFileNameW(szDot, szPrefix, 0, filename)) + return; + DeleteFileW(filename); + + /* The two flags are mutually exclusive */ + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_FILE_STORE_COMMIT_ENABLE_FLAG | CERT_STORE_READONLY_FLAG, filename); + ok(!store && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + + /* In all of the following tests, the encoding type seems to be ignored */ + if (initFileFromData(filename, bigCert, sizeof(bigCert))) + { + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_STORE_READONLY_FLAG, filename); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + + cert = CertEnumCertificatesInStore(store, NULL); + ok(cert != NULL, "CertEnumCertificatesInStore failed: %08x\n", + GetLastError()); + cert = CertEnumCertificatesInStore(store, cert); + ok(!cert, "Expected only one cert\n"); + if (pCertEnumCRLsInStore) + { + crl = pCertEnumCRLsInStore(store, NULL); + ok(!crl, "Expected no CRLs\n"); + } + + CertCloseStore(store, 0); + DeleteFileW(filename); + } + if (initFileFromData(filename, serializedStoreWithCert, + sizeof(serializedStoreWithCert))) + { + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_STORE_READONLY_FLAG, filename); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + + cert = CertEnumCertificatesInStore(store, NULL); + ok(cert != NULL, "CertEnumCertificatesInStore failed: %08x\n", + GetLastError()); + cert = CertEnumCertificatesInStore(store, cert); + ok(!cert, "Expected only one cert\n"); + if (pCertEnumCRLsInStore) + { + crl = pCertEnumCRLsInStore(store, NULL); + ok(!crl, "Expected no CRLs\n"); + } + + CertCloseStore(store, 0); + DeleteFileW(filename); + } + if (initFileFromData(filename, serializedStoreWithCertAndCRL, + sizeof(serializedStoreWithCertAndCRL))) + { + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_STORE_READONLY_FLAG, filename); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + + cert = CertEnumCertificatesInStore(store, NULL); + ok(cert != NULL, "CertEnumCertificatesInStore failed: %08x\n", + GetLastError()); + cert = CertEnumCertificatesInStore(store, cert); + ok(!cert, "Expected only one cert\n"); + if (pCertEnumCRLsInStore) + { + crl = pCertEnumCRLsInStore(store, NULL); + ok(crl != NULL, "CertEnumCRLsInStore failed: %08x\n", GetLastError()); + crl = pCertEnumCRLsInStore(store, crl); + ok(!crl, "Expected only one CRL\n"); + } + + CertCloseStore(store, 0); + /* Don't delete it this time, the next test uses it */ + } + /* Now that the file exists, we can open it read-only */ + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_STORE_READONLY_FLAG, filename); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + CertCloseStore(store, 0); + DeleteFileW(filename); + + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_FILE_STORE_COMMIT_ENABLE_FLAG | CERT_STORE_CREATE_NEW_FLAG, filename); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + CertCloseStore(store, 0); + compareFile(filename, serializedStoreWithCert, + sizeof(serializedStoreWithCert)); + } + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_FILE_STORE_COMMIT_ENABLE_FLAG, filename); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + ret = CertAddEncodedCRLToStore(store, X509_ASN_ENCODING, + signedCRL, sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCRLToStore failed: %08x\n", GetLastError()); + CertCloseStore(store, 0); + compareFile(filename, serializedStoreWithCertAndCRL, + sizeof(serializedStoreWithCertAndCRL)); + } + DeleteFileW(filename); + + if (!GetTempFileNameW(szDot, spcPrefix, 0, filename)) + return; + DeleteFileW(filename); + + if (initFileFromData(filename, base64SPC, sizeof(base64SPC))) + { + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_STORE_READONLY_FLAG, filename); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + + cert = CertEnumCertificatesInStore(store, NULL); + ok(cert != NULL, "CertEnumCertificatesInStore failed: %08x\n", + GetLastError()); + cert = CertEnumCertificatesInStore(store, cert); + ok(!cert, "Expected only one cert\n"); + if (pCertEnumCRLsInStore) + { + crl = pCertEnumCRLsInStore(store, NULL); + ok(!crl, "Expected no CRLs\n"); + } + + CertCloseStore(store, 0); + DeleteFileW(filename); + } + if (initFileFromData(filename, (BYTE *)utf16Base64SPC, + sizeof(utf16Base64SPC))) + { + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + + store = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, 0, + CERT_STORE_READONLY_FLAG, filename); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + + cert = CertEnumCertificatesInStore(store, NULL); + ok(cert != NULL, "CertEnumCertificatesInStore failed: %08x\n", + GetLastError()); + cert = CertEnumCertificatesInStore(store, cert); + ok(!cert, "Expected only one cert\n"); + if (pCertEnumCRLsInStore) + { + crl = pCertEnumCRLsInStore(store, NULL); + ok(!crl, "Expected no CRLs\n"); + } + + CertCloseStore(store, 0); + DeleteFileW(filename); + } +} + +static const BYTE signedContent[] = { +0x30,0x81,0xb2,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x81,0xa4,0x30,0x81,0xa1,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a, +0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04, +0x31,0x77,0x30,0x75,0x02,0x01,0x01,0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x02,0x01,0x01,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x04,0x06,0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70, +0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b,0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d, +0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c,0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe, +0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d,0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29, +0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39,0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8, +0x0d }; +static const BYTE signedWithCertAndCrlBareContent[] = { +0x30,0x82,0x01,0x4f,0x02,0x01,0x01,0x31,0x0e,0x30,0x0c,0x06,0x08,0x2a,0x86, +0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48, +0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0xa0, +0x7c,0x30,0x7a,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14, +0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01, +0x01,0xff,0x02,0x01,0x01,0xa1,0x2e,0x30,0x2c,0x30,0x02,0x06,0x00,0x30,0x15, +0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e, +0x20,0x4c,0x61,0x6e,0x67,0x00,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30, +0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x31,0x77,0x30,0x75,0x02,0x01,0x01, +0x30,0x1a,0x30,0x15,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a, +0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x00,0x02,0x01,0x01,0x30,0x0c, +0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,0x30,0x04,0x06, +0x00,0x05,0x00,0x04,0x40,0x81,0xa6,0x70,0xb3,0xef,0x59,0xd1,0x66,0xd1,0x9b, +0xc0,0x9a,0xb6,0x9a,0x5e,0x6d,0x6f,0x6d,0x0d,0x59,0xa9,0xaa,0x6e,0xe9,0x2c, +0xa0,0x1e,0xee,0xc2,0x60,0xbc,0x59,0xbe,0x3f,0x63,0x06,0x8d,0xc9,0x11,0x1d, +0x23,0x64,0x92,0xef,0x2e,0xfc,0x57,0x29,0xa4,0xaf,0xe0,0xee,0x93,0x19,0x39, +0x51,0xe4,0x44,0xb8,0x0b,0x28,0xf4,0xa8,0x0d }; +static const BYTE hashContent[] = { +0x30,0x47,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x05,0xa0,0x3a, +0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0, +0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f }; +static const BYTE hashBareContent[] = { +0x30,0x38,0x02,0x01,0x00,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, +0x02,0x05,0x05,0x00,0x30,0x13,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x07,0x01,0xa0,0x06,0x04,0x04,0x01,0x02,0x03,0x04,0x04,0x10,0x08,0xd6,0xc0, +0x5a,0x21,0x51,0x2a,0x79,0xa1,0xdf,0xeb,0x9d,0x2a,0x8f,0x26,0x2f }; + +static void testMessageStore(void) +{ + HCERTSTORE store; + HCRYPTMSG msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, + NULL); + CRYPT_DATA_BLOB blob = { sizeof(signedWithCertAndCrlBareContent), + (LPBYTE)signedWithCertAndCrlBareContent }; + DWORD count, size; + BOOL ret; + + /* Crashes + store = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0, NULL); + */ + SetLastError(0xdeadbeef); + store = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0, msg); + ok(!store && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + CryptMsgUpdate(msg, signedContent, sizeof(signedContent), TRUE); + store = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0, msg); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + PCCERT_CONTEXT cert = NULL; + PCCRL_CONTEXT crl = NULL; + + count = 0; + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + count++; + } while (cert); + ok(count == 0, "Expected 0 certificates, got %d\n", count); + + if (pCertEnumCRLsInStore) + { + count = 0; + do { + crl = pCertEnumCRLsInStore(store, crl); + if (crl) + count++; + } while (crl); + ok(count == 0, "Expected 0 CRLs, got %d\n", count); + } + + /* Can add certs to a message store */ + ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, + bigCert, sizeof(bigCert), CERT_STORE_ADD_ALWAYS, NULL); + ok(ret, "CertAddEncodedCertificateToStore failed: %08x\n", + GetLastError()); + count = 0; + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + count++; + } while (cert); + ok(count == 1, "Expected 1 certificate, got %d\n", count); + + CertCloseStore(store, 0); + } + /* but the added certs weren't actually added to the message */ + size = sizeof(count); + ret = CryptMsgGetParam(msg, CMSG_CERT_COUNT_PARAM, 0, &count, &size); + ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError()); + ok(count == 0, "Expected 0 certificates, got %d\n", count); + CryptMsgClose(msg); + + /* Crashes + store = CertOpenStore(CERT_STORE_PROV_PKCS7, 0, 0, 0, NULL); + */ + store = CertOpenStore(CERT_STORE_PROV_PKCS7, 0, 0, 0, &blob); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + { + DWORD count = 0; + PCCERT_CONTEXT cert = NULL; + PCCRL_CONTEXT crl = NULL; + + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + count++; + } while (cert); + ok(count == 1, "Expected 1 certificate, got %d\n", count); + + if (pCertEnumCRLsInStore) + { + count = 0; + do { + crl = pCertEnumCRLsInStore(store, crl); + if (crl) + count++; + } while (crl); + ok(count == 1, "Expected 1 CRL, got %d\n", count); + } + CertCloseStore(store, 0); + } + /* Encoding appears to be ignored */ + store = CertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING, 0, 0, + &blob); + ok(store != NULL, "CertOpenStore failed: %08x\n", GetLastError()); + if (store) + CertCloseStore(store, 0); + /* Messages other than signed messages aren't allowed */ + blob.cbData = sizeof(hashContent); + blob.pbData = (LPBYTE)hashContent; + SetLastError(0xdeadbeef); + store = CertOpenStore(CERT_STORE_PROV_PKCS7, 0, 0, 0, &blob); + ok(!store && GetLastError() == CRYPT_E_INVALID_MSG_TYPE, + "Expected CRYPT_E_INVALID_MSG_TYPE, got %08x\n", GetLastError()); + blob.cbData = sizeof(hashBareContent); + blob.pbData = (LPBYTE)hashBareContent; + SetLastError(0xdeadbeef); + store = CertOpenStore(CERT_STORE_PROV_PKCS7, 0, 0, 0, &blob); + ok(!store && + (GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_DATA_ERROR), /* win9x */ + "Expected CRYPT_E_ASN1_BADTAG, got %08x\n", GetLastError()); +} + +static void testCertOpenSystemStore(void) +{ + HCERTSTORE store; + + store = CertOpenSystemStoreW(0, NULL); + ok(!store && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* This succeeds, and on WinXP at least, the Bogus key is created under + * HKCU (but not under HKLM, even when run as an administrator.) + */ + store = CertOpenSystemStoreW(0, BogusW); + ok(store != 0, "CertOpenSystemStore failed: %08x\n", GetLastError()); + if (store) + CertCloseStore(store, 0); + /* Delete it so other tests succeed next time around */ + store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, BogusW); + RegDeleteKeyW(HKEY_CURRENT_USER, BogusPathW); +} + +struct EnumSystemStoreInfo +{ + BOOL goOn; + DWORD storeCount; +}; + +static BOOL CALLBACK enumSystemStoreCB(const void *systemStore, DWORD dwFlags, + PCERT_SYSTEM_STORE_INFO pStoreInfo, void *pvReserved, void *pvArg) +{ + struct EnumSystemStoreInfo *info = pvArg; + + info->storeCount++; + return info->goOn; +} + +static void testCertEnumSystemStore(void) +{ + BOOL ret; + struct EnumSystemStoreInfo info = { FALSE, 0 }; + + if (!pCertEnumSystemStore) + { + win_skip("CertEnumSystemStore() is not available\n"); + return; + } + + SetLastError(0xdeadbeef); + ret = pCertEnumSystemStore(0, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + /* Crashes + ret = pCertEnumSystemStore(CERT_SYSTEM_STORE_LOCAL_MACHINE, NULL, NULL, + NULL); + */ + + SetLastError(0xdeadbeef); + ret = pCertEnumSystemStore(CERT_SYSTEM_STORE_LOCAL_MACHINE, NULL, &info, + enumSystemStoreCB); + /* Callback returning FALSE stops enumeration */ + ok(!ret, "Expected CertEnumSystemStore to stop\n"); + ok(info.storeCount == 0 || info.storeCount == 1, + "Expected 0 or 1 stores\n"); + + info.goOn = TRUE; + info.storeCount = 0; + ret = pCertEnumSystemStore(CERT_SYSTEM_STORE_LOCAL_MACHINE, NULL, &info, + enumSystemStoreCB); + ok(ret, "CertEnumSystemStore failed: %08x\n", GetLastError()); + /* There should always be at least My, Root, and CA stores */ + ok(info.storeCount == 0 || info.storeCount >= 3, + "Expected at least 3 stores\n"); +} + +static void testStoreProperty(void) +{ + HCERTSTORE store; + BOOL ret; + DWORD propID, size = 0, state; + CRYPT_DATA_BLOB blob; + + if (!pCertGetStoreProperty || !pCertSetStoreProperty) + { + win_skip("CertGet/SetStoreProperty() is not available\n"); + return; + } + + /* Crash + ret = pCertGetStoreProperty(NULL, 0, NULL, NULL); + ret = pCertGetStoreProperty(NULL, 0, NULL, &size); + ret = pCertGetStoreProperty(store, 0, NULL, NULL); + */ + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Check a missing prop ID */ + SetLastError(0xdeadbeef); + ret = pCertGetStoreProperty(store, 0, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* Contrary to MSDN, CERT_ACCESS_STATE_PROP_ID is supported for stores.. */ + size = sizeof(state); + ret = pCertGetStoreProperty(store, CERT_ACCESS_STATE_PROP_ID, &state, &size); + ok(ret, "CertGetStoreProperty failed for CERT_ACCESS_STATE_PROP_ID: %08x\n", + GetLastError()); + ok(!state, "Expected a non-persisted store\n"); + /* and CERT_STORE_LOCALIZED_NAME_PROP_ID isn't supported by default. */ + size = 0; + ret = pCertGetStoreProperty(store, CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, + &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* Delete an arbitrary property on a store */ + ret = pCertSetStoreProperty(store, CERT_FIRST_USER_PROP_ID, 0, NULL); + ok(ret, "CertSetStoreProperty failed: %08x\n", GetLastError()); + /* Set an arbitrary property on a store */ + blob.pbData = (LPBYTE)&state; + blob.cbData = sizeof(state); + ret = pCertSetStoreProperty(store, CERT_FIRST_USER_PROP_ID, 0, &blob); + ok(ret, "CertSetStoreProperty failed: %08x\n", GetLastError()); + /* Get an arbitrary property that's been set */ + ret = pCertGetStoreProperty(store, CERT_FIRST_USER_PROP_ID, NULL, &size); + ok(ret, "CertGetStoreProperty failed: %08x\n", GetLastError()); + ok(size == sizeof(state), "Unexpected data size %d\n", size); + ret = pCertGetStoreProperty(store, CERT_FIRST_USER_PROP_ID, &propID, &size); + ok(ret, "CertGetStoreProperty failed: %08x\n", GetLastError()); + ok(propID == state, "CertGetStoreProperty got the wrong value\n"); + /* Delete it again */ + ret = pCertSetStoreProperty(store, CERT_FIRST_USER_PROP_ID, 0, NULL); + ok(ret, "CertSetStoreProperty failed: %08x\n", GetLastError()); + /* And check that it's missing */ + SetLastError(0xdeadbeef); + ret = pCertGetStoreProperty(store, CERT_FIRST_USER_PROP_ID, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + CertCloseStore(store, 0); + + /* Recheck on the My store.. */ + store = CertOpenSystemStoreW(0, MyW); + size = sizeof(state); + ret = pCertGetStoreProperty(store, CERT_ACCESS_STATE_PROP_ID, &state, &size); + ok(ret, "CertGetStoreProperty failed for CERT_ACCESS_STATE_PROP_ID: %08x\n", + GetLastError()); + ok(state, "Expected a persisted store\n"); + SetLastError(0xdeadbeef); + size = 0; + ret = pCertGetStoreProperty(store, CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, + &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + CertCloseStore(store, 0); +} + +static void testAddSerialized(void) +{ + BOOL ret; + HCERTSTORE store; + BYTE buf[sizeof(struct CertPropIDHeader) * 2 + 20 + sizeof(bigCert)] = + { 0 }; + BYTE hash[20]; + struct CertPropIDHeader *hdr; + PCCERT_CONTEXT context; + + ret = CertAddSerializedElementToStore(0, NULL, 0, 0, 0, 0, NULL, NULL); + ok(!ret && GetLastError() == ERROR_END_OF_MEDIA, + "Expected ERROR_END_OF_MEDIA, got %08x\n", GetLastError()); + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + ok(store != 0, "CertOpenStore failed: %08x\n", GetLastError()); + + ret = CertAddSerializedElementToStore(store, NULL, 0, 0, 0, 0, NULL, NULL); + ok(!ret && GetLastError() == ERROR_END_OF_MEDIA, + "Expected ERROR_END_OF_MEDIA, got %08x\n", GetLastError()); + + /* Test with an empty property */ + hdr = (struct CertPropIDHeader *)buf; + hdr->propID = CERT_CERT_PROP_ID; + hdr->unknown1 = 1; + hdr->cb = 0; + ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0, + NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Test with a bad size in property header */ + hdr->cb = sizeof(bigCert) - 1; + memcpy(buf + sizeof(struct CertPropIDHeader), bigCert, sizeof(bigCert)); + ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0, + NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 0, NULL, + NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW, + 0, 0, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Kosher size in property header, but no context type */ + hdr->cb = sizeof(bigCert); + ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, 0, + NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, 0, NULL, + NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW, + 0, 0, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* With a bad context type */ + ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, + CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, + CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW, + 0, CERT_STORE_CRL_CONTEXT_FLAG, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Bad unknown field, good type */ + hdr->unknown1 = 2; + ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, + CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND got %08x\n", GetLastError()); + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, + CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND got %08x\n", GetLastError()); + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW, + 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND got %08x\n", GetLastError()); + /* Most everything okay, but bad add disposition */ + hdr->unknown1 = 1; + /* This crashes + ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), 0, 0, + CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL); + * as does this + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), 0, 0, + CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL); + */ + /* Everything okay, but buffer's too big */ + ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), + CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL); + ok(ret, "CertAddSerializedElementToStore failed: %08x\n", GetLastError()); + /* Everything okay, check it's not re-added */ + ret = CertAddSerializedElementToStore(store, buf, + sizeof(struct CertPropIDHeader) + sizeof(bigCert), CERT_STORE_ADD_NEW, + 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_EXISTS, + "Expected CRYPT_E_EXISTS, got %08x\n", GetLastError()); + + context = CertEnumCertificatesInStore(store, NULL); + ok(context != NULL, "Expected a cert\n"); + if (context) + CertDeleteCertificateFromStore(context); + + /* Try adding with a bogus hash. Oddly enough, it succeeds, and the hash, + * when queried, is the real hash rather than the bogus hash. + */ + hdr = (struct CertPropIDHeader *)(buf + sizeof(struct CertPropIDHeader) + + sizeof(bigCert)); + hdr->propID = CERT_HASH_PROP_ID; + hdr->unknown1 = 1; + hdr->cb = sizeof(hash); + memset(hash, 0xc, sizeof(hash)); + memcpy((LPBYTE)hdr + sizeof(struct CertPropIDHeader), hash, sizeof(hash)); + ret = CertAddSerializedElementToStore(store, buf, sizeof(buf), + CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, + (const void **)&context); + ok(ret, "CertAddSerializedElementToStore failed: %08x\n", GetLastError()); + if (context) + { + BYTE hashVal[20], realHash[20]; + DWORD size = sizeof(hashVal); + + ret = CryptHashCertificate(0, 0, 0, bigCert, sizeof(bigCert), + realHash, &size); + ok(ret, "CryptHashCertificate failed: %08x\n", GetLastError()); + ret = CertGetCertificateContextProperty(context, CERT_HASH_PROP_ID, + hashVal, &size); + ok(ret, "CertGetCertificateContextProperty failed: %08x\n", + GetLastError()); + ok(!memcmp(hashVal, realHash, size), "Unexpected hash\n"); + CertFreeCertificateContext(context); + } + + CertCloseStore(store, 0); +} + +static DWORD countCertsInStore(HCERTSTORE store) +{ + PCCERT_CONTEXT cert = NULL; + DWORD certs = 0; + + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + certs++; + } while (cert); + return certs; +} + +static DWORD countCRLsInStore(HCERTSTORE store) +{ + PCCRL_CONTEXT crl = NULL; + DWORD crls = 0; + + do { + crl = pCertEnumCRLsInStore(store, crl); + if (crl) + crls++; + } while (crl); + return crls; +} + +static void test_I_UpdateStore(void) +{ + HMODULE lib = GetModuleHandleA("crypt32"); + BOOL (WINAPI *pI_CertUpdatestore)(HCERTSTORE, HCERTSTORE, DWORD, DWORD) = + (void *)GetProcAddress(lib, "I_CertUpdateStore"); + BOOL ret; + HCERTSTORE store1, store2; + PCCERT_CONTEXT cert; + DWORD certs; + + if (!pI_CertUpdatestore) + { + win_skip("No I_CertUpdateStore\n"); + return; + } + store1 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + store2 = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + + /* Crash + ret = pI_CertUpdatestore(NULL, NULL, 0, 0); + ret = pI_CertUpdatestore(store1, NULL, 0, 0); + ret = pI_CertUpdatestore(NULL, store2, 0, 0); + */ + ret = pI_CertUpdatestore(store1, store2, 0, 0); + ok(ret, "I_CertUpdateStore failed: %08x\n", GetLastError()); + + CertAddEncodedCertificateToStore(store2, X509_ASN_ENCODING, bigCert, + sizeof(bigCert), CERT_STORE_ADD_ALWAYS, &cert); + /* I_CertUpdateStore adds the contexts from store2 to store1 */ + ret = pI_CertUpdatestore(store1, store2, 0, 0); + ok(ret, "I_CertUpdateStore failed: %08x\n", GetLastError()); + certs = countCertsInStore(store1); + ok(certs == 1, "Expected 1 cert, got %d\n", certs); + /* Calling it a second time has no effect */ + ret = pI_CertUpdatestore(store1, store2, 0, 0); + ok(ret, "I_CertUpdateStore failed: %08x\n", GetLastError()); + certs = countCertsInStore(store1); + ok(certs == 1, "Expected 1 cert, got %d\n", certs); + + /* The last parameters to I_CertUpdateStore appear to be ignored */ + ret = pI_CertUpdatestore(store1, store2, 1, 0); + ok(ret, "I_CertUpdateStore failed: %08x\n", GetLastError()); + ret = pI_CertUpdatestore(store1, store2, 0, 1); + ok(ret, "I_CertUpdateStore failed: %08x\n", GetLastError()); + + CertAddEncodedCRLToStore(store2, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL); + + /* I_CertUpdateStore also adds the CRLs from store2 to store1 */ + ret = pI_CertUpdatestore(store1, store2, 0, 0); + ok(ret, "I_CertUpdateStore failed: %08x\n", GetLastError()); + certs = countCertsInStore(store1); + ok(certs == 1, "Expected 1 cert, got %d\n", certs); + if (pCertEnumCRLsInStore) + { + certs = countCRLsInStore(store1); + ok(certs == 1, "Expected 1 CRL, got %d\n", certs); + } + + CertDeleteCertificateFromStore(cert); + /* If a context is deleted from store2, I_CertUpdateStore deletes it + * from store1 + */ + ret = pI_CertUpdatestore(store1, store2, 0, 0); + ok(ret, "I_CertUpdateStore failed: %08x\n", GetLastError()); + certs = countCertsInStore(store1); + ok(certs == 0, "Expected 0 certs, got %d\n", certs); + + CertCloseStore(store1, 0); + CertCloseStore(store2, 0); +} + +START_TEST(store) +{ + HMODULE hdll; + + hdll = GetModuleHandleA("Crypt32.dll"); + pCertAddStoreToCollection = (void*)GetProcAddress(hdll, "CertAddStoreToCollection"); + pCertControlStore = (void*)GetProcAddress(hdll, "CertControlStore"); + pCertEnumCRLsInStore = (void*)GetProcAddress(hdll, "CertEnumCRLsInStore"); + pCertEnumSystemStore = (void*)GetProcAddress(hdll, "CertEnumSystemStore"); + pCertGetStoreProperty = (void*)GetProcAddress(hdll, "CertGetStoreProperty"); + pCertRemoveStoreFromCollection = (void*)GetProcAddress(hdll, "CertRemoveStoreFromCollection"); + pCertSetStoreProperty = (void*)GetProcAddress(hdll, "CertSetStoreProperty"); + + /* various combinations of CertOpenStore */ + testMemStore(); + testCollectionStore(); + testRegStore(); + testSystemRegStore(); + testSystemStore(); + testFileStore(); + testFileNameStore(); + testMessageStore(); + + testCertOpenSystemStore(); + testCertEnumSystemStore(); + testStoreProperty(); + + testAddSerialized(); + + test_I_UpdateStore(); +} diff --git a/rostests/winetests/crypt32/str.c b/rostests/winetests/crypt32/str.c new file mode 100644 index 00000000000..ebc334240ae --- /dev/null +++ b/rostests/winetests/crypt32/str.c @@ -0,0 +1,654 @@ +/* + * Unit test suite for crypt32.dll's Cert*ToStr and CertStrToName functions. + * + * Copyright 2006 Juan Lang, Aric Stewart for CodeWeavers + * + * 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 + */ +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +/*#define DUMP_STRINGS*/ +#ifdef DUMP_STRINGS +#include "wine/debug.h" +#endif + +typedef struct _CertRDNAttrEncoding { + LPCSTR pszObjId; + DWORD dwValueType; + CERT_RDN_VALUE_BLOB Value; + LPCSTR str; +} CertRDNAttrEncoding, *PCertRDNAttrEncoding; + +typedef struct _CertRDNAttrEncodingW { + LPCSTR pszObjId; + DWORD dwValueType; + CERT_RDN_VALUE_BLOB Value; + LPCWSTR str; +} CertRDNAttrEncodingW, *PCertRDNAttrEncodingW; + +static BYTE bin1[] = { 0x55, 0x53 }; +static BYTE bin2[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x73, 0x6f, 0x74, + 0x61 }; +static BYTE bin3[] = { 0x4d, 0x69, 0x6e, 0x6e, 0x65, 0x61, 0x70, 0x6f, + 0x6c, 0x69, 0x73 }; +static BYTE bin4[] = { 0x43, 0x6f, 0x64, 0x65, 0x57, 0x65, 0x61, 0x76, + 0x65, 0x72, 0x73 }; +static BYTE bin5[] = { 0x57, 0x69, 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76, + 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74 }; +static BYTE bin6[] = { 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, + 0x74 }; +static BYTE bin7[] = { 0x61, 0x72, 0x69, 0x63, 0x40, 0x63, 0x6f, 0x64, + 0x65, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x6f, 0x6d }; + +static const BYTE cert[] = +{0x30,0x82,0x2,0xbb,0x30,0x82,0x2,0x24,0x2,0x9,0x0,0xe3,0x5a,0x10,0xf1,0xfc, + 0x4b,0xf3,0xa2,0x30,0xd,0x6,0x9,0x2a,0x86,0x48,0x86,0xf7,0xd,0x1,0x1,0x4,0x5, + 0x0,0x30,0x81,0xa1,0x31,0xb,0x30,0x9,0x6,0x3,0x55,0x4,0x6,0x13,0x2,0x55,0x53, + 0x31,0x12,0x30,0x10,0x6,0x3,0x55,0x4,0x8,0x13,0x9,0x4d,0x69,0x6e,0x6e,0x65, + 0x73,0x6f,0x74,0x61,0x31,0x14,0x30,0x12,0x6,0x3,0x55,0x4,0x7,0x13,0xb,0x4d, + 0x69,0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69,0x73,0x31,0x14,0x30,0x12,0x6,0x3, + 0x55,0x4,0xa,0x13,0xb,0x43,0x6f,0x64,0x65,0x57,0x65,0x61,0x76,0x65,0x72,0x73, + 0x31,0x19,0x30,0x17,0x6,0x3,0x55,0x4,0xb,0x13,0x10,0x57,0x69,0x6e,0x65,0x20, + 0x44,0x65,0x76,0x65,0x6c,0x6f,0x70,0x6d,0x65,0x6e,0x74,0x31,0x12,0x30,0x10, + 0x6,0x3,0x55,0x4,0x3,0x13,0x9,0x6c,0x6f,0x63,0x61,0x6c,0x68,0x6f,0x73,0x74, + 0x31,0x23,0x30,0x21,0x6,0x9,0x2a,0x86,0x48,0x86,0xf7,0xd,0x1,0x9,0x1,0x16, + 0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64,0x65,0x77,0x65,0x61,0x76,0x65, + 0x72,0x73,0x2e,0x63,0x6f,0x6d,0x30,0x1e,0x17,0xd,0x30,0x36,0x30,0x31,0x32, + 0x35,0x31,0x33,0x35,0x37,0x32,0x34,0x5a,0x17,0xd,0x30,0x36,0x30,0x32,0x32, + 0x34,0x31,0x33,0x35,0x37,0x32,0x34,0x5a,0x30,0x81,0xa1,0x31,0xb,0x30,0x9,0x6, + 0x3,0x55,0x4,0x6,0x13,0x2,0x55,0x53,0x31,0x12,0x30,0x10,0x6,0x3,0x55,0x4,0x8, + 0x13,0x9,0x4d,0x69,0x6e,0x6e,0x65,0x73,0x6f,0x74,0x61,0x31,0x14,0x30,0x12,0x6, + 0x3,0x55,0x4,0x7,0x13,0xb,0x4d,0x69,0x6e,0x6e,0x65,0x61,0x70,0x6f,0x6c,0x69, + 0x73,0x31,0x14,0x30,0x12,0x6,0x3,0x55,0x4,0xa,0x13,0xb,0x43,0x6f,0x64,0x65, + 0x57,0x65,0x61,0x76,0x65,0x72,0x73,0x31,0x19,0x30,0x17,0x6,0x3,0x55,0x4,0xb, + 0x13,0x10,0x57,0x69,0x6e,0x65,0x20,0x44,0x65,0x76,0x65,0x6c,0x6f,0x70,0x6d, + 0x65,0x6e,0x74,0x31,0x12,0x30,0x10,0x6,0x3,0x55,0x4,0x3,0x13,0x9,0x6c,0x6f, + 0x63,0x61,0x6c,0x68,0x6f,0x73,0x74,0x31,0x23,0x30,0x21,0x6,0x9,0x2a,0x86,0x48, + 0x86,0xf7,0xd,0x1,0x9,0x1,0x16,0x14,0x61,0x72,0x69,0x63,0x40,0x63,0x6f,0x64, + 0x65,0x77,0x65,0x61,0x76,0x65,0x72,0x73,0x2e,0x63,0x6f,0x6d,0x30,0x81,0x9f, + 0x30,0xd,0x6,0x9,0x2a,0x86,0x48,0x86,0xf7,0xd,0x1,0x1,0x1,0x5,0x0,0x3,0x81, + 0x8d,0x0,0x30,0x81,0x89,0x2,0x81,0x81,0x0,0x9b,0xb5,0x8f,0xaf,0xfb,0x9a,0xaf, + 0xdc,0xa2,0x4d,0xb1,0xc8,0x72,0x44,0xef,0x79,0x7f,0x28,0xb6,0xfe,0x50,0xdc, + 0x8a,0xf7,0x11,0x2f,0x90,0x70,0xed,0xa4,0xa9,0xd,0xbf,0x82,0x3e,0x56,0xd8, + 0x36,0xb6,0x9,0x52,0x83,0xab,0x65,0x95,0x0,0xe2,0xea,0x3c,0x4f,0x85,0xb8,0xc, + 0x41,0x42,0x77,0x5c,0x9d,0x44,0xeb,0xcf,0x7d,0x60,0x64,0x7a,0x6c,0x4c,0xac, + 0x4a,0x9a,0x23,0x25,0x15,0xd7,0x92,0xb4,0x10,0xe7,0x95,0xad,0x4b,0x93,0xda, + 0x6a,0x76,0xe0,0xa5,0xd2,0x13,0x8,0x12,0x30,0x68,0xde,0xb9,0x5b,0x6e,0x2a, + 0x97,0x43,0xaa,0x7b,0x22,0x33,0x34,0xb1,0xca,0x5d,0x19,0xd8,0x42,0x26,0x45, + 0xc6,0xe9,0x1d,0xee,0x7,0xc2,0x27,0x95,0x87,0xd8,0x12,0xec,0x4b,0x16,0x9f,0x2, + 0x3,0x1,0x0,0x1,0x30,0xd,0x6,0x9,0x2a,0x86,0x48,0x86,0xf7,0xd,0x1,0x1,0x4,0x5, + 0x0,0x3,0x81,0x81,0x0,0x96,0xf9,0xf6,0x6a,0x3d,0xd9,0xca,0x6e,0xd5,0x76,0x73, + 0xab,0x75,0xc1,0xcc,0x98,0x44,0xc3,0xa9,0x90,0x68,0x88,0x76,0xb9,0xeb,0xb6, + 0xbe,0x60,0x62,0xb9,0x67,0x1e,0xcc,0xf4,0xe1,0xe7,0x6c,0xc8,0x67,0x3f,0x1d, + 0xf3,0x68,0x86,0x30,0xee,0xaa,0x92,0x61,0x37,0xd7,0x82,0x90,0x28,0xaa,0x7a, + 0x18,0x88,0x60,0x14,0x88,0x75,0xc0,0x4a,0x4e,0x7d,0x48,0xe7,0x3,0xa6,0xfd, + 0xd7,0xce,0x3c,0xe5,0x9b,0xaf,0x2f,0xdc,0xbb,0x7c,0xbd,0x20,0x49,0xd9,0x68, + 0x37,0xeb,0x5d,0xbb,0xe2,0x6d,0x66,0xe3,0x11,0xc1,0xa7,0x88,0x49,0xc6,0x6f, + 0x65,0xd3,0xce,0xae,0x26,0x19,0x3,0x2e,0x4f,0x78,0xa5,0xa,0x97,0x7e,0x4f,0xc4, + 0x91,0x8a,0xf8,0x5,0xef,0x5b,0x3b,0x49,0xbf,0x5f,0x2b}; + +static char issuerStr[] = + "US, Minnesota, Minneapolis, CodeWeavers, Wine Development, localhost, aric@codeweavers.com"; +static char issuerStrSemicolon[] = + "US; Minnesota; Minneapolis; CodeWeavers; Wine Development; localhost; aric@codeweavers.com"; +static char issuerStrCRLF[] = + "US\r\nMinnesota\r\nMinneapolis\r\nCodeWeavers\r\nWine Development\r\nlocalhost\r\naric@codeweavers.com"; +static char subjectStr[] = + "2.5.4.6=US, 2.5.4.8=Minnesota, 2.5.4.7=Minneapolis, 2.5.4.10=CodeWeavers, 2.5.4.11=Wine Development, 2.5.4.3=localhost, 1.2.840.113549.1.9.1=aric@codeweavers.com"; +static char subjectStrSemicolon[] = + "2.5.4.6=US; 2.5.4.8=Minnesota; 2.5.4.7=Minneapolis; 2.5.4.10=CodeWeavers; 2.5.4.11=Wine Development; 2.5.4.3=localhost; 1.2.840.113549.1.9.1=aric@codeweavers.com"; +static char subjectStrCRLF[] = + "2.5.4.6=US\r\n2.5.4.8=Minnesota\r\n2.5.4.7=Minneapolis\r\n2.5.4.10=CodeWeavers\r\n2.5.4.11=Wine Development\r\n2.5.4.3=localhost\r\n1.2.840.113549.1.9.1=aric@codeweavers.com"; +static char x500SubjectStr[] = "C=US, S=Minnesota, L=Minneapolis, O=CodeWeavers, OU=Wine Development, CN=localhost, E=aric@codeweavers.com"; +static char x500SubjectStrSemicolonReverse[] = "E=aric@codeweavers.com; CN=localhost; OU=Wine Development; O=CodeWeavers; L=Minneapolis; S=Minnesota; C=US"; +static WCHAR issuerStrW[] = { + 'U','S',',',' ','M','i','n','n','e','s','o','t','a',',',' ','M','i','n','n', + 'e','a','p','o','l','i','s',',',' ','C','o','d','e','W','e','a','v','e','r', + 's',',',' ','W','i','n','e',' ','D','e','v','e','l','o','p','m','e','n','t', + ',',' ','l','o','c','a','l','h','o','s','t',',',' ','a','r','i','c','@','c', + 'o','d','e','w','e','a','v','e','r','s','.','c','o','m',0 }; +static WCHAR issuerStrSemicolonW[] = { + 'U','S',';',' ','M','i','n','n','e','s','o','t','a',';',' ','M','i','n','n', + 'e','a','p','o','l','i','s',';',' ','C','o','d','e','W','e','a','v','e','r', + 's',';',' ','W','i','n','e',' ','D','e','v','e','l','o','p','m','e','n','t', + ';',' ','l','o','c','a','l','h','o','s','t',';',' ','a','r','i','c','@','c', + 'o','d','e','w','e','a','v','e','r','s','.','c','o','m',0 }; +static WCHAR issuerStrCRLFW[] = { + 'U','S','\r','\n','M','i','n','n','e','s','o','t','a','\r','\n','M','i','n', + 'n','e','a','p','o','l','i','s','\r','\n','C','o','d','e','W','e','a','v','e', + 'r','s','\r','\n','W','i','n','e',' ','D','e','v','e','l','o','p','m','e','n', + 't','\r','\n','l','o','c','a','l','h','o','s','t','\r','\n','a','r','i','c', + '@','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0 }; +static WCHAR subjectStrW[] = { + '2','.','5','.','4','.','6','=','U','S',',',' ','2','.','5','.','4','.','8', + '=','M','i','n','n','e','s','o','t','a',',',' ','2','.','5','.','4','.','7', + '=','M','i','n','n','e','a','p','o','l','i','s',',',' ','2','.','5','.','4', + '.','1','0','=','C','o','d','e','W','e','a','v','e','r','s',',',' ','2','.', + '5','.','4','.','1','1','=','W','i','n','e',' ','D','e','v','e','l','o','p', + 'm','e','n','t',',',' ','2','.','5','.','4','.','3','=','l','o','c','a','l', + 'h','o','s','t',',',' ','1','.','2','.','8','4','0','.','1','1','3','5','4', + '9','.','1','.','9','.','1','=','a','r','i','c','@','c','o','d','e','w','e', + 'a','v','e','r','s','.','c','o','m',0 }; +static WCHAR subjectStrSemicolonW[] = { + '2','.','5','.','4','.','6','=','U','S',';',' ','2','.','5','.','4','.','8', + '=','M','i','n','n','e','s','o','t','a',';',' ','2','.','5','.','4','.','7', + '=','M','i','n','n','e','a','p','o','l','i','s',';',' ','2','.','5','.','4', + '.','1','0','=','C','o','d','e','W','e','a','v','e','r','s',';',' ','2','.', + '5','.','4','.','1','1','=','W','i','n','e',' ','D','e','v','e','l','o','p', + 'm','e','n','t',';',' ','2','.','5','.','4','.','3','=','l','o','c','a','l', + 'h','o','s','t',';',' ','1','.','2','.','8','4','0','.','1','1','3','5','4', + '9','.','1','.','9','.','1','=','a','r','i','c','@','c','o','d','e','w','e', + 'a','v','e','r','s','.','c','o','m',0 }; +static WCHAR subjectStrCRLFW[] = { + '2','.','5','.','4','.','6','=','U','S','\r','\n','2','.','5','.','4','.','8', + '=','M','i','n','n','e','s','o','t','a','\r','\n','2','.','5','.','4','.','7', + '=','M','i','n','n','e','a','p','o','l','i','s','\r','\n','2','.','5','.','4', + '.','1','0','=','C','o','d','e','W','e','a','v','e','r','s','\r','\n','2','.', + '5','.','4','.','1','1','=','W','i','n','e',' ','D','e','v','e','l','o','p', + 'm','e','n','t','\r','\n','2','.','5','.','4','.','3','=','l','o','c','a','l', + 'h','o','s','t','\r','\n','1','.','2','.','8','4','0','.','1','1','3','5','4', + '9','.','1','.','9','.','1','=','a','r','i','c','@','c','o','d','e','w','e', + 'a','v','e','r','s','.','c','o','m',0 }; +static WCHAR x500SubjectStrSemicolonReverseW[] = { + 'E','=','a','r','i','c','@','c','o','d','e','w','e','a','v','e','r','s','.','c', + 'o','m',';',' ','C','N','=','l','o','c','a','l','h','o','s','t',';',' ','O','U', + '=','W','i','n','e',' ','D','e','v','e','l','o','p','m','e','n','t',';',' ','O', + '=','C','o','d','e','W','e','a','v','e','r','s',';',' ','L','=','M','i','n','n', + 'e','a','p','o','l','i','s',';',' ','S','=','M','i','n','n','e','s','o','t','a', + ';',' ','C','=','U','S',0 }; + +typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *, + DWORD, DWORD, void *, DWORD *); +typedef DWORD (WINAPI *CertNameToStrAFunc)(DWORD,LPVOID,DWORD,LPSTR,DWORD); +typedef DWORD (WINAPI *CertNameToStrWFunc)(DWORD,LPVOID,DWORD,LPWSTR,DWORD); +typedef DWORD (WINAPI *CertRDNValueToStrAFunc)(DWORD, PCERT_RDN_VALUE_BLOB, + LPSTR, DWORD); +typedef DWORD (WINAPI *CertRDNValueToStrWFunc)(DWORD, PCERT_RDN_VALUE_BLOB, + LPWSTR, DWORD); +typedef BOOL (WINAPI *CertStrToNameAFunc)(DWORD dwCertEncodingType, + LPCSTR pszX500, DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, + DWORD *pcbEncoded, LPCSTR *ppszError); +typedef BOOL (WINAPI *CertStrToNameWFunc)(DWORD dwCertEncodingType, + LPCWSTR pszX500, DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, + DWORD *pcbEncoded, LPCWSTR *ppszError); + +HMODULE dll; +static CertNameToStrAFunc pCertNameToStrA; +static CertNameToStrWFunc pCertNameToStrW; +static CryptDecodeObjectFunc pCryptDecodeObject; +static CertRDNValueToStrAFunc pCertRDNValueToStrA; +static CertRDNValueToStrWFunc pCertRDNValueToStrW; +static CertStrToNameAFunc pCertStrToNameA; +static CertStrToNameWFunc pCertStrToNameW; + +static void test_CertRDNValueToStrA(void) +{ + CertRDNAttrEncoding attrs[] = { + { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin1), bin1 }, "US" }, + { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin2), bin2 }, "Minnesota" }, + { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin3), bin3 }, "Minneapolis" }, + { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin4), bin4 }, "CodeWeavers" }, + { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin5), bin5 }, "Wine Development" }, + { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin6), bin6 }, "localhost" }, + { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, + { sizeof(bin7), bin7 }, "aric@codeweavers.com" }, + }; + DWORD i, ret; + char buffer[2000]; + CERT_RDN_VALUE_BLOB blob = { 0, NULL }; + + if (!pCertRDNValueToStrA) return; + + /* This crashes + ret = pCertRDNValueToStrA(0, NULL, NULL, 0); + */ + /* With empty input, it generates the empty string */ + SetLastError(0xdeadbeef); + ret = pCertRDNValueToStrA(0, &blob, NULL, 0); + ok(ret == 1 && GetLastError() == 0xdeadbeef, "Expected empty string\n"); + ret = pCertRDNValueToStrA(0, &blob, buffer, sizeof(buffer)); + ok(ret == 1 && GetLastError() == 0xdeadbeef, "Expected empty string\n"); + ok(!buffer[0], "Expected empty string\n"); + + for (i = 0; i < sizeof(attrs) / sizeof(attrs[0]); i++) + { + ret = pCertRDNValueToStrA(attrs[i].dwValueType, &attrs[i].Value, + buffer, sizeof(buffer)); + ok(ret == strlen(attrs[i].str) + 1, "Expected length %d, got %d\n", + lstrlenA(attrs[i].str) + 1, ret); + ok(!strcmp(buffer, attrs[i].str), "Expected %s, got %s\n", attrs[i].str, + buffer); + } +} + +static void test_CertRDNValueToStrW(void) +{ + static const WCHAR usW[] = { 'U','S',0 }; + static const WCHAR minnesotaW[] = { 'M','i','n','n','e','s','o','t','a',0 }; + static const WCHAR minneapolisW[] = { 'M','i','n','n','e','a','p','o','l', + 'i','s',0 }; + static const WCHAR codeweaversW[] = { 'C','o','d','e','W','e','a','v','e', + 'r','s',0 }; + static const WCHAR wineDevW[] = { 'W','i','n','e',' ','D','e','v','e','l', + 'o','p','m','e','n','t',0 }; + static const WCHAR localhostW[] = { 'l','o','c','a','l','h','o','s','t',0 }; + static const WCHAR aricW[] = { 'a','r','i','c','@','c','o','d','e','w','e', + 'a','v','e','r','s','.','c','o','m',0 }; + CertRDNAttrEncodingW attrs[] = { + { "2.5.4.6", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin1), bin1 }, usW }, + { "2.5.4.8", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin2), bin2 }, minnesotaW }, + { "2.5.4.7", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin3), bin3 }, minneapolisW }, + { "2.5.4.10", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin4), bin4 }, codeweaversW }, + { "2.5.4.11", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin5), bin5 }, wineDevW }, + { "2.5.4.3", CERT_RDN_PRINTABLE_STRING, + { sizeof(bin6), bin6 }, localhostW }, + { "1.2.840.113549.1.9.1", CERT_RDN_IA5_STRING, + { sizeof(bin7), bin7 }, aricW }, + }; + DWORD i, ret; + WCHAR buffer[2000]; + CERT_RDN_VALUE_BLOB blob = { 0, NULL }; + + if (!pCertRDNValueToStrW) + { + win_skip("CertRDNValueToStrW is not available\n"); + return; + } + + /* This crashes + ret = pCertRDNValueToStrW(0, NULL, NULL, 0); + */ + /* With empty input, it generates the empty string */ + SetLastError(0xdeadbeef); + ret = pCertRDNValueToStrW(0, &blob, NULL, 0); + ok(ret == 1 && GetLastError() == 0xdeadbeef, "Expected empty string\n"); + ret = pCertRDNValueToStrW(0, &blob, buffer, + sizeof(buffer) / sizeof(buffer[0])); + ok(ret == 1 && GetLastError() == 0xdeadbeef, "Expected empty string\n"); + ok(!buffer[0], "Expected empty string\n"); + + for (i = 0; i < sizeof(attrs) / sizeof(attrs[0]); i++) + { + ret = pCertRDNValueToStrW(attrs[i].dwValueType, &attrs[i].Value, + buffer, sizeof(buffer) / sizeof(buffer[0])); + ok(ret == lstrlenW(attrs[i].str) + 1, "Expected length %d, got %d\n", + lstrlenW(attrs[i].str) + 1, ret); + ok(!lstrcmpW(buffer, attrs[i].str), "Unexpected value\n"); +#ifdef DUMP_STRINGS + trace("Expected %s, got %s\n", + wine_dbgstr_w(attrs[i].str), wine_dbgstr_w(buffer)); +#endif + } +} + +static void test_NameToStrConversionA(PCERT_NAME_BLOB pName, DWORD dwStrType, + LPCSTR expected) +{ + char buffer[2000] = { 0 }; + DWORD i; + + i = pCertNameToStrA(X509_ASN_ENCODING, pName, dwStrType, NULL, 0); + ok(i == strlen(expected) + 1, "Expected %d chars, got %d\n", + lstrlenA(expected) + 1, i); + i = pCertNameToStrA(X509_ASN_ENCODING,pName, dwStrType, buffer, + sizeof(buffer)); + ok(i == strlen(expected) + 1, "Expected %d chars, got %d\n", + lstrlenA(expected) + 1, i); + ok(!strcmp(buffer, expected), "Expected %s, got %s\n", expected, buffer); +} + +static void test_CertNameToStrA(void) +{ + PCCERT_CONTEXT context; + + if (!pCertNameToStrA) + { + win_skip("CertNameToStrA is not available\n"); + return; + } + + context = CertCreateCertificateContext(X509_ASN_ENCODING, cert, + sizeof(cert)); + ok(context != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + if (context) + { + DWORD ret; + + /* This crashes + ret = pCertNameToStrA(0, NULL, 0, NULL, 0); + */ + /* Test with a bogus encoding type */ + SetLastError(0xdeadbeef); + ret = pCertNameToStrA(0, &context->pCertInfo->Issuer, 0, NULL, 0); + ok(ret == 1 && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected retval 1 and ERROR_FILE_NOT_FOUND, got %d - %08x\n", + ret, GetLastError()); + SetLastError(0xdeadbeef); + ret = pCertNameToStrA(X509_ASN_ENCODING, &context->pCertInfo->Issuer, + 0, NULL, 0); + ok(ret && GetLastError() == ERROR_SUCCESS, + "Expected positive return and ERROR_SUCCESS, got %d - %08x\n", + ret, GetLastError()); + + test_NameToStrConversionA(&context->pCertInfo->Issuer, + CERT_SIMPLE_NAME_STR, issuerStr); + test_NameToStrConversionA(&context->pCertInfo->Issuer, + CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, + issuerStrSemicolon); + test_NameToStrConversionA(&context->pCertInfo->Issuer, + CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG, + issuerStrCRLF); + test_NameToStrConversionA(&context->pCertInfo->Subject, + CERT_OID_NAME_STR, subjectStr); + test_NameToStrConversionA(&context->pCertInfo->Subject, + CERT_OID_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, + subjectStrSemicolon); + test_NameToStrConversionA(&context->pCertInfo->Subject, + CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG, + subjectStrCRLF); + test_NameToStrConversionA(&context->pCertInfo->Subject, + CERT_X500_NAME_STR, x500SubjectStr); + test_NameToStrConversionA(&context->pCertInfo->Subject, + CERT_X500_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG | CERT_NAME_STR_REVERSE_FLAG, x500SubjectStrSemicolonReverse); + + CertFreeCertificateContext(context); + } +} + +static void test_NameToStrConversionW(PCERT_NAME_BLOB pName, DWORD dwStrType, + LPCWSTR expected) +{ + WCHAR buffer[2000] = { 0 }; + DWORD i; + + i = pCertNameToStrW(X509_ASN_ENCODING,pName, dwStrType, NULL, 0); + ok(i == lstrlenW(expected) + 1, "Expected %d chars, got %d\n", + lstrlenW(expected) + 1, i); + i = pCertNameToStrW(X509_ASN_ENCODING,pName, dwStrType, buffer, + sizeof(buffer) / sizeof(buffer[0])); + ok(i == lstrlenW(expected) + 1, "Expected %d chars, got %d\n", + lstrlenW(expected) + 1, i); + ok(!lstrcmpW(buffer, expected), "Unexpected value\n"); +#ifdef DUMP_STRINGS + trace("Expected %s, got %s\n", + wine_dbgstr_w(expected), wine_dbgstr_w(buffer)); +#endif +} + +static void test_CertNameToStrW(void) +{ + PCCERT_CONTEXT context; + + if (!pCertNameToStrW) + { + win_skip("CertNameToStrW is not available\n"); + return; + } + + context = CertCreateCertificateContext(X509_ASN_ENCODING, cert, + sizeof(cert)); + ok(context != NULL, "CertCreateCertificateContext failed: %08x\n", + GetLastError()); + if (context) + { + DWORD ret; + + /* This crashes + ret = pCertNameToStrW(0, NULL, 0, NULL, 0); + */ + /* Test with a bogus encoding type */ + SetLastError(0xdeadbeef); + ret = pCertNameToStrW(0, &context->pCertInfo->Issuer, 0, NULL, 0); + ok(ret == 1 && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected retval 1 and ERROR_FILE_NOT_FOUND, got %d - %08x\n", + ret, GetLastError()); + SetLastError(0xdeadbeef); + ret = pCertNameToStrW(X509_ASN_ENCODING, &context->pCertInfo->Issuer, + 0, NULL, 0); + ok(ret && GetLastError() == ERROR_SUCCESS, + "Expected positive return and ERROR_SUCCESS, got %d - %08x\n", + ret, GetLastError()); + + test_NameToStrConversionW(&context->pCertInfo->Issuer, + CERT_SIMPLE_NAME_STR, issuerStrW); + test_NameToStrConversionW(&context->pCertInfo->Issuer, + CERT_SIMPLE_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, + issuerStrSemicolonW); + test_NameToStrConversionW(&context->pCertInfo->Issuer, + CERT_SIMPLE_NAME_STR | CERT_NAME_STR_CRLF_FLAG, + issuerStrCRLFW); + test_NameToStrConversionW(&context->pCertInfo->Subject, + CERT_OID_NAME_STR, subjectStrW); + test_NameToStrConversionW(&context->pCertInfo->Subject, + CERT_OID_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG, + subjectStrSemicolonW); + test_NameToStrConversionW(&context->pCertInfo->Subject, + CERT_OID_NAME_STR | CERT_NAME_STR_CRLF_FLAG, + subjectStrCRLFW); + test_NameToStrConversionW(&context->pCertInfo->Subject, + CERT_X500_NAME_STR | CERT_NAME_STR_SEMICOLON_FLAG | CERT_NAME_STR_REVERSE_FLAG, x500SubjectStrSemicolonReverseW); + + CertFreeCertificateContext(context); + } +} + +struct StrToNameA +{ + LPCSTR x500; + DWORD encodedSize; + const BYTE *encoded; +}; + +const BYTE encodedSimpleCN[] = { +0x30,0x0c,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x03,0x13,0x01,0x31 }; +static const BYTE encodedSingleQuotedCN[] = { 0x30,0x0e,0x31,0x0c,0x30,0x0a, + 0x06,0x03,0x55,0x04,0x03,0x13,0x03,0x27,0x31,0x27 }; +static const BYTE encodedSpacedCN[] = { 0x30,0x0e,0x31,0x0c,0x30,0x0a,0x06,0x03, + 0x55,0x04,0x03,0x13,0x03,0x20,0x31,0x20 }; +static const BYTE encodedQuotedCN[] = { 0x30,0x11,0x31,0x0f,0x30,0x0d,0x06,0x03, + 0x55, 0x04,0x03,0x1e,0x06,0x00,0x22,0x00,0x31,0x00,0x22, }; +static const BYTE encodedMultipleAttrCN[] = { 0x30,0x0e,0x31,0x0c,0x30,0x0a, + 0x06,0x03,0x55,0x04,0x03,0x13,0x03,0x31,0x2b,0x32 }; + +struct StrToNameA namesA[] = { + { "CN=1", sizeof(encodedSimpleCN), encodedSimpleCN }, + { "CN=\"1\"", sizeof(encodedSimpleCN), encodedSimpleCN }, + { "CN = \"1\"", sizeof(encodedSimpleCN), encodedSimpleCN }, + { "CN='1'", sizeof(encodedSingleQuotedCN), encodedSingleQuotedCN }, + { "CN=\" 1 \"", sizeof(encodedSpacedCN), encodedSpacedCN }, + { "CN=\"\"\"1\"\"\"", sizeof(encodedQuotedCN), encodedQuotedCN }, + { "CN=\"1+2\"", sizeof(encodedMultipleAttrCN), encodedMultipleAttrCN }, +}; + +static void test_CertStrToNameA(void) +{ + BOOL ret; + DWORD size, i; + BYTE buf[100]; + + if (!pCertStrToNameA) + { + win_skip("CertStrToNameA is not available\n"); + return; + } + + /* Crash + ret = pCertStrToNameA(0, NULL, 0, NULL, NULL, NULL, NULL); + */ + ret = pCertStrToNameA(0, NULL, 0, NULL, NULL, &size, NULL); + ok(!ret, "Expected failure\n"); + ret = pCertStrToNameA(0, "bogus", 0, NULL, NULL, &size, NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING, + "Expected CRYPT_E_INVALID_X500_STRING, got %08x\n", GetLastError()); + ret = pCertStrToNameA(0, "foo=1", 0, NULL, NULL, &size, NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING, + "Expected CRYPT_E_INVALID_X500_STRING, got %08x\n", GetLastError()); + ret = pCertStrToNameA(0, "CN=1", 0, NULL, NULL, &size, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = pCertStrToNameA(X509_ASN_ENCODING, "CN=1", 0, NULL, NULL, &size, NULL); + ok(ret, "CertStrToNameA failed: %08x\n", GetLastError()); + size = sizeof(buf); + ret = pCertStrToNameA(X509_ASN_ENCODING, "CN=\"\"1\"\"", 0, NULL, buf, &size, + NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING, + "Expected CRYPT_E_INVALID_X500_STRING, got %08x\n", GetLastError()); + ret = pCertStrToNameA(X509_ASN_ENCODING, "CN=1+2", 0, NULL, buf, + &size, NULL); + todo_wine ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING, + "Expected CRYPT_E_INVALID_X500_STRING, got %08x\n", GetLastError()); + for (i = 0; i < sizeof(namesA) / sizeof(namesA[0]); i++) + { + size = sizeof(buf); + ret = pCertStrToNameA(X509_ASN_ENCODING, namesA[i].x500, 0, NULL, buf, + &size, NULL); + ok(ret, "CertStrToNameA failed on string %s: %08x\n", namesA[i].x500, + GetLastError()); + ok(size == namesA[i].encodedSize, + "Expected size %d, got %d\n", namesA[i].encodedSize, size); + if (ret) + ok(!memcmp(buf, namesA[i].encoded, namesA[i].encodedSize), + "Unexpected value for string %s\n", namesA[i].x500); + } +} + +struct StrToNameW +{ + LPCWSTR x500; + DWORD encodedSize; + const BYTE *encoded; +}; + +static const WCHAR badlyQuotedCN_W[] = { 'C','N','=','"','"','1','"','"',0 }; +static const WCHAR simpleCN_W[] = { 'C','N','=','1',0 }; +static const WCHAR simpleCN2_W[] = { 'C','N','=','"','1','"',0 }; +static const WCHAR simpleCN3_W[] = { 'C','N',' ','=',' ','"','1','"',0 }; +static const WCHAR singledQuotedCN_W[] = { 'C','N','=','\'','1','\'',0 }; +static const WCHAR spacedCN_W[] = { 'C','N','=','"',' ','1',' ','"',0 }; +static const WCHAR quotedCN_W[] = { 'C','N','=','"','"','"','1','"','"','"',0 }; +static const WCHAR multipleAttrCN_W[] = { 'C','N','=','"','1','+','2','"',0 }; +static const WCHAR japaneseCN_W[] = { 'C','N','=',0x226f,0x575b,0 }; +static const BYTE encodedJapaneseCN[] = { 0x30,0x0f,0x31,0x0d,0x30,0x0b,0x06, + 0x03,0x55,0x04,0x03,0x1e,0x04,0x22,0x6f,0x57,0x5b }; + +struct StrToNameW namesW[] = { + { simpleCN_W, sizeof(encodedSimpleCN), encodedSimpleCN }, + { simpleCN2_W, sizeof(encodedSimpleCN), encodedSimpleCN }, + { simpleCN3_W, sizeof(encodedSimpleCN), encodedSimpleCN }, + { singledQuotedCN_W, sizeof(encodedSingleQuotedCN), encodedSingleQuotedCN }, + { spacedCN_W, sizeof(encodedSpacedCN), encodedSpacedCN }, + { quotedCN_W, sizeof(encodedQuotedCN), encodedQuotedCN }, + { multipleAttrCN_W, sizeof(encodedMultipleAttrCN), encodedMultipleAttrCN }, + { japaneseCN_W, sizeof(encodedJapaneseCN), encodedJapaneseCN }, +}; + +static void test_CertStrToNameW(void) +{ + static const WCHAR bogusW[] = { 'b','o','g','u','s',0 }; + static const WCHAR fooW[] = { 'f','o','o','=','1',0 }; + BOOL ret; + DWORD size, i; + LPCWSTR errorPtr; + BYTE buf[100]; + + if (!pCertStrToNameW) + { + win_skip("CertStrToNameW is not available\n"); + return; + } + + /* Crash + ret = pCertStrToNameW(0, NULL, 0, NULL, NULL, NULL, NULL); + */ + ret = pCertStrToNameW(0, NULL, 0, NULL, NULL, &size, NULL); + ok(!ret, "Expected failure\n"); + ret = pCertStrToNameW(0, bogusW, 0, NULL, NULL, &size, NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING, + "Expected CRYPT_E_INVALID_X500_STRING, got %08x\n", GetLastError()); + ret = pCertStrToNameW(0, fooW, 0, NULL, NULL, &size, NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING, + "Expected CRYPT_E_INVALID_X500_STRING, got %08x\n", GetLastError()); + ret = pCertStrToNameW(0, simpleCN_W, 0, NULL, NULL, &size, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %08x\n", GetLastError()); + ret = pCertStrToNameW(X509_ASN_ENCODING, simpleCN_W, 0, NULL, NULL, &size, + NULL); + ok(ret, "CertStrToNameW failed: %08x\n", GetLastError()); + size = sizeof(buf); + ret = pCertStrToNameW(X509_ASN_ENCODING, badlyQuotedCN_W, 0, NULL, buf, + &size, NULL); + ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING, + "Expected CRYPT_E_INVALID_X500_STRING, got %08x\n", GetLastError()); + ret = pCertStrToNameW(X509_ASN_ENCODING, badlyQuotedCN_W, 0, NULL, buf, + &size, &errorPtr); + ok(!ret && GetLastError() == CRYPT_E_INVALID_X500_STRING, + "Expected CRYPT_E_INVALID_X500_STRING, got %08x\n", GetLastError()); + ok(errorPtr && *errorPtr == '1', "Expected first error character was 1\n"); + for (i = 0; i < sizeof(namesW) / sizeof(namesW[0]); i++) + { + size = sizeof(buf); + ret = pCertStrToNameW(X509_ASN_ENCODING, namesW[i].x500, 0, NULL, buf, + &size, NULL); + ok(ret, "Index %d: CertStrToNameW failed: %08x\n", i, GetLastError()); + ok(size == namesW[i].encodedSize, + "Index %d: expected size %d, got %d\n", i, namesW[i].encodedSize, + size); + if (ret) + ok(!memcmp(buf, namesW[i].encoded, size), + "Index %d: unexpected value\n", i); + } +} + +START_TEST(str) +{ + dll = GetModuleHandleA("Crypt32.dll"); + + pCertNameToStrA = (CertNameToStrAFunc)GetProcAddress(dll,"CertNameToStrA"); + pCertNameToStrW = (CertNameToStrWFunc)GetProcAddress(dll,"CertNameToStrW"); + pCertRDNValueToStrA = (CertRDNValueToStrAFunc)GetProcAddress(dll, + "CertRDNValueToStrA"); + pCertRDNValueToStrW = (CertRDNValueToStrWFunc)GetProcAddress(dll, + "CertRDNValueToStrW"); + pCryptDecodeObject = (CryptDecodeObjectFunc)GetProcAddress(dll, + "CryptDecodeObject"); + pCertStrToNameA = (CertStrToNameAFunc)GetProcAddress(dll,"CertStrToNameA"); + pCertStrToNameW = (CertStrToNameWFunc)GetProcAddress(dll,"CertStrToNameW"); + + test_CertRDNValueToStrA(); + test_CertRDNValueToStrW(); + test_CertNameToStrA(); + test_CertNameToStrW(); + test_CertStrToNameA(); + test_CertStrToNameW(); +} diff --git a/rostests/winetests/crypt32/testlist.c b/rostests/winetests/crypt32/testlist.c new file mode 100644 index 00000000000..7486cad4546 --- /dev/null +++ b/rostests/winetests/crypt32/testlist.c @@ -0,0 +1,43 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_base64(void); +extern void func_cert(void); +extern void func_chain(void); +extern void func_crl(void); +extern void func_ctl(void); +extern void func_encode(void); +extern void func_main(void); +extern void func_message(void); +extern void func_msg(void); +extern void func_object(void); +extern void func_oid(void); +extern void func_protectdata(void); +extern void func_sip(void); +extern void func_store(void); +extern void func_str(void); + +const struct test winetest_testlist[] = +{ + { "base64", func_base64 }, + { "cert", func_cert }, + { "chain", func_chain }, + { "crl", func_crl }, + { "ctl", func_ctl }, + { "encode", func_encode }, + { "main", func_main }, + { "message", func_message }, + { "msg", func_msg }, + { "object", func_object }, + { "oid", func_oid }, + { "protectdata", func_protectdata }, + { "sip", func_sip }, + { "store", func_store }, + { "str", func_str }, + { 0, 0 } +}; diff --git a/rostests/winetests/cryptnet/cryptnet.c b/rostests/winetests/cryptnet/cryptnet.c new file mode 100644 index 00000000000..618e494a878 --- /dev/null +++ b/rostests/winetests/cryptnet/cryptnet.c @@ -0,0 +1,400 @@ +/* + * Unit test suite for cryptnet.dll + * + * Copyright 2007 Juan Lang + * + * 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 + */ +#include +#include +#define NONAMELESSUNION +#include +#include +#include +#include +#include "wine/test.h" + +static const BYTE bigCert[] = { +0x30,0x78,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x14,0x31,0x12,0x30,0x10, +0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x30, +0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x14,0x31,0x12,0x30,0x10,0x06,0x03, +0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,0x67,0x30, +0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x16,0x30,0x14,0x30,0x12,0x06, +0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02, +0x01,0x01}; +static const BYTE certWithIssuingDistPoint[] = { +0x30,0x81,0x99,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x14,0x31,0x12, +0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c, +0x61,0x6e,0x67,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x14,0x31,0x12,0x30,0x10, +0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x27,0x30,0x25,0x30, +0x23,0x06,0x03,0x55,0x1d,0x1c,0x01,0x01,0xff,0x04,0x19,0x30,0x17,0xa0,0x15, +0xa0,0x13,0x86,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65, +0x68,0x71,0x2e,0x6f,0x72,0x67, }; +static const BYTE certWithCRLDistPoint[] = { +0x30,0x81,0x9b,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x01,0x30,0x0d,0x06,0x09, +0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x14,0x31,0x12, +0x30,0x10,0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c, +0x61,0x6e,0x67,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x14,0x31,0x12,0x30,0x10, +0x06,0x03,0x55,0x04,0x03,0x13,0x09,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x30,0x07,0x30,0x02,0x06,0x00,0x03,0x01,0x00,0xa3,0x29,0x30,0x27,0x30, +0x25,0x06,0x03,0x55,0x1d,0x1f,0x01,0x01,0xff,0x04,0x1b,0x30,0x19,0x30,0x17, +0xa0,0x15,0xa0,0x13,0x86,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69, +0x6e,0x65,0x68,0x71,0x2e,0x6f,0x72,0x67, }; + +static void compareUrlArray(const CRYPT_URL_ARRAY *expected, + const CRYPT_URL_ARRAY *got) +{ + ok(expected->cUrl == got->cUrl, "Expected %d URLs, got %d\n", + expected->cUrl, got->cUrl); + if (expected->cUrl == got->cUrl) + { + DWORD i; + + for (i = 0; i < got->cUrl; i++) + ok(!lstrcmpiW(expected->rgwszUrl[i], got->rgwszUrl[i]), + "%d: unexpected URL\n", i); + } +} + +static WCHAR url[] = + { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 }; + +static void test_getObjectUrl(void) +{ + BOOL ret; + DWORD urlArraySize = 0, infoSize = 0; + PCCERT_CONTEXT cert; + + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + /* Crash + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL, NULL, + NULL, NULL, NULL); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL, NULL, + NULL, &infoSize, NULL); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, NULL, 0, NULL, + &urlArraySize, NULL, &infoSize, NULL); + */ + /* A cert with no CRL dist point extension fails.. */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0, NULL, + NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + CertFreeCertificateContext(cert); + + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + certWithIssuingDistPoint, sizeof(certWithIssuingDistPoint)); + if (cert) + { + /* This cert has no AIA extension, so expect this to fail */ + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0, + NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, + CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, + CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* It does have an issuing dist point extension, but that's not what + * this is looking for (it wants a CRL dist points extension) + */ + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, 0, NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL, + NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL, + NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + CertFreeCertificateContext(cert); + } + cert = CertCreateCertificateContext(X509_ASN_ENCODING, + certWithCRLDistPoint, sizeof(certWithCRLDistPoint)); + if (cert) + { + PCRYPT_URL_ARRAY urlArray; + + /* This cert has no AIA extension, so expect this to fail */ + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, 0, + NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, + CRYPT_GET_URL_FROM_PROPERTY, NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void *)cert, + CRYPT_GET_URL_FROM_EXTENSION, NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + /* It does have a CRL dist points extension */ + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, 0, NULL, NULL, NULL, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, 0, NULL, NULL, NULL, &infoSize, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Can get it without specifying the location: */ + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, 0, NULL, &urlArraySize, NULL, NULL, NULL); + ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError()); + urlArray = HeapAlloc(GetProcessHeap(), 0, urlArraySize); + if (urlArray) + { + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, 0, urlArray, &urlArraySize, NULL, NULL, NULL); + ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError()); + if (ret) + { + LPWSTR pUrl = url; + CRYPT_URL_ARRAY expectedUrl = { 1, &pUrl }; + + compareUrlArray(&expectedUrl, urlArray); + } + HeapFree(GetProcessHeap(), 0, urlArray); + } + /* or by specifying it's an extension: */ + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, NULL, &urlArraySize, NULL, + NULL, NULL); + ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError()); + urlArray = HeapAlloc(GetProcessHeap(), 0, urlArraySize); + if (urlArray) + { + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, CRYPT_GET_URL_FROM_EXTENSION, urlArray, + &urlArraySize, NULL, NULL, NULL); + ok(ret, "CryptGetObjectUrl failed: %08x\n", GetLastError()); + if (ret) + { + LPWSTR pUrl = url; + CRYPT_URL_ARRAY expectedUrl = { 1, &pUrl }; + + compareUrlArray(&expectedUrl, urlArray); + } + HeapFree(GetProcessHeap(), 0, urlArray); + } + /* but it isn't contained in a property: */ + SetLastError(0xdeadbeef); + ret = CryptGetObjectUrl(URL_OID_CERTIFICATE_CRL_DIST_POINT, + (void *)cert, CRYPT_GET_URL_FROM_PROPERTY, NULL, &urlArraySize, NULL, + NULL, NULL); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, + "Expected CRYPT_E_NOT_FOUND, got %08x\n", GetLastError()); + CertFreeCertificateContext(cert); + } +} + +static void make_tmp_file(LPSTR path) +{ + static char curr[MAX_PATH] = { 0 }; + char temp[MAX_PATH]; + DWORD dwNumberOfBytesWritten; + HANDLE hf; + + if (!*curr) + GetCurrentDirectoryA(MAX_PATH, curr); + GetTempFileNameA(curr, "net", 0, temp); + lstrcpyA(path, temp); + hf = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + WriteFile(hf, certWithCRLDistPoint, sizeof(certWithCRLDistPoint), + &dwNumberOfBytesWritten, NULL); + CloseHandle(hf); +} + +static void test_retrieveObjectByUrl(void) +{ + BOOL ret; + char tmpfile[MAX_PATH * 2], *ptr, url[MAX_PATH + 8]; + CRYPT_BLOB_ARRAY *pBlobArray; + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + HCERTSTORE store; + CRYPT_RETRIEVE_AUX_INFO aux = { 0 }; + FILETIME ft = { 0 }; + + SetLastError(0xdeadbeef); + ret = CryptRetrieveObjectByUrlA(NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL); + ok(!ret && (GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == E_INVALIDARG), + "got 0x%x/%u (expected ERROR_INVALID_PARAMETER or E_INVALIDARG)\n", + GetLastError(), GetLastError()); + + make_tmp_file(tmpfile); + ptr = strchr(tmpfile, ':'); + if (ptr) + ptr += 2; /* skip colon and first slash */ + else + ptr = tmpfile; + snprintf(url, sizeof(url), "file:///%s", ptr); + do { + ptr = strchr(url, '\\'); + if (ptr) + *ptr = '/'; + } while (ptr); + + pBlobArray = (CRYPT_BLOB_ARRAY *)0xdeadbeef; + ret = CryptRetrieveObjectByUrlA(url, NULL, 0, 0, (void **)&pBlobArray, + NULL, NULL, NULL, NULL); + if (!ret) + { + /* File URL support was apparently removed in Vista/Windows 2008 */ + win_skip("File URLs not supported\n"); + return; + } + ok(ret, "CryptRetrieveObjectByUrlA failed: %d\n", GetLastError()); + ok(pBlobArray && pBlobArray != (CRYPT_BLOB_ARRAY *)0xdeadbeef, + "Expected a valid pointer\n"); + if (pBlobArray && pBlobArray != (CRYPT_BLOB_ARRAY *)0xdeadbeef) + { + ok(pBlobArray->cBlob == 1, "Expected 1 blob, got %d\n", + pBlobArray->cBlob); + ok(pBlobArray->rgBlob[0].cbData == sizeof(certWithCRLDistPoint), + "Unexpected size %d\n", pBlobArray->rgBlob[0].cbData); + CryptMemFree(pBlobArray); + } + cert = (PCCERT_CONTEXT)0xdeadbeef; + ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, + (void **)&cert, NULL, NULL, NULL, NULL); + ok(cert && cert != (PCCERT_CONTEXT)0xdeadbeef, "Expected a cert\n"); + if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) + CertFreeCertificateContext(cert); + crl = (PCCRL_CONTEXT)0xdeadbeef; + SetLastError(0xdeadbeef); + ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CRL, 0, 0, (void **)&crl, + NULL, NULL, NULL, NULL); + /* w2k3,XP, newer w2k: CRYPT_E_NO_MATCH, 95: OSS_DATA_ERROR */ + ok(!ret && (GetLastError() == CRYPT_E_NO_MATCH || + GetLastError() == CRYPT_E_ASN1_BADTAG || + GetLastError() == OSS_DATA_ERROR), + "got 0x%x/%u (expected CRYPT_E_NO_MATCH or CRYPT_E_ASN1_BADTAG or " + "OSS_DATA_ERROR)\n", GetLastError(), GetLastError()); + + /* only newer versions of cryptnet do the cleanup */ + if(!ret && GetLastError() != CRYPT_E_ASN1_BADTAG && + GetLastError() != OSS_DATA_ERROR) { + ok(crl == NULL, "Expected CRL to be NULL\n"); + } + + if (crl && crl != (PCCRL_CONTEXT)0xdeadbeef) + CertFreeCRLContext(crl); + store = (HCERTSTORE)0xdeadbeef; + ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CAPI2_ANY, 0, 0, + &store, NULL, NULL, NULL, NULL); + ok(ret, "CryptRetrieveObjectByUrlA failed: %d\n", GetLastError()); + if (store && store != (HCERTSTORE)0xdeadbeef) + { + DWORD certs = 0; + + cert = NULL; + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + certs++; + } while (cert); + ok(certs == 1, "Expected 1 cert, got %d\n", certs); + CertCloseStore(store, 0); + } + /* Are file URLs cached? */ + cert = (PCCERT_CONTEXT)0xdeadbeef; + ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, + CRYPT_CACHE_ONLY_RETRIEVAL, 0, (void **)&cert, NULL, NULL, NULL, NULL); + ok(ret, "CryptRetrieveObjectByUrlA failed: %08x\n", GetLastError()); + if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) + CertFreeCertificateContext(cert); + + cert = (PCCERT_CONTEXT)0xdeadbeef; + ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, + (void **)&cert, NULL, NULL, NULL, &aux); + /* w2k: success, 9x: fail with E_INVALIDARG */ + ok(ret || (GetLastError() == E_INVALIDARG), + "got %u with 0x%x/%u (expected '!=0' or '0' with E_INVALIDARG)\n", + ret, GetLastError(), GetLastError()); + if (cert && cert != (PCCERT_CONTEXT)0xdeadbeef) + CertFreeCertificateContext(cert); + + cert = (PCCERT_CONTEXT)0xdeadbeef; + aux.cbSize = sizeof(aux); + ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, + (void **)&cert, NULL, NULL, NULL, &aux); + /* w2k: success, 9x: fail with E_INVALIDARG */ + ok(ret || (GetLastError() == E_INVALIDARG), + "got %u with 0x%x/%u (expected '!=0' or '0' with E_INVALIDARG)\n", + ret, GetLastError(), GetLastError()); + if (!ret) { + /* no more tests useful */ + DeleteFileA(tmpfile); + skip("no usable CertificateContext\n"); + return; + } + + aux.pLastSyncTime = &ft; + ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, 0, 0, + (void **)&cert, NULL, NULL, NULL, &aux); + ok(ft.dwLowDateTime || ft.dwHighDateTime, + "Expected last sync time to be set\n"); + DeleteFileA(tmpfile); + /* Okay, after being deleted, are file URLs still cached? */ + SetLastError(0xdeadbeef); + ret = CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CERTIFICATE, + CRYPT_CACHE_ONLY_RETRIEVAL, 0, (void **)&cert, NULL, NULL, NULL, NULL); + ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_PATH_NOT_FOUND), + "Expected ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND, got %d\n", + GetLastError()); +} + +START_TEST(cryptnet) +{ + test_getObjectUrl(); + test_retrieveObjectByUrl(); +} diff --git a/rostests/winetests/cryptnet/cryptnet.rbuild b/rostests/winetests/cryptnet/cryptnet.rbuild new file mode 100644 index 00000000000..309455432af --- /dev/null +++ b/rostests/winetests/cryptnet/cryptnet.rbuild @@ -0,0 +1,10 @@ + + . + + cryptnet.c + testlist.c + wine + cryptnet + crypt32 + ntdll + diff --git a/rostests/winetests/cryptnet/testlist.c b/rostests/winetests/cryptnet/testlist.c new file mode 100644 index 00000000000..5321c62f438 --- /dev/null +++ b/rostests/winetests/cryptnet/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_cryptnet(void); + +const struct test winetest_testlist[] = +{ + { "cryptnet", func_cryptnet }, + { 0, 0 } +}; diff --git a/rostests/winetests/cryptui/cryptui.c b/rostests/winetests/cryptui/cryptui.c new file mode 100644 index 00000000000..534d0e7f6ae --- /dev/null +++ b/rostests/winetests/cryptui/cryptui.c @@ -0,0 +1,664 @@ +/* + * Unit test suite for cryptui.dll + * + * Copyright 2008 Juan Lang + * + * 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 + */ +#include +#include +#define NONAMELESSUNION +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static BYTE v1CertWithValidPubKey[] = { +0x30,0x81,0xcf,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x5c,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x4b,0x00,0x30,0x48,0x02,0x41,0x00,0xe2,0x54,0x3a, +0xa7,0x83,0xb1,0x27,0x14,0x3e,0x59,0xbb,0xb4,0x53,0xe6,0x1f,0xe7,0x5d,0xf1, +0x21,0x68,0xad,0x85,0x53,0xdb,0x6b,0x1e,0xeb,0x65,0x97,0x03,0x86,0x60,0xde, +0xf3,0x6c,0x38,0x75,0xe0,0x4c,0x61,0xbb,0xbc,0x62,0x17,0xa9,0xcd,0x79,0x3f, +0x21,0x4e,0x96,0xcb,0x0e,0xdc,0x61,0x94,0x30,0x18,0x10,0x6b,0xd0,0x1c,0x10, +0x79,0x02,0x03,0x01,0x00,0x01,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,0x03,0x55, +0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01 }; +static const BYTE iTunesCert1[] = { +0x30,0x82,0x03,0xff,0x30,0x82,0x02,0xe7,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x0d,0xe9,0x2b,0xf0,0xd4,0xd8,0x29,0x88,0x18,0x32,0x05,0x09,0x5e,0x9a,0x76, +0x88,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72, +0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x2b,0x30,0x29, +0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e, +0x20,0x54,0x69,0x6d,0x65,0x20,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x20, +0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d, +0x30,0x33,0x31,0x32,0x30,0x34,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d, +0x30,0x38,0x31,0x32,0x30,0x33,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x57, +0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17, +0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69, +0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x2f,0x30,0x2d,0x06,0x03,0x55, +0x04,0x03,0x13,0x26,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x54,0x69, +0x6d,0x65,0x20,0x53,0x74,0x61,0x6d,0x70,0x69,0x6e,0x67,0x20,0x53,0x65,0x72, +0x76,0x69,0x63,0x65,0x73,0x20,0x53,0x69,0x67,0x6e,0x65,0x72,0x30,0x82,0x01, +0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, +0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00, +0xb2,0x50,0x28,0x48,0xdd,0xd3,0x68,0x7a,0x84,0x18,0x44,0x66,0x75,0x5d,0x7e, +0xc4,0xb8,0x9f,0x63,0x26,0xff,0x3d,0x43,0x9c,0x7c,0x11,0x38,0x10,0x25,0x55, +0x73,0xd9,0x75,0x27,0x69,0xfd,0x4e,0xb9,0x20,0x5c,0xd3,0x0a,0xf9,0xa0,0x1b, +0x2a,0xed,0x55,0x56,0x21,0x61,0xd8,0x1e,0xdb,0xe4,0xbc,0x33,0x6b,0xc7,0xef, +0xdd,0xa3,0x37,0x65,0x8e,0x1b,0x93,0x0c,0xb6,0x53,0x1e,0x5c,0x7c,0x66,0x35, +0x5f,0x05,0x8a,0x45,0xfe,0x76,0x4e,0xdf,0x53,0x80,0xa2,0x81,0x20,0x9d,0xae, +0x88,0x5c,0xa2,0x08,0xf7,0xe5,0x30,0xf9,0xee,0x22,0x37,0x4c,0x42,0x0a,0xce, +0xdf,0xc6,0x1f,0xc4,0xd6,0x55,0xe9,0x81,0x3f,0xb5,0x52,0xa3,0x2c,0xaa,0x01, +0x7a,0xf2,0xa2,0xaa,0x8d,0x35,0xfe,0x9f,0xe6,0x5d,0x6a,0x05,0x9f,0x3d,0x6b, +0xe3,0xbf,0x96,0xc0,0xfe,0xcc,0x60,0xf9,0x40,0xe7,0x07,0xa0,0x44,0xeb,0x81, +0x51,0x6e,0xa5,0x2a,0xf2,0xb6,0x8a,0x10,0x28,0xed,0x8f,0xdc,0x06,0xa0,0x86, +0x50,0x9a,0x7b,0x4a,0x08,0x0d,0x30,0x1d,0xca,0x10,0x9e,0x6b,0xf7,0xe9,0x58, +0xae,0x04,0xa9,0x40,0x99,0xb2,0x28,0xe8,0x8f,0x16,0xac,0x3c,0xe3,0x53,0x6f, +0x4b,0xd3,0x35,0x9d,0xb5,0x6f,0x64,0x1d,0xb3,0x96,0x2c,0xbb,0x3d,0xe7,0x79, +0xeb,0x6d,0x7a,0xf9,0x16,0xe6,0x26,0xad,0xaf,0xef,0x99,0x53,0xb7,0x40,0x2c, +0x95,0xb8,0x79,0xaa,0xfe,0xd4,0x52,0xab,0x29,0x74,0x7e,0x42,0xec,0x39,0x1e, +0xa2,0x6a,0x16,0xe6,0x59,0xbb,0x24,0x68,0xd8,0x00,0x80,0x43,0x10,0x87,0x80, +0x6b,0x02,0x03,0x01,0x00,0x01,0xa3,0x81,0xca,0x30,0x81,0xc7,0x30,0x34,0x06, +0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x28,0x30,0x26,0x30,0x24, +0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74, +0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e,0x76,0x65,0x72,0x69,0x73,0x69, +0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01, +0xff,0x04,0x02,0x30,0x00,0x30,0x33,0x06,0x03,0x55,0x1d,0x1f,0x04,0x2c,0x30, +0x2a,0x30,0x28,0xa0,0x26,0xa0,0x24,0x86,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f, +0x2f,0x63,0x72,0x6c,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63, +0x6f,0x6d,0x2f,0x74,0x73,0x73,0x2d,0x63,0x61,0x2e,0x63,0x72,0x6c,0x30,0x16, +0x06,0x03,0x55,0x1d,0x25,0x01,0x01,0xff,0x04,0x0c,0x30,0x0a,0x06,0x08,0x2b, +0x06,0x01,0x05,0x05,0x07,0x03,0x08,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01, +0x01,0xff,0x04,0x04,0x03,0x02,0x06,0xc0,0x30,0x24,0x06,0x03,0x55,0x1d,0x11, +0x04,0x1d,0x30,0x1b,0xa4,0x19,0x30,0x17,0x31,0x15,0x30,0x13,0x06,0x03,0x55, +0x04,0x03,0x13,0x0c,0x54,0x53,0x41,0x32,0x30,0x34,0x38,0x2d,0x31,0x2d,0x35, +0x34,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x03,0x82,0x01,0x01,0x00,0x87,0x78,0x70,0xda,0x4e,0x52,0x01,0x20,0x5b, +0xe0,0x79,0xc9,0x82,0x30,0xc4,0xfd,0xb9,0x19,0x96,0xbd,0x91,0x00,0xc3,0xbd, +0xcd,0xcd,0xc6,0xf4,0x0e,0xd8,0xff,0xf9,0x4d,0xc0,0x33,0x62,0x30,0x11,0xc5, +0xf5,0x74,0x1b,0xd4,0x92,0xde,0x5f,0x9c,0x20,0x13,0xb1,0x7c,0x45,0xbe,0x50, +0xcd,0x83,0xe7,0x80,0x17,0x83,0xa7,0x27,0x93,0x67,0x13,0x46,0xfb,0xca,0xb8, +0x98,0x41,0x03,0xcc,0x9b,0x51,0x5b,0x05,0x8b,0x7f,0xa8,0x6f,0xf3,0x1b,0x50, +0x1b,0x24,0x2e,0xf2,0x69,0x8d,0x6c,0x22,0xf7,0xbb,0xca,0x16,0x95,0xed,0x0c, +0x74,0xc0,0x68,0x77,0xd9,0xeb,0x99,0x62,0x87,0xc1,0x73,0x90,0xf8,0x89,0x74, +0x7a,0x23,0xab,0xa3,0x98,0x7b,0x97,0xb1,0xf7,0x8f,0x29,0x71,0x4d,0x2e,0x75, +0x1b,0x48,0x41,0xda,0xf0,0xb5,0x0d,0x20,0x54,0xd6,0x77,0xa0,0x97,0x82,0x63, +0x69,0xfd,0x09,0xcf,0x8a,0xf0,0x75,0xbb,0x09,0x9b,0xd9,0xf9,0x11,0x55,0x26, +0x9a,0x61,0x32,0xbe,0x7a,0x02,0xb0,0x7b,0x86,0xbe,0xa2,0xc3,0x8b,0x22,0x2c, +0x78,0xd1,0x35,0x76,0xbc,0x92,0x73,0x5c,0xf9,0xb9,0xe6,0x4c,0x15,0x0a,0x23, +0xcc,0xe4,0xd2,0xd4,0x34,0x2e,0x49,0x40,0x15,0x3c,0x0f,0x60,0x7a,0x24,0xc6, +0xa5,0x66,0xef,0x96,0xcf,0x70,0xeb,0x3e,0xe7,0xf4,0x0d,0x7e,0xdc,0xd1,0x7c, +0xa3,0x76,0x71,0x69,0xc1,0x9c,0x4f,0x47,0x30,0x35,0x21,0xb1,0xa2,0xaf,0x1a, +0x62,0x3c,0x2b,0xd9,0x8e,0xaa,0x2a,0x07,0x7b,0xd8,0x18,0xb3,0x5c,0x7b,0xe2, +0x9d,0xa5,0x6f,0xfe,0x3c,0x89,0xad }; +static const BYTE iTunesCert2[] = { +0x30,0x82,0x04,0xbf,0x30,0x82,0x04,0x28,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x41,0x91,0xa1,0x5a,0x39,0x78,0xdf,0xcf,0x49,0x65,0x66,0x38,0x1d,0x4c,0x75, +0xc2,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x5f,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55, +0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72, +0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x37,0x30,0x35, +0x06,0x03,0x55,0x04,0x0b,0x13,0x2e,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20, +0x50,0x75,0x62,0x6c,0x69,0x63,0x20,0x50,0x72,0x69,0x6d,0x61,0x72,0x79,0x20, +0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41, +0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x30,0x1e,0x17,0x0d,0x30,0x34,0x30, +0x37,0x31,0x36,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x31,0x34,0x30, +0x37,0x31,0x35,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xb4,0x31,0x0b, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30,0x15, +0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e, +0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x0b, +0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20,0x54,0x72,0x75,0x73, +0x74,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x3b,0x30,0x39,0x06,0x03, +0x55,0x04,0x0b,0x13,0x32,0x54,0x65,0x72,0x6d,0x73,0x20,0x6f,0x66,0x20,0x75, +0x73,0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77, +0x77,0x77,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d, +0x2f,0x72,0x70,0x61,0x20,0x28,0x63,0x29,0x30,0x34,0x31,0x2e,0x30,0x2c,0x06, +0x03,0x55,0x04,0x03,0x13,0x25,0x56,0x65,0x72,0x69,0x53,0x69,0x67,0x6e,0x20, +0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x43,0x6f,0x64,0x65,0x20,0x53,0x69, +0x67,0x6e,0x69,0x6e,0x67,0x20,0x32,0x30,0x30,0x34,0x20,0x43,0x41,0x30,0x82, +0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, +0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01, +0x00,0xbe,0xbc,0xee,0xbc,0x7e,0xef,0x83,0xeb,0xe0,0x37,0x4f,0xfb,0x03,0x10, +0x38,0xbe,0x08,0xd2,0x8c,0x7d,0x9d,0xfa,0x92,0x7f,0x19,0x0c,0xc2,0x6b,0xee, +0x42,0x52,0x8c,0xde,0xd3,0x1c,0x48,0x13,0x25,0xea,0xc1,0x63,0x7a,0xf9,0x51, +0x65,0xee,0xd3,0xaa,0x3b,0xf5,0xf0,0x94,0x9c,0x2b,0xfb,0xf2,0x66,0xd4,0x24, +0xda,0xf7,0xf5,0x9f,0x6e,0x19,0x39,0x36,0xbc,0xd0,0xa3,0x76,0x08,0x1e,0x22, +0x27,0x24,0x6c,0x38,0x91,0x27,0xe2,0x84,0x49,0xae,0x1b,0x8a,0xa1,0xfd,0x25, +0x82,0x2c,0x10,0x30,0xe8,0x71,0xab,0x28,0xe8,0x77,0x4a,0x51,0xf1,0xec,0xcd, +0xf8,0xf0,0x54,0xd4,0x6f,0xc0,0xe3,0x6d,0x0a,0x8f,0xd9,0xd8,0x64,0x8d,0x63, +0xb2,0x2d,0x4e,0x27,0xf6,0x85,0x0e,0xfe,0x6d,0xe3,0x29,0x99,0xe2,0x85,0x47, +0x7c,0x2d,0x86,0x7f,0xe8,0x57,0x8f,0xad,0x67,0xc2,0x33,0x32,0x91,0x13,0x20, +0xfc,0xa9,0x23,0x14,0x9a,0x6d,0xc2,0x84,0x4b,0x76,0x68,0x04,0xd5,0x71,0x2c, +0x5d,0x21,0xfa,0x88,0x0d,0x26,0xfd,0x1f,0x2d,0x91,0x2b,0xe7,0x01,0x55,0x4d, +0xf2,0x6d,0x35,0x28,0x82,0xdf,0xd9,0x6b,0x5c,0xb6,0xd6,0xd9,0xaa,0x81,0xfd, +0x5f,0xcd,0x83,0xba,0x63,0x9d,0xd0,0x22,0xfc,0xa9,0x3b,0x42,0x69,0xb2,0x8e, +0x3a,0xb5,0xbc,0xb4,0x9e,0x0f,0x5e,0xc4,0xea,0x2c,0x82,0x8b,0x28,0xfd,0x53, +0x08,0x96,0xdd,0xb5,0x01,0x20,0xd1,0xf9,0xa5,0x18,0xe7,0xc0,0xee,0x51,0x70, +0x37,0xe1,0xb6,0x05,0x48,0x52,0x48,0x6f,0x38,0xea,0xc3,0xe8,0x6c,0x7b,0x44, +0x84,0xbb,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xa0,0x30,0x82,0x01,0x9c, +0x30,0x12,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01, +0x01,0xff,0x02,0x01,0x00,0x30,0x44,0x06,0x03,0x55,0x1d,0x20,0x04,0x3d,0x30, +0x3b,0x30,0x39,0x06,0x0b,0x60,0x86,0x48,0x01,0x86,0xf8,0x45,0x01,0x07,0x17, +0x03,0x30,0x2a,0x30,0x28,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01, +0x16,0x1c,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76, +0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61, +0x30,0x31,0x06,0x03,0x55,0x1d,0x1f,0x04,0x2a,0x30,0x28,0x30,0x26,0xa0,0x24, +0xa0,0x22,0x86,0x20,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e, +0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x70,0x63, +0x61,0x33,0x2e,0x63,0x72,0x6c,0x30,0x1d,0x06,0x03,0x55,0x1d,0x25,0x04,0x16, +0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x08,0x2b, +0x06,0x01,0x05,0x05,0x07,0x03,0x03,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01, +0x01,0xff,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x11,0x06,0x09,0x60,0x86,0x48, +0x01,0x86,0xf8,0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x00,0x01,0x30,0x29,0x06, +0x03,0x55,0x1d,0x11,0x04,0x22,0x30,0x20,0xa4,0x1e,0x30,0x1c,0x31,0x1a,0x30, +0x18,0x06,0x03,0x55,0x04,0x03,0x13,0x11,0x43,0x6c,0x61,0x73,0x73,0x33,0x43, +0x41,0x32,0x30,0x34,0x38,0x2d,0x31,0x2d,0x34,0x33,0x30,0x1d,0x06,0x03,0x55, +0x1d,0x0e,0x04,0x16,0x04,0x14,0x08,0xf5,0x51,0xe8,0xfb,0xfe,0x3d,0x3d,0x64, +0x36,0x7c,0x68,0xcf,0x5b,0x78,0xa8,0xdf,0xb9,0xc5,0x37,0x30,0x81,0x80,0x06, +0x03,0x55,0x1d,0x23,0x04,0x79,0x30,0x77,0xa1,0x63,0xa4,0x61,0x30,0x5f,0x31, +0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x17,0x30, +0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x37,0x30,0x35,0x06,0x03,0x55,0x04, +0x0b,0x13,0x2e,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x50,0x75,0x62,0x6c, +0x69,0x63,0x20,0x50,0x72,0x69,0x6d,0x61,0x72,0x79,0x20,0x43,0x65,0x72,0x74, +0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f, +0x72,0x69,0x74,0x79,0x82,0x10,0x70,0xba,0xe4,0x1d,0x10,0xd9,0x29,0x34,0xb6, +0x38,0xca,0x7b,0x03,0xcc,0xba,0xbf,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86, +0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x81,0x81,0x00,0xae,0x3a,0x17,0xb8, +0x4a,0x7b,0x55,0xfa,0x64,0x55,0xec,0x40,0xa4,0xed,0x49,0x41,0x90,0x99,0x9c, +0x89,0xbc,0xaf,0x2e,0x1d,0xca,0x78,0x23,0xf9,0x1c,0x19,0x0f,0x7f,0xeb,0x68, +0xbc,0x32,0xd9,0x88,0x38,0xde,0xdc,0x3f,0xd3,0x89,0xb4,0x3f,0xb1,0x82,0x96, +0xf1,0xa4,0x5a,0xba,0xed,0x2e,0x26,0xd3,0xde,0x7c,0x01,0x6e,0x00,0x0a,0x00, +0xa4,0x06,0x92,0x11,0x48,0x09,0x40,0xf9,0x1c,0x18,0x79,0x67,0x23,0x24,0xe0, +0xbb,0xd5,0xe1,0x50,0xae,0x1b,0xf5,0x0e,0xdd,0xe0,0x2e,0x81,0xcd,0x80,0xa3, +0x6c,0x52,0x4f,0x91,0x75,0x55,0x8a,0xba,0x22,0xf2,0xd2,0xea,0x41,0x75,0x88, +0x2f,0x63,0x55,0x7d,0x1e,0x54,0x5a,0x95,0x59,0xca,0xd9,0x34,0x81,0xc0,0x5f, +0x5e,0xf6,0x7a,0xb5 }; +static const BYTE iTunesCert3[] = { +0x30,0x82,0x04,0xf1,0x30,0x82,0x03,0xd9,0xa0,0x03,0x02,0x01,0x02,0x02,0x10, +0x0f,0x1a,0xa0,0xe0,0x9b,0x9b,0x61,0xa6,0xb6,0xfe,0x40,0xd2,0xdf,0x6a,0xf6, +0x8d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05, +0x00,0x30,0x81,0xb4,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, +0x55,0x53,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x56,0x65, +0x72,0x69,0x53,0x69,0x67,0x6e,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x31,0x1f,0x30, +0x1d,0x06,0x03,0x55,0x04,0x0b,0x13,0x16,0x56,0x65,0x72,0x69,0x53,0x69,0x67, +0x6e,0x20,0x54,0x72,0x75,0x73,0x74,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b, +0x31,0x3b,0x30,0x39,0x06,0x03,0x55,0x04,0x0b,0x13,0x32,0x54,0x65,0x72,0x6d, +0x73,0x20,0x6f,0x66,0x20,0x75,0x73,0x65,0x20,0x61,0x74,0x20,0x68,0x74,0x74, +0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76,0x65,0x72,0x69,0x73,0x69, +0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61,0x20,0x28,0x63,0x29,0x30, +0x34,0x31,0x2e,0x30,0x2c,0x06,0x03,0x55,0x04,0x03,0x13,0x25,0x56,0x65,0x72, +0x69,0x53,0x69,0x67,0x6e,0x20,0x43,0x6c,0x61,0x73,0x73,0x20,0x33,0x20,0x43, +0x6f,0x64,0x65,0x20,0x53,0x69,0x67,0x6e,0x69,0x6e,0x67,0x20,0x32,0x30,0x30, +0x34,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x30,0x36,0x30,0x31,0x31,0x37,0x30, +0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x30,0x38,0x30,0x31,0x32,0x32,0x32, +0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xb4,0x31,0x0b,0x30,0x09,0x06,0x03, +0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04, +0x08,0x13,0x0a,0x43,0x61,0x6c,0x69,0x66,0x6f,0x72,0x6e,0x69,0x61,0x31,0x12, +0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13,0x09,0x43,0x75,0x70,0x65,0x72,0x74, +0x69,0x6e,0x6f,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55,0x04,0x0a,0x14,0x14,0x41, +0x70,0x70,0x6c,0x65,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x2c,0x20, +0x49,0x6e,0x63,0x2e,0x31,0x3e,0x30,0x3c,0x06,0x03,0x55,0x04,0x0b,0x13,0x35, +0x44,0x69,0x67,0x69,0x74,0x61,0x6c,0x20,0x49,0x44,0x20,0x43,0x6c,0x61,0x73, +0x73,0x20,0x33,0x20,0x2d,0x20,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74, +0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x56,0x61,0x6c,0x69,0x64, +0x61,0x74,0x69,0x6f,0x6e,0x20,0x76,0x32,0x31,0x1d,0x30,0x1b,0x06,0x03,0x55, +0x04,0x03,0x14,0x14,0x41,0x70,0x70,0x6c,0x65,0x20,0x43,0x6f,0x6d,0x70,0x75, +0x74,0x65,0x72,0x2c,0x20,0x49,0x6e,0x63,0x2e,0x30,0x81,0x9f,0x30,0x0d,0x06, +0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8d, +0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xd3,0xab,0x3b,0x7f,0xec,0x48,0x84, +0xce,0xa8,0x1a,0x12,0xf3,0x3c,0x87,0xcb,0x24,0x58,0x96,0x02,0x87,0x66,0x49, +0xeb,0x89,0xee,0x79,0x44,0x70,0x8d,0xe7,0xd4,0x1f,0x30,0x92,0xc0,0x9c,0x35, +0x78,0xc0,0xaf,0x1c,0xb6,0x28,0xd3,0xe0,0xe0,0x9d,0xd3,0x49,0x76,0x73,0x57, +0x19,0x4d,0x8d,0x70,0x85,0x64,0x4d,0x1d,0xc6,0x02,0x3e,0xe5,0x2c,0x66,0x07, +0xd2,0x27,0x4b,0xd6,0xc8,0x3c,0x93,0xb6,0x15,0x0c,0xde,0x5b,0xd7,0x93,0xdd, +0xbe,0x85,0x62,0x34,0x17,0x8a,0x05,0x60,0xf0,0x8a,0x1c,0x5a,0x40,0x21,0x8d, +0x51,0x6c,0xb0,0x62,0xd8,0xb5,0xd4,0xf9,0xb1,0xd0,0x58,0x7a,0x7a,0x82,0x55, +0xb3,0xf9,0x53,0x71,0xde,0xd2,0xc9,0x37,0x8c,0xf6,0x5a,0x1f,0x2d,0xcd,0x7c, +0x67,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0x7f,0x30,0x82,0x01,0x7b,0x30, +0x09,0x06,0x03,0x55,0x1d,0x13,0x04,0x02,0x30,0x00,0x30,0x0e,0x06,0x03,0x55, +0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x07,0x80,0x30,0x40,0x06,0x03, +0x55,0x1d,0x1f,0x04,0x39,0x30,0x37,0x30,0x35,0xa0,0x33,0xa0,0x31,0x86,0x2f, +0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30, +0x34,0x2d,0x63,0x72,0x6c,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e, +0x63,0x6f,0x6d,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2e,0x63, +0x72,0x6c,0x30,0x44,0x06,0x03,0x55,0x1d,0x20,0x04,0x3d,0x30,0x3b,0x30,0x39, +0x06,0x0b,0x60,0x86,0x48,0x01,0x86,0xf8,0x45,0x01,0x07,0x17,0x03,0x30,0x2a, +0x30,0x28,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1c,0x68, +0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x76,0x65,0x72,0x69, +0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f,0x72,0x70,0x61,0x30,0x13,0x06, +0x03,0x55,0x1d,0x25,0x04,0x0c,0x30,0x0a,0x06,0x08,0x2b,0x06,0x01,0x05,0x05, +0x07,0x03,0x03,0x30,0x75,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01, +0x04,0x69,0x30,0x67,0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30, +0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e, +0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x30,0x3f,0x06, +0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x33,0x68,0x74,0x74,0x70, +0x3a,0x2f,0x2f,0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2d,0x61,0x69, +0x61,0x2e,0x76,0x65,0x72,0x69,0x73,0x69,0x67,0x6e,0x2e,0x63,0x6f,0x6d,0x2f, +0x43,0x53,0x43,0x33,0x2d,0x32,0x30,0x30,0x34,0x2d,0x61,0x69,0x61,0x2e,0x63, +0x65,0x72,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14, +0x08,0xf5,0x51,0xe8,0xfb,0xfe,0x3d,0x3d,0x64,0x36,0x7c,0x68,0xcf,0x5b,0x78, +0xa8,0xdf,0xb9,0xc5,0x37,0x30,0x11,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xf8, +0x42,0x01,0x01,0x04,0x04,0x03,0x02,0x04,0x10,0x30,0x16,0x06,0x0a,0x2b,0x06, +0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x1b,0x04,0x08,0x30,0x06,0x01,0x01,0x00, +0x01,0x01,0xff,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01, +0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x6a,0xa6,0x06,0xd0,0x33,0x18,0x64, +0xe2,0x69,0x82,0xee,0x6e,0x36,0x9e,0x9d,0x9a,0x0e,0x18,0xa8,0xac,0x9d,0x10, +0xed,0x01,0x3c,0xb9,0x61,0x04,0x62,0xf3,0x85,0x8f,0xcc,0x4f,0x2c,0x66,0x35, +0x54,0x25,0x45,0x8d,0x95,0x1c,0xd2,0x33,0xbe,0x2e,0xdd,0x7f,0x74,0xaf,0x03, +0x7b,0x86,0x63,0xb0,0xc9,0xe6,0xbd,0xc7,0x8e,0xde,0x03,0x18,0x98,0x82,0xc3, +0xbb,0xf8,0x15,0x99,0x1a,0xa9,0xdd,0xb9,0x5d,0xb9,0xbd,0x53,0x95,0x25,0x76, +0xfb,0x5c,0x53,0x90,0xea,0x01,0x0a,0xa0,0xb1,0xbf,0x09,0x1b,0x97,0x8f,0x40, +0xfa,0x85,0x12,0x74,0x01,0xdb,0xf6,0xdb,0x09,0xd6,0x5f,0x4f,0xd7,0x17,0xb4, +0xbf,0x9e,0x2f,0x86,0x52,0x5d,0x70,0x24,0x52,0x32,0x1e,0xa5,0x1d,0x39,0x8b, +0x66,0xf6,0xba,0x9b,0x69,0x8e,0x12,0x60,0xdb,0xb6,0xcf,0xe6,0x0d,0xd6,0x1c, +0x8f,0xd4,0x5b,0x4b,0x00,0xde,0x21,0x93,0xfb,0x6e,0xc7,0x3d,0xb4,0x66,0x0d, +0x29,0x0c,0x4e,0xe9,0x3f,0x94,0xd6,0xd6,0xdc,0xec,0xf8,0x53,0x3b,0x62,0xd5, +0x97,0x50,0x53,0x84,0x17,0xfe,0xe2,0xed,0x4c,0x23,0x0a,0x49,0xce,0x5b,0xe9, +0x70,0x31,0xc1,0x04,0x02,0x02,0x6c,0xb8,0x52,0xcd,0xc7,0x4e,0x70,0xb4,0x13, +0xd7,0xe0,0x92,0xba,0x44,0x1a,0x10,0x4c,0x6e,0x45,0xc6,0x86,0x04,0xc6,0x64, +0xd3,0x9c,0x6e,0xc1,0x9c,0xac,0x74,0x3d,0x77,0x06,0x5e,0x28,0x28,0x5c,0xf5, +0xe0,0x9c,0x19,0xd8,0xba,0x74,0x81,0x2d,0x67,0x77,0x93,0x8d,0xbf,0xd2,0x52, +0x00,0xe6,0xa5,0x38,0x4e,0x2e,0x73,0x66,0x7a }; +static const BYTE signedCRL[] = { 0x30, 0x45, 0x30, 0x2c, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x18, 0x0f, + 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x30, 0x02, 0x06, 0x00, 0x03, 0x11, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, + 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; + +/* CBT hook to ensure a window (e.g., MessageBox) cannot be created */ +static HHOOK hook; +static LRESULT CALLBACK cbt_hook_proc(int code, WPARAM wp, LPARAM lp) +{ + return code == HCBT_CREATEWND ? 1: CallNextHookEx(hook, code, wp, lp); +} + +static BOOL (WINAPI *pCryptUIWizImport)(DWORD dwFlags, HWND hwndParent, + LPCWSTR pwszWizardTitle, PCCRYPTUI_WIZ_IMPORT_SRC_INFO pImportSrc, + HCERTSTORE hDestCertStore); + +static BOOL find_and_delete_cert_in_store(HCERTSTORE store, PCCERT_CONTEXT cert) +{ + CERT_ID id; + PCCERT_CONTEXT found; + + id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; + memcpy(&id.u.IssuerSerialNumber.Issuer, + &cert->pCertInfo->Issuer, sizeof(CERT_NAME_BLOB)); + memcpy(&id.u.IssuerSerialNumber.SerialNumber, + &cert->pCertInfo->SerialNumber, sizeof(CRYPT_INTEGER_BLOB)); + found = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, + CERT_FIND_CERT_ID, &id, NULL); + if (!found) + return FALSE; + + CertDeleteCertificateFromStore(found); + CertFreeCertificateContext(found); + + return TRUE; +} + +static void test_crypt_ui_wiz_import(void) +{ + BOOL ret; + CRYPTUI_WIZ_IMPORT_SRC_INFO info; + HCERTSTORE store; + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + DWORD count; + + if (!pCryptUIWizImport) + { + skip("No CryptUIWizImport\n"); + return; + } + + /* Set CBT hook to disallow MessageBox and wizard creation in current + * thread. + */ + hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); + + /* Brings up UI. Cancelling yields ret = 1. */ + if (0) + { + ret = pCryptUIWizImport(0, 0, NULL, NULL, NULL); + } + SetLastError(0xdeadbeef); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI, 0, NULL, NULL, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + memset(&info, 0, sizeof(info)); + SetLastError(0xdeadbeef); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI, 0, NULL, &info, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + info.dwSize = sizeof(info); + SetLastError(0xdeadbeef); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI, 0, NULL, &info, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + info.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT; + SetLastError(0xdeadbeef); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI, 0, NULL, &info, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CERT, + 0, NULL, &info, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + /* Check allowed vs. given type mismatches */ + info.u.pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, + v1CertWithValidPubKey, sizeof(v1CertWithValidPubKey)); + SetLastError(0xdeadbeef); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CRL, + 0, NULL, &info, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + CertFreeCertificateContext(info.u.pCertContext); + info.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_CRL_CONTEXT; + info.u.pCRLContext = CertCreateCRLContext(X509_ASN_ENCODING, + signedCRL, sizeof(signedCRL)); + SetLastError(0xdeadbeef); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CERT, + 0, NULL, &info, NULL); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + CertFreeCRLContext(info.u.pCRLContext); + /* Imports the following cert--self-signed, with no basic constraints set-- + * to the CA store. Puts up a dialog at the end if it succeeds or fails. + */ + info.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_CONTEXT; + info.u.pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, + v1CertWithValidPubKey, sizeof(v1CertWithValidPubKey)); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI, 0, NULL, &info, NULL); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + if (ret) + { + static const WCHAR CA[] = { 'C','A',0 }; + HCERTSTORE ca = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER, CA); + + if (ca) + { + ret = find_and_delete_cert_in_store(ca, info.u.pCertContext); + ok(ret || + broken(!ret) /* Win9x/NT4 */, + "expected to find v1CertWithValidPubKey in CA store\n"); + CertCloseStore(ca, 0); + } + } + CertFreeCertificateContext(info.u.pCertContext); + /* Imports the following cert--not self-signed, with a basic constraints2 + * extensions--to the "AddressBook" store. Puts up a dialog at the end if + * it succeeds or fails. + */ + info.u.pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, + iTunesCert3, sizeof(iTunesCert3)); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI, 0, NULL, &info, NULL); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + if (ret) + { + static const WCHAR AddressBook[] = { 'A','d','d','r','e','s','s', + 'B','o','o','k',0 }; + HCERTSTORE addressBook = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER, AddressBook); + + if (addressBook) + { + ret = find_and_delete_cert_in_store(addressBook, + info.u.pCertContext); + ok(ret || + broken(!ret), /* Windows 2000 and earlier */ + "expected to find iTunesCert3 in AddressBook store\n"); + CertCloseStore(addressBook, 0); + } + } + /* Displays the wizard, but disables the "Certificate store" edit and + * the Browse button. Confusingly, the "Place all certificates in the + * following store" radio button is not disabled. + */ + if (0) + { + ret = pCryptUIWizImport(CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE, 0, + NULL, &info, NULL); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + } + store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + /* Displays the wizard, but sets the "Certificate store" edit to the + * string "Determined by the program", and disables it and the Browse + * button, as well as the "Automatically select the certificate store + * based on the type of certificate" radio button. + */ + if (0) + { + ret = pCryptUIWizImport(CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE, 0, + NULL, &info, store); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + } + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI | + CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE, 0, NULL, &info, store); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + ret = find_and_delete_cert_in_store(store, info.u.pCertContext); + ok(ret || + broken(!ret) /* Win9x/NT4 */, + "expected to find iTunesCert3 in memory store\n"); + CertFreeCertificateContext(info.u.pCertContext); + CertCloseStore(store, 0); + + info.u.pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, + iTunesCert1, sizeof(iTunesCert1)); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI, 0, NULL, &info, NULL); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + if (ret) + { + static const WCHAR AddressBook[] = { 'A','d','d','r','e','s','s', + 'B','o','o','k',0 }; + HCERTSTORE addressBook = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER, AddressBook); + + if (addressBook) + { + ret = find_and_delete_cert_in_store(addressBook, + info.u.pCertContext); + ok(ret || + broken(!ret), /* Windows 2000 and earlier */ + "expected to find iTunesCert1 in AddressBook store\n"); + CertCloseStore(addressBook, 0); + } + } + CertFreeCertificateContext(info.u.pCertContext); + + info.u.pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, + iTunesCert2, sizeof(iTunesCert2)); + ret = pCryptUIWizImport(CRYPTUI_WIZ_NO_UI, 0, NULL, &info, NULL); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + if (ret) + { + static const WCHAR CA[] = { 'C','A',0 }; + HCERTSTORE ca = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, + CERT_SYSTEM_STORE_CURRENT_USER, CA); + + if (ca) + { + ret = find_and_delete_cert_in_store(ca, info.u.pCertContext); + ok(ret || + broken(!ret) /* Win9x/NT4 */, + "expected to find iTunesCert2 in CA store\n"); + CertCloseStore(ca, 0); + } + } + CertFreeCertificateContext(info.u.pCertContext); + + info.u.hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(info.u.hCertStore, X509_ASN_ENCODING, + v1CertWithValidPubKey, sizeof(v1CertWithValidPubKey), + CERT_STORE_ADD_ALWAYS, NULL); + CertAddEncodedCRLToStore(info.u.hCertStore, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL); + info.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_CERT_STORE; + /* The ALLOW flags aren't allowed with a store as the source if the source + * contains types other than those allowed. + */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + SetLastError(0xdeadbeef); + ret = CryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CERT, + 0, NULL, &info, store); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CRL, + 0, NULL, &info, store); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = CryptUIWizImport(CRYPTUI_WIZ_NO_UI | + CRYPTUI_WIZ_IMPORT_NO_CHANGE_DEST_STORE | + CRYPTUI_WIZ_IMPORT_ALLOW_CERT | CRYPTUI_WIZ_IMPORT_ALLOW_CRL, 0, NULL, + &info, store); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + if (ret) + { + count = 0; + cert = NULL; + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + count++; + } while (cert); + ok(count == 1, "expected 1 cert, got %d\n", count); + count = 0; + crl = NULL; + do { + crl = CertEnumCRLsInStore(store, crl); + if (crl) + count++; + } while (cert); + ok(count == 1, "expected 1 CRL, got %d\n", count); + } + CertCloseStore(store, 0); + CertCloseStore(info.u.hCertStore, 0); + + /* If the ALLOW flags match the content of the store, the store can be + * imported. + */ + info.u.hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(info.u.hCertStore, X509_ASN_ENCODING, + v1CertWithValidPubKey, sizeof(v1CertWithValidPubKey), + CERT_STORE_ADD_ALWAYS, NULL); + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + SetLastError(0xdeadbeef); + ret = CryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CERT, + 0, NULL, &info, store); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + if (ret) + { + count = 0; + cert = NULL; + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + count++; + } while (cert); + ok(count == 1, "expected 1 cert, got %d\n", count); + count = 0; + crl = NULL; + do { + crl = CertEnumCRLsInStore(store, crl); + if (crl) + count++; + } while (cert); + ok(count == 0, "expected 0 CRLs, got %d\n", count); + } + SetLastError(0xdeadbeef); + ret = CryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CRL, + 0, NULL, &info, store); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + CertCloseStore(store, 0); + CertCloseStore(info.u.hCertStore, 0); + + /* Again, if the ALLOW flags match the content of the store, the store can + * be imported. + */ + info.u.hCertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCRLToStore(info.u.hCertStore, X509_ASN_ENCODING, signedCRL, + sizeof(signedCRL), CERT_STORE_ADD_ALWAYS, NULL); + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + SetLastError(0xdeadbeef); + ret = CryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CRL, + 0, NULL, &info, store); + ok(ret, "CryptUIWizImport failed: %08x\n", GetLastError()); + if (ret) + { + count = 0; + cert = NULL; + do { + cert = CertEnumCertificatesInStore(store, cert); + if (cert) + count++; + } while (cert); + ok(count == 0, "expected 0 certs, got %d\n", count); + count = 0; + crl = NULL; + do { + crl = CertEnumCRLsInStore(store, crl); + if (crl) + count++; + } while (cert); + ok(count == 1, "expected 1 CRL, got %d\n", count); + } + SetLastError(0xdeadbeef); + ret = CryptUIWizImport(CRYPTUI_WIZ_NO_UI | CRYPTUI_WIZ_IMPORT_ALLOW_CERT, + 0, NULL, &info, store); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + CertCloseStore(store, 0); + CertCloseStore(info.u.hCertStore, 0); + + UnhookWindowsHookEx(hook); +} + +START_TEST(cryptui) +{ + HMODULE lib = LoadLibraryA("cryptui"); + + if (lib) + { + pCryptUIWizImport = (void *)GetProcAddress(lib, "CryptUIWizImport"); + + test_crypt_ui_wiz_import(); + FreeLibrary(lib); + } +} diff --git a/rostests/winetests/cryptui/cryptui.rbuild b/rostests/winetests/cryptui/cryptui.rbuild new file mode 100644 index 00000000000..2c6daf31b46 --- /dev/null +++ b/rostests/winetests/cryptui/cryptui.rbuild @@ -0,0 +1,10 @@ + + . + + cryptui.c + testlist.c + wine + cryptui + crypt32 + user32 + ntdll diff --git a/rostests/winetests/cryptui/testlist.c b/rostests/winetests/cryptui/testlist.c new file mode 100644 index 00000000000..315bb4fe129 --- /dev/null +++ b/rostests/winetests/cryptui/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_cryptui(void); + +const struct test winetest_testlist[] = +{ + { "cryptui", func_cryptui }, + { 0, 0 } +}; diff --git a/rostests/winetests/directory.rbuild b/rostests/winetests/directory.rbuild index 99192fce6f8..f774eb8b6e6 100644 --- a/rostests/winetests/directory.rbuild +++ b/rostests/winetests/directory.rbuild @@ -22,6 +22,24 @@ + + + + + + + + + + + + + + + + + + @@ -37,9 +55,30 @@ + + + + + + + + + + + + + + + + + + + + + @@ -52,33 +91,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + @@ -100,21 +178,42 @@ + + + + + + + + + + + + + + + + + + + + + @@ -124,12 +223,28 @@ + + + - + + - --> diff --git a/rostests/winetests/dnsapi/dnsapi.rbuild b/rostests/winetests/dnsapi/dnsapi.rbuild new file mode 100644 index 00000000000..918d8d6f49e --- /dev/null +++ b/rostests/winetests/dnsapi/dnsapi.rbuild @@ -0,0 +1,10 @@ + + . + + name.c + record.c + testlist.c + wine + dnsapi + ntdll + diff --git a/rostests/winetests/dnsapi/name.c b/rostests/winetests/dnsapi/name.c new file mode 100644 index 00000000000..d472687b9d3 --- /dev/null +++ b/rostests/winetests/dnsapi/name.c @@ -0,0 +1,208 @@ +/* + * Tests for name handling functions + * + * Copyright 2006 Hans Leidekker + * + * 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 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "windns.h" + +#include "wine/test.h" + +static const struct +{ + LPCSTR name; + DNS_NAME_FORMAT format; + DNS_STATUS status; +} +test_data[] = +{ + { "", DnsNameDomain, ERROR_INVALID_NAME }, + { ".", DnsNameDomain, ERROR_SUCCESS }, + { "..", DnsNameDomain, ERROR_INVALID_NAME }, + { ".a", DnsNameDomain, ERROR_INVALID_NAME }, + { "a.", DnsNameDomain, ERROR_SUCCESS }, + { "a..", DnsNameDomain, ERROR_INVALID_NAME }, + { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", DnsNameDomain, ERROR_INVALID_NAME }, + { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", DnsNameDomain, ERROR_INVALID_NAME }, + { "a.?", DnsNameDomain, DNS_ERROR_INVALID_NAME_CHAR }, + { "a.*", DnsNameDomain, DNS_ERROR_INVALID_NAME_CHAR }, + { "a ", DnsNameDomain, DNS_ERROR_INVALID_NAME_CHAR }, + { "a._b", DnsNameDomain, DNS_ERROR_NON_RFC_NAME }, + { "123", DnsNameDomain, DNS_ERROR_NUMERIC_NAME }, + { "123.456", DnsNameDomain, DNS_ERROR_NUMERIC_NAME }, + { "a.b", DnsNameDomain, ERROR_SUCCESS }, + + { "", DnsNameDomainLabel, ERROR_INVALID_NAME }, + { ".", DnsNameDomainLabel, ERROR_INVALID_NAME }, + { "..", DnsNameDomainLabel, ERROR_INVALID_NAME }, + { ".c", DnsNameDomainLabel, ERROR_INVALID_NAME }, + { "c.", DnsNameDomainLabel, ERROR_INVALID_NAME }, + { "c..", DnsNameDomainLabel, ERROR_INVALID_NAME }, + { "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", DnsNameDomainLabel, ERROR_INVALID_NAME }, + { "?", DnsNameDomainLabel, DNS_ERROR_INVALID_NAME_CHAR }, + { "*", DnsNameDomainLabel, DNS_ERROR_INVALID_NAME_CHAR }, + { "c ", DnsNameDomainLabel, DNS_ERROR_INVALID_NAME_CHAR }, + { "_c", DnsNameDomainLabel, DNS_ERROR_NON_RFC_NAME }, + { "456", DnsNameDomainLabel, ERROR_SUCCESS }, + { "456.789", DnsNameDomainLabel, ERROR_INVALID_NAME }, + { "c.d", DnsNameDomainLabel, ERROR_INVALID_NAME }, + + { "", DnsNameHostnameFull, ERROR_INVALID_NAME }, + { ".", DnsNameHostnameFull, ERROR_SUCCESS }, + { "..", DnsNameHostnameFull, ERROR_INVALID_NAME }, + { ".e", DnsNameHostnameFull, ERROR_INVALID_NAME }, + { "e.", DnsNameHostnameFull, ERROR_SUCCESS }, + { "e..", DnsNameHostnameFull, ERROR_INVALID_NAME }, + { "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", DnsNameDomain, ERROR_INVALID_NAME }, + { "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", DnsNameHostnameFull, ERROR_INVALID_NAME }, + { "?", DnsNameHostnameLabel, DNS_ERROR_INVALID_NAME_CHAR }, + { "e.?", DnsNameHostnameFull, DNS_ERROR_INVALID_NAME_CHAR }, + { "e.*", DnsNameHostnameFull, DNS_ERROR_INVALID_NAME_CHAR }, + { "e ", DnsNameHostnameFull, DNS_ERROR_INVALID_NAME_CHAR }, + { "e._f", DnsNameHostnameFull, DNS_ERROR_NON_RFC_NAME }, + { "789", DnsNameHostnameFull, DNS_ERROR_NUMERIC_NAME }, + { "789.456", DnsNameHostnameFull, DNS_ERROR_NUMERIC_NAME }, + { "e.f", DnsNameHostnameFull, ERROR_SUCCESS }, + + { "", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + { ".", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + { "..", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + { ".g", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + { "g.", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + { "g..", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + { "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + { "*", DnsNameHostnameLabel, DNS_ERROR_INVALID_NAME_CHAR }, + { "g ", DnsNameHostnameLabel, DNS_ERROR_INVALID_NAME_CHAR }, + { "_g", DnsNameHostnameLabel, DNS_ERROR_NON_RFC_NAME }, + { "123", DnsNameHostnameLabel, DNS_ERROR_NUMERIC_NAME }, + { "123.456", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + { "g.h", DnsNameHostnameLabel, ERROR_INVALID_NAME }, + + { "", DnsNameWildcard, ERROR_INVALID_NAME }, + { ".", DnsNameWildcard, ERROR_INVALID_NAME }, + { "..", DnsNameWildcard, ERROR_INVALID_NAME }, + { ".j", DnsNameWildcard, ERROR_INVALID_NAME }, + { "j.", DnsNameWildcard, ERROR_INVALID_NAME }, + { "j..", DnsNameWildcard, ERROR_INVALID_NAME }, + { "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", DnsNameWildcard, ERROR_INVALID_NAME }, + { "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj.jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj.jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj.jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj", DnsNameWildcard, ERROR_INVALID_NAME }, + { "?", DnsNameWildcard, ERROR_INVALID_NAME }, + { "i ", DnsNameWildcard, ERROR_INVALID_NAME }, + { "_i", DnsNameWildcard, ERROR_INVALID_NAME }, + { "123", DnsNameWildcard, ERROR_INVALID_NAME }, + { "123.456", DnsNameWildcard, ERROR_INVALID_NAME }, + { "i.j", DnsNameWildcard, ERROR_INVALID_NAME }, + { "*", DnsNameWildcard, ERROR_SUCCESS }, + { "*j", DnsNameWildcard, DNS_ERROR_INVALID_NAME_CHAR }, + { "*.j", DnsNameWildcard, ERROR_SUCCESS }, + { "i.*", DnsNameWildcard, ERROR_INVALID_NAME }, + + { "", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { ".", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "..", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { ".k", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "k.", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "k..", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "?", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "k ", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "_k", DnsNameSrvRecord, ERROR_SUCCESS }, + { "123", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "123.456", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "k.l", DnsNameSrvRecord, ERROR_INVALID_NAME }, + { "_", DnsNameSrvRecord, DNS_ERROR_NON_RFC_NAME }, + { "_k.l", DnsNameSrvRecord, ERROR_SUCCESS }, + { "k._l", DnsNameSrvRecord, ERROR_INVALID_NAME } +}; + +static void test_DnsValidateName_A( void ) +{ + unsigned int i; + DNS_STATUS status; + + status = DnsValidateName_A( NULL, DnsNameDomain ); + ok( status == ERROR_INVALID_NAME, "succeeded unexpectedly\n" ); + + for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++) + { + status = DnsValidateName_A( test_data[i].name, test_data[i].format ); + ok( status == test_data[i].status, "%d: \'%s\': got %d, expected %d\n", + i, test_data[i].name, status, test_data[i].status ); + } +} + +static void test_DnsNameCompare_A( void ) +{ + static CHAR empty[] = "", + dot[] = ".", + dotdot[] = "..", + A[] = "A", + a[] = "a", + B[] = "B", + b[] = "b", + A_dot_B[] = "A.B", + a_dot_a[] = "a.a", + a_dot_b[] = "a.b", + a_dot_b_dot[] = "a.b.", + a_dot_b_dotdot[] = "a.b..", + B_dot_A[] = "B.A", + b_dot_a[] = "b.a", + b_dot_a_dot[] = "b.a.", + b_dot_a_dotdot[] = "b.a.."; + + ok( DnsNameCompare_A( NULL, NULL ) == TRUE, "failed unexpectedly\n" ); + + ok( DnsNameCompare_A( empty, empty ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( dot, empty ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( empty, dot ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( dot, dotdot ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( dotdot, dot ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( a, a ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( a, A ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( A, a ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b, A_dot_B ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b, a_dot_b ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b_dot, a_dot_b_dot ) == TRUE, "failed unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b_dotdot, a_dot_b_dotdot ) == TRUE, "failed unexpectedly\n" ); + + ok( DnsNameCompare_A( empty, NULL ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( NULL, empty ) == FALSE, "succeeded unexpectedly\n" ); + + ok( DnsNameCompare_A( a, b ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a, B ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( A, b ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b, B_dot_A ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b_dot, b_dot_a_dot ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b, a_dot_a ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b_dotdot, b_dot_a_dotdot ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b_dot, b_dot_a_dotdot ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b_dotdot, b_dot_a_dot ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b_dot, b_dot_a ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsNameCompare_A( a_dot_b, b_dot_a_dot ) == FALSE, "succeeded unexpectedly\n" ); +} + +START_TEST(name) +{ + test_DnsValidateName_A(); + test_DnsNameCompare_A(); +} diff --git a/rostests/winetests/dnsapi/record.c b/rostests/winetests/dnsapi/record.c new file mode 100644 index 00000000000..4e97d85d756 --- /dev/null +++ b/rostests/winetests/dnsapi/record.c @@ -0,0 +1,146 @@ +/* + * Tests for record handling functions + * + * Copyright 2006 Hans Leidekker + * + * 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 + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "windns.h" + +#include "wine/test.h" + +static char name1[] = "localhost"; +static char name2[] = "LOCALHOST"; + +static DNS_RECORDA r1 = { NULL, name1, DNS_TYPE_A, sizeof(DNS_A_DATA), { 0 }, 1200, 0, { { 0xffffffff } } }; +static DNS_RECORDA r2 = { NULL, name1, DNS_TYPE_A, sizeof(DNS_A_DATA), { 0 }, 1200, 0, { { 0xffffffff } } }; +static DNS_RECORDA r3 = { NULL, name1, DNS_TYPE_A, sizeof(DNS_A_DATA), { 0 }, 1200, 0, { { 0xffffffff } } }; + +static void test_DnsRecordCompare( void ) +{ + ok( DnsRecordCompare( &r1, &r1 ) == TRUE, "failed unexpectedly\n" ); + + r2.pName = name2; + ok( DnsRecordCompare( &r1, &r2 ) == TRUE, "failed unexpectedly\n" ); + + r2.Flags.S.CharSet = DnsCharSetUnicode; + ok( DnsRecordCompare( &r1, &r2 ) == FALSE, "succeeded unexpectedly\n" ); + + r2.Flags.S.CharSet = DnsCharSetAnsi; + ok( DnsRecordCompare( &r1, &r2 ) == FALSE, "succeeded unexpectedly\n" ); + + r1.Flags.S.CharSet = DnsCharSetAnsi; + ok( DnsRecordCompare( &r1, &r2 ) == TRUE, "failed unexpectedly\n" ); + + r1.dwTtl = 0; + ok( DnsRecordCompare( &r1, &r2 ) == TRUE, "failed unexpectedly\n" ); + + r2.Data.A.IpAddress = 0; + ok( DnsRecordCompare( &r1, &r2 ) == FALSE, "succeeded unexpectedly\n" ); +} + +static void test_DnsRecordSetCompare( void ) +{ + DNS_RECORD *diff1; + DNS_RECORD *diff2; + DNS_RRSET rr1, rr2; + + r1.Flags.DW = 0x2019; + r2.Flags.DW = 0x2019; + r2.Data.A.IpAddress = 0xffffffff; + + DNS_RRSET_INIT( rr1 ); + DNS_RRSET_INIT( rr2 ); + + DNS_RRSET_ADD( rr1, &r1 ); + DNS_RRSET_ADD( rr2, &r2 ); + + DNS_RRSET_TERMINATE( rr1 ); + DNS_RRSET_TERMINATE( rr2 ); + + ok( DnsRecordSetCompare( NULL, NULL, NULL, NULL ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsRecordSetCompare( rr1.pFirstRR, NULL, NULL, NULL ) == FALSE, "succeeded unexpectedly\n" ); + ok( DnsRecordSetCompare( NULL, rr2.pFirstRR, NULL, NULL ) == FALSE, "succeeded unexpectedly\n" ); + + diff1 = NULL; + diff2 = NULL; + + ok( DnsRecordSetCompare( NULL, NULL, &diff1, &diff2 ) == FALSE, "succeeded unexpectedly\n" ); + ok( diff1 == NULL && diff2 == NULL, "unexpected result: %p, %p\n", diff1, diff2 ); + + ok( DnsRecordSetCompare( rr1.pFirstRR, NULL, &diff1, &diff2 ) == FALSE, "succeeded unexpectedly\n" ); + ok( diff1 != NULL && diff2 == NULL, "unexpected result: %p, %p\n", diff1, diff2 ); + DnsRecordListFree( diff1, DnsFreeRecordList ); + + ok( DnsRecordSetCompare( NULL, rr2.pFirstRR, &diff1, &diff2 ) == FALSE, "succeeded unexpectedly\n" ); + ok( diff1 == NULL && diff2 != NULL, "unexpected result: %p, %p\n", diff1, diff2 ); + DnsRecordListFree( diff2, DnsFreeRecordList ); + + ok( DnsRecordSetCompare( rr1.pFirstRR, rr2.pFirstRR, NULL, &diff2 ) == TRUE, "failed unexpectedly\n" ); + ok( diff2 == NULL, "unexpected result: %p\n", diff2 ); + + ok( DnsRecordSetCompare( rr1.pFirstRR, rr2.pFirstRR, &diff1, NULL ) == TRUE, "failed unexpectedly\n" ); + ok( diff1 == NULL, "unexpected result: %p\n", diff1 ); + + ok( DnsRecordSetCompare( rr1.pFirstRR, rr2.pFirstRR, &diff1, &diff2 ) == TRUE, "failed unexpectedly\n" ); + ok( diff1 == NULL && diff2 == NULL, "unexpected result: %p, %p\n", diff1, diff2 ); + + r2.Data.A.IpAddress = 0; + + ok( DnsRecordSetCompare( rr1.pFirstRR, rr2.pFirstRR, NULL, &diff2 ) == FALSE, "succeeded unexpectedly\n" ); + DnsRecordListFree( diff2, DnsFreeRecordList ); + + ok( DnsRecordSetCompare( rr1.pFirstRR, rr2.pFirstRR, &diff1, NULL ) == FALSE, "succeeded unexpectedly\n" ); + DnsRecordListFree( diff1, DnsFreeRecordList ); + + ok( DnsRecordSetCompare( rr1.pFirstRR, rr2.pFirstRR, &diff1, &diff2 ) == FALSE, "succeeded unexpectedly\n" ); + DnsRecordListFree( diff1, DnsFreeRecordList ); + DnsRecordListFree( diff2, DnsFreeRecordList ); +} + +static void test_DnsRecordSetDetach( void ) +{ + DNS_RRSET rr; + DNS_RECORDA *r, *s; + + DNS_RRSET_INIT( rr ); + DNS_RRSET_ADD( rr, &r1 ); + DNS_RRSET_ADD( rr, &r2 ); + DNS_RRSET_ADD( rr, &r3 ); + DNS_RRSET_TERMINATE( rr ); + + ok( !DnsRecordSetDetach( NULL ), "succeeded unexpectedly\n" ); + + r = rr.pFirstRR; + s = DnsRecordSetDetach( r ); + + ok( s == &r3, "failed unexpectedly: got %p, expected %p\n", s, &r3 ); + ok( r == &r1, "failed unexpectedly: got %p, expected %p\n", r, &r1 ); + ok( !r2.pNext, "failed unexpectedly\n" ); +} + +START_TEST(record) +{ + test_DnsRecordCompare(); + test_DnsRecordSetCompare(); + test_DnsRecordSetDetach(); +} diff --git a/rostests/winetests/dnsapi/testlist.c b/rostests/winetests/dnsapi/testlist.c new file mode 100644 index 00000000000..5ca23fe84a1 --- /dev/null +++ b/rostests/winetests/dnsapi/testlist.c @@ -0,0 +1,17 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_name(void); +extern void func_record(void); + +const struct test winetest_testlist[] = +{ + { "name", func_name }, + { "record", func_record }, + { 0, 0 } +}; diff --git a/rostests/winetests/dsound/capture.c b/rostests/winetests/dsound/capture.c new file mode 100644 index 00000000000..87a5a59aca7 --- /dev/null +++ b/rostests/winetests/dsound/capture.c @@ -0,0 +1,709 @@ +/* + * Unit tests for capture functions + * + * Copyright (c) 2002 Francois Gouget + * Copyright (c) 2003 Robert Reif + * + * 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 + */ + +#include +#include "initguid.h" +#include "windows.h" +#include "wine/test.h" +#include "dsound.h" +#include "mmreg.h" +#include "dsconf.h" + +#include "dsound_test.h" + +#define NOTIFICATIONS 5 + +static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID,LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; + +static const char * get_format_str(WORD format) +{ + static char msg[32]; +#define WAVE_FORMAT(f) case f: return #f + switch (format) { + WAVE_FORMAT(WAVE_FORMAT_PCM); + WAVE_FORMAT(WAVE_FORMAT_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_IBM_CVSD); + WAVE_FORMAT(WAVE_FORMAT_ALAW); + WAVE_FORMAT(WAVE_FORMAT_MULAW); + WAVE_FORMAT(WAVE_FORMAT_OKI_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_IMA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_MEDIASPACE_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_SIERRA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_G723_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_DIGISTD); + WAVE_FORMAT(WAVE_FORMAT_DIGIFIX); + WAVE_FORMAT(WAVE_FORMAT_DIALOGIC_OKI_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_YAMAHA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_SONARC); + WAVE_FORMAT(WAVE_FORMAT_DSPGROUP_TRUESPEECH); + WAVE_FORMAT(WAVE_FORMAT_ECHOSC1); + WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF36); + WAVE_FORMAT(WAVE_FORMAT_APTX); + WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF10); + WAVE_FORMAT(WAVE_FORMAT_DOLBY_AC2); + WAVE_FORMAT(WAVE_FORMAT_GSM610); + WAVE_FORMAT(WAVE_FORMAT_ANTEX_ADPCME); + WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_VQLPC); + WAVE_FORMAT(WAVE_FORMAT_DIGIREAL); + WAVE_FORMAT(WAVE_FORMAT_DIGIADPCM); + WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_CR10); + WAVE_FORMAT(WAVE_FORMAT_NMS_VBXADPCM); + WAVE_FORMAT(WAVE_FORMAT_G721_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_MPEG); + WAVE_FORMAT(WAVE_FORMAT_MPEGLAYER3); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH8); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH10); + WAVE_FORMAT(WAVE_FORMAT_FM_TOWNS_SND); + WAVE_FORMAT(WAVE_FORMAT_OLIGSM); + WAVE_FORMAT(WAVE_FORMAT_OLIADPCM); + WAVE_FORMAT(WAVE_FORMAT_OLICELP); + WAVE_FORMAT(WAVE_FORMAT_OLISBC); + WAVE_FORMAT(WAVE_FORMAT_OLIOPR); + WAVE_FORMAT(WAVE_FORMAT_DEVELOPMENT); + WAVE_FORMAT(WAVE_FORMAT_EXTENSIBLE); + } +#undef WAVE_FORMAT + sprintf(msg, "Unknown(0x%04x)", format); + return msg; +} + +const char * format_string(const WAVEFORMATEX* wfx) +{ + static char str[64]; + + sprintf(str, "%5dx%2dx%d %s", + wfx->nSamplesPerSec, wfx->wBitsPerSample, wfx->nChannels, + get_format_str(wfx->wFormatTag)); + + return str; +} + +static void IDirectSoundCapture_test(LPDIRECTSOUNDCAPTURE dsco, + BOOL initialized, LPCGUID lpGuid) +{ + HRESULT rc; + DSCCAPS dsccaps; + int ref; + IUnknown * unknown; + IDirectSoundCapture * dsc; + + /* Try to Query for objects */ + rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IUnknown, + (LPVOID*)&unknown); + ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IUnknown) " + "failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSoundCapture_Release(unknown); + + rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IDirectSoundCapture, + (LPVOID*)&dsc); + ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IDirectSoundCapture) " + "failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSoundCapture_Release(dsc); + + if (initialized == FALSE) { + /* try uninitialized object */ + rc=IDirectSoundCapture_GetCaps(dsco,0); + ok(rc==DSERR_UNINITIALIZED||rc==E_INVALIDARG, + "IDirectSoundCapture_GetCaps(NULL) should have returned " + "DSERR_UNINITIALIZED or E_INVALIDARG, returned: %08x\n", rc); + + rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSoundCapture_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSoundCapture_Initialize(dsco, lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED|| + rc==E_FAIL||rc==E_INVALIDARG, + "IDirectSoundCapture_Initialize() failed: %08x\n", rc); + if (rc==DSERR_NODRIVER||rc==E_INVALIDARG) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSoundCapture_Initialize(dsco, lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSoundCapture_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSoundCapture_GetCaps(dsco, 0); + ok(rc==DSERR_INVALIDPARAM, "IDirectSoundCapture_GetCaps(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + ZeroMemory(&dsccaps, sizeof(dsccaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dsco, &dsccaps); + ok(rc==DSERR_INVALIDPARAM, "IDirectSound_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + dsccaps.dwSize=sizeof(dsccaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps); + ok(rc==DS_OK, "IDirectSoundCapture_GetCaps() failed: %08x\n", rc); + +EXIT: + ref=IDirectSoundCapture_Release(dsco); + ok(ref==0, "IDirectSoundCapture_Release() has %d references, " + "should have 0\n", ref); +} + +static void IDirectSoundCapture_tests(void) +{ + HRESULT rc; + LPDIRECTSOUNDCAPTURE dsco=NULL; + LPCLASSFACTORY cf=NULL; + + trace("Testing IDirectSoundCapture\n"); + + rc=CoGetClassObject(&CLSID_DirectSoundCapture, CLSCTX_INPROC_SERVER, NULL, + &IID_IClassFactory, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) " + "failed: %08x\n", rc); + + rc=CoGetClassObject(&CLSID_DirectSoundCapture, CLSCTX_INPROC_SERVER, NULL, + &IID_IUnknown, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSoundCapture, IID_IUnknown) " + "failed: %08x\n", rc); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc); + if (rc==REGDB_E_CLASSNOTREG) { + trace(" Class Not Registered\n"); + return; + } + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, NULL); + + /* try the COM class factory method of creation with default capture + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc); + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultCapture); + + /* try the COM class factory method of creation with default voice + * capture device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc); + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultVoiceCapture); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dsco); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSoundCapture,CLSID_DirectSoundPrivate) " + "should have failed: %08x\n",rc); + + /* try with no device specified */ + rc=pDirectSoundCaptureCreate(NULL,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(NULL) failed: %08x\n",rc); + if (rc==S_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with default capture device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultCapture,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(DSDEVID_DefaultCapture) failed: %08x\n", rc); + if (rc==DS_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with default voice capture device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoiceCapture,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(DSDEVID_DefaultVoiceCapture) failed: %08x\n", rc); + if (rc==DS_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with a bad device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoicePlayback,&dsco,NULL); + ok(rc==DSERR_NODRIVER, + "DirectSoundCaptureCreate(DSDEVID_DefaultVoicePlatback) " + "should have failed: %08x\n",rc); + if (rc==DS_OK && dsco) + IDirectSoundCapture_Release(dsco); +} + +typedef struct { + char* wave; + DWORD wave_len; + + LPDIRECTSOUNDCAPTUREBUFFER dscbo; + LPWAVEFORMATEX wfx; + DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS]; + HANDLE event[NOTIFICATIONS]; + LPDIRECTSOUNDNOTIFY notify; + + DWORD buffer_size; + DWORD read; + DWORD offset; + DWORD size; + + DWORD last_pos; +} capture_state_t; + +static int capture_buffer_service(capture_state_t* state) +{ + HRESULT rc; + LPVOID ptr1,ptr2; + DWORD len1,len2; + DWORD capture_pos,read_pos; + + rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos, + &read_pos); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCurrentPosition() failed: %08x\n", rc); + if (rc!=DS_OK) + return 0; + + rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Lock() failed: %08x\n", rc); + if (rc!=DS_OK) + return 0; + + rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Unlock() failed: %08x\n", rc); + if (rc!=DS_OK) + return 0; + + state->offset = (state->offset + state->size) % state->buffer_size; + + return 1; +} + +static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, + LPDIRECTSOUNDCAPTUREBUFFER dscbo, int record) +{ + HRESULT rc; + DSCBCAPS dscbcaps; + WAVEFORMATEX wfx; + DWORD size,status; + capture_state_t state; + int i, ref; + + /* Private dsound.dll: Error: Invalid caps pointer */ + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should " + "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + /* Private dsound.dll: Error: Invalid caps pointer */ + dscbcaps.dwSize=0; + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should " + "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + dscbcaps.dwSize=sizeof(dscbcaps); + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCaps() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: size = %d flags=0x%08x buffer size=%d\n", + dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes); + } + + /* Query the format size. Note that it may not match sizeof(wfx) */ + /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must + * be non-NULL */ + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetFormat() should " + "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + size=0; + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size); + ok(rc==DS_OK && size!=0,"IDirectSoundCaptureBuffer_GetFormat() should " + "have returned the needed size: rc=%08x, size=%d\n", rc,size); + + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetFormat() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Format: tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* Private dsound.dll: Error: Invalid status pointer */ + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetStatus() should " + "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Status=0x%04x\n",status); + } + + ZeroMemory(&state, sizeof(state)); + state.dscbo=dscbo; + state.wfx=&wfx; + state.buffer_size = dscbcaps.dwBufferBytes; + for (i = 0; i < NOTIFICATIONS; i++) + state.event[i] = CreateEvent( NULL, FALSE, FALSE, NULL ); + state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS; + + rc=IDirectSoundCaptureBuffer_QueryInterface(dscbo,&IID_IDirectSoundNotify, + (void **)&(state.notify)); + ok((rc==DS_OK)&&(state.notify!=NULL), + "IDirectSoundCaptureBuffer_QueryInterface() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + + for (i = 0; i < NOTIFICATIONS; i++) { + state.posnotify[i].dwOffset = (i * state.size) + state.size - 1; + state.posnotify[i].hEventNotify = state.event[i]; + } + + rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS, + state.posnotify); + ok(rc==DS_OK,"IDirectSoundNotify_SetNotificationPositions() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + + ref=IDirectSoundNotify_Release(state.notify); + ok(ref==0,"IDirectSoundNotify_Release(): has %d references, should have " + "0\n",ref); + if (ref!=0) + return; + + if (record) { + rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Start() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %08x\n", rc); + ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING), + "GetStatus: bad status: %x\n",status); + if (rc!=DS_OK) + return; + + /* wait for the notifications */ + for (i = 0; i < (NOTIFICATIONS * 2); i++) { + rc=WaitForMultipleObjects(NOTIFICATIONS,state.event,FALSE,3000); + ok(rc==(WAIT_OBJECT_0+(i%NOTIFICATIONS)), + "WaitForMultipleObjects failed: 0x%x\n",rc); + if (rc!=(WAIT_OBJECT_0+(i%NOTIFICATIONS))) { + ok((rc==WAIT_TIMEOUT)||(rc==WAIT_FAILED), + "Wrong notification: should be %d, got %d\n", + i%NOTIFICATIONS,rc-WAIT_OBJECT_0); + } + if (!capture_buffer_service(&state)) + break; + } + + rc=IDirectSoundCaptureBuffer_Stop(dscbo); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Stop() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + } +} + +static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + LPDIRECTSOUNDCAPTURE dsco=NULL; + LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL; + DSCBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + DSCCAPS dsccaps; + DWORD f; + int ref; + + /* Private dsound.dll: Error: Invalid interface buffer */ + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + rc=pDirectSoundCaptureCreate(lpGuid,NULL,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + rc=pDirectSoundCaptureCreate(lpGuid,&dsco,NULL); + ok((rc==DS_OK)||(rc==DSERR_NODRIVER)||(rc==E_FAIL)||(rc==DSERR_ALLOCATED), + "DirectSoundCaptureCreate() failed: %08x\n",rc); + if (rc!=DS_OK) { + if (rc==DSERR_NODRIVER) + trace(" No Driver\n"); + else if (rc==E_FAIL) + trace(" No Device\n"); + else if (rc==DSERR_ALLOCATED) + trace(" Already In Use\n"); + goto EXIT; + } + + /* Private dsound.dll: Error: Invalid caps buffer */ + rc=IDirectSoundCapture_GetCaps(dsco,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* Private dsound.dll: Error: Invalid caps buffer */ + dsccaps.dwSize=0; + rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + dsccaps.dwSize=sizeof(dsccaps); + rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps); + ok(rc==DS_OK,"IDirectSoundCapture_GetCaps() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: size=%d flags=0x%08x formats=%05x channels=%d\n", + dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats, + dsccaps.dwChannels); + } + + /* Private dsound.dll: Error: Invalid size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=0; + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=NULL; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=NULL; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + ZeroMemory(&wfx, sizeof(wfx)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + for (f=0;f + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "mmreg.h" +#include "dsound_test.h" + +#define PI 3.14159265358979323846 + + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*, + LPUNKNOWN)=NULL; + +char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size) +{ + int i; + int nb_samples; + char* buf; + char* b; + + nb_samples=(int)(duration*wfx->nSamplesPerSec); + *size=nb_samples*wfx->nBlockAlign; + b=buf=HeapAlloc(GetProcessHeap(), 0, *size); + for (i=0;inSamplesPerSec); + if (wfx->wBitsPerSample==8) { + unsigned char sample=(unsigned char)((double)127.5*(y+1.0)); + *b++=sample; + if (wfx->nChannels==2) + *b++=sample; + } else if (wfx->wBitsPerSample == 16) { + signed short sample=(signed short)((double)32767.5*y-0.5); + b[0]=sample & 0xff; + b[1]=sample >> 8; + b+=2; + if (wfx->nChannels==2) { + b[0]=sample & 0xff; + b[1]=sample >> 8; + b+=2; + } + } else if (wfx->wBitsPerSample == 24) { + signed int sample=(signed int)((double)8388607.5*y-0.5); + b[0]=sample & 0xff; + b[1]=(sample >> 8)&0xff; + b[2]=sample >> 16; + b+=3; + if (wfx->nChannels==2) { + b[0]=sample & 0xff; + b[1]=(sample >> 8)&0xff; + b[2]=sample >> 16; + b+=3; + } + } else if (wfx->wBitsPerSample == 32) { + signed int sample=(signed int)((double)2147483647.5*y-0.5); + b[0]=sample & 0xff; + b[1]=(sample >> 8)&0xff; + b[2]=(sample >> 16)&0xff; + b[3]=sample >> 24; + b+=4; + if (wfx->nChannels==2) { + b[0]=sample & 0xff; + b[1]=(sample >> 8)&0xff; + b[2]=(sample >> 16)&0xff; + b[3]=sample >> 24; + b+=4; + } + } + } + return buf; +} + +const char * getDSBCAPS(DWORD xmask) { + static struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x }, + FE(DSBCAPS_PRIMARYBUFFER) + FE(DSBCAPS_STATIC) + FE(DSBCAPS_LOCHARDWARE) + FE(DSBCAPS_LOCSOFTWARE) + FE(DSBCAPS_CTRL3D) + FE(DSBCAPS_CTRLFREQUENCY) + FE(DSBCAPS_CTRLPAN) + FE(DSBCAPS_CTRLVOLUME) + FE(DSBCAPS_CTRLPOSITIONNOTIFY) + FE(DSBCAPS_STICKYFOCUS) + FE(DSBCAPS_GLOBALFOCUS) + FE(DSBCAPS_GETCURRENTPOSITION2) + FE(DSBCAPS_MUTE3DATMAXDISTANCE) +#undef FE + }; + static char buffer[512]; + unsigned int i; + BOOL first = TRUE; + + buffer[0] = 0; + + for (i=0;iwFormatTag=format; + wfx->nChannels=channels; + wfx->wBitsPerSample=depth; + wfx->nSamplesPerSec=rate; + wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8; + /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */ + if (wfx->nBlockAlign==0) + { + /* align compressed formats to byte boundary */ + wfx->nBlockAlign=1; + } + wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign; + wfx->cbSize=0; +} + +typedef struct { + char* wave; + DWORD wave_len; + + LPDIRECTSOUNDBUFFER dsbo; + LPWAVEFORMATEX wfx; + DWORD buffer_size; + DWORD written; + DWORD played; + DWORD offset; +} play_state_t; + +static int buffer_refill(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + + if (size>state->wave_len-state->written) + size=state->wave_len-state->written; + + /* some broken apps like Navyfield mistakenly pass NULL for a ppValue */ + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,NULL,&ptr2,&len2,0); + ok(rc==DSERR_INVALIDPARAM,"expected %08x got %08x\n",DSERR_INVALIDPARAM, rc); + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc); + if (rc!=DS_OK) + return -1; + + memcpy(ptr1,state->wave+state->written,len1); + state->written+=len1; + if (ptr2!=NULL) { + memcpy(ptr2,state->wave+state->written,len2); + state->written+=len2; + } + state->offset=state->written % state->buffer_size; + /* some apps blindly pass &ptr1 instead of ptr1 */ + rc=IDirectSoundBuffer_Unlock(state->dsbo,&ptr1,len1,ptr2,len2); + ok(rc==DSERR_INVALIDPARAM, "IDDirectSoundBuffer_Unlock(): expected %08x got %08x, %p %p\n",DSERR_INVALIDPARAM, rc, &ptr1, ptr1); + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_silence(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + BYTE s; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc); + if (rc!=DS_OK) + return -1; + + s=(state->wfx->wBitsPerSample==8?0x80:0); + memset(ptr1,s,len1); + if (ptr2!=NULL) { + memset(ptr2,s,len2); + } + state->offset=(state->offset+size) % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_service(play_state_t* state) +{ + DWORD last_play_pos,play_pos,buf_free; + HRESULT rc; + + rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %08x\n", rc); + if (rc!=DS_OK) { + goto STOP; + } + + /* Update the amount played */ + last_play_pos=state->played % state->buffer_size; + if (play_posplayed+=state->buffer_size-last_play_pos+play_pos; + else + state->played+=play_pos-last_play_pos; + + if (winetest_debug > 1) + trace("buf size=%d last_play_pos=%d play_pos=%d played=%d / %d\n", + state->buffer_size,last_play_pos,play_pos,state->played, + state->wave_len); + + if (state->played>state->wave_len) + { + /* Everything has been played */ + goto STOP; + } + + /* Refill the buffer */ + if (state->offset<=play_pos) + buf_free=play_pos-state->offset; + else + buf_free=state->buffer_size-state->offset+play_pos; + + if (winetest_debug > 1) + trace("offset=%d free=%d written=%d / %d\n", + state->offset,buf_free,state->written,state->wave_len); + if (buf_free==0) + return 1; + + if (state->writtenwave_len) + { + int w=buffer_refill(state,buf_free); + if (w==-1) + goto STOP; + buf_free-=w; + if (state->written==state->wave_len && winetest_debug > 1) + trace("last sound byte at %d\n", + (state->written % state->buffer_size)); + } + + if (buf_free>0) { + /* Fill with silence */ + if (winetest_debug > 1) + trace("writing %d bytes of silence\n",buf_free); + if (buffer_silence(state,buf_free)==-1) + goto STOP; + } + return 1; + +STOP: + if (winetest_debug > 1) + trace("stopping playback\n"); + rc=IDirectSoundBuffer_Stop(state->dsbo); + ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %08x\n", rc); + return 0; +} + +void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER *dsbo, + BOOL is_primary, BOOL set_volume, LONG volume, + BOOL set_pan, LONG pan, BOOL play, double duration, + BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener, + BOOL move_listener, BOOL move_sound, + BOOL set_frequency, DWORD frequency) +{ + HRESULT rc; + DSBCAPS dsbcaps; + WAVEFORMATEX wfx,wfx2; + DWORD size,status,freq; + int ref; + + if (set_frequency) { + rc=IDirectSoundBuffer_SetFrequency(*dsbo,frequency); + ok(rc==DS_OK||rc==DSERR_CONTROLUNAVAIL, + "IDirectSoundBuffer_SetFrequency() failed to set frequency %08x\n",rc); + if (rc!=DS_OK) + return; + } + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(*dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + ZeroMemory(&dsbcaps, sizeof(dsbcaps)); + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + dsbcaps.dwSize=sizeof(dsbcaps); + rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: flags=0x%08x size=%d\n",dsbcaps.dwFlags, + dsbcaps.dwBufferBytes); + } + + /* Query the format size. */ + size=0; + rc=IDirectSoundBuffer_GetFormat(*dsbo,NULL,0,&size); + ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have " + "returned the needed size: rc=%08x size=%d\n",rc,size); + + ok(size == sizeof(WAVEFORMATEX) || size == sizeof(WAVEFORMATEXTENSIBLE), + "Expected a correct structure size, got %d\n", size); + + if (size == sizeof(WAVEFORMATEX)) { + rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,size,NULL); + } + else if (size == sizeof(WAVEFORMATEXTENSIBLE)) { + WAVEFORMATEXTENSIBLE wfxe; + rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL); + wfx = wfxe.Format; + } + ok(rc==DS_OK, + "IDirectSoundBuffer_GetFormat() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Format: %s tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", + is_primary ? "Primary" : "Secondary", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* DSOUND: Error: Invalid frequency buffer */ + rc=IDirectSoundBuffer_GetFrequency(*dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ + rc=IDirectSoundBuffer_GetFrequency(*dsbo,&freq); + ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || + (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), + "IDirectSoundBuffer_GetFrequency() failed: %08x\n",rc); + if (rc==DS_OK) { + DWORD f = set_frequency?frequency:wfx.nSamplesPerSec; + ok(freq==f,"The frequency returned by GetFrequency " + "%d does not match the format %d\n",freq,f); + } + + /* DSOUND: Error: Invalid status pointer */ + rc=IDirectSoundBuffer_GetStatus(*dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + rc=IDirectSoundBuffer_GetStatus(*dsbo,&status); + ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc); + ok(status==0,"status=0x%x instead of 0\n",status); + + if (is_primary) { + DSBCAPS new_dsbcaps; + /* We must call SetCooperativeLevel to be allowed to call SetFormat */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + return; + + /* DSOUND: Error: Invalid format pointer */ + rc=IDirectSoundBuffer_SetFormat(*dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2); + rc=IDirectSoundBuffer_SetFormat(*dsbo,&wfx2); + ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %08x\n", + format_string(&wfx2), rc); + + /* There is no guarantee that SetFormat will actually change the + * format to what we asked for. It depends on what the soundcard + * supports. So we must re-query the format. + */ + rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc); + if (rc==DS_OK && + (wfx.wFormatTag!=wfx2.wFormatTag || + wfx.nSamplesPerSec!=wfx2.nSamplesPerSec || + wfx.wBitsPerSample!=wfx2.wBitsPerSample || + wfx.nChannels!=wfx2.nChannels)) { + trace("Requested format tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", + wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample, + wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign); + trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + ZeroMemory(&new_dsbcaps, sizeof(new_dsbcaps)); + new_dsbcaps.dwSize = sizeof(new_dsbcaps); + rc=IDirectSoundBuffer_GetCaps(*dsbo,&new_dsbcaps); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" new Caps: flags=0x%08x size=%d\n",new_dsbcaps.dwFlags, + new_dsbcaps.dwBufferBytes); + } + + /* Check for primary buffer size change */ + ok(new_dsbcaps.dwBufferBytes == dsbcaps.dwBufferBytes, + " buffer size changed after SetFormat() - " + "previous size was %u, current size is %u\n", + dsbcaps.dwBufferBytes, new_dsbcaps.dwBufferBytes); + dsbcaps.dwBufferBytes = new_dsbcaps.dwBufferBytes; + + /* Check for primary buffer flags change */ + ok(new_dsbcaps.dwFlags == dsbcaps.dwFlags, + " flags changed after SetFormat() - " + "previous flags were %08x, current flags are %08x\n", + dsbcaps.dwFlags, new_dsbcaps.dwFlags); + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc); + } + + if (play) { + play_state_t state; + DS3DLISTENER listener_param; + LPDIRECTSOUND3DBUFFER buffer=NULL; + DS3DBUFFER buffer_param; + DWORD start_time,now; + LPVOID buffer1; + DWORD length1; + + if (winetest_interactive) { + if (set_frequency) + trace(" Playing %g second 440Hz tone at %dx%dx%d with a " + "frequency of %d (%dHz)\n", duration, + wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels, + frequency, (440 * frequency) / wfx.nSamplesPerSec); + else + trace(" Playing %g second 440Hz tone at %dx%dx%d\n", duration, + wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels); + } + + if (is_primary) { + /* We must call SetCooperativeLevel to be allowed to call Lock */ + /* DSOUND: Setting DirectSound cooperative level to + * DSSCL_WRITEPRIMARY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(), + DSSCL_WRITEPRIMARY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_WRITEPRIMARY) " + "failed: %08x\n",rc); + if (rc!=DS_OK) + return; + } + if (buffer3d) { + LPDIRECTSOUNDBUFFER temp_buffer; + + rc=IDirectSoundBuffer_QueryInterface(*dsbo,&IID_IDirectSound3DBuffer, + (LPVOID *)&buffer); + ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + + /* check the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); + ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n", + temp_buffer,*dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DBuffer_QueryInterface(*dsbo, + &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSound3DBuffer_QueryInterface() failed: %08x\n", rc); + ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n", + temp_buffer,*dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + ref=IDirectSoundBuffer_Release(*dsbo); + ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " + "should have 0\n",ref); + + rc=IDirectSound3DBuffer_QueryInterface(buffer, + &IID_IDirectSoundBuffer, + (LPVOID *)dsbo); + ok(rc==DS_OK && *dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() " + "failed: %08x\n",rc); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " + "failed: %08x\n",rc); + + ZeroMemory(&buffer_param, sizeof(buffer_param)); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " + "failed: %08x\n",rc); + + buffer_param.dwSize=sizeof(buffer_param); + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %08x\n", rc); + } + if (set_volume) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { + LONG val; + rc=IDirectSoundBuffer_GetVolume(*dsbo,&val); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc); + + rc=IDirectSoundBuffer_SetVolume(*dsbo,volume); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %08x\n", rc); + } else { + /* DSOUND: Error: Buffer does not have CTRLVOLUME */ + rc=IDirectSoundBuffer_GetVolume(*dsbo,&volume); + ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() " + "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc); + } + } + + if (set_pan) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { + LONG val; + rc=IDirectSoundBuffer_GetPan(*dsbo,&val); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %08x\n", rc); + + rc=IDirectSoundBuffer_SetPan(*dsbo,pan); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %08x\n", rc); + } else { + /* DSOUND: Error: Buffer does not have CTRLPAN */ + rc=IDirectSoundBuffer_GetPan(*dsbo,&pan); + ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() " + "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc); + } + } + + /* try an offset past the end of the buffer */ + rc = IDirectSoundBuffer_Lock(*dsbo, dsbcaps.dwBufferBytes, 0, &buffer1, + &length1, NULL, NULL, + DSBLOCK_ENTIREBUFFER); + ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have " + "returned DSERR_INVALIDPARAM, returned %08x\n", rc); + + /* try a size larger than the buffer */ + rc = IDirectSoundBuffer_Lock(*dsbo, 0, dsbcaps.dwBufferBytes + 1, + &buffer1, &length1, NULL, NULL, + DSBLOCK_FROMWRITECURSOR); + ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have " + "returned DSERR_INVALIDPARAM, returned %08x\n", rc); + + if (set_frequency) + state.wave=wave_generate_la(&wfx,(duration*frequency)/wfx.nSamplesPerSec,&state.wave_len); + else + state.wave=wave_generate_la(&wfx,duration,&state.wave_len); + + state.dsbo=*dsbo; + state.wfx=&wfx; + state.buffer_size=dsbcaps.dwBufferBytes; + state.played=state.written=state.offset=0; + buffer_refill(&state,state.buffer_size); + + rc=IDirectSoundBuffer_Play(*dsbo,0,0,DSBPLAY_LOOPING); + ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %08x\n", rc); + + rc=IDirectSoundBuffer_GetStatus(*dsbo,&status); + ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc); + ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), + "GetStatus: bad status: %x\n",status); + + if (listener) { + ZeroMemory(&listener_param,sizeof(listener_param)); + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " + "failed: %08x\n",rc); + if (move_listener) { + listener_param.vPosition.x = -5.0f; + listener_param.vVelocity.x = (float)(10.0/duration); + } + rc=IDirectSound3DListener_SetAllParameters(listener, + &listener_param, + DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n", rc); + } + if (buffer3d) { + if (move_sound) { + buffer_param.vPosition.x = 100.0f; + buffer_param.vVelocity.x = (float)(-200.0/duration); + } + buffer_param.flMinDistance = 10; + rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param, + DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc); + } + + start_time=GetTickCount(); + while (buffer_service(&state)) { + WaitForSingleObject(GetCurrentProcess(),TIME_SLICE); + now=GetTickCount(); + if (listener && move_listener) { + listener_param.vPosition.x = (float)(-5.0+10.0*(now-start_time)/1000/duration); + if (winetest_debug>2) + trace("listener position=%g\n",listener_param.vPosition.x); + rc=IDirectSound3DListener_SetPosition(listener, + listener_param.vPosition.x,listener_param.vPosition.y, + listener_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n",rc); + } + if (buffer3d && move_sound) { + buffer_param.vPosition.x = (float)(100-200.0*(now-start_time)/1000/duration); + if (winetest_debug>2) + trace("sound position=%g\n",buffer_param.vPosition.x); + rc=IDirectSound3DBuffer_SetPosition(buffer, + buffer_param.vPosition.x,buffer_param.vPosition.y, + buffer_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc); + } + } + /* Check the sound duration was within 10% of the expected value */ + now=GetTickCount(); + ok(fabs(1000*duration-now+start_time)<=100*duration, + "The sound played for %d ms instead of %g ms\n", + now-start_time,1000*duration); + + HeapFree(GetProcessHeap(), 0, state.wave); + if (is_primary) { + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) " + "failed: %08x\n",rc); + } + if (buffer3d) { + ref=IDirectSound3DBuffer_Release(buffer); + ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, " + "should have 0\n",ref); + } + } +} + +static HRESULT test_secondary(LPGUID lpGuid, int play, + int has_3d, int has_3dbuffer, + int has_listener, int has_duplicate, + int move_listener, int move_sound) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + LPDIRECTSOUND3DLISTENER listener=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx, wfx1; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound_CreateSoundBuffer() failed to create a %sprimary buffer: %08x\n",has_3d?"3D ":"", rc); + if (rc==DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT1; + + if (has_listener) { + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSound3DListener, + (void **)&listener); + ok(rc==DS_OK && listener!=NULL, + "IDirectSoundBuffer_QueryInterface() failed to get a 3D listener: %08x\n",rc); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + if (rc==DS_OK && listener!=NULL) { + DS3DLISTENER listener_param; + ZeroMemory(&listener_param,sizeof(listener_param)); + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound3dListener_GetAllParameters() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound3dListener_GetAllParameters() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " + "failed: %08x\n",rc); + } else { + ok(listener==NULL, "IDirectSoundBuffer_QueryInterface() " + "failed but returned a listener anyway\n"); + ok(rc!=DS_OK, "IDirectSoundBuffer_QueryInterface() succeeded " + "but returned a NULL listener\n"); + if (listener) { + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3dListener_Release() listener has " + "%d references, should have 0\n",ref); + } + goto EXIT2; + } + } + + init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2); + secondary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|= + (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + if (winetest_interactive) { + trace(" Testing a %s%ssecondary buffer %s%s%s%sat %dx%dx%d " + "with a primary buffer at %dx%dx%d\n", + has_3dbuffer?"3D ":"", + has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", + move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound? + "moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels); + } + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL,"IDirectSound_CreateSoundBuffer() " + "failed to create a %s%ssecondary buffer %s%s%s%sat %dx%dx%d (%s): %08x\n", + has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound? + "moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + getDSBCAPS(bufdesc.dwFlags),rc); + if (rc==DS_OK && secondary!=NULL) { + if (!has_3d) { + LONG refvol,vol,refpan,pan; + + /* Check the initial secondary buffer's volume and pan */ + rc=IDirectSoundBuffer_GetVolume(secondary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: %08x\n",rc); + ok(vol==0,"wrong volume for a new secondary buffer: %d\n",vol); + rc=IDirectSoundBuffer_GetPan(secondary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: %08x\n",rc); + ok(pan==0,"wrong pan for a new secondary buffer: %d\n",pan); + + /* Check that changing the secondary buffer's volume and pan + * does not impact the primary buffer's volume and pan + */ + rc=IDirectSoundBuffer_GetVolume(primary,&refvol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc); + rc=IDirectSoundBuffer_GetPan(primary,&refpan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc); + + rc=IDirectSoundBuffer_SetVolume(secondary,-1000); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); + rc=IDirectSoundBuffer_GetVolume(secondary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); + ok(vol==-1000,"secondary: wrong volume %d instead of -1000\n", + vol); + rc=IDirectSoundBuffer_SetPan(secondary,-1000); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); + rc=IDirectSoundBuffer_GetPan(secondary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); + ok(pan==-1000,"secondary: wrong pan %d instead of -1000\n", + pan); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc); + ok(vol==refvol,"The primary volume changed from %d to %d\n", + refvol,vol); + rc=IDirectSoundBuffer_GetPan(primary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc); + ok(pan==refpan,"The primary pan changed from %d to %d\n", + refpan,pan); + + rc=IDirectSoundBuffer_SetVolume(secondary,0); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); + rc=IDirectSoundBuffer_SetPan(secondary,0); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); + } + if (has_duplicate) { + LPDIRECTSOUNDBUFFER duplicated=NULL; + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,0,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Invalid dest buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + duplicated=NULL; + rc=IDirectSound_DuplicateSoundBuffer(dso,secondary, + &duplicated); + ok(rc==DS_OK && duplicated!=NULL, + "IDirectSound_DuplicateSoundBuffer() failed to duplicate " + "a secondary buffer: %08x\n",rc); + + if (rc==DS_OK && duplicated!=NULL) { + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " + "references, should have 0\n",ref); + secondary=duplicated; + } + } + + if (rc==DS_OK && secondary!=NULL) { + double duration; + duration=(move_listener || move_sound?4.0:1.0); + test_buffer(dso,&secondary,0,FALSE,0,FALSE,0, + winetest_interactive,duration,has_3dbuffer, + listener,move_listener,move_sound,FALSE,0); + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, " + "should have 0\n",has_duplicate?"duplicated":"secondary", + ref); + } + } +EXIT1: + if (has_listener) { + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3dListener_Release() listener has %d " + "references, should have 0\n",ref); + } else { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + } else { + ok(primary==NULL,"IDirectSound_CreateSoundBuffer(primary) failed " + "but primary created anyway\n"); + ok(rc!=DS_OK,"IDirectSound_CreateSoundBuffer(primary) succeeded " + "but primary not created\n"); + if (primary) { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + } +EXIT2: + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_for_driver(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref, i; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: %08x\n",rc); + if (rc==DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + test_buffer(dso,&primary,1,TRUE,0,TRUE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0, + FALSE,0); + if (winetest_interactive) { + LONG volume,pan; + + volume = DSBVOLUME_MAX; + for (i = 0; i < 6; i++) { + test_buffer(dso,&primary,1,TRUE,volume,TRUE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER), + 1.0,0,NULL,0,0,FALSE,0); + volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); + } + + pan = DSBPAN_LEFT; + for (i = 0; i < 7; i++) { + test_buffer(dso,&primary,1,TRUE,0,TRUE,pan, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,FALSE,0); + pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6); + } + } + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " + "to create a primary buffer: %08x\n",rc); + if (rc==DS_OK && primary!=NULL) { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() " + "failed to create a 3D primary buffer: %08x\n",rc); + if (rc==DS_OK && primary!=NULL) { + test_buffer(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0, + FALSE,0); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + } + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d_with_listener(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " + "to create a 3D primary buffer: %08x\n",rc); + if (rc==DS_OK && primary!=NULL) { + LPDIRECTSOUND3DLISTENER listener=NULL; + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSound3DListener,(void **)&listener); + ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() " + "failed to get a 3D listener: %08x\n",rc); + if (rc==DS_OK && listener!=NULL) { + LPDIRECTSOUNDBUFFER temp_buffer=NULL; + + /* Checking the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); + ok(temp_buffer==primary, + "COM interface broken: %p != %p\n", + temp_buffer,primary); + if (rc==DS_OK && temp_buffer!=NULL) { + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DListener_QueryInterface(listener, + &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); + ok(temp_buffer==primary, + "COM interface broken: %p != %p\n", + temp_buffer,primary); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + /* Testing the buffer */ + test_buffer(dso,&primary,1,FALSE,0,FALSE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0, + listener,0,0,FALSE,0); + } + + /* Testing the reference counting */ + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3DListener_Release() listener has %d " + "references, should have 0\n",ref); + } + + /* Testing the reference counting */ + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) +return DSERR_GENERIC; + + return rc; +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + rc = test_for_driver(lpGuid); + if (rc == DSERR_NODRIVER) { + trace(" No Driver\n"); + return 1; + } else if (rc == DSERR_ALLOCATED) { + trace(" Already In Use\n"); + return 1; + } else if (rc == E_FAIL) { + trace(" No Device\n"); + return 1; + } + + trace(" Testing the primary buffer\n"); + test_primary(lpGuid); + + trace(" Testing 3D primary buffer\n"); + test_primary_3d(lpGuid); + + trace(" Testing 3D primary buffer with listener\n"); + test_primary_3d_with_listener(lpGuid); + + /* Testing secondary buffers */ + test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0); + + /* Testing 3D secondary buffers */ + test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1); + + return 1; +} + +static void ds3d_tests(void) +{ + HRESULT rc; + rc=pDirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc); +} + +START_TEST(ds3d) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibrary("dsound.dll"); + if (hDsound) + { + + pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound, + "DirectSoundEnumerateA"); + pDirectSoundCreate = (void*)GetProcAddress(hDsound, + "DirectSoundCreate"); + + ds3d_tests(); + + FreeLibrary(hDsound); + } + else + skip("dsound.dll not found!\n"); + + CoUninitialize(); +} diff --git a/rostests/winetests/dsound/ds3d8.c b/rostests/winetests/dsound/ds3d8.c new file mode 100644 index 00000000000..8ad428d3edc --- /dev/null +++ b/rostests/winetests/dsound/ds3d8.c @@ -0,0 +1,1154 @@ +/* + * Tests the panning and 3D functions of DirectSound + * + * Part of this test involves playing test tones. But this only makes + * sense if someone is going to carefully listen to it, and would only + * bother everyone else. + * So this is only done if the test is being run in interactive mode. + * + * Copyright (c) 2002-2004 Francois Gouget + * + * 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 + */ + +#include + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "mmreg.h" +#include "dsound_test.h" + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL; + +typedef struct { + char* wave; + DWORD wave_len; + + LPDIRECTSOUNDBUFFER dsbo; + LPWAVEFORMATEX wfx; + DWORD buffer_size; + DWORD written; + DWORD played; + DWORD offset; +} play_state_t; + +static int buffer_refill8(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + + if (size>state->wave_len-state->written) + size=state->wave_len-state->written; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc); + if (rc!=DS_OK) + return -1; + + memcpy(ptr1,state->wave+state->written,len1); + state->written+=len1; + if (ptr2!=NULL) { + memcpy(ptr2,state->wave+state->written,len2); + state->written+=len2; + } + state->offset=state->written % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_silence8(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + BYTE s; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc); + if (rc!=DS_OK) + return -1; + + s=(state->wfx->wBitsPerSample==8?0x80:0); + memset(ptr1,s,len1); + if (ptr2!=NULL) { + memset(ptr2,s,len2); + } + state->offset=(state->offset+size) % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_service8(play_state_t* state) +{ + DWORD last_play_pos,play_pos,buf_free; + HRESULT rc; + + rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %08x\n", rc); + if (rc!=DS_OK) { + goto STOP; + } + + /* Update the amount played */ + last_play_pos=state->played % state->buffer_size; + if (play_posplayed+=state->buffer_size-last_play_pos+play_pos; + else + state->played+=play_pos-last_play_pos; + + if (winetest_debug > 1) + trace("buf size=%d last_play_pos=%d play_pos=%d played=%d / %d\n", + state->buffer_size,last_play_pos,play_pos,state->played, + state->wave_len); + + if (state->played>state->wave_len) + { + /* Everything has been played */ + goto STOP; + } + + /* Refill the buffer */ + if (state->offset<=play_pos) + buf_free=play_pos-state->offset; + else + buf_free=state->buffer_size-state->offset+play_pos; + + if (winetest_debug > 1) + trace("offset=%d free=%d written=%d / %d\n", + state->offset,buf_free,state->written,state->wave_len); + if (buf_free==0) + return 1; + + if (state->writtenwave_len) + { + int w=buffer_refill8(state,buf_free); + if (w==-1) + goto STOP; + buf_free-=w; + if (state->written==state->wave_len && winetest_debug > 1) + trace("last sound byte at %d\n", + (state->written % state->buffer_size)); + } + + if (buf_free>0) { + /* Fill with silence */ + if (winetest_debug > 1) + trace("writing %d bytes of silence\n",buf_free); + if (buffer_silence8(state,buf_free)==-1) + goto STOP; + } + return 1; + +STOP: + if (winetest_debug > 1) + trace("stopping playback\n"); + rc=IDirectSoundBuffer_Stop(state->dsbo); + ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %08x\n", rc); + return 0; +} + +void test_buffer8(LPDIRECTSOUND8 dso, LPDIRECTSOUNDBUFFER * dsbo, + BOOL is_primary, BOOL set_volume, LONG volume, + BOOL set_pan, LONG pan, BOOL play, double duration, + BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener, + BOOL move_listener, BOOL move_sound) +{ + HRESULT rc; + DSBCAPS dsbcaps; + WAVEFORMATEX wfx,wfx2; + DWORD size,status,freq; + int ref; + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(*dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + ZeroMemory(&dsbcaps, sizeof(dsbcaps)); + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + dsbcaps.dwSize=sizeof(dsbcaps); + rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: flags=0x%08x size=%d\n",dsbcaps.dwFlags, + dsbcaps.dwBufferBytes); + } + + /* Query the format size. */ + size=0; + rc=IDirectSoundBuffer_GetFormat(*dsbo,NULL,0,&size); + ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have " + "returned the needed size: rc=%08x size=%d\n",rc,size); + + ok(size == sizeof(WAVEFORMATEX) || size == sizeof(WAVEFORMATEXTENSIBLE), + "Expected a correct structure size, got %d\n", size); + + if (size == sizeof(WAVEFORMATEX)) { + rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,size,NULL); + } else if (size == sizeof(WAVEFORMATEXTENSIBLE)) { + WAVEFORMATEXTENSIBLE wfxe; + rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL); + wfx = wfxe.Format; + } + ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Format: %s tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", + is_primary ? "Primary" : "Secondary", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* DSOUND: Error: Invalid frequency buffer */ + rc=IDirectSoundBuffer_GetFrequency(*dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ + rc=IDirectSoundBuffer_GetFrequency(*dsbo,&freq); + ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || + (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), + "IDirectSoundBuffer_GetFrequency() failed: %08x\n",rc); + if (rc==DS_OK) { + ok(freq==wfx.nSamplesPerSec,"The frequency returned by GetFrequency " + "%d does not match the format %d\n",freq,wfx.nSamplesPerSec); + } + + /* DSOUND: Error: Invalid status pointer */ + rc=IDirectSoundBuffer_GetStatus(*dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + rc=IDirectSoundBuffer_GetStatus(*dsbo,&status); + ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc); + ok(status==0,"status=0x%x instead of 0\n",status); + + if (is_primary) { + DSBCAPS new_dsbcaps; + /* We must call SetCooperativeLevel to be allowed to call SetFormat */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) " + "failed: %08x\n",rc); + if (rc!=DS_OK) + return; + + /* DSOUND: Error: Invalid format pointer */ + rc=IDirectSoundBuffer_SetFormat(*dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2); + rc=IDirectSoundBuffer_SetFormat(*dsbo,&wfx2); + ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %08x\n", + format_string(&wfx2), rc); + + /* There is no guarantee that SetFormat will actually change the + * format to what we asked for. It depends on what the soundcard + * supports. So we must re-query the format. + */ + rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc); + if (rc==DS_OK && + (wfx.wFormatTag!=wfx2.wFormatTag || + wfx.nSamplesPerSec!=wfx2.nSamplesPerSec || + wfx.wBitsPerSample!=wfx2.wBitsPerSample || + wfx.nChannels!=wfx2.nChannels)) { + trace("Requested format tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", + wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample, + wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign); + trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + ZeroMemory(&new_dsbcaps, sizeof(new_dsbcaps)); + new_dsbcaps.dwSize = sizeof(new_dsbcaps); + rc=IDirectSoundBuffer_GetCaps(*dsbo,&new_dsbcaps); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" new Caps: flags=0x%08x size=%d\n",new_dsbcaps.dwFlags, + new_dsbcaps.dwBufferBytes); + } + + /* Check for primary buffer size change */ + ok(new_dsbcaps.dwBufferBytes == dsbcaps.dwBufferBytes, + " buffer size changed after SetFormat() - " + "previous size was %u, current size is %u\n", + dsbcaps.dwBufferBytes, new_dsbcaps.dwBufferBytes); + dsbcaps.dwBufferBytes = new_dsbcaps.dwBufferBytes; + + /* Check for primary buffer flags change */ + ok(new_dsbcaps.dwFlags == dsbcaps.dwFlags, + " flags changed after SetFormat() - " + "previous flags were %08x, current flags are %08x\n", + dsbcaps.dwFlags, new_dsbcaps.dwFlags); + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) " + "failed: %08x\n",rc); + } + + if (play) { + play_state_t state; + DS3DLISTENER listener_param; + LPDIRECTSOUND3DBUFFER buffer=NULL; + DS3DBUFFER buffer_param; + DWORD start_time,now; + LPVOID buffer1; + DWORD length1; + + if (winetest_interactive) { + trace(" Playing %g second 440Hz tone at %dx%dx%d\n", duration, + wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels); + } + + if (is_primary) { + /* We must call SetCooperativeLevel to be allowed to call Lock */ + /* DSOUND: Setting DirectSound cooperative level to + * DSSCL_WRITEPRIMARY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(), + DSSCL_WRITEPRIMARY); + ok(rc==DS_OK, + "IDirectSound8_SetCooperativeLevel(DSSCL_WRITEPRIMARY) failed: %08x\n",rc); + if (rc!=DS_OK) + return; + } + if (buffer3d) { + LPDIRECTSOUNDBUFFER temp_buffer; + + rc=IDirectSoundBuffer_QueryInterface(*dsbo,&IID_IDirectSound3DBuffer, + (LPVOID *)&buffer); + ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + + /* check the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); + ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n", + temp_buffer,*dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSound3DBuffer_QueryInterface() failed: %08x\n", rc); + ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n", + temp_buffer,*dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + ref=IDirectSoundBuffer_Release(*dsbo); + ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " + "should have 0\n",ref); + + rc=IDirectSound3DBuffer_QueryInterface(buffer, + &IID_IDirectSoundBuffer, + (LPVOID *)dsbo); + ok(rc==DS_OK && *dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() " + "failed: %08x\n",rc); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " + "failed: %08x\n",rc); + + ZeroMemory(&buffer_param, sizeof(buffer_param)); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " + "failed: %08x\n",rc); + + buffer_param.dwSize=sizeof(buffer_param); + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %08x\n", rc); + } + if (set_volume) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { + LONG val; + rc=IDirectSoundBuffer_GetVolume(*dsbo,&val); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc); + + rc=IDirectSoundBuffer_SetVolume(*dsbo,volume); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %08x\n", rc); + } else { + /* DSOUND: Error: Buffer does not have CTRLVOLUME */ + rc=IDirectSoundBuffer_GetVolume(*dsbo,&volume); + ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() " + "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc); + } + } + + if (set_pan) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { + LONG val; + rc=IDirectSoundBuffer_GetPan(*dsbo,&val); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %08x\n", rc); + + rc=IDirectSoundBuffer_SetPan(*dsbo,pan); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %08x\n", rc); + } else { + /* DSOUND: Error: Buffer does not have CTRLPAN */ + rc=IDirectSoundBuffer_GetPan(*dsbo,&pan); + ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() " + "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc); + } + } + + /* try an offset past the end of the buffer */ + rc = IDirectSoundBuffer_Lock(*dsbo, dsbcaps.dwBufferBytes, 0, &buffer1, + &length1, NULL, NULL, + DSBLOCK_ENTIREBUFFER); + ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have " + "returned DSERR_INVALIDPARAM, returned %08x\n", rc); + + /* try a size larger than the buffer */ + rc = IDirectSoundBuffer_Lock(*dsbo, 0, dsbcaps.dwBufferBytes + 1, + &buffer1, &length1, NULL, NULL, + DSBLOCK_FROMWRITECURSOR); + ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have " + "returned DSERR_INVALIDPARAM, returned %08x\n", rc); + + state.wave=wave_generate_la(&wfx,duration,&state.wave_len); + + state.dsbo=*dsbo; + state.wfx=&wfx; + state.buffer_size=dsbcaps.dwBufferBytes; + state.played=state.written=state.offset=0; + buffer_refill8(&state,state.buffer_size); + + rc=IDirectSoundBuffer_Play(*dsbo,0,0,DSBPLAY_LOOPING); + ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %08x\n", rc); + + rc=IDirectSoundBuffer_GetStatus(*dsbo,&status); + ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc); + ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), + "GetStatus: bad status: %x\n",status); + + if (listener) { + ZeroMemory(&listener_param,sizeof(listener_param)); + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " + "failed: %08x\n",rc); + if (move_listener) { + listener_param.vPosition.x = -5.0f; + listener_param.vVelocity.x = (float)(10.0/duration); + } + rc=IDirectSound3DListener_SetAllParameters(listener, + &listener_param, + DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n", rc); + } + if (buffer3d) { + if (move_sound) { + buffer_param.vPosition.x = 100.0f; + buffer_param.vVelocity.x = (float)(-200.0/duration); + } + buffer_param.flMinDistance = 10; + rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param, + DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc); + } + + start_time=GetTickCount(); + while (buffer_service8(&state)) { + WaitForSingleObject(GetCurrentProcess(),TIME_SLICE); + now=GetTickCount(); + if (listener && move_listener) { + listener_param.vPosition.x = (float)(-5.0+10.0*(now-start_time)/1000/duration); + if (winetest_debug>2) + trace("listener position=%g\n",listener_param.vPosition.x); + rc=IDirectSound3DListener_SetPosition(listener, + listener_param.vPosition.x,listener_param.vPosition.y, + listener_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n",rc); + } + if (buffer3d && move_sound) { + buffer_param.vPosition.x = (float)(100-200.0*(now-start_time)/1000/duration); + if (winetest_debug>2) + trace("sound position=%g\n",buffer_param.vPosition.x); + rc=IDirectSound3DBuffer_SetPosition(buffer, + buffer_param.vPosition.x,buffer_param.vPosition.y, + buffer_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc); + } + } + /* Check the sound duration was within 10% of the expected value */ + now=GetTickCount(); + ok(fabs(1000*duration-now+start_time)<=100*duration, + "The sound played for %d ms instead of %g ms\n", + now-start_time,1000*duration); + + HeapFree(GetProcessHeap(), 0, state.wave); + if (is_primary) { + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) " + "failed: %08x\n",rc); + } + if (buffer3d) { + ref=IDirectSound3DBuffer_Release(buffer); + ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, " + "should have 0\n",ref); + } + } +} + +static HRESULT test_secondary8(LPGUID lpGuid, int play, + int has_3d, int has_3dbuffer, + int has_listener, int has_duplicate, + int move_listener, int move_sound) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + LPDIRECTSOUND3DLISTENER listener=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx, wfx1; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc == DSERR_CONTROLUNAVAIL), + "IDirectSound8_CreateSoundBuffer() failed to create a %sprimary buffer: %08x\n",has_3d?"3D ":"", rc); + if (rc == DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT1; + + if (has_listener) { + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSound3DListener, + (void **)&listener); + ok(rc==DS_OK && listener!=NULL, + "IDirectSoundBuffer_QueryInterface() failed to get a 3D " + "listener %08x\n",rc); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + if (rc==DS_OK && listener!=NULL) { + DS3DLISTENER listener_param; + ZeroMemory(&listener_param,sizeof(listener_param)); + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound3dListener_GetAllParameters() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound3dListener_GetAllParameters() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " + "failed: %08x\n",rc); + } else { + ok(listener==NULL, "IDirectSoundBuffer_QueryInterface() " + "failed but returned a listener anyway\n"); + ok(rc!=DS_OK, "IDirectSoundBuffer_QueryInterface() succeeded " + "but returned a NULL listener\n"); + if (listener) { + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3dListener_Release() listener has " + "%d references, should have 0\n",ref); + } + goto EXIT2; + } + } + + init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2); + secondary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|= + (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + if (has_3d) { + /* a stereo 3D buffer should fail */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_CreateSoundBuffer(secondary) should have " + "returned DSERR_INVALIDPARAM, returned %08x\n", rc); + if (secondary) + ref=IDirectSoundBuffer_Release(secondary); + init_format(&wfx,WAVE_FORMAT_PCM,22050,16,1); + } + + if (winetest_interactive) { + trace(" Testing a %s%ssecondary buffer %s%s%s%sat %dx%dx%d " + "with a primary buffer at %dx%dx%d\n", + has_3dbuffer?"3D ":"", + has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", + move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound? + "moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels); + } + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL,"IDirectSound8_CreateSoundBuffer() " + "failed to create a %s%ssecondary buffer %s%s%s%sat %dx%dx%d (%s): %08x\n", + has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound? + "moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + getDSBCAPS(bufdesc.dwFlags),rc); + if (rc==DS_OK && secondary!=NULL) { + if (!has_3d) { + LONG refvol,vol,refpan,pan; + + /* Check the initial secondary buffer's volume and pan */ + rc=IDirectSoundBuffer_GetVolume(secondary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: %08x\n",rc); + ok(vol==0,"wrong volume for a new secondary buffer: %d\n",vol); + rc=IDirectSoundBuffer_GetPan(secondary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: %08x\n",rc); + ok(pan==0,"wrong pan for a new secondary buffer: %d\n",pan); + + /* Check that changing the secondary buffer's volume and pan + * does not impact the primary buffer's volume and pan + */ + rc=IDirectSoundBuffer_GetVolume(primary,&refvol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc); + rc=IDirectSoundBuffer_GetPan(primary,&refpan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n",rc); + + rc=IDirectSoundBuffer_SetVolume(secondary,-1000); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); + rc=IDirectSoundBuffer_GetVolume(secondary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); + ok(vol==-1000,"secondary: wrong volume %d instead of -1000\n", + vol); + rc=IDirectSoundBuffer_SetPan(secondary,-1000); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); + rc=IDirectSoundBuffer_GetPan(secondary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); + ok(pan==-1000,"secondary: wrong pan %d instead of -1000\n", + pan); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_`GetVolume(primary) failed: i%08x\n",rc); + ok(vol==refvol,"The primary volume changed from %d to %d\n", + refvol,vol); + rc=IDirectSoundBuffer_GetPan(primary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n",rc); + ok(pan==refpan,"The primary pan changed from %d to %d\n", + refpan,pan); + + rc=IDirectSoundBuffer_SetVolume(secondary,0); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); + rc=IDirectSoundBuffer_SetPan(secondary,0); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); + } + if (has_duplicate) { + LPDIRECTSOUNDBUFFER duplicated=NULL; + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,0,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Invalid dest buffer */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,0,&duplicated); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + duplicated=NULL; + rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary, + &duplicated); + ok(rc==DS_OK && duplicated!=NULL, + "IDirectSound8_DuplicateSoundBuffer() failed to duplicate " + "a secondary buffer: %08x\n",rc); + + if (rc==DS_OK && duplicated!=NULL) { + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " + "references, should have 0\n",ref); + secondary=duplicated; + } + } + + if (rc==DS_OK && secondary!=NULL) { + double duration; + duration=(move_listener || move_sound?4.0:1.0); + test_buffer8(dso,&secondary,0,FALSE,0,FALSE,0, + winetest_interactive,duration,has_3dbuffer, + listener,move_listener,move_sound); + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, " + "should have 0\n",has_duplicate?"duplicated":"secondary", + ref); + } + } +EXIT1: + if (has_listener) { + if (listener) { + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3dListener_Release() listener has %d " + "references, should have 0\n",ref); + } + } else { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + } else { + ok(primary==NULL,"IDirectSound8_CreateSoundBuffer(primary) failed " + "but primary created anyway\n"); + ok(rc!=DS_OK,"IDirectSound8_CreateSoundBuffer(primary) succeeded " + "but primary not created\n"); + if (primary) { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + } +EXIT2: + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_for_driver8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref, i; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc == DSERR_CONTROLUNAVAIL), + "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer: %08x\n",rc); + if (rc == DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + test_buffer8(dso,&primary,1,TRUE,0,TRUE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0); + if (winetest_interactive) { + LONG volume,pan; + + volume = DSBVOLUME_MAX; + for (i = 0; i < 6; i++) { + test_buffer8(dso,&primary,1,TRUE,volume,TRUE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER), + 1.0,0,NULL,0,0); + volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); + } + + pan = DSBPAN_LEFT; + for (i = 0; i < 7; i++) { + test_buffer8(dso,&primary,1,TRUE,0,TRUE,pan, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); + pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6); + } + } + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed " + "to create a primary buffer: %08x\n",rc); + if (rc==DS_OK && primary!=NULL) { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() " + "failed to create a 3D primary buffer: %08x\n",rc); + if (rc==DS_OK && primary!=NULL) { + test_buffer8(dso,&primary,1,FALSE,0,FALSE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + } + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d_with_listener8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed " + "to create a 3D primary buffer %08x\n",rc); + if (rc==DS_OK && primary!=NULL) { + LPDIRECTSOUND3DLISTENER listener=NULL; + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSound3DListener, + (void **)&listener); + ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() " + "failed to get a 3D listener: %08x\n",rc); + if (rc==DS_OK && listener!=NULL) { + LPDIRECTSOUNDBUFFER temp_buffer=NULL; + + /* Checking the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); + ok(temp_buffer==primary,"COM interface broken: %p != %p\n",temp_buffer,primary); + if (rc==DS_OK && temp_buffer!=NULL) { + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DListener_QueryInterface(listener, + &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); + ok(temp_buffer==primary,"COM interface broken: %p != %p\n",temp_buffer,primary); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + /* Testing the buffer */ + test_buffer8(dso,&primary,1,FALSE,0,FALSE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER), + 1.0,0,listener,0,0); + } + + /* Testing the reference counting */ + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3DListener_Release() listener has %d " + "references, should have 0\n",ref); + } + + /* Testing the reference counting */ + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) +return DSERR_GENERIC; + + return rc; +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + rc = test_for_driver8(lpGuid); + if (rc == DSERR_NODRIVER) { + trace(" No Driver\n"); + return 1; + } else if (rc == DSERR_ALLOCATED) { + trace(" Already In Use\n"); + return 1; + } else if (rc == E_FAIL) { + trace(" No Device\n"); + return 1; + } + + trace(" Testing the primary buffer\n"); + test_primary8(lpGuid); + + trace(" Testing 3D primary buffer\n"); + test_primary_3d8(lpGuid); + + trace(" Testing 3D primary buffer with listener\n"); + test_primary_3d_with_listener8(lpGuid); + + /* Testing secondary buffers */ + test_secondary8(lpGuid,winetest_interactive,0,0,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,0,0,0,1,0,0); + + /* Testing 3D secondary buffers */ + test_secondary8(lpGuid,winetest_interactive,1,0,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,0,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,0,1,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,0,1,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,1); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,1); + + return 1; +} + +static void ds3d8_tests(void) +{ + HRESULT rc; + rc=pDirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc); +} + +START_TEST(ds3d8) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibrary("dsound.dll"); + if (hDsound) + { + + pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound, + "DirectSoundEnumerateA"); + pDirectSoundCreate8 = (void*)GetProcAddress(hDsound, + "DirectSoundCreate8"); + if (pDirectSoundCreate8) + ds3d8_tests(); + else + skip("ds3d8 test skipped\n"); + + FreeLibrary(hDsound); + } + else + skip("dsound.dll not found!\n"); + + CoUninitialize(); +} diff --git a/rostests/winetests/dsound/dsound.c b/rostests/winetests/dsound/dsound.c new file mode 100644 index 00000000000..114dbb6ced2 --- /dev/null +++ b/rostests/winetests/dsound/dsound.c @@ -0,0 +1,1103 @@ +/* + * Tests basic sound playback in DirectSound. + * In particular we test each standard Windows sound format to make sure + * we handle the sound card/driver quirks correctly. + * + * Part of this test involves playing test tones. But this only makes + * sense if someone is going to carefully listen to it, and would only + * bother everyone else. + * So this is only done if the test is being run in interactive mode. + * + * Copyright (c) 2002-2004 Francois Gouget + * Copyright (c) 2007 Maarten Lankhorst + * + * 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 + */ + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "dsconf.h" +#include "mmreg.h" +#include "initguid.h" +#include "ks.h" +#include "ksmedia.h" + +#include "dsound_test.h" + +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*, + LPUNKNOWN)=NULL; + +static BOOL gotdx8; + +static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized, + LPCGUID lpGuid) +{ + HRESULT rc; + DSCAPS dscaps; + int ref; + IUnknown * unknown; + IDirectSound * ds; + IDirectSound8 * ds8; + DWORD speaker_config, new_speaker_config; + + /* Try to Query for objects */ + rc=IDirectSound_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); + ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IUnknown) failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSound_Release(unknown); + + rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds); + ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IDirectSound) failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSound_Release(ds); + + rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8); + ok(rc==E_NOINTERFACE,"IDirectSound_QueryInterface(IID_IDirectSound8) " + "should have failed: %08x\n",rc); + if (rc==DS_OK) + IDirectSound8_Release(ds8); + + if (initialized == FALSE) { + /* try uninitialized object */ + rc=IDirectSound_GetCaps(dso,0); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps(NULL) " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound_Compact(dso); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_Compact() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetSpeakerConfig() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound_Initialize(dso,lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "IDirectSound_Initialize() failed: %08x\n",rc); + if (rc==DSERR_NODRIVER) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSound_Initialize(dso,lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + ZeroMemory(&dscaps, sizeof(dscaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + dscaps.dwSize=sizeof(dscaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); + + rc=IDirectSound_Compact(dso); + ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound_Compact() failed: %08x\n", rc); + + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); + + rc=IDirectSound_Compact(dso); + ok(rc==DS_OK,"IDirectSound_Compact() failed: %08x\n",rc); + + rc=IDirectSound_GetSpeakerConfig(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetSpeakerConfig(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %08x\n", rc); + + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, + DSSPEAKER_GEOMETRY_WIDE); + rc=IDirectSound_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"IDirectSound_SetSpeakerConfig() failed: %08x\n", rc); + if (rc==DS_OK) { + rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config); + ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %08x\n", rc); + if (rc==DS_OK && speaker_config!=new_speaker_config) + trace("IDirectSound_GetSpeakerConfig() failed to set speaker " + "config: expected 0x%08x, got 0x%08x\n", + speaker_config,new_speaker_config); + } + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); +} + +static void IDirectSound_tests(void) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPCLASSFACTORY cf=NULL; + + trace("Testing IDirectSound\n"); + + rc=CoGetClassObject(&CLSID_DirectSound, CLSCTX_INPROC_SERVER, NULL, + &IID_IClassFactory, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound, IID_IClassFactory) " + "failed: %08x\n", rc); + + rc=CoGetClassObject(&CLSID_DirectSound, CLSCTX_INPROC_SERVER, NULL, + &IID_IUnknown, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound, IID_IUnknown) " + "failed: %08x\n", rc); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound_test(dso, FALSE, NULL); + + /* try the COM class factory method of creation with default playback + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound_test(dso, FALSE, &DSDEVID_DefaultPlayback); + + /* try the COM class factory method of creation with default voice + * playback device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dso); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSound,CLSID_DirectSoundPrivate) " + "should have failed: %08x\n",rc); + + /* try the COM class factory method of creation with a bad + * GUID and IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==REGDB_E_CLASSNOTREG, + "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound) " + "should have failed: %08x\n",rc); + + /* try with no device specified */ + rc=pDirectSoundCreate(NULL,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(NULL) failed: %08x\n",rc); + if (rc==S_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with default playback device specified */ + rc=pDirectSoundCreate(&DSDEVID_DefaultPlayback,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(DSDEVID_DefaultPlayback) failed: %08x\n", rc); + if (rc==DS_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with default voice playback device specified */ + rc=pDirectSoundCreate(&DSDEVID_DefaultVoicePlayback,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(DSDEVID_DefaultVoicePlayback) failed: %08x\n", rc); + if (rc==DS_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with a bad device specified */ + rc=pDirectSoundCreate(&DSDEVID_DefaultVoiceCapture,&dso,NULL); + ok(rc==DSERR_NODRIVER,"DirectSoundCreate(DSDEVID_DefaultVoiceCapture) " + "should have failed: %08x\n",rc); + if (rc==DS_OK && dso) + IDirectSound_Release(dso); +} + +static HRESULT test_dsound(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + int ref; + + /* DSOUND: Error: Invalid interface buffer */ + rc=pDirectSoundCreate(lpGuid,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Try the enumerated device */ + IDirectSound_test(dso, TRUE, lpGuid); + + /* Try the COM class factory method of creation with enumerated device */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound_test(dso, FALSE, lpGuid); + + /* Create a DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc); + if (rc==DS_OK) { + LPDIRECTSOUND dso1=NULL; + + /* Create a second DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso1,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc); + if (rc==DS_OK) { + /* Release the second DirectSound object */ + ref=IDirectSound_Release(dso1); + ok(ref==0,"IDirectSound_Release() has %d references, should have " + "0\n",ref); + ok(dso!=dso1,"DirectSound objects should be unique: dso=%p,dso1=%p\n",dso,dso1); + } + + /* Release the first DirectSound object */ + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + /* Create a DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc); + if (rc==DS_OK) { + LPDIRECTSOUNDBUFFER secondary; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D; + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a secondary " + "buffer %08x\n",rc); + if (rc==DS_OK && secondary!=NULL) { + LPDIRECTSOUND3DBUFFER buffer3d; + rc=IDirectSound_QueryInterface(secondary, &IID_IDirectSound3DBuffer, + (void **)&buffer3d); + ok(rc==DS_OK && buffer3d!=NULL,"IDirectSound_QueryInterface() " + "failed: %08x\n",rc); + if (rc==DS_OK && buffer3d!=NULL) { + ref=IDirectSound3DBuffer_AddRef(buffer3d); + ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + ref=IDirectSoundBuffer_AddRef(secondary); + ok(ref==2,"IDirectSoundBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + /* release with buffer */ + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + return DS_OK; +} + +static HRESULT test_primary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound_CreateSoundBuffer(dso,0,0,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_CreateSoundBuffer() should have failed: %08x\n", rc); + + /* DSOUND: Error: NULL pointer is invalid */ + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound_CreateSoundBuffer(dso,0,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x," + "dsbo=%p\n",rc,primary); + + /* DSOUND: Error: Invalid size */ + /* DSOUND: Error: Invalid buffer description */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc)-1; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x," + "primary=%p\n",rc,primary); + + /* DSOUND: Error: DSBCAPS_PRIMARYBUFFER flag with non-NULL lpwfxFormat */ + /* DSOUND: Error: Invalid buffer description pointer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x," + "primary=%p\n",rc,primary); + + /* DSOUND: Error: No DSBCAPS_PRIMARYBUFFER flag with NULL lpwfxFormat */ + /* DSOUND: Error: Invalid buffer description pointer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.lpwfxFormat=NULL; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x," + "primary=%p\n",rc,primary); + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + bufdesc.lpwfxFormat = &wfx; + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_CreateSoundBuffer() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK && primary!=NULL) + IDirectSoundBuffer_Release(primary); + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: %08x\n",rc); + if (rc==DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + LONG vol; + + /* Try to create a second primary buffer */ + /* DSOUND: Error: The primary buffer already exists. + * Any changes made to the buffer description will be ignored. */ + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&second,NULL); + ok(rc==DS_OK && second==primary, + "IDirectSound_CreateSoundBuffer() should have returned original " + "primary buffer: %08x\n",rc); + ref=IDirectSoundBuffer_Release(second); + ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 1\n",ref); + + /* Try to duplicate a primary buffer */ + /* DSOUND: Error: Can't duplicate primary buffers */ + rc=IDirectSound_DuplicateSoundBuffer(dso,primary,&third); + /* rc=0x88780032 */ + ok(rc!=DS_OK,"IDirectSound_DuplicateSoundBuffer() primary buffer " + "should have failed %08x\n",rc); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc); + + if (winetest_interactive) { + trace("Playing a 5 seconds reference tone at the current " + "volume.\n"); + if (rc==DS_OK) + trace("(the current volume is %d according to DirectSound)\n", + vol); + trace("All subsequent tones should be identical to this one.\n"); + trace("Listen for stutter, changes in pitch, volume, etc.\n"); + } + test_buffer(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0,FALSE,0); + + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +/* + * Test the primary buffer at different formats while keeping the + * secondary buffer at a constant format. + */ +static HRESULT test_primary_secondary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx, wfx2; + int f,ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a primary buffer %08x\n",rc); + + if (rc==DS_OK && primary!=NULL) { + for (f=0;f 16) + ok(((rc == DSERR_CONTROLUNAVAIL || rc == DSERR_INVALIDCALL || rc == DSERR_INVALIDPARAM /* 2003 */) && !secondary) + || rc == DS_OK, /* driver dependent? */ + "IDirectSound_CreateSoundBuffer() " + "should have returned (DSERR_CONTROLUNAVAIL or DSERR_INVALIDCALL) " + "and NULL, returned: %08x %p\n", rc, secondary); + else + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n",rc); + } + else + ok(rc==E_INVALIDARG, "Creating %d bpp buffer on dx < 8 returned: %p %08x\n", + wfx.wBitsPerSample, secondary, rc); + + if (!gotdx8) + { + skip("Not doing the WAVE_FORMAT_EXTENSIBLE tests\n"); + /* Apparently they succeed with bogus values, + * which means that older dsound doesn't look at them + */ + goto no_wfe; + } + + if (secondary) + IDirectSoundBuffer_Release(secondary); + secondary = NULL; + + bufdesc.lpwfxFormat=(WAVEFORMATEX*)&wfxe; + wfxe.Format = wfx; + wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + wfxe.Format.cbSize = 1; + wfxe.Samples.wValidBitsPerSample = wfx.wBitsPerSample; + wfxe.dwChannelMask = (wfx.nChannels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO); + + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok((rc==DSERR_INVALIDPARAM || rc==DSERR_INVALIDCALL /* 2003 */) && !secondary, + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + + wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx) + 1; + + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL || rc==DSERR_INVALIDPARAM) + && !secondary) + || rc==DS_OK, /* 2003 / 2008 */ + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + + wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx); + wfxe.SubFormat = GUID_NULL; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok((rc==DSERR_INVALIDPARAM || rc==DSERR_INVALIDCALL) && !secondary, + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + ++wfxe.Samples.wValidBitsPerSample; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DSERR_INVALIDPARAM && !secondary, + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + --wfxe.Samples.wValidBitsPerSample; + + wfxe.Samples.wValidBitsPerSample = 0; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary, + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + wfxe.Samples.wValidBitsPerSample = wfxe.Format.wBitsPerSample; + + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n",rc); + +no_wfe: + if (rc==DS_OK && secondary!=NULL) { + if (winetest_interactive) { + trace(" Testing a secondary buffer at %dx%dx%d " + "with a primary buffer at %dx%dx%d\n", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels); + } + test_buffer(dso,&secondary,0,FALSE,0,FALSE,0, + winetest_interactive,1.0,0,NULL,0,0,FALSE,0); + + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " + "should have 0\n",ref); + } + } +EXIT1: + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_block_align(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER secondary=NULL; + DSBUFFERDESC bufdesc; + DSBCAPS dsbcaps; + WAVEFORMATEX wfx; + DWORD pos, pos2; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + init_format(&wfx,WAVE_FORMAT_PCM,11025,16,2); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; + bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec + 1; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK,"IDirectSound_CreateSoundBuffer() " + "should have returned DS_OK, returned: %08x\n", rc); + + if (rc==DS_OK && secondary!=NULL) { + ZeroMemory(&dsbcaps, sizeof(dsbcaps)); + dsbcaps.dwSize = sizeof(dsbcaps); + rc=IDirectSoundBuffer_GetCaps(secondary,&dsbcaps); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() should have returned DS_OK, " + "returned: %08x\n", rc); + if (rc==DS_OK && wfx.nBlockAlign > 1) + { + ok(dsbcaps.dwBufferBytes==(wfx.nAvgBytesPerSec + wfx.nBlockAlign), + "Buffer size not a multiple of nBlockAlign: requested %d, " + "got %d, should be %d\n", bufdesc.dwBufferBytes, + dsbcaps.dwBufferBytes, wfx.nAvgBytesPerSec + wfx.nBlockAlign); + + rc = IDirectSoundBuffer_SetCurrentPosition(secondary, 0); + ok(rc == DS_OK, "Could not set position to 0: %08x\n", rc); + rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &pos, NULL); + ok(rc == DS_OK, "Could not get position: %08x\n", rc); + rc = IDirectSoundBuffer_SetCurrentPosition(secondary, 1); + ok(rc == DS_OK, "Could not set position to 1: %08x\n", rc); + rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &pos2, NULL); + ok(rc == DS_OK, "Could not get new position: %08x\n", rc); + ok(pos == pos2, "Positions not the same! Old position: %d, new position: %d\n", pos, pos2); + } + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d references, " + "should have 0\n",ref); + } + + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static struct fmt { + int bits; + int channels; +} fmts[] = { { 8, 1 }, { 8, 2 }, { 16, 1 }, {16, 2 } }; + +static HRESULT test_frequency(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx, wfx1; + DWORD f, r; + int ref; + int rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, + 48000, 96000 }; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a primary buffer %08x\n",rc); + + if (rc==DS_OK && primary!=NULL) { + rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT1; + + for (f=0;f + + + + . + + wine + uuid + dsound + dxguid + ole32 + user32 + capture.c + ds3d8.c + ds3d.c + dsound8.c + dsound.c + duplex.c + propset.c + testlist.c + + diff --git a/rostests/winetests/dsound/dsound8.c b/rostests/winetests/dsound/dsound8.c new file mode 100644 index 00000000000..a2b16d85bbb --- /dev/null +++ b/rostests/winetests/dsound/dsound8.c @@ -0,0 +1,940 @@ +/* + * Tests basic sound playback in DirectSound. + * In particular we test each standard Windows sound format to make sure + * we handle the sound card/driver quirks correctly. + * + * Part of this test involves playing test tones. But this only makes + * sense if someone is going to carefully listen to it, and would only + * bother everyone else. + * So this is only done if the test is being run in interactive mode. + * + * Copyright (c) 2002-2004 Francois Gouget + * + * 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 + */ + +#include +#include + +#include "wine/test.h" +#include "dsound.h" +#include "dsconf.h" +#include "mmreg.h" +#include "ks.h" +#include "ksmedia.h" + +#include "dsound_test.h" + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL; + +int align(int length, int align) +{ + return (length / align) * align; +} + +static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized, + LPCGUID lpGuid) +{ + HRESULT rc; + DSCAPS dscaps; + int ref; + IUnknown * unknown; + IDirectSound * ds; + IDirectSound8 * ds8; + DWORD speaker_config, new_speaker_config; + DWORD certified; + + /* Try to Query for objects */ + rc=IDirectSound8_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IUnknown) failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSound8_Release(unknown); + + rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound) failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSound_Release(ds); + + rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound8) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK) + IDirectSound8_Release(ds8); + + if (initialized == FALSE) { + /* try uninitialized object */ + rc=IDirectSound8_GetCaps(dso,0); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps(NULL) " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_Compact(dso); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_Compact() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetSpeakerConfig() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_VerifyCertification(dso, &certified); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_VerifyCertification() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_Initialize(dso,lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "IDirectSound8_Initialize() failed: %08x\n",rc); + if (rc==DSERR_NODRIVER) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSound8_Initialize(dso,lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound8_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound8_GetCaps(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + ZeroMemory(&dscaps, sizeof(dscaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + dscaps.dwSize=sizeof(dscaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc); + + rc=IDirectSound8_Compact(dso); + ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound8_Compact() failed: %08x\n", rc); + + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc); + + rc=IDirectSound8_Compact(dso); + ok(rc==DS_OK,"IDirectSound8_Compact() failed: %08x\n",rc); + + rc=IDirectSound8_GetSpeakerConfig(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetSpeakerConfig(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc); + + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, + DSSPEAKER_GEOMETRY_WIDE); + rc=IDirectSound8_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"IDirectSound8_SetSpeakerConfig() failed: %08x\n", rc); + if (rc==DS_OK) { + rc=IDirectSound8_GetSpeakerConfig(dso,&new_speaker_config); + ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc); + if (rc==DS_OK && speaker_config!=new_speaker_config) + trace("IDirectSound8_GetSpeakerConfig() failed to set speaker " + "config: expected 0x%08x, got 0x%08x\n", + speaker_config,new_speaker_config); + } + + rc=IDirectSound8_VerifyCertification(dso, &certified); + ok(rc==DS_OK||rc==E_NOTIMPL,"IDirectSound8_VerifyCertification() failed: %08x\n", rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); +} + +static void IDirectSound8_tests(void) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPCLASSFACTORY cf=NULL; + + trace("Testing IDirectSound8\n"); + + rc=CoGetClassObject(&CLSID_DirectSound8, CLSCTX_INPROC_SERVER, NULL, + &IID_IClassFactory, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound8, IID_IClassFactory) " + "failed: %08x\n", rc); + + rc=CoGetClassObject(&CLSID_DirectSound8, CLSCTX_INPROC_SERVER, NULL, + &IID_IUnknown, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound8, IID_IUnknown) " + "failed: %08x\n", rc); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance() failed: %08x\n", rc); + if (rc==REGDB_E_CLASSNOTREG) { + trace(" Class Not Registered\n"); + return; + } + if (dso) + IDirectSound8_test(dso, FALSE, NULL); + + /* try the COM class factory method of creation with default playback + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %08x\n", rc); + if (dso) + IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultPlayback); + + /* try the COM class factory method of creation with default voice + * playback device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %08x\n", rc); + if (dso) + IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dso); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSound8,CLSID_DirectSoundPrivate) " + "should have failed: %08x\n",rc); + + /* try the COM class factory method of creation with a bad + * GUID and IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==REGDB_E_CLASSNOTREG, + "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound8) " + "should have failed: %08x\n",rc); + + /* try with no device specified */ + rc=pDirectSoundCreate8(NULL,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with default playback device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultPlayback,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with default voice playback device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultVoicePlayback,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with a bad device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultVoiceCapture,&dso,NULL); + ok(rc==DSERR_NODRIVER,"DirectSoundCreate8(DSDEVID_DefaultVoiceCapture) " + "should have failed: %08x\n",rc); +} + +static HRESULT test_dsound8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + int ref; + + /* DSOUND: Error: Invalid interface buffer */ + rc=pDirectSoundCreate8(lpGuid,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate8() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* Create the DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Try the enumerated device */ + IDirectSound8_test(dso, TRUE, lpGuid); + + /* Try the COM class factory method of creation with enumerated device */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound8_test(dso, FALSE, lpGuid); + + /* Create a DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK) { + LPDIRECTSOUND8 dso1=NULL; + + /* Create a second DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso1,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK) { + /* Release the second DirectSound8 object */ + ref=IDirectSound8_Release(dso1); + ok(ref==0,"IDirectSound8_Release() has %d references, " + "should have 0\n",ref); + ok(dso!=dso1,"DirectSound8 objects should be unique: " + "dso=%p,dso1=%p\n",dso,dso1); + } + + /* Release the first DirectSound8 object */ + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + /* Create a DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK) { + LPDIRECTSOUNDBUFFER secondary; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D; + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound8_CreateSoundBuffer() failed to create a secondary " + "buffer: %08x\n",rc); + if (rc==DS_OK && secondary!=NULL) { + LPDIRECTSOUND3DBUFFER buffer3d; + LPDIRECTSOUNDBUFFER8 buffer8; + rc=IDirectSound8_QueryInterface(secondary, + &IID_IDirectSound3DBuffer, + (void **)&buffer3d); + ok(rc==DS_OK && buffer3d!=NULL, + "IDirectSound8_QueryInterface() failed: %08x\n", rc); + if (rc==DS_OK && buffer3d!=NULL) { + ref=IDirectSound3DBuffer_AddRef(buffer3d); + ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + rc=IDirectSound8_QueryInterface(secondary, + &IID_IDirectSoundBuffer8, + (void **)&buffer8); + if (rc==DS_OK && buffer8!=NULL) { + ref=IDirectSoundBuffer8_AddRef(buffer8); + ok(ref==3,"IDirectSoundBuffer8_AddRef() has %d references, " + "should have 3\n",ref); + } + ref=IDirectSoundBuffer_AddRef(secondary); + ok(ref==4,"IDirectSoundBuffer_AddRef() has %d references, " + "should have 4\n",ref); + } + /* release with buffer */ + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + return DS_OK; +} + +static HRESULT test_primary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL; + LPDIRECTSOUNDBUFFER8 pb8 = NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,0,0,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_CreateSoundBuffer should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,0,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: rc=%08x,dsbo=%p\n", + rc,primary); + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize = sizeof(DSBUFFERDESC); + + /* DSOUND: Error: Invalid dsound buffer interface pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,0,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have failed: rc=%08x," + "dsbo=%p\n",rc,primary); + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + + /* DSOUND: Error: Invalid size */ + /* DSOUND: Error: Invalid buffer description */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have failed: rc=%08x," + "primary=%p\n",rc,primary); + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + bufdesc.lpwfxFormat = &wfx; + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2); + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_CreateSoundBuffer() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK && primary!=NULL) + IDirectSoundBuffer_Release(primary); + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer: " + "%08x\n",rc); + if (rc==DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + LONG vol; + + /* Try to create a second primary buffer */ + /* DSOUND: Error: The primary buffer already exists. + * Any changes made to the buffer description will be ignored. */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&second,NULL); + ok(rc==DS_OK && second==primary, + "IDirectSound8_CreateSoundBuffer() should have returned original " + "primary buffer: %08x\n",rc); + ref=IDirectSoundBuffer_Release(second); + ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 1\n",ref); + + /* Try to duplicate a primary buffer */ + /* DSOUND: Error: Can't duplicate primary buffers */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,primary,&third); + /* rc=0x88780032 */ + ok(rc!=DS_OK,"IDirectSound8_DuplicateSoundBuffer() primary buffer " + "should have failed %08x\n",rc); + + /* Primary buffers don't have an IDirectSoundBuffer8 */ + rc = IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer8, (LPVOID*)&pb8); + ok(FAILED(rc), "Primary buffer does have an IDirectSoundBuffer8: %08x\n", rc); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc); + + if (winetest_interactive) { + trace("Playing a 5 seconds reference tone at the current volume.\n"); + if (rc==DS_OK) + trace("(the current volume is %d according to DirectSound)\n", + vol); + trace("All subsequent tones should be identical to this one.\n"); + trace("Listen for stutter, changes in pitch, volume, etc.\n"); + } + test_buffer8(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0); + + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +/* + * Test the primary buffer at different formats while keeping the + * secondary buffer at a constant format. + */ +static HRESULT test_primary_secondary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx, wfx2; + int ref; + unsigned int f; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL, + "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer " + "%08x\n",rc); + + if (rc==DS_OK && primary!=NULL) { + for (f=0;f + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "mmreg.h" +#include "dsconf.h" + +#include "dsound_test.h" + +static HRESULT (WINAPI *pDirectSoundFullDuplexCreate)(LPCGUID, LPCGUID, + LPCDSCBUFFERDESC, LPCDSBUFFERDESC, HWND, DWORD, LPDIRECTSOUNDFULLDUPLEX *, + LPDIRECTSOUNDCAPTUREBUFFER8*, LPDIRECTSOUNDBUFFER8*, LPUNKNOWN)=NULL; + +static void IDirectSoundFullDuplex_test(LPDIRECTSOUNDFULLDUPLEX dsfdo, + BOOL initialized, LPCGUID lpGuidCapture, + LPCGUID lpGuidRender) +{ + HRESULT rc; + int ref; + IUnknown * unknown; + IDirectSound * ds; + IDirectSound8 * ds8; + IDirectSoundCapture * dsc; + IDirectSoundFullDuplex * dsfd; + + /* Try to Query for objects */ + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IUnknown,(LPVOID*)&unknown); + ok(rc==DS_OK,"IDirectSoundFullDuplex_QueryInterface(IID_IUnknown) failed: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundFullDuplex_Release(unknown); + ok(ref==0, "IDirectSoundFullDuplex_Release() has %d references, " + "should have 0\n", ref); + } + + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSound,(LPVOID*)&ds); + ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSound) failed: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSound_Release(ds); + ok(ref==0, "IDirectSound_Release() has %d references, " + "should have 0\n", ref); + } + + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSound8,(LPVOID*)&ds8); + ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSound8) " + "failed: %08x\n",rc); + if (rc==DS_OK) { + IDirectSoundFullDuplex * dsfd1; + rc=IDirectSound8_QueryInterface(ds8,&IID_IDirectSoundFullDuplex,(LPVOID*)&dsfd1); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSoundFullDuplex) " + "failed: %08x\n",rc); + if (rc==DS_OK) { + ref=IDirectSoundFullDuplex_Release(dsfd1); + ok(ref==1, "IDirectSoundFullDuplex_Release() has %d references, " + "should have 1\n", ref); + } + ref=IDirectSound8_Release(ds8); + ok(ref==0, "IDirectSound8_Release() has %d references, " + "should have 0\n", ref); + } + + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSoundCapture,(LPVOID*)&dsc); + ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSoundCapture) " + "failed: %08x\n",rc); + if (rc==DS_OK) { + ref=IDirectSoundCapture_Release(dsc); + ok(ref==0, "IDirectSoundCapture_Release() has %d references, " + "should have 0\n", ref); + } + + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSoundFullDuplex,(LPVOID*)&dsfd); + ok(rc==DS_OK,"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSoundFullDuplex) " + "failed: %08x\n",rc); + if (rc==DS_OK) { + ok (dsfdo==dsfd, "different interfaces\n"); + ref=IDirectSound8_Release(dsfd); + } + + ref=IDirectSoundFullDuplex_Release(dsfdo); + ok(ref==0, "IDirectSoundFullDuplex_Release() has %d references, " + "should have 0\n", ref); +} + +static void IDirectSoundFullDuplex_tests(void) +{ + HRESULT rc; + LPDIRECTSOUNDFULLDUPLEX dsfdo = NULL; + DSCBUFFERDESC DSCBufferDesc; + DSBUFFERDESC DSBufferDesc; + LPDIRECTSOUNDCAPTUREBUFFER8 pDSCBuffer8; + LPDIRECTSOUNDBUFFER8 pDSBuffer8; + WAVEFORMATEX wfex; + + trace("Testing IDirectSoundFullDuplex\n"); + + /* try the COM class factory method of creation with no devices specified */ + rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, + CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex, + (void**)&dsfdo); + ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG||rc==CLASS_E_CLASSNOTAVAILABLE, + "CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc); + if (rc==REGDB_E_CLASSNOTREG) { + trace(" Class Not Registered\n"); + return; + } else if (rc==CLASS_E_CLASSNOTAVAILABLE) { + trace(" Class Not Available\n"); + return; + } + if (dsfdo) + IDirectSoundFullDuplex_test(dsfdo, FALSE, NULL, NULL); + + /* try the COM class factory method of creation with default devices + * specified */ + rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, + CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex, + (void**)&dsfdo); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc); + if (dsfdo) + IDirectSoundFullDuplex_test(dsfdo, FALSE, &DSDEVID_DefaultCapture, + &DSDEVID_DefaultPlayback); + + /* try the COM class factory method of creation with default voice + * devices specified */ + rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, + CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex, + (void**)&dsfdo); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc); + if (dsfdo) + IDirectSoundFullDuplex_test(dsfdo, FALSE, &DSDEVID_DefaultVoiceCapture, + &DSDEVID_DefaultVoicePlayback); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, + CLSCTX_INPROC_SERVER, &CLSID_DirectSoundPrivate, + (void**)&dsfdo); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSoundFullDuplex,CLSID_DirectSoundPrivate) " + "should have failed: 0x%08x\n", rc); + + ZeroMemory(&wfex, sizeof(wfex)); + wfex.wFormatTag = WAVE_FORMAT_PCM; + wfex.nChannels = 1; + wfex.nSamplesPerSec = 8000; + wfex.wBitsPerSample = 16; + wfex.nBlockAlign = (wfex.wBitsPerSample * wfex.nChannels) / 8; + wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign; + + ZeroMemory(&DSCBufferDesc, sizeof(DSCBufferDesc)); + DSCBufferDesc.dwSize = sizeof(DSCBufferDesc); + DSCBufferDesc.dwFlags = DSCBCAPS_WAVEMAPPED; + DSCBufferDesc.dwBufferBytes = 8192; + DSCBufferDesc.lpwfxFormat = &wfex; + + ZeroMemory(&DSBufferDesc, sizeof(DSBufferDesc)); + DSBufferDesc.dwSize = sizeof(DSBufferDesc); + DSBufferDesc.dwFlags = DSBCAPS_GLOBALFOCUS; + DSBufferDesc.dwBufferBytes = 8192; + DSBufferDesc.lpwfxFormat = &wfex; + + /* try with no device specified */ + rc=pDirectSoundFullDuplexCreate(NULL,NULL,&DSCBufferDesc,&DSBufferDesc, + get_hwnd(),DSSCL_EXCLUSIVE ,&dsfdo,&pDSCBuffer8, + &pDSBuffer8,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL, + "DirectSoundFullDuplexCreate(NULL,NULL) failed: %08x\n",rc); + if (rc==S_OK && dsfdo) + IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL); + + /* try with default devices specified */ + rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultCapture, + &DSDEVID_DefaultPlayback,&DSCBufferDesc, + &DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE,&dsfdo, + &pDSCBuffer8,&pDSBuffer8,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL, + "DirectSoundFullDuplexCreate(DSDEVID_DefaultCapture," + "DSDEVID_DefaultPlayback) failed: %08x\n", rc); + if (rc==DS_OK && dsfdo) + IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL); + + /* try with default voice devices specified */ + rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultVoiceCapture, + &DSDEVID_DefaultVoicePlayback, + &DSCBufferDesc,&DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE, + &dsfdo,&pDSCBuffer8,&pDSBuffer8,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL, + "DirectSoundFullDuplexCreate(DSDEVID_DefaultVoiceCapture," + "DSDEVID_DefaultVoicePlayback) failed: %08x\n", rc); + if (rc==DS_OK && dsfdo) + IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL); + + /* try with bad devices specified */ + rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultVoicePlayback, + &DSDEVID_DefaultVoiceCapture, + &DSCBufferDesc,&DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE, + &dsfdo,&pDSCBuffer8,&pDSBuffer8,NULL); + ok(rc==DSERR_NODRIVER||rc==DSERR_INVALIDCALL, + "DirectSoundFullDuplexCreate(DSDEVID_DefaultVoicePlayback," + "DSDEVID_DefaultVoiceCapture) should have failed: %08x\n", rc); + if (rc==DS_OK && dsfdo) + IDirectSoundFullDuplex_Release(dsfdo); +} + +START_TEST(duplex) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibrary("dsound.dll"); + if (hDsound) + { + + pDirectSoundFullDuplexCreate=(void*)GetProcAddress(hDsound, + "DirectSoundFullDuplexCreate"); + if (pDirectSoundFullDuplexCreate) + IDirectSoundFullDuplex_tests(); + else + skip("duplex test skipped\n"); + + FreeLibrary(hDsound); + } + else + skip("dsound.dll not found!\n"); + + CoUninitialize(); +} diff --git a/rostests/winetests/dsound/propset.c b/rostests/winetests/dsound/propset.c new file mode 100644 index 00000000000..70a8e0d9f24 --- /dev/null +++ b/rostests/winetests/dsound/propset.c @@ -0,0 +1,748 @@ +/* + * Unit tests for CLSID_DirectSoundPrivate property set functions + * (used by dxdiag) + * + * Copyright (c) 2003 Robert Reif + * + * 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 + */ + +#define COBJMACROS +#include + +#include "wine/test.h" +#include "dsound.h" +#include "dsconf.h" + +#include "dsound_test.h" + +#ifndef DSBCAPS_CTRLDEFAULT +#define DSBCAPS_CTRLDEFAULT \ + DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME +#endif + +#include "initguid.h" + +DEFINE_GUID(DSPROPSETID_VoiceManager, + 0x62A69BAE,0xDF9D,0x11D1,0x99,0xA6,0x00,0xC0,0x4F,0xC9,0x9D,0x46); +DEFINE_GUID(DSPROPSETID_EAX20_ListenerProperties, + 0x306a6a8,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22); +DEFINE_GUID(DSPROPSETID_EAX20_BufferProperties, + 0x306a6a7,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22); +DEFINE_GUID(DSPROPSETID_I3DL2_ListenerProperties, + 0xDA0F0520,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11); +DEFINE_GUID(DSPROPSETID_I3DL2_BufferProperties, + 0xDA0F0521,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11); +DEFINE_GUID(DSPROPSETID_ZOOMFX_BufferProperties, + 0xCD5368E0,0x3450,0x11D3,0x8B,0x6E,0x00,0x10,0x5A,0x9B,0x7B,0xBC); + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID*)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*, + LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*, + LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID, + LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureCreate8)(LPCGUID, + LPDIRECTSOUNDCAPTURE8*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundFullDuplexCreate)(LPCGUID,LPCGUID, + LPCDSCBUFFERDESC,LPCDSBUFFERDESC,HWND,DWORD,LPDIRECTSOUNDFULLDUPLEX*, + LPDIRECTSOUNDCAPTUREBUFFER8*,LPDIRECTSOUNDBUFFER8*,LPUNKNOWN)=NULL; + +static BOOL CALLBACK callback(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA data, + LPVOID context) +{ + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" Description: %s\n", data->Description); + trace(" Module: %s\n", data->Module); + trace(" Interface: %s\n", data->Interface); + trace(" WaveDeviceId: %d\n", data->WaveDeviceId); + + return TRUE; +} + +static BOOL CALLBACK callback1(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA data, + LPVOID context) +{ + char descriptionA[0x100]; + char moduleA[MAX_PATH]; + + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" DescriptionA: %s\n", data->DescriptionA); + WideCharToMultiByte(CP_ACP, 0, data->DescriptionW, -1, descriptionA, sizeof(descriptionA), NULL, NULL); + trace(" DescriptionW: %s\n", descriptionA); + trace(" ModuleA: %s\n", data->ModuleA); + WideCharToMultiByte(CP_ACP, 0, data->ModuleW, -1, moduleA, sizeof(moduleA), NULL, NULL); + trace(" ModuleW: %s\n", moduleA); + trace(" WaveDeviceId: %d\n", data->WaveDeviceId); + + return TRUE; +} + +static BOOL CALLBACK callbackA(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA data, + LPVOID context) +{ + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" Description: %s\n", data->Description); + trace(" Module: %s\n", data->Module); + trace(" Interface: %s\n", data->Interface); + trace(" WaveDeviceId: %d\n", data->WaveDeviceId); + + return TRUE; +} + +static BOOL CALLBACK callbackW(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data, + LPVOID context) +{ + char descriptionA[0x100]; + char moduleA[MAX_PATH]; + char interfaceA[MAX_PATH]; + + trace("found device:\n"); + trace("\tType: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace("\tDataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace("\tDeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + WideCharToMultiByte(CP_ACP, 0, data->Description, -1, descriptionA, sizeof(descriptionA), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, data->Module, -1, moduleA, sizeof(moduleA), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, data->Interface, -1, interfaceA, sizeof(interfaceA), NULL, NULL); + trace("\tDescription: %s\n", descriptionA); + trace("\tModule: %s\n", moduleA); + trace("\tInterface: %s\n", interfaceA); + trace("\tWaveDeviceId: %d\n", data->WaveDeviceId); + + return TRUE; +} + +static void propset_private_tests(void) +{ + HRESULT rc; + IClassFactory * pcf; + IKsPropertySet * pps; + ULONG support; + + /* try direct sound first */ + /* DSOUND: Error: Invalid interface buffer */ + rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IClassFactory, NULL); + ok(rc==DSERR_INVALIDPARAM,"DllGetClassObject(CLSID_DirectSound, " + "IID_IClassFactory) should have returned DSERR_INVALIDPARAM, " + "returned: %08x\n",rc); + + rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IDirectSound, (void **)(&pcf)); + ok(rc==E_NOINTERFACE,"DllGetClassObject(CLSID_DirectSound, " + "IID_IDirectSound) should have returned E_NOINTERFACE, " + "returned: %08x\n",rc); + + rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IUnknown, (void **)(&pcf)); + ok(rc==DS_OK,"DllGetClassObject(CLSID_DirectSound, " + "IID_IUnknown) failed: %08x\n",rc); + + rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IClassFactory, (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound, IID_IClassFactory) " + "failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound doesn't have an IKsPropertySet */ + /* DSOUND: Error: Invalid interface buffer */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + NULL); + ok(rc==DSERR_INVALIDPARAM, "CreateInstance(IID_IKsPropertySet) should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %08x\n",rc); + + /* and the direct sound 8 version */ + if (pDirectSoundCreate8) { + rc = (pDllGetClassObject)(&CLSID_DirectSound8, &IID_IClassFactory, (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound8, IID_IClassFactory) " + "failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound 8 doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %08x\n",rc); + } + + /* try direct sound capture next */ + if (pDirectSoundCaptureCreate) { + rc = (pDllGetClassObject)(&CLSID_DirectSoundCapture, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) " + "failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound capture doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE,returned: %08x\n",rc); + } + + /* and the direct sound capture 8 version */ + if (pDirectSoundCaptureCreate8) { + rc = (pDllGetClassObject)(&CLSID_DirectSoundCapture8, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture8, " + "IID_IClassFactory) failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound capture 8 doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %08x\n",rc); + } + + /* try direct sound full duplex next */ + if (pDirectSoundFullDuplexCreate) { + rc = (pDllGetClassObject)(&CLSID_DirectSoundFullDuplex, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundFullDuplex, " + "IID_IClassFactory) failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound full duplex doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned NOINTERFACE, returned: %08x\n",rc); + } + + /* try direct sound private last */ + rc = (pDllGetClassObject)(&CLSID_DirectSoundPrivate, &IID_IClassFactory, + (void **)(&pcf)); + + /* some early versions of Direct Sound do not have this */ + if (rc==CLASS_E_CLASSNOTAVAILABLE) + return; + + /* direct sound private does have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==DS_OK, "CreateInstance(IID_IKsPropertySet) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION) failed: %08x\n", + rc); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + return; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: " + "support = 0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1 */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1) failed: %08x\n", + rc); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + return; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: " + "support = 0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A) failed: %08x\n", + rc); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + return; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: " + "support = 0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W) failed: %08x\n", + rc); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + return; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: " + "support = 0x%x\n",support); + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: support = " + "0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: support = " + "0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: support = " + "0x%x\n",support); + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: support = 0x%x\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_DATA data; + ULONG bytes; + + data.Callback = callback; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: support = 0x%x\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1_DATA data; + ULONG bytes; + + data.Callback = callback1; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: support = 0x%x\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A_DATA data; + ULONG bytes; + + data.Callback = callbackA; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: support = 0x%x\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA data; + ULONG bytes; + + data.Callback = callbackW; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc); + } +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + int ref; + + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate() failed: %08x\n",rc); + if (rc!=DS_OK) { + if (rc==DSERR_NODRIVER) + trace(" No Driver\n"); + else if (rc == DSERR_ALLOCATED) + trace(" Already In Use\n"); + else if (rc == E_FAIL) + trace(" No Device\n"); + goto EXIT; + } + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", + rc); + if (rc!=DS_OK) + goto EXIT; + + /* Testing 3D buffers */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_LOCHARDWARE|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK&&primary!=NULL) + || broken(rc==DSERR_INVALIDPARAM), + "IDirectSound_CreateSoundBuffer() failed to " + "create a hardware 3D primary buffer: %08x\n",rc); + if(rc==DSERR_INVALIDPARAM) { + skip("broken driver\n"); + goto EXIT; + } + if (rc==DS_OK&&primary!=NULL) { + ZeroMemory(&wfx, sizeof(wfx)); + wfx.wFormatTag=WAVE_FORMAT_PCM; + wfx.nChannels=1; + wfx.wBitsPerSample=16; + wfx.nSamplesPerSec=44100; + wfx.nBlockAlign=wfx.nChannels*wfx.wBitsPerSample/8; + wfx.nAvgBytesPerSec=wfx.nSamplesPerSec*wfx.nBlockAlign; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2; + bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec; + bufdesc.lpwfxFormat=&wfx; + trace(" Testing a secondary buffer at %dx%dx%d\n", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK&&secondary!=NULL,"IDirectSound_CreateSoundBuffer() " + "failed to create a secondary buffer: %08x\n",rc); + if (rc==DS_OK&&secondary!=NULL) { + IKsPropertySet * pPropertySet=NULL; + rc=IDirectSoundBuffer_QueryInterface(secondary, + &IID_IKsPropertySet, + (void **)&pPropertySet); + /* it's not an error for this to fail */ + if(rc==DS_OK) { + ULONG ulTypeSupport; + trace(" Supports property sets\n"); + /* it's not an error for these to fail */ + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_VoiceManager, + 0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_VoiceManager supported\n"); + else + trace(" DSPROPSETID_VoiceManager not supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_EAX20_ListenerProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_EAX20_ListenerProperties " + "supported\n"); + else + trace(" DSPROPSETID_EAX20_ListenerProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_EAX20_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_EAX20_BufferProperties supported\n"); + else + trace(" DSPROPSETID_EAX20_BufferProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_I3DL2_ListenerProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_I3DL2_ListenerProperties " + "supported\n"); + else + trace(" DSPROPSETID_I3DL2_ListenerProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_I3DL2_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_I3DL2_BufferProperties supported\n"); + else + trace(" DSPROPSETID_I3DL2_BufferProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_ZOOMFX_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_ZOOMFX_BufferProperties " + "supported\n"); + else + trace(" DSPROPSETID_ZOOMFX_BufferProperties not " + "supported\n"); + ref=IKsPropertySet_Release(pPropertySet); + /* try a few common ones */ + ok(ref==0,"IKsPropertySet_Release() secondary has %d " + "references, should have 0\n",ref); + } else + trace(" Doesn't support property sets\n"); + + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " + "references, should have 0\n",ref); + } + + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + +EXIT: + if (dso!=NULL) { + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + } + return 1; +} + +static void propset_buffer_tests(void) +{ + HRESULT rc; + rc=pDirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc); +} + +START_TEST(propset) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibrary("dsound.dll"); + if (hDsound) + { + + pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound, + "DirectSoundEnumerateA"); + pDllGetClassObject = (void *)GetProcAddress(hDsound, + "DllGetClassObject"); + pDirectSoundCreate = (void*)GetProcAddress(hDsound, + "DirectSoundCreate"); + pDirectSoundCreate8 = (void*)GetProcAddress(hDsound, + "DirectSoundCreate8"); + pDirectSoundCaptureCreate=(void*)GetProcAddress(hDsound, + "DirectSoundCaptureCreate"); + pDirectSoundCaptureCreate8=(void*)GetProcAddress(hDsound, + "DirectSoundCaptureCreate8"); + pDirectSoundFullDuplexCreate=(void*)GetProcAddress(hDsound, + "DirectSoundFullDuplexCreate"); + + propset_private_tests(); + propset_buffer_tests(); + + FreeLibrary(hDsound); + } + else + skip("dsound.dll not found!\n"); + + CoUninitialize(); +} diff --git a/rostests/winetests/dsound/testlist.c b/rostests/winetests/dsound/testlist.c new file mode 100644 index 00000000000..2afeb2ffd66 --- /dev/null +++ b/rostests/winetests/dsound/testlist.c @@ -0,0 +1,27 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_capture(void); +extern void func_ds3d8(void); +extern void func_ds3d(void); +extern void func_dsound8(void); +extern void func_dsound(void); +extern void func_duplex(void); +extern void func_propset(void); + +const struct test winetest_testlist[] = +{ + { "capture", func_capture }, + { "ds3d8", func_ds3d8 }, + { "ds3d", func_ds3d }, + { "dsound8", func_dsound8 }, + { "dsound", func_dsound }, + { "duplex", func_duplex }, + { "propset", func_propset }, + { 0, 0 } +}; diff --git a/rostests/winetests/fusion/asmcache.c b/rostests/winetests/fusion/asmcache.c new file mode 100644 index 00000000000..81c0e762d4f --- /dev/null +++ b/rostests/winetests/fusion/asmcache.c @@ -0,0 +1,1533 @@ +/* + * Copyright 2008 James Hawkins + * + * 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 + */ + +#define COBJMACROS +#define INITGUID + +#include + +#include +#include +#include +#include + +#include "wine/test.h" + +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 +#define CLDB_E_FILE_OLDVER EMAKEHR(0x1107) + +typedef struct _tagASSEMBLY ASSEMBLY; + +typedef struct +{ + ULONG Signature; + USHORT MajorVersion; + USHORT MinorVersion; + ULONG Reserved; + ULONG VersionLength; + BYTE Version[12]; + BYTE Flags; + WORD Streams; +} METADATAHDR; + +#include + +typedef struct +{ + DWORD Offset; + DWORD Size; +} METADATASTREAMHDR; + +typedef struct +{ + DWORD Reserved1; + BYTE MajorVersion; + BYTE MinorVersion; + BYTE HeapOffsetSizes; + BYTE Reserved2; + LARGE_INTEGER MaskValid; + LARGE_INTEGER MaskSorted; +} METADATATABLESHDR; + +typedef struct +{ + WORD Generation; + WORD Name; + WORD Mvid; + WORD EncId; + WORD EncBaseId; +} MODULETABLE; + +typedef struct +{ + DWORD Flags; + WORD Name; + WORD Namespace; + WORD Extends; + WORD FieldList; + WORD MethodList; +} TYPEDEFTABLE; + +typedef struct +{ + DWORD HashAlgId; + WORD MajorVersion; + WORD MinorVersion; + WORD BuildNumber; + WORD RevisionNumber; + DWORD Flags; + WORD PublicKey; + WORD Name; + WORD Culture; +} ASSEMBLYTABLE; + +typedef struct +{ + DWORD Offset; + DWORD Flags; + WORD Name; + WORD Implementation; +} MANIFESTRESTABLE; + +typedef struct +{ + DWORD ImportLookupTable; + DWORD DateTimeStamp; + DWORD ForwarderChain; + DWORD Name; + DWORD ImportAddressTable; + BYTE pad[20]; +} IMPORTTABLE; + +typedef struct +{ + DWORD HintNameTableRVA; + BYTE pad[8]; +} IMPORTLOOKUPTABLE; + +typedef struct +{ + WORD Hint; + BYTE Name[12]; + BYTE Module[12]; + DWORD Reserved; + WORD EntryPoint; + DWORD RVA; +} HINTNAMETABLE; + +typedef struct +{ + DWORD PageRVA; + DWORD Size; + DWORD Relocation; +} RELOCATION; + +typedef struct +{ + WORD wLength; + WORD wValueLength; + WORD wType; + WCHAR szKey[17]; + VS_FIXEDFILEINFO Value; +} VS_VERSIONINFO; + +typedef struct +{ + WORD wLength; + WORD wValueLength; + WORD wType; + WCHAR szKey[13]; +} VARFILEINFO; + +typedef struct +{ + WORD wLength; + WORD wValueLength; + WORD wType; + WCHAR szKey[13]; + DWORD Value; +} VAR; + +typedef struct +{ + WORD wLength; + WORD wValueLength; + WORD wType; + WCHAR szKey[15]; +} STRINGFILEINFO; + +typedef struct +{ + WORD wLength; + WORD wValueLength; + WORD wType; + WCHAR szKey[9]; +} STRINGTABLE; + +typedef struct +{ + WORD wLength; + WORD wValueLength; + WORD wType; +} STRINGHDR; + +typedef struct +{ + DWORD Size; + DWORD Signature; + DWORD HeaderVersion; + DWORD SkipBytes; + BYTE Data[168]; +} RESOURCE; + +#include + +static struct _tagASSEMBLY +{ + IMAGE_DOS_HEADER doshdr; + WORD unknown[32]; + IMAGE_NT_HEADERS32 nthdrs; + IMAGE_SECTION_HEADER text; + IMAGE_SECTION_HEADER rsrc; + IMAGE_SECTION_HEADER reloc; + BYTE pad[16]; + IMAGE_IMPORT_BY_NAME iat; + BYTE pad2[3]; + IMAGE_COR20_HEADER clrhdr; + WORD strongname[64]; + RESOURCE resource; + METADATAHDR metadatahdr; + METADATASTREAMHDR roothdr; + BYTE rootname[4]; + METADATASTREAMHDR stringshdr; + BYTE stringsname[12]; + METADATASTREAMHDR ushdr; + BYTE usname[4]; + METADATASTREAMHDR guidhdr; + BYTE guidname[8]; + METADATASTREAMHDR blobhdr; + BYTE blobname[8]; + METADATATABLESHDR tableshdr; + DWORD numrows[4]; + MODULETABLE modtable; + TYPEDEFTABLE tdtable; + ASSEMBLYTABLE asmtable; + MANIFESTRESTABLE manifestrestable; + WORD pad3; + BYTE stringheap[40]; + WORD usheap[4]; + WORD guidheap[8]; + WORD blobheap[82]; + IMAGE_IMPORT_DESCRIPTOR importdesc; + BYTE pad4[20]; + IMPORTLOOKUPTABLE importlookup; + HINTNAMETABLE hintnametable; + BYTE pad5[108]; + IMAGE_RESOURCE_DIRECTORY topresdir; + IMAGE_RESOURCE_DIRECTORY_ENTRY labelres; + IMAGE_RESOURCE_DIRECTORY res11dir; + IMAGE_RESOURCE_DIRECTORY_ENTRY label11res; + IMAGE_RESOURCE_DIRECTORY res10dir; + IMAGE_RESOURCE_DIRECTORY_ENTRY label10res; + IMAGE_RESOURCE_DATA_ENTRY resdata; + VS_VERSIONINFO verinfo; + VARFILEINFO varfileinfo; + VAR translation; + STRINGFILEINFO strfileinfo; + STRINGTABLE strtable; + STRINGHDR filedeschdr; + WCHAR filedesckey[17]; + WCHAR filedescval[2]; + STRINGHDR fileverhdr; + WCHAR fileverkey[13]; + WCHAR fileverval[8]; + STRINGHDR intnamehdr; + WCHAR intnamekey[13]; + WCHAR intnameval[10]; + STRINGHDR copyrighthdr; + WCHAR copyrightkey[15]; + WCHAR copyrightval[2]; + STRINGHDR orignamehdr; + WCHAR orignamekey[17]; + WCHAR orignameval[10]; + STRINGHDR prodverhdr; + WCHAR prodverkey[15]; + WCHAR prodverval[8]; + STRINGHDR asmverhdr; + WCHAR asmverkey[17]; + WCHAR asmverval[8]; + WORD pad6[182]; + RELOCATION relocation; + WORD pad7[250]; +} assembly = +{ + /* IMAGE_DOS_HEADER */ + { + IMAGE_DOS_SIGNATURE, 144, 3, 0, 4, 0, 0xFFFF, 0, 0xB8, 0, 0, 0, 0x40, + 0, { 0 }, 0, 0, { 0 }, 0x80 + }, + /* binary to print "This program cannot be run in DOS mode." */ + { + 0x1F0E, 0x0EBA, 0xB400, 0xCD09, 0xB821, 0x4C01, 0x21CD, 0x6854, 0x7369, + 0x7020, 0x6F72, 0x7267, 0x6D61, 0x6320, 0x6E61, 0x6F6E, 0x2074, 0x6562, + 0x7220, 0x6E75, 0x6920, 0x206E, 0x4F44, 0x2053, 0x6F6D, 0x6564, 0x0D2E, + 0x0A0D, 0x0024, 0x0000, 0x0000, 0x0000 + }, + /* IMAGE_NT_HEADERS32 */ + { + IMAGE_NT_SIGNATURE, /* Signature */ + /* IMAGE_FILE_HEADER */ + { + IMAGE_FILE_MACHINE_I386, /* Machine */ + 3, /* NumberOfSections */ + 0x47EFDF09, /* TimeDateStamp */ + 0, /* PointerToSymbolTable */ + 0, /* NumberOfSymbols */ + 0xE0, /* SizeOfOptionalHeader */ + IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_LOCAL_SYMS_STRIPPED | + IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | + IMAGE_FILE_DLL, /* Characteristics */ + }, + /* IMAGE_OPTIONAL_HEADER32 */ + { + IMAGE_NT_OPTIONAL_HDR32_MAGIC, /* Magic */ + 8, /* MajorLinkerVersion */ + 0, /* MinorLinkerVersion */ + 0x400, /* SizeOfCode */ + 0x600, /* SizeOfInitializedData */ + 0, /* SizeOfUninitializedData */ + 0x238E, /* AddressOfEntryPoint */ + 0x2000, /* BaseOfCode */ + 0x4000, /* BaseOfData */ + 0x400000, /* ImageBase */ + 0x2000, /* SectionAlignment */ + 0x200, /* FileAlignment */ + 4, /* MajorOperatingSystemVersion */ + 0, /* MinorOperatingSystemVersion */ + 0, /* MajorImageVersion */ + 0, /* MinorImageVersion */ + 4, /* MajorSubsystemVersion */ + 0, /* MinorSubsystemVersion */ + 0, /* Win32VersionValue */ + 0x8000, /* SizeOfImage */ + 0x200, /* SizeOfHeaders */ + 0xB576, /* CheckSum */ + IMAGE_SUBSYSTEM_WINDOWS_CUI, /* Subsystem */ + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | + IMAGE_DLLCHARACTERISTICS_NO_SEH | + IMAGE_DLLCHARACTERISTICS_NX_COMPAT, /* DllCharacteristics */ + 0x100000, /* SizeOfStackReserve */ + 0x1000, /* SizeOfStackCommit */ + 0x100000, /* SizeOfHeapReserve */ + 0x1000, /* SizeOfHeapCommit */ + 0, /* LoaderFlags */ + 0x10, /* NumberOfRvaAndSizes */ + /* IMAGE_DATA_DIRECTORY */ + { + { 0 }, /* Export Table */ + { 0x233C, 0x4F }, /* Import Table */ + { 0x4000, 0x298 }, /* Resource Table */ + { 0 }, /* Exception Table */ + { 0 }, /* Certificate Table */ + { 0x6000, 0xC }, /* Base Relocation Table */ + { 0 }, /* Debug */ + { 0 }, /* Copyright */ + { 0 }, /* Global Ptr */ + { 0 }, /* TLS Table */ + { 0 }, /* Load Config Table */ + { 0 }, /* Bound Import */ + { 0x2000, 8 }, /* IAT */ + { 0 }, /* Delay Import Descriptor */ + { 0x2008, 0x48 }, /* CLI Header */ + { 0 } /* Reserved */ + } + } + }, + /* IMAGE_SECTION_HEADER */ + { + ".text", /* Name */ + { 0x394 }, /* Misc.VirtualSize */ + 0x2000, /* VirtualAddress */ + 0x400, /* SizeOfRawData */ + 0x200, /* PointerToRawData */ + 0, /* PointerToRelocations */ + 0, /* PointerToLinenumbers */ + 0, /* NumberOfRelocations */ + 0, /* NumberOfLinenumbers */ + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE | + IMAGE_SCN_CNT_CODE, /* Characteristics */ + }, + /* IMAGE_SECTION_HEADER */ + { + ".rsrc", /* Name */ + { 0x298 }, /* Misc.VirtualSize */ + 0x4000, /* VirtualAddress */ + 0x400, /* SizeOfRawData */ + 0x600, /* PointerToRawData */ + 0, /* PointerToRelocations */ + 0, /* PointerToLinenumbers */ + 0, /* NumberOfRelocations */ + 0, /* NumberOfLinenumbers */ + IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */ + }, + /* IMAGE_SECTION_HEADER */ + { + ".reloc", /* Name */ + { 0xC }, /* Misc.VirtualSize */ + 0x6000, /* VirtualAddress */ + 0x200, /* SizeOfRawData */ + 0xA00, /* PointerToRawData */ + 0, /* PointerToRelocations */ + 0, /* PointerToLinenumbers */ + 0, /* NumberOfRelocations */ + 0, /* NumberOfLinenumbers */ + IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | + IMAGE_SCN_MEM_DISCARDABLE, /* Characteristics */ + }, + /* fill */ + { 0 }, + /* IMAGE_IMPORT_BY_NAME */ + { + 0x2370, /* Hint */ + { 0 } /* Name */ + }, + /* fill */ + { 0 }, + /* IMAGE_COR20_HEADER */ + { + 0x48, /* Cb */ + 2, /* MajorRuntimeVersion */ + 5, /* MinorRuntimeVersion */ + { 0x2188, 0x1B4 }, /* MetaData */ + COMIMAGE_FLAGS_ILONLY | COMIMAGE_FLAGS_STRONGNAMESIGNED, /* Flags */ + 0, /* EntryPointToken */ + { 0x20D0, 0xB8 }, /* Resources */ + { 0x2050, 0x80 }, /* StrongNameSignature */ + { 0 }, /* CodeManagerTable */ + { 0 }, /* VTableFixups */ + { 0 }, /* ExportAddressTableJumps */ + { 0 } /* ManagedNativeHeader */ + }, + { 0xE496, 0x9A6E, 0xD95E, 0xA2A1, 0x5D72, 0x9CEF, 0x41E3, 0xD483, + 0xCB5C, 0x329A, 0x887C, 0xE18E, 0xE664, 0x2E1C, 0x0E61, 0xB361, + 0x8B88, 0xC8D0, 0x47A5, 0x9260, 0x6CC5, 0xE60F, 0x1F61, 0x1E3E, + 0xAFEE, 0x925A, 0xA084, 0x6B44, 0x2DC6, 0x8126, 0xEBC9, 0xD812, + 0xF3E9, 0xA3F3, 0xD0D5, 0x2C7F, 0x4592, 0xA0AF, 0x8B15, 0xD91E, + 0x693E, 0x7A4F, 0x5567, 0xC466, 0xC410, 0x3D29, 0xB25F, 0xCD6C, + 0x53EF, 0x0D29, 0x085A, 0xEC39, 0xE3BD, 0x58E0, 0x78F5, 0x0587, + 0xF8D8, 0x14E4, 0x77CE, 0xCCC9, 0x4DCF, 0x8A18, 0x90E8, 0x1A52 + }, + /* RESOURCE */ + { + 0xB4, /* Size */ + 0xBEEFCACE, /* Signature */ + 1, /* HeaderVersion */ + 0x91, /* SkipBytes */ + { 'l','S','y','s','t','e','m','.','R','e','s','o','u','r','c','e','s','.', + 'R','e','s','o','u','r','c','e','R','e','a','d','e','r',',',' ', + 'm','s','c','o','r','l','i','b',',',' ','V','e','r','s','i','o','n','=', + '2','.','0','.','0','.','0',',',' ','C','u','l','t','u','r','e','=', + 'n','e','u','t','r','a','l',',',' ','P','u','b','l','i','c','K','e','y','T','o','k','e','n','=', + 'b','7','7','a','5','c','5','6','1','9','3','4','e','0','8','9', + '#','S','y','s','t','e','m','.','R','e','s','o','u','r','c','e','s','.', + 'R','u','n','t','i','m','e','R','e','s','o','u','r','c','e','S','e','t', + 2,0,0,0,0,0,0,0,0,0,0,0,'P','A','D','P','A','D','P',180,0,0,0 + } + }, + /* METADATAHDR */ + { + 0x424A5342, /* Signature */ + 1, /* MajorVersion */ + 1, /* MinorVersion */ + 0, /* Reserved */ + 0xC, /* VersionLength */ + "v2.0.50727", /* Version */ + 0, /* Flags */ + 5 /* Streams */ + }, + /* METADATASTREAMHDR */ + { + 0x6C, /* Offset */ + 0x64, /* Size */ + }, + "#~\0\0", + /* METADATASTREAMHDR */ + { + 0xD0, /* Offset */ + 0x28, /* Size */ + }, + "#Strings\0\0\0\0", + /* METADATASTREAMHDR */ + { + 0xF8, /* Offset */ + 0x8, /* Size */ + }, + "#US\0", + /* METADATASTREAMHDR */ + { + 0x100, /* Offset */ + 0x10, /* Size */ + }, + "#GUID\0\0\0", + /* METADATASTREAMHDR */ + { + 0x110, /* Offset */ + 0xA4, /* Size */ + }, + "#Blob\0\0\0", + /* METADATATABLESHDR */ + { + 0, /* Reserved1 */ + 2, /* MajorVersion */ + 0, /* MinorVersion */ + 0, /* HeapOffsetSizes */ + 1, /* Reserved2 */ + { { 0 } }, /* MaskValid */ + { { 0 } } /* MaskSorted */ + }, + /* numrows */ + { 1, 1, 1, 1 }, + /* MODULETABLE */ + { + 0, /* Generation */ + 0xA, /* Name */ + 1, /* Mvid */ + 0, /* EncId */ + 0 /* EncBaseId */ + }, + /* TYPEDEFTABLE */ + { + 0, /* Flags */ + 0x1, /* Name */ + 0, /* Namespace */ + 0, /* Extends */ + 1, /* FieldList */ + 1 /* MethodList */ + }, + /* ASSEMBLYTABLE */ + { + 0x8004, /* HashAlgId */ + 1, /* MajorVersion */ + 0, /* MinorVersion */ + 0, /* BuildNumber */ + 0, /* RevisionNumber */ + 1, /* Flags */ + 1, /* PublicKey */ + 0x13, /* Name */ + 0 /* Culture */ + }, + /* MANIFESTRESTABLE */ + { + 0, /* Offset */ + 0x2, /* Flags */ + 0x18, /* Name */ + 0 /* Implementation */ + }, + /* pad */ + 0, + /* String heap */ + "\0\0wine.dll\0wine\0wine.resources\0\0", + /* US heap */ + { 0x0300, 0x0020 }, + /* GUID heap */ + { 0x86EF, 0x5B5A, 0x2C5E, 0x4F6D, 0xC2AB, 0x0A94, 0xD658, 0x31DA }, + /* BLOB heap */ + { 0x8000, 0x00A0, 0x0024, 0x0400, 0x0080, 0x9400, 0x0000, 0x0600, + 0x0002, 0x0000, 0x0024, 0x5200, 0x4153, 0x0031, 0x0004, 0x0100, + 0x0100, 0x2F00, 0x60E0, 0x4D76, 0x5E5C, 0x430A, 0x6FF3, 0x77D6, + 0x04CA, 0xF6AD, 0xF54D, 0x0AD2, 0x9FB6, 0x39C2, 0x2E66, 0xD30F, + 0x916F, 0x1826, 0xFB52, 0x78A0, 0x8262, 0x6902, 0xBD47, 0xAF30, + 0xBAB1, 0x29DA, 0xAA6D, 0xF189, 0x296A, 0x0F13, 0x4982, 0x531D, + 0x8283, 0x1343, 0x5A33, 0x5D36, 0xEB3F, 0x0863, 0xA771, 0x0679, + 0x4DFF, 0xD30A, 0xBEAD, 0x2A9F, 0x12A8, 0x4319, 0x5706, 0x333D, + 0x0CAC, 0xE80A, 0xFD99, 0xC82D, 0x3D3B, 0xBFFE, 0xF256, 0x25E3, + 0x1A12, 0xC116, 0x8936, 0xF237, 0x5F26, 0xC68A, 0x1E42, 0xCE41, + 0xC17C, 0x00C4 + }, + /* IMAGE_IMPORT_DESCRIPTOR */ + { + { 0x2364 }, /* OriginalFirstThunk */ + 0, /* TimeDateStamp */ + 0, /* ForwarderChain */ + 0x237E, /* Name */ + 0x2000, /* FirstThunk */ + }, + /* pad */ + { 0 }, + /* IMPORTLOOKUPTABLE */ + { + 0x2370, /* HintNameTableRVA */ + { 0 }, /* pad */ + }, + /* HINTNAMETABLE */ + { + 0, /* Hint */ + "_CorDllMain", /* Name */ + "mscoree.dll", /* Module */ + 0, /* Reserved */ + 0x25FF, /* EntryPoint */ + 0x402000 /* RVA */ + }, + /* pad to 0x600 */ + { 0 }, + /* IMAGE_RESOURCE_DIRECTORY */ + { + 0, /* Characteristics */ + 0, /* TimeDateStamp */ + 0, /* MajorVersion */ + 0, /* MinorVersion */ + 0, /* NumberOfNamedEntries */ + 1, /* NumberOfIdEntries */ + }, + /* IMAGE_RESOURCE_DIRECTORY_ENTRY */ + { { { 0 } }, { 0 } }, /* nameless unions initialized later */ + /* IMAGE_RESOURCE_DIRECTORY */ + { + 0, /* Characteristics */ + 0, /* TimeDateStamp */ + 0, /* MajorVersion */ + 0, /* MinorVersion */ + 0, /* NumberOfNamedEntries */ + 1, /* NumberOfIdEntries */ + }, + /* IMAGE_RESOURCE_DIRECTORY_ENTRY */ + { { { 0 } }, { 0 } }, /* nameless unions initialized later */ + /* IMAGE_RESOURCE_DIRECTORY */ + { + 0, /* Characteristics */ + 0, /* TimeDateStamp */ + 0, /* MajorVersion */ + 0, /* MinorVersion */ + 0, /* NumberOfNamedEntries */ + 1, /* NumberOfIdEntries */ + }, + /* IMAGE_RESOURCE_DIRECTORY_ENTRY */ + { { { 0 } }, { 0 } }, /* nameless unions initialized later */ + /* IMAGE_RESOURCE_DATA_ENTRY */ + { + 0x4058, /* OffsetToData */ + 0x23C, /* Size */ + 0, /* CodePage */ + 0, /* Reserved */ + }, + /* VS_VERSIONINFO */ + { + 0x23C, /* wLength */ + 0x34, /* wValueLength */ + 0, /* wType */ + { 'V','S','_','V','E','R','S','I','O','N','_','I','N','F','O',0,0 }, /* szKey */ + /* VS_FIXEDFILEINFO */ + { + VS_FFI_SIGNATURE, /* dwSignature */ + VS_FFI_STRUCVERSION, /* dwStrucVersion */ + 0x10000, /* dwFileVersionMS */ + 0x00000, /* dwFileVersionLS */ + 0x10000, /* dwProductVersionMS */ + 0x00000, /* dwProductVersionLS */ + VS_FFI_FILEFLAGSMASK, /* dwFileFlagsMask */ + 0x0, /* dwFileFlags */ + VOS__WINDOWS32, /* dwFileOS */ + VFT_DLL, /* dwFileType */ + VFT2_UNKNOWN, /* dwFileSubtype */ + 0, /* dwFileDateMS */ + 0, /* dwFileDateLS */ + }, + }, + /* VARFILEINFO */ + { + 0x44, /* wLength */ + 0, /* wValueLength */ + 1, /* wType */ + { 'V','a','r','F','i','l','e','I','n','f','o',0,0 } /* szKey */ + }, + /* VAR */ + { + 0x24, /* wLength */ + 0x4, /* wValueLength */ + 0, /* wType */ + { 'T','r','a','n','s','l','a','t','i','o','n',0,0 }, /* szKey */ + 0x4B00000, /* Value */ + }, + /* STRINGFILEINFO */ + { + 0x19C, /* wLength */ + 0, /* wValueLength */ + 1, /* wType */ + { 'S','t','r','i','n','g','F','i','l','e','I','n','f','o',0 }, /* szKey */ + }, + /* STRINGTABLE */ + { + 0x178, /* wLength */ + 0, /* wValueLength */ + 1, /* wType */ + { '0','0','0','0','0','4','b','0',0 }, /* szKey */ + }, + /* STRINGHDR */ + { + 0x2C, /* wLength */ + 2, /* wValueLength */ + 1, /* wType */ + }, + { 'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0,0 }, /* szKey */ + { ' ',0 }, /* szValue */ + /* STRINGHDR */ + { + 0x30, /* wLength */ + 8, /* wValueLength */ + 1, /* wType */ + }, + { 'F','i','l','e','V','e','r','s','i','o','n',0,0 }, /* szKey */ + { '1','.','0','.','0','.','0',0 }, /* szValue */ + /* STRINGHDR */ + { + 0x34, /* wLength */ + 9, /* wValueLength */ + 1, /* wType */ + }, + { 'I','n','t','e','r','n','a','l','N','a','m','e',0 }, /* szKey */ + { 'w','i','n','e','.','d','l','l',0 }, /* szValue */ + /* STRINGHDR */ + { + 0x28, /* wLength */ + 2, /* wValueLength */ + 1, /* wType */ + }, + { 'L','e','g','a','l','C','o','p','y','r','i','g','h','t',0 }, /* szKey */ + { ' ',0 }, /* szValue */ + /* STRINGHDR */ + { + 0x3C, /* wLength */ + 9, /* wValueLength */ + 1, /* wType */ + }, + { 'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0 }, /* szKey */ + { 'w','i','n','e','.','d','l','l',0,0 }, /* szValue */ + /* STRINGHDR */ + { + 0x34, /* wLength */ + 8, /* wValueLength */ + 1, /* wType */ + }, + { 'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0 }, /* szKey */ + { '1','.','0','.','0','.','0',0 }, /* szValue */ + /* STRINGHDR */ + { + 0x38, /* wLength */ + 8, /* wValueLength */ + 1, /* wType */ + }, + { 'A','s','s','e','m','b','l','y',' ','V','e','r','s','i','o','n',0 }, /* szKey */ + { '1','.','0','.','0','.','0',0 }, /* szValue */ + { 0 }, /* pad */ + /* RELOCATION */ + { + 0x2000, /* PageRVA */ + 0xC, /* Size */ + 0x3390, /* Relocation */ + }, + { 0 } +}; + + +static HRESULT (WINAPI *pCreateAssemblyCache)(IAssemblyCache **ppAsmCache, + DWORD dwReserved); +static HRESULT (WINAPI *pGetCachePath)(ASM_CACHE_FLAGS dwCacheFlags, + LPWSTR pwzCachePath, PDWORD pcchPath); +static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion, + LPVOID pvReserved, HMODULE *phModDll); + +static BOOL init_functionpointers(void) +{ + HRESULT hr; + HMODULE hfusion; + HMODULE hmscoree; + + static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0}; + + hmscoree = LoadLibraryA("mscoree.dll"); + if (!hmscoree) + { + win_skip("mscoree.dll not available\n"); + return FALSE; + } + + pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim"); + if (!pLoadLibraryShim) + { + win_skip("LoadLibraryShim not available\n"); + FreeLibrary(hmscoree); + return FALSE; + } + + hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion); + if (FAILED(hr)) + { + win_skip("fusion.dll not available\n"); + FreeLibrary(hmscoree); + return FALSE; + } + + pCreateAssemblyCache = (void *)GetProcAddress(hfusion, "CreateAssemblyCache"); + pGetCachePath = (void *)GetProcAddress(hfusion, "GetCachePath"); + + if (!pCreateAssemblyCache || !pGetCachePath) + { + win_skip("fusion.dll not implemented\n"); + return FALSE; + } + + FreeLibrary(hmscoree); + return TRUE; +} + +static void create_file_data(LPCSTR name, LPCSTR data, DWORD size) +{ + HANDLE file; + DWORD written; + + file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name); + WriteFile(file, data, strlen(data), &written, NULL); + + if (size) + { + SetFilePointer(file, size, NULL, FILE_BEGIN); + SetEndOfFile(file); + } + + CloseHandle(file); +} + +#define create_file(name, size) create_file_data(name, name, size) + +static void create_assembly(LPCSTR file) +{ + HANDLE hfile; + DWORD written; + + /* nameless unions initialized here */ + assembly.tableshdr.MaskValid.u.HighPart = 0x101; + assembly.tableshdr.MaskValid.u.LowPart = 0x00000005; + assembly.tableshdr.MaskSorted.u.HighPart = 0x1600; + assembly.tableshdr.MaskSorted.u.LowPart = 0x3301FA00; + U1(assembly.labelres).Name = 0x10; + U2(assembly.labelres).OffsetToData = 0x80000018; + U1(assembly.label11res).Name = 0x1; + U2(assembly.label11res).OffsetToData = 0x80000030; + U1(assembly.label10res).Name = 0x0; + U2(assembly.label10res).OffsetToData = 0x48; + + hfile = CreateFileA(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + + WriteFile(hfile, &assembly, sizeof(ASSEMBLY), &written, NULL); + CloseHandle(hfile); +} + +static BOOL check_dotnet20(void) +{ + IAssemblyCache *cache; + HRESULT hr; + BOOL ret = FALSE; + ULONG disp; + + static const WCHAR winedll[] = {'w','i','n','e','.','d','l','l',0}; + + create_assembly("wine.dll"); + + hr = pCreateAssemblyCache(&cache, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + hr = IAssemblyCache_InstallAssembly(cache, 0, winedll, NULL); + if (hr == S_OK) + ret = TRUE; + else if (hr == CLDB_E_FILE_OLDVER) + win_skip("Tests can't be run on older .NET version (.NET 1.1)\n"); + else if (hr == E_ACCESSDENIED) + skip("Not enough rights to install an assembly\n"); + else + ok(0, "Expected S_OK, got %08x\n", hr); + + DeleteFileA("wine.dll"); + IAssemblyCache_UninstallAssembly(cache, 0, winedll, NULL, &disp); + IAssemblyCache_Release(cache); + return ret; +} + +static void test_CreateAssemblyCache(void) +{ + IAssemblyCache *cache; + HRESULT hr; + + /* NULL ppAsmCache */ + hr = pCreateAssemblyCache(NULL, 0); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + + /* dwReserved is non-zero */ + hr = pCreateAssemblyCache(&cache, 42); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + IAssemblyCache_Release(cache); +} + +static void test_InstallAssembly(void) +{ + IAssemblyCache *cache; + HRESULT hr; + ULONG disp; + DWORD attr; + char dllpath[MAX_PATH]; + UINT size; + + static const WCHAR empty[] = {0}; + static const WCHAR noext[] = {'f','i','l','e',0}; + static const WCHAR badext[] = {'f','i','l','e','.','b','a','d',0}; + static const WCHAR dllext[] = {'f','i','l','e','.','d','l','l',0}; + static const WCHAR exeext[] = {'f','i','l','e','.','e','x','e',0}; + static const WCHAR testdll[] = {'t','e','s','t','.','d','l','l',0}; + static const WCHAR winedll[] = {'w','i','n','e','.','d','l','l',0}; + static const WCHAR wine[] = {'w','i','n','e',0}; + + create_file("test.dll", 100); + create_assembly("wine.dll"); + + hr = pCreateAssemblyCache(&cache, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + /* NULL pszManifestFilePath */ + hr = IAssemblyCache_InstallAssembly(cache, 0, NULL, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + + /* empty pszManifestFilePath */ + hr = IAssemblyCache_InstallAssembly(cache, 0, empty, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + + /* pszManifestFilePath has no extension */ + hr = IAssemblyCache_InstallAssembly(cache, 0, noext, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), + "Expected HRESULT_FROM_WIN32(ERROR_INVALID_NAME), got %08x\n", hr); + + /* pszManifestFilePath has bad extension */ + hr = IAssemblyCache_InstallAssembly(cache, 0, badext, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), + "Expected HRESULT_FROM_WIN32(ERROR_INVALID_NAME), got %08x\n", hr); + + /* pszManifestFilePath has dll extension */ + hr = IAssemblyCache_InstallAssembly(cache, 0, dllext, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr); + + /* pszManifestFilePath has exe extension */ + hr = IAssemblyCache_InstallAssembly(cache, 0, exeext, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr); + + /* empty file */ + hr = IAssemblyCache_InstallAssembly(cache, 0, testdll, NULL); + ok(hr == COR_E_ASSEMBLYEXPECTED, + "Expected COR_E_ASSEMBLYEXPECTED, got %08x\n", hr); + + /* wine assembly */ + hr = IAssemblyCache_InstallAssembly(cache, 0, winedll, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + size = GetWindowsDirectoryA(dllpath, MAX_PATH); + strcat(dllpath, "\\assembly\\GAC_MSIL\\wine\\\\1.0.0.0__2d03617b1c31e2f5\\wine.dll"); + + attr = GetFileAttributes(dllpath); + ok(attr != INVALID_FILE_ATTRIBUTES, "Expected assembly to exist\n"); + + /* uninstall the assembly from the GAC */ + disp = 0xf00dbad; + hr = IAssemblyCache_UninstallAssembly(cache, 0, wine, NULL, &disp); + todo_wine + { + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(disp == IASSEMBLYCACHE_UNINSTALL_DISPOSITION_UNINSTALLED, + "Expected IASSEMBLYCACHE_UNINSTALL_DISPOSITION_UNINSTALLED, got %d\n", disp); + } + + /* FIXME: remove once UninstallAssembly is implemented */ + DeleteFileA(dllpath); + dllpath[size + sizeof("\\assembly\\GAC_MSIL\\wine\\1.0.0.0__2d03617b1c31e2f5")] = '\0'; + RemoveDirectoryA(dllpath); + dllpath[size + sizeof("\\assembly\\GAC_MSIL\\wine")] = '\0'; + RemoveDirectoryA(dllpath); + + DeleteFileA("test.dll"); + DeleteFileA("wine.dll"); + IAssemblyCache_Release(cache); +} + +#define INIT_ASM_INFO() \ + ZeroMemory(&info, sizeof(ASSEMBLY_INFO)); \ + info.cbAssemblyInfo = sizeof(ASSEMBLY_INFO); \ + info.pszCurrentAssemblyPathBuf = path; \ + info.cchBuf = MAX_PATH; \ + path[0] = '\0'; + +static void test_QueryAssemblyInfo(void) +{ + IAssemblyCache *cache; + ASSEMBLY_INFO info; + WCHAR path[MAX_PATH]; + WCHAR asmpath[MAX_PATH]; + WCHAR name[MAX_PATH]; + HRESULT hr; + DWORD size; + ULONG disp; + char dllpath[MAX_PATH]; + UINT len; + + static const WCHAR empty[] = {0}; + static const WCHAR commasep[] = {',',' ',0}; + static const WCHAR winedll[] = {'w','i','n','e','.','d','l','l',0}; + static const WCHAR wine[] = {'w','i','n','e',0}; + static const WCHAR ver[] = { + 'V','e','r','s','i','o','n','=','1','.','0','.','0','.','0',0}; + static const WCHAR otherver[] = { + 'V','e','r','s','i','o','n','=','1','.','0','.','0','.','0','0','0','0','0',0}; + static const WCHAR badver[] = { + 'V','e','r','s','i','o','n','=','1','.','0','.','0','.','1',0}; + static const WCHAR culture[] = { + 'C','u','l','t','u','r','e','=','n','e','u','t','r','a','l',0}; + static const WCHAR badculture[] = { + 'C','u','l','t','u','r','e','=','e','n',0}; + static const WCHAR pubkey[] = { + 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=', + '2','d','0','3','6','1','7','b','1','c','3','1','e','2','f','5',0}; + static const WCHAR badpubkey[] = { + 'P','u','b','l','i','c','K','e','y','T','o','k','e','n','=', + 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',0}; + static const WCHAR badprop[] = {'B','a','d','P','r','o','p','=','b','u','h',0}; + static const WCHAR msil[] = { + '_','M','S','I','L','\\','w','i','n','e','\\', + '1','.','0','.','0','.','0','_','_','2','d','0','3','6','1','7','b', + '1','c','3','1','e','2','f','5','\\',0}; + + size = MAX_PATH; + hr = pGetCachePath(ASM_CACHE_GAC, asmpath, &size); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + lstrcatW(asmpath, msil); + lstrcatW(asmpath, winedll); + + create_assembly("wine.dll"); + + hr = pCreateAssemblyCache(&cache, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + /* assembly not installed yet */ + INIT_ASM_INFO(); + hr = IAssemblyCache_QueryAssemblyInfo(cache, 0, wine, &info); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + hr = IAssemblyCache_InstallAssembly(cache, 0, winedll, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + /* NULL pszAssemblyName */ + INIT_ASM_INFO(); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE, + NULL, &info); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + /* empty pszAssemblyName */ + INIT_ASM_INFO(); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE, + empty, &info); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + /* no dwFlags */ + INIT_ASM_INFO(); + hr = IAssemblyCache_QueryAssemblyInfo(cache, 0, wine, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + todo_wine + { + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* pwzCachePath is full filename */ + INIT_ASM_INFO(); + hr = IAssemblyCache_QueryAssemblyInfo(cache, 0, winedll, &info); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + /* NULL pAsmInfo, QUERYASMINFO_FLAG_VALIDATE */ + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE, + wine, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + /* NULL pAsmInfo, QUERYASMINFO_FLAG_GETSIZE */ + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + wine, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + /* info.cbAssemblyInfo is 0 */ + INIT_ASM_INFO(); + info.cbAssemblyInfo = 0; + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE, + wine, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + todo_wine + { + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* info.cbAssemblyInfo is 1 */ + INIT_ASM_INFO(); + info.cbAssemblyInfo = 1; + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_VALIDATE, + wine, &info); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(info.cbAssemblyInfo == 1, "Expected 1, got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + /* info.cbAssemblyInfo is > sizeof(ASSEMBLY_INFO) */ + INIT_ASM_INFO(); + info.cbAssemblyInfo = sizeof(ASSEMBLY_INFO) * 2; + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + wine, &info); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO) * 2, + "Expected sizeof(ASSEMBLY_INFO) * 2, got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + /* QUERYASMINFO_FLAG_GETSIZE */ + INIT_ASM_INFO(); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + wine, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + todo_wine + { + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* QUERYASMINFO_FLAG_GETSIZE and QUERYASMINFO_FLAG_VALIDATE */ + INIT_ASM_INFO(); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE | + QUERYASMINFO_FLAG_VALIDATE,wine, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + todo_wine + { + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* info.pszCurrentAssemblyPathBuf is NULL */ + INIT_ASM_INFO(); + info.pszCurrentAssemblyPathBuf = NULL; + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + wine, &info); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + todo_wine + { + ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), + "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got %08x\n", hr); + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* info.cchBuf is exactly size of asmpath */ + INIT_ASM_INFO(); + info.cchBuf = lstrlenW(asmpath); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + wine, &info); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + todo_wine + { + ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), + "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got %08x\n", hr); + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* info.cchBuf has room for NULL-terminator */ + INIT_ASM_INFO(); + info.cchBuf = lstrlenW(asmpath) + 1; + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + wine, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + todo_wine + { + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + } + + /* display name is "wine, Version=1.0.0.0" */ + INIT_ASM_INFO(); + lstrcpyW(name, wine); + lstrcatW(name, commasep); + lstrcatW(name, ver); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + name, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + todo_wine + { + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* display name is "wine, Version=1.0.0.00000" */ + INIT_ASM_INFO(); + lstrcpyW(name, wine); + lstrcatW(name, commasep); + lstrcatW(name, otherver); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + name, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + todo_wine + { + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* display name is "wine, Version=1.0.0.1", versions don't match */ + INIT_ASM_INFO(); + lstrcpyW(name, wine); + lstrcatW(name, commasep); + lstrcatW(name, badver); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + name, &info); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + /* display name is "wine, Culture=neutral" */ + INIT_ASM_INFO(); + lstrcpyW(name, wine); + lstrcatW(name, commasep); + lstrcatW(name, culture); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + name, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + todo_wine + { + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* display name is "wine, Culture=en", cultures don't match */ + INIT_ASM_INFO(); + lstrcpyW(name, wine); + lstrcatW(name, commasep); + lstrcatW(name, badculture); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + name, &info); + todo_wine + { + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + } + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + /* display name is "wine, PublicKeyTokens=2d03617b1c31e2f5" */ + INIT_ASM_INFO(); + lstrcpyW(name, wine); + lstrcatW(name, commasep); + lstrcatW(name, pubkey); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + name, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + todo_wine + { + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* display name is "wine, PublicKeyToken=aaaaaaaaaaaaaaaa", pubkeys don't match */ + INIT_ASM_INFO(); + lstrcpyW(name, wine); + lstrcatW(name, commasep); + lstrcatW(name, badpubkey); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + name, &info); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == 0, "Expected 0, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + ok(info.uliAssemblySizeInKB.u.LowPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, empty), + "Assembly path was changed\n"); + ok(info.cchBuf == MAX_PATH, "Expected MAX_PATH, got %d\n", info.cchBuf); + + /* display name is "wine, BadProp=buh", bad property */ + INIT_ASM_INFO(); + lstrcpyW(name, wine); + lstrcatW(name, commasep); + lstrcatW(name, badprop); + hr = IAssemblyCache_QueryAssemblyInfo(cache, QUERYASMINFO_FLAG_GETSIZE, + name, &info); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(info.cbAssemblyInfo == sizeof(ASSEMBLY_INFO), + "Expected sizeof(ASSEMBLY_INFO), got %d\n", info.cbAssemblyInfo); + ok(info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED, + "Expected ASSEMBLYINFO_FLAG_INSTALLED, got %08x\n", info.dwAssemblyFlags); + ok(info.uliAssemblySizeInKB.u.HighPart == 0, + "Expected 0, got %d\n", info.uliAssemblySizeInKB.u.HighPart); + todo_wine + { + /* win9x: 32 */ + ok((info.uliAssemblySizeInKB.u.LowPart == 4) || + broken(info.uliAssemblySizeInKB.u.LowPart == 32), + "Expected 4, got %d\n", info.uliAssemblySizeInKB.u.LowPart); + ok(!lstrcmpW(info.pszCurrentAssemblyPathBuf, asmpath), + "Wrong assembly path returned\n"); + ok(info.cchBuf == lstrlenW(asmpath) + 1, + "Expected %d, got %d\n", lstrlenW(asmpath) + 1, info.cchBuf); + } + + /* uninstall the assembly from the GAC */ + disp = 0xf00dbad; + hr = IAssemblyCache_UninstallAssembly(cache, 0, wine, NULL, &disp); + todo_wine + { + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(disp == IASSEMBLYCACHE_UNINSTALL_DISPOSITION_UNINSTALLED, + "Expected IASSEMBLYCACHE_UNINSTALL_DISPOSITION_UNINSTALLED, got %d\n", disp); + } + + /* FIXME: remove once UninstallAssembly is implemented */ + len = GetWindowsDirectoryA(dllpath, MAX_PATH); + strcat(dllpath, "\\assembly\\GAC_MSIL\\wine\\\\1.0.0.0__2d03617b1c31e2f5\\wine.dll"); + DeleteFileA(dllpath); + dllpath[len + sizeof("\\assembly\\GAC_MSIL\\wine\\1.0.0.0__2d03617b1c31e2f5")] = '\0'; + RemoveDirectoryA(dllpath); + dllpath[len + sizeof("\\assembly\\GAC_MSIL\\wine")] = '\0'; + RemoveDirectoryA(dllpath); + + DeleteFileA("test.dll"); + DeleteFileA("wine.dll"); + IAssemblyCache_Release(cache); +} + +START_TEST(asmcache) +{ + if (!init_functionpointers()) + return; + + if (!check_dotnet20()) + return; + + test_CreateAssemblyCache(); + test_InstallAssembly(); + test_QueryAssemblyInfo(); +} diff --git a/rostests/winetests/fusion/asmenum.c b/rostests/winetests/fusion/asmenum.c new file mode 100644 index 00000000000..48f7b2a97b1 --- /dev/null +++ b/rostests/winetests/fusion/asmenum.c @@ -0,0 +1,675 @@ +/* + * Copyright 2008 James Hawkins + * + * 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 + */ + +#define COBJMACROS + +#include + +#include +#include +#include +#include +#include + +#include "wine/test.h" +#include "wine/list.h" + +static HRESULT (WINAPI *pCreateAssemblyEnum)(IAssemblyEnum **pEnum, + IUnknown *pUnkReserved, + IAssemblyName *pName, + DWORD dwFlags, LPVOID pvReserved); +static HRESULT (WINAPI *pCreateAssemblyNameObject)(LPASSEMBLYNAME *ppAssemblyNameObj, + LPCWSTR szAssemblyName, DWORD dwFlags, + LPVOID pvReserved); +static HRESULT (WINAPI *pGetCachePath)(ASM_CACHE_FLAGS dwCacheFlags, + LPWSTR pwzCachePath, PDWORD pcchPath); +static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion, + LPVOID pvReserved, HMODULE *phModDll); + +static BOOL init_functionpointers(void) +{ + HRESULT hr; + HMODULE hfusion; + HMODULE hmscoree; + + static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0}; + + hmscoree = LoadLibraryA("mscoree.dll"); + if (!hmscoree) + { + win_skip("mscoree.dll not available\n"); + return FALSE; + } + + pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim"); + if (!pLoadLibraryShim) + { + win_skip("LoadLibraryShim not available\n"); + FreeLibrary(hmscoree); + return FALSE; + } + + hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion); + if (FAILED(hr)) + { + win_skip("fusion.dll not available\n"); + FreeLibrary(hmscoree); + return FALSE; + } + + pCreateAssemblyEnum = (void *)GetProcAddress(hfusion, "CreateAssemblyEnum"); + pCreateAssemblyNameObject = (void *)GetProcAddress(hfusion, "CreateAssemblyNameObject"); + pGetCachePath = (void *)GetProcAddress(hfusion, "GetCachePath"); + + if (!pCreateAssemblyEnum || + !pCreateAssemblyNameObject || !pGetCachePath) + { + win_skip("fusion.dll not implemented\n"); + return FALSE; + } + + FreeLibrary(hmscoree); + return TRUE; +} + +static inline void to_widechar(LPWSTR dest, LPCSTR src) +{ + MultiByteToWideChar(CP_ACP, 0, src, -1, dest, MAX_PATH); +} + +static inline void to_multibyte(LPSTR dest, LPWSTR src) +{ + WideCharToMultiByte(CP_ACP, 0, src, -1, dest, MAX_PATH, NULL, NULL); +} + +static BOOL create_full_path(LPCSTR path) +{ + LPSTR new_path; + BOOL ret = TRUE; + int len; + + new_path = HeapAlloc(GetProcessHeap(), 0, lstrlenA(path) + 1); + if (!new_path) + return FALSE; + + lstrcpyA(new_path, path); + + while ((len = lstrlenA(new_path)) && new_path[len - 1] == '\\') + new_path[len - 1] = 0; + + while (!CreateDirectoryA(new_path, NULL)) + { + LPSTR slash; + DWORD last_error = GetLastError(); + + if(last_error == ERROR_ALREADY_EXISTS) + break; + + if(last_error != ERROR_PATH_NOT_FOUND) + { + ret = FALSE; + break; + } + + if(!(slash = strrchr(new_path, '\\'))) + { + ret = FALSE; + break; + } + + len = slash - new_path; + new_path[len] = 0; + if(!create_full_path(new_path)) + { + ret = FALSE; + break; + } + + new_path[len] = '\\'; + } + + HeapFree(GetProcessHeap(), 0, new_path); + return ret; +} + +static void create_file_data(LPCSTR name, LPCSTR data, DWORD size) +{ + HANDLE file; + DWORD written; + + file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name); + WriteFile(file, data, strlen(data), &written, NULL); + + if (size) + { + SetFilePointer(file, size, NULL, FILE_BEGIN); + SetEndOfFile(file); + } + + CloseHandle(file); +} + +#define create_file(name, size) create_file_data(name, name, size) + +static void test_CreateAssemblyEnum(void) +{ + HRESULT hr; + WCHAR namestr[MAX_PATH]; + IAssemblyEnum *asmenum; + IAssemblyName *asmname; + + to_widechar(namestr, "wine"); + asmname = NULL; + hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmname != NULL, "Expected non-NULL asmname\n"); + + /* pEnum is NULL */ + if (0) + { + /* Crashes on .NET 1.x */ + hr = pCreateAssemblyEnum(NULL, NULL, asmname, ASM_CACHE_GAC, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + } + + /* pName is NULL */ + asmenum = NULL; + hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_GAC, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmenum != NULL, "Expected non-NULL asmenum\n"); + + IAssemblyEnum_Release(asmenum); + + /* dwFlags is ASM_CACHE_ROOT */ + asmenum = (IAssemblyEnum *)0xdeadbeef; + hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_ROOT, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(asmenum == (IAssemblyEnum *)0xdeadbeef, + "Expected asmenum to be unchanged, got %p\n", asmenum); + + /* invalid dwFlags */ + asmenum = (IAssemblyEnum *)0xdeadbeef; + hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, 0, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(asmenum == (IAssemblyEnum *)0xdeadbeef, + "Expected asmenum to be unchanged, got %p\n", asmenum); +} + +typedef struct _tagASMNAME +{ + struct list entry; + LPSTR data; +} ASMNAME; + +static BOOL enum_gac_assemblies(struct list *assemblies, int depth, LPSTR path) +{ + WIN32_FIND_DATAA ffd; + CHAR buf[MAX_PATH]; + CHAR disp[MAX_PATH]; + ASMNAME *name; + HANDLE hfind; + LPSTR ptr; + + static CHAR parent[MAX_PATH]; + + sprintf(buf, "%s\\*", path); + hfind = FindFirstFileA(buf, &ffd); + if (hfind == INVALID_HANDLE_VALUE) + return FALSE; + + do + { + if (!lstrcmpA(ffd.cFileName, ".") || !lstrcmpA(ffd.cFileName, "..")) + continue; + + if (depth == 0) + { + lstrcpyA(parent, ffd.cFileName); + } + else if (depth == 1) + { + char culture[MAX_PATH]; + char dll[MAX_PATH], exe[MAX_PATH]; + + /* Directories with no dll or exe will not be enumerated */ + sprintf(dll, "%s\\%s\\%s.dll", path, ffd.cFileName, parent); + sprintf(exe, "%s\\%s\\%s.exe", path, ffd.cFileName, parent); + if (GetFileAttributesA(dll) == INVALID_FILE_ATTRIBUTES && + GetFileAttributesA(exe) == INVALID_FILE_ATTRIBUTES) + continue; + + ptr = strstr(ffd.cFileName, "_"); + *ptr = '\0'; + ptr++; + + if (*ptr != '_') + { + lstrcpyA(culture, ptr); + *strstr(culture, "_") = '\0'; + } + else + lstrcpyA(culture, "neutral"); + + ptr = strchr(ptr, '_'); + ptr++; + sprintf(buf, ", Version=%s, Culture=%s, PublicKeyToken=%s", + ffd.cFileName, culture, ptr); + lstrcpyA(disp, parent); + lstrcatA(disp, buf); + + name = HeapAlloc(GetProcessHeap(), 0, sizeof(ASMNAME)); + name->data = HeapAlloc(GetProcessHeap(), 0, lstrlenA(disp) + 1); + lstrcpyA(name->data, disp); + list_add_tail(assemblies, &name->entry); + + continue; + } + + sprintf(buf, "%s\\%s", path, ffd.cFileName); + enum_gac_assemblies(assemblies, depth + 1, buf); + } while (FindNextFileA(hfind, &ffd) != 0); + + FindClose(hfind); + return TRUE; +} + +static void test_enumerate(void) +{ + struct list assemblies = LIST_INIT(assemblies); + struct list *item, *cursor; + IAssemblyEnum *asmenum; + IAssemblyName *next; + WCHAR buf[MAX_PATH]; + CHAR path[MAX_PATH]; + CHAR disp[MAX_PATH]; + HRESULT hr; + BOOL found; + DWORD size; + + size = MAX_PATH; + hr = pGetCachePath(ASM_CACHE_GAC, buf, &size); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + to_multibyte(path, buf); + lstrcatA(path, "_32"); + enum_gac_assemblies(&assemblies, 0, path); + + to_multibyte(path, buf); + lstrcatA(path, "_64"); + enum_gac_assemblies(&assemblies, 0, path); + + to_multibyte(path, buf); + lstrcatA(path, "_MSIL"); + enum_gac_assemblies(&assemblies, 0, path); + + to_multibyte(path, buf); + enum_gac_assemblies(&assemblies, 0, path); + + asmenum = NULL; + hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_GAC, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmenum != NULL, "Expected non-NULL asmenum\n"); + + while (IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0) == S_OK) + { + size = MAX_PATH; + IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + + found = FALSE; + LIST_FOR_EACH_SAFE(item, cursor, &assemblies) + { + ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry); + + if (!lstrcmpA(asmname->data, disp)) + { + found = TRUE; + + list_remove(&asmname->entry); + HeapFree(GetProcessHeap(), 0, asmname->data); + HeapFree(GetProcessHeap(), 0, asmname); + break; + } + } + + ok(found, "Extra assembly enumerated: %s\n", disp); + IAssemblyName_Release(next); + } + + /* enumeration is exhausted */ + next = (IAssemblyName *)0xdeadbeef; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); + ok(next == (IAssemblyName *)0xdeadbeef, + "Expected next to be unchanged, got %p\n", next); + + LIST_FOR_EACH_SAFE(item, cursor, &assemblies) + { + ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry); + + ok(FALSE, "Assembly not enumerated: %s\n", asmname->data); + + list_remove(&asmname->entry); + HeapFree(GetProcessHeap(), 0, asmname->data); + HeapFree(GetProcessHeap(), 0, asmname); + } + + IAssemblyEnum_Release(asmenum); +} + +static void test_enumerate_name(void) +{ + IAssemblyEnum *asmenum; + IAssemblyName *asmname, *next; + WCHAR buf[MAX_PATH]; + CHAR gac[MAX_PATH]; + CHAR path[MAX_PATH]; + CHAR disp[MAX_PATH]; + WCHAR namestr[MAX_PATH]; + CHAR exp[6][MAX_PATH]; + HRESULT hr; + DWORD size; + + lstrcpyA(exp[0], "wine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d"); + lstrcpyA(exp[1], "wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=123456789abcdef0"); + lstrcpyA(exp[2], "wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d"); + lstrcpyA(exp[3], "Wine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d"); + lstrcpyA(exp[4], "Wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=123456789abcdef0"); + lstrcpyA(exp[5], "Wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d"); + + size = MAX_PATH; + hr = pGetCachePath(ASM_CACHE_GAC, buf, &size); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + to_multibyte(gac, buf); + create_full_path(gac); + + sprintf(path, "%s\\Wine", gac); + CreateDirectoryA(path, NULL); + + sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d", gac); + CreateDirectoryA(path, NULL); + + lstrcatA(path, "\\Wine.dll"); + create_file(path, 100); + + sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac); + CreateDirectoryA(path, NULL); + + lstrcatA(path, "\\Wine.dll"); + create_file(path, 100); + + sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac); + CreateDirectoryA(path, NULL); + + lstrcatA(path, "\\Wine.dll"); + create_file(path, 100); + + /* test case sensitivity */ + to_widechar(namestr, "wine"); + asmname = NULL; + hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmname != NULL, "Expected non-NULL asmname\n"); + + asmenum = NULL; + hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmenum != NULL, "Expected non-NULL asmenum\n"); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[0]), + "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[0], exp[1], disp); + + IAssemblyName_Release(next); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[1]) || + !lstrcmpA(disp, exp[2]), /* Win98 */ + "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp); + + IAssemblyName_Release(next); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[2]) || + !lstrcmpA(disp, exp[1]), /* Win98 */ + "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[2], exp[1], disp); + + IAssemblyName_Release(next); + + next = (IAssemblyName *)0xdeadbeef; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); + ok(next == (IAssemblyName *)0xdeadbeef, + "Expected next to be unchanged, got %p\n", next); + + IAssemblyEnum_Release(asmenum); + IAssemblyName_Release(asmname); + + /* only Version */ + to_widechar(namestr, "Wine, Version=1.0.1.2"); + asmname = NULL; + hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmname != NULL, "Expected non-NULL asmname\n"); + + asmenum = NULL; + hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmenum != NULL, "Expected non-NULL asmenum\n"); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[4]) || + !lstrcmpA(disp, exp[5]), /* Win98 */ + "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[4], exp[5], disp); + + IAssemblyName_Release(next); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[5]) || + !lstrcmpA(disp, exp[4]), /* Win98 */ + "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[5], exp[4], disp); + + IAssemblyName_Release(next); + + next = (IAssemblyName *)0xdeadbeef; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); + ok(next == (IAssemblyName *)0xdeadbeef, + "Expected next to be unchanged, got %p\n", next); + + IAssemblyEnum_Release(asmenum); + IAssemblyName_Release(asmname); + + /* only PublicKeyToken */ + to_widechar(namestr, "Wine, PublicKeyToken=16a3fcd171e93a8d"); + asmname = NULL; + hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmname != NULL, "Expected non-NULL asmname\n"); + + asmenum = NULL; + hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmenum != NULL, "Expected non-NULL asmenum\n"); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[3]), "Expected \"%s\", got \"%s\"\n", exp[3], disp); + + IAssemblyName_Release(next); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[5]), "Expected \"%s\", got \"%s\"\n", exp[5], disp); + + IAssemblyName_Release(next); + + next = (IAssemblyName *)0xdeadbeef; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); + ok(next == (IAssemblyName *)0xdeadbeef, + "Expected next to be unchanged, got %p\n", next); + + IAssemblyEnum_Release(asmenum); + IAssemblyName_Release(asmname); + + /* only Culture */ + to_widechar(namestr, "wine, Culture=neutral"); + asmname = NULL; + hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmname != NULL, "Expected non-NULL asmname\n"); + + asmenum = NULL; + hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(asmenum != NULL, "Expected non-NULL asmenum\n"); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[0]), "Expected \"%s\", got \"%s\"\n", exp[0], disp); + + IAssemblyName_Release(next); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[1]) || + !lstrcmpA(disp, exp[2]), /* Win98 */ + "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp); + + IAssemblyName_Release(next); + + next = NULL; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(next != NULL, "Expected non-NULL next\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(next, buf, &size, 0); + to_multibyte(disp, buf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpA(disp, exp[2]) || + !lstrcmpA(disp, exp[1]), /* Win98 */ + "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[2], exp[1], disp); + + IAssemblyName_Release(next); + + next = (IAssemblyName *)0xdeadbeef; + hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0); + ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); + ok(next == (IAssemblyName *)0xdeadbeef, + "Expected next to be unchanged, got %p\n", next); + + IAssemblyEnum_Release(asmenum); + IAssemblyName_Release(asmname); + + sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d\\Wine.dll", gac); + DeleteFileA(path); + sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d\\Wine.dll", gac); + DeleteFileA(path); + sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0\\Wine.dll", gac); + DeleteFileA(path); + sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d", gac); + RemoveDirectoryA(path); + sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac); + RemoveDirectoryA(path); + sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac); + RemoveDirectoryA(path); + sprintf(path, "%s\\Wine", gac); + RemoveDirectoryA(path); +} + +START_TEST(asmenum) +{ + if (!init_functionpointers()) + return; + + test_CreateAssemblyEnum(); + test_enumerate(); + test_enumerate_name(); +} diff --git a/rostests/winetests/fusion/asmname.c b/rostests/winetests/fusion/asmname.c new file mode 100644 index 00000000000..442f00f7c45 --- /dev/null +++ b/rostests/winetests/fusion/asmname.c @@ -0,0 +1,816 @@ +/* + * Copyright 2008 James Hawkins + * + * 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 + */ + +#define COBJMACROS + +#include + +#include +#include +#include +#include + +#include "wine/test.h" + +/* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */ +static CHAR string1[MAX_PATH]; + +#define ok_aw(aString, wString) \ + WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \ + if (lstrcmpA(string1, aString) != 0) \ + ok(0, "Expected \"%s\", got \"%s\"\n", aString, string1); + +static HRESULT (WINAPI *pCreateAssemblyNameObject)(LPASSEMBLYNAME *ppAssemblyNameObj, + LPCWSTR szAssemblyName, DWORD dwFlags, + LPVOID pvReserved); +static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion, + LPVOID pvReserved, HMODULE *phModDll); + +static BOOL init_functionpointers(void) +{ + HRESULT hr; + HMODULE hfusion; + HMODULE hmscoree; + + static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0}; + + hmscoree = LoadLibraryA("mscoree.dll"); + if (!hmscoree) + return FALSE; + + pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim"); + if (!pLoadLibraryShim) + { + FreeLibrary(hmscoree); + return FALSE; + } + + hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion); + if (FAILED(hr)) + return FALSE; + + pCreateAssemblyNameObject = (void *)GetProcAddress(hfusion, "CreateAssemblyNameObject"); + if (!pCreateAssemblyNameObject) + return FALSE; + + return TRUE; +} + +typedef struct _tagASMPROP_RES +{ + HRESULT hr; + CHAR val[MAX_PATH]; + DWORD size; +} ASMPROP_RES; + +static const ASMPROP_RES defaults[ASM_NAME_MAX_PARAMS] = +{ + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_FALSE, "", MAX_PATH}, + {S_FALSE, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0} +}; + +static const ASMPROP_RES emptyname[ASM_NAME_MAX_PARAMS] = +{ + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 2}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_FALSE, "", MAX_PATH}, + {S_FALSE, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0} +}; + +static const ASMPROP_RES winename[ASM_NAME_MAX_PARAMS] = +{ + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "wine", 10}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_FALSE, "", MAX_PATH}, + {S_FALSE, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0} +}; + +static const ASMPROP_RES vername[ASM_NAME_MAX_PARAMS] = +{ + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "wine", 10}, + {S_OK, "\x01", 2}, + {S_OK, "\x02", 2}, + {S_OK, "\x03", 2}, + {S_OK, "\x04", 2}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_FALSE, "", MAX_PATH}, + {S_FALSE, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0} +}; + +static const ASMPROP_RES badvername[ASM_NAME_MAX_PARAMS] = +{ + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "wine", 10}, + {S_OK, "\x01", 2}, + {S_OK, "\x05", 2}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_FALSE, "", MAX_PATH}, + {S_FALSE, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0} +}; + +static const ASMPROP_RES neutralname[ASM_NAME_MAX_PARAMS] = +{ + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "wine", 10}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 2}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_FALSE, "", MAX_PATH}, + {S_FALSE, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0} +}; + +static const ASMPROP_RES enname[ASM_NAME_MAX_PARAMS] = +{ + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "wine", 10}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "en", 6}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_FALSE, "", MAX_PATH}, + {S_FALSE, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0} +}; + +static const ASMPROP_RES pubkeyname[ASM_NAME_MAX_PARAMS] = +{ + {S_OK, "", 0}, + {S_OK, "\x12\x34\x56\x78\x90\xab\xcd\xef", 8}, + {S_OK, "", 0}, + {S_OK, "wine", 10}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", MAX_PATH}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0}, + {S_OK, "", 0} +}; + +static inline void to_widechar(LPWSTR dest, LPCSTR src) +{ + MultiByteToWideChar(CP_ACP, 0, src, -1, dest, MAX_PATH); +} + +static inline void to_multibyte(LPSTR dest, LPWSTR src) +{ + WideCharToMultiByte(CP_ACP, 0, src, -1, dest, MAX_PATH, NULL, NULL); +} + +static void test_assembly_name_props_line(IAssemblyName *name, + const ASMPROP_RES *vals, int line) +{ + HRESULT hr; + DWORD i, size; + WCHAR expect[MAX_PATH]; + WCHAR str[MAX_PATH]; + CHAR val[MAX_PATH]; + + for (i = 0; i < ASM_NAME_MAX_PARAMS; i++) + { + to_widechar(expect, vals[i].val); + + size = MAX_PATH; + ZeroMemory(str, MAX_PATH); + hr = IAssemblyName_GetProperty(name, i, str, &size); + to_multibyte(val, str); + + ok(hr == vals[i].hr || + broken(i >= ASM_NAME_CONFIG_MASK && hr == E_INVALIDARG) || /* .NET 1.1 */ + broken(i >= ASM_NAME_FILE_MAJOR_VERSION && hr == E_INVALIDARG), /* .NET 1.0 */ + "%d: prop %d: Expected %08x, got %08x\n", line, i, vals[i].hr, hr); + if (hr != E_INVALIDARG) + { + if (i == ASM_NAME_PUBLIC_KEY_TOKEN) + ok(!memcmp(vals[i].val, str, size), "Expected a correct ASM_NAME_PUBLIC_KEY_TOKEN\n"); + else + ok(!lstrcmpA(vals[i].val, val), "%d: prop %d: Expected \"%s\", got \"%s\"\n", line, i, vals[i].val, val); + ok(size == vals[i].size, "%d: prop %d: Expected %d, got %d\n", line, i, vals[i].size, size); + } + } +} + +#define test_assembly_name_props(name, vals) \ + test_assembly_name_props_line(name, vals, __LINE__); + +static void test_CreateAssemblyNameObject(void) +{ + IAssemblyName *name; + WCHAR str[MAX_PATH]; + WCHAR namestr[MAX_PATH]; + DWORD size, hi, lo; + HRESULT hr; + + static const WCHAR empty[] = {0}; + + /* NULL ppAssemblyNameObj */ + to_widechar(namestr, "wine.dll"); + hr = pCreateAssemblyNameObject(NULL, namestr, 0, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + + /* NULL szAssemblyName, CANOF_PARSE_DISPLAY_NAME */ + name = (IAssemblyName *)0xdeadbeef; + hr = pCreateAssemblyNameObject(&name, NULL, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(name == (IAssemblyName *)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", name); + + /* empty szAssemblyName, CANOF_PARSE_DISPLAY_NAME */ + name = (IAssemblyName *)0xdeadbeef; + hr = pCreateAssemblyNameObject(&name, empty, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(name == (IAssemblyName *)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", name); + + /* check the contents of the AssemblyName for default values */ + + /* NULL szAssemblyName */ + name = NULL; + hr = pCreateAssemblyNameObject(&name, NULL, CANOF_SET_DEFAULT_VALUES, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == E_INVALIDARG), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(lstrlenW(str) == 0, "Expected empty name\n"); + ok(size == 0, "Expected 0, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0, "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + if (hr == S_OK) + win_skip(".NET 1.x doesn't handle ASM_NAME_PROCESSOR_ID_ARRAY" + " and ASM_NAME_OSINFO_ARRAY correctly\n"); + else + test_assembly_name_props(name, defaults); + + IAssemblyName_Release(name); + + /* empty szAssemblyName */ + name = NULL; + hr = pCreateAssemblyNameObject(&name, empty, CANOF_SET_DEFAULT_VALUES, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(lstrlenW(str) == 0, "Expected empty name\n"); + ok(size == 1, "Expected 1, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0, "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + if (hr == S_OK) + win_skip(".NET 1.x doesn't handle ASM_NAME_PROCESSOR_ID_ARRAY" + " and ASM_NAME_OSINFO_ARRAY correctly\n"); + else + test_assembly_name_props(name, emptyname); + + IAssemblyName_Release(name); + + /* 'wine' */ + to_widechar(namestr, "wine"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_SET_DEFAULT_VALUES, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0, "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + if (hr == S_OK) + win_skip(".NET 1.x doesn't handle ASM_NAME_PROCESSOR_ID_ARRAY" + " and ASM_NAME_OSINFO_ARRAY correctly\n"); + else + test_assembly_name_props(name, winename); + + IAssemblyName_Release(name); + + /* check the contents of the AssemblyName with parsing */ + + /* 'wine' */ + to_widechar(namestr, "wine"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0, "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + test_assembly_name_props(name, winename); + + IAssemblyName_Release(name); + + /* 'wine, Version=1.2.3.4' */ + to_widechar(namestr, "wine, Version=1.2.3.4"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, Version=1.2.3.4", str); + ok(size == 22, "Expected 22, got %d\n", size); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(hi == 0x00010002, "Expected 0x00010002, got %08x\n", hi); + ok(lo == 0x00030004, "Expected 0x00030004, got %08x\n", lo); + + test_assembly_name_props(name, vername); + + IAssemblyName_Release(name); + + /* Version isn't of the form 1.x.x.x */ + to_widechar(namestr, "wine, Version=1.5"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, Version=1.5", str); + ok(size == 18, "Expected 18, got %d\n", size); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0 || + broken(hi == 0x10005), /* .NET 1.x */ + "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + test_assembly_name_props(name, badvername); + + IAssemblyName_Release(name); + + /* 'wine, Culture=neutral' */ + to_widechar(namestr, "wine, Culture=neutral"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, Culture=neutral", str); + ok(size == 22, "Expected 22, got %d\n", size); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0, "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + test_assembly_name_props(name, neutralname); + + IAssemblyName_Release(name); + + /* 'wine, Culture=en' */ + to_widechar(namestr, "wine, Culture=en"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, Culture=en", str); + ok(size == 17, "Expected 17, got %d\n", size); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0, "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + test_assembly_name_props(name, enname); + + IAssemblyName_Release(name); + + /* 'wine, PublicKeyToken=1234567890abcdef' */ + to_widechar(namestr, "wine, PublicKeyToken=1234567890abcdef"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine, PublicKeyToken=1234567890abcdef", str); + ok(size == 38, "Expected 38, got %d\n", size); + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0, "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + test_assembly_name_props(name, pubkeyname); + + IAssemblyName_Release(name); + + /* invalid property */ + to_widechar(namestr, "wine, BadProp=42"); + name = NULL; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(name != NULL, "Expected non-NULL name\n"); + + size = MAX_PATH; + hr = IAssemblyName_GetDisplayName(name, str, &size, ASM_DISPLAYF_FULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + todo_wine + { + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + } + + size = MAX_PATH; + str[0] = '\0'; + hr = IAssemblyName_GetName(name, &size, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_aw("wine", str); + ok(size == 5, "Expected 5, got %d\n", size); + + hi = 0xbeefcace; + lo = 0xcafebabe; + hr = IAssemblyName_GetVersion(name, &hi, &lo); + ok(hr == FUSION_E_INVALID_NAME || + broken(hr == S_OK), /* .NET 1.x */ + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(hi == 0, "Expected 0, got %08x\n", hi); + ok(lo == 0, "Expected 0, got %08x\n", lo); + + test_assembly_name_props(name, winename); + + IAssemblyName_Release(name); + + /* PublicKeyToken is not 16 chars long */ + to_widechar(namestr, "wine, PublicKeyToken=567890abcdef"); + name = (IAssemblyName *)0xdeadbeef; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + if (hr == S_OK && name != (IAssemblyName *)0xdeadbeef) + { + win_skip(".NET 1.x doesn't check PublicKeyToken correctly\n"); + IAssemblyName_Release(name); + return; + } + ok(hr == FUSION_E_INVALID_NAME, + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(name == (IAssemblyName *)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", name); + + /* PublicKeyToken contains invalid chars */ + to_widechar(namestr, "wine, PublicKeyToken=1234567890ghijkl"); + name = (IAssemblyName *)0xdeadbeef; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == FUSION_E_INVALID_NAME, + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(name == (IAssemblyName *)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", name); + + /* no comma separator */ + to_widechar(namestr, "wine PublicKeyToken=1234567890abcdef"); + name = (IAssemblyName *)0xdeadbeef; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + todo_wine + { + ok(hr == FUSION_E_INVALID_NAME, + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(name == (IAssemblyName *)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", name); + } + + /* no '=' */ + to_widechar(namestr, "wine, PublicKeyToken"); + name = (IAssemblyName *)0xdeadbeef; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == FUSION_E_INVALID_NAME, + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(name == (IAssemblyName *)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", name); + + /* no value */ + to_widechar(namestr, "wine, PublicKeyToken="); + name = (IAssemblyName *)0xdeadbeef; + hr = pCreateAssemblyNameObject(&name, namestr, CANOF_PARSE_DISPLAY_NAME, NULL); + ok(hr == FUSION_E_INVALID_NAME, + "Expected FUSION_E_INVALID_NAME, got %08x\n", hr); + ok(name == (IAssemblyName *)0xdeadbeef, "Expected 0xdeadbeef, got %p\n", name); +} + +START_TEST(asmname) +{ + if (!init_functionpointers()) + { + win_skip("fusion.dll not available\n"); + return; + } + + test_CreateAssemblyNameObject(); +} diff --git a/rostests/winetests/fusion/fusion.c b/rostests/winetests/fusion/fusion.c new file mode 100644 index 00000000000..6ebd4550eb0 --- /dev/null +++ b/rostests/winetests/fusion/fusion.c @@ -0,0 +1,213 @@ +/* + * Copyright 2008 James Hawkins + * + * 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 + */ + +#include +#include + +#include "wine/test.h" + +static HMODULE hmscoree; + +static HRESULT (WINAPI *pGetCachePath)(ASM_CACHE_FLAGS dwCacheFlags, + LPWSTR pwzCachePath, PDWORD pcchPath); +static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion, + LPVOID pvReserved, HMODULE *phModDll); +static HRESULT (WINAPI *pGetCORVersion)(LPWSTR pbuffer, DWORD cchBuffer, + DWORD *dwLength); + +static CHAR string1[MAX_PATH], string2[MAX_PATH]; + +#define ok_w2(format, szString1, szString2) \ +\ + WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ + WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ + ok(!lstrcmpA(string1, string2), format, string1, string2) + +static BOOL init_functionpointers(void) +{ + HRESULT hr; + HMODULE hfusion; + + static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0}; + + hmscoree = LoadLibraryA("mscoree.dll"); + if (!hmscoree) + { + win_skip("mscoree.dll not available\n"); + return FALSE; + } + + pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim"); + if (!pLoadLibraryShim) + { + win_skip("LoadLibraryShim not available\n"); + FreeLibrary(hmscoree); + return FALSE; + } + + pGetCORVersion = (void *)GetProcAddress(hmscoree, "GetCORVersion"); + + hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion); + if (FAILED(hr)) + { + win_skip("fusion.dll not available\n"); + FreeLibrary(hmscoree); + return FALSE; + } + + pGetCachePath = (void *)GetProcAddress(hfusion, "GetCachePath"); + return TRUE; +} + +static void test_GetCachePath(void) +{ + CHAR windirA[MAX_PATH]; + WCHAR windir[MAX_PATH]; + WCHAR cachepath[MAX_PATH]; + WCHAR version[MAX_PATH]; + WCHAR path[MAX_PATH]; + DWORD size; + HRESULT hr; + + static const WCHAR backslash[] = {'\\',0}; + static const WCHAR nochange[] = {'n','o','c','h','a','n','g','e',0}; + static const WCHAR assembly[] = {'a','s','s','e','m','b','l','y',0}; + static const WCHAR gac[] = {'G','A','C',0}; + + if (!pGetCachePath) + { + win_skip("GetCachePath not implemented\n"); + return; + } + + GetWindowsDirectoryA(windirA, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, windirA, -1, windir, MAX_PATH); + lstrcpyW(cachepath, windir); + lstrcatW(cachepath, backslash); + lstrcatW(cachepath, assembly); + lstrcatW(cachepath, backslash); + lstrcatW(cachepath, gac); + + /* NULL pwzCachePath, pcchPath is 0 */ + size = 0; + hr = pGetCachePath(ASM_CACHE_GAC, NULL, &size); + ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), + "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got %08x\n", hr); + ok(size == lstrlenW(cachepath) + 1, + "Expected %d, got %d\n", lstrlenW(cachepath) + 1, size); + + /* NULL pwszCachePath, pcchPath is MAX_PATH */ + size = MAX_PATH; + hr = pGetCachePath(ASM_CACHE_GAC, NULL, &size); + ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), + "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got %08x\n", hr); + ok(size == lstrlenW(cachepath) + 1, + "Expected %d, got %d\n", lstrlenW(cachepath) + 1, size); + + /* both pwszCachePath and pcchPath NULL */ + hr = pGetCachePath(ASM_CACHE_GAC, NULL, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + + /* NULL pcchPath */ + lstrcpyW(path, nochange); + hr = pGetCachePath(ASM_CACHE_GAC, path, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok_w2("Expected \"%s\", got \"%s\"\n", nochange, path); + + /* get the cache path */ + lstrcpyW(path, nochange); + size = MAX_PATH; + hr = pGetCachePath(ASM_CACHE_GAC, path, &size); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_w2("Expected \"%s\", got \"%s\"\n", cachepath, path); + + /* pcchPath has no room for NULL terminator */ + lstrcpyW(path, nochange); + size = lstrlenW(cachepath); + hr = pGetCachePath(ASM_CACHE_GAC, path, &size); + ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), + "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got %08x\n", hr); + ok_w2("Expected \"%s\", got \"%s\"\n", nochange, path); + + lstrcpyW(cachepath, windir); + lstrcatW(cachepath, backslash); + lstrcatW(cachepath, assembly); + + /* ASM_CACHE_ROOT */ + lstrcpyW(path, nochange); + size = MAX_PATH; + hr = pGetCachePath(ASM_CACHE_ROOT, path, &size); + ok(hr == S_OK || + broken(hr == E_INVALIDARG), /* .NET 1.1 */ + "Expected S_OK, got %08x\n", hr); + if (hr == S_OK) + ok_w2("Expected \"%s\", got \"%s\"\n", cachepath, path); + + if (pGetCORVersion) + { + CHAR versionA[MAX_PATH]; + CHAR cachepathA[MAX_PATH]; + CHAR nativeimgA[MAX_PATH]; + CHAR zapfmtA[MAX_PATH]; + + if (hr == S_OK) + { + lstrcpyA(nativeimgA, "NativeImages_"); +#ifdef _WIN64 + lstrcpyA(zapfmtA, "%s\\%s\\%s%s_64"); +#else + lstrcpyA(zapfmtA, "%s\\%s\\%s%s_32"); +#endif + } + else + { + lstrcpyA(nativeimgA, "NativeImages1_"); + lstrcpyA(zapfmtA, "%s\\%s\\%s%s"); + } + + pGetCORVersion(version, MAX_PATH, &size); + WideCharToMultiByte(CP_ACP, 0, version, -1, versionA, MAX_PATH, 0, 0); + + wsprintfA(cachepathA, zapfmtA, windirA, "assembly", nativeimgA, versionA); + MultiByteToWideChar(CP_ACP, 0, cachepathA, -1, cachepath, MAX_PATH); + + /* ASM_CACHE_ZAP */ + lstrcpyW(path, nochange); + size = MAX_PATH; + hr = pGetCachePath(ASM_CACHE_ZAP, path, &size); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_w2("Expected \"%s\", got \"%s\"\n", cachepath, path); + } + + /* two flags at once */ + lstrcpyW(path, nochange); + size = MAX_PATH; + hr = pGetCachePath(ASM_CACHE_GAC | ASM_CACHE_ROOT, path, &size); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok_w2("Expected \"%s\", got \"%s\"\n", nochange, path); +} + +START_TEST(fusion) +{ + if (!init_functionpointers()) + return; + + test_GetCachePath(); + + FreeLibrary(hmscoree); +} diff --git a/rostests/winetests/fusion/fusion.rbuild b/rostests/winetests/fusion/fusion.rbuild new file mode 100644 index 00000000000..6114362de3c --- /dev/null +++ b/rostests/winetests/fusion/fusion.rbuild @@ -0,0 +1,12 @@ + + . + + asmcache.c + asmenum.c + asmname.c + fusion.c + testlist.c + wine + user32 + ntdll + diff --git a/rostests/winetests/fusion/testlist.c b/rostests/winetests/fusion/testlist.c new file mode 100644 index 00000000000..a42cfc24642 --- /dev/null +++ b/rostests/winetests/fusion/testlist.c @@ -0,0 +1,21 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_fusion(void); +extern void func_asmname(void); +extern void func_asmenum(void); +extern void func_asmcache(void); + +const struct test winetest_testlist[] = +{ + { "fusion", func_fusion }, + { "asmname", func_asmname }, + { "asmenum", func_asmenum }, + { "asmcache", func_asmcache }, + { 0, 0 } +}; diff --git a/rostests/winetests/gdi32/bitmap.c b/rostests/winetests/gdi32/bitmap.c index 2ef28914a03..f9cc76ebb93 100755 --- a/rostests/winetests/gdi32/bitmap.c +++ b/rostests/winetests/gdi32/bitmap.c @@ -70,13 +70,15 @@ static INT BITMAP_GetWidthBytes( INT bmWidth, INT bpp ) static void test_bitmap_info(HBITMAP hbm, INT expected_depth, const BITMAPINFOHEADER *bmih) { BITMAP bm; + BITMAP bma[2]; INT ret, width_bytes; - char buf[512], buf_cmp[512]; + BYTE buf[512], buf_cmp[512]; + DWORD gle; ret = GetObject(hbm, sizeof(bm), &bm); ok(ret == sizeof(bm), "GetObject returned %d\n", ret); - ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType); + ok(bm.bmType == 0 || broken(bm.bmType == 21072 /* Win9x */), "wrong bm.bmType %d\n", bm.bmType); ok(bm.bmWidth == bmih->biWidth, "wrong bm.bmWidth %d\n", bm.bmWidth); ok(bm.bmHeight == bmih->biHeight, "wrong bm.bmHeight %d\n", bm.bmHeight); width_bytes = BITMAP_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel); @@ -88,8 +90,10 @@ static void test_bitmap_info(HBITMAP hbm, INT expected_depth, const BITMAPINFOHE assert(sizeof(buf) >= bm.bmWidthBytes * bm.bmHeight); assert(sizeof(buf) == sizeof(buf_cmp)); + SetLastError(0xdeadbeef); ret = GetBitmapBits(hbm, 0, NULL); - ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight); + gle=GetLastError(); + ok(ret == bm.bmWidthBytes * bm.bmHeight || (ret == 0 && gle == ERROR_INVALID_PARAMETER /* Win9x */), "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight); memset(buf_cmp, 0xAA, sizeof(buf_cmp)); memset(buf_cmp, 0, bm.bmWidthBytes * bm.bmHeight); @@ -97,23 +101,29 @@ static void test_bitmap_info(HBITMAP hbm, INT expected_depth, const BITMAPINFOHE memset(buf, 0xAA, sizeof(buf)); ret = GetBitmapBits(hbm, sizeof(buf), buf); ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight); - ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n"); + ok(!memcmp(buf, buf_cmp, sizeof(buf)) || + broken(memcmp(buf, buf_cmp, sizeof(buf))), /* win9x doesn't init the bitmap bits */ + "buffers do not match, depth %d\n", bmih->biBitCount); /* test various buffer sizes for GetObject */ - ret = GetObject(hbm, 0, NULL); - ok(ret == sizeof(bm), "wrong size %d\n", ret); - - ret = GetObject(hbm, sizeof(bm) * 2, &bm); - ok(ret == sizeof(bm), "wrong size %d\n", ret); + ret = GetObject(hbm, sizeof(*bma) * 2, bma); + ok(ret == sizeof(*bma) || broken(ret == sizeof(*bma) * 2 /* Win9x */), "wrong size %d\n", ret); ret = GetObject(hbm, sizeof(bm) / 2, &bm); - ok(ret == 0, "%d != 0\n", ret); + ok(ret == 0 || broken(ret == sizeof(bm) / 2 /* Win9x */), "%d != 0\n", ret); ret = GetObject(hbm, 0, &bm); ok(ret == 0, "%d != 0\n", ret); ret = GetObject(hbm, 1, &bm); - ok(ret == 0, "%d != 0\n", ret); + ok(ret == 0 || broken(ret == 1 /* Win9x */), "%d != 0\n", ret); + + /* Don't trust Win9x not to try to write to NULL */ + if (ret == 0) + { + ret = GetObject(hbm, 0, NULL); + ok(ret == sizeof(bm), "wrong size %d\n", ret); +} } static void test_createdibitmap(void) @@ -135,6 +145,11 @@ static void test_createdibitmap(void) bmih.biBitCount = 32; bmih.biCompression = BI_RGB; + hbm = CreateDIBitmap(hdc, NULL, CBM_INIT, NULL, NULL, 0); + ok(hbm == NULL, "CreateDIBitmap should fail\n"); + hbm = CreateDIBitmap(hdc, NULL, 0, NULL, NULL, 0); + ok(hbm == NULL, "CreateDIBitmap should fail\n"); + /* First create an un-initialised bitmap. The depth of the bitmap should match that of the hdc and not that supplied in bmih. */ @@ -275,7 +290,9 @@ static INT DIB_GetWidthBytes( int width, int bpp ) static void test_dib_info(HBITMAP hbm, const void *bits, const BITMAPINFOHEADER *bmih) { BITMAP bm; + BITMAP bma[2]; DIBSECTION ds; + DIBSECTION dsa[2]; INT ret, bm_width_bytes, dib_width_bytes; BYTE *buf; @@ -298,8 +315,11 @@ static void test_dib_info(HBITMAP hbm, const void *bits, const BITMAPINFOHEADER buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight + 4096); /* GetBitmapBits returns not 32-bit aligned data */ + SetLastError(0xdeadbeef); ret = GetBitmapBits(hbm, 0, NULL); - ok(ret == bm_width_bytes * bm.bmHeight, "%d != %d\n", ret, bm_width_bytes * bm.bmHeight); + ok(ret == bm_width_bytes * bm.bmHeight || + broken(ret == 0 && GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */ + "%d != %d\n", ret, bm_width_bytes * bm.bmHeight); memset(buf, 0xAA, bm.bmWidthBytes * bm.bmHeight + 4096); ret = GetBitmapBits(hbm, bm.bmWidthBytes * bm.bmHeight + 4096, buf); @@ -309,27 +329,30 @@ static void test_dib_info(HBITMAP hbm, const void *bits, const BITMAPINFOHEADER /* test various buffer sizes for GetObject */ memset(&ds, 0xAA, sizeof(ds)); - ret = GetObject(hbm, sizeof(bm) * 2, &bm); - ok(ret == sizeof(bm), "wrong size %d\n", ret); + ret = GetObject(hbm, sizeof(*bma) * 2, bma); + ok(ret == sizeof(*bma) || broken(ret == sizeof(*bma) * 2 /* Win9x */), "wrong size %d\n", ret); ok(bm.bmWidth == bmih->biWidth, "wrong bm.bmWidth %d\n", bm.bmWidth); ok(bm.bmHeight == bmih->biHeight, "wrong bm.bmHeight %d\n", bm.bmHeight); ok(bm.bmBits == bits, "wrong bm.bmBits %p != %p\n", bm.bmBits, bits); ret = GetObject(hbm, sizeof(bm) / 2, &bm); - ok(ret == 0, "%d != 0\n", ret); + ok(ret == 0 || broken(ret == sizeof(bm) / 2 /* Win9x */), "%d != 0\n", ret); ret = GetObject(hbm, 0, &bm); ok(ret == 0, "%d != 0\n", ret); ret = GetObject(hbm, 1, &bm); - ok(ret == 0, "%d != 0\n", ret); + ok(ret == 0 || broken(ret == 1 /* Win9x */), "%d != 0\n", ret); /* test various buffer sizes for GetObject */ ret = GetObject(hbm, 0, NULL); - ok(ret == sizeof(bm), "wrong size %d\n", ret); + ok(ret == sizeof(bm) || broken(ret == sizeof(DIBSECTION) /* Win9x */), "wrong size %d\n", ret); + + ret = GetObject(hbm, sizeof(*dsa) * 2, dsa); + ok(ret == sizeof(*dsa) || broken(ret == sizeof(*dsa) * 2 /* Win9x */), "wrong size %d\n", ret); memset(&ds, 0xAA, sizeof(ds)); - ret = GetObject(hbm, sizeof(ds) * 2, &ds); + ret = GetObject(hbm, sizeof(ds), &ds); ok(ret == sizeof(ds), "wrong size %d\n", ret); ok(ds.dsBm.bmBits == bits, "wrong bm.bmBits %p != %p\n", ds.dsBm.bmBits, bits); @@ -351,7 +374,7 @@ static void test_dib_info(HBITMAP hbm, const void *bits, const BITMAPINFOHEADER memset(&ds, 0xAA, sizeof(ds)); ret = GetObject(hbm, sizeof(ds) - 4, &ds); - ok(ret == sizeof(ds.dsBm), "wrong size %d\n", ret); + ok(ret == sizeof(ds.dsBm) || broken(ret == (sizeof(ds) - 4) /* Win9x */), "wrong size %d\n", ret); ok(ds.dsBm.bmWidth == bmih->biWidth, "%u != %u\n", ds.dsBmih.biWidth, bmih->biWidth); ok(ds.dsBm.bmHeight == bmih->biHeight, "%u != %u\n", ds.dsBmih.biHeight, bmih->biHeight); ok(ds.dsBm.bmBits == bits, "%p != %p\n", ds.dsBm.bmBits, bits); @@ -360,7 +383,7 @@ static void test_dib_info(HBITMAP hbm, const void *bits, const BITMAPINFOHEADER ok(ret == 0, "%d != 0\n", ret); ret = GetObject(hbm, 1, &ds); - ok(ret == 0, "%d != 0\n", ret); + ok(ret == 0 || broken(ret == 1 /* Win9x */), "%d != 0\n", ret); } #define test_color_todo(got, exp, txt, todo) \ @@ -380,6 +403,64 @@ static void test_dib_info(HBITMAP hbm, const void *bits, const BITMAPINFOHEADER test_color_todo(c, exp, GetPixel, todo_getp); \ } +static void test_dib_bits_access( HBITMAP hdib, void *bits ) +{ + MEMORY_BASIC_INFORMATION info; + char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)]; + DWORD data[256]; + BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf; + HDC hdc = GetDC(0); + char filename[MAX_PATH]; + HANDLE file; + DWORD written; + INT ret; + + ok(VirtualQuery(bits, &info, sizeof(info)) == sizeof(info), + "VirtualQuery failed\n"); + ok(info.BaseAddress == bits, "%p != %p\n", info.BaseAddress, bits); + ok(info.AllocationBase == bits, "%p != %p\n", info.AllocationBase, bits); + ok(info.AllocationProtect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State); + ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect); + ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + + memset( pbmi, 0, sizeof(bmibuf) ); + memset( data, 0xcc, sizeof(data) ); + pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader); + pbmi->bmiHeader.biHeight = 16; + pbmi->bmiHeader.biWidth = 16; + pbmi->bmiHeader.biBitCount = 32; + pbmi->bmiHeader.biPlanes = 1; + pbmi->bmiHeader.biCompression = BI_RGB; + + ret = SetDIBits( hdc, hdib, 0, 16, data, pbmi, DIB_RGB_COLORS ); + ok(ret == 16 || + broken(ret == 0), /* win9x */ + "SetDIBits failed: expected 16 got %d\n", ret); + + ok(VirtualQuery(bits, &info, sizeof(info)) == sizeof(info), + "VirtualQuery failed\n"); + ok(info.BaseAddress == bits, "%p != %p\n", info.BaseAddress, bits); + ok(info.AllocationBase == bits, "%p != %p\n", info.AllocationBase, bits); + ok(info.AllocationProtect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State); + ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + /* it has been protected now */ + todo_wine ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect); + + /* try writing protected bits to a file */ + + GetTempFileNameA( ".", "dib", 0, filename ); + file = CreateFileA( filename, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, + CREATE_ALWAYS, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "failed to open %s error %u\n", filename, GetLastError() ); + ret = WriteFile( file, bits, 8192, &written, NULL ); + ok( ret, "WriteFile failed error %u\n", GetLastError() ); + if (ret) ok( written == 8192, "only wrote %u bytes\n", written ); + CloseHandle( file ); + DeleteFileA( filename ); +} + static void test_dibsections(void) { HDC hdc, hdcmem, hdcmem2; @@ -416,6 +497,13 @@ static void test_dibsections(void) pbmi->bmiHeader.biCompression = BI_RGB; SetLastError(0xdeadbeef); + + /* invalid pointer for BITMAPINFO + (*bits should be NULL on error) */ + bits = (BYTE*)0xdeadbeef; + hdib = CreateDIBSection(hdc, NULL, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok(hdib == NULL && bits == NULL, "CreateDIBSection failed for invalid parameter: bmi == 0x0\n"); + hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0); ok(hdib != NULL, "CreateDIBSection error %d\n", GetLastError()); ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIBSection\n"); @@ -432,6 +520,8 @@ static void test_dibsections(void) ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect); ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type); + test_dib_bits_access( hdib, bits ); + test_dib_info(hdib, bits, &pbmi->bmiHeader); DeleteObject(hdib); @@ -635,7 +725,8 @@ static void test_dibsections(void) hdib = CreateDIBSection(hdc, pbmi, DIB_PAL_COLORS, (void**)&bits, NULL, 0); ok(hdib != NULL, "CreateDIBSection failed\n"); ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n"); - ok(dibsec.dsBmih.biClrUsed == 2, + ok(dibsec.dsBmih.biClrUsed == 2 || + broken(dibsec.dsBmih.biClrUsed == 0), /* win9x */ "created DIBSection: wrong biClrUsed field: %u, should be: %u\n", dibsec.dsBmih.biClrUsed, 2); /* The colour table has already been grabbed from the dc, so we select back the @@ -689,7 +780,9 @@ static void test_dibsections(void) BitBlt(hdcmem2, 0, 0, 16,16, hdcmem, 0, 0, SRCCOPY); ok(bits32[0] == 0xff00, "lower left pixel is %08x\n", bits32[0]); - ok(bits32[17] == 0xff00ff, "bottom but one, left pixel is %08x\n", bits32[17]); + ok(bits32[17] == 0xff00ff || + broken(bits32[17] == 0x00ff00), /* Intermittent on Win9x/ME */ + "bottom but one, left pixel is %08x\n", bits32[17]); SelectObject(hdcmem2, oldbm2); test_dib_info(hdib2, bits32, &pbmi->bmiHeader); @@ -727,7 +820,8 @@ static void test_dibsections(void) hdib = CreateDIBSection(hdc, pbmi, DIB_PAL_COLORS, (void**)&bits, NULL, 0); ok(hdib != NULL, "CreateDIBSection failed\n"); ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n"); - ok(dibsec.dsBmih.biClrUsed == 256, + ok(dibsec.dsBmih.biClrUsed == 256 || + broken(dibsec.dsBmih.biClrUsed == 0), /* win9x */ "created DIBSection: wrong biClrUsed field: %u, should be: %u\n", dibsec.dsBmih.biClrUsed, 256); test_dib_info(hdib, bits, &pbmi->bmiHeader); @@ -965,6 +1059,7 @@ static void test_bitmap(void) HBITMAP hbmp, hbmp_old; HDC hdc; BITMAP bm; + BITMAP bma[2]; INT ret; hdc = CreateCompatibleDC(0); @@ -974,7 +1069,8 @@ static void test_bitmap(void) hbmp = CreateBitmap(0x7ffffff, 1, 1, 1, NULL); if (!hbmp) { - ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY, + ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY /* XP */ || + GetLastError() == ERROR_INVALID_PARAMETER /* Win2k */, "expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError()); } else @@ -993,9 +1089,12 @@ static void test_bitmap(void) SetLastError(0xdeadbeef); hbmp = CreateBitmap(0x7ffffff + 1, 1, 1, 1, NULL); - ok(!hbmp, "CreateBitmap should fail\n"); + ok(!hbmp || broken(hbmp != NULL /* Win9x */), "CreateBitmap should fail\n"); + if (!hbmp) ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + else + DeleteObject(hbmp); hbmp = CreateBitmap(15, 15, 1, 1, NULL); assert(hbmp != NULL); @@ -1015,7 +1114,8 @@ static void test_bitmap(void) assert(sizeof(buf) == sizeof(buf_cmp)); ret = GetBitmapBits(hbmp, 0, NULL); - ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight); + ok(ret == bm.bmWidthBytes * bm.bmHeight || broken(ret == 0 /* Win9x */), + "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight); memset(buf_cmp, 0xAA, sizeof(buf_cmp)); memset(buf_cmp, 0, bm.bmWidthBytes * bm.bmHeight); @@ -1023,7 +1123,9 @@ static void test_bitmap(void) memset(buf, 0xAA, sizeof(buf)); ret = GetBitmapBits(hbmp, sizeof(buf), buf); ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight); - ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n"); + ok(!memcmp(buf, buf_cmp, sizeof(buf)) || + broken(memcmp(buf, buf_cmp, sizeof(buf))), /* win9x doesn't init the bitmap bits */ + "buffers do not match\n"); hbmp_old = SelectObject(hdc, hbmp); @@ -1041,23 +1143,25 @@ static void test_bitmap(void) memset(buf, 0xAA, sizeof(buf)); ret = GetBitmapBits(hbmp, sizeof(buf), buf); ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight); - ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n"); + ok(!memcmp(buf, buf_cmp, sizeof(buf)) || + broken(memcmp(buf, buf_cmp, sizeof(buf))), /* win9x doesn't init the bitmap bits */ + "buffers do not match\n"); hbmp_old = SelectObject(hdc, hbmp_old); ok(hbmp_old == hbmp, "wrong old bitmap %p\n", hbmp_old); /* test various buffer sizes for GetObject */ - ret = GetObject(hbmp, sizeof(bm) * 2, &bm); - ok(ret == sizeof(bm), "wrong size %d\n", ret); + ret = GetObject(hbmp, sizeof(*bma) * 2, bma); + ok(ret == sizeof(*bma) || broken(ret == sizeof(*bma) * 2 /* Win9x */), "wrong size %d\n", ret); ret = GetObject(hbmp, sizeof(bm) / 2, &bm); - ok(ret == 0, "%d != 0\n", ret); + ok(ret == 0 || broken(ret == sizeof(bm) / 2 /* Win9x */), "%d != 0\n", ret); ret = GetObject(hbmp, 0, &bm); ok(ret == 0, "%d != 0\n", ret); ret = GetObject(hbmp, 1, &bm); - ok(ret == 0, "%d != 0\n", ret); + ok(ret == 0 || broken(ret == 1 /* Win9x */), "%d != 0\n", ret); DeleteObject(hbmp); DeleteDC(hdc); @@ -1133,7 +1237,7 @@ static void test_GetDIBits_selected_DIB(UINT bpp) /* Select the DIB into a DC */ dib_dc = CreateCompatibleDC(NULL); - old_bmp = (HBITMAP) SelectObject(dib_dc, dib); + old_bmp = SelectObject(dib_dc, dib); dc = CreateCompatibleDC(NULL); bits2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dib_size); assert(bits2); @@ -1168,10 +1272,7 @@ static void test_GetDIBits_selected_DIB(UINT bpp) break; } } - if (bpp != 1) ok(equalContents, "GetDIBits with %d bpp DIB selected in DC: Invalid DIB bits\n",bpp); - else - todo_wine ok(equalContents, "GetDIBits with %d bpp DIB selected in DC: Invalid DIB bits\n",bpp); HeapFree(GetProcessHeap(), 0, bits2); DeleteDC(dc); @@ -1217,7 +1318,7 @@ static void test_GetDIBits_selected_DDB(BOOL monochrome) /* Set the pixels */ ddb_dc = CreateCompatibleDC(NULL); - old_bmp = (HBITMAP) SelectObject(ddb_dc, ddb); + old_bmp = SelectObject(ddb_dc, ddb); for (i = 0; i < width; i++) { for (j=0; j < height; j++) @@ -1259,7 +1360,7 @@ static void test_GetDIBits_selected_DDB(BOOL monochrome) memcpy(info2, info, sizeof(BITMAPINFOHEADER)); /* Select the DDB into another DC */ - old_bmp = (HBITMAP) SelectObject(ddb_dc, ddb); + old_bmp = SelectObject(ddb_dc, ddb); /* Get the bits */ res = GetDIBits(dc, ddb, 0, height, bits2, info2, DIB_RGB_COLORS); @@ -1293,6 +1394,30 @@ static void test_GetDIBits_selected_DDB(BOOL monochrome) } ok(equalContents, "GetDIBits with DDB selected in DC: Got different DIB bits\n"); + /* Test the palette */ + equalContents = TRUE; + if (info2->bmiHeader.biBitCount <= 8) + { + WORD *colors = (WORD*)info2->bmiColors; + + /* Get the palette indices */ + res = GetDIBits(dc, ddb, 0, 0, NULL, info2, DIB_PAL_COLORS); + if (res == 0 && GetLastError() == ERROR_INVALID_PARAMETER) /* Win9x */ + res = GetDIBits(dc, ddb, 0, height, NULL, info2, DIB_PAL_COLORS); + ok(res, "GetDIBits failed\n"); + + for (i=0;i < 1 << info->bmiHeader.biSizeImage; i++) + { + if (colors[i] != i) + { + equalContents = FALSE; + break; + } + } + } + + ok(equalContents, "GetDIBits with DDB selected in DC: non 1:1 palette indices\n"); + HeapFree(GetProcessHeap(), 0, bits2); HeapFree(GetProcessHeap(), 0, bits); DeleteDC(dc); @@ -1323,6 +1448,13 @@ static void test_GetDIBits(void) 0,0,0,0, 0xff,0xff,0,0, 0,0,0,0, 0xff,0xff,0,0, 0,0,0,0, 0xff,0xff,0,0, 0,0,0,0, 0xff,0xff,0,0 }; + static const BYTE dib_bits_1_9x[16 * 4] = + { + 0,0,0xaa,0xaa, 0xff,0xff,0xaa,0xaa, 0,0,0xaa,0xaa, 0xff,0xff,0xaa,0xaa, + 0,0,0xaa,0xaa, 0xff,0xff,0xaa,0xaa, 0,0,0xaa,0xaa, 0xff,0xff,0xaa,0xaa, + 0,0,0xaa,0xaa, 0xff,0xff,0xaa,0xaa, 0,0,0xaa,0xaa, 0xff,0xff,0xaa,0xaa, + 0,0,0xaa,0xaa, 0xff,0xff,0xaa,0xaa, 0,0,0xaa,0xaa, 0xff,0xff,0xaa,0xaa + }; /* 2-bytes aligned 24-bit bitmap data: 16x16 */ static const BYTE bmp_bits_24[16 * 16*3] = { @@ -1421,7 +1553,7 @@ static void test_GetDIBits(void) ok(!bm.bmBits, "wrong bmBits %p\n", bm.bmBits); bytes = GetBitmapBits(hbmp, 0, NULL); - ok(bytes == sizeof(bmp_bits_1), "expected 16*2 got %d bytes\n", bytes); + ok(bytes == sizeof(bmp_bits_1) || broken(bytes == 0 /* Win9x */), "expected 16*2 got %d bytes\n", bytes); bytes = GetBitmapBits(hbmp, sizeof(buf), buf); ok(bytes == sizeof(bmp_bits_1), "expected 16*2 got %d bytes\n", bytes); ok(!memcmp(buf, bmp_bits_1, sizeof(bmp_bits_1)), "bitmap bits don't match\n"); @@ -1439,7 +1571,9 @@ static void test_GetDIBits(void) SetLastError(0xdeadbeef); lines = GetDIBits(0, hbmp, 0, bm.bmHeight, buf, bi, DIB_RGB_COLORS); ok(lines == 0, "GetDIBits copied %d lines with hdc = 0\n", lines); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER || + broken(GetLastError() == 0xdeadbeef), /* winnt */ + "wrong error %u\n", GetLastError()); ok(bi->bmiHeader.biSizeImage == 0, "expected 0, got %u\n", bi->bmiHeader.biSizeImage); memset(buf, 0xAA, sizeof(buf)); @@ -1447,7 +1581,9 @@ static void test_GetDIBits(void) lines = GetDIBits(hdc, hbmp, 0, bm.bmHeight, buf, bi, DIB_RGB_COLORS); ok(lines == bm.bmHeight, "GetDIBits copied %d lines of %d, error %u\n", lines, bm.bmHeight, GetLastError()); - ok(bi->bmiHeader.biSizeImage == sizeof(dib_bits_1), "expected 16*4, got %u\n", bi->bmiHeader.biSizeImage); + ok(bi->bmiHeader.biSizeImage == sizeof(dib_bits_1) || + broken(bi->bmiHeader.biSizeImage == 0), /* win9x */ + "expected 16*4, got %u\n", bi->bmiHeader.biSizeImage); /* the color table consists of black and white */ ok(bi->bmiColors[0].rgbRed == 0 && bi->bmiColors[0].rgbGreen == 0 && @@ -1455,7 +1591,6 @@ static void test_GetDIBits(void) "expected bmiColors[0] 0,0,0,0 - got %x %x %x %x\n", bi->bmiColors[0].rgbRed, bi->bmiColors[0].rgbGreen, bi->bmiColors[0].rgbBlue, bi->bmiColors[0].rgbReserved); -todo_wine ok(bi->bmiColors[1].rgbRed == 0xff && bi->bmiColors[1].rgbGreen == 0xff && bi->bmiColors[1].rgbBlue == 0xff && bi->bmiColors[1].rgbReserved == 0, "expected bmiColors[0] 0xff,0xff,0xff,0 - got %x %x %x %x\n", @@ -1471,8 +1606,23 @@ todo_wine } /* returned bits are DWORD aligned and upside down */ -todo_wine - ok(!memcmp(buf, dib_bits_1, sizeof(dib_bits_1)), "DIB bits don't match\n"); + ok(!memcmp(buf, dib_bits_1, sizeof(dib_bits_1)) || + broken(!memcmp(buf, dib_bits_1_9x, sizeof(dib_bits_1_9x))), /* Win9x, WinME */ + "DIB bits don't match\n"); + + /* Test the palette indices */ + memset(bi->bmiColors, 0xAA, sizeof(RGBQUAD) * 256); + SetLastError(0xdeadbeef); + lines = GetDIBits(hdc, hbmp, 0, 0, NULL, bi, DIB_PAL_COLORS); + if (lines == 0 && GetLastError() == ERROR_INVALID_PARAMETER) + win_skip("Win9x/WinMe doesn't handle 0 for the number of scan lines\n"); + else + { + ok(((WORD*)bi->bmiColors)[0] == 0, "Color 0 is %d\n", ((WORD*)bi->bmiColors)[0]); + ok(((WORD*)bi->bmiColors)[1] == 1, "Color 1 is %d\n", ((WORD*)bi->bmiColors)[1]); + } + for (i = 2; i < 256; i++) + ok(((WORD*)bi->bmiColors)[i] == 0xAAAA, "Color %d is %d\n", i, ((WORD*)bi->bmiColors)[1]); /* retrieve 24-bit DIB data */ memset(bi, 0, sizeof(*bi)); @@ -1489,7 +1639,9 @@ todo_wine lines = GetDIBits(hdc, hbmp, 0, bm.bmHeight, buf, bi, DIB_RGB_COLORS); ok(lines == bm.bmHeight, "GetDIBits copied %d lines of %d, error %u\n", lines, bm.bmHeight, GetLastError()); - ok(bi->bmiHeader.biSizeImage == sizeof(dib_bits_24), "expected 16*16*3, got %u\n", bi->bmiHeader.biSizeImage); + ok(bi->bmiHeader.biSizeImage == sizeof(dib_bits_24) || + broken(bi->bmiHeader.biSizeImage == 0), /* win9x */ + "expected 16*16*3, got %u\n", bi->bmiHeader.biSizeImage); /* the color table doesn't exist for 24-bit images */ for (i = 0; i < 256; i++) @@ -1502,7 +1654,6 @@ todo_wine } /* returned bits are DWORD aligned and upside down */ -todo_wine ok(!memcmp(buf, dib_bits_24, sizeof(dib_bits_24)), "DIB bits don't match\n"); DeleteObject(hbmp); @@ -1518,7 +1669,9 @@ todo_wine memset(&bm, 0xAA, sizeof(bm)); bytes = GetObject(hbmp, sizeof(bm), &bm); ok(bytes == sizeof(bm), "GetObject returned %d\n", bytes); - ok(bm.bmType == 0, "wrong bmType %d\n", bm.bmType); + ok(bm.bmType == 0 || + broken(bm.bmType == 21072), /* win9x */ + "wrong bmType %d\n", bm.bmType); ok(bm.bmWidth == 16, "wrong bmWidth %d\n", bm.bmWidth); ok(bm.bmHeight == 16, "wrong bmHeight %d\n", bm.bmHeight); ok(bm.bmWidthBytes == BITMAP_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel), "wrong bmWidthBytes %d\n", bm.bmWidthBytes); @@ -1527,8 +1680,9 @@ todo_wine ok(!bm.bmBits, "wrong bmBits %p\n", bm.bmBits); bytes = GetBitmapBits(hbmp, 0, NULL); - ok(bytes == bm.bmWidthBytes * bm.bmHeight, "expected %d got %d bytes\n", - bm.bmWidthBytes * bm.bmHeight, bytes); + ok(bytes == bm.bmWidthBytes * bm.bmHeight || + broken(bytes == 0), /* win9x */ + "expected %d got %d bytes\n", bm.bmWidthBytes * bm.bmHeight, bytes); bytes = GetBitmapBits(hbmp, sizeof(buf), buf); ok(bytes == bm.bmWidthBytes * bm.bmHeight, "expected %d got %d bytes\n", bm.bmWidthBytes * bm.bmHeight, bytes); @@ -1548,7 +1702,9 @@ todo_wine lines = GetDIBits(hdc, hbmp, 0, bm.bmHeight, buf, bi, DIB_RGB_COLORS); ok(lines == bm.bmHeight, "GetDIBits copied %d lines of %d, error %u\n", lines, bm.bmHeight, GetLastError()); - ok(bi->bmiHeader.biSizeImage == sizeof(dib_bits_1), "expected 16*4, got %u\n", bi->bmiHeader.biSizeImage); + ok(bi->bmiHeader.biSizeImage == sizeof(dib_bits_1) || + broken(bi->bmiHeader.biSizeImage == 0), /* win9x */ + "expected 16*4, got %u\n", bi->bmiHeader.biSizeImage); /* the color table consists of black and white */ ok(bi->bmiColors[0].rgbRed == 0 && bi->bmiColors[0].rgbGreen == 0 && @@ -1572,7 +1728,23 @@ todo_wine /* returned bits are DWORD aligned and upside down */ todo_wine - ok(!memcmp(buf, dib_bits_1, sizeof(dib_bits_1)), "DIB bits don't match\n"); + ok(!memcmp(buf, dib_bits_1, sizeof(dib_bits_1)) || + broken(!memcmp(buf, dib_bits_1_9x, sizeof(dib_bits_1_9x))), /* Win9x, WinME */ + "DIB bits don't match\n"); + + /* Test the palette indices */ + memset(bi->bmiColors, 0xAA, sizeof(RGBQUAD) * 256); + SetLastError(0xdeadbeef); + lines = GetDIBits(hdc, hbmp, 0, 0, NULL, bi, DIB_PAL_COLORS); + if (lines == 0 && GetLastError() == ERROR_INVALID_PARAMETER) + win_skip("Win9x/WinMe doesn't handle 0 for the number of scan lines\n"); + else + { + ok(((WORD*)bi->bmiColors)[0] == 0, "Color 0 is %d\n", ((WORD*)bi->bmiColors)[0]); + ok(((WORD*)bi->bmiColors)[1] == 1, "Color 1 is %d\n", ((WORD*)bi->bmiColors)[1]); + } + for (i = 2; i < 256; i++) + ok(((WORD*)bi->bmiColors)[i] == 0xAAAA, "Color %d is %d\n", i, ((WORD*)bi->bmiColors)[i]); /* retrieve 24-bit DIB data */ memset(bi, 0, sizeof(*bi)); @@ -1589,7 +1761,9 @@ todo_wine lines = GetDIBits(hdc, hbmp, 0, bm.bmHeight, buf, bi, DIB_RGB_COLORS); ok(lines == bm.bmHeight, "GetDIBits copied %d lines of %d, error %u\n", lines, bm.bmHeight, GetLastError()); - ok(bi->bmiHeader.biSizeImage == sizeof(dib_bits_24), "expected 16*16*3, got %u\n", bi->bmiHeader.biSizeImage); + ok(bi->bmiHeader.biSizeImage == sizeof(dib_bits_24) || + broken(bi->bmiHeader.biSizeImage == 0), /* win9x */ + "expected 16*16*3, got %u\n", bi->bmiHeader.biSizeImage); /* the color table doesn't exist for 24-bit images */ for (i = 0; i < 256; i++) @@ -1669,13 +1843,21 @@ static void test_GetDIBits_BI_BITFIELDS(void) ok( bitmasks[0] != 0, "red mask is not set\n" ); ok( bitmasks[1] != 0, "green mask is not set\n" ); ok( bitmasks[2] != 0, "blue mask is not set\n" ); - ok( dibinfo->bmiHeader.biSizeImage != 0xdeadbeef, "size image not set\n" ); + ok( dibinfo->bmiHeader.biSizeImage != 0xdeadbeef || + broken(dibinfo->bmiHeader.biSizeImage == 0xdeadbeef), /* win9x */ + "size image not set\n" ); /* now with bits and 0 lines */ memset(dibinfo, 0, sizeof(dibinfo_buf)); dibinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); dibinfo->bmiHeader.biSizeImage = 0xdeadbeef; + SetLastError(0xdeadbeef); ret = GetDIBits(hdc, hbm, 0, 0, bits, dibinfo, DIB_RGB_COLORS); + if (ret == 0 && GetLastError() == ERROR_INVALID_PARAMETER) + win_skip("Win9x/WinMe doesn't handle 0 for the number of scan lines\n"); + else + { + ok(ret == 1, "GetDIBits failed ret %u err %u\n",ret,GetLastError()); ok( !bitmasks[0], "red mask is set\n" ); ok( !bitmasks[1], "green mask is set\n" ); @@ -1692,6 +1874,7 @@ static void test_GetDIBits_BI_BITFIELDS(void) ok( bitmasks[2] != 0, "blue mask is not set\n" ); ok( dibinfo->bmiHeader.biSizeImage != 0xdeadbeef, "size image not set\n" ); } + } else skip("not in 16 bpp BI_BITFIELDS mode, skipping that test\n"); DeleteObject(hbm); @@ -1765,13 +1948,17 @@ static void test_select_object(void) memset(&bm, 0xAA, sizeof(bm)); bytes = GetObject(hbm, sizeof(bm), &bm); ok(bytes == sizeof(bm), "GetObject returned %d\n", bytes); - ok(bm.bmType == 0, "wrong bmType %d\n", bm.bmType); + ok(bm.bmType == 0 || + broken(bm.bmType == 21072), /* win9x */ + "wrong bmType %d\n", bm.bmType); ok(bm.bmWidth == 10, "wrong bmWidth %d\n", bm.bmWidth); ok(bm.bmHeight == 10, "wrong bmHeight %d\n", bm.bmHeight); ok(bm.bmWidthBytes == BITMAP_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel), "wrong bmWidthBytes %d\n", bm.bmWidthBytes); ok(bm.bmPlanes == planes, "wrong bmPlanes %u\n", bm.bmPlanes); if(depths[i] == 15) { - ok(bm.bmBitsPixel == 16, "wrong bmBitsPixel %d(15 bpp special)\n", bm.bmBitsPixel); + ok(bm.bmBitsPixel == 16 || + broken(bm.bmBitsPixel == 15), /* Win9x/WinME */ + "wrong bmBitsPixel %d(15 bpp special)\n", bm.bmBitsPixel); } else { ok(bm.bmBitsPixel == depths[i], "wrong bmBitsPixel %d\n", bm.bmBitsPixel); } @@ -1825,15 +2012,15 @@ static void test_CreateBitmap(void) HBITMAP bm1 = CreateCompatibleBitmap(screenDC, 0, 0); HBITMAP bm4 = CreateBitmap(0, 1, 0, 0, 0); HBITMAP bm5 = CreateDiscardableBitmap(hdc, 0, 0); - HBITMAP curObj1 = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP); - HBITMAP curObj2 = (HBITMAP)GetCurrentObject(screenDC, OBJ_BITMAP); + HBITMAP curObj1 = GetCurrentObject(hdc, OBJ_BITMAP); + HBITMAP curObj2 = GetCurrentObject(screenDC, OBJ_BITMAP); /* these 2 are not the stock monochrome bitmap */ HBITMAP bm2 = CreateCompatibleBitmap(hdc, 1, 1); HBITMAP bm3 = CreateBitmap(1, 1, 1, 1, 0); - HBITMAP old1 = (HBITMAP)SelectObject(hdc, bm2); - HBITMAP old2 = (HBITMAP)SelectObject(screenDC, bm3); + HBITMAP old1 = SelectObject(hdc, bm2); + HBITMAP old2 = SelectObject(screenDC, bm3); SelectObject(hdc, old1); SelectObject(screenDC, old2); @@ -1841,7 +2028,9 @@ static void test_CreateBitmap(void) "0: %p, 1: %p, 4: %p, 5: %p, curObj1 %p, old1 %p\n", bm, bm1, bm4, bm5, curObj1, old1); ok(bm != bm2 && bm != bm3, "0: %p, 2: %p, 3: %p\n", bm, bm2, bm3); - ok(bm != curObj2 /* XP */ || bm == curObj2 /* Win9x */, +todo_wine + ok(bm != curObj2 || /* WinXP */ + broken(bm == curObj2) /* Win9x */, "0: %p, curObj2 %p\n", bm, curObj2); ok(old2 == 0, "old2 %p\n", old2); @@ -1853,7 +2042,6 @@ static void test_CreateBitmap(void) test_mono_1x1_bmp(bm5); test_mono_1x1_bmp(old1); test_mono_1x1_bmp(curObj1); - test_mono_1x1_bmp(curObj2); DeleteObject(bm); DeleteObject(bm1); @@ -1887,11 +2075,17 @@ static void test_CreateBitmap(void) bmp.bmPlanes = 1; bmp.bmBitsPixel = i; bmp.bmBits = NULL; + SetLastError(0xdeadbeef); bm = CreateBitmapIndirect(&bmp); if(i > 32) { DWORD error = GetLastError(); - ok(bm == 0, "CreateBitmapIndirect for %d bpp succeeded\n", i); - ok(error == ERROR_INVALID_PARAMETER, "Got error %d, expected ERROR_INVALID_PARAMETER\n", error); + ok(bm == 0 || + broken(bm != 0), /* Win9x and WinMe */ + "CreateBitmapIndirect for %d bpp succeeded\n", i); + ok(error == ERROR_INVALID_PARAMETER || + broken(error == 0xdeadbeef), /* Win9x and WinME */ + "Got error %d, expected ERROR_INVALID_PARAMETER\n", error); + DeleteObject(bm); continue; } ok(bm != 0, "CreateBitmapIndirect error %u\n", GetLastError()); @@ -1909,7 +2103,9 @@ static void test_CreateBitmap(void) } else if(i <= 32) { expect = 32; } - ok(bmp.bmBitsPixel == expect, "CreateBitmapIndirect for a %d bpp bitmap created a %d bpp bitmap, expected %d\n", + ok(bmp.bmBitsPixel == expect || + broken(bmp.bmBitsPixel == i), /* Win9x and WinMe */ + "CreateBitmapIndirect for a %d bpp bitmap created a %d bpp bitmap, expected %d\n", i, bmp.bmBitsPixel, expect); DeleteObject(bm); } @@ -1944,21 +2140,27 @@ static void test_bitmapinfoheadersize(void) SetLastError(0xdeadbeef); hdib = CreateDIBSection(hdc, &bmi, 0, NULL, NULL, 0); - ok(hdib != NULL, "CreateDIBSection error %d\n", GetLastError()); + ok(hdib != NULL || + broken(!hdib), /* Win98, WinMe */ + "CreateDIBSection error %d\n", GetLastError()); DeleteObject(hdib); bmi.bmiHeader.biSize = sizeof(BITMAPINFO); SetLastError(0xdeadbeef); hdib = CreateDIBSection(hdc, &bmi, 0, NULL, NULL, 0); - ok(hdib != NULL, "CreateDIBSection error %d\n", GetLastError()); + ok(hdib != NULL || + broken(!hdib), /* Win98, WinMe */ + "CreateDIBSection error %d\n", GetLastError()); DeleteObject(hdib); bmi.bmiHeader.biSize++; SetLastError(0xdeadbeef); hdib = CreateDIBSection(hdc, &bmi, 0, NULL, NULL, 0); - ok(hdib != NULL, "CreateDIBSection error %d\n", GetLastError()); + ok(hdib != NULL || + broken(!hdib), /* Win98, WinMe */ + "CreateDIBSection error %d\n", GetLastError()); DeleteObject(hdib); bmi.bmiHeader.biSize = sizeof(BITMAPV4HEADER); @@ -1972,7 +2174,9 @@ static void test_bitmapinfoheadersize(void) SetLastError(0xdeadbeef); hdib = CreateDIBSection(hdc, &bmi, 0, NULL, NULL, 0); - ok(hdib != NULL, "CreateDIBSection error %d\n", GetLastError()); + ok(hdib != NULL || + broken(!hdib), /* Win95 */ + "CreateDIBSection error %d\n", GetLastError()); DeleteObject(hdib); memset(&bci, 0, sizeof(BITMAPCOREINFO)); @@ -2034,7 +2238,9 @@ static void test_get16dibits(void) info->bmiHeader.biCompression = BI_RGB; ret = GetDIBits(screen_dc, hbmp, 0, 0, NULL, info, 0); - ok(ret != 0, "GetDIBits failed\n"); + ok(ret != 0 || + broken(ret == 0), /* win9x */ + "GetDIBits failed got %d\n", ret); for (p = ((BYTE *) info) + sizeof(info->bmiHeader); (p - ((BYTE *) info)) < info_len; p++) if (*p != '!') @@ -2046,7 +2252,470 @@ static void test_get16dibits(void) ReleaseDC(NULL, screen_dc); } -void test_GdiAlphaBlend() +static BOOL compare_buffers_no_alpha(UINT32 *a, UINT32 *b, int length) +{ + int i; + for(i = 0; i < length; i++) + if((a[i] & 0x00FFFFFF) != (b[i] & 0x00FFFFFF)) + return FALSE; + return TRUE; +} + +static void check_BitBlt_pixel(HDC hdcDst, HDC hdcSrc, UINT32 *dstBuffer, UINT32 *srcBuffer, + DWORD dwRop, UINT32 expected, int line) +{ + *srcBuffer = 0xFEDCBA98; + *dstBuffer = 0x89ABCDEF; + Rectangle(hdcSrc, 0, 0, 1, 1); /* A null operation to ensure dibs are coerced to X11 */ + BitBlt(hdcDst, 0, 0, 1, 1, hdcSrc, 0, 0, dwRop); + ok(expected == *dstBuffer, + "BitBlt with dwRop %06X. Expected 0x%08X, got 0x%08X from line %d\n", + dwRop, expected, *dstBuffer, line); +} + +static void test_BitBlt(void) +{ + HBITMAP bmpDst, bmpSrc; + HBITMAP oldDst, oldSrc; + HDC hdcScreen, hdcDst, hdcSrc; + UINT32 *dstBuffer, *srcBuffer; + HBRUSH hBrush, hOldBrush; + BITMAPINFO bitmapInfo; + + memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = 1; + bitmapInfo.bmiHeader.biHeight = 1; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32); + + hdcScreen = CreateCompatibleDC(0); + hdcDst = CreateCompatibleDC(hdcScreen); + hdcSrc = CreateCompatibleDC(hdcDst); + + /* Setup the destination dib section */ + bmpDst = CreateDIBSection(hdcScreen, &bitmapInfo, DIB_RGB_COLORS, (void**)&dstBuffer, + NULL, 0); + oldDst = SelectObject(hdcDst, bmpDst); + + hBrush = CreateSolidBrush(0x012345678); + hOldBrush = SelectObject(hdcDst, hBrush); + + /* Setup the source dib section */ + bmpSrc = CreateDIBSection(hdcScreen, &bitmapInfo, DIB_RGB_COLORS, (void**)&srcBuffer, + NULL, 0); + oldSrc = SelectObject(hdcSrc, bmpSrc); + + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCCOPY, 0xFEDCBA98, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCPAINT, 0xFFFFFFFF, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCAND, 0x88888888, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCINVERT, 0x77777777, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCERASE, 0x76543210, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, NOTSRCCOPY, 0x01234567, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, NOTSRCERASE, 0x00000000, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, MERGECOPY, 0x00581210, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, MERGEPAINT, 0x89ABCDEF, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, PATCOPY, 0x00785634, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, PATPAINT, 0x89FBDFFF, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, PATINVERT, 0x89D39BDB, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, DSTINVERT, 0x76543210, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, BLACKNESS, 0x00000000, __LINE__); + check_BitBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, WHITENESS, 0xFFFFFFFF, __LINE__); + + /* Tidy up */ + SelectObject(hdcSrc, oldSrc); + DeleteObject(bmpSrc); + DeleteDC(hdcSrc); + + SelectObject(hdcDst, hOldBrush); + DeleteObject(hBrush); + SelectObject(hdcDst, oldDst); + DeleteObject(bmpDst); + DeleteDC(hdcDst); + + + DeleteDC(hdcScreen); +} + +static void check_StretchBlt_pixel(HDC hdcDst, HDC hdcSrc, UINT32 *dstBuffer, UINT32 *srcBuffer, + DWORD dwRop, UINT32 expected, int line) +{ + *srcBuffer = 0xFEDCBA98; + *dstBuffer = 0x89ABCDEF; + StretchBlt(hdcDst, 0, 0, 2, 1, hdcSrc, 0, 0, 1, 1, dwRop); + ok(expected == *dstBuffer, + "StretchBlt with dwRop %06X. Expected 0x%08X, got 0x%08X from line %d\n", + dwRop, expected, *dstBuffer, line); +} + +static void check_StretchBlt_stretch(HDC hdcDst, HDC hdcSrc, UINT32 *dstBuffer, UINT32 *srcBuffer, + int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, + int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, + UINT32 expected[4], UINT32 legacy_expected[4], int line) +{ + memset(dstBuffer, 0, 16); + StretchBlt(hdcDst, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, + hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY); + ok(memcmp(dstBuffer, expected, 16) == 0 || + broken(compare_buffers_no_alpha(dstBuffer, legacy_expected, 4)), + "StretchBlt expected { %08X, %08X, %08X, %08X } got { %08X, %08X, %08X, %08X } " + "stretching { %d, %d, %d, %d } to { %d, %d, %d, %d } from line %d\n", + expected[0], expected[1], expected[2], expected[3], + dstBuffer[0], dstBuffer[1], dstBuffer[2], dstBuffer[3], + nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, + nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, line); +} + +static void test_StretchBlt(void) +{ + HBITMAP bmpDst, bmpSrc; + HBITMAP oldDst, oldSrc; + HDC hdcScreen, hdcDst, hdcSrc; + UINT32 *dstBuffer, *srcBuffer; + HBRUSH hBrush, hOldBrush; + BITMAPINFO biDst, biSrc; + UINT32 expected[4], legacy_expected[4]; + + memset(&biDst, 0, sizeof(BITMAPINFO)); + biDst.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + biDst.bmiHeader.biWidth = 2; + biDst.bmiHeader.biHeight = -2; + biDst.bmiHeader.biPlanes = 1; + biDst.bmiHeader.biBitCount = 32; + biDst.bmiHeader.biCompression = BI_RGB; + memcpy(&biSrc, &biDst, sizeof(BITMAPINFO)); + + hdcScreen = CreateCompatibleDC(0); + hdcDst = CreateCompatibleDC(hdcScreen); + hdcSrc = CreateCompatibleDC(hdcDst); + + /* Pixel Tests */ + bmpDst = CreateDIBSection(hdcScreen, &biDst, DIB_RGB_COLORS, (void**)&dstBuffer, + NULL, 0); + oldDst = SelectObject(hdcDst, bmpDst); + + bmpSrc = CreateDIBSection(hdcScreen, &biDst, DIB_RGB_COLORS, (void**)&srcBuffer, + NULL, 0); + oldSrc = SelectObject(hdcSrc, bmpSrc); + + hBrush = CreateSolidBrush(0x012345678); + hOldBrush = SelectObject(hdcDst, hBrush); + + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCCOPY, 0xFEDCBA98, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCPAINT, 0xFFFFFFFF, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCAND, 0x88888888, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCINVERT, 0x77777777, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, SRCERASE, 0x76543210, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, NOTSRCCOPY, 0x01234567, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, NOTSRCERASE, 0x00000000, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, MERGECOPY, 0x00581210, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, MERGEPAINT, 0x89ABCDEF, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, PATCOPY, 0x00785634, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, PATPAINT, 0x89FBDFFF, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, PATINVERT, 0x89D39BDB, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, DSTINVERT, 0x76543210, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, BLACKNESS, 0x00000000, __LINE__); + check_StretchBlt_pixel(hdcDst, hdcSrc, dstBuffer, srcBuffer, WHITENESS, 0xFFFFFFFF, __LINE__); + + SelectObject(hdcDst, hOldBrush); + DeleteObject(hBrush); + + /* Top-down to top-down tests */ + srcBuffer[0] = 0xCAFED00D, srcBuffer[1] = 0xFEEDFACE; + srcBuffer[2] = 0xFEDCBA98, srcBuffer[3] = 0x76543210; + + expected[0] = 0xCAFED00D, expected[1] = 0xFEEDFACE; + expected[2] = 0xFEDCBA98, expected[3] = 0x76543210; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 0, 0, 2, 2, expected, expected, __LINE__); + + expected[0] = 0xCAFED00D, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0x00000000; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 1, 1, 0, 0, 1, 1, expected, expected, __LINE__); + + expected[0] = 0xCAFED00D, expected[1] = 0xCAFED00D; + expected[2] = 0xCAFED00D, expected[3] = 0xCAFED00D; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 0, 0, 1, 1, expected, expected, __LINE__); + + expected[0] = 0xCAFED00D, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0x00000000; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 1, 1, 0, 0, 2, 2, expected, expected, __LINE__); + + expected[0] = 0x76543210, expected[1] = 0xFEDCBA98; + expected[2] = 0xFEEDFACE, expected[3] = 0xCAFED00D; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 1, 1, -2, -2, expected, expected, __LINE__); + + expected[0] = 0x76543210, expected[1] = 0xFEDCBA98; + expected[2] = 0xFEEDFACE, expected[3] = 0xCAFED00D; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 1, 1, -2, -2, 0, 0, 2, 2, expected, expected, __LINE__); + + /* This result seems broken. One might expect the following result: + * 0xCAFED00D 0xFEEDFACE + * 0xFEDCBA98 0x76543210 + */ + expected[0] = 0xCAFED00D, expected[1] = 0x00000000; + expected[2] = 0xFEDCBA98, expected[3] = 0x76543210; + legacy_expected[0] = 0xCAFED00D, legacy_expected[1] = 0x00000000; + legacy_expected[2] = 0x00000000, legacy_expected[3] = 0x00000000; + todo_wine check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 1, 1, -2, -2, 1, 1, -2, -2, expected, + legacy_expected, __LINE__); + + expected[0] = 0x00000000, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0xCAFED00D; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 1, 1, 2, 2, 0, 0, 2, 2, expected, expected, __LINE__); + + SelectObject(hdcDst, oldDst); + DeleteObject(bmpDst); + + /* Top-down to bottom-up tests */ + biDst.bmiHeader.biHeight = 2; + bmpDst = CreateDIBSection(hdcScreen, &biDst, DIB_RGB_COLORS, (void**)&dstBuffer, + NULL, 0); + oldDst = SelectObject(hdcDst, bmpDst); + + expected[0] = 0xFEDCBA98, expected[1] = 0x76543210; + expected[2] = 0xCAFED00D, expected[3] = 0xFEEDFACE; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 0, 0, 2, 2, expected, expected, __LINE__); + + expected[0] = 0xFEEDFACE, expected[1] = 0xCAFED00D; + expected[2] = 0x76543210, expected[3] = 0xFEDCBA98; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 1, 1, -2, -2, expected, expected, __LINE__); + + SelectObject(hdcSrc, oldSrc); + DeleteObject(bmpSrc); + + /* Bottom-up to bottom-up tests */ + biSrc.bmiHeader.biHeight = 2; + bmpSrc = CreateDIBSection(hdcScreen, &biSrc, DIB_RGB_COLORS, (void**)&srcBuffer, + NULL, 0); + srcBuffer[0] = 0xCAFED00D, srcBuffer[1] = 0xFEEDFACE; + srcBuffer[2] = 0xFEDCBA98, srcBuffer[3] = 0x76543210; + oldSrc = SelectObject(hdcSrc, bmpSrc); + + expected[0] = 0xCAFED00D, expected[1] = 0xFEEDFACE; + expected[2] = 0xFEDCBA98, expected[3] = 0x76543210; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 0, 0, 2, 2, expected, expected, __LINE__); + + expected[0] = 0x76543210, expected[1] = 0xFEDCBA98; + expected[2] = 0xFEEDFACE, expected[3] = 0xCAFED00D; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 1, 1, -2, -2, expected, expected, __LINE__); + + SelectObject(hdcDst, oldDst); + DeleteObject(bmpDst); + + /* Bottom-up to top-down tests */ + biDst.bmiHeader.biHeight = -2; + bmpDst = CreateDIBSection(hdcScreen, &biDst, DIB_RGB_COLORS, (void**)&dstBuffer, + NULL, 0); + oldDst = SelectObject(hdcDst, bmpDst); + + expected[0] = 0xFEDCBA98, expected[1] = 0x76543210; + expected[2] = 0xCAFED00D, expected[3] = 0xFEEDFACE; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 0, 0, 2, 2, expected, expected, __LINE__); + + expected[0] = 0xFEEDFACE, expected[1] = 0xCAFED00D; + expected[2] = 0x76543210, expected[3] = 0xFEDCBA98; + check_StretchBlt_stretch(hdcDst, hdcSrc, dstBuffer, srcBuffer, + 0, 0, 2, 2, 1, 1, -2, -2, expected, expected, __LINE__); + + /* Tidy up */ + SelectObject(hdcSrc, oldSrc); + DeleteObject(bmpSrc); + DeleteDC(hdcSrc); + + SelectObject(hdcDst, oldDst); + DeleteObject(bmpDst); + DeleteDC(hdcDst); + + DeleteDC(hdcScreen); +} + +static void check_StretchDIBits_pixel(HDC hdcDst, UINT32 *dstBuffer, UINT32 *srcBuffer, + DWORD dwRop, UINT32 expected, int line) +{ + const UINT32 buffer[2] = { 0xFEDCBA98, 0 }; + BITMAPINFO bitmapInfo; + + memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = 2; + bitmapInfo.bmiHeader.biHeight = 1; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = sizeof(buffer); + + *dstBuffer = 0x89ABCDEF; + + StretchDIBits(hdcDst, 0, 0, 2, 1, 0, 0, 1, 1, &buffer, &bitmapInfo, DIB_RGB_COLORS, dwRop); + ok(expected == *dstBuffer, + "StretchDIBits with dwRop %06X. Expected 0x%08X, got 0x%08X from line %d\n", + dwRop, expected, *dstBuffer, line); +} + +static void check_StretchDIBits_stretch(HDC hdcDst, UINT32 *dstBuffer, UINT32 *srcBuffer, + int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, + int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, + UINT32 expected[4], UINT32 legacy_expected[4], int line) +{ + BITMAPINFO bitmapInfo; + + memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = 2; + bitmapInfo.bmiHeader.biHeight = -2; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + memset(dstBuffer, 0, 16); + StretchDIBits(hdcDst, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, + nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, + srcBuffer, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY); + ok(memcmp(dstBuffer, expected, 16) == 0 || /* Win2k/XP */ + broken(compare_buffers_no_alpha(dstBuffer, legacy_expected, 4)) || /* Win9X/ME */ + broken(nWidthSrc < 0 || nHeightSrc < 0), /* Win9X/ME */ + "StretchDIBits expected { %08X, %08X, %08X, %08X } got { %08X, %08X, %08X, %08X } " + "stretching { %d, %d, %d, %d } to { %d, %d, %d, %d } from line %d\n", + expected[0], expected[1], expected[2], expected[3], + dstBuffer[0], dstBuffer[1], dstBuffer[2], dstBuffer[3], + nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, + nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, line); +} + +static void test_StretchDIBits(void) +{ + HBITMAP bmpDst; + HBITMAP oldDst; + HDC hdcScreen, hdcDst; + UINT32 *dstBuffer, srcBuffer[4]; + HBRUSH hBrush, hOldBrush; + BITMAPINFO biDst; + UINT32 expected[4], legacy_expected[4]; + + memset(&biDst, 0, sizeof(BITMAPINFO)); + biDst.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + biDst.bmiHeader.biWidth = 2; + biDst.bmiHeader.biHeight = -2; + biDst.bmiHeader.biPlanes = 1; + biDst.bmiHeader.biBitCount = 32; + biDst.bmiHeader.biCompression = BI_RGB; + + hdcScreen = CreateCompatibleDC(0); + hdcDst = CreateCompatibleDC(hdcScreen); + + /* Pixel Tests */ + bmpDst = CreateDIBSection(hdcScreen, &biDst, DIB_RGB_COLORS, (void**)&dstBuffer, + NULL, 0); + oldDst = SelectObject(hdcDst, bmpDst); + + hBrush = CreateSolidBrush(0x012345678); + hOldBrush = SelectObject(hdcDst, hBrush); + + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, SRCCOPY, 0xFEDCBA98, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, SRCPAINT, 0xFFFFFFFF, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, SRCAND, 0x88888888, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, SRCINVERT, 0x77777777, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, SRCERASE, 0x76543210, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, NOTSRCCOPY, 0x01234567, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, NOTSRCERASE, 0x00000000, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, MERGECOPY, 0x00581210, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, MERGEPAINT, 0x89ABCDEF, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, PATCOPY, 0x00785634, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, PATPAINT, 0x89FBDFFF, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, PATINVERT, 0x89D39BDB, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, DSTINVERT, 0x76543210, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, BLACKNESS, 0x00000000, __LINE__); + check_StretchDIBits_pixel(hdcDst, dstBuffer, srcBuffer, WHITENESS, 0xFFFFFFFF, __LINE__); + + SelectObject(hdcDst, hOldBrush); + DeleteObject(hBrush); + + /* Top-down destination tests */ + srcBuffer[0] = 0xCAFED00D, srcBuffer[1] = 0xFEEDFACE; + srcBuffer[2] = 0xFEDCBA98, srcBuffer[3] = 0x76543210; + + expected[0] = 0xCAFED00D, expected[1] = 0xFEEDFACE; + expected[2] = 0xFEDCBA98, expected[3] = 0x76543210; + check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 0, 0, 2, 2, 0, 0, 2, 2, expected, expected, __LINE__); + + expected[0] = 0xCAFED00D, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0x00000000; + legacy_expected[0] = 0xFEDCBA98, legacy_expected[1] = 0x00000000; + legacy_expected[2] = 0x00000000, legacy_expected[3] = 0x00000000; + todo_wine check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 0, 0, 1, 1, 0, 0, 1, 1, expected, legacy_expected, __LINE__); + + expected[0] = 0xFEDCBA98, expected[1] = 0xFEDCBA98; + expected[2] = 0xFEDCBA98, expected[3] = 0xFEDCBA98; + check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 0, 0, 2, 2, 0, 0, 1, 1, expected, expected, __LINE__); + + expected[0] = 0x42441000, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0x00000000; + legacy_expected[0] = 0x00543210, legacy_expected[1] = 0x00000000; + legacy_expected[2] = 0x00000000, legacy_expected[3] = 0x00000000; + todo_wine check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 0, 0, 1, 1, 0, 0, 2, 2, expected, legacy_expected, __LINE__); + + expected[0] = 0x00000000, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0x00000000; + check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 0, 0, 2, 2, 1, 1, -2, -2, expected, expected, __LINE__); + + expected[0] = 0x00000000, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0x00000000; + check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 0, 0, 2, 2, 1, 1, -2, -2, expected, expected, __LINE__); + + expected[0] = 0x00000000, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0x00000000; + check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 1, 1, -2, -2, 1, 1, -2, -2, expected, expected, __LINE__); + + expected[0] = 0x00000000, expected[1] = 0x00000000; + expected[2] = 0x00000000, expected[3] = 0xCAFED00D; + check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 1, 1, 2, 2, 0, 0, 2, 2, expected, expected, __LINE__); + + SelectObject(hdcDst, oldDst); + DeleteObject(bmpDst); + + /* Bottom up destination tests */ + biDst.bmiHeader.biHeight = 2; + bmpDst = CreateDIBSection(hdcScreen, &biDst, DIB_RGB_COLORS, (void**)&dstBuffer, + NULL, 0); + oldDst = SelectObject(hdcDst, bmpDst); + + expected[0] = 0xFEDCBA98, expected[1] = 0x76543210; + expected[2] = 0xCAFED00D, expected[3] = 0xFEEDFACE; + check_StretchDIBits_stretch(hdcDst, dstBuffer, srcBuffer, + 0, 0, 2, 2, 0, 0, 2, 2, expected, expected, __LINE__); + + /* Tidy up */ + SelectObject(hdcDst, oldDst); + DeleteObject(bmpDst); + DeleteDC(hdcDst); + + DeleteDC(hdcScreen); +} + +static void test_GdiAlphaBlend(void) { /* test out-of-bound parameters for GdiAlphaBlend */ HDC hdcNull; @@ -2065,7 +2734,7 @@ void test_GdiAlphaBlend() if (!pGdiAlphaBlend) { - skip("GdiAlphaBlend() is not implemented\n"); + win_skip("GdiAlphaBlend() is not implemented\n"); return; } @@ -2084,8 +2753,8 @@ void test_GdiAlphaBlend() bmpSrc = CreateDIBSection(hdcDst, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); ok(bmpSrc != NULL, "Couldn't create source bitmap\n"); - oldDst = (HBITMAP)SelectObject(hdcDst, bmpDst); - oldSrc = (HBITMAP)SelectObject(hdcSrc, bmpSrc); + oldDst = SelectObject(hdcDst, bmpDst); + oldSrc = SelectObject(hdcSrc, bmpSrc); blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; @@ -2109,6 +2778,10 @@ void test_GdiAlphaBlend() expect_eq(pGdiAlphaBlend(hdcDst, 0, 0, 20, 20, hdcSrc, -1, 0, 30, 30, blend), TRUE, BOOL, "%d"); expect_eq(pGdiAlphaBlend(hdcDst, 0, 0, 20, 20, hdcSrc, 0, -1, 30, 30, blend), TRUE, BOOL, "%d"); + SetLastError(0xdeadbeef); + expect_eq(pGdiAlphaBlend(hdcDst, 0, 0, 20, 20, NULL, 0, 0, 20, 20, blend), FALSE, BOOL, "%d"); + expect_eq(GetLastError(), 0xdeadbeef, int, "%d"); + SelectObject(hdcDst, oldDst); SelectObject(hdcSrc, oldSrc); DeleteObject(bmpSrc); @@ -2120,6 +2793,51 @@ void test_GdiAlphaBlend() } +static void test_clipping(void) +{ + HBITMAP bmpDst; + HBITMAP oldDst; + HBITMAP bmpSrc; + HBITMAP oldSrc; + HRGN hRgn; + LPVOID bits; + BOOL result; + + HDC hdcDst = CreateCompatibleDC( NULL ); + HDC hdcSrc = CreateCompatibleDC( NULL ); + + BITMAPINFO bmpinfo={{0}}; + bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmpinfo.bmiHeader.biWidth = 100; + bmpinfo.bmiHeader.biHeight = 100; + bmpinfo.bmiHeader.biPlanes = 1; + bmpinfo.bmiHeader.biBitCount = GetDeviceCaps( hdcDst, BITSPIXEL ); + bmpinfo.bmiHeader.biCompression = BI_RGB; + + bmpDst = CreateDIBSection( hdcDst, &bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 ); + ok(bmpDst != NULL, "Couldn't create destination bitmap\n"); + oldDst = SelectObject( hdcDst, bmpDst ); + + bmpSrc = CreateDIBSection( hdcSrc, &bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 ); + ok(bmpSrc != NULL, "Couldn't create source bitmap\n"); + oldSrc = SelectObject( hdcSrc, bmpSrc ); + + result = BitBlt( hdcDst, 0, 0, 100, 100, hdcSrc, 100, 100, SRCCOPY ); + ok(result, "BitBlt failed\n"); + + hRgn = CreateRectRgn( 0,0,0,0 ); + SelectClipRgn( hdcDst, hRgn ); + + result = BitBlt( hdcDst, 0, 0, 100, 100, hdcSrc, 0, 0, SRCCOPY ); + ok(result, "BitBlt failed\n"); + + DeleteObject( bmpDst ); + DeleteObject( bmpSrc ); + DeleteObject( hRgn ); + DeleteDC( hdcDst ); + DeleteDC( hdcSrc ); +} + START_TEST(bitmap) { HMODULE hdll; @@ -2142,7 +2860,11 @@ START_TEST(bitmap) test_GetDIBits_BI_BITFIELDS(); test_select_object(); test_CreateBitmap(); + test_BitBlt(); + test_StretchBlt(); + test_StretchDIBits(); test_GdiAlphaBlend(); test_bitmapinfoheadersize(); test_get16dibits(); + test_clipping(); } diff --git a/rostests/winetests/gdi32/brush.c b/rostests/winetests/gdi32/brush.c index 3d96a3409fa..2197f7e3c18 100755 --- a/rostests/winetests/gdi32/brush.c +++ b/rostests/winetests/gdi32/brush.c @@ -51,8 +51,10 @@ static void test_solidbrush(void) solidBrush = CreateSolidBrush(stock[i].color); if(stock[i].stockobj != -1) { - stockBrush = (HBRUSH)GetStockObject(stock[i].stockobj); - ok(stockBrush!=solidBrush, "Stock %s brush equals solid %s brush\n", stock[i].name, stock[i].name); + stockBrush = GetStockObject(stock[i].stockobj); + ok(stockBrush!=solidBrush || + broken(stockBrush==solidBrush), /* win9x does return stock object */ + "Stock %s brush equals solid %s brush\n", stock[i].name, stock[i].name); } else stockBrush = NULL; @@ -70,7 +72,10 @@ static void test_solidbrush(void) } DeleteObject(solidBrush); - ok(GetObject(solidBrush, sizeof(br), &br)==0, "GetObject succeeded on a deleted %s brush\n", stock[i].name); + ret = GetObject(solidBrush, sizeof(br), &br); + ok(ret==0 || + broken(ret!=0), /* win9x */ + "GetObject succeeded on a deleted %s brush\n", stock[i].name); } } diff --git a/rostests/winetests/gdi32/clipping.c b/rostests/winetests/gdi32/clipping.c index 595a94e0b88..d0586821519 100644 --- a/rostests/winetests/gdi32/clipping.c +++ b/rostests/winetests/gdi32/clipping.c @@ -111,7 +111,9 @@ static void test_GetRandomRgn(void) GetRgnBox(hrgn, &ret_rc); if(GetVersion() & 0x80000000) OffsetRect(&window_rc, -window_rc.left, -window_rc.top); - ok(EqualRect(&window_rc, &ret_rc), "GetRandomRgn %d,%d - %d,%d\n", + ok(EqualRect(&window_rc, &ret_rc) || + broken(IsRectEmpty(&ret_rc)), /* win95 */ + "GetRandomRgn %d,%d - %d,%d\n", ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom); DeleteObject(hrgn); @@ -160,12 +162,16 @@ static void verify_region(HRGN hrgn, const RECT *rc) if (IsRectEmpty(rc)) { ok(rgn.data.rdh.nCount == 0, "expected 0, got %u\n", rgn.data.rdh.nCount); - ok(rgn.data.rdh.nRgnSize == 0, "expected 0, got %u\n", rgn.data.rdh.nRgnSize); + ok(rgn.data.rdh.nRgnSize == 0 || + broken(rgn.data.rdh.nRgnSize == 168), /* NT4 */ + "expected 0, got %u\n", rgn.data.rdh.nRgnSize); } else { ok(rgn.data.rdh.nCount == 1, "expected 1, got %u\n", rgn.data.rdh.nCount); - ok(rgn.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn.data.rdh.nRgnSize); + ok(rgn.data.rdh.nRgnSize == sizeof(RECT) || + broken(rgn.data.rdh.nRgnSize == 168), /* NT4 */ + "expected sizeof(RECT), got %u\n", rgn.data.rdh.nRgnSize); } ok(EqualRect(&rgn.data.rdh.rcBound, rc), "rects don't match\n"); } @@ -234,9 +240,14 @@ if (0) /* crashes under Win9x */ SetLastError(0xdeadbeef); hrgn = ExtCreateRegion(NULL, 1, &rgn.data); - ok(hrgn != 0, "ExtCreateRegion error %u\n", GetLastError()); + ok(hrgn != 0 || + broken(GetLastError() == 0xdeadbeef), /* NT4 */ + "ExtCreateRegion error %u\n", GetLastError()); + if(hrgn) + { verify_region(hrgn, &rc); DeleteObject(hrgn); + } xform.eM11 = 0.5; /* 50% width */ xform.eM12 = 0.0; diff --git a/rostests/winetests/gdi32/dc.c b/rostests/winetests/gdi32/dc.c index 9e0048e4fce..1efde38b134 100644 --- a/rostests/winetests/gdi32/dc.c +++ b/rostests/winetests/gdi32/dc.c @@ -185,7 +185,7 @@ static void test_GdiConvertToDevmodeW(void) pGdiConvertToDevmodeW = (void *)GetProcAddress(GetModuleHandleA("gdi32.dll"), "GdiConvertToDevmodeW"); if (!pGdiConvertToDevmodeW) { - skip("GdiConvertToDevmodeW is not available on this platform\n"); + win_skip("GdiConvertToDevmodeW is not available on this platform\n"); return; } @@ -253,10 +253,86 @@ static void test_CreateCompatibleDC(void) ok(hNewDC == NULL, "CreateCompatibleDC returned %p\n", hNewDC); } +static void test_DC_bitmap(void) +{ + HDC hdc, hdcmem; + DWORD bits[64]; + HBITMAP hbmp, oldhbmp; + COLORREF col; + int i, bitspixel; + + /* fill bitmap data with b&w pattern */ + for( i = 0; i < 64; i++) bits[i] = i & 1 ? 0 : 0xffffff; + + hdc = GetDC(0); + ok( hdc != NULL, "CreateDC rets %p\n", hdc); + bitspixel = GetDeviceCaps( hdc, BITSPIXEL); + /* create a memory dc */ + hdcmem = CreateCompatibleDC( hdc); + ok( hdcmem != NULL, "CreateCompatibleDC rets %p\n", hdcmem); + /* tests */ + /* test monochrome bitmap: should always work */ + hbmp = CreateBitmap(32, 32, 1, 1, bits); + ok( hbmp != NULL, "CreateBitmap returns %p\n", hbmp); + oldhbmp = SelectObject( hdcmem, hbmp); + ok( oldhbmp != NULL, "SelectObject returned NULL\n" ); /* a memdc always has a bitmap selected */ + col = GetPixel( hdcmem, 0, 0); + ok( col == 0xffffff, "GetPixel returned %08x, expected 00ffffff\n", col); + col = GetPixel( hdcmem, 1, 1); + ok( col == 0x000000, "GetPixel returned %08x, expected 00000000\n", col); + col = GetPixel( hdcmem, 100, 1); + ok( col == CLR_INVALID, "GetPixel returned %08x, expected ffffffff\n", col); + SelectObject( hdcmem, oldhbmp); + DeleteObject( hbmp); + + /* test with 2 bits color depth, not likely to succeed */ + hbmp = CreateBitmap(16, 16, 1, 2, bits); + ok( hbmp != NULL, "CreateBitmap returns %p\n", hbmp); + oldhbmp = SelectObject( hdcmem, hbmp); + if( bitspixel != 2) + ok( !oldhbmp, "SelectObject of a bitmap with 2 bits/pixel should return NULL\n"); + if( oldhbmp) SelectObject( hdcmem, oldhbmp); + DeleteObject( hbmp); + + /* test with 16 bits color depth, might succeed */ + hbmp = CreateBitmap(6, 6, 1, 16, bits); + ok( hbmp != NULL, "CreateBitmap returns %p\n", hbmp); + oldhbmp = SelectObject( hdcmem, hbmp); + if( bitspixel == 16) { + ok( oldhbmp != NULL, "SelectObject returned NULL\n" ); + col = GetPixel( hdcmem, 0, 0); + ok( col == 0xffffff, + "GetPixel of a bitmap with 16 bits/pixel returned %08x, expected 00ffffff\n", col); + col = GetPixel( hdcmem, 1, 1); + ok( col == 0x000000, + "GetPixel of a bitmap with 16 bits/pixel returned returned %08x, expected 00000000\n", col); + } + if( oldhbmp) SelectObject( hdcmem, oldhbmp); + DeleteObject( hbmp); + + /* test with 32 bits color depth, probably succeed */ + hbmp = CreateBitmap(4, 4, 1, 32, bits); + ok( hbmp != NULL, "CreateBitmap returns %p\n", hbmp); + oldhbmp = SelectObject( hdcmem, hbmp); + if( bitspixel == 32) { + ok( oldhbmp != NULL, "SelectObject returned NULL\n" ); + col = GetPixel( hdcmem, 0, 0); + ok( col == 0xffffff, + "GetPixel of a bitmap with 32 bits/pixel returned %08x, expected 00ffffff\n", col); + col = GetPixel( hdcmem, 1, 1); + ok( col == 0x000000, + "GetPixel of a bitmap with 32 bits/pixel returned returned %08x, expected 00000000\n", col); + } + if( oldhbmp) SelectObject( hdcmem, oldhbmp); + DeleteObject( hbmp); + ReleaseDC( 0, hdc ); +} + START_TEST(dc) { test_savedc(); test_savedc_2(); test_GdiConvertToDevmodeW(); test_CreateCompatibleDC(); + test_DC_bitmap(); } diff --git a/rostests/winetests/gdi32/font.c b/rostests/winetests/gdi32/font.c index c627521f0e8..0fb9c0ba448 100644 --- a/rostests/winetests/gdi32/font.c +++ b/rostests/winetests/gdi32/font.c @@ -30,6 +30,7 @@ #include "wine/test.h" +#define near_match(a, b) (abs((a) - (b)) <= 6) #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height); @@ -105,8 +106,31 @@ static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont) minlen++; minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1; ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret); - ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test); - ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName), + ok(lf->lfHeight == getobj_lf.lfHeight || + broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */ + "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight); + ok(lf->lfWidth == getobj_lf.lfWidth || + broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */ + "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth); + ok(lf->lfEscapement == getobj_lf.lfEscapement || + broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */ + "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement); + ok(lf->lfOrientation == getobj_lf.lfOrientation || + broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */ + "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation); + ok(lf->lfWeight == getobj_lf.lfWeight || + broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */ + "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight); + ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic); + ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline); + ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut); + ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet); + ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision); + ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision); + ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality); + ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily); + ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) || + broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */ "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName); } @@ -158,56 +182,119 @@ static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DW return 1; /* continue enumeration */ } +static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm) +{ + ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight); + ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent); + ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent); + ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading); + ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading); + ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth); + ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth); + ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight); + ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang); + ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX); + ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY); + ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar); + ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar); + ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar); + ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar); + ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic); + ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined); + ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut); + ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily); + ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet); +} + static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight, LONG lfWidth, const char *test_str, INT test_str_len, const TEXTMETRICA *tm_orig, const SIZE *size_orig, INT width_of_A_orig, INT scale_x, INT scale_y) { - HFONT old_hfont; LOGFONTA lf; + OUTLINETEXTMETRIC otm; TEXTMETRICA tm; SIZE size; INT width_of_A, cx, cy; + UINT ret; if (!hfont) return; + ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n"); + GetObjectA(hfont, sizeof(lf), &lf); - old_hfont = SelectObject(hdc, hfont); + if (GetOutlineTextMetricsA(hdc, 0, NULL)) + { + otm.otmSize = sizeof(otm) / 2; + ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm); + ok(ret == sizeof(otm)/2 /* XP */ || + ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret); - GetTextMetricsA(hdc, &tm); + memset(&otm, 0x1, sizeof(otm)); + otm.otmSize = sizeof(otm); + ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm); + ok(ret == sizeof(otm) /* XP */ || + ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret); + + memset(&tm, 0x2, sizeof(tm)); + ret = GetTextMetricsA(hdc, &tm); + ok(ret, "GetTextMetricsA failed\n"); + /* the structure size is aligned */ + if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1)) + { + ok(0, "tm != otm\n"); + compare_tm(&tm, &otm.otmTextMetrics); + } + + tm = otm.otmTextMetrics; +if (0) /* these metrics are scaled too, but with rounding errors */ +{ + ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent); + ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent); +} + ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent); + ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n"); + ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n"); + ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n"); + ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent); + ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare); + } + else + { + ret = GetTextMetricsA(hdc, &tm); + ok(ret, "GetTextMetricsA failed\n"); + } cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth; cy = tm.tmHeight / tm_orig->tmHeight; - ok(cx == scale_x && cy == scale_y, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n", - scale_x, scale_y, cx, cy); - ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y); - ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y); - ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y); - ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x); - ok(tm.tmMaxCharWidth == tm_orig->tmMaxCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmMaxCharWidth * scale_x); + ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n", + lfHeight, scale_x, scale_y, cx, cy); + ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y); + ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y); + ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y); + ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x); + ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x); - ok(lf.lfHeight == lfHeight, "lf %d != %d\n", lf.lfHeight, lfHeight); + ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight); if (lf.lfHeight) { if (lf.lfWidth) - ok(lf.lfWidth == tm.tmAveCharWidth, "lf %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth); + ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth); } else - ok(lf.lfWidth == lfWidth, "lf %d != %d\n", lf.lfWidth, lfWidth); + ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth); GetTextExtentPoint32A(hdc, test_str, test_str_len, &size); - ok(size.cx == size_orig->cx * scale_x, "%d != %d\n", size.cx, size_orig->cx * scale_x); - ok(size.cy == size_orig->cy * scale_y, "%d != %d\n", size.cy, size_orig->cy * scale_y); + ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x); + ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y); GetCharWidthA(hdc, 'A', 'A', &width_of_A); - ok(width_of_A == width_of_A_orig * scale_x, "%d != %d\n", width_of_A, width_of_A_orig * scale_x); - - SelectObject(hdc, old_hfont); + ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x); } /* Test how GDI scales bitmap font metrics */ @@ -221,6 +308,9 @@ static void test_bitmap_font(void) SIZE size_orig; INT ret, i, width_orig, height_orig, scale, lfWidth; + skip("ROS-HACK: Skipping bitmap font tests!\n"); + return; + hdc = GetDC(0); /* "System" has only 1 pixel size defined, otherwise the test breaks */ @@ -248,14 +338,16 @@ static void test_bitmap_font(void) bitmap_lf.lfHeight = 0; bitmap_lf.lfWidth = 4; hfont = create_font("bitmap", &bitmap_lf); + old_hfont = SelectObject(hdc, hfont); test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1); + SelectObject(hdc, old_hfont); DeleteObject(hfont); bitmap_lf.lfHeight = height_orig; bitmap_lf.lfWidth = lfWidth; /* test fractional scaling */ - for (i = 1; i <= height_orig * 3; i++) + for (i = 1; i <= height_orig * 6; i++) { INT nearest_height; @@ -263,9 +355,15 @@ static void test_bitmap_font(void) hfont = create_font("fractional", &bitmap_lf); scale = (i + height_orig - 1) / height_orig; nearest_height = scale * height_orig; - /* XP allows not more than 10% deviation */ - if (scale > 1 && nearest_height - i > nearest_height / 10) scale--; + /* Only jump to the next height if the difference <= 25% original height */ + if (scale > 2 && nearest_height - i > height_orig / 4) scale--; + /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x, + so we'll not test this particular height. */ + else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue; + else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--; + old_hfont = SelectObject(hdc, hfont); test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale); + SelectObject(hdc, old_hfont); DeleteObject(hfont); } @@ -273,19 +371,275 @@ static void test_bitmap_font(void) bitmap_lf.lfHeight = height_orig * 2; bitmap_lf.lfWidth *= 3; hfont = create_font("3x2", &bitmap_lf); + old_hfont = SelectObject(hdc, hfont); test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2); + SelectObject(hdc, old_hfont); DeleteObject(hfont); /* test integer scaling 3x3 */ bitmap_lf.lfHeight = height_orig * 3; bitmap_lf.lfWidth = 0; hfont = create_font("3x3", &bitmap_lf); + old_hfont = SelectObject(hdc, hfont); test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3); + SelectObject(hdc, old_hfont); DeleteObject(hfont); ReleaseDC(0, hdc); } +/* Test how GDI scales outline font metrics */ +static void test_outline_font(void) +{ + static const char test_str[11] = "Test String"; + HDC hdc, hdc_2; + LOGFONTA lf; + HFONT hfont, old_hfont, old_hfont_2; + OUTLINETEXTMETRICA otm; + SIZE size_orig; + INT width_orig, height_orig, lfWidth; + XFORM xform; + GLYPHMETRICS gm; + MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; + MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} }; + POINT pt; + INT ret; + + if (!is_truetype_font_installed("Arial")) + { + skip("Arial is not installed\n"); + return; + } + + hdc = CreateCompatibleDC(0); + + memset(&lf, 0, sizeof(lf)); + strcpy(lf.lfFaceName, "Arial"); + lf.lfHeight = 72; + hfont = create_font("outline", &lf); + old_hfont = SelectObject(hdc, hfont); + otm.otmSize = sizeof(otm); + ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n"); + ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n"); + ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n"); + + test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + + /* font of otmEMSquare height helps to avoid a lot of rounding errors */ + lf.lfHeight = otm.otmEMSquare; + lf.lfHeight = -lf.lfHeight; + hfont = create_font("outline", &lf); + old_hfont = SelectObject(hdc, hfont); + otm.otmSize = sizeof(otm); + ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n"); + ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n"); + ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n"); + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + + height_orig = otm.otmTextMetrics.tmHeight; + lfWidth = otm.otmTextMetrics.tmAveCharWidth; + + /* test integer scaling 3x2 */ + lf.lfHeight = height_orig * 2; + lf.lfWidth = lfWidth * 3; + hfont = create_font("3x2", &lf); + old_hfont = SelectObject(hdc, hfont); + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2); + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + + /* test integer scaling 3x3 */ + lf.lfHeight = height_orig * 3; + lf.lfWidth = lfWidth * 3; + hfont = create_font("3x3", &lf); + old_hfont = SelectObject(hdc, hfont); + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3); + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + + /* test integer scaling 1x1 */ + lf.lfHeight = height_orig * 1; + lf.lfWidth = lfWidth * 1; + hfont = create_font("1x1", &lf); + old_hfont = SelectObject(hdc, hfont); + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + + /* test integer scaling 1x1 */ + lf.lfHeight = height_orig; + lf.lfWidth = 0; + hfont = create_font("1x1", &lf); + old_hfont = SelectObject(hdc, hfont); + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + /* with an identity matrix */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); + trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); + ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig); + ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); + /* with a custom matrix */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); + trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); + ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2); + ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); + + /* Test that changing the DC transformation affects only the font + * selected on this DC and doesn't affect the same font selected on + * another DC. + */ + hdc_2 = CreateCompatibleDC(0); + old_hfont_2 = SelectObject(hdc_2, hfont); + test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + SetMapMode(hdc, MM_ANISOTROPIC); + + /* font metrics on another DC should be unchanged */ + test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + /* test restrictions of compatibility mode GM_COMPATIBLE */ + /* part 1: rescaling only X should not change font scaling on screen. + So compressing the X axis by 2 is not done, and this + appears as X scaling of 2 that no one requested. */ + SetWindowExtEx(hdc, 100, 100, NULL); + SetViewportExtEx(hdc, 50, 100, NULL); + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1); + /* font metrics on another DC should be unchanged */ + test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + /* part 2: rescaling only Y should change font scaling. + As also X is scaled by a factor of 2, but this is not + requested by the DC transformation, we get a scaling factor + of 2 in the X coordinate. */ + SetViewportExtEx(hdc, 100, 200, NULL); + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1); + /* font metrics on another DC should be unchanged */ + test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + /* restore scaling */ + SetMapMode(hdc, MM_TEXT); + + /* font metrics on another DC should be unchanged */ + test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + SelectObject(hdc_2, old_hfont_2); + DeleteDC(hdc_2); + + if (!SetGraphicsMode(hdc, GM_ADVANCED)) + { + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + DeleteDC(hdc); + skip("GM_ADVANCED is not supported on this platform\n"); + return; + } + + xform.eM11 = 20.0f; + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = 20.0f; + xform.eDx = 0.0f; + xform.eDy = 0.0f; + + SetLastError(0xdeadbeef); + ret = SetWorldTransform(hdc, &xform); + ok(ret, "SetWorldTransform error %u\n", GetLastError()); + + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + /* with an identity matrix */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); + trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); + pt.x = width_orig; pt.y = 0; + LPtoDP(hdc, &pt, 1); + ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x); + ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig); + ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); + /* with a custom matrix */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); + trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); + pt.x = width_orig; pt.y = 0; + LPtoDP(hdc, &pt, 1); + ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2); + ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig); + ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); + + SetLastError(0xdeadbeef); + ret = SetMapMode(hdc, MM_LOMETRIC); + ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError()); + + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + /* with an identity matrix */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); + trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); + pt.x = width_orig; pt.y = 0; + LPtoDP(hdc, &pt, 1); + ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x); + ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); + /* with a custom matrix */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); + trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); + pt.x = width_orig; pt.y = 0; + LPtoDP(hdc, &pt, 1); + ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2); + ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); + + SetLastError(0xdeadbeef); + ret = SetMapMode(hdc, MM_TEXT); + ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError()); + + test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1); + + /* with an identity matrix */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); + trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); + pt.x = width_orig; pt.y = 0; + LPtoDP(hdc, &pt, 1); + ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x); + ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig); + ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); + /* with a custom matrix */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError()); + trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig); + pt.x = width_orig; pt.y = 0; + LPtoDP(hdc, &pt, 1); + ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2); + ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig); + ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY); + + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + DeleteDC(hdc); +} + static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam) { LOGFONT *lf = (LOGFONT *)lParam; @@ -304,68 +658,117 @@ static void test_bitmap_font_metrics(void) { const char face_name[LF_FACESIZE]; int weight, height, ascent, descent, int_leading, ext_leading; - int ave_char_width, max_char_width; + int ave_char_width, max_char_width, dpi; DWORD ansi_bitfield; } fd[] = { - { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, - { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, - { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC }, - { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 }, - { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 }, - { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 }, - { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC }, - { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 }, - { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 }, - { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC }, - { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, - { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 }, - { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC }, - { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, - { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 }, - { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC }, - { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 }, - { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC }, - { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 }, - { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC }, - { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 }, - { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 }, - { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC }, - { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 }, - { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 }, - { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC }, - { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 }, - { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC }, - { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, - { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, - { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, - { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 }, - { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 }, + { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 }, + { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 }, + { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 }, + { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 }, + { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + + { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 }, + { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 }, + { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + + { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 }, + { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 }, + { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 }, + { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC }, + + { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 }, + { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 }, + { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 }, + { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC }, + { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + + { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + + { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + + { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 }, + { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC }, /* * TODO: the system for CP932 should be NORMAL, not BOLD. However that would * require a new system.sfd for that font */ - { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN }, - { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 }, - { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC }, - { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN }, - { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 }, - { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC }, - { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN }, - { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 }, - { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC }, - { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN }, - { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 }, - { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC }, - { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN }, - { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 }, - { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC }, - { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN }, - { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, - { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN }, - { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 }, - { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC }, - { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN } + { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN }, + + { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 }, + { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC }, + + { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 }, + { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 }, + { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 }, + { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 }, + { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 }, + { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN }, + + { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC }, + { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN }, + { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC }, + + { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 }, + { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC }, + { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN }, + + /* The 120dpi version still has its dpi marked as 96 */ + { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC } /* FIXME: add "Terminal" */ }; @@ -401,12 +804,12 @@ static void test_bitmap_font_metrics(void) ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0); if (ret) continue; - trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet); - hfont = create_font(lf.lfFaceName, &lf); old_hfont = SelectObject(hdc, hfont); ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError()); - + if(fd[i].dpi == tm.tmDigitizedAspectX) + { + trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi); ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight); ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height); ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent); @@ -419,7 +822,7 @@ static void test_bitmap_font_metrics(void) that make the max width bigger */ if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET) ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width); - + } SelectObject(hdc, old_hfont); DeleteObject(hfont); } @@ -439,7 +842,7 @@ static void test_GdiGetCharDimensions(void) if (!pGdiGetCharDimensions) { - skip("GdiGetCharDimensions not available on this platform\n"); + win_skip("GdiGetCharDimensions not available on this platform\n"); return; } @@ -479,7 +882,7 @@ static void test_GetCharABCWidths(void) if (!pGetCharABCWidthsW || !pGetCharABCWidthsI) { - skip("GetCharABCWidthsW/I not available on this platform\n"); + win_skip("GetCharABCWidthsW/I not available on this platform\n"); return; } @@ -544,7 +947,7 @@ static void test_text_extents(void) GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("Skipping remainder of text extents test on a Win9x platform\n"); + win_skip("Skipping remainder of text extents test on a Win9x platform\n"); hfont = SelectObject(hdc, hfont); DeleteObject(hfont); ReleaseDC(0, hdc); @@ -602,7 +1005,7 @@ static void test_GetGlyphIndices(void) HFONT hOldFont; if (!pGetGlyphIndicesW) { - skip("GetGlyphIndicesW not available on platform\n"); + win_skip("GetGlyphIndicesW not available on platform\n"); return; } @@ -639,7 +1042,7 @@ static void test_GetGlyphIndices(void) testtext[0] = textm.tmDefaultChar; charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags); ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount); - todo_wine ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]); + ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]); ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]); DeleteObject(SelectObject(hdc, hOldFont)); } @@ -737,7 +1140,7 @@ static void test_GetKerningPairs(void) GetKerningPairsW(hdc, 0, NULL); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("Skipping the GetKerningPairs test on a Win9x platform\n"); + win_skip("Skipping the GetKerningPairs test on a Win9x platform\n"); ReleaseDC(0, hdc); return; } @@ -781,6 +1184,8 @@ static void test_GetKerningPairs(void) kd[i].otmDescent, otm.otmDescent); ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n", kd[i].otmLineGap, otm.otmLineGap); + ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n", + kd[i].otmMacDescent, otm.otmMacDescent); todo_wine { ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n", kd[i].otmsCapEmHeight, otm.otmsCapEmHeight); @@ -788,8 +1193,6 @@ todo_wine { kd[i].otmsXHeight, otm.otmsXHeight); ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n", kd[i].otmMacAscent, otm.otmMacAscent); - ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n", - kd[i].otmMacDescent, otm.otmMacDescent); /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */ if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n", kd[i].otmMacLineGap, otm.otmMacLineGap); @@ -861,6 +1264,7 @@ static void test_GetOutlineTextMetrics(void) HFONT hfont, hfont_old; HDC hdc; DWORD ret, otm_size; + LPSTR unset_ptr; if (!is_font_installed("Arial")) { @@ -917,6 +1321,7 @@ static void test_GetOutlineTextMetrics(void) /* ask about truncated data */ memset(otm, 0xAA, otm_size); + memset(&unset_ptr, 0xAA, sizeof(unset_ptr)); SetLastError(0xdeadbeef); otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */ ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm); @@ -929,7 +1334,7 @@ static void test_GetOutlineTextMetrics(void) ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName); ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName); } - ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName); + ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName); HeapFree(GetProcessHeap(), 0, otm); @@ -943,7 +1348,6 @@ static void testJustification(HDC hdc, PSTR str, RECT *clientArea) { INT x, y, breakCount, - outputWidth = 0, /* to test TabbedTextOut() */ justifiedWidth = 0, /* to test GetTextExtentExPointW() */ areaWidth = clientArea->right - clientArea->left, nErrors = 0, e; @@ -955,7 +1359,6 @@ static void testJustification(HDC hdc, PSTR str, RECT *clientArea) { char extent[100]; int GetTextExtentExPointWWidth; - int TabbedTextOutWidth; } error[10]; GetTextMetricsA(hdc, &tm); @@ -1001,15 +1404,11 @@ static void testJustification(HDC hdc, PSTR str, RECT *clientArea) x = clientArea->left; - outputWidth = LOWORD(TabbedTextOut( - hdc, x, y, pFirstChar, pLastChar - pFirstChar, - 0, NULL, 0)); /* catch errors and report them */ - if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth))) + if (!lastExtent && (justifiedWidth != areaWidth)) { memset(error[nErrors].extent, 0, 100); memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar); - error[nErrors].TabbedTextOutWidth = outputWidth; error[nErrors].GetTextExtentExPointWWidth = justifiedWidth; nErrors++; } @@ -1020,9 +1419,6 @@ static void testJustification(HDC hdc, PSTR str, RECT *clientArea) for (e = 0; e < nErrors; e++) { - ok(error[e].TabbedTextOutWidth == areaWidth, - "The output text (\"%s\") width should be %d, not %d.\n", - error[e].extent, areaWidth, error[e].TabbedTextOutWidth); /* The width returned by GetTextExtentPoint32() is exactly the same returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */ ok(error[e].GetTextExtentExPointWWidth == areaWidth, @@ -1097,8 +1493,8 @@ static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count ok(cs == charset, "expected %d, got %d\n", charset, cs); SetLastError(0xdeadbeef); - ret = GetTextFace(hdc, sizeof(name), name); - ok(ret, "GetTextFace error %u\n", GetLastError()); + ret = GetTextFaceA(hdc, sizeof(name), name); + ok(ret, "GetTextFaceA error %u\n", GetLastError()); if (charset == SYMBOL_CHARSET) { @@ -1111,7 +1507,7 @@ static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n"); } - if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET)) + if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET)) { trace("Can't find codepage for charset %d\n", cs); ReleaseDC(0, hdc); @@ -1168,7 +1564,7 @@ static void test_font_charset(void) if (!pGetGlyphIndicesA || !pGetGlyphIndicesW) { - skip("Skipping the font charset test on a Win9x platform\n"); + win_skip("Skipping the font charset test on a Win9x platform\n"); return; } @@ -1213,7 +1609,7 @@ static void test_GetFontUnicodeRanges(void) if (!pGetFontUnicodeRanges) { - skip("GetFontUnicodeRanges not available before W2K\n"); + win_skip("GetFontUnicodeRanges not available before W2K\n"); return; } @@ -1247,7 +1643,7 @@ static void test_GetFontUnicodeRanges(void) ReleaseDC(NULL, hdc); } -#define MAX_ENUM_FONTS 256 +#define MAX_ENUM_FONTS 4096 struct enum_font_data { @@ -1255,17 +1651,46 @@ struct enum_font_data LOGFONT lf[MAX_ENUM_FONTS]; }; +struct enum_font_dataW +{ + int total; + LOGFONTW lf[MAX_ENUM_FONTS]; +}; + static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam) { struct enum_font_data *efd = (struct enum_font_data *)lParam; + ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight); + if (type != TRUETYPE_FONTTYPE) return 1; #if 0 - trace("enumed font \"%s\", charset %d, weight %d, italic %d\n", - lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic); + trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n", + lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic); #endif if (efd->total < MAX_ENUM_FONTS) efd->lf[efd->total++] = *lf; + else + trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS); + + return 1; +} + +static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam) +{ + struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam; + + ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight); + + if (type != TRUETYPE_FONTTYPE) return 1; +#if 0 + trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n", + lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic); +#endif + if (efd->total < MAX_ENUM_FONTS) + efd->lf[efd->total++] = *lf; + else + trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS); return 1; } @@ -1297,9 +1722,37 @@ static void get_charset_stats(struct enum_font_data *efd, } } +static void get_charset_statsW(struct enum_font_dataW *efd, + int *ansi_charset, int *symbol_charset, + int *russian_charset) +{ + int i; + + *ansi_charset = 0; + *symbol_charset = 0; + *russian_charset = 0; + + for (i = 0; i < efd->total; i++) + { + switch (efd->lf[i].lfCharSet) + { + case ANSI_CHARSET: + (*ansi_charset)++; + break; + case SYMBOL_CHARSET: + (*symbol_charset)++; + break; + case RUSSIAN_CHARSET: + (*russian_charset)++; + break; + } + } +} + static void test_EnumFontFamilies(const char *font_name, INT font_charset) { struct enum_font_data efd; + struct enum_font_dataW efdw; LOGFONT lf; HDC hdc; int i, ret, ansi_charset, symbol_charset, russian_charset; @@ -1319,30 +1772,42 @@ static void test_EnumFontFamilies(const char *font_name, INT font_charset) */ if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */ { - efd.total = 0; + /* + * Use EnumFontFamiliesW since win98 crashes when the + * second parameter is NULL using EnumFontFamilies + */ + efdw.total = 0; SetLastError(0xdeadbeef); - ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd); - ok(ret, "EnumFontFamilies error %u\n", GetLastError()); - get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset); + ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw); + ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError()); + if(ret) + { + get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset); trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n", ansi_charset, symbol_charset, russian_charset); - ok(efd.total > 0, "no fonts enumerated: NULL\n"); + ok(efdw.total > 0, "fonts enumerated: NULL\n"); ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n"); ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n"); - ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n"); + ok(russian_charset > 0 || + broken(russian_charset == 0), /* NT4 */ + "NULL family should enumerate RUSSIAN_CHARSET\n"); + } - efd.total = 0; + efdw.total = 0; SetLastError(0xdeadbeef); - ret = EnumFontFamiliesEx(hdc, NULL, arial_enum_proc, (LPARAM)&efd, 0); - ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError()); - get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset); + ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0); + ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError()); + if(ret) + { + get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset); trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n", ansi_charset, symbol_charset, russian_charset); - ok(efd.total > 0, "no fonts enumerated: NULL\n"); + ok(efdw.total > 0, "fonts enumerated: NULL\n"); ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n"); ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n"); ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n"); } + } efd.total = 0; SetLastError(0xdeadbeef); @@ -1503,6 +1968,9 @@ static void test_negative_width(HDC hdc, const LOGFONTA *lf) WORD idx; MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; + if(!pGetGlyphIndicesA) + return; + /* negative widths are handled just as positive ones */ lf2.lfWidth = -lf->lfWidth; @@ -1611,29 +2079,230 @@ typedef struct #ifdef WORDS_BIGENDIAN #define GET_BE_WORD(x) (x) +#define GET_BE_DWORD(x) (x) #else #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) +#define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x))); #endif #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \ ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24)) #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2') +#define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p') + +typedef struct +{ + USHORT version; + USHORT num_tables; +} cmap_header; + +typedef struct +{ + USHORT plat_id; + USHORT enc_id; + ULONG offset; +} cmap_encoding_record; + +typedef struct +{ + USHORT format; + USHORT length; + USHORT language; + + BYTE glyph_ids[256]; +} cmap_format_0; + +typedef struct +{ + USHORT format; + USHORT length; + USHORT language; + + USHORT seg_countx2; + USHORT search_range; + USHORT entry_selector; + USHORT range_shift; + + USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */ +/* Then follows: + USHORT pad; + USHORT start_count[seg_countx2 / 2]; + USHORT id_delta[seg_countx2 / 2]; + USHORT id_range_offset[seg_countx2 / 2]; + USHORT glyph_ids[]; +*/ +} cmap_format_4; + +typedef struct +{ + USHORT end_count; + USHORT start_count; + USHORT id_delta; + USHORT id_range_offset; +} cmap_format_4_seg; + +static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name) +{ + ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n", + name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle, + os2->panose.bWeight, os2->panose.bProportion); +} + +static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last) +{ + int i; + cmap_format_0 *cmap = (cmap_format_0*)ptr; + + *first = 256; + + for(i = 0; i < 256; i++) + { + if(cmap->glyph_ids[i] == 0) continue; + *last = i; + if(*first == 256) *first = i; + } + if(*first == 256) return FALSE; + return TRUE; +} + +static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg) +{ + USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2; + seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]); + seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]); + seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]); + seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]); +} + +static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit) +{ + int i; + cmap_format_4 *cmap = (cmap_format_4*)ptr; + USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2; + USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1; + + *first = 0x10000; + + for(i = 0; i < seg_count; i++) + { + DWORD code, index; + cmap_format_4_seg seg; + + get_seg4(cmap, i, &seg); + for(code = seg.start_count; code <= seg.end_count; code++) + { + if(seg.id_range_offset == 0) + index = (seg.id_delta + code) & 0xffff; + else + { + index = seg.id_range_offset / 2 + + code - seg.start_count + + i - seg_count; + + /* some fonts have broken last segment */ + if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit) + index = GET_BE_WORD(glyph_ids[index]); + else + { + trace("segment %04x/%04x index %04x points to nowhere\n", + seg.start_count, seg.end_count, index); + index = 0; + } + if(index) index += seg.id_delta; + } + if(*first == 0x10000) + *last = *first = code; + else if(index) + *last = code; + } + } + + if(*first == 0x10000) return FALSE; + return TRUE; +} + +static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id) +{ + USHORT i; + cmap_encoding_record *record = (cmap_encoding_record *)(header + 1); + + for(i = 0; i < GET_BE_WORD(header->num_tables); i++) + { + if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id) + return (BYTE *)header + GET_BE_DWORD(record->offset); + record++; + } + return NULL; +} + +typedef enum +{ + cmap_none, + cmap_ms_unicode, + cmap_ms_symbol +} cmap_type; + +static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type) +{ + LONG size, ret; + cmap_header *header; + void *cmap; + BOOL r = FALSE; + WORD format; + + size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0); + ok(size != GDI_ERROR, "no cmap table found\n"); + if(size == GDI_ERROR) return FALSE; + + header = HeapAlloc(GetProcessHeap(), 0, size); + ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size); + ok(ret == size, "GetFontData should return %u not %u\n", size, ret); + ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version)); + + cmap = get_cmap(header, 3, 1); + if(cmap) + *cmap_type = cmap_ms_unicode; + else + { + cmap = get_cmap(header, 3, 0); + if(cmap) *cmap_type = cmap_ms_symbol; + } + if(!cmap) + { + *cmap_type = cmap_none; + goto end; + } + + format = GET_BE_WORD(*(WORD *)cmap); + switch(format) + { + case 0: + r = get_first_last_from_cmap0(cmap, first, last); + break; + case 4: + r = get_first_last_from_cmap4(cmap, first, last, size); + break; + default: + trace("unhandled cmap format %d\n", format); + break; + } + +end: + HeapFree(GetProcessHeap(), 0, header); + return r; +} static void test_text_metrics(const LOGFONTA *lf) { HDC hdc; HFONT hfont, hfont_old; TEXTMETRICA tmA; - TEXTMETRICW tmW; - UINT first_unicode_char, last_unicode_char, default_char, break_char; - INT test_char; TT_OS2_V2 tt_os2; - USHORT version; LONG size, ret; const char *font_name = lf->lfFaceName; - - trace("Testing font metrics for %s, charset %d\n", font_name, lf->lfCharSet); + DWORD cmap_first = 0, cmap_last = 0; + cmap_type cmap_type; hdc = GetDC(0); @@ -1659,40 +2328,83 @@ static void test_text_metrics(const LOGFONTA *lf) ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size); ok(ret == size, "GetFontData should return %u not %u\n", size, ret); - version = GET_BE_WORD(tt_os2.version); - trace("OS/2 chunk version %u, vendor %4.4s\n", version, (LPCSTR)&tt_os2.achVendID); - - first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex); - last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex); - default_char = GET_BE_WORD(tt_os2.usDefaultChar); - break_char = GET_BE_WORD(tt_os2.usBreakChar); - - trace("for %s first %x, last %x, default %x, break %x\n", font_name, - first_unicode_char, last_unicode_char, default_char, break_char); - SetLastError(0xdeadbeef); ret = GetTextMetricsA(hdc, &tmA); ok(ret, "GetTextMetricsA error %u\n", GetLastError()); - trace("A: first %x, last %x, default %x, break %x\n", - tmA.tmFirstChar, tmA.tmLastChar, tmA.tmDefaultChar, tmA.tmBreakChar); -#if 0 /* FIXME: This doesn't appear to be what Windows does */ - test_char = min(first_unicode_char - 1, 255); - ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n", - font_name, tmA.tmFirstChar, test_char); -#endif - if (lf->lfCharSet == SYMBOL_CHARSET) + if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type)) { - test_char = min(last_unicode_char - 0xf000, 255); - ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n", - font_name, tmA.tmLastChar, test_char); + skip("Unable to retrieve first and last glyphs from cmap\n"); } else { - test_char = min(last_unicode_char, 255); - ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n", - font_name, tmA.tmLastChar, test_char); + USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A; + USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W; + UINT os2_first_char, os2_last_char, default_char, break_char; + USHORT version; + TEXTMETRICW tmW; + + version = GET_BE_WORD(tt_os2.version); + + os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex); + os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex); + default_char = GET_BE_WORD(tt_os2.usDefaultChar); + break_char = GET_BE_WORD(tt_os2.usBreakChar); + + trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n", + font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last, + default_char, break_char, version, (LPCSTR)&tt_os2.achVendID); + + if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100)) + { + expect_first_W = 0; + switch(GetACP()) + { + case 1257: /* Baltic */ + expect_last_W = 0xf8fd; + break; + default: + expect_last_W = 0xf0ff; } + expect_break_W = 0x20; + expect_default_W = expect_break_W - 1; + expect_first_A = 0x1e; + expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff); + } + else + { + expect_first_W = cmap_first; + expect_last_W = min(cmap_last, os2_last_char); + if(os2_first_char <= 1) + expect_break_W = os2_first_char + 2; + else if(os2_first_char > 0xff) + expect_break_W = 0x20; + else + expect_break_W = os2_first_char; + expect_default_W = expect_break_W - 1; + expect_first_A = expect_default_W - 1; + expect_last_A = min(expect_last_W, 0xff); + } + expect_break_A = expect_break_W; + expect_default_A = expect_default_W; + + /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */ + if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e) + todo_wine ok(tmA.tmFirstChar == expect_first_A || + tmA.tmFirstChar == expect_first_A + 1 /* win9x */, + "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A); + else + ok(tmA.tmFirstChar == expect_first_A || + tmA.tmFirstChar == expect_first_A + 1 /* win9x */, + "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A); + ok(tmA.tmLastChar == expect_last_A || + tmA.tmLastChar == 0xff /* win9x */, + "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A); + ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n", + font_name, tmA.tmBreakChar, expect_break_A); + ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n", + font_name, tmA.tmDefaultChar, expect_default_A); + SetLastError(0xdeadbeef); ret = GetTextMetricsW(hdc, &tmW); @@ -1700,33 +2412,27 @@ static void test_text_metrics(const LOGFONTA *lf) "GetTextMetricsW error %u\n", GetLastError()); if (ret) { - trace("W: first %x, last %x, default %x, break %x\n", - tmW.tmFirstChar, tmW.tmLastChar, tmW.tmDefaultChar, - tmW.tmBreakChar); + /* Wine uses the os2 first char */ + if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol) + todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n", + font_name, tmW.tmFirstChar, expect_first_W); + else + ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n", + font_name, tmW.tmFirstChar, expect_first_W); - if (lf->lfCharSet == SYMBOL_CHARSET) - { - /* It appears that for fonts with SYMBOL_CHARSET Windows always - * sets symbol range to 0 - f0ff - */ - ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n", - font_name, tmW.tmFirstChar); - /* FIXME: Windows returns f0ff here, while Wine f0xx */ - ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n", - font_name, tmW.tmLastChar); + /* Wine uses the os2 last char */ + if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol) + todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n", + font_name, tmW.tmLastChar, expect_last_W); + else + ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n", + font_name, tmW.tmLastChar, expect_last_W); + ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n", + font_name, tmW.tmBreakChar, expect_break_W); + ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n", + font_name, tmW.tmDefaultChar, expect_default_W); - ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n", - font_name, tmW.tmDefaultChar); - ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n", - font_name, tmW.tmBreakChar); - } - else - { - ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n", - font_name, tmW.tmFirstChar, first_unicode_char); - ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n", - font_name, tmW.tmLastChar, last_unicode_char); - } + /* Test the aspect ratio while we have tmW */ ret = GetDeviceCaps(hdc, LOGPIXELSX); ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n", tmW.tmDigitizedAspectX, ret); @@ -1734,6 +2440,60 @@ static void test_text_metrics(const LOGFONTA *lf) ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n", tmW.tmDigitizedAspectX, ret); } + } + + /* test FF_ values */ + switch(tt_os2.panose.bFamilyType) + { + case PAN_ANY: + case PAN_NO_FIT: + case PAN_FAMILY_TEXT_DISPLAY: + case PAN_FAMILY_PICTORIAL: + default: + if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */ + tt_os2.panose.bProportion == PAN_PROP_MONOSPACED) + { + expect_ff(&tmA, &tt_os2, FF_MODERN, font_name); + break; + } + switch(tt_os2.panose.bSerifStyle) + { + case PAN_ANY: + case PAN_NO_FIT: + default: + expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name); + 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: + expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name); + break; + + case PAN_SERIF_NORMAL_SANS: + case PAN_SERIF_OBTUSE_SANS: + case PAN_SERIF_PERP_SANS: + case PAN_SERIF_FLARED: + case PAN_SERIF_ROUNDED: + expect_ff(&tmA, &tt_os2, FF_SWISS, font_name); + break; + } + break; + + case PAN_FAMILY_SCRIPT: + expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name); + break; + + case PAN_FAMILY_DECORATIVE: + expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name); + break; + } test_negative_width(hdc, lf); @@ -1762,6 +2522,10 @@ static void test_GetTextMetrics(void) HDC hdc; INT enumed; + /* Report only once */ + if(!pGetGlyphIndicesA) + win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n"); + hdc = GetDC(0); memset(&lf, 0, sizeof(lf)); @@ -1775,17 +2539,41 @@ static void test_GetTextMetrics(void) static void test_nonexistent_font(void) { + static const struct + { + const char *name; + int charset; + } font_subst[] = + { + { "Times New Roman Baltic", 186 }, + { "Times New Roman CE", 238 }, + { "Times New Roman CYR", 204 }, + { "Times New Roman Greek", 161 }, + { "Times New Roman TUR", 162 } + }; LOGFONTA lf; HDC hdc; HFONT hfont; + CHARSETINFO csi; + INT cs, expected_cs, i; char buf[LF_FACESIZE]; - if (!is_truetype_font_installed("Arial Black")) + if (!is_truetype_font_installed("Arial") || + !is_truetype_font_installed("Times New Roman")) { - skip("Arial not installed\n"); + skip("Arial or Times New Roman not installed\n"); return; } + expected_cs = GetACP(); + if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE)) + { + skip("TranslateCharsetInfo failed for code page %d\n", expected_cs); + return; + } + expected_cs = csi.ciCharset; + trace("ACP %d -> charset %d\n", GetACP(), expected_cs); + hdc = GetDC(0); memset(&lf, 0, sizeof(lf)); @@ -1794,12 +2582,96 @@ static void test_nonexistent_font(void) lf.lfCharSet = ANSI_CHARSET; lf.lfPitchAndFamily = FF_SWISS; strcpy(lf.lfFaceName, "Nonexistent font"); - hfont = CreateFontIndirectA(&lf); hfont = SelectObject(hdc, hfont); GetTextFaceA(hdc, sizeof(buf), buf); ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf); + cs = GetTextCharset(hdc); + ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs); DeleteObject(SelectObject(hdc, hfont)); + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -13; + lf.lfWeight = FW_DONTCARE; + strcpy(lf.lfFaceName, "Nonexistent font"); + hfont = CreateFontIndirectA(&lf); + hfont = SelectObject(hdc, hfont); + GetTextFaceA(hdc, sizeof(buf), buf); +todo_wine /* Wine uses Arial for all substitutions */ + ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ || + !lstrcmpiA(buf, "MS Serif") || /* Win9x */ + !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */ + "Got %s\n", buf); + cs = GetTextCharset(hdc); + ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs); + DeleteObject(SelectObject(hdc, hfont)); + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -13; + lf.lfWeight = FW_REGULAR; + strcpy(lf.lfFaceName, "Nonexistent font"); + hfont = CreateFontIndirectA(&lf); + hfont = SelectObject(hdc, hfont); + GetTextFaceA(hdc, sizeof(buf), buf); + ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ || + !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf); + cs = GetTextCharset(hdc); + ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs); + DeleteObject(SelectObject(hdc, hfont)); + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -13; + lf.lfWeight = FW_DONTCARE; + strcpy(lf.lfFaceName, "Times New Roman"); + hfont = CreateFontIndirectA(&lf); + hfont = SelectObject(hdc, hfont); + GetTextFaceA(hdc, sizeof(buf), buf); + ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf); + cs = GetTextCharset(hdc); + ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs); + DeleteObject(SelectObject(hdc, hfont)); + + for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++) + { + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -13; + lf.lfWeight = FW_REGULAR; + strcpy(lf.lfFaceName, font_subst[i].name); + hfont = CreateFontIndirectA(&lf); + hfont = SelectObject(hdc, hfont); + cs = GetTextCharset(hdc); + if (font_subst[i].charset == expected_cs) + { + ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name); + GetTextFaceA(hdc, sizeof(buf), buf); + ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf); + } + else + { + ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name); + GetTextFaceA(hdc, sizeof(buf), buf); + ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ || + !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name); + } + DeleteObject(SelectObject(hdc, hfont)); + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -13; + lf.lfWeight = FW_DONTCARE; + strcpy(lf.lfFaceName, font_subst[i].name); + hfont = CreateFontIndirectA(&lf); + hfont = SelectObject(hdc, hfont); + GetTextFaceA(hdc, sizeof(buf), buf); + ok(!lstrcmpiA(buf, "Arial") /* Wine */ || + !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ || + !lstrcmpiA(buf, "MS Serif") /* Win9x */ || + !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */ + "got %s for font %s\n", buf, font_subst[i].name); + cs = GetTextCharset(hdc); + ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name); + DeleteObject(SelectObject(hdc, hfont)); + } + ReleaseDC(0, hdc); } @@ -1813,7 +2685,7 @@ static void test_GdiRealizationInfo(void) if(!pGdiRealizationInfo) { - skip("GdiRealizationInfo not available\n"); + win_skip("GdiRealizationInfo not available\n"); return; } @@ -1822,7 +2694,7 @@ static void test_GdiRealizationInfo(void) memset(info, 0xcc, sizeof(info)); r = pGdiRealizationInfo(hdc, info); ok(r != 0, "ret 0\n"); - ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]); + ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]); ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n"); if (!is_truetype_font_installed("Arial")) @@ -1841,7 +2713,7 @@ static void test_GdiRealizationInfo(void) memset(info, 0xcc, sizeof(info)); r = pGdiRealizationInfo(hdc, info); ok(r != 0, "ret 0\n"); - ok(info[0] == 3, "info[0] = %x for arial\n", info[0]); + ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]); ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n"); DeleteObject(SelectObject(hdc, hfont_old)); @@ -1850,12 +2722,270 @@ static void test_GdiRealizationInfo(void) ReleaseDC(0, hdc); } +/* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include + the nul in the count of characters copied when the face name buffer is not + NULL, whereas it does if the buffer is NULL. Further, the Unicode version + always includes it. */ +static void test_GetTextFace(void) +{ + static const char faceA[] = "Tahoma"; + static const WCHAR faceW[] = {'T','a','h','o','m','a', 0}; + LOGFONTA fA = {0}; + LOGFONTW fW = {0}; + char bufA[LF_FACESIZE]; + WCHAR bufW[LF_FACESIZE]; + HFONT f, g; + HDC dc; + int n; + + if(!is_font_installed("Tahoma")) + { + skip("Tahoma is not installed so skipping this test\n"); + return; + } + + /* 'A' case. */ + memcpy(fA.lfFaceName, faceA, sizeof faceA); + f = CreateFontIndirectA(&fA); + ok(f != NULL, "CreateFontIndirectA failed\n"); + + dc = GetDC(NULL); + g = SelectObject(dc, f); + n = GetTextFaceA(dc, sizeof bufA, bufA); + ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n); + ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n"); + + /* Play with the count arg. */ + bufA[0] = 'x'; + n = GetTextFaceA(dc, 0, bufA); + ok(n == 0, "GetTextFaceA returned %d\n", n); + ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]); + + bufA[0] = 'x'; + n = GetTextFaceA(dc, 1, bufA); + ok(n == 0, "GetTextFaceA returned %d\n", n); + ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]); + + bufA[0] = 'x'; bufA[1] = 'y'; + n = GetTextFaceA(dc, 2, bufA); + ok(n == 1, "GetTextFaceA returned %d\n", n); + ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n"); + + n = GetTextFaceA(dc, 0, NULL); + ok(n == sizeof faceA || + broken(n == 0), /* win98, winMe */ + "GetTextFaceA returned %d\n", n); + + DeleteObject(SelectObject(dc, g)); + ReleaseDC(NULL, dc); + + /* 'W' case. */ + memcpy(fW.lfFaceName, faceW, sizeof faceW); + SetLastError(0xdeadbeef); + f = CreateFontIndirectW(&fW); + if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("CreateFontIndirectW is not implemented\n"); + return; + } + ok(f != NULL, "CreateFontIndirectW failed\n"); + + dc = GetDC(NULL); + g = SelectObject(dc, f); + n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW); + ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n); + ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n"); + + /* Play with the count arg. */ + bufW[0] = 'x'; + n = GetTextFaceW(dc, 0, bufW); + ok(n == 0, "GetTextFaceW returned %d\n", n); + ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]); + + bufW[0] = 'x'; + n = GetTextFaceW(dc, 1, bufW); + ok(n == 1, "GetTextFaceW returned %d\n", n); + ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]); + + bufW[0] = 'x'; bufW[1] = 'y'; + n = GetTextFaceW(dc, 2, bufW); + ok(n == 2, "GetTextFaceW returned %d\n", n); + ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n"); + + n = GetTextFaceW(dc, 0, NULL); + ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n); + + DeleteObject(SelectObject(dc, g)); + ReleaseDC(NULL, dc); +} + +static void test_orientation(void) +{ + static const char test_str[11] = "Test String"; + HDC hdc; + LOGFONTA lf; + HFONT hfont, old_hfont; + SIZE size; + + if (!is_truetype_font_installed("Arial")) + { + skip("Arial is not installed\n"); + return; + } + + hdc = CreateCompatibleDC(0); + memset(&lf, 0, sizeof(lf)); + lstrcpyA(lf.lfFaceName, "Arial"); + lf.lfHeight = 72; + lf.lfOrientation = lf.lfEscapement = 900; + hfont = create_font("orientation", &lf); + old_hfont = SelectObject(hdc, hfont); + ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n"); + ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx); + ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy); + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + DeleteDC(hdc); +} + +static void test_GetGlyphOutline(void) +{ + MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; + HDC hdc; + GLYPHMETRICS gm; + LOGFONTA lf; + HFONT hfont, old_hfont; + INT ret; + + if (!is_truetype_font_installed("Tahoma")) + { + skip("Tahoma is not installed\n"); + return; + } + + hdc = CreateCompatibleDC(0); + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = 72; + lstrcpyA(lf.lfFaceName, "Tahoma"); + SetLastError(0xdeadbeef); + hfont = CreateFontIndirectA(&lf); + ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); + old_hfont = SelectObject(hdc, hfont); + + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError()); + + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL); + ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n"); + ok(GetLastError() == 0xdeadbeef || + GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */ + "expected 0xdeadbeef, got %u\n", GetLastError()); + + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat); + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError()); + + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL); + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + { + ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n"); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError()); + } + + /* test for needed buffer size request on space char */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat); + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n"); + + /* requesting buffer size for space char + error */ + memset(&gm, 0, sizeof(gm)); + SetLastError(0xdeadbeef); + ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL); + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + { + ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n"); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError()); + } + + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + DeleteDC(hdc); +} + +/* bug #9995: there is a limit to the character width that can be specified */ +static void test_GetTextMetrics2(const char *fontname, int font_height) +{ + HFONT of, hf; + HDC hdc; + TEXTMETRICA tm; + BOOL ret; + int ave_width, height, width, ratio, scale; + + if (!is_truetype_font_installed( fontname)) { + skip("%s is not installed\n", fontname); + return; + } + hdc = CreateCompatibleDC(0); + ok( hdc != NULL, "CreateCompatibleDC failed\n"); + /* select width = 0 */ + hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES, + DEFAULT_QUALITY, VARIABLE_PITCH, + fontname); + ok( hf != NULL, "CreateFontA failed\n"); + of = SelectObject( hdc, hf); + ret = GetTextMetricsA( hdc, &tm); + ok(ret, "GetTextMetricsA error %u\n", GetLastError()); + height = tm.tmHeight; + ave_width = tm.tmAveCharWidth; + SelectObject( hdc, of); + DeleteObject( hf); + + trace("height %d, ave width %d\n", height, ave_width); + + for (width = ave_width * 2; /* nothing*/; width += ave_width) + { + hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES, + DEFAULT_QUALITY, VARIABLE_PITCH, fontname); + ok(hf != 0, "CreateFont failed\n"); + of = SelectObject(hdc, hf); + ret = GetTextMetrics(hdc, &tm); + ok(ret, "GetTextMetrics error %u\n", GetLastError()); + SelectObject(hdc, of); + DeleteObject(hf); + + if (tm.tmAveCharWidth == ave_width || width / height > 200) + break; + } + + DeleteDC(hdc); + + ratio = width / height; + scale = width / ave_width; + + trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n", + width, height, ratio, width, ave_width, scale); + + ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio); +} + START_TEST(font) { init(); - test_logfont(); test_bitmap_font(); + test_outline_font(); test_bitmap_font_metrics(); test_GdiGetCharDimensions(); test_GetCharABCWidths(); @@ -1867,6 +2997,7 @@ START_TEST(font) test_font_charset(); test_GetFontUnicodeRanges(); test_nonexistent_font(); + test_orientation(); /* On Windows Arial has a lot of default charset aliases such as Arial Cyr, * I'd like to avoid them in this test. @@ -1884,4 +3015,12 @@ START_TEST(font) skip("Arial Black or Symbol/Wingdings is not installed\n"); test_GetTextMetrics(); test_GdiRealizationInfo(); + test_GetTextFace(); + test_GetGlyphOutline(); + test_GetTextMetrics2("Tahoma", -11); + test_GetTextMetrics2("Tahoma", -55); + test_GetTextMetrics2("Tahoma", -110); + test_GetTextMetrics2("Arial", -11); + test_GetTextMetrics2("Arial", -55); + test_GetTextMetrics2("Arial", -110); } diff --git a/rostests/winetests/gdi32/gdi32.rbuild b/rostests/winetests/gdi32/gdi32.rbuild index e363c0ed36b..ffb6854b627 100644 --- a/rostests/winetests/gdi32/gdi32.rbuild +++ b/rostests/winetests/gdi32/gdi32.rbuild @@ -1,13 +1,10 @@ - . - 0x0600 - + ntdll gdi32 - kernel32 user32 advapi32 bitmap.c @@ -25,4 +22,3 @@ pen.c testlist.c - diff --git a/rostests/winetests/gdi32/gdiobj.c b/rostests/winetests/gdi32/gdiobj.c index bd7a065bb86..c1adc0f57f9 100755 --- a/rostests/winetests/gdi32/gdiobj.c +++ b/rostests/winetests/gdi32/gdiobj.c @@ -43,7 +43,7 @@ static void test_gdi_objects(void) */ SetLastError(0); hp = SelectObject(NULL, GetStockObject(BLACK_PEN)); - ok(!hp && GetLastError() == ERROR_INVALID_HANDLE, + ok(!hp && (GetLastError() == ERROR_INVALID_HANDLE || broken(!GetLastError())), "SelectObject(NULL DC) expected 0, ERROR_INVALID_HANDLE, got %p, %u\n", hp, GetLastError()); @@ -77,7 +77,7 @@ static void test_gdi_objects(void) /* GetObject does not SetLastError() on a null object */ SetLastError(0); i = GetObjectA(NULL, sizeof(buff), buff); - ok (!i && !GetLastError(), + ok (!i && (GetLastError() == 0 || GetLastError() == ERROR_INVALID_PARAMETER), "GetObject(NULL obj), expected 0, NO_ERROR, got %d, %u\n", i, GetLastError()); @@ -110,7 +110,7 @@ struct hgdiobj_event static DWORD WINAPI thread_proc(void *param) { LOGPEN lp; - struct hgdiobj_event *hgdiobj_event = (struct hgdiobj_event *)param; + struct hgdiobj_event *hgdiobj_event = param; hgdiobj_event->hdc = CreateDC("display", NULL, NULL, NULL); ok(hgdiobj_event->hdc != NULL, "CreateDC error %u\n", GetLastError()); @@ -207,7 +207,7 @@ static void test_GetCurrentObject(void) hobj = GetCurrentObject(hdc, OBJ_PEN); ok(hobj == hpen, "OBJ_PEN is wrong: %p\n", hobj); hobj = GetCurrentObject(hdc, OBJ_EXTPEN); - ok(hobj == hpen, "OBJ_EXTPEN is wrong: %p\n", hobj); + ok(hobj == hpen || broken(hobj == 0) /* win9x */, "OBJ_EXTPEN is wrong: %p\n", hobj); hbrush = CreateSolidBrush(RGB(10, 20, 30)); assert(hbrush != 0); @@ -243,7 +243,7 @@ static void test_GetCurrentObject(void) hobj = GetCurrentObject(hdc, OBJ_PEN); ok(hobj == hpen, "OBJ_PEN is wrong: %p\n", hobj); hobj = GetCurrentObject(hdc, OBJ_EXTPEN); - ok(hobj == hpen, "OBJ_EXTPEN is wrong: %p\n", hobj); + ok(hobj == hpen || broken(hobj == 0) /* win9x */, "OBJ_EXTPEN is wrong: %p\n", hobj); hcs = GetColorSpace(hdc); if (hcs) @@ -254,7 +254,7 @@ static void test_GetCurrentObject(void) ok(hcs != 0, "CreateColorSpace failed\n"); SelectObject(hdc, hcs); hobj = GetCurrentObject(hdc, OBJ_COLORSPACE); - ok(hobj == hcs, "OBJ_COLORSPACE is wrong: %p\n", hobj); + ok(hobj == hcs || broken(hobj == 0) /* win9x */, "OBJ_COLORSPACE is wrong: %p\n", hobj); } hrgn = CreateRectRgn(1, 1, 100, 100); @@ -266,9 +266,49 @@ static void test_GetCurrentObject(void) DeleteDC(hdc); } +static void test_region(void) +{ + HRGN hrgn = CreateRectRgn(10, 10, 20, 20); + RECT rc = { 5, 5, 15, 15 }; + BOOL ret = RectInRegion( hrgn, &rc); + ok( ret, "RectInRegion should return TRUE\n"); + /* swap left and right */ + SetRect( &rc, 15, 5, 5, 15 ); + ret = RectInRegion( hrgn, &rc); + ok( ret, "RectInRegion should return TRUE\n"); + /* swap top and bottom */ + SetRect( &rc, 5, 15, 15, 5 ); + ret = RectInRegion( hrgn, &rc); + ok( ret, "RectInRegion should return TRUE\n"); + /* swap both */ + SetRect( &rc, 15, 15, 5, 5 ); + ret = RectInRegion( hrgn, &rc); + ok( ret, "RectInRegion should return TRUE\n"); + DeleteObject(hrgn); + /* swap left and right in the region */ + hrgn = CreateRectRgn(20, 10, 10, 20); + SetRect( &rc, 5, 5, 15, 15 ); + ret = RectInRegion( hrgn, &rc); + ok( ret, "RectInRegion should return TRUE\n"); + /* swap left and right */ + SetRect( &rc, 15, 5, 5, 15 ); + ret = RectInRegion( hrgn, &rc); + ok( ret, "RectInRegion should return TRUE\n"); + /* swap top and bottom */ + SetRect( &rc, 5, 15, 15, 5 ); + ret = RectInRegion( hrgn, &rc); + ok( ret, "RectInRegion should return TRUE\n"); + /* swap both */ + SetRect( &rc, 15, 15, 5, 5 ); + ret = RectInRegion( hrgn, &rc); + ok( ret, "RectInRegion should return TRUE\n"); + DeleteObject(hrgn); +} + START_TEST(gdiobj) { test_gdi_objects(); test_thread_objects(); test_GetCurrentObject(); + test_region(); } diff --git a/rostests/winetests/gdi32/generated.c b/rostests/winetests/gdi32/generated.c index 9a35f24070b..3d742ee9fd8 100644 --- a/rostests/winetests/gdi32/generated.c +++ b/rostests/winetests/gdi32/generated.c @@ -1,4 +1,4 @@ -/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* File generated automatically from tools/winapi/tests.dat; do not edit! */ /* This file can be copied, modified and distributed without restriction. */ /* @@ -27,22 +27,14 @@ * Windows API extension */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) -# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) -#elif defined(__GNUC__) -# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) -#else -/* FIXME: Not sure if is possible to do without compiler extension */ -#endif - #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) #elif defined(__GNUC__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* - * FIXME: Not sure if is possible to do without compiler extension - * (if type is not just a name that is, if so the normal) + * FIXME: May not be possible without a compiler extension + * (if type is not just a name that is, otherwise the normal * TYPE_ALIGNMENT can be used) */ #endif @@ -59,3877 +51,6568 @@ * Test helper macros */ -#ifdef FIELD_ALIGNMENT -# define TEST_FIELD_ALIGNMENT(type, field, align) \ - ok(FIELD_ALIGNMENT(type, field) == align, \ - "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ - (int)FIELD_ALIGNMENT(type, field)) +#ifdef _WIN64 + +# define TEST_TYPE_SIZE(type, size) +# define TEST_TYPE_ALIGN(type, align) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) +# define TEST_FIELD_OFFSET(type, field, offset) + #else -# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) + +# define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); + +# ifdef TYPE_ALIGNMENT +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +#else +# define TEST_TYPE_ALIGN(type, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) \ - ok(FIELD_OFFSET(type, field) == offset, \ - "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ - (long int)FIELD_OFFSET(type, field)) - -#ifdef _TYPE_ALIGNMENT -#define TEST__TYPE_ALIGNMENT(type, align) \ - ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +# ifdef _TYPE_ALIGNMENT +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else -# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) #endif -#ifdef TYPE_ALIGNMENT -#define TEST_TYPE_ALIGNMENT(type, align) \ - ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) -#else -# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); + #endif -#define TEST_TYPE_SIZE(type, size) \ - ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) +#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) +#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) +#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0); +#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0); -/*********************************************************************** - * Test macros - */ - -#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ - TEST_TYPE_SIZE(field_type, field_size); \ - TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ - TEST_FIELD_OFFSET(type, field_name, field_offset); \ - -#define TEST_TYPE(type, size, align) \ - TEST_TYPE_ALIGNMENT(type, align); \ - TEST_TYPE_SIZE(type, size) - -#define TEST_TYPE_POINTER(type, size, align) \ - TEST__TYPE_ALIGNMENT(*(type)0, align); \ - TEST_TYPE_SIZE(*(type)0, size) - -#define TEST_TYPE_SIGNED(type) \ - ok((type) -1 < 0, "(" #type ") -1 < 0\n"); - -#define TEST_TYPE_UNSIGNED(type) \ - ok((type) -1 > 0, "(" #type ") -1 > 0\n"); static void test_pack_ABC(void) { /* ABC (pack 4) */ - TEST_TYPE(ABC, 12, 4); - TEST_FIELD(ABC, INT, abcA, 0, 4, 4); - TEST_FIELD(ABC, UINT, abcB, 4, 4, 4); - TEST_FIELD(ABC, INT, abcC, 8, 4, 4); + TEST_TYPE_SIZE (ABC, 12) + TEST_TYPE_ALIGN (ABC, 4) + TEST_FIELD_SIZE (ABC, abcA, 4) + TEST_FIELD_ALIGN (ABC, abcA, 4) + TEST_FIELD_OFFSET(ABC, abcA, 0) + TEST_FIELD_SIZE (ABC, abcB, 4) + TEST_FIELD_ALIGN (ABC, abcB, 4) + TEST_FIELD_OFFSET(ABC, abcB, 4) + TEST_FIELD_SIZE (ABC, abcC, 4) + TEST_FIELD_ALIGN (ABC, abcC, 4) + TEST_FIELD_OFFSET(ABC, abcC, 8) } static void test_pack_ABCFLOAT(void) { /* ABCFLOAT (pack 4) */ - TEST_TYPE(ABCFLOAT, 12, 4); - TEST_FIELD(ABCFLOAT, FLOAT, abcfA, 0, 4, 4); - TEST_FIELD(ABCFLOAT, FLOAT, abcfB, 4, 4, 4); - TEST_FIELD(ABCFLOAT, FLOAT, abcfC, 8, 4, 4); + TEST_TYPE_SIZE (ABCFLOAT, 12) + TEST_TYPE_ALIGN (ABCFLOAT, 4) + TEST_FIELD_SIZE (ABCFLOAT, abcfA, 4) + TEST_FIELD_ALIGN (ABCFLOAT, abcfA, 4) + TEST_FIELD_OFFSET(ABCFLOAT, abcfA, 0) + TEST_FIELD_SIZE (ABCFLOAT, abcfB, 4) + TEST_FIELD_ALIGN (ABCFLOAT, abcfB, 4) + TEST_FIELD_OFFSET(ABCFLOAT, abcfB, 4) + TEST_FIELD_SIZE (ABCFLOAT, abcfC, 4) + TEST_FIELD_ALIGN (ABCFLOAT, abcfC, 4) + TEST_FIELD_OFFSET(ABCFLOAT, abcfC, 8) } static void test_pack_ABORTPROC(void) { /* ABORTPROC */ - TEST_TYPE(ABORTPROC, 4, 4); + TEST_TYPE_SIZE (ABORTPROC, 4) + TEST_TYPE_ALIGN (ABORTPROC, 4) } static void test_pack_BITMAP(void) { /* BITMAP (pack 4) */ - TEST_TYPE(BITMAP, 24, 4); - TEST_FIELD(BITMAP, INT, bmType, 0, 4, 4); - TEST_FIELD(BITMAP, INT, bmWidth, 4, 4, 4); - TEST_FIELD(BITMAP, INT, bmHeight, 8, 4, 4); - TEST_FIELD(BITMAP, INT, bmWidthBytes, 12, 4, 4); - TEST_FIELD(BITMAP, WORD, bmPlanes, 16, 2, 2); - TEST_FIELD(BITMAP, WORD, bmBitsPixel, 18, 2, 2); - TEST_FIELD(BITMAP, LPVOID, bmBits, 20, 4, 4); + TEST_TYPE_SIZE (BITMAP, 24) + TEST_TYPE_ALIGN (BITMAP, 4) + TEST_FIELD_SIZE (BITMAP, bmType, 4) + TEST_FIELD_ALIGN (BITMAP, bmType, 4) + TEST_FIELD_OFFSET(BITMAP, bmType, 0) + TEST_FIELD_SIZE (BITMAP, bmWidth, 4) + TEST_FIELD_ALIGN (BITMAP, bmWidth, 4) + TEST_FIELD_OFFSET(BITMAP, bmWidth, 4) + TEST_FIELD_SIZE (BITMAP, bmHeight, 4) + TEST_FIELD_ALIGN (BITMAP, bmHeight, 4) + TEST_FIELD_OFFSET(BITMAP, bmHeight, 8) + TEST_FIELD_SIZE (BITMAP, bmWidthBytes, 4) + TEST_FIELD_ALIGN (BITMAP, bmWidthBytes, 4) + TEST_FIELD_OFFSET(BITMAP, bmWidthBytes, 12) + TEST_FIELD_SIZE (BITMAP, bmPlanes, 2) + TEST_FIELD_ALIGN (BITMAP, bmPlanes, 2) + TEST_FIELD_OFFSET(BITMAP, bmPlanes, 16) + TEST_FIELD_SIZE (BITMAP, bmBitsPixel, 2) + TEST_FIELD_ALIGN (BITMAP, bmBitsPixel, 2) + TEST_FIELD_OFFSET(BITMAP, bmBitsPixel, 18) + TEST_FIELD_SIZE (BITMAP, bmBits, 4) + TEST_FIELD_ALIGN (BITMAP, bmBits, 4) + TEST_FIELD_OFFSET(BITMAP, bmBits, 20) } static void test_pack_BITMAPCOREHEADER(void) { /* BITMAPCOREHEADER (pack 4) */ - TEST_TYPE(BITMAPCOREHEADER, 12, 4); - TEST_FIELD(BITMAPCOREHEADER, DWORD, bcSize, 0, 4, 4); - TEST_FIELD(BITMAPCOREHEADER, WORD, bcWidth, 4, 2, 2); - TEST_FIELD(BITMAPCOREHEADER, WORD, bcHeight, 6, 2, 2); - TEST_FIELD(BITMAPCOREHEADER, WORD, bcPlanes, 8, 2, 2); - TEST_FIELD(BITMAPCOREHEADER, WORD, bcBitCount, 10, 2, 2); + TEST_TYPE_SIZE (BITMAPCOREHEADER, 12) + TEST_TYPE_ALIGN (BITMAPCOREHEADER, 4) + TEST_FIELD_SIZE (BITMAPCOREHEADER, bcSize, 4) + TEST_FIELD_ALIGN (BITMAPCOREHEADER, bcSize, 4) + TEST_FIELD_OFFSET(BITMAPCOREHEADER, bcSize, 0) + TEST_FIELD_SIZE (BITMAPCOREHEADER, bcWidth, 2) + TEST_FIELD_ALIGN (BITMAPCOREHEADER, bcWidth, 2) + TEST_FIELD_OFFSET(BITMAPCOREHEADER, bcWidth, 4) + TEST_FIELD_SIZE (BITMAPCOREHEADER, bcHeight, 2) + TEST_FIELD_ALIGN (BITMAPCOREHEADER, bcHeight, 2) + TEST_FIELD_OFFSET(BITMAPCOREHEADER, bcHeight, 6) + TEST_FIELD_SIZE (BITMAPCOREHEADER, bcPlanes, 2) + TEST_FIELD_ALIGN (BITMAPCOREHEADER, bcPlanes, 2) + TEST_FIELD_OFFSET(BITMAPCOREHEADER, bcPlanes, 8) + TEST_FIELD_SIZE (BITMAPCOREHEADER, bcBitCount, 2) + TEST_FIELD_ALIGN (BITMAPCOREHEADER, bcBitCount, 2) + TEST_FIELD_OFFSET(BITMAPCOREHEADER, bcBitCount, 10) } static void test_pack_BITMAPCOREINFO(void) { /* BITMAPCOREINFO (pack 4) */ - TEST_TYPE(BITMAPCOREINFO, 16, 4); - TEST_FIELD(BITMAPCOREINFO, BITMAPCOREHEADER, bmciHeader, 0, 12, 4); - TEST_FIELD(BITMAPCOREINFO, RGBTRIPLE[1], bmciColors, 12, 3, 1); + TEST_TYPE_SIZE (BITMAPCOREINFO, 16) + TEST_TYPE_ALIGN (BITMAPCOREINFO, 4) + TEST_FIELD_SIZE (BITMAPCOREINFO, bmciHeader, 12) + TEST_FIELD_ALIGN (BITMAPCOREINFO, bmciHeader, 4) + TEST_FIELD_OFFSET(BITMAPCOREINFO, bmciHeader, 0) + TEST_FIELD_SIZE (BITMAPCOREINFO, bmciColors, 3) + TEST_FIELD_ALIGN (BITMAPCOREINFO, bmciColors, 1) + TEST_FIELD_OFFSET(BITMAPCOREINFO, bmciColors, 12) } static void test_pack_BITMAPFILEHEADER(void) { /* BITMAPFILEHEADER (pack 2) */ - TEST_TYPE(BITMAPFILEHEADER, 14, 2); - TEST_FIELD(BITMAPFILEHEADER, WORD, bfType, 0, 2, 2); - TEST_FIELD(BITMAPFILEHEADER, DWORD, bfSize, 2, 4, 2); - TEST_FIELD(BITMAPFILEHEADER, WORD, bfReserved1, 6, 2, 2); - TEST_FIELD(BITMAPFILEHEADER, WORD, bfReserved2, 8, 2, 2); - TEST_FIELD(BITMAPFILEHEADER, DWORD, bfOffBits, 10, 4, 2); + TEST_TYPE_SIZE (BITMAPFILEHEADER, 14) + TEST_TYPE_ALIGN (BITMAPFILEHEADER, 2) + TEST_FIELD_SIZE (BITMAPFILEHEADER, bfType, 2) + TEST_FIELD_ALIGN (BITMAPFILEHEADER, bfType, 2) + TEST_FIELD_OFFSET(BITMAPFILEHEADER, bfType, 0) + TEST_FIELD_SIZE (BITMAPFILEHEADER, bfSize, 4) + TEST_FIELD_ALIGN (BITMAPFILEHEADER, bfSize, 2) + TEST_FIELD_OFFSET(BITMAPFILEHEADER, bfSize, 2) + TEST_FIELD_SIZE (BITMAPFILEHEADER, bfReserved1, 2) + TEST_FIELD_ALIGN (BITMAPFILEHEADER, bfReserved1, 2) + TEST_FIELD_OFFSET(BITMAPFILEHEADER, bfReserved1, 6) + TEST_FIELD_SIZE (BITMAPFILEHEADER, bfReserved2, 2) + TEST_FIELD_ALIGN (BITMAPFILEHEADER, bfReserved2, 2) + TEST_FIELD_OFFSET(BITMAPFILEHEADER, bfReserved2, 8) + TEST_FIELD_SIZE (BITMAPFILEHEADER, bfOffBits, 4) + TEST_FIELD_ALIGN (BITMAPFILEHEADER, bfOffBits, 2) + TEST_FIELD_OFFSET(BITMAPFILEHEADER, bfOffBits, 10) } static void test_pack_BITMAPINFO(void) { /* BITMAPINFO (pack 4) */ - TEST_TYPE(BITMAPINFO, 44, 4); - TEST_FIELD(BITMAPINFO, BITMAPINFOHEADER, bmiHeader, 0, 40, 4); - TEST_FIELD(BITMAPINFO, RGBQUAD[1], bmiColors, 40, 4, 1); + TEST_TYPE_SIZE (BITMAPINFO, 44) + TEST_TYPE_ALIGN (BITMAPINFO, 4) + TEST_FIELD_SIZE (BITMAPINFO, bmiHeader, 40) + TEST_FIELD_ALIGN (BITMAPINFO, bmiHeader, 4) + TEST_FIELD_OFFSET(BITMAPINFO, bmiHeader, 0) + TEST_FIELD_SIZE (BITMAPINFO, bmiColors, 4) + TEST_FIELD_ALIGN (BITMAPINFO, bmiColors, 1) + TEST_FIELD_OFFSET(BITMAPINFO, bmiColors, 40) } static void test_pack_BITMAPINFOHEADER(void) { /* BITMAPINFOHEADER (pack 4) */ - TEST_TYPE(BITMAPINFOHEADER, 40, 4); - TEST_FIELD(BITMAPINFOHEADER, DWORD, biSize, 0, 4, 4); - TEST_FIELD(BITMAPINFOHEADER, LONG, biWidth, 4, 4, 4); - TEST_FIELD(BITMAPINFOHEADER, LONG, biHeight, 8, 4, 4); - TEST_FIELD(BITMAPINFOHEADER, WORD, biPlanes, 12, 2, 2); - TEST_FIELD(BITMAPINFOHEADER, WORD, biBitCount, 14, 2, 2); - TEST_FIELD(BITMAPINFOHEADER, DWORD, biCompression, 16, 4, 4); - TEST_FIELD(BITMAPINFOHEADER, DWORD, biSizeImage, 20, 4, 4); - TEST_FIELD(BITMAPINFOHEADER, LONG, biXPelsPerMeter, 24, 4, 4); - TEST_FIELD(BITMAPINFOHEADER, LONG, biYPelsPerMeter, 28, 4, 4); - TEST_FIELD(BITMAPINFOHEADER, DWORD, biClrUsed, 32, 4, 4); - TEST_FIELD(BITMAPINFOHEADER, DWORD, biClrImportant, 36, 4, 4); + TEST_TYPE_SIZE (BITMAPINFOHEADER, 40) + TEST_TYPE_ALIGN (BITMAPINFOHEADER, 4) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biSize, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biSize, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biSize, 0) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biWidth, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biWidth, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biWidth, 4) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biHeight, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biHeight, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biHeight, 8) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biPlanes, 2) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biPlanes, 2) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biPlanes, 12) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biBitCount, 2) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biBitCount, 2) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biBitCount, 14) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biCompression, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biCompression, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biCompression, 16) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biSizeImage, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biSizeImage, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biSizeImage, 20) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biXPelsPerMeter, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biXPelsPerMeter, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biXPelsPerMeter, 24) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biYPelsPerMeter, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biYPelsPerMeter, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biYPelsPerMeter, 28) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biClrUsed, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biClrUsed, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biClrUsed, 32) + TEST_FIELD_SIZE (BITMAPINFOHEADER, biClrImportant, 4) + TEST_FIELD_ALIGN (BITMAPINFOHEADER, biClrImportant, 4) + TEST_FIELD_OFFSET(BITMAPINFOHEADER, biClrImportant, 36) } static void test_pack_BITMAPV4HEADER(void) { /* BITMAPV4HEADER (pack 4) */ - TEST_TYPE(BITMAPV4HEADER, 108, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4Size, 0, 4, 4); - TEST_FIELD(BITMAPV4HEADER, LONG, bV4Width, 4, 4, 4); - TEST_FIELD(BITMAPV4HEADER, LONG, bV4Height, 8, 4, 4); - TEST_FIELD(BITMAPV4HEADER, WORD, bV4Planes, 12, 2, 2); - TEST_FIELD(BITMAPV4HEADER, WORD, bV4BitCount, 14, 2, 2); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4V4Compression, 16, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4SizeImage, 20, 4, 4); - TEST_FIELD(BITMAPV4HEADER, LONG, bV4XPelsPerMeter, 24, 4, 4); - TEST_FIELD(BITMAPV4HEADER, LONG, bV4YPelsPerMeter, 28, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4ClrUsed, 32, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4ClrImportant, 36, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4RedMask, 40, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4GreenMask, 44, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4BlueMask, 48, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4AlphaMask, 52, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4CSType, 56, 4, 4); - TEST_FIELD(BITMAPV4HEADER, CIEXYZTRIPLE, bV4Endpoints, 60, 36, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4GammaRed, 96, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4GammaGreen, 100, 4, 4); - TEST_FIELD(BITMAPV4HEADER, DWORD, bV4GammaBlue, 104, 4, 4); + TEST_TYPE_SIZE (BITMAPV4HEADER, 108) + TEST_TYPE_ALIGN (BITMAPV4HEADER, 4) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4Size, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4Size, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4Size, 0) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4Width, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4Width, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4Width, 4) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4Height, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4Height, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4Height, 8) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4Planes, 2) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4Planes, 2) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4Planes, 12) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4BitCount, 2) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4BitCount, 2) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4BitCount, 14) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4V4Compression, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4V4Compression, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4V4Compression, 16) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4SizeImage, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4SizeImage, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4SizeImage, 20) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4XPelsPerMeter, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4XPelsPerMeter, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4XPelsPerMeter, 24) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4YPelsPerMeter, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4YPelsPerMeter, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4YPelsPerMeter, 28) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4ClrUsed, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4ClrUsed, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4ClrUsed, 32) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4ClrImportant, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4ClrImportant, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4ClrImportant, 36) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4RedMask, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4RedMask, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4RedMask, 40) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4GreenMask, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4GreenMask, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4GreenMask, 44) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4BlueMask, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4BlueMask, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4BlueMask, 48) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4AlphaMask, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4AlphaMask, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4AlphaMask, 52) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4CSType, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4CSType, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4CSType, 56) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4Endpoints, 36) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4Endpoints, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4Endpoints, 60) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4GammaRed, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4GammaRed, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4GammaRed, 96) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4GammaGreen, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4GammaGreen, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4GammaGreen, 100) + TEST_FIELD_SIZE (BITMAPV4HEADER, bV4GammaBlue, 4) + TEST_FIELD_ALIGN (BITMAPV4HEADER, bV4GammaBlue, 4) + TEST_FIELD_OFFSET(BITMAPV4HEADER, bV4GammaBlue, 104) } static void test_pack_BITMAPV5HEADER(void) { /* BITMAPV5HEADER (pack 4) */ - TEST_TYPE(BITMAPV5HEADER, 124, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5Size, 0, 4, 4); - TEST_FIELD(BITMAPV5HEADER, LONG, bV5Width, 4, 4, 4); - TEST_FIELD(BITMAPV5HEADER, LONG, bV5Height, 8, 4, 4); - TEST_FIELD(BITMAPV5HEADER, WORD, bV5Planes, 12, 2, 2); - TEST_FIELD(BITMAPV5HEADER, WORD, bV5BitCount, 14, 2, 2); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5Compression, 16, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5SizeImage, 20, 4, 4); - TEST_FIELD(BITMAPV5HEADER, LONG, bV5XPelsPerMeter, 24, 4, 4); - TEST_FIELD(BITMAPV5HEADER, LONG, bV5YPelsPerMeter, 28, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5ClrUsed, 32, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5ClrImportant, 36, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5RedMask, 40, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5GreenMask, 44, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5BlueMask, 48, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5AlphaMask, 52, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5CSType, 56, 4, 4); - TEST_FIELD(BITMAPV5HEADER, CIEXYZTRIPLE, bV5Endpoints, 60, 36, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5GammaRed, 96, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5GammaGreen, 100, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5GammaBlue, 104, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5Intent, 108, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5ProfileData, 112, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5ProfileSize, 116, 4, 4); - TEST_FIELD(BITMAPV5HEADER, DWORD, bV5Reserved, 120, 4, 4); + TEST_TYPE_SIZE (BITMAPV5HEADER, 124) + TEST_TYPE_ALIGN (BITMAPV5HEADER, 4) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5Size, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5Size, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5Size, 0) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5Width, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5Width, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5Width, 4) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5Height, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5Height, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5Height, 8) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5Planes, 2) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5Planes, 2) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5Planes, 12) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5BitCount, 2) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5BitCount, 2) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5BitCount, 14) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5Compression, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5Compression, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5Compression, 16) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5SizeImage, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5SizeImage, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5SizeImage, 20) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5XPelsPerMeter, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5XPelsPerMeter, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5XPelsPerMeter, 24) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5YPelsPerMeter, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5YPelsPerMeter, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5YPelsPerMeter, 28) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5ClrUsed, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5ClrUsed, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5ClrUsed, 32) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5ClrImportant, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5ClrImportant, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5ClrImportant, 36) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5RedMask, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5RedMask, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5RedMask, 40) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5GreenMask, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5GreenMask, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5GreenMask, 44) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5BlueMask, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5BlueMask, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5BlueMask, 48) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5AlphaMask, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5AlphaMask, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5AlphaMask, 52) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5CSType, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5CSType, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5CSType, 56) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5Endpoints, 36) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5Endpoints, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5Endpoints, 60) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5GammaRed, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5GammaRed, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5GammaRed, 96) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5GammaGreen, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5GammaGreen, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5GammaGreen, 100) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5GammaBlue, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5GammaBlue, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5GammaBlue, 104) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5Intent, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5Intent, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5Intent, 108) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5ProfileData, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5ProfileData, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5ProfileData, 112) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5ProfileSize, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5ProfileSize, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5ProfileSize, 116) + TEST_FIELD_SIZE (BITMAPV5HEADER, bV5Reserved, 4) + TEST_FIELD_ALIGN (BITMAPV5HEADER, bV5Reserved, 4) + TEST_FIELD_OFFSET(BITMAPV5HEADER, bV5Reserved, 120) } static void test_pack_BLENDFUNCTION(void) { /* BLENDFUNCTION (pack 4) */ - TEST_TYPE(BLENDFUNCTION, 4, 1); - TEST_FIELD(BLENDFUNCTION, BYTE, BlendOp, 0, 1, 1); - TEST_FIELD(BLENDFUNCTION, BYTE, BlendFlags, 1, 1, 1); - TEST_FIELD(BLENDFUNCTION, BYTE, SourceConstantAlpha, 2, 1, 1); - TEST_FIELD(BLENDFUNCTION, BYTE, AlphaFormat, 3, 1, 1); + TEST_TYPE_SIZE (BLENDFUNCTION, 4) + TEST_TYPE_ALIGN (BLENDFUNCTION, 1) + TEST_FIELD_SIZE (BLENDFUNCTION, BlendOp, 1) + TEST_FIELD_ALIGN (BLENDFUNCTION, BlendOp, 1) + TEST_FIELD_OFFSET(BLENDFUNCTION, BlendOp, 0) + TEST_FIELD_SIZE (BLENDFUNCTION, BlendFlags, 1) + TEST_FIELD_ALIGN (BLENDFUNCTION, BlendFlags, 1) + TEST_FIELD_OFFSET(BLENDFUNCTION, BlendFlags, 1) + TEST_FIELD_SIZE (BLENDFUNCTION, SourceConstantAlpha, 1) + TEST_FIELD_ALIGN (BLENDFUNCTION, SourceConstantAlpha, 1) + TEST_FIELD_OFFSET(BLENDFUNCTION, SourceConstantAlpha, 2) + TEST_FIELD_SIZE (BLENDFUNCTION, AlphaFormat, 1) + TEST_FIELD_ALIGN (BLENDFUNCTION, AlphaFormat, 1) + TEST_FIELD_OFFSET(BLENDFUNCTION, AlphaFormat, 3) } static void test_pack_CHARSETINFO(void) { /* CHARSETINFO (pack 4) */ - TEST_TYPE(CHARSETINFO, 32, 4); - TEST_FIELD(CHARSETINFO, UINT, ciCharset, 0, 4, 4); - TEST_FIELD(CHARSETINFO, UINT, ciACP, 4, 4, 4); - TEST_FIELD(CHARSETINFO, FONTSIGNATURE, fs, 8, 24, 4); + TEST_TYPE_SIZE (CHARSETINFO, 32) + TEST_TYPE_ALIGN (CHARSETINFO, 4) + TEST_FIELD_SIZE (CHARSETINFO, ciCharset, 4) + TEST_FIELD_ALIGN (CHARSETINFO, ciCharset, 4) + TEST_FIELD_OFFSET(CHARSETINFO, ciCharset, 0) + TEST_FIELD_SIZE (CHARSETINFO, ciACP, 4) + TEST_FIELD_ALIGN (CHARSETINFO, ciACP, 4) + TEST_FIELD_OFFSET(CHARSETINFO, ciACP, 4) + TEST_FIELD_SIZE (CHARSETINFO, fs, 24) + TEST_FIELD_ALIGN (CHARSETINFO, fs, 4) + TEST_FIELD_OFFSET(CHARSETINFO, fs, 8) } static void test_pack_CIEXYZ(void) { /* CIEXYZ (pack 4) */ - TEST_TYPE(CIEXYZ, 12, 4); - TEST_FIELD(CIEXYZ, FXPT2DOT30, ciexyzX, 0, 4, 4); - TEST_FIELD(CIEXYZ, FXPT2DOT30, ciexyzY, 4, 4, 4); - TEST_FIELD(CIEXYZ, FXPT2DOT30, ciexyzZ, 8, 4, 4); + TEST_TYPE_SIZE (CIEXYZ, 12) + TEST_TYPE_ALIGN (CIEXYZ, 4) + TEST_FIELD_SIZE (CIEXYZ, ciexyzX, 4) + TEST_FIELD_ALIGN (CIEXYZ, ciexyzX, 4) + TEST_FIELD_OFFSET(CIEXYZ, ciexyzX, 0) + TEST_FIELD_SIZE (CIEXYZ, ciexyzY, 4) + TEST_FIELD_ALIGN (CIEXYZ, ciexyzY, 4) + TEST_FIELD_OFFSET(CIEXYZ, ciexyzY, 4) + TEST_FIELD_SIZE (CIEXYZ, ciexyzZ, 4) + TEST_FIELD_ALIGN (CIEXYZ, ciexyzZ, 4) + TEST_FIELD_OFFSET(CIEXYZ, ciexyzZ, 8) } static void test_pack_CIEXYZTRIPLE(void) { /* CIEXYZTRIPLE (pack 4) */ - TEST_TYPE(CIEXYZTRIPLE, 36, 4); - TEST_FIELD(CIEXYZTRIPLE, CIEXYZ, ciexyzRed, 0, 12, 4); - TEST_FIELD(CIEXYZTRIPLE, CIEXYZ, ciexyzGreen, 12, 12, 4); - TEST_FIELD(CIEXYZTRIPLE, CIEXYZ, ciexyzBlue, 24, 12, 4); + TEST_TYPE_SIZE (CIEXYZTRIPLE, 36) + TEST_TYPE_ALIGN (CIEXYZTRIPLE, 4) + TEST_FIELD_SIZE (CIEXYZTRIPLE, ciexyzRed, 12) + TEST_FIELD_ALIGN (CIEXYZTRIPLE, ciexyzRed, 4) + TEST_FIELD_OFFSET(CIEXYZTRIPLE, ciexyzRed, 0) + TEST_FIELD_SIZE (CIEXYZTRIPLE, ciexyzGreen, 12) + TEST_FIELD_ALIGN (CIEXYZTRIPLE, ciexyzGreen, 4) + TEST_FIELD_OFFSET(CIEXYZTRIPLE, ciexyzGreen, 12) + TEST_FIELD_SIZE (CIEXYZTRIPLE, ciexyzBlue, 12) + TEST_FIELD_ALIGN (CIEXYZTRIPLE, ciexyzBlue, 4) + TEST_FIELD_OFFSET(CIEXYZTRIPLE, ciexyzBlue, 24) } static void test_pack_COLOR16(void) { /* COLOR16 */ - TEST_TYPE(COLOR16, 2, 2); + TEST_TYPE_SIZE (COLOR16, 2) + TEST_TYPE_ALIGN (COLOR16, 2) } static void test_pack_COLORADJUSTMENT(void) { /* COLORADJUSTMENT (pack 4) */ - TEST_TYPE(COLORADJUSTMENT, 24, 2); - TEST_FIELD(COLORADJUSTMENT, WORD, caSize, 0, 2, 2); - TEST_FIELD(COLORADJUSTMENT, WORD, caFlags, 2, 2, 2); - TEST_FIELD(COLORADJUSTMENT, WORD, caIlluminantIndex, 4, 2, 2); - TEST_FIELD(COLORADJUSTMENT, WORD, caRedGamma, 6, 2, 2); - TEST_FIELD(COLORADJUSTMENT, WORD, caGreenGamma, 8, 2, 2); - TEST_FIELD(COLORADJUSTMENT, WORD, caBlueGamma, 10, 2, 2); - TEST_FIELD(COLORADJUSTMENT, WORD, caReferenceBlack, 12, 2, 2); - TEST_FIELD(COLORADJUSTMENT, WORD, caReferenceWhite, 14, 2, 2); - TEST_FIELD(COLORADJUSTMENT, SHORT, caContrast, 16, 2, 2); - TEST_FIELD(COLORADJUSTMENT, SHORT, caBrightness, 18, 2, 2); - TEST_FIELD(COLORADJUSTMENT, SHORT, caColorfulness, 20, 2, 2); - TEST_FIELD(COLORADJUSTMENT, SHORT, caRedGreenTint, 22, 2, 2); + TEST_TYPE_SIZE (COLORADJUSTMENT, 24) + TEST_TYPE_ALIGN (COLORADJUSTMENT, 2) + TEST_FIELD_SIZE (COLORADJUSTMENT, caSize, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caSize, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caSize, 0) + TEST_FIELD_SIZE (COLORADJUSTMENT, caFlags, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caFlags, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caFlags, 2) + TEST_FIELD_SIZE (COLORADJUSTMENT, caIlluminantIndex, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caIlluminantIndex, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caIlluminantIndex, 4) + TEST_FIELD_SIZE (COLORADJUSTMENT, caRedGamma, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caRedGamma, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caRedGamma, 6) + TEST_FIELD_SIZE (COLORADJUSTMENT, caGreenGamma, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caGreenGamma, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caGreenGamma, 8) + TEST_FIELD_SIZE (COLORADJUSTMENT, caBlueGamma, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caBlueGamma, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caBlueGamma, 10) + TEST_FIELD_SIZE (COLORADJUSTMENT, caReferenceBlack, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caReferenceBlack, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caReferenceBlack, 12) + TEST_FIELD_SIZE (COLORADJUSTMENT, caReferenceWhite, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caReferenceWhite, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caReferenceWhite, 14) + TEST_FIELD_SIZE (COLORADJUSTMENT, caContrast, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caContrast, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caContrast, 16) + TEST_FIELD_SIZE (COLORADJUSTMENT, caBrightness, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caBrightness, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caBrightness, 18) + TEST_FIELD_SIZE (COLORADJUSTMENT, caColorfulness, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caColorfulness, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caColorfulness, 20) + TEST_FIELD_SIZE (COLORADJUSTMENT, caRedGreenTint, 2) + TEST_FIELD_ALIGN (COLORADJUSTMENT, caRedGreenTint, 2) + TEST_FIELD_OFFSET(COLORADJUSTMENT, caRedGreenTint, 22) } static void test_pack_DEVMODEA(void) { /* DEVMODEA (pack 4) */ - TEST_FIELD(DEVMODEA, BYTE[CCHDEVICENAME], dmDeviceName, 0, 32, 1); - TEST_FIELD(DEVMODEA, WORD, dmSpecVersion, 32, 2, 2); - TEST_FIELD(DEVMODEA, WORD, dmDriverVersion, 34, 2, 2); - TEST_FIELD(DEVMODEA, WORD, dmSize, 36, 2, 2); - TEST_FIELD(DEVMODEA, WORD, dmDriverExtra, 38, 2, 2); - TEST_FIELD(DEVMODEA, DWORD, dmFields, 40, 4, 4); + TEST_FIELD_SIZE (DEVMODEA, dmDeviceName, 32) + TEST_FIELD_ALIGN (DEVMODEA, dmDeviceName, 1) + TEST_FIELD_OFFSET(DEVMODEA, dmDeviceName, 0) + TEST_FIELD_SIZE (DEVMODEA, dmSpecVersion, 2) + TEST_FIELD_ALIGN (DEVMODEA, dmSpecVersion, 2) + TEST_FIELD_OFFSET(DEVMODEA, dmSpecVersion, 32) + TEST_FIELD_SIZE (DEVMODEA, dmDriverVersion, 2) + TEST_FIELD_ALIGN (DEVMODEA, dmDriverVersion, 2) + TEST_FIELD_OFFSET(DEVMODEA, dmDriverVersion, 34) + TEST_FIELD_SIZE (DEVMODEA, dmSize, 2) + TEST_FIELD_ALIGN (DEVMODEA, dmSize, 2) + TEST_FIELD_OFFSET(DEVMODEA, dmSize, 36) + TEST_FIELD_SIZE (DEVMODEA, dmDriverExtra, 2) + TEST_FIELD_ALIGN (DEVMODEA, dmDriverExtra, 2) + TEST_FIELD_OFFSET(DEVMODEA, dmDriverExtra, 38) + TEST_FIELD_SIZE (DEVMODEA, dmFields, 4) + TEST_FIELD_ALIGN (DEVMODEA, dmFields, 4) + TEST_FIELD_OFFSET(DEVMODEA, dmFields, 40) } static void test_pack_DEVMODEW(void) { /* DEVMODEW (pack 4) */ - TEST_FIELD(DEVMODEW, WCHAR[CCHDEVICENAME], dmDeviceName, 0, 64, 2); - TEST_FIELD(DEVMODEW, WORD, dmSpecVersion, 64, 2, 2); - TEST_FIELD(DEVMODEW, WORD, dmDriverVersion, 66, 2, 2); - TEST_FIELD(DEVMODEW, WORD, dmSize, 68, 2, 2); - TEST_FIELD(DEVMODEW, WORD, dmDriverExtra, 70, 2, 2); - TEST_FIELD(DEVMODEW, DWORD, dmFields, 72, 4, 4); + TEST_FIELD_SIZE (DEVMODEW, dmDeviceName, 64) + TEST_FIELD_ALIGN (DEVMODEW, dmDeviceName, 2) + TEST_FIELD_OFFSET(DEVMODEW, dmDeviceName, 0) + TEST_FIELD_SIZE (DEVMODEW, dmSpecVersion, 2) + TEST_FIELD_ALIGN (DEVMODEW, dmSpecVersion, 2) + TEST_FIELD_OFFSET(DEVMODEW, dmSpecVersion, 64) + TEST_FIELD_SIZE (DEVMODEW, dmDriverVersion, 2) + TEST_FIELD_ALIGN (DEVMODEW, dmDriverVersion, 2) + TEST_FIELD_OFFSET(DEVMODEW, dmDriverVersion, 66) + TEST_FIELD_SIZE (DEVMODEW, dmSize, 2) + TEST_FIELD_ALIGN (DEVMODEW, dmSize, 2) + TEST_FIELD_OFFSET(DEVMODEW, dmSize, 68) + TEST_FIELD_SIZE (DEVMODEW, dmDriverExtra, 2) + TEST_FIELD_ALIGN (DEVMODEW, dmDriverExtra, 2) + TEST_FIELD_OFFSET(DEVMODEW, dmDriverExtra, 70) + TEST_FIELD_SIZE (DEVMODEW, dmFields, 4) + TEST_FIELD_ALIGN (DEVMODEW, dmFields, 4) + TEST_FIELD_OFFSET(DEVMODEW, dmFields, 72) } static void test_pack_DIBSECTION(void) { /* DIBSECTION (pack 4) */ - TEST_TYPE(DIBSECTION, 84, 4); - TEST_FIELD(DIBSECTION, BITMAP, dsBm, 0, 24, 4); - TEST_FIELD(DIBSECTION, BITMAPINFOHEADER, dsBmih, 24, 40, 4); - TEST_FIELD(DIBSECTION, DWORD[3], dsBitfields, 64, 12, 4); - TEST_FIELD(DIBSECTION, HANDLE, dshSection, 76, 4, 4); - TEST_FIELD(DIBSECTION, DWORD, dsOffset, 80, 4, 4); + TEST_TYPE_SIZE (DIBSECTION, 84) + TEST_TYPE_ALIGN (DIBSECTION, 4) + TEST_FIELD_SIZE (DIBSECTION, dsBm, 24) + TEST_FIELD_ALIGN (DIBSECTION, dsBm, 4) + TEST_FIELD_OFFSET(DIBSECTION, dsBm, 0) + TEST_FIELD_SIZE (DIBSECTION, dsBmih, 40) + TEST_FIELD_ALIGN (DIBSECTION, dsBmih, 4) + TEST_FIELD_OFFSET(DIBSECTION, dsBmih, 24) + TEST_FIELD_SIZE (DIBSECTION, dsBitfields, 12) + TEST_FIELD_ALIGN (DIBSECTION, dsBitfields, 4) + TEST_FIELD_OFFSET(DIBSECTION, dsBitfields, 64) + TEST_FIELD_SIZE (DIBSECTION, dshSection, 4) + TEST_FIELD_ALIGN (DIBSECTION, dshSection, 4) + TEST_FIELD_OFFSET(DIBSECTION, dshSection, 76) + TEST_FIELD_SIZE (DIBSECTION, dsOffset, 4) + TEST_FIELD_ALIGN (DIBSECTION, dsOffset, 4) + TEST_FIELD_OFFSET(DIBSECTION, dsOffset, 80) } static void test_pack_DISPLAY_DEVICEA(void) { /* DISPLAY_DEVICEA (pack 4) */ - TEST_TYPE(DISPLAY_DEVICEA, 424, 4); - TEST_FIELD(DISPLAY_DEVICEA, DWORD, cb, 0, 4, 4); - TEST_FIELD(DISPLAY_DEVICEA, CHAR[32], DeviceName, 4, 32, 1); - TEST_FIELD(DISPLAY_DEVICEA, CHAR[128], DeviceString, 36, 128, 1); - TEST_FIELD(DISPLAY_DEVICEA, DWORD, StateFlags, 164, 4, 4); - TEST_FIELD(DISPLAY_DEVICEA, CHAR[128], DeviceID, 168, 128, 1); - TEST_FIELD(DISPLAY_DEVICEA, CHAR[128], DeviceKey, 296, 128, 1); + TEST_TYPE_SIZE (DISPLAY_DEVICEA, 424) + TEST_TYPE_ALIGN (DISPLAY_DEVICEA, 4) + TEST_FIELD_SIZE (DISPLAY_DEVICEA, cb, 4) + TEST_FIELD_ALIGN (DISPLAY_DEVICEA, cb, 4) + TEST_FIELD_OFFSET(DISPLAY_DEVICEA, cb, 0) + TEST_FIELD_SIZE (DISPLAY_DEVICEA, DeviceName, 32) + TEST_FIELD_ALIGN (DISPLAY_DEVICEA, DeviceName, 1) + TEST_FIELD_OFFSET(DISPLAY_DEVICEA, DeviceName, 4) + TEST_FIELD_SIZE (DISPLAY_DEVICEA, DeviceString, 128) + TEST_FIELD_ALIGN (DISPLAY_DEVICEA, DeviceString, 1) + TEST_FIELD_OFFSET(DISPLAY_DEVICEA, DeviceString, 36) + TEST_FIELD_SIZE (DISPLAY_DEVICEA, StateFlags, 4) + TEST_FIELD_ALIGN (DISPLAY_DEVICEA, StateFlags, 4) + TEST_FIELD_OFFSET(DISPLAY_DEVICEA, StateFlags, 164) + TEST_FIELD_SIZE (DISPLAY_DEVICEA, DeviceID, 128) + TEST_FIELD_ALIGN (DISPLAY_DEVICEA, DeviceID, 1) + TEST_FIELD_OFFSET(DISPLAY_DEVICEA, DeviceID, 168) + TEST_FIELD_SIZE (DISPLAY_DEVICEA, DeviceKey, 128) + TEST_FIELD_ALIGN (DISPLAY_DEVICEA, DeviceKey, 1) + TEST_FIELD_OFFSET(DISPLAY_DEVICEA, DeviceKey, 296) } static void test_pack_DISPLAY_DEVICEW(void) { /* DISPLAY_DEVICEW (pack 4) */ - TEST_TYPE(DISPLAY_DEVICEW, 840, 4); - TEST_FIELD(DISPLAY_DEVICEW, DWORD, cb, 0, 4, 4); - TEST_FIELD(DISPLAY_DEVICEW, WCHAR[32], DeviceName, 4, 64, 2); - TEST_FIELD(DISPLAY_DEVICEW, WCHAR[128], DeviceString, 68, 256, 2); - TEST_FIELD(DISPLAY_DEVICEW, DWORD, StateFlags, 324, 4, 4); - TEST_FIELD(DISPLAY_DEVICEW, WCHAR[128], DeviceID, 328, 256, 2); - TEST_FIELD(DISPLAY_DEVICEW, WCHAR[128], DeviceKey, 584, 256, 2); + TEST_TYPE_SIZE (DISPLAY_DEVICEW, 840) + TEST_TYPE_ALIGN (DISPLAY_DEVICEW, 4) + TEST_FIELD_SIZE (DISPLAY_DEVICEW, cb, 4) + TEST_FIELD_ALIGN (DISPLAY_DEVICEW, cb, 4) + TEST_FIELD_OFFSET(DISPLAY_DEVICEW, cb, 0) + TEST_FIELD_SIZE (DISPLAY_DEVICEW, DeviceName, 64) + TEST_FIELD_ALIGN (DISPLAY_DEVICEW, DeviceName, 2) + TEST_FIELD_OFFSET(DISPLAY_DEVICEW, DeviceName, 4) + TEST_FIELD_SIZE (DISPLAY_DEVICEW, DeviceString, 256) + TEST_FIELD_ALIGN (DISPLAY_DEVICEW, DeviceString, 2) + TEST_FIELD_OFFSET(DISPLAY_DEVICEW, DeviceString, 68) + TEST_FIELD_SIZE (DISPLAY_DEVICEW, StateFlags, 4) + TEST_FIELD_ALIGN (DISPLAY_DEVICEW, StateFlags, 4) + TEST_FIELD_OFFSET(DISPLAY_DEVICEW, StateFlags, 324) + TEST_FIELD_SIZE (DISPLAY_DEVICEW, DeviceID, 256) + TEST_FIELD_ALIGN (DISPLAY_DEVICEW, DeviceID, 2) + TEST_FIELD_OFFSET(DISPLAY_DEVICEW, DeviceID, 328) + TEST_FIELD_SIZE (DISPLAY_DEVICEW, DeviceKey, 256) + TEST_FIELD_ALIGN (DISPLAY_DEVICEW, DeviceKey, 2) + TEST_FIELD_OFFSET(DISPLAY_DEVICEW, DeviceKey, 584) } static void test_pack_DOCINFOA(void) { /* DOCINFOA (pack 4) */ - TEST_TYPE(DOCINFOA, 20, 4); - TEST_FIELD(DOCINFOA, INT, cbSize, 0, 4, 4); - TEST_FIELD(DOCINFOA, LPCSTR, lpszDocName, 4, 4, 4); - TEST_FIELD(DOCINFOA, LPCSTR, lpszOutput, 8, 4, 4); - TEST_FIELD(DOCINFOA, LPCSTR, lpszDatatype, 12, 4, 4); - TEST_FIELD(DOCINFOA, DWORD, fwType, 16, 4, 4); + TEST_TYPE_SIZE (DOCINFOA, 20) + TEST_TYPE_ALIGN (DOCINFOA, 4) + TEST_FIELD_SIZE (DOCINFOA, cbSize, 4) + TEST_FIELD_ALIGN (DOCINFOA, cbSize, 4) + TEST_FIELD_OFFSET(DOCINFOA, cbSize, 0) + TEST_FIELD_SIZE (DOCINFOA, lpszDocName, 4) + TEST_FIELD_ALIGN (DOCINFOA, lpszDocName, 4) + TEST_FIELD_OFFSET(DOCINFOA, lpszDocName, 4) + TEST_FIELD_SIZE (DOCINFOA, lpszOutput, 4) + TEST_FIELD_ALIGN (DOCINFOA, lpszOutput, 4) + TEST_FIELD_OFFSET(DOCINFOA, lpszOutput, 8) + TEST_FIELD_SIZE (DOCINFOA, lpszDatatype, 4) + TEST_FIELD_ALIGN (DOCINFOA, lpszDatatype, 4) + TEST_FIELD_OFFSET(DOCINFOA, lpszDatatype, 12) + TEST_FIELD_SIZE (DOCINFOA, fwType, 4) + TEST_FIELD_ALIGN (DOCINFOA, fwType, 4) + TEST_FIELD_OFFSET(DOCINFOA, fwType, 16) } static void test_pack_DOCINFOW(void) { /* DOCINFOW (pack 4) */ - TEST_TYPE(DOCINFOW, 20, 4); - TEST_FIELD(DOCINFOW, INT, cbSize, 0, 4, 4); - TEST_FIELD(DOCINFOW, LPCWSTR, lpszDocName, 4, 4, 4); - TEST_FIELD(DOCINFOW, LPCWSTR, lpszOutput, 8, 4, 4); - TEST_FIELD(DOCINFOW, LPCWSTR, lpszDatatype, 12, 4, 4); - TEST_FIELD(DOCINFOW, DWORD, fwType, 16, 4, 4); + TEST_TYPE_SIZE (DOCINFOW, 20) + TEST_TYPE_ALIGN (DOCINFOW, 4) + TEST_FIELD_SIZE (DOCINFOW, cbSize, 4) + TEST_FIELD_ALIGN (DOCINFOW, cbSize, 4) + TEST_FIELD_OFFSET(DOCINFOW, cbSize, 0) + TEST_FIELD_SIZE (DOCINFOW, lpszDocName, 4) + TEST_FIELD_ALIGN (DOCINFOW, lpszDocName, 4) + TEST_FIELD_OFFSET(DOCINFOW, lpszDocName, 4) + TEST_FIELD_SIZE (DOCINFOW, lpszOutput, 4) + TEST_FIELD_ALIGN (DOCINFOW, lpszOutput, 4) + TEST_FIELD_OFFSET(DOCINFOW, lpszOutput, 8) + TEST_FIELD_SIZE (DOCINFOW, lpszDatatype, 4) + TEST_FIELD_ALIGN (DOCINFOW, lpszDatatype, 4) + TEST_FIELD_OFFSET(DOCINFOW, lpszDatatype, 12) + TEST_FIELD_SIZE (DOCINFOW, fwType, 4) + TEST_FIELD_ALIGN (DOCINFOW, fwType, 4) + TEST_FIELD_OFFSET(DOCINFOW, fwType, 16) } static void test_pack_EMR(void) { /* EMR (pack 4) */ - TEST_TYPE(EMR, 8, 4); - TEST_FIELD(EMR, DWORD, iType, 0, 4, 4); - TEST_FIELD(EMR, DWORD, nSize, 4, 4, 4); + TEST_TYPE_SIZE (EMR, 8) + TEST_TYPE_ALIGN (EMR, 4) + TEST_FIELD_SIZE (EMR, iType, 4) + TEST_FIELD_ALIGN (EMR, iType, 4) + TEST_FIELD_OFFSET(EMR, iType, 0) + TEST_FIELD_SIZE (EMR, nSize, 4) + TEST_FIELD_ALIGN (EMR, nSize, 4) + TEST_FIELD_OFFSET(EMR, nSize, 4) } static void test_pack_EMRABORTPATH(void) { /* EMRABORTPATH (pack 4) */ - TEST_TYPE(EMRABORTPATH, 8, 4); - TEST_FIELD(EMRABORTPATH, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRABORTPATH, 8) + TEST_TYPE_ALIGN (EMRABORTPATH, 4) + TEST_FIELD_SIZE (EMRABORTPATH, emr, 8) + TEST_FIELD_ALIGN (EMRABORTPATH, emr, 4) + TEST_FIELD_OFFSET(EMRABORTPATH, emr, 0) } static void test_pack_EMRANGLEARC(void) { /* EMRANGLEARC (pack 4) */ - TEST_TYPE(EMRANGLEARC, 28, 4); - TEST_FIELD(EMRANGLEARC, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRANGLEARC, POINTL, ptlCenter, 8, 8, 4); - TEST_FIELD(EMRANGLEARC, DWORD, nRadius, 16, 4, 4); - TEST_FIELD(EMRANGLEARC, FLOAT, eStartAngle, 20, 4, 4); - TEST_FIELD(EMRANGLEARC, FLOAT, eSweepAngle, 24, 4, 4); + TEST_TYPE_SIZE (EMRANGLEARC, 28) + TEST_TYPE_ALIGN (EMRANGLEARC, 4) + TEST_FIELD_SIZE (EMRANGLEARC, emr, 8) + TEST_FIELD_ALIGN (EMRANGLEARC, emr, 4) + TEST_FIELD_OFFSET(EMRANGLEARC, emr, 0) + TEST_FIELD_SIZE (EMRANGLEARC, ptlCenter, 8) + TEST_FIELD_ALIGN (EMRANGLEARC, ptlCenter, 4) + TEST_FIELD_OFFSET(EMRANGLEARC, ptlCenter, 8) + TEST_FIELD_SIZE (EMRANGLEARC, nRadius, 4) + TEST_FIELD_ALIGN (EMRANGLEARC, nRadius, 4) + TEST_FIELD_OFFSET(EMRANGLEARC, nRadius, 16) + TEST_FIELD_SIZE (EMRANGLEARC, eStartAngle, 4) + TEST_FIELD_ALIGN (EMRANGLEARC, eStartAngle, 4) + TEST_FIELD_OFFSET(EMRANGLEARC, eStartAngle, 20) + TEST_FIELD_SIZE (EMRANGLEARC, eSweepAngle, 4) + TEST_FIELD_ALIGN (EMRANGLEARC, eSweepAngle, 4) + TEST_FIELD_OFFSET(EMRANGLEARC, eSweepAngle, 24) } static void test_pack_EMRARC(void) { /* EMRARC (pack 4) */ - TEST_TYPE(EMRARC, 40, 4); - TEST_FIELD(EMRARC, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRARC, RECTL, rclBox, 8, 16, 4); - TEST_FIELD(EMRARC, POINTL, ptlStart, 24, 8, 4); - TEST_FIELD(EMRARC, POINTL, ptlEnd, 32, 8, 4); + TEST_TYPE_SIZE (EMRARC, 40) + TEST_TYPE_ALIGN (EMRARC, 4) + TEST_FIELD_SIZE (EMRARC, emr, 8) + TEST_FIELD_ALIGN (EMRARC, emr, 4) + TEST_FIELD_OFFSET(EMRARC, emr, 0) + TEST_FIELD_SIZE (EMRARC, rclBox, 16) + TEST_FIELD_ALIGN (EMRARC, rclBox, 4) + TEST_FIELD_OFFSET(EMRARC, rclBox, 8) + TEST_FIELD_SIZE (EMRARC, ptlStart, 8) + TEST_FIELD_ALIGN (EMRARC, ptlStart, 4) + TEST_FIELD_OFFSET(EMRARC, ptlStart, 24) + TEST_FIELD_SIZE (EMRARC, ptlEnd, 8) + TEST_FIELD_ALIGN (EMRARC, ptlEnd, 4) + TEST_FIELD_OFFSET(EMRARC, ptlEnd, 32) } static void test_pack_EMRARCTO(void) { /* EMRARCTO (pack 4) */ - TEST_TYPE(EMRARCTO, 40, 4); - TEST_FIELD(EMRARCTO, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRARCTO, RECTL, rclBox, 8, 16, 4); - TEST_FIELD(EMRARCTO, POINTL, ptlStart, 24, 8, 4); - TEST_FIELD(EMRARCTO, POINTL, ptlEnd, 32, 8, 4); + TEST_TYPE_SIZE (EMRARCTO, 40) + TEST_TYPE_ALIGN (EMRARCTO, 4) + TEST_FIELD_SIZE (EMRARCTO, emr, 8) + TEST_FIELD_ALIGN (EMRARCTO, emr, 4) + TEST_FIELD_OFFSET(EMRARCTO, emr, 0) + TEST_FIELD_SIZE (EMRARCTO, rclBox, 16) + TEST_FIELD_ALIGN (EMRARCTO, rclBox, 4) + TEST_FIELD_OFFSET(EMRARCTO, rclBox, 8) + TEST_FIELD_SIZE (EMRARCTO, ptlStart, 8) + TEST_FIELD_ALIGN (EMRARCTO, ptlStart, 4) + TEST_FIELD_OFFSET(EMRARCTO, ptlStart, 24) + TEST_FIELD_SIZE (EMRARCTO, ptlEnd, 8) + TEST_FIELD_ALIGN (EMRARCTO, ptlEnd, 4) + TEST_FIELD_OFFSET(EMRARCTO, ptlEnd, 32) } static void test_pack_EMRBEGINPATH(void) { /* EMRBEGINPATH (pack 4) */ - TEST_TYPE(EMRBEGINPATH, 8, 4); - TEST_FIELD(EMRBEGINPATH, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRBEGINPATH, 8) + TEST_TYPE_ALIGN (EMRBEGINPATH, 4) + TEST_FIELD_SIZE (EMRBEGINPATH, emr, 8) + TEST_FIELD_ALIGN (EMRBEGINPATH, emr, 4) + TEST_FIELD_OFFSET(EMRBEGINPATH, emr, 0) } static void test_pack_EMRBITBLT(void) { /* EMRBITBLT (pack 4) */ - TEST_TYPE(EMRBITBLT, 100, 4); - TEST_FIELD(EMRBITBLT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRBITBLT, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRBITBLT, LONG, xDest, 24, 4, 4); - TEST_FIELD(EMRBITBLT, LONG, yDest, 28, 4, 4); - TEST_FIELD(EMRBITBLT, LONG, cxDest, 32, 4, 4); - TEST_FIELD(EMRBITBLT, LONG, cyDest, 36, 4, 4); - TEST_FIELD(EMRBITBLT, DWORD, dwRop, 40, 4, 4); - TEST_FIELD(EMRBITBLT, LONG, xSrc, 44, 4, 4); - TEST_FIELD(EMRBITBLT, LONG, ySrc, 48, 4, 4); - TEST_FIELD(EMRBITBLT, XFORM, xformSrc, 52, 24, 4); - TEST_FIELD(EMRBITBLT, COLORREF, crBkColorSrc, 76, 4, 4); - TEST_FIELD(EMRBITBLT, DWORD, iUsageSrc, 80, 4, 4); - TEST_FIELD(EMRBITBLT, DWORD, offBmiSrc, 84, 4, 4); - TEST_FIELD(EMRBITBLT, DWORD, cbBmiSrc, 88, 4, 4); - TEST_FIELD(EMRBITBLT, DWORD, offBitsSrc, 92, 4, 4); - TEST_FIELD(EMRBITBLT, DWORD, cbBitsSrc, 96, 4, 4); + TEST_TYPE_SIZE (EMRBITBLT, 100) + TEST_TYPE_ALIGN (EMRBITBLT, 4) + TEST_FIELD_SIZE (EMRBITBLT, emr, 8) + TEST_FIELD_ALIGN (EMRBITBLT, emr, 4) + TEST_FIELD_OFFSET(EMRBITBLT, emr, 0) + TEST_FIELD_SIZE (EMRBITBLT, rclBounds, 16) + TEST_FIELD_ALIGN (EMRBITBLT, rclBounds, 4) + TEST_FIELD_OFFSET(EMRBITBLT, rclBounds, 8) + TEST_FIELD_SIZE (EMRBITBLT, xDest, 4) + TEST_FIELD_ALIGN (EMRBITBLT, xDest, 4) + TEST_FIELD_OFFSET(EMRBITBLT, xDest, 24) + TEST_FIELD_SIZE (EMRBITBLT, yDest, 4) + TEST_FIELD_ALIGN (EMRBITBLT, yDest, 4) + TEST_FIELD_OFFSET(EMRBITBLT, yDest, 28) + TEST_FIELD_SIZE (EMRBITBLT, cxDest, 4) + TEST_FIELD_ALIGN (EMRBITBLT, cxDest, 4) + TEST_FIELD_OFFSET(EMRBITBLT, cxDest, 32) + TEST_FIELD_SIZE (EMRBITBLT, cyDest, 4) + TEST_FIELD_ALIGN (EMRBITBLT, cyDest, 4) + TEST_FIELD_OFFSET(EMRBITBLT, cyDest, 36) + TEST_FIELD_SIZE (EMRBITBLT, dwRop, 4) + TEST_FIELD_ALIGN (EMRBITBLT, dwRop, 4) + TEST_FIELD_OFFSET(EMRBITBLT, dwRop, 40) + TEST_FIELD_SIZE (EMRBITBLT, xSrc, 4) + TEST_FIELD_ALIGN (EMRBITBLT, xSrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, xSrc, 44) + TEST_FIELD_SIZE (EMRBITBLT, ySrc, 4) + TEST_FIELD_ALIGN (EMRBITBLT, ySrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, ySrc, 48) + TEST_FIELD_SIZE (EMRBITBLT, xformSrc, 24) + TEST_FIELD_ALIGN (EMRBITBLT, xformSrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, xformSrc, 52) + TEST_FIELD_SIZE (EMRBITBLT, crBkColorSrc, 4) + TEST_FIELD_ALIGN (EMRBITBLT, crBkColorSrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, crBkColorSrc, 76) + TEST_FIELD_SIZE (EMRBITBLT, iUsageSrc, 4) + TEST_FIELD_ALIGN (EMRBITBLT, iUsageSrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, iUsageSrc, 80) + TEST_FIELD_SIZE (EMRBITBLT, offBmiSrc, 4) + TEST_FIELD_ALIGN (EMRBITBLT, offBmiSrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, offBmiSrc, 84) + TEST_FIELD_SIZE (EMRBITBLT, cbBmiSrc, 4) + TEST_FIELD_ALIGN (EMRBITBLT, cbBmiSrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, cbBmiSrc, 88) + TEST_FIELD_SIZE (EMRBITBLT, offBitsSrc, 4) + TEST_FIELD_ALIGN (EMRBITBLT, offBitsSrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, offBitsSrc, 92) + TEST_FIELD_SIZE (EMRBITBLT, cbBitsSrc, 4) + TEST_FIELD_ALIGN (EMRBITBLT, cbBitsSrc, 4) + TEST_FIELD_OFFSET(EMRBITBLT, cbBitsSrc, 96) } static void test_pack_EMRCHORD(void) { /* EMRCHORD (pack 4) */ - TEST_TYPE(EMRCHORD, 40, 4); - TEST_FIELD(EMRCHORD, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRCHORD, RECTL, rclBox, 8, 16, 4); - TEST_FIELD(EMRCHORD, POINTL, ptlStart, 24, 8, 4); - TEST_FIELD(EMRCHORD, POINTL, ptlEnd, 32, 8, 4); + TEST_TYPE_SIZE (EMRCHORD, 40) + TEST_TYPE_ALIGN (EMRCHORD, 4) + TEST_FIELD_SIZE (EMRCHORD, emr, 8) + TEST_FIELD_ALIGN (EMRCHORD, emr, 4) + TEST_FIELD_OFFSET(EMRCHORD, emr, 0) + TEST_FIELD_SIZE (EMRCHORD, rclBox, 16) + TEST_FIELD_ALIGN (EMRCHORD, rclBox, 4) + TEST_FIELD_OFFSET(EMRCHORD, rclBox, 8) + TEST_FIELD_SIZE (EMRCHORD, ptlStart, 8) + TEST_FIELD_ALIGN (EMRCHORD, ptlStart, 4) + TEST_FIELD_OFFSET(EMRCHORD, ptlStart, 24) + TEST_FIELD_SIZE (EMRCHORD, ptlEnd, 8) + TEST_FIELD_ALIGN (EMRCHORD, ptlEnd, 4) + TEST_FIELD_OFFSET(EMRCHORD, ptlEnd, 32) } static void test_pack_EMRCLOSEFIGURE(void) { /* EMRCLOSEFIGURE (pack 4) */ - TEST_TYPE(EMRCLOSEFIGURE, 8, 4); - TEST_FIELD(EMRCLOSEFIGURE, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRCLOSEFIGURE, 8) + TEST_TYPE_ALIGN (EMRCLOSEFIGURE, 4) + TEST_FIELD_SIZE (EMRCLOSEFIGURE, emr, 8) + TEST_FIELD_ALIGN (EMRCLOSEFIGURE, emr, 4) + TEST_FIELD_OFFSET(EMRCLOSEFIGURE, emr, 0) } static void test_pack_EMRCREATEBRUSHINDIRECT(void) { /* EMRCREATEBRUSHINDIRECT (pack 4) */ - TEST_TYPE(EMRCREATEBRUSHINDIRECT, 24, 4); - TEST_FIELD(EMRCREATEBRUSHINDIRECT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRCREATEBRUSHINDIRECT, DWORD, ihBrush, 8, 4, 4); - TEST_FIELD(EMRCREATEBRUSHINDIRECT, LOGBRUSH32, lb, 12, 12, 4); + TEST_TYPE_SIZE (EMRCREATEBRUSHINDIRECT, 24) + TEST_TYPE_ALIGN (EMRCREATEBRUSHINDIRECT, 4) + TEST_FIELD_SIZE (EMRCREATEBRUSHINDIRECT, emr, 8) + TEST_FIELD_ALIGN (EMRCREATEBRUSHINDIRECT, emr, 4) + TEST_FIELD_OFFSET(EMRCREATEBRUSHINDIRECT, emr, 0) + TEST_FIELD_SIZE (EMRCREATEBRUSHINDIRECT, ihBrush, 4) + TEST_FIELD_ALIGN (EMRCREATEBRUSHINDIRECT, ihBrush, 4) + TEST_FIELD_OFFSET(EMRCREATEBRUSHINDIRECT, ihBrush, 8) + TEST_FIELD_SIZE (EMRCREATEBRUSHINDIRECT, lb, 12) + TEST_FIELD_ALIGN (EMRCREATEBRUSHINDIRECT, lb, 4) + TEST_FIELD_OFFSET(EMRCREATEBRUSHINDIRECT, lb, 12) } static void test_pack_EMRCREATECOLORSPACE(void) { /* EMRCREATECOLORSPACE (pack 4) */ - TEST_TYPE(EMRCREATECOLORSPACE, 340, 4); - TEST_FIELD(EMRCREATECOLORSPACE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRCREATECOLORSPACE, DWORD, ihCS, 8, 4, 4); - TEST_FIELD(EMRCREATECOLORSPACE, LOGCOLORSPACEA, lcs, 12, 328, 4); + TEST_TYPE_SIZE (EMRCREATECOLORSPACE, 340) + TEST_TYPE_ALIGN (EMRCREATECOLORSPACE, 4) + TEST_FIELD_SIZE (EMRCREATECOLORSPACE, emr, 8) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACE, emr, 4) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACE, emr, 0) + TEST_FIELD_SIZE (EMRCREATECOLORSPACE, ihCS, 4) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACE, ihCS, 4) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACE, ihCS, 8) + TEST_FIELD_SIZE (EMRCREATECOLORSPACE, lcs, 328) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACE, lcs, 4) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACE, lcs, 12) } static void test_pack_EMRCREATECOLORSPACEW(void) { /* EMRCREATECOLORSPACEW (pack 4) */ - TEST_TYPE(EMRCREATECOLORSPACEW, 612, 4); - TEST_FIELD(EMRCREATECOLORSPACEW, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRCREATECOLORSPACEW, DWORD, ihCS, 8, 4, 4); - TEST_FIELD(EMRCREATECOLORSPACEW, LOGCOLORSPACEW, lcs, 12, 588, 4); - TEST_FIELD(EMRCREATECOLORSPACEW, DWORD, dwFlags, 600, 4, 4); - TEST_FIELD(EMRCREATECOLORSPACEW, DWORD, cbData, 604, 4, 4); - TEST_FIELD(EMRCREATECOLORSPACEW, BYTE[1], Data, 608, 1, 1); + TEST_TYPE_SIZE (EMRCREATECOLORSPACEW, 612) + TEST_TYPE_ALIGN (EMRCREATECOLORSPACEW, 4) + TEST_FIELD_SIZE (EMRCREATECOLORSPACEW, emr, 8) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACEW, emr, 4) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACEW, emr, 0) + TEST_FIELD_SIZE (EMRCREATECOLORSPACEW, ihCS, 4) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACEW, ihCS, 4) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACEW, ihCS, 8) + TEST_FIELD_SIZE (EMRCREATECOLORSPACEW, lcs, 588) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACEW, lcs, 4) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACEW, lcs, 12) + TEST_FIELD_SIZE (EMRCREATECOLORSPACEW, dwFlags, 4) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACEW, dwFlags, 4) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACEW, dwFlags, 600) + TEST_FIELD_SIZE (EMRCREATECOLORSPACEW, cbData, 4) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACEW, cbData, 4) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACEW, cbData, 604) + TEST_FIELD_SIZE (EMRCREATECOLORSPACEW, Data, 1) + TEST_FIELD_ALIGN (EMRCREATECOLORSPACEW, Data, 1) + TEST_FIELD_OFFSET(EMRCREATECOLORSPACEW, Data, 608) } static void test_pack_EMRCREATEDIBPATTERNBRUSHPT(void) { /* EMRCREATEDIBPATTERNBRUSHPT (pack 4) */ - TEST_TYPE(EMRCREATEDIBPATTERNBRUSHPT, 32, 4); - TEST_FIELD(EMRCREATEDIBPATTERNBRUSHPT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRCREATEDIBPATTERNBRUSHPT, DWORD, ihBrush, 8, 4, 4); - TEST_FIELD(EMRCREATEDIBPATTERNBRUSHPT, DWORD, iUsage, 12, 4, 4); - TEST_FIELD(EMRCREATEDIBPATTERNBRUSHPT, DWORD, offBmi, 16, 4, 4); - TEST_FIELD(EMRCREATEDIBPATTERNBRUSHPT, DWORD, cbBmi, 20, 4, 4); - TEST_FIELD(EMRCREATEDIBPATTERNBRUSHPT, DWORD, offBits, 24, 4, 4); - TEST_FIELD(EMRCREATEDIBPATTERNBRUSHPT, DWORD, cbBits, 28, 4, 4); + TEST_TYPE_SIZE (EMRCREATEDIBPATTERNBRUSHPT, 32) + TEST_TYPE_ALIGN (EMRCREATEDIBPATTERNBRUSHPT, 4) + TEST_FIELD_SIZE (EMRCREATEDIBPATTERNBRUSHPT, emr, 8) + TEST_FIELD_ALIGN (EMRCREATEDIBPATTERNBRUSHPT, emr, 4) + TEST_FIELD_OFFSET(EMRCREATEDIBPATTERNBRUSHPT, emr, 0) + TEST_FIELD_SIZE (EMRCREATEDIBPATTERNBRUSHPT, ihBrush, 4) + TEST_FIELD_ALIGN (EMRCREATEDIBPATTERNBRUSHPT, ihBrush, 4) + TEST_FIELD_OFFSET(EMRCREATEDIBPATTERNBRUSHPT, ihBrush, 8) + TEST_FIELD_SIZE (EMRCREATEDIBPATTERNBRUSHPT, iUsage, 4) + TEST_FIELD_ALIGN (EMRCREATEDIBPATTERNBRUSHPT, iUsage, 4) + TEST_FIELD_OFFSET(EMRCREATEDIBPATTERNBRUSHPT, iUsage, 12) + TEST_FIELD_SIZE (EMRCREATEDIBPATTERNBRUSHPT, offBmi, 4) + TEST_FIELD_ALIGN (EMRCREATEDIBPATTERNBRUSHPT, offBmi, 4) + TEST_FIELD_OFFSET(EMRCREATEDIBPATTERNBRUSHPT, offBmi, 16) + TEST_FIELD_SIZE (EMRCREATEDIBPATTERNBRUSHPT, cbBmi, 4) + TEST_FIELD_ALIGN (EMRCREATEDIBPATTERNBRUSHPT, cbBmi, 4) + TEST_FIELD_OFFSET(EMRCREATEDIBPATTERNBRUSHPT, cbBmi, 20) + TEST_FIELD_SIZE (EMRCREATEDIBPATTERNBRUSHPT, offBits, 4) + TEST_FIELD_ALIGN (EMRCREATEDIBPATTERNBRUSHPT, offBits, 4) + TEST_FIELD_OFFSET(EMRCREATEDIBPATTERNBRUSHPT, offBits, 24) + TEST_FIELD_SIZE (EMRCREATEDIBPATTERNBRUSHPT, cbBits, 4) + TEST_FIELD_ALIGN (EMRCREATEDIBPATTERNBRUSHPT, cbBits, 4) + TEST_FIELD_OFFSET(EMRCREATEDIBPATTERNBRUSHPT, cbBits, 28) } static void test_pack_EMRCREATEMONOBRUSH(void) { /* EMRCREATEMONOBRUSH (pack 4) */ - TEST_TYPE(EMRCREATEMONOBRUSH, 32, 4); - TEST_FIELD(EMRCREATEMONOBRUSH, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRCREATEMONOBRUSH, DWORD, ihBrush, 8, 4, 4); - TEST_FIELD(EMRCREATEMONOBRUSH, DWORD, iUsage, 12, 4, 4); - TEST_FIELD(EMRCREATEMONOBRUSH, DWORD, offBmi, 16, 4, 4); - TEST_FIELD(EMRCREATEMONOBRUSH, DWORD, cbBmi, 20, 4, 4); - TEST_FIELD(EMRCREATEMONOBRUSH, DWORD, offBits, 24, 4, 4); - TEST_FIELD(EMRCREATEMONOBRUSH, DWORD, cbBits, 28, 4, 4); + TEST_TYPE_SIZE (EMRCREATEMONOBRUSH, 32) + TEST_TYPE_ALIGN (EMRCREATEMONOBRUSH, 4) + TEST_FIELD_SIZE (EMRCREATEMONOBRUSH, emr, 8) + TEST_FIELD_ALIGN (EMRCREATEMONOBRUSH, emr, 4) + TEST_FIELD_OFFSET(EMRCREATEMONOBRUSH, emr, 0) + TEST_FIELD_SIZE (EMRCREATEMONOBRUSH, ihBrush, 4) + TEST_FIELD_ALIGN (EMRCREATEMONOBRUSH, ihBrush, 4) + TEST_FIELD_OFFSET(EMRCREATEMONOBRUSH, ihBrush, 8) + TEST_FIELD_SIZE (EMRCREATEMONOBRUSH, iUsage, 4) + TEST_FIELD_ALIGN (EMRCREATEMONOBRUSH, iUsage, 4) + TEST_FIELD_OFFSET(EMRCREATEMONOBRUSH, iUsage, 12) + TEST_FIELD_SIZE (EMRCREATEMONOBRUSH, offBmi, 4) + TEST_FIELD_ALIGN (EMRCREATEMONOBRUSH, offBmi, 4) + TEST_FIELD_OFFSET(EMRCREATEMONOBRUSH, offBmi, 16) + TEST_FIELD_SIZE (EMRCREATEMONOBRUSH, cbBmi, 4) + TEST_FIELD_ALIGN (EMRCREATEMONOBRUSH, cbBmi, 4) + TEST_FIELD_OFFSET(EMRCREATEMONOBRUSH, cbBmi, 20) + TEST_FIELD_SIZE (EMRCREATEMONOBRUSH, offBits, 4) + TEST_FIELD_ALIGN (EMRCREATEMONOBRUSH, offBits, 4) + TEST_FIELD_OFFSET(EMRCREATEMONOBRUSH, offBits, 24) + TEST_FIELD_SIZE (EMRCREATEMONOBRUSH, cbBits, 4) + TEST_FIELD_ALIGN (EMRCREATEMONOBRUSH, cbBits, 4) + TEST_FIELD_OFFSET(EMRCREATEMONOBRUSH, cbBits, 28) } static void test_pack_EMRCREATEPEN(void) { /* EMRCREATEPEN (pack 4) */ - TEST_TYPE(EMRCREATEPEN, 28, 4); - TEST_FIELD(EMRCREATEPEN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRCREATEPEN, DWORD, ihPen, 8, 4, 4); - TEST_FIELD(EMRCREATEPEN, LOGPEN, lopn, 12, 16, 4); + TEST_TYPE_SIZE (EMRCREATEPEN, 28) + TEST_TYPE_ALIGN (EMRCREATEPEN, 4) + TEST_FIELD_SIZE (EMRCREATEPEN, emr, 8) + TEST_FIELD_ALIGN (EMRCREATEPEN, emr, 4) + TEST_FIELD_OFFSET(EMRCREATEPEN, emr, 0) + TEST_FIELD_SIZE (EMRCREATEPEN, ihPen, 4) + TEST_FIELD_ALIGN (EMRCREATEPEN, ihPen, 4) + TEST_FIELD_OFFSET(EMRCREATEPEN, ihPen, 8) + TEST_FIELD_SIZE (EMRCREATEPEN, lopn, 16) + TEST_FIELD_ALIGN (EMRCREATEPEN, lopn, 4) + TEST_FIELD_OFFSET(EMRCREATEPEN, lopn, 12) } static void test_pack_EMRDELETECOLORSPACE(void) { /* EMRDELETECOLORSPACE (pack 4) */ - TEST_TYPE(EMRDELETECOLORSPACE, 12, 4); - TEST_FIELD(EMRDELETECOLORSPACE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRDELETECOLORSPACE, DWORD, ihCS, 8, 4, 4); + TEST_TYPE_SIZE (EMRDELETECOLORSPACE, 12) + TEST_TYPE_ALIGN (EMRDELETECOLORSPACE, 4) + TEST_FIELD_SIZE (EMRDELETECOLORSPACE, emr, 8) + TEST_FIELD_ALIGN (EMRDELETECOLORSPACE, emr, 4) + TEST_FIELD_OFFSET(EMRDELETECOLORSPACE, emr, 0) + TEST_FIELD_SIZE (EMRDELETECOLORSPACE, ihCS, 4) + TEST_FIELD_ALIGN (EMRDELETECOLORSPACE, ihCS, 4) + TEST_FIELD_OFFSET(EMRDELETECOLORSPACE, ihCS, 8) } static void test_pack_EMRDELETEOBJECT(void) { /* EMRDELETEOBJECT (pack 4) */ - TEST_TYPE(EMRDELETEOBJECT, 12, 4); - TEST_FIELD(EMRDELETEOBJECT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRDELETEOBJECT, DWORD, ihObject, 8, 4, 4); + TEST_TYPE_SIZE (EMRDELETEOBJECT, 12) + TEST_TYPE_ALIGN (EMRDELETEOBJECT, 4) + TEST_FIELD_SIZE (EMRDELETEOBJECT, emr, 8) + TEST_FIELD_ALIGN (EMRDELETEOBJECT, emr, 4) + TEST_FIELD_OFFSET(EMRDELETEOBJECT, emr, 0) + TEST_FIELD_SIZE (EMRDELETEOBJECT, ihObject, 4) + TEST_FIELD_ALIGN (EMRDELETEOBJECT, ihObject, 4) + TEST_FIELD_OFFSET(EMRDELETEOBJECT, ihObject, 8) } static void test_pack_EMRELLIPSE(void) { /* EMRELLIPSE (pack 4) */ - TEST_TYPE(EMRELLIPSE, 24, 4); - TEST_FIELD(EMRELLIPSE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRELLIPSE, RECTL, rclBox, 8, 16, 4); + TEST_TYPE_SIZE (EMRELLIPSE, 24) + TEST_TYPE_ALIGN (EMRELLIPSE, 4) + TEST_FIELD_SIZE (EMRELLIPSE, emr, 8) + TEST_FIELD_ALIGN (EMRELLIPSE, emr, 4) + TEST_FIELD_OFFSET(EMRELLIPSE, emr, 0) + TEST_FIELD_SIZE (EMRELLIPSE, rclBox, 16) + TEST_FIELD_ALIGN (EMRELLIPSE, rclBox, 4) + TEST_FIELD_OFFSET(EMRELLIPSE, rclBox, 8) } static void test_pack_EMRENDPATH(void) { /* EMRENDPATH (pack 4) */ - TEST_TYPE(EMRENDPATH, 8, 4); - TEST_FIELD(EMRENDPATH, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRENDPATH, 8) + TEST_TYPE_ALIGN (EMRENDPATH, 4) + TEST_FIELD_SIZE (EMRENDPATH, emr, 8) + TEST_FIELD_ALIGN (EMRENDPATH, emr, 4) + TEST_FIELD_OFFSET(EMRENDPATH, emr, 0) } static void test_pack_EMREOF(void) { /* EMREOF (pack 4) */ - TEST_TYPE(EMREOF, 20, 4); - TEST_FIELD(EMREOF, EMR, emr, 0, 8, 4); - TEST_FIELD(EMREOF, DWORD, nPalEntries, 8, 4, 4); - TEST_FIELD(EMREOF, DWORD, offPalEntries, 12, 4, 4); - TEST_FIELD(EMREOF, DWORD, nSizeLast, 16, 4, 4); + TEST_TYPE_SIZE (EMREOF, 20) + TEST_TYPE_ALIGN (EMREOF, 4) + TEST_FIELD_SIZE (EMREOF, emr, 8) + TEST_FIELD_ALIGN (EMREOF, emr, 4) + TEST_FIELD_OFFSET(EMREOF, emr, 0) + TEST_FIELD_SIZE (EMREOF, nPalEntries, 4) + TEST_FIELD_ALIGN (EMREOF, nPalEntries, 4) + TEST_FIELD_OFFSET(EMREOF, nPalEntries, 8) + TEST_FIELD_SIZE (EMREOF, offPalEntries, 4) + TEST_FIELD_ALIGN (EMREOF, offPalEntries, 4) + TEST_FIELD_OFFSET(EMREOF, offPalEntries, 12) + TEST_FIELD_SIZE (EMREOF, nSizeLast, 4) + TEST_FIELD_ALIGN (EMREOF, nSizeLast, 4) + TEST_FIELD_OFFSET(EMREOF, nSizeLast, 16) } static void test_pack_EMREXCLUDECLIPRECT(void) { /* EMREXCLUDECLIPRECT (pack 4) */ - TEST_TYPE(EMREXCLUDECLIPRECT, 24, 4); - TEST_FIELD(EMREXCLUDECLIPRECT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMREXCLUDECLIPRECT, RECTL, rclClip, 8, 16, 4); + TEST_TYPE_SIZE (EMREXCLUDECLIPRECT, 24) + TEST_TYPE_ALIGN (EMREXCLUDECLIPRECT, 4) + TEST_FIELD_SIZE (EMREXCLUDECLIPRECT, emr, 8) + TEST_FIELD_ALIGN (EMREXCLUDECLIPRECT, emr, 4) + TEST_FIELD_OFFSET(EMREXCLUDECLIPRECT, emr, 0) + TEST_FIELD_SIZE (EMREXCLUDECLIPRECT, rclClip, 16) + TEST_FIELD_ALIGN (EMREXCLUDECLIPRECT, rclClip, 4) + TEST_FIELD_OFFSET(EMREXCLUDECLIPRECT, rclClip, 8) } static void test_pack_EMREXTCREATEFONTINDIRECTW(void) { /* EMREXTCREATEFONTINDIRECTW (pack 4) */ - TEST_TYPE(EMREXTCREATEFONTINDIRECTW, 332, 4); - TEST_FIELD(EMREXTCREATEFONTINDIRECTW, EMR, emr, 0, 8, 4); - TEST_FIELD(EMREXTCREATEFONTINDIRECTW, DWORD, ihFont, 8, 4, 4); - TEST_FIELD(EMREXTCREATEFONTINDIRECTW, EXTLOGFONTW, elfw, 12, 320, 4); + TEST_TYPE_SIZE (EMREXTCREATEFONTINDIRECTW, 332) + TEST_TYPE_ALIGN (EMREXTCREATEFONTINDIRECTW, 4) + TEST_FIELD_SIZE (EMREXTCREATEFONTINDIRECTW, emr, 8) + TEST_FIELD_ALIGN (EMREXTCREATEFONTINDIRECTW, emr, 4) + TEST_FIELD_OFFSET(EMREXTCREATEFONTINDIRECTW, emr, 0) + TEST_FIELD_SIZE (EMREXTCREATEFONTINDIRECTW, ihFont, 4) + TEST_FIELD_ALIGN (EMREXTCREATEFONTINDIRECTW, ihFont, 4) + TEST_FIELD_OFFSET(EMREXTCREATEFONTINDIRECTW, ihFont, 8) + TEST_FIELD_SIZE (EMREXTCREATEFONTINDIRECTW, elfw, 320) + TEST_FIELD_ALIGN (EMREXTCREATEFONTINDIRECTW, elfw, 4) + TEST_FIELD_OFFSET(EMREXTCREATEFONTINDIRECTW, elfw, 12) } static void test_pack_EMREXTCREATEPEN(void) { /* EMREXTCREATEPEN (pack 4) */ - TEST_TYPE(EMREXTCREATEPEN, 56, 4); - TEST_FIELD(EMREXTCREATEPEN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMREXTCREATEPEN, DWORD, ihPen, 8, 4, 4); - TEST_FIELD(EMREXTCREATEPEN, DWORD, offBmi, 12, 4, 4); - TEST_FIELD(EMREXTCREATEPEN, DWORD, cbBmi, 16, 4, 4); - TEST_FIELD(EMREXTCREATEPEN, DWORD, offBits, 20, 4, 4); - TEST_FIELD(EMREXTCREATEPEN, DWORD, cbBits, 24, 4, 4); - TEST_FIELD(EMREXTCREATEPEN, EXTLOGPEN, elp, 28, 28, 4); + TEST_TYPE_SIZE (EMREXTCREATEPEN, 56) + TEST_TYPE_ALIGN (EMREXTCREATEPEN, 4) + TEST_FIELD_SIZE (EMREXTCREATEPEN, emr, 8) + TEST_FIELD_ALIGN (EMREXTCREATEPEN, emr, 4) + TEST_FIELD_OFFSET(EMREXTCREATEPEN, emr, 0) + TEST_FIELD_SIZE (EMREXTCREATEPEN, ihPen, 4) + TEST_FIELD_ALIGN (EMREXTCREATEPEN, ihPen, 4) + TEST_FIELD_OFFSET(EMREXTCREATEPEN, ihPen, 8) + TEST_FIELD_SIZE (EMREXTCREATEPEN, offBmi, 4) + TEST_FIELD_ALIGN (EMREXTCREATEPEN, offBmi, 4) + TEST_FIELD_OFFSET(EMREXTCREATEPEN, offBmi, 12) + TEST_FIELD_SIZE (EMREXTCREATEPEN, cbBmi, 4) + TEST_FIELD_ALIGN (EMREXTCREATEPEN, cbBmi, 4) + TEST_FIELD_OFFSET(EMREXTCREATEPEN, cbBmi, 16) + TEST_FIELD_SIZE (EMREXTCREATEPEN, offBits, 4) + TEST_FIELD_ALIGN (EMREXTCREATEPEN, offBits, 4) + TEST_FIELD_OFFSET(EMREXTCREATEPEN, offBits, 20) + TEST_FIELD_SIZE (EMREXTCREATEPEN, cbBits, 4) + TEST_FIELD_ALIGN (EMREXTCREATEPEN, cbBits, 4) + TEST_FIELD_OFFSET(EMREXTCREATEPEN, cbBits, 24) + TEST_FIELD_SIZE (EMREXTCREATEPEN, elp, 28) + TEST_FIELD_ALIGN (EMREXTCREATEPEN, elp, 4) + TEST_FIELD_OFFSET(EMREXTCREATEPEN, elp, 28) } static void test_pack_EMREXTFLOODFILL(void) { /* EMREXTFLOODFILL (pack 4) */ - TEST_TYPE(EMREXTFLOODFILL, 24, 4); - TEST_FIELD(EMREXTFLOODFILL, EMR, emr, 0, 8, 4); - TEST_FIELD(EMREXTFLOODFILL, POINTL, ptlStart, 8, 8, 4); - TEST_FIELD(EMREXTFLOODFILL, COLORREF, crColor, 16, 4, 4); - TEST_FIELD(EMREXTFLOODFILL, DWORD, iMode, 20, 4, 4); + TEST_TYPE_SIZE (EMREXTFLOODFILL, 24) + TEST_TYPE_ALIGN (EMREXTFLOODFILL, 4) + TEST_FIELD_SIZE (EMREXTFLOODFILL, emr, 8) + TEST_FIELD_ALIGN (EMREXTFLOODFILL, emr, 4) + TEST_FIELD_OFFSET(EMREXTFLOODFILL, emr, 0) + TEST_FIELD_SIZE (EMREXTFLOODFILL, ptlStart, 8) + TEST_FIELD_ALIGN (EMREXTFLOODFILL, ptlStart, 4) + TEST_FIELD_OFFSET(EMREXTFLOODFILL, ptlStart, 8) + TEST_FIELD_SIZE (EMREXTFLOODFILL, crColor, 4) + TEST_FIELD_ALIGN (EMREXTFLOODFILL, crColor, 4) + TEST_FIELD_OFFSET(EMREXTFLOODFILL, crColor, 16) + TEST_FIELD_SIZE (EMREXTFLOODFILL, iMode, 4) + TEST_FIELD_ALIGN (EMREXTFLOODFILL, iMode, 4) + TEST_FIELD_OFFSET(EMREXTFLOODFILL, iMode, 20) } static void test_pack_EMREXTSELECTCLIPRGN(void) { /* EMREXTSELECTCLIPRGN (pack 4) */ - TEST_TYPE(EMREXTSELECTCLIPRGN, 20, 4); - TEST_FIELD(EMREXTSELECTCLIPRGN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMREXTSELECTCLIPRGN, DWORD, cbRgnData, 8, 4, 4); - TEST_FIELD(EMREXTSELECTCLIPRGN, DWORD, iMode, 12, 4, 4); - TEST_FIELD(EMREXTSELECTCLIPRGN, BYTE[1], RgnData, 16, 1, 1); + TEST_TYPE_SIZE (EMREXTSELECTCLIPRGN, 20) + TEST_TYPE_ALIGN (EMREXTSELECTCLIPRGN, 4) + TEST_FIELD_SIZE (EMREXTSELECTCLIPRGN, emr, 8) + TEST_FIELD_ALIGN (EMREXTSELECTCLIPRGN, emr, 4) + TEST_FIELD_OFFSET(EMREXTSELECTCLIPRGN, emr, 0) + TEST_FIELD_SIZE (EMREXTSELECTCLIPRGN, cbRgnData, 4) + TEST_FIELD_ALIGN (EMREXTSELECTCLIPRGN, cbRgnData, 4) + TEST_FIELD_OFFSET(EMREXTSELECTCLIPRGN, cbRgnData, 8) + TEST_FIELD_SIZE (EMREXTSELECTCLIPRGN, iMode, 4) + TEST_FIELD_ALIGN (EMREXTSELECTCLIPRGN, iMode, 4) + TEST_FIELD_OFFSET(EMREXTSELECTCLIPRGN, iMode, 12) + TEST_FIELD_SIZE (EMREXTSELECTCLIPRGN, RgnData, 1) + TEST_FIELD_ALIGN (EMREXTSELECTCLIPRGN, RgnData, 1) + TEST_FIELD_OFFSET(EMREXTSELECTCLIPRGN, RgnData, 16) } static void test_pack_EMREXTTEXTOUTA(void) { /* EMREXTTEXTOUTA (pack 4) */ - TEST_TYPE(EMREXTTEXTOUTA, 76, 4); - TEST_FIELD(EMREXTTEXTOUTA, EMR, emr, 0, 8, 4); - TEST_FIELD(EMREXTTEXTOUTA, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMREXTTEXTOUTA, DWORD, iGraphicsMode, 24, 4, 4); - TEST_FIELD(EMREXTTEXTOUTA, FLOAT, exScale, 28, 4, 4); - TEST_FIELD(EMREXTTEXTOUTA, FLOAT, eyScale, 32, 4, 4); - TEST_FIELD(EMREXTTEXTOUTA, EMRTEXT, emrtext, 36, 40, 4); + TEST_TYPE_SIZE (EMREXTTEXTOUTA, 76) + TEST_TYPE_ALIGN (EMREXTTEXTOUTA, 4) + TEST_FIELD_SIZE (EMREXTTEXTOUTA, emr, 8) + TEST_FIELD_ALIGN (EMREXTTEXTOUTA, emr, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTA, emr, 0) + TEST_FIELD_SIZE (EMREXTTEXTOUTA, rclBounds, 16) + TEST_FIELD_ALIGN (EMREXTTEXTOUTA, rclBounds, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTA, rclBounds, 8) + TEST_FIELD_SIZE (EMREXTTEXTOUTA, iGraphicsMode, 4) + TEST_FIELD_ALIGN (EMREXTTEXTOUTA, iGraphicsMode, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTA, iGraphicsMode, 24) + TEST_FIELD_SIZE (EMREXTTEXTOUTA, exScale, 4) + TEST_FIELD_ALIGN (EMREXTTEXTOUTA, exScale, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTA, exScale, 28) + TEST_FIELD_SIZE (EMREXTTEXTOUTA, eyScale, 4) + TEST_FIELD_ALIGN (EMREXTTEXTOUTA, eyScale, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTA, eyScale, 32) + TEST_FIELD_SIZE (EMREXTTEXTOUTA, emrtext, 40) + TEST_FIELD_ALIGN (EMREXTTEXTOUTA, emrtext, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTA, emrtext, 36) } static void test_pack_EMREXTTEXTOUTW(void) { /* EMREXTTEXTOUTW (pack 4) */ - TEST_TYPE(EMREXTTEXTOUTW, 76, 4); - TEST_FIELD(EMREXTTEXTOUTW, EMR, emr, 0, 8, 4); - TEST_FIELD(EMREXTTEXTOUTW, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMREXTTEXTOUTW, DWORD, iGraphicsMode, 24, 4, 4); - TEST_FIELD(EMREXTTEXTOUTW, FLOAT, exScale, 28, 4, 4); - TEST_FIELD(EMREXTTEXTOUTW, FLOAT, eyScale, 32, 4, 4); - TEST_FIELD(EMREXTTEXTOUTW, EMRTEXT, emrtext, 36, 40, 4); + TEST_TYPE_SIZE (EMREXTTEXTOUTW, 76) + TEST_TYPE_ALIGN (EMREXTTEXTOUTW, 4) + TEST_FIELD_SIZE (EMREXTTEXTOUTW, emr, 8) + TEST_FIELD_ALIGN (EMREXTTEXTOUTW, emr, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTW, emr, 0) + TEST_FIELD_SIZE (EMREXTTEXTOUTW, rclBounds, 16) + TEST_FIELD_ALIGN (EMREXTTEXTOUTW, rclBounds, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTW, rclBounds, 8) + TEST_FIELD_SIZE (EMREXTTEXTOUTW, iGraphicsMode, 4) + TEST_FIELD_ALIGN (EMREXTTEXTOUTW, iGraphicsMode, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTW, iGraphicsMode, 24) + TEST_FIELD_SIZE (EMREXTTEXTOUTW, exScale, 4) + TEST_FIELD_ALIGN (EMREXTTEXTOUTW, exScale, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTW, exScale, 28) + TEST_FIELD_SIZE (EMREXTTEXTOUTW, eyScale, 4) + TEST_FIELD_ALIGN (EMREXTTEXTOUTW, eyScale, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTW, eyScale, 32) + TEST_FIELD_SIZE (EMREXTTEXTOUTW, emrtext, 40) + TEST_FIELD_ALIGN (EMREXTTEXTOUTW, emrtext, 4) + TEST_FIELD_OFFSET(EMREXTTEXTOUTW, emrtext, 36) } static void test_pack_EMRFILLPATH(void) { /* EMRFILLPATH (pack 4) */ - TEST_TYPE(EMRFILLPATH, 24, 4); - TEST_FIELD(EMRFILLPATH, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRFILLPATH, RECTL, rclBounds, 8, 16, 4); + TEST_TYPE_SIZE (EMRFILLPATH, 24) + TEST_TYPE_ALIGN (EMRFILLPATH, 4) + TEST_FIELD_SIZE (EMRFILLPATH, emr, 8) + TEST_FIELD_ALIGN (EMRFILLPATH, emr, 4) + TEST_FIELD_OFFSET(EMRFILLPATH, emr, 0) + TEST_FIELD_SIZE (EMRFILLPATH, rclBounds, 16) + TEST_FIELD_ALIGN (EMRFILLPATH, rclBounds, 4) + TEST_FIELD_OFFSET(EMRFILLPATH, rclBounds, 8) } static void test_pack_EMRFILLRGN(void) { /* EMRFILLRGN (pack 4) */ - TEST_TYPE(EMRFILLRGN, 36, 4); - TEST_FIELD(EMRFILLRGN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRFILLRGN, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRFILLRGN, DWORD, cbRgnData, 24, 4, 4); - TEST_FIELD(EMRFILLRGN, DWORD, ihBrush, 28, 4, 4); - TEST_FIELD(EMRFILLRGN, BYTE[1], RgnData, 32, 1, 1); + TEST_TYPE_SIZE (EMRFILLRGN, 36) + TEST_TYPE_ALIGN (EMRFILLRGN, 4) + TEST_FIELD_SIZE (EMRFILLRGN, emr, 8) + TEST_FIELD_ALIGN (EMRFILLRGN, emr, 4) + TEST_FIELD_OFFSET(EMRFILLRGN, emr, 0) + TEST_FIELD_SIZE (EMRFILLRGN, rclBounds, 16) + TEST_FIELD_ALIGN (EMRFILLRGN, rclBounds, 4) + TEST_FIELD_OFFSET(EMRFILLRGN, rclBounds, 8) + TEST_FIELD_SIZE (EMRFILLRGN, cbRgnData, 4) + TEST_FIELD_ALIGN (EMRFILLRGN, cbRgnData, 4) + TEST_FIELD_OFFSET(EMRFILLRGN, cbRgnData, 24) + TEST_FIELD_SIZE (EMRFILLRGN, ihBrush, 4) + TEST_FIELD_ALIGN (EMRFILLRGN, ihBrush, 4) + TEST_FIELD_OFFSET(EMRFILLRGN, ihBrush, 28) + TEST_FIELD_SIZE (EMRFILLRGN, RgnData, 1) + TEST_FIELD_ALIGN (EMRFILLRGN, RgnData, 1) + TEST_FIELD_OFFSET(EMRFILLRGN, RgnData, 32) } static void test_pack_EMRFLATTENPATH(void) { /* EMRFLATTENPATH (pack 4) */ - TEST_TYPE(EMRFLATTENPATH, 8, 4); - TEST_FIELD(EMRFLATTENPATH, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRFLATTENPATH, 8) + TEST_TYPE_ALIGN (EMRFLATTENPATH, 4) + TEST_FIELD_SIZE (EMRFLATTENPATH, emr, 8) + TEST_FIELD_ALIGN (EMRFLATTENPATH, emr, 4) + TEST_FIELD_OFFSET(EMRFLATTENPATH, emr, 0) } static void test_pack_EMRFORMAT(void) { /* EMRFORMAT (pack 4) */ - TEST_TYPE(EMRFORMAT, 16, 4); - TEST_FIELD(EMRFORMAT, DWORD, dSignature, 0, 4, 4); - TEST_FIELD(EMRFORMAT, DWORD, nVersion, 4, 4, 4); - TEST_FIELD(EMRFORMAT, DWORD, cbData, 8, 4, 4); - TEST_FIELD(EMRFORMAT, DWORD, offData, 12, 4, 4); + TEST_TYPE_SIZE (EMRFORMAT, 16) + TEST_TYPE_ALIGN (EMRFORMAT, 4) + TEST_FIELD_SIZE (EMRFORMAT, dSignature, 4) + TEST_FIELD_ALIGN (EMRFORMAT, dSignature, 4) + TEST_FIELD_OFFSET(EMRFORMAT, dSignature, 0) + TEST_FIELD_SIZE (EMRFORMAT, nVersion, 4) + TEST_FIELD_ALIGN (EMRFORMAT, nVersion, 4) + TEST_FIELD_OFFSET(EMRFORMAT, nVersion, 4) + TEST_FIELD_SIZE (EMRFORMAT, cbData, 4) + TEST_FIELD_ALIGN (EMRFORMAT, cbData, 4) + TEST_FIELD_OFFSET(EMRFORMAT, cbData, 8) + TEST_FIELD_SIZE (EMRFORMAT, offData, 4) + TEST_FIELD_ALIGN (EMRFORMAT, offData, 4) + TEST_FIELD_OFFSET(EMRFORMAT, offData, 12) } static void test_pack_EMRFRAMERGN(void) { /* EMRFRAMERGN (pack 4) */ - TEST_TYPE(EMRFRAMERGN, 44, 4); - TEST_FIELD(EMRFRAMERGN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRFRAMERGN, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRFRAMERGN, DWORD, cbRgnData, 24, 4, 4); - TEST_FIELD(EMRFRAMERGN, DWORD, ihBrush, 28, 4, 4); - TEST_FIELD(EMRFRAMERGN, SIZEL, szlStroke, 32, 8, 4); - TEST_FIELD(EMRFRAMERGN, BYTE[1], RgnData, 40, 1, 1); + TEST_TYPE_SIZE (EMRFRAMERGN, 44) + TEST_TYPE_ALIGN (EMRFRAMERGN, 4) + TEST_FIELD_SIZE (EMRFRAMERGN, emr, 8) + TEST_FIELD_ALIGN (EMRFRAMERGN, emr, 4) + TEST_FIELD_OFFSET(EMRFRAMERGN, emr, 0) + TEST_FIELD_SIZE (EMRFRAMERGN, rclBounds, 16) + TEST_FIELD_ALIGN (EMRFRAMERGN, rclBounds, 4) + TEST_FIELD_OFFSET(EMRFRAMERGN, rclBounds, 8) + TEST_FIELD_SIZE (EMRFRAMERGN, cbRgnData, 4) + TEST_FIELD_ALIGN (EMRFRAMERGN, cbRgnData, 4) + TEST_FIELD_OFFSET(EMRFRAMERGN, cbRgnData, 24) + TEST_FIELD_SIZE (EMRFRAMERGN, ihBrush, 4) + TEST_FIELD_ALIGN (EMRFRAMERGN, ihBrush, 4) + TEST_FIELD_OFFSET(EMRFRAMERGN, ihBrush, 28) + TEST_FIELD_SIZE (EMRFRAMERGN, szlStroke, 8) + TEST_FIELD_ALIGN (EMRFRAMERGN, szlStroke, 4) + TEST_FIELD_OFFSET(EMRFRAMERGN, szlStroke, 32) + TEST_FIELD_SIZE (EMRFRAMERGN, RgnData, 1) + TEST_FIELD_ALIGN (EMRFRAMERGN, RgnData, 1) + TEST_FIELD_OFFSET(EMRFRAMERGN, RgnData, 40) } static void test_pack_EMRGDICOMMENT(void) { /* EMRGDICOMMENT (pack 4) */ - TEST_TYPE(EMRGDICOMMENT, 16, 4); - TEST_FIELD(EMRGDICOMMENT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRGDICOMMENT, DWORD, cbData, 8, 4, 4); - TEST_FIELD(EMRGDICOMMENT, BYTE[1], Data, 12, 1, 1); + TEST_TYPE_SIZE (EMRGDICOMMENT, 16) + TEST_TYPE_ALIGN (EMRGDICOMMENT, 4) + TEST_FIELD_SIZE (EMRGDICOMMENT, emr, 8) + TEST_FIELD_ALIGN (EMRGDICOMMENT, emr, 4) + TEST_FIELD_OFFSET(EMRGDICOMMENT, emr, 0) + TEST_FIELD_SIZE (EMRGDICOMMENT, cbData, 4) + TEST_FIELD_ALIGN (EMRGDICOMMENT, cbData, 4) + TEST_FIELD_OFFSET(EMRGDICOMMENT, cbData, 8) + TEST_FIELD_SIZE (EMRGDICOMMENT, Data, 1) + TEST_FIELD_ALIGN (EMRGDICOMMENT, Data, 1) + TEST_FIELD_OFFSET(EMRGDICOMMENT, Data, 12) } static void test_pack_EMRGLSBOUNDEDRECORD(void) { /* EMRGLSBOUNDEDRECORD (pack 4) */ - TEST_TYPE(EMRGLSBOUNDEDRECORD, 32, 4); - TEST_FIELD(EMRGLSBOUNDEDRECORD, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRGLSBOUNDEDRECORD, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRGLSBOUNDEDRECORD, DWORD, cbData, 24, 4, 4); - TEST_FIELD(EMRGLSBOUNDEDRECORD, BYTE[1], Data, 28, 1, 1); + TEST_TYPE_SIZE (EMRGLSBOUNDEDRECORD, 32) + TEST_TYPE_ALIGN (EMRGLSBOUNDEDRECORD, 4) + TEST_FIELD_SIZE (EMRGLSBOUNDEDRECORD, emr, 8) + TEST_FIELD_ALIGN (EMRGLSBOUNDEDRECORD, emr, 4) + TEST_FIELD_OFFSET(EMRGLSBOUNDEDRECORD, emr, 0) + TEST_FIELD_SIZE (EMRGLSBOUNDEDRECORD, rclBounds, 16) + TEST_FIELD_ALIGN (EMRGLSBOUNDEDRECORD, rclBounds, 4) + TEST_FIELD_OFFSET(EMRGLSBOUNDEDRECORD, rclBounds, 8) + TEST_FIELD_SIZE (EMRGLSBOUNDEDRECORD, cbData, 4) + TEST_FIELD_ALIGN (EMRGLSBOUNDEDRECORD, cbData, 4) + TEST_FIELD_OFFSET(EMRGLSBOUNDEDRECORD, cbData, 24) + TEST_FIELD_SIZE (EMRGLSBOUNDEDRECORD, Data, 1) + TEST_FIELD_ALIGN (EMRGLSBOUNDEDRECORD, Data, 1) + TEST_FIELD_OFFSET(EMRGLSBOUNDEDRECORD, Data, 28) } static void test_pack_EMRGLSRECORD(void) { /* EMRGLSRECORD (pack 4) */ - TEST_TYPE(EMRGLSRECORD, 16, 4); - TEST_FIELD(EMRGLSRECORD, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRGLSRECORD, DWORD, cbData, 8, 4, 4); - TEST_FIELD(EMRGLSRECORD, BYTE[1], Data, 12, 1, 1); + TEST_TYPE_SIZE (EMRGLSRECORD, 16) + TEST_TYPE_ALIGN (EMRGLSRECORD, 4) + TEST_FIELD_SIZE (EMRGLSRECORD, emr, 8) + TEST_FIELD_ALIGN (EMRGLSRECORD, emr, 4) + TEST_FIELD_OFFSET(EMRGLSRECORD, emr, 0) + TEST_FIELD_SIZE (EMRGLSRECORD, cbData, 4) + TEST_FIELD_ALIGN (EMRGLSRECORD, cbData, 4) + TEST_FIELD_OFFSET(EMRGLSRECORD, cbData, 8) + TEST_FIELD_SIZE (EMRGLSRECORD, Data, 1) + TEST_FIELD_ALIGN (EMRGLSRECORD, Data, 1) + TEST_FIELD_OFFSET(EMRGLSRECORD, Data, 12) } static void test_pack_EMRINTERSECTCLIPRECT(void) { /* EMRINTERSECTCLIPRECT (pack 4) */ - TEST_TYPE(EMRINTERSECTCLIPRECT, 24, 4); - TEST_FIELD(EMRINTERSECTCLIPRECT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRINTERSECTCLIPRECT, RECTL, rclClip, 8, 16, 4); + TEST_TYPE_SIZE (EMRINTERSECTCLIPRECT, 24) + TEST_TYPE_ALIGN (EMRINTERSECTCLIPRECT, 4) + TEST_FIELD_SIZE (EMRINTERSECTCLIPRECT, emr, 8) + TEST_FIELD_ALIGN (EMRINTERSECTCLIPRECT, emr, 4) + TEST_FIELD_OFFSET(EMRINTERSECTCLIPRECT, emr, 0) + TEST_FIELD_SIZE (EMRINTERSECTCLIPRECT, rclClip, 16) + TEST_FIELD_ALIGN (EMRINTERSECTCLIPRECT, rclClip, 4) + TEST_FIELD_OFFSET(EMRINTERSECTCLIPRECT, rclClip, 8) } static void test_pack_EMRINVERTRGN(void) { /* EMRINVERTRGN (pack 4) */ - TEST_TYPE(EMRINVERTRGN, 32, 4); - TEST_FIELD(EMRINVERTRGN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRINVERTRGN, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRINVERTRGN, DWORD, cbRgnData, 24, 4, 4); - TEST_FIELD(EMRINVERTRGN, BYTE[1], RgnData, 28, 1, 1); + TEST_TYPE_SIZE (EMRINVERTRGN, 32) + TEST_TYPE_ALIGN (EMRINVERTRGN, 4) + TEST_FIELD_SIZE (EMRINVERTRGN, emr, 8) + TEST_FIELD_ALIGN (EMRINVERTRGN, emr, 4) + TEST_FIELD_OFFSET(EMRINVERTRGN, emr, 0) + TEST_FIELD_SIZE (EMRINVERTRGN, rclBounds, 16) + TEST_FIELD_ALIGN (EMRINVERTRGN, rclBounds, 4) + TEST_FIELD_OFFSET(EMRINVERTRGN, rclBounds, 8) + TEST_FIELD_SIZE (EMRINVERTRGN, cbRgnData, 4) + TEST_FIELD_ALIGN (EMRINVERTRGN, cbRgnData, 4) + TEST_FIELD_OFFSET(EMRINVERTRGN, cbRgnData, 24) + TEST_FIELD_SIZE (EMRINVERTRGN, RgnData, 1) + TEST_FIELD_ALIGN (EMRINVERTRGN, RgnData, 1) + TEST_FIELD_OFFSET(EMRINVERTRGN, RgnData, 28) } static void test_pack_EMRLINETO(void) { /* EMRLINETO (pack 4) */ - TEST_TYPE(EMRLINETO, 16, 4); - TEST_FIELD(EMRLINETO, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRLINETO, POINTL, ptl, 8, 8, 4); + TEST_TYPE_SIZE (EMRLINETO, 16) + TEST_TYPE_ALIGN (EMRLINETO, 4) + TEST_FIELD_SIZE (EMRLINETO, emr, 8) + TEST_FIELD_ALIGN (EMRLINETO, emr, 4) + TEST_FIELD_OFFSET(EMRLINETO, emr, 0) + TEST_FIELD_SIZE (EMRLINETO, ptl, 8) + TEST_FIELD_ALIGN (EMRLINETO, ptl, 4) + TEST_FIELD_OFFSET(EMRLINETO, ptl, 8) } static void test_pack_EMRMASKBLT(void) { /* EMRMASKBLT (pack 4) */ - TEST_TYPE(EMRMASKBLT, 128, 4); - TEST_FIELD(EMRMASKBLT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRMASKBLT, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRMASKBLT, LONG, xDest, 24, 4, 4); - TEST_FIELD(EMRMASKBLT, LONG, yDest, 28, 4, 4); - TEST_FIELD(EMRMASKBLT, LONG, cxDest, 32, 4, 4); - TEST_FIELD(EMRMASKBLT, LONG, cyDest, 36, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, dwRop, 40, 4, 4); - TEST_FIELD(EMRMASKBLT, LONG, xSrc, 44, 4, 4); - TEST_FIELD(EMRMASKBLT, LONG, ySrc, 48, 4, 4); - TEST_FIELD(EMRMASKBLT, XFORM, xformSrc, 52, 24, 4); - TEST_FIELD(EMRMASKBLT, COLORREF, crBkColorSrc, 76, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, iUsageSrc, 80, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, offBmiSrc, 84, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, cbBmiSrc, 88, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, offBitsSrc, 92, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, cbBitsSrc, 96, 4, 4); - TEST_FIELD(EMRMASKBLT, LONG, xMask, 100, 4, 4); - TEST_FIELD(EMRMASKBLT, LONG, yMask, 104, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, iUsageMask, 108, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, offBmiMask, 112, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, cbBmiMask, 116, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, offBitsMask, 120, 4, 4); - TEST_FIELD(EMRMASKBLT, DWORD, cbBitsMask, 124, 4, 4); + TEST_TYPE_SIZE (EMRMASKBLT, 128) + TEST_TYPE_ALIGN (EMRMASKBLT, 4) + TEST_FIELD_SIZE (EMRMASKBLT, emr, 8) + TEST_FIELD_ALIGN (EMRMASKBLT, emr, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, emr, 0) + TEST_FIELD_SIZE (EMRMASKBLT, rclBounds, 16) + TEST_FIELD_ALIGN (EMRMASKBLT, rclBounds, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, rclBounds, 8) + TEST_FIELD_SIZE (EMRMASKBLT, xDest, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, xDest, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, xDest, 24) + TEST_FIELD_SIZE (EMRMASKBLT, yDest, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, yDest, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, yDest, 28) + TEST_FIELD_SIZE (EMRMASKBLT, cxDest, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, cxDest, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, cxDest, 32) + TEST_FIELD_SIZE (EMRMASKBLT, cyDest, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, cyDest, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, cyDest, 36) + TEST_FIELD_SIZE (EMRMASKBLT, dwRop, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, dwRop, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, dwRop, 40) + TEST_FIELD_SIZE (EMRMASKBLT, xSrc, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, xSrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, xSrc, 44) + TEST_FIELD_SIZE (EMRMASKBLT, ySrc, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, ySrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, ySrc, 48) + TEST_FIELD_SIZE (EMRMASKBLT, xformSrc, 24) + TEST_FIELD_ALIGN (EMRMASKBLT, xformSrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, xformSrc, 52) + TEST_FIELD_SIZE (EMRMASKBLT, crBkColorSrc, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, crBkColorSrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, crBkColorSrc, 76) + TEST_FIELD_SIZE (EMRMASKBLT, iUsageSrc, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, iUsageSrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, iUsageSrc, 80) + TEST_FIELD_SIZE (EMRMASKBLT, offBmiSrc, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, offBmiSrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, offBmiSrc, 84) + TEST_FIELD_SIZE (EMRMASKBLT, cbBmiSrc, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, cbBmiSrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, cbBmiSrc, 88) + TEST_FIELD_SIZE (EMRMASKBLT, offBitsSrc, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, offBitsSrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, offBitsSrc, 92) + TEST_FIELD_SIZE (EMRMASKBLT, cbBitsSrc, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, cbBitsSrc, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, cbBitsSrc, 96) + TEST_FIELD_SIZE (EMRMASKBLT, xMask, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, xMask, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, xMask, 100) + TEST_FIELD_SIZE (EMRMASKBLT, yMask, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, yMask, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, yMask, 104) + TEST_FIELD_SIZE (EMRMASKBLT, iUsageMask, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, iUsageMask, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, iUsageMask, 108) + TEST_FIELD_SIZE (EMRMASKBLT, offBmiMask, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, offBmiMask, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, offBmiMask, 112) + TEST_FIELD_SIZE (EMRMASKBLT, cbBmiMask, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, cbBmiMask, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, cbBmiMask, 116) + TEST_FIELD_SIZE (EMRMASKBLT, offBitsMask, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, offBitsMask, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, offBitsMask, 120) + TEST_FIELD_SIZE (EMRMASKBLT, cbBitsMask, 4) + TEST_FIELD_ALIGN (EMRMASKBLT, cbBitsMask, 4) + TEST_FIELD_OFFSET(EMRMASKBLT, cbBitsMask, 124) } static void test_pack_EMRMODIFYWORLDTRANSFORM(void) { /* EMRMODIFYWORLDTRANSFORM (pack 4) */ - TEST_TYPE(EMRMODIFYWORLDTRANSFORM, 36, 4); - TEST_FIELD(EMRMODIFYWORLDTRANSFORM, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRMODIFYWORLDTRANSFORM, XFORM, xform, 8, 24, 4); - TEST_FIELD(EMRMODIFYWORLDTRANSFORM, DWORD, iMode, 32, 4, 4); + TEST_TYPE_SIZE (EMRMODIFYWORLDTRANSFORM, 36) + TEST_TYPE_ALIGN (EMRMODIFYWORLDTRANSFORM, 4) + TEST_FIELD_SIZE (EMRMODIFYWORLDTRANSFORM, emr, 8) + TEST_FIELD_ALIGN (EMRMODIFYWORLDTRANSFORM, emr, 4) + TEST_FIELD_OFFSET(EMRMODIFYWORLDTRANSFORM, emr, 0) + TEST_FIELD_SIZE (EMRMODIFYWORLDTRANSFORM, xform, 24) + TEST_FIELD_ALIGN (EMRMODIFYWORLDTRANSFORM, xform, 4) + TEST_FIELD_OFFSET(EMRMODIFYWORLDTRANSFORM, xform, 8) + TEST_FIELD_SIZE (EMRMODIFYWORLDTRANSFORM, iMode, 4) + TEST_FIELD_ALIGN (EMRMODIFYWORLDTRANSFORM, iMode, 4) + TEST_FIELD_OFFSET(EMRMODIFYWORLDTRANSFORM, iMode, 32) } static void test_pack_EMRMOVETOEX(void) { /* EMRMOVETOEX (pack 4) */ - TEST_TYPE(EMRMOVETOEX, 16, 4); - TEST_FIELD(EMRMOVETOEX, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRMOVETOEX, POINTL, ptl, 8, 8, 4); + TEST_TYPE_SIZE (EMRMOVETOEX, 16) + TEST_TYPE_ALIGN (EMRMOVETOEX, 4) + TEST_FIELD_SIZE (EMRMOVETOEX, emr, 8) + TEST_FIELD_ALIGN (EMRMOVETOEX, emr, 4) + TEST_FIELD_OFFSET(EMRMOVETOEX, emr, 0) + TEST_FIELD_SIZE (EMRMOVETOEX, ptl, 8) + TEST_FIELD_ALIGN (EMRMOVETOEX, ptl, 4) + TEST_FIELD_OFFSET(EMRMOVETOEX, ptl, 8) } static void test_pack_EMROFFSETCLIPRGN(void) { /* EMROFFSETCLIPRGN (pack 4) */ - TEST_TYPE(EMROFFSETCLIPRGN, 16, 4); - TEST_FIELD(EMROFFSETCLIPRGN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMROFFSETCLIPRGN, POINTL, ptlOffset, 8, 8, 4); + TEST_TYPE_SIZE (EMROFFSETCLIPRGN, 16) + TEST_TYPE_ALIGN (EMROFFSETCLIPRGN, 4) + TEST_FIELD_SIZE (EMROFFSETCLIPRGN, emr, 8) + TEST_FIELD_ALIGN (EMROFFSETCLIPRGN, emr, 4) + TEST_FIELD_OFFSET(EMROFFSETCLIPRGN, emr, 0) + TEST_FIELD_SIZE (EMROFFSETCLIPRGN, ptlOffset, 8) + TEST_FIELD_ALIGN (EMROFFSETCLIPRGN, ptlOffset, 4) + TEST_FIELD_OFFSET(EMROFFSETCLIPRGN, ptlOffset, 8) } static void test_pack_EMRPAINTRGN(void) { /* EMRPAINTRGN (pack 4) */ - TEST_TYPE(EMRPAINTRGN, 32, 4); - TEST_FIELD(EMRPAINTRGN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPAINTRGN, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPAINTRGN, DWORD, cbRgnData, 24, 4, 4); - TEST_FIELD(EMRPAINTRGN, BYTE[1], RgnData, 28, 1, 1); + TEST_TYPE_SIZE (EMRPAINTRGN, 32) + TEST_TYPE_ALIGN (EMRPAINTRGN, 4) + TEST_FIELD_SIZE (EMRPAINTRGN, emr, 8) + TEST_FIELD_ALIGN (EMRPAINTRGN, emr, 4) + TEST_FIELD_OFFSET(EMRPAINTRGN, emr, 0) + TEST_FIELD_SIZE (EMRPAINTRGN, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPAINTRGN, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPAINTRGN, rclBounds, 8) + TEST_FIELD_SIZE (EMRPAINTRGN, cbRgnData, 4) + TEST_FIELD_ALIGN (EMRPAINTRGN, cbRgnData, 4) + TEST_FIELD_OFFSET(EMRPAINTRGN, cbRgnData, 24) + TEST_FIELD_SIZE (EMRPAINTRGN, RgnData, 1) + TEST_FIELD_ALIGN (EMRPAINTRGN, RgnData, 1) + TEST_FIELD_OFFSET(EMRPAINTRGN, RgnData, 28) } static void test_pack_EMRPIE(void) { /* EMRPIE (pack 4) */ - TEST_TYPE(EMRPIE, 40, 4); - TEST_FIELD(EMRPIE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPIE, RECTL, rclBox, 8, 16, 4); - TEST_FIELD(EMRPIE, POINTL, ptlStart, 24, 8, 4); - TEST_FIELD(EMRPIE, POINTL, ptlEnd, 32, 8, 4); + TEST_TYPE_SIZE (EMRPIE, 40) + TEST_TYPE_ALIGN (EMRPIE, 4) + TEST_FIELD_SIZE (EMRPIE, emr, 8) + TEST_FIELD_ALIGN (EMRPIE, emr, 4) + TEST_FIELD_OFFSET(EMRPIE, emr, 0) + TEST_FIELD_SIZE (EMRPIE, rclBox, 16) + TEST_FIELD_ALIGN (EMRPIE, rclBox, 4) + TEST_FIELD_OFFSET(EMRPIE, rclBox, 8) + TEST_FIELD_SIZE (EMRPIE, ptlStart, 8) + TEST_FIELD_ALIGN (EMRPIE, ptlStart, 4) + TEST_FIELD_OFFSET(EMRPIE, ptlStart, 24) + TEST_FIELD_SIZE (EMRPIE, ptlEnd, 8) + TEST_FIELD_ALIGN (EMRPIE, ptlEnd, 4) + TEST_FIELD_OFFSET(EMRPIE, ptlEnd, 32) } static void test_pack_EMRPIXELFORMAT(void) { /* EMRPIXELFORMAT (pack 4) */ - TEST_TYPE(EMRPIXELFORMAT, 48, 4); - TEST_FIELD(EMRPIXELFORMAT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPIXELFORMAT, PIXELFORMATDESCRIPTOR, pfd, 8, 40, 4); + TEST_TYPE_SIZE (EMRPIXELFORMAT, 48) + TEST_TYPE_ALIGN (EMRPIXELFORMAT, 4) + TEST_FIELD_SIZE (EMRPIXELFORMAT, emr, 8) + TEST_FIELD_ALIGN (EMRPIXELFORMAT, emr, 4) + TEST_FIELD_OFFSET(EMRPIXELFORMAT, emr, 0) + TEST_FIELD_SIZE (EMRPIXELFORMAT, pfd, 40) + TEST_FIELD_ALIGN (EMRPIXELFORMAT, pfd, 4) + TEST_FIELD_OFFSET(EMRPIXELFORMAT, pfd, 8) } static void test_pack_EMRPLGBLT(void) { /* EMRPLGBLT (pack 4) */ - TEST_TYPE(EMRPLGBLT, 140, 4); - TEST_FIELD(EMRPLGBLT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPLGBLT, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPLGBLT, POINTL[3], aptlDest, 24, 24, 4); - TEST_FIELD(EMRPLGBLT, LONG, xSrc, 48, 4, 4); - TEST_FIELD(EMRPLGBLT, LONG, ySrc, 52, 4, 4); - TEST_FIELD(EMRPLGBLT, LONG, cxSrc, 56, 4, 4); - TEST_FIELD(EMRPLGBLT, LONG, cySrc, 60, 4, 4); - TEST_FIELD(EMRPLGBLT, XFORM, xformSrc, 64, 24, 4); - TEST_FIELD(EMRPLGBLT, COLORREF, crBkColorSrc, 88, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, iUsageSrc, 92, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, offBmiSrc, 96, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, cbBmiSrc, 100, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, offBitsSrc, 104, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, cbBitsSrc, 108, 4, 4); - TEST_FIELD(EMRPLGBLT, LONG, xMask, 112, 4, 4); - TEST_FIELD(EMRPLGBLT, LONG, yMask, 116, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, iUsageMask, 120, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, offBmiMask, 124, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, cbBmiMask, 128, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, offBitsMask, 132, 4, 4); - TEST_FIELD(EMRPLGBLT, DWORD, cbBitsMask, 136, 4, 4); + TEST_TYPE_SIZE (EMRPLGBLT, 140) + TEST_TYPE_ALIGN (EMRPLGBLT, 4) + TEST_FIELD_SIZE (EMRPLGBLT, emr, 8) + TEST_FIELD_ALIGN (EMRPLGBLT, emr, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, emr, 0) + TEST_FIELD_SIZE (EMRPLGBLT, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPLGBLT, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, rclBounds, 8) + TEST_FIELD_SIZE (EMRPLGBLT, aptlDest, 24) + TEST_FIELD_ALIGN (EMRPLGBLT, aptlDest, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, aptlDest, 24) + TEST_FIELD_SIZE (EMRPLGBLT, xSrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, xSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, xSrc, 48) + TEST_FIELD_SIZE (EMRPLGBLT, ySrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, ySrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, ySrc, 52) + TEST_FIELD_SIZE (EMRPLGBLT, cxSrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, cxSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, cxSrc, 56) + TEST_FIELD_SIZE (EMRPLGBLT, cySrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, cySrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, cySrc, 60) + TEST_FIELD_SIZE (EMRPLGBLT, xformSrc, 24) + TEST_FIELD_ALIGN (EMRPLGBLT, xformSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, xformSrc, 64) + TEST_FIELD_SIZE (EMRPLGBLT, crBkColorSrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, crBkColorSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, crBkColorSrc, 88) + TEST_FIELD_SIZE (EMRPLGBLT, iUsageSrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, iUsageSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, iUsageSrc, 92) + TEST_FIELD_SIZE (EMRPLGBLT, offBmiSrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, offBmiSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, offBmiSrc, 96) + TEST_FIELD_SIZE (EMRPLGBLT, cbBmiSrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, cbBmiSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, cbBmiSrc, 100) + TEST_FIELD_SIZE (EMRPLGBLT, offBitsSrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, offBitsSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, offBitsSrc, 104) + TEST_FIELD_SIZE (EMRPLGBLT, cbBitsSrc, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, cbBitsSrc, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, cbBitsSrc, 108) + TEST_FIELD_SIZE (EMRPLGBLT, xMask, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, xMask, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, xMask, 112) + TEST_FIELD_SIZE (EMRPLGBLT, yMask, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, yMask, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, yMask, 116) + TEST_FIELD_SIZE (EMRPLGBLT, iUsageMask, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, iUsageMask, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, iUsageMask, 120) + TEST_FIELD_SIZE (EMRPLGBLT, offBmiMask, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, offBmiMask, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, offBmiMask, 124) + TEST_FIELD_SIZE (EMRPLGBLT, cbBmiMask, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, cbBmiMask, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, cbBmiMask, 128) + TEST_FIELD_SIZE (EMRPLGBLT, offBitsMask, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, offBitsMask, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, offBitsMask, 132) + TEST_FIELD_SIZE (EMRPLGBLT, cbBitsMask, 4) + TEST_FIELD_ALIGN (EMRPLGBLT, cbBitsMask, 4) + TEST_FIELD_OFFSET(EMRPLGBLT, cbBitsMask, 136) } static void test_pack_EMRPOLYBEZIER(void) { /* EMRPOLYBEZIER (pack 4) */ - TEST_TYPE(EMRPOLYBEZIER, 36, 4); - TEST_FIELD(EMRPOLYBEZIER, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYBEZIER, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYBEZIER, DWORD, cptl, 24, 4, 4); - TEST_FIELD(EMRPOLYBEZIER, POINTL[1], aptl, 28, 8, 4); + TEST_TYPE_SIZE (EMRPOLYBEZIER, 36) + TEST_TYPE_ALIGN (EMRPOLYBEZIER, 4) + TEST_FIELD_SIZE (EMRPOLYBEZIER, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYBEZIER, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIER, emr, 0) + TEST_FIELD_SIZE (EMRPOLYBEZIER, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYBEZIER, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIER, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYBEZIER, cptl, 4) + TEST_FIELD_ALIGN (EMRPOLYBEZIER, cptl, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIER, cptl, 24) + TEST_FIELD_SIZE (EMRPOLYBEZIER, aptl, 8) + TEST_FIELD_ALIGN (EMRPOLYBEZIER, aptl, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIER, aptl, 28) } static void test_pack_EMRPOLYBEZIER16(void) { /* EMRPOLYBEZIER16 (pack 4) */ - TEST_TYPE(EMRPOLYBEZIER16, 32, 4); - TEST_FIELD(EMRPOLYBEZIER16, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYBEZIER16, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYBEZIER16, DWORD, cpts, 24, 4, 4); - TEST_FIELD(EMRPOLYBEZIER16, POINTS[1], apts, 28, 4, 2); + TEST_TYPE_SIZE (EMRPOLYBEZIER16, 32) + TEST_TYPE_ALIGN (EMRPOLYBEZIER16, 4) + TEST_FIELD_SIZE (EMRPOLYBEZIER16, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYBEZIER16, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIER16, emr, 0) + TEST_FIELD_SIZE (EMRPOLYBEZIER16, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYBEZIER16, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIER16, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYBEZIER16, cpts, 4) + TEST_FIELD_ALIGN (EMRPOLYBEZIER16, cpts, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIER16, cpts, 24) + TEST_FIELD_SIZE (EMRPOLYBEZIER16, apts, 4) + TEST_FIELD_ALIGN (EMRPOLYBEZIER16, apts, 2) + TEST_FIELD_OFFSET(EMRPOLYBEZIER16, apts, 28) } static void test_pack_EMRPOLYBEZIERTO(void) { /* EMRPOLYBEZIERTO (pack 4) */ - TEST_TYPE(EMRPOLYBEZIERTO, 36, 4); - TEST_FIELD(EMRPOLYBEZIERTO, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYBEZIERTO, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYBEZIERTO, DWORD, cptl, 24, 4, 4); - TEST_FIELD(EMRPOLYBEZIERTO, POINTL[1], aptl, 28, 8, 4); + TEST_TYPE_SIZE (EMRPOLYBEZIERTO, 36) + TEST_TYPE_ALIGN (EMRPOLYBEZIERTO, 4) + TEST_FIELD_SIZE (EMRPOLYBEZIERTO, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYBEZIERTO, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIERTO, emr, 0) + TEST_FIELD_SIZE (EMRPOLYBEZIERTO, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYBEZIERTO, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIERTO, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYBEZIERTO, cptl, 4) + TEST_FIELD_ALIGN (EMRPOLYBEZIERTO, cptl, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIERTO, cptl, 24) + TEST_FIELD_SIZE (EMRPOLYBEZIERTO, aptl, 8) + TEST_FIELD_ALIGN (EMRPOLYBEZIERTO, aptl, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIERTO, aptl, 28) } static void test_pack_EMRPOLYBEZIERTO16(void) { /* EMRPOLYBEZIERTO16 (pack 4) */ - TEST_TYPE(EMRPOLYBEZIERTO16, 32, 4); - TEST_FIELD(EMRPOLYBEZIERTO16, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYBEZIERTO16, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYBEZIERTO16, DWORD, cpts, 24, 4, 4); - TEST_FIELD(EMRPOLYBEZIERTO16, POINTS[1], apts, 28, 4, 2); + TEST_TYPE_SIZE (EMRPOLYBEZIERTO16, 32) + TEST_TYPE_ALIGN (EMRPOLYBEZIERTO16, 4) + TEST_FIELD_SIZE (EMRPOLYBEZIERTO16, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYBEZIERTO16, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIERTO16, emr, 0) + TEST_FIELD_SIZE (EMRPOLYBEZIERTO16, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYBEZIERTO16, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIERTO16, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYBEZIERTO16, cpts, 4) + TEST_FIELD_ALIGN (EMRPOLYBEZIERTO16, cpts, 4) + TEST_FIELD_OFFSET(EMRPOLYBEZIERTO16, cpts, 24) + TEST_FIELD_SIZE (EMRPOLYBEZIERTO16, apts, 4) + TEST_FIELD_ALIGN (EMRPOLYBEZIERTO16, apts, 2) + TEST_FIELD_OFFSET(EMRPOLYBEZIERTO16, apts, 28) } static void test_pack_EMRPOLYDRAW(void) { /* EMRPOLYDRAW (pack 4) */ - TEST_TYPE(EMRPOLYDRAW, 40, 4); - TEST_FIELD(EMRPOLYDRAW, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYDRAW, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYDRAW, DWORD, cptl, 24, 4, 4); - TEST_FIELD(EMRPOLYDRAW, POINTL[1], aptl, 28, 8, 4); - TEST_FIELD(EMRPOLYDRAW, BYTE[1], abTypes, 36, 1, 1); + TEST_TYPE_SIZE (EMRPOLYDRAW, 40) + TEST_TYPE_ALIGN (EMRPOLYDRAW, 4) + TEST_FIELD_SIZE (EMRPOLYDRAW, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYDRAW, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYDRAW, emr, 0) + TEST_FIELD_SIZE (EMRPOLYDRAW, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYDRAW, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYDRAW, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYDRAW, cptl, 4) + TEST_FIELD_ALIGN (EMRPOLYDRAW, cptl, 4) + TEST_FIELD_OFFSET(EMRPOLYDRAW, cptl, 24) + TEST_FIELD_SIZE (EMRPOLYDRAW, aptl, 8) + TEST_FIELD_ALIGN (EMRPOLYDRAW, aptl, 4) + TEST_FIELD_OFFSET(EMRPOLYDRAW, aptl, 28) + TEST_FIELD_SIZE (EMRPOLYDRAW, abTypes, 1) + TEST_FIELD_ALIGN (EMRPOLYDRAW, abTypes, 1) + TEST_FIELD_OFFSET(EMRPOLYDRAW, abTypes, 36) } static void test_pack_EMRPOLYDRAW16(void) { /* EMRPOLYDRAW16 (pack 4) */ - TEST_TYPE(EMRPOLYDRAW16, 36, 4); - TEST_FIELD(EMRPOLYDRAW16, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYDRAW16, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYDRAW16, DWORD, cpts, 24, 4, 4); - TEST_FIELD(EMRPOLYDRAW16, POINTS[1], apts, 28, 4, 2); - TEST_FIELD(EMRPOLYDRAW16, BYTE[1], abTypes, 32, 1, 1); + TEST_TYPE_SIZE (EMRPOLYDRAW16, 36) + TEST_TYPE_ALIGN (EMRPOLYDRAW16, 4) + TEST_FIELD_SIZE (EMRPOLYDRAW16, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYDRAW16, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYDRAW16, emr, 0) + TEST_FIELD_SIZE (EMRPOLYDRAW16, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYDRAW16, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYDRAW16, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYDRAW16, cpts, 4) + TEST_FIELD_ALIGN (EMRPOLYDRAW16, cpts, 4) + TEST_FIELD_OFFSET(EMRPOLYDRAW16, cpts, 24) + TEST_FIELD_SIZE (EMRPOLYDRAW16, apts, 4) + TEST_FIELD_ALIGN (EMRPOLYDRAW16, apts, 2) + TEST_FIELD_OFFSET(EMRPOLYDRAW16, apts, 28) + TEST_FIELD_SIZE (EMRPOLYDRAW16, abTypes, 1) + TEST_FIELD_ALIGN (EMRPOLYDRAW16, abTypes, 1) + TEST_FIELD_OFFSET(EMRPOLYDRAW16, abTypes, 32) } static void test_pack_EMRPOLYGON(void) { /* EMRPOLYGON (pack 4) */ - TEST_TYPE(EMRPOLYGON, 36, 4); - TEST_FIELD(EMRPOLYGON, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYGON, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYGON, DWORD, cptl, 24, 4, 4); - TEST_FIELD(EMRPOLYGON, POINTL[1], aptl, 28, 8, 4); + TEST_TYPE_SIZE (EMRPOLYGON, 36) + TEST_TYPE_ALIGN (EMRPOLYGON, 4) + TEST_FIELD_SIZE (EMRPOLYGON, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYGON, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYGON, emr, 0) + TEST_FIELD_SIZE (EMRPOLYGON, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYGON, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYGON, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYGON, cptl, 4) + TEST_FIELD_ALIGN (EMRPOLYGON, cptl, 4) + TEST_FIELD_OFFSET(EMRPOLYGON, cptl, 24) + TEST_FIELD_SIZE (EMRPOLYGON, aptl, 8) + TEST_FIELD_ALIGN (EMRPOLYGON, aptl, 4) + TEST_FIELD_OFFSET(EMRPOLYGON, aptl, 28) } static void test_pack_EMRPOLYGON16(void) { /* EMRPOLYGON16 (pack 4) */ - TEST_TYPE(EMRPOLYGON16, 32, 4); - TEST_FIELD(EMRPOLYGON16, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYGON16, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYGON16, DWORD, cpts, 24, 4, 4); - TEST_FIELD(EMRPOLYGON16, POINTS[1], apts, 28, 4, 2); + TEST_TYPE_SIZE (EMRPOLYGON16, 32) + TEST_TYPE_ALIGN (EMRPOLYGON16, 4) + TEST_FIELD_SIZE (EMRPOLYGON16, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYGON16, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYGON16, emr, 0) + TEST_FIELD_SIZE (EMRPOLYGON16, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYGON16, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYGON16, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYGON16, cpts, 4) + TEST_FIELD_ALIGN (EMRPOLYGON16, cpts, 4) + TEST_FIELD_OFFSET(EMRPOLYGON16, cpts, 24) + TEST_FIELD_SIZE (EMRPOLYGON16, apts, 4) + TEST_FIELD_ALIGN (EMRPOLYGON16, apts, 2) + TEST_FIELD_OFFSET(EMRPOLYGON16, apts, 28) } static void test_pack_EMRPOLYLINE(void) { /* EMRPOLYLINE (pack 4) */ - TEST_TYPE(EMRPOLYLINE, 36, 4); - TEST_FIELD(EMRPOLYLINE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYLINE, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYLINE, DWORD, cptl, 24, 4, 4); - TEST_FIELD(EMRPOLYLINE, POINTL[1], aptl, 28, 8, 4); + TEST_TYPE_SIZE (EMRPOLYLINE, 36) + TEST_TYPE_ALIGN (EMRPOLYLINE, 4) + TEST_FIELD_SIZE (EMRPOLYLINE, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYLINE, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYLINE, emr, 0) + TEST_FIELD_SIZE (EMRPOLYLINE, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYLINE, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYLINE, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYLINE, cptl, 4) + TEST_FIELD_ALIGN (EMRPOLYLINE, cptl, 4) + TEST_FIELD_OFFSET(EMRPOLYLINE, cptl, 24) + TEST_FIELD_SIZE (EMRPOLYLINE, aptl, 8) + TEST_FIELD_ALIGN (EMRPOLYLINE, aptl, 4) + TEST_FIELD_OFFSET(EMRPOLYLINE, aptl, 28) } static void test_pack_EMRPOLYLINE16(void) { /* EMRPOLYLINE16 (pack 4) */ - TEST_TYPE(EMRPOLYLINE16, 32, 4); - TEST_FIELD(EMRPOLYLINE16, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYLINE16, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYLINE16, DWORD, cpts, 24, 4, 4); - TEST_FIELD(EMRPOLYLINE16, POINTS[1], apts, 28, 4, 2); + TEST_TYPE_SIZE (EMRPOLYLINE16, 32) + TEST_TYPE_ALIGN (EMRPOLYLINE16, 4) + TEST_FIELD_SIZE (EMRPOLYLINE16, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYLINE16, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYLINE16, emr, 0) + TEST_FIELD_SIZE (EMRPOLYLINE16, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYLINE16, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYLINE16, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYLINE16, cpts, 4) + TEST_FIELD_ALIGN (EMRPOLYLINE16, cpts, 4) + TEST_FIELD_OFFSET(EMRPOLYLINE16, cpts, 24) + TEST_FIELD_SIZE (EMRPOLYLINE16, apts, 4) + TEST_FIELD_ALIGN (EMRPOLYLINE16, apts, 2) + TEST_FIELD_OFFSET(EMRPOLYLINE16, apts, 28) } static void test_pack_EMRPOLYLINETO(void) { /* EMRPOLYLINETO (pack 4) */ - TEST_TYPE(EMRPOLYLINETO, 36, 4); - TEST_FIELD(EMRPOLYLINETO, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYLINETO, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYLINETO, DWORD, cptl, 24, 4, 4); - TEST_FIELD(EMRPOLYLINETO, POINTL[1], aptl, 28, 8, 4); + TEST_TYPE_SIZE (EMRPOLYLINETO, 36) + TEST_TYPE_ALIGN (EMRPOLYLINETO, 4) + TEST_FIELD_SIZE (EMRPOLYLINETO, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYLINETO, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYLINETO, emr, 0) + TEST_FIELD_SIZE (EMRPOLYLINETO, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYLINETO, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYLINETO, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYLINETO, cptl, 4) + TEST_FIELD_ALIGN (EMRPOLYLINETO, cptl, 4) + TEST_FIELD_OFFSET(EMRPOLYLINETO, cptl, 24) + TEST_FIELD_SIZE (EMRPOLYLINETO, aptl, 8) + TEST_FIELD_ALIGN (EMRPOLYLINETO, aptl, 4) + TEST_FIELD_OFFSET(EMRPOLYLINETO, aptl, 28) } static void test_pack_EMRPOLYLINETO16(void) { /* EMRPOLYLINETO16 (pack 4) */ - TEST_TYPE(EMRPOLYLINETO16, 32, 4); - TEST_FIELD(EMRPOLYLINETO16, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYLINETO16, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYLINETO16, DWORD, cpts, 24, 4, 4); - TEST_FIELD(EMRPOLYLINETO16, POINTS[1], apts, 28, 4, 2); + TEST_TYPE_SIZE (EMRPOLYLINETO16, 32) + TEST_TYPE_ALIGN (EMRPOLYLINETO16, 4) + TEST_FIELD_SIZE (EMRPOLYLINETO16, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYLINETO16, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYLINETO16, emr, 0) + TEST_FIELD_SIZE (EMRPOLYLINETO16, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYLINETO16, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYLINETO16, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYLINETO16, cpts, 4) + TEST_FIELD_ALIGN (EMRPOLYLINETO16, cpts, 4) + TEST_FIELD_OFFSET(EMRPOLYLINETO16, cpts, 24) + TEST_FIELD_SIZE (EMRPOLYLINETO16, apts, 4) + TEST_FIELD_ALIGN (EMRPOLYLINETO16, apts, 2) + TEST_FIELD_OFFSET(EMRPOLYLINETO16, apts, 28) } static void test_pack_EMRPOLYPOLYGON(void) { /* EMRPOLYPOLYGON (pack 4) */ - TEST_TYPE(EMRPOLYPOLYGON, 44, 4); - TEST_FIELD(EMRPOLYPOLYGON, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYPOLYGON, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYPOLYGON, DWORD, nPolys, 24, 4, 4); - TEST_FIELD(EMRPOLYPOLYGON, DWORD, cptl, 28, 4, 4); - TEST_FIELD(EMRPOLYPOLYGON, DWORD[1], aPolyCounts, 32, 4, 4); - TEST_FIELD(EMRPOLYPOLYGON, POINTL[1], aptl, 36, 8, 4); + TEST_TYPE_SIZE (EMRPOLYPOLYGON, 44) + TEST_TYPE_ALIGN (EMRPOLYPOLYGON, 4) + TEST_FIELD_SIZE (EMRPOLYPOLYGON, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON, emr, 0) + TEST_FIELD_SIZE (EMRPOLYPOLYGON, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYPOLYGON, nPolys, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON, nPolys, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON, nPolys, 24) + TEST_FIELD_SIZE (EMRPOLYPOLYGON, cptl, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON, cptl, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON, cptl, 28) + TEST_FIELD_SIZE (EMRPOLYPOLYGON, aPolyCounts, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON, aPolyCounts, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON, aPolyCounts, 32) + TEST_FIELD_SIZE (EMRPOLYPOLYGON, aptl, 8) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON, aptl, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON, aptl, 36) } static void test_pack_EMRPOLYPOLYGON16(void) { /* EMRPOLYPOLYGON16 (pack 4) */ - TEST_TYPE(EMRPOLYPOLYGON16, 40, 4); - TEST_FIELD(EMRPOLYPOLYGON16, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYPOLYGON16, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYPOLYGON16, DWORD, nPolys, 24, 4, 4); - TEST_FIELD(EMRPOLYPOLYGON16, DWORD, cpts, 28, 4, 4); - TEST_FIELD(EMRPOLYPOLYGON16, DWORD[1], aPolyCounts, 32, 4, 4); - TEST_FIELD(EMRPOLYPOLYGON16, POINTS[1], apts, 36, 4, 2); + TEST_TYPE_SIZE (EMRPOLYPOLYGON16, 40) + TEST_TYPE_ALIGN (EMRPOLYPOLYGON16, 4) + TEST_FIELD_SIZE (EMRPOLYPOLYGON16, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON16, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON16, emr, 0) + TEST_FIELD_SIZE (EMRPOLYPOLYGON16, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON16, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON16, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYPOLYGON16, nPolys, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON16, nPolys, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON16, nPolys, 24) + TEST_FIELD_SIZE (EMRPOLYPOLYGON16, cpts, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON16, cpts, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON16, cpts, 28) + TEST_FIELD_SIZE (EMRPOLYPOLYGON16, aPolyCounts, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON16, aPolyCounts, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON16, aPolyCounts, 32) + TEST_FIELD_SIZE (EMRPOLYPOLYGON16, apts, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYGON16, apts, 2) + TEST_FIELD_OFFSET(EMRPOLYPOLYGON16, apts, 36) } static void test_pack_EMRPOLYPOLYLINE(void) { /* EMRPOLYPOLYLINE (pack 4) */ - TEST_TYPE(EMRPOLYPOLYLINE, 44, 4); - TEST_FIELD(EMRPOLYPOLYLINE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYPOLYLINE, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYPOLYLINE, DWORD, nPolys, 24, 4, 4); - TEST_FIELD(EMRPOLYPOLYLINE, DWORD, cptl, 28, 4, 4); - TEST_FIELD(EMRPOLYPOLYLINE, DWORD[1], aPolyCounts, 32, 4, 4); - TEST_FIELD(EMRPOLYPOLYLINE, POINTL[1], aptl, 36, 8, 4); + TEST_TYPE_SIZE (EMRPOLYPOLYLINE, 44) + TEST_TYPE_ALIGN (EMRPOLYPOLYLINE, 4) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE, emr, 0) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE, nPolys, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE, nPolys, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE, nPolys, 24) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE, cptl, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE, cptl, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE, cptl, 28) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE, aPolyCounts, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE, aPolyCounts, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE, aPolyCounts, 32) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE, aptl, 8) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE, aptl, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE, aptl, 36) } static void test_pack_EMRPOLYPOLYLINE16(void) { /* EMRPOLYPOLYLINE16 (pack 4) */ - TEST_TYPE(EMRPOLYPOLYLINE16, 40, 4); - TEST_FIELD(EMRPOLYPOLYLINE16, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYPOLYLINE16, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYPOLYLINE16, DWORD, nPolys, 24, 4, 4); - TEST_FIELD(EMRPOLYPOLYLINE16, DWORD, cpts, 28, 4, 4); - TEST_FIELD(EMRPOLYPOLYLINE16, DWORD[1], aPolyCounts, 32, 4, 4); - TEST_FIELD(EMRPOLYPOLYLINE16, POINTS[1], apts, 36, 4, 2); + TEST_TYPE_SIZE (EMRPOLYPOLYLINE16, 40) + TEST_TYPE_ALIGN (EMRPOLYPOLYLINE16, 4) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE16, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE16, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE16, emr, 0) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE16, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE16, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE16, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE16, nPolys, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE16, nPolys, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE16, nPolys, 24) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE16, cpts, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE16, cpts, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE16, cpts, 28) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE16, aPolyCounts, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE16, aPolyCounts, 4) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE16, aPolyCounts, 32) + TEST_FIELD_SIZE (EMRPOLYPOLYLINE16, apts, 4) + TEST_FIELD_ALIGN (EMRPOLYPOLYLINE16, apts, 2) + TEST_FIELD_OFFSET(EMRPOLYPOLYLINE16, apts, 36) } static void test_pack_EMRPOLYTEXTOUTA(void) { /* EMRPOLYTEXTOUTA (pack 4) */ - TEST_TYPE(EMRPOLYTEXTOUTA, 80, 4); - TEST_FIELD(EMRPOLYTEXTOUTA, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYTEXTOUTA, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYTEXTOUTA, DWORD, iGraphicsMode, 24, 4, 4); - TEST_FIELD(EMRPOLYTEXTOUTA, FLOAT, exScale, 28, 4, 4); - TEST_FIELD(EMRPOLYTEXTOUTA, FLOAT, eyScale, 32, 4, 4); - TEST_FIELD(EMRPOLYTEXTOUTA, LONG, cStrings, 36, 4, 4); - TEST_FIELD(EMRPOLYTEXTOUTA, EMRTEXT[1], aemrtext, 40, 40, 4); + TEST_TYPE_SIZE (EMRPOLYTEXTOUTA, 80) + TEST_TYPE_ALIGN (EMRPOLYTEXTOUTA, 4) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTA, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTA, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTA, emr, 0) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTA, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTA, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTA, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTA, iGraphicsMode, 4) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTA, iGraphicsMode, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTA, iGraphicsMode, 24) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTA, exScale, 4) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTA, exScale, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTA, exScale, 28) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTA, eyScale, 4) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTA, eyScale, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTA, eyScale, 32) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTA, cStrings, 4) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTA, cStrings, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTA, cStrings, 36) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTA, aemrtext, 40) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTA, aemrtext, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTA, aemrtext, 40) } static void test_pack_EMRPOLYTEXTOUTW(void) { /* EMRPOLYTEXTOUTW (pack 4) */ - TEST_TYPE(EMRPOLYTEXTOUTW, 80, 4); - TEST_FIELD(EMRPOLYTEXTOUTW, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRPOLYTEXTOUTW, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRPOLYTEXTOUTW, DWORD, iGraphicsMode, 24, 4, 4); - TEST_FIELD(EMRPOLYTEXTOUTW, FLOAT, exScale, 28, 4, 4); - TEST_FIELD(EMRPOLYTEXTOUTW, FLOAT, eyScale, 32, 4, 4); - TEST_FIELD(EMRPOLYTEXTOUTW, LONG, cStrings, 36, 4, 4); - TEST_FIELD(EMRPOLYTEXTOUTW, EMRTEXT[1], aemrtext, 40, 40, 4); + TEST_TYPE_SIZE (EMRPOLYTEXTOUTW, 80) + TEST_TYPE_ALIGN (EMRPOLYTEXTOUTW, 4) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTW, emr, 8) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTW, emr, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTW, emr, 0) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTW, rclBounds, 16) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTW, rclBounds, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTW, rclBounds, 8) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTW, iGraphicsMode, 4) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTW, iGraphicsMode, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTW, iGraphicsMode, 24) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTW, exScale, 4) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTW, exScale, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTW, exScale, 28) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTW, eyScale, 4) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTW, eyScale, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTW, eyScale, 32) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTW, cStrings, 4) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTW, cStrings, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTW, cStrings, 36) + TEST_FIELD_SIZE (EMRPOLYTEXTOUTW, aemrtext, 40) + TEST_FIELD_ALIGN (EMRPOLYTEXTOUTW, aemrtext, 4) + TEST_FIELD_OFFSET(EMRPOLYTEXTOUTW, aemrtext, 40) } static void test_pack_EMRREALIZEPALETTE(void) { /* EMRREALIZEPALETTE (pack 4) */ - TEST_TYPE(EMRREALIZEPALETTE, 8, 4); - TEST_FIELD(EMRREALIZEPALETTE, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRREALIZEPALETTE, 8) + TEST_TYPE_ALIGN (EMRREALIZEPALETTE, 4) + TEST_FIELD_SIZE (EMRREALIZEPALETTE, emr, 8) + TEST_FIELD_ALIGN (EMRREALIZEPALETTE, emr, 4) + TEST_FIELD_OFFSET(EMRREALIZEPALETTE, emr, 0) } static void test_pack_EMRRECTANGLE(void) { /* EMRRECTANGLE (pack 4) */ - TEST_TYPE(EMRRECTANGLE, 24, 4); - TEST_FIELD(EMRRECTANGLE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRRECTANGLE, RECTL, rclBox, 8, 16, 4); + TEST_TYPE_SIZE (EMRRECTANGLE, 24) + TEST_TYPE_ALIGN (EMRRECTANGLE, 4) + TEST_FIELD_SIZE (EMRRECTANGLE, emr, 8) + TEST_FIELD_ALIGN (EMRRECTANGLE, emr, 4) + TEST_FIELD_OFFSET(EMRRECTANGLE, emr, 0) + TEST_FIELD_SIZE (EMRRECTANGLE, rclBox, 16) + TEST_FIELD_ALIGN (EMRRECTANGLE, rclBox, 4) + TEST_FIELD_OFFSET(EMRRECTANGLE, rclBox, 8) } static void test_pack_EMRRESIZEPALETTE(void) { /* EMRRESIZEPALETTE (pack 4) */ - TEST_TYPE(EMRRESIZEPALETTE, 16, 4); - TEST_FIELD(EMRRESIZEPALETTE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRRESIZEPALETTE, DWORD, ihPal, 8, 4, 4); - TEST_FIELD(EMRRESIZEPALETTE, DWORD, cEntries, 12, 4, 4); + TEST_TYPE_SIZE (EMRRESIZEPALETTE, 16) + TEST_TYPE_ALIGN (EMRRESIZEPALETTE, 4) + TEST_FIELD_SIZE (EMRRESIZEPALETTE, emr, 8) + TEST_FIELD_ALIGN (EMRRESIZEPALETTE, emr, 4) + TEST_FIELD_OFFSET(EMRRESIZEPALETTE, emr, 0) + TEST_FIELD_SIZE (EMRRESIZEPALETTE, ihPal, 4) + TEST_FIELD_ALIGN (EMRRESIZEPALETTE, ihPal, 4) + TEST_FIELD_OFFSET(EMRRESIZEPALETTE, ihPal, 8) + TEST_FIELD_SIZE (EMRRESIZEPALETTE, cEntries, 4) + TEST_FIELD_ALIGN (EMRRESIZEPALETTE, cEntries, 4) + TEST_FIELD_OFFSET(EMRRESIZEPALETTE, cEntries, 12) } static void test_pack_EMRRESTOREDC(void) { /* EMRRESTOREDC (pack 4) */ - TEST_TYPE(EMRRESTOREDC, 12, 4); - TEST_FIELD(EMRRESTOREDC, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRRESTOREDC, LONG, iRelative, 8, 4, 4); + TEST_TYPE_SIZE (EMRRESTOREDC, 12) + TEST_TYPE_ALIGN (EMRRESTOREDC, 4) + TEST_FIELD_SIZE (EMRRESTOREDC, emr, 8) + TEST_FIELD_ALIGN (EMRRESTOREDC, emr, 4) + TEST_FIELD_OFFSET(EMRRESTOREDC, emr, 0) + TEST_FIELD_SIZE (EMRRESTOREDC, iRelative, 4) + TEST_FIELD_ALIGN (EMRRESTOREDC, iRelative, 4) + TEST_FIELD_OFFSET(EMRRESTOREDC, iRelative, 8) } static void test_pack_EMRROUNDRECT(void) { /* EMRROUNDRECT (pack 4) */ - TEST_TYPE(EMRROUNDRECT, 32, 4); - TEST_FIELD(EMRROUNDRECT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRROUNDRECT, RECTL, rclBox, 8, 16, 4); - TEST_FIELD(EMRROUNDRECT, SIZEL, szlCorner, 24, 8, 4); + TEST_TYPE_SIZE (EMRROUNDRECT, 32) + TEST_TYPE_ALIGN (EMRROUNDRECT, 4) + TEST_FIELD_SIZE (EMRROUNDRECT, emr, 8) + TEST_FIELD_ALIGN (EMRROUNDRECT, emr, 4) + TEST_FIELD_OFFSET(EMRROUNDRECT, emr, 0) + TEST_FIELD_SIZE (EMRROUNDRECT, rclBox, 16) + TEST_FIELD_ALIGN (EMRROUNDRECT, rclBox, 4) + TEST_FIELD_OFFSET(EMRROUNDRECT, rclBox, 8) + TEST_FIELD_SIZE (EMRROUNDRECT, szlCorner, 8) + TEST_FIELD_ALIGN (EMRROUNDRECT, szlCorner, 4) + TEST_FIELD_OFFSET(EMRROUNDRECT, szlCorner, 24) } static void test_pack_EMRSAVEDC(void) { /* EMRSAVEDC (pack 4) */ - TEST_TYPE(EMRSAVEDC, 8, 4); - TEST_FIELD(EMRSAVEDC, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRSAVEDC, 8) + TEST_TYPE_ALIGN (EMRSAVEDC, 4) + TEST_FIELD_SIZE (EMRSAVEDC, emr, 8) + TEST_FIELD_ALIGN (EMRSAVEDC, emr, 4) + TEST_FIELD_OFFSET(EMRSAVEDC, emr, 0) } static void test_pack_EMRSCALEVIEWPORTEXTEX(void) { /* EMRSCALEVIEWPORTEXTEX (pack 4) */ - TEST_TYPE(EMRSCALEVIEWPORTEXTEX, 24, 4); - TEST_FIELD(EMRSCALEVIEWPORTEXTEX, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSCALEVIEWPORTEXTEX, LONG, xNum, 8, 4, 4); - TEST_FIELD(EMRSCALEVIEWPORTEXTEX, LONG, xDenom, 12, 4, 4); - TEST_FIELD(EMRSCALEVIEWPORTEXTEX, LONG, yNum, 16, 4, 4); - TEST_FIELD(EMRSCALEVIEWPORTEXTEX, LONG, yDenom, 20, 4, 4); + TEST_TYPE_SIZE (EMRSCALEVIEWPORTEXTEX, 24) + TEST_TYPE_ALIGN (EMRSCALEVIEWPORTEXTEX, 4) + TEST_FIELD_SIZE (EMRSCALEVIEWPORTEXTEX, emr, 8) + TEST_FIELD_ALIGN (EMRSCALEVIEWPORTEXTEX, emr, 4) + TEST_FIELD_OFFSET(EMRSCALEVIEWPORTEXTEX, emr, 0) + TEST_FIELD_SIZE (EMRSCALEVIEWPORTEXTEX, xNum, 4) + TEST_FIELD_ALIGN (EMRSCALEVIEWPORTEXTEX, xNum, 4) + TEST_FIELD_OFFSET(EMRSCALEVIEWPORTEXTEX, xNum, 8) + TEST_FIELD_SIZE (EMRSCALEVIEWPORTEXTEX, xDenom, 4) + TEST_FIELD_ALIGN (EMRSCALEVIEWPORTEXTEX, xDenom, 4) + TEST_FIELD_OFFSET(EMRSCALEVIEWPORTEXTEX, xDenom, 12) + TEST_FIELD_SIZE (EMRSCALEVIEWPORTEXTEX, yNum, 4) + TEST_FIELD_ALIGN (EMRSCALEVIEWPORTEXTEX, yNum, 4) + TEST_FIELD_OFFSET(EMRSCALEVIEWPORTEXTEX, yNum, 16) + TEST_FIELD_SIZE (EMRSCALEVIEWPORTEXTEX, yDenom, 4) + TEST_FIELD_ALIGN (EMRSCALEVIEWPORTEXTEX, yDenom, 4) + TEST_FIELD_OFFSET(EMRSCALEVIEWPORTEXTEX, yDenom, 20) } static void test_pack_EMRSCALEWINDOWEXTEX(void) { /* EMRSCALEWINDOWEXTEX (pack 4) */ - TEST_TYPE(EMRSCALEWINDOWEXTEX, 24, 4); - TEST_FIELD(EMRSCALEWINDOWEXTEX, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSCALEWINDOWEXTEX, LONG, xNum, 8, 4, 4); - TEST_FIELD(EMRSCALEWINDOWEXTEX, LONG, xDenom, 12, 4, 4); - TEST_FIELD(EMRSCALEWINDOWEXTEX, LONG, yNum, 16, 4, 4); - TEST_FIELD(EMRSCALEWINDOWEXTEX, LONG, yDenom, 20, 4, 4); + TEST_TYPE_SIZE (EMRSCALEWINDOWEXTEX, 24) + TEST_TYPE_ALIGN (EMRSCALEWINDOWEXTEX, 4) + TEST_FIELD_SIZE (EMRSCALEWINDOWEXTEX, emr, 8) + TEST_FIELD_ALIGN (EMRSCALEWINDOWEXTEX, emr, 4) + TEST_FIELD_OFFSET(EMRSCALEWINDOWEXTEX, emr, 0) + TEST_FIELD_SIZE (EMRSCALEWINDOWEXTEX, xNum, 4) + TEST_FIELD_ALIGN (EMRSCALEWINDOWEXTEX, xNum, 4) + TEST_FIELD_OFFSET(EMRSCALEWINDOWEXTEX, xNum, 8) + TEST_FIELD_SIZE (EMRSCALEWINDOWEXTEX, xDenom, 4) + TEST_FIELD_ALIGN (EMRSCALEWINDOWEXTEX, xDenom, 4) + TEST_FIELD_OFFSET(EMRSCALEWINDOWEXTEX, xDenom, 12) + TEST_FIELD_SIZE (EMRSCALEWINDOWEXTEX, yNum, 4) + TEST_FIELD_ALIGN (EMRSCALEWINDOWEXTEX, yNum, 4) + TEST_FIELD_OFFSET(EMRSCALEWINDOWEXTEX, yNum, 16) + TEST_FIELD_SIZE (EMRSCALEWINDOWEXTEX, yDenom, 4) + TEST_FIELD_ALIGN (EMRSCALEWINDOWEXTEX, yDenom, 4) + TEST_FIELD_OFFSET(EMRSCALEWINDOWEXTEX, yDenom, 20) } static void test_pack_EMRSELECTCLIPPATH(void) { /* EMRSELECTCLIPPATH (pack 4) */ - TEST_TYPE(EMRSELECTCLIPPATH, 12, 4); - TEST_FIELD(EMRSELECTCLIPPATH, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSELECTCLIPPATH, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSELECTCLIPPATH, 12) + TEST_TYPE_ALIGN (EMRSELECTCLIPPATH, 4) + TEST_FIELD_SIZE (EMRSELECTCLIPPATH, emr, 8) + TEST_FIELD_ALIGN (EMRSELECTCLIPPATH, emr, 4) + TEST_FIELD_OFFSET(EMRSELECTCLIPPATH, emr, 0) + TEST_FIELD_SIZE (EMRSELECTCLIPPATH, iMode, 4) + TEST_FIELD_ALIGN (EMRSELECTCLIPPATH, iMode, 4) + TEST_FIELD_OFFSET(EMRSELECTCLIPPATH, iMode, 8) } static void test_pack_EMRSELECTCOLORSPACE(void) { /* EMRSELECTCOLORSPACE (pack 4) */ - TEST_TYPE(EMRSELECTCOLORSPACE, 12, 4); - TEST_FIELD(EMRSELECTCOLORSPACE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSELECTCOLORSPACE, DWORD, ihCS, 8, 4, 4); + TEST_TYPE_SIZE (EMRSELECTCOLORSPACE, 12) + TEST_TYPE_ALIGN (EMRSELECTCOLORSPACE, 4) + TEST_FIELD_SIZE (EMRSELECTCOLORSPACE, emr, 8) + TEST_FIELD_ALIGN (EMRSELECTCOLORSPACE, emr, 4) + TEST_FIELD_OFFSET(EMRSELECTCOLORSPACE, emr, 0) + TEST_FIELD_SIZE (EMRSELECTCOLORSPACE, ihCS, 4) + TEST_FIELD_ALIGN (EMRSELECTCOLORSPACE, ihCS, 4) + TEST_FIELD_OFFSET(EMRSELECTCOLORSPACE, ihCS, 8) } static void test_pack_EMRSELECTOBJECT(void) { /* EMRSELECTOBJECT (pack 4) */ - TEST_TYPE(EMRSELECTOBJECT, 12, 4); - TEST_FIELD(EMRSELECTOBJECT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSELECTOBJECT, DWORD, ihObject, 8, 4, 4); + TEST_TYPE_SIZE (EMRSELECTOBJECT, 12) + TEST_TYPE_ALIGN (EMRSELECTOBJECT, 4) + TEST_FIELD_SIZE (EMRSELECTOBJECT, emr, 8) + TEST_FIELD_ALIGN (EMRSELECTOBJECT, emr, 4) + TEST_FIELD_OFFSET(EMRSELECTOBJECT, emr, 0) + TEST_FIELD_SIZE (EMRSELECTOBJECT, ihObject, 4) + TEST_FIELD_ALIGN (EMRSELECTOBJECT, ihObject, 4) + TEST_FIELD_OFFSET(EMRSELECTOBJECT, ihObject, 8) } static void test_pack_EMRSELECTPALETTE(void) { /* EMRSELECTPALETTE (pack 4) */ - TEST_TYPE(EMRSELECTPALETTE, 12, 4); - TEST_FIELD(EMRSELECTPALETTE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSELECTPALETTE, DWORD, ihPal, 8, 4, 4); + TEST_TYPE_SIZE (EMRSELECTPALETTE, 12) + TEST_TYPE_ALIGN (EMRSELECTPALETTE, 4) + TEST_FIELD_SIZE (EMRSELECTPALETTE, emr, 8) + TEST_FIELD_ALIGN (EMRSELECTPALETTE, emr, 4) + TEST_FIELD_OFFSET(EMRSELECTPALETTE, emr, 0) + TEST_FIELD_SIZE (EMRSELECTPALETTE, ihPal, 4) + TEST_FIELD_ALIGN (EMRSELECTPALETTE, ihPal, 4) + TEST_FIELD_OFFSET(EMRSELECTPALETTE, ihPal, 8) } static void test_pack_EMRSETARCDIRECTION(void) { /* EMRSETARCDIRECTION (pack 4) */ - TEST_TYPE(EMRSETARCDIRECTION, 12, 4); - TEST_FIELD(EMRSETARCDIRECTION, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETARCDIRECTION, DWORD, iArcDirection, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETARCDIRECTION, 12) + TEST_TYPE_ALIGN (EMRSETARCDIRECTION, 4) + TEST_FIELD_SIZE (EMRSETARCDIRECTION, emr, 8) + TEST_FIELD_ALIGN (EMRSETARCDIRECTION, emr, 4) + TEST_FIELD_OFFSET(EMRSETARCDIRECTION, emr, 0) + TEST_FIELD_SIZE (EMRSETARCDIRECTION, iArcDirection, 4) + TEST_FIELD_ALIGN (EMRSETARCDIRECTION, iArcDirection, 4) + TEST_FIELD_OFFSET(EMRSETARCDIRECTION, iArcDirection, 8) } static void test_pack_EMRSETBKCOLOR(void) { /* EMRSETBKCOLOR (pack 4) */ - TEST_TYPE(EMRSETBKCOLOR, 12, 4); - TEST_FIELD(EMRSETBKCOLOR, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETBKCOLOR, COLORREF, crColor, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETBKCOLOR, 12) + TEST_TYPE_ALIGN (EMRSETBKCOLOR, 4) + TEST_FIELD_SIZE (EMRSETBKCOLOR, emr, 8) + TEST_FIELD_ALIGN (EMRSETBKCOLOR, emr, 4) + TEST_FIELD_OFFSET(EMRSETBKCOLOR, emr, 0) + TEST_FIELD_SIZE (EMRSETBKCOLOR, crColor, 4) + TEST_FIELD_ALIGN (EMRSETBKCOLOR, crColor, 4) + TEST_FIELD_OFFSET(EMRSETBKCOLOR, crColor, 8) } static void test_pack_EMRSETBKMODE(void) { /* EMRSETBKMODE (pack 4) */ - TEST_TYPE(EMRSETBKMODE, 12, 4); - TEST_FIELD(EMRSETBKMODE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETBKMODE, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETBKMODE, 12) + TEST_TYPE_ALIGN (EMRSETBKMODE, 4) + TEST_FIELD_SIZE (EMRSETBKMODE, emr, 8) + TEST_FIELD_ALIGN (EMRSETBKMODE, emr, 4) + TEST_FIELD_OFFSET(EMRSETBKMODE, emr, 0) + TEST_FIELD_SIZE (EMRSETBKMODE, iMode, 4) + TEST_FIELD_ALIGN (EMRSETBKMODE, iMode, 4) + TEST_FIELD_OFFSET(EMRSETBKMODE, iMode, 8) } static void test_pack_EMRSETBRUSHORGEX(void) { /* EMRSETBRUSHORGEX (pack 4) */ - TEST_TYPE(EMRSETBRUSHORGEX, 16, 4); - TEST_FIELD(EMRSETBRUSHORGEX, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETBRUSHORGEX, POINTL, ptlOrigin, 8, 8, 4); + TEST_TYPE_SIZE (EMRSETBRUSHORGEX, 16) + TEST_TYPE_ALIGN (EMRSETBRUSHORGEX, 4) + TEST_FIELD_SIZE (EMRSETBRUSHORGEX, emr, 8) + TEST_FIELD_ALIGN (EMRSETBRUSHORGEX, emr, 4) + TEST_FIELD_OFFSET(EMRSETBRUSHORGEX, emr, 0) + TEST_FIELD_SIZE (EMRSETBRUSHORGEX, ptlOrigin, 8) + TEST_FIELD_ALIGN (EMRSETBRUSHORGEX, ptlOrigin, 4) + TEST_FIELD_OFFSET(EMRSETBRUSHORGEX, ptlOrigin, 8) } static void test_pack_EMRSETCOLORADJUSTMENT(void) { /* EMRSETCOLORADJUSTMENT (pack 4) */ - TEST_TYPE(EMRSETCOLORADJUSTMENT, 32, 4); - TEST_FIELD(EMRSETCOLORADJUSTMENT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETCOLORADJUSTMENT, COLORADJUSTMENT, ColorAdjustment, 8, 24, 2); + TEST_TYPE_SIZE (EMRSETCOLORADJUSTMENT, 32) + TEST_TYPE_ALIGN (EMRSETCOLORADJUSTMENT, 4) + TEST_FIELD_SIZE (EMRSETCOLORADJUSTMENT, emr, 8) + TEST_FIELD_ALIGN (EMRSETCOLORADJUSTMENT, emr, 4) + TEST_FIELD_OFFSET(EMRSETCOLORADJUSTMENT, emr, 0) + TEST_FIELD_SIZE (EMRSETCOLORADJUSTMENT, ColorAdjustment, 24) + TEST_FIELD_ALIGN (EMRSETCOLORADJUSTMENT, ColorAdjustment, 2) + TEST_FIELD_OFFSET(EMRSETCOLORADJUSTMENT, ColorAdjustment, 8) } static void test_pack_EMRSETCOLORSPACE(void) { /* EMRSETCOLORSPACE (pack 4) */ - TEST_TYPE(EMRSETCOLORSPACE, 12, 4); - TEST_FIELD(EMRSETCOLORSPACE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETCOLORSPACE, DWORD, ihCS, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETCOLORSPACE, 12) + TEST_TYPE_ALIGN (EMRSETCOLORSPACE, 4) + TEST_FIELD_SIZE (EMRSETCOLORSPACE, emr, 8) + TEST_FIELD_ALIGN (EMRSETCOLORSPACE, emr, 4) + TEST_FIELD_OFFSET(EMRSETCOLORSPACE, emr, 0) + TEST_FIELD_SIZE (EMRSETCOLORSPACE, ihCS, 4) + TEST_FIELD_ALIGN (EMRSETCOLORSPACE, ihCS, 4) + TEST_FIELD_OFFSET(EMRSETCOLORSPACE, ihCS, 8) } static void test_pack_EMRSETDIBITSTODEVICE(void) { /* EMRSETDIBITSTODEVICE (pack 4) */ - TEST_TYPE(EMRSETDIBITSTODEVICE, 76, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, LONG, xDest, 24, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, LONG, yDest, 28, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, LONG, xSrc, 32, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, LONG, ySrc, 36, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, LONG, cxSrc, 40, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, LONG, cySrc, 44, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, DWORD, offBmiSrc, 48, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, DWORD, cbBmiSrc, 52, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, DWORD, offBitsSrc, 56, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, DWORD, cbBitsSrc, 60, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, DWORD, iUsageSrc, 64, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, DWORD, iStartScan, 68, 4, 4); - TEST_FIELD(EMRSETDIBITSTODEVICE, DWORD, cScans, 72, 4, 4); + TEST_TYPE_SIZE (EMRSETDIBITSTODEVICE, 76) + TEST_TYPE_ALIGN (EMRSETDIBITSTODEVICE, 4) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, emr, 8) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, emr, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, emr, 0) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, rclBounds, 16) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, rclBounds, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, rclBounds, 8) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, xDest, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, xDest, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, xDest, 24) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, yDest, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, yDest, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, yDest, 28) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, xSrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, xSrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, xSrc, 32) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, ySrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, ySrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, ySrc, 36) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, cxSrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, cxSrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, cxSrc, 40) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, cySrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, cySrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, cySrc, 44) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, offBmiSrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, offBmiSrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, offBmiSrc, 48) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, cbBmiSrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, cbBmiSrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, cbBmiSrc, 52) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, offBitsSrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, offBitsSrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, offBitsSrc, 56) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, cbBitsSrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, cbBitsSrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, cbBitsSrc, 60) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, iUsageSrc, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, iUsageSrc, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, iUsageSrc, 64) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, iStartScan, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, iStartScan, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, iStartScan, 68) + TEST_FIELD_SIZE (EMRSETDIBITSTODEVICE, cScans, 4) + TEST_FIELD_ALIGN (EMRSETDIBITSTODEVICE, cScans, 4) + TEST_FIELD_OFFSET(EMRSETDIBITSTODEVICE, cScans, 72) } static void test_pack_EMRSETICMMODE(void) { /* EMRSETICMMODE (pack 4) */ - TEST_TYPE(EMRSETICMMODE, 12, 4); - TEST_FIELD(EMRSETICMMODE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETICMMODE, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETICMMODE, 12) + TEST_TYPE_ALIGN (EMRSETICMMODE, 4) + TEST_FIELD_SIZE (EMRSETICMMODE, emr, 8) + TEST_FIELD_ALIGN (EMRSETICMMODE, emr, 4) + TEST_FIELD_OFFSET(EMRSETICMMODE, emr, 0) + TEST_FIELD_SIZE (EMRSETICMMODE, iMode, 4) + TEST_FIELD_ALIGN (EMRSETICMMODE, iMode, 4) + TEST_FIELD_OFFSET(EMRSETICMMODE, iMode, 8) } static void test_pack_EMRSETLAYOUT(void) { /* EMRSETLAYOUT (pack 4) */ - TEST_TYPE(EMRSETLAYOUT, 12, 4); - TEST_FIELD(EMRSETLAYOUT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETLAYOUT, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETLAYOUT, 12) + TEST_TYPE_ALIGN (EMRSETLAYOUT, 4) + TEST_FIELD_SIZE (EMRSETLAYOUT, emr, 8) + TEST_FIELD_ALIGN (EMRSETLAYOUT, emr, 4) + TEST_FIELD_OFFSET(EMRSETLAYOUT, emr, 0) + TEST_FIELD_SIZE (EMRSETLAYOUT, iMode, 4) + TEST_FIELD_ALIGN (EMRSETLAYOUT, iMode, 4) + TEST_FIELD_OFFSET(EMRSETLAYOUT, iMode, 8) } static void test_pack_EMRSETMAPMODE(void) { /* EMRSETMAPMODE (pack 4) */ - TEST_TYPE(EMRSETMAPMODE, 12, 4); - TEST_FIELD(EMRSETMAPMODE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETMAPMODE, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETMAPMODE, 12) + TEST_TYPE_ALIGN (EMRSETMAPMODE, 4) + TEST_FIELD_SIZE (EMRSETMAPMODE, emr, 8) + TEST_FIELD_ALIGN (EMRSETMAPMODE, emr, 4) + TEST_FIELD_OFFSET(EMRSETMAPMODE, emr, 0) + TEST_FIELD_SIZE (EMRSETMAPMODE, iMode, 4) + TEST_FIELD_ALIGN (EMRSETMAPMODE, iMode, 4) + TEST_FIELD_OFFSET(EMRSETMAPMODE, iMode, 8) } static void test_pack_EMRSETMAPPERFLAGS(void) { /* EMRSETMAPPERFLAGS (pack 4) */ - TEST_TYPE(EMRSETMAPPERFLAGS, 12, 4); - TEST_FIELD(EMRSETMAPPERFLAGS, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETMAPPERFLAGS, DWORD, dwFlags, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETMAPPERFLAGS, 12) + TEST_TYPE_ALIGN (EMRSETMAPPERFLAGS, 4) + TEST_FIELD_SIZE (EMRSETMAPPERFLAGS, emr, 8) + TEST_FIELD_ALIGN (EMRSETMAPPERFLAGS, emr, 4) + TEST_FIELD_OFFSET(EMRSETMAPPERFLAGS, emr, 0) + TEST_FIELD_SIZE (EMRSETMAPPERFLAGS, dwFlags, 4) + TEST_FIELD_ALIGN (EMRSETMAPPERFLAGS, dwFlags, 4) + TEST_FIELD_OFFSET(EMRSETMAPPERFLAGS, dwFlags, 8) } static void test_pack_EMRSETMETARGN(void) { /* EMRSETMETARGN (pack 4) */ - TEST_TYPE(EMRSETMETARGN, 8, 4); - TEST_FIELD(EMRSETMETARGN, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRSETMETARGN, 8) + TEST_TYPE_ALIGN (EMRSETMETARGN, 4) + TEST_FIELD_SIZE (EMRSETMETARGN, emr, 8) + TEST_FIELD_ALIGN (EMRSETMETARGN, emr, 4) + TEST_FIELD_OFFSET(EMRSETMETARGN, emr, 0) } static void test_pack_EMRSETMITERLIMIT(void) { /* EMRSETMITERLIMIT (pack 4) */ - TEST_TYPE(EMRSETMITERLIMIT, 12, 4); - TEST_FIELD(EMRSETMITERLIMIT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETMITERLIMIT, FLOAT, eMiterLimit, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETMITERLIMIT, 12) + TEST_TYPE_ALIGN (EMRSETMITERLIMIT, 4) + TEST_FIELD_SIZE (EMRSETMITERLIMIT, emr, 8) + TEST_FIELD_ALIGN (EMRSETMITERLIMIT, emr, 4) + TEST_FIELD_OFFSET(EMRSETMITERLIMIT, emr, 0) + TEST_FIELD_SIZE (EMRSETMITERLIMIT, eMiterLimit, 4) + TEST_FIELD_ALIGN (EMRSETMITERLIMIT, eMiterLimit, 4) + TEST_FIELD_OFFSET(EMRSETMITERLIMIT, eMiterLimit, 8) } static void test_pack_EMRSETPIXELV(void) { /* EMRSETPIXELV (pack 4) */ - TEST_TYPE(EMRSETPIXELV, 20, 4); - TEST_FIELD(EMRSETPIXELV, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETPIXELV, POINTL, ptlPixel, 8, 8, 4); - TEST_FIELD(EMRSETPIXELV, COLORREF, crColor, 16, 4, 4); + TEST_TYPE_SIZE (EMRSETPIXELV, 20) + TEST_TYPE_ALIGN (EMRSETPIXELV, 4) + TEST_FIELD_SIZE (EMRSETPIXELV, emr, 8) + TEST_FIELD_ALIGN (EMRSETPIXELV, emr, 4) + TEST_FIELD_OFFSET(EMRSETPIXELV, emr, 0) + TEST_FIELD_SIZE (EMRSETPIXELV, ptlPixel, 8) + TEST_FIELD_ALIGN (EMRSETPIXELV, ptlPixel, 4) + TEST_FIELD_OFFSET(EMRSETPIXELV, ptlPixel, 8) + TEST_FIELD_SIZE (EMRSETPIXELV, crColor, 4) + TEST_FIELD_ALIGN (EMRSETPIXELV, crColor, 4) + TEST_FIELD_OFFSET(EMRSETPIXELV, crColor, 16) } static void test_pack_EMRSETPOLYFILLMODE(void) { /* EMRSETPOLYFILLMODE (pack 4) */ - TEST_TYPE(EMRSETPOLYFILLMODE, 12, 4); - TEST_FIELD(EMRSETPOLYFILLMODE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETPOLYFILLMODE, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETPOLYFILLMODE, 12) + TEST_TYPE_ALIGN (EMRSETPOLYFILLMODE, 4) + TEST_FIELD_SIZE (EMRSETPOLYFILLMODE, emr, 8) + TEST_FIELD_ALIGN (EMRSETPOLYFILLMODE, emr, 4) + TEST_FIELD_OFFSET(EMRSETPOLYFILLMODE, emr, 0) + TEST_FIELD_SIZE (EMRSETPOLYFILLMODE, iMode, 4) + TEST_FIELD_ALIGN (EMRSETPOLYFILLMODE, iMode, 4) + TEST_FIELD_OFFSET(EMRSETPOLYFILLMODE, iMode, 8) } static void test_pack_EMRSETROP2(void) { /* EMRSETROP2 (pack 4) */ - TEST_TYPE(EMRSETROP2, 12, 4); - TEST_FIELD(EMRSETROP2, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETROP2, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETROP2, 12) + TEST_TYPE_ALIGN (EMRSETROP2, 4) + TEST_FIELD_SIZE (EMRSETROP2, emr, 8) + TEST_FIELD_ALIGN (EMRSETROP2, emr, 4) + TEST_FIELD_OFFSET(EMRSETROP2, emr, 0) + TEST_FIELD_SIZE (EMRSETROP2, iMode, 4) + TEST_FIELD_ALIGN (EMRSETROP2, iMode, 4) + TEST_FIELD_OFFSET(EMRSETROP2, iMode, 8) } static void test_pack_EMRSETSTRETCHBLTMODE(void) { /* EMRSETSTRETCHBLTMODE (pack 4) */ - TEST_TYPE(EMRSETSTRETCHBLTMODE, 12, 4); - TEST_FIELD(EMRSETSTRETCHBLTMODE, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETSTRETCHBLTMODE, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETSTRETCHBLTMODE, 12) + TEST_TYPE_ALIGN (EMRSETSTRETCHBLTMODE, 4) + TEST_FIELD_SIZE (EMRSETSTRETCHBLTMODE, emr, 8) + TEST_FIELD_ALIGN (EMRSETSTRETCHBLTMODE, emr, 4) + TEST_FIELD_OFFSET(EMRSETSTRETCHBLTMODE, emr, 0) + TEST_FIELD_SIZE (EMRSETSTRETCHBLTMODE, iMode, 4) + TEST_FIELD_ALIGN (EMRSETSTRETCHBLTMODE, iMode, 4) + TEST_FIELD_OFFSET(EMRSETSTRETCHBLTMODE, iMode, 8) } static void test_pack_EMRSETTEXTALIGN(void) { /* EMRSETTEXTALIGN (pack 4) */ - TEST_TYPE(EMRSETTEXTALIGN, 12, 4); - TEST_FIELD(EMRSETTEXTALIGN, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETTEXTALIGN, DWORD, iMode, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETTEXTALIGN, 12) + TEST_TYPE_ALIGN (EMRSETTEXTALIGN, 4) + TEST_FIELD_SIZE (EMRSETTEXTALIGN, emr, 8) + TEST_FIELD_ALIGN (EMRSETTEXTALIGN, emr, 4) + TEST_FIELD_OFFSET(EMRSETTEXTALIGN, emr, 0) + TEST_FIELD_SIZE (EMRSETTEXTALIGN, iMode, 4) + TEST_FIELD_ALIGN (EMRSETTEXTALIGN, iMode, 4) + TEST_FIELD_OFFSET(EMRSETTEXTALIGN, iMode, 8) } static void test_pack_EMRSETTEXTCOLOR(void) { /* EMRSETTEXTCOLOR (pack 4) */ - TEST_TYPE(EMRSETTEXTCOLOR, 12, 4); - TEST_FIELD(EMRSETTEXTCOLOR, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETTEXTCOLOR, COLORREF, crColor, 8, 4, 4); + TEST_TYPE_SIZE (EMRSETTEXTCOLOR, 12) + TEST_TYPE_ALIGN (EMRSETTEXTCOLOR, 4) + TEST_FIELD_SIZE (EMRSETTEXTCOLOR, emr, 8) + TEST_FIELD_ALIGN (EMRSETTEXTCOLOR, emr, 4) + TEST_FIELD_OFFSET(EMRSETTEXTCOLOR, emr, 0) + TEST_FIELD_SIZE (EMRSETTEXTCOLOR, crColor, 4) + TEST_FIELD_ALIGN (EMRSETTEXTCOLOR, crColor, 4) + TEST_FIELD_OFFSET(EMRSETTEXTCOLOR, crColor, 8) } static void test_pack_EMRSETVIEWPORTEXTEX(void) { /* EMRSETVIEWPORTEXTEX (pack 4) */ - TEST_TYPE(EMRSETVIEWPORTEXTEX, 16, 4); - TEST_FIELD(EMRSETVIEWPORTEXTEX, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETVIEWPORTEXTEX, SIZEL, szlExtent, 8, 8, 4); + TEST_TYPE_SIZE (EMRSETVIEWPORTEXTEX, 16) + TEST_TYPE_ALIGN (EMRSETVIEWPORTEXTEX, 4) + TEST_FIELD_SIZE (EMRSETVIEWPORTEXTEX, emr, 8) + TEST_FIELD_ALIGN (EMRSETVIEWPORTEXTEX, emr, 4) + TEST_FIELD_OFFSET(EMRSETVIEWPORTEXTEX, emr, 0) + TEST_FIELD_SIZE (EMRSETVIEWPORTEXTEX, szlExtent, 8) + TEST_FIELD_ALIGN (EMRSETVIEWPORTEXTEX, szlExtent, 4) + TEST_FIELD_OFFSET(EMRSETVIEWPORTEXTEX, szlExtent, 8) } static void test_pack_EMRSETVIEWPORTORGEX(void) { /* EMRSETVIEWPORTORGEX (pack 4) */ - TEST_TYPE(EMRSETVIEWPORTORGEX, 16, 4); - TEST_FIELD(EMRSETVIEWPORTORGEX, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETVIEWPORTORGEX, POINTL, ptlOrigin, 8, 8, 4); + TEST_TYPE_SIZE (EMRSETVIEWPORTORGEX, 16) + TEST_TYPE_ALIGN (EMRSETVIEWPORTORGEX, 4) + TEST_FIELD_SIZE (EMRSETVIEWPORTORGEX, emr, 8) + TEST_FIELD_ALIGN (EMRSETVIEWPORTORGEX, emr, 4) + TEST_FIELD_OFFSET(EMRSETVIEWPORTORGEX, emr, 0) + TEST_FIELD_SIZE (EMRSETVIEWPORTORGEX, ptlOrigin, 8) + TEST_FIELD_ALIGN (EMRSETVIEWPORTORGEX, ptlOrigin, 4) + TEST_FIELD_OFFSET(EMRSETVIEWPORTORGEX, ptlOrigin, 8) } static void test_pack_EMRSETWINDOWEXTEX(void) { /* EMRSETWINDOWEXTEX (pack 4) */ - TEST_TYPE(EMRSETWINDOWEXTEX, 16, 4); - TEST_FIELD(EMRSETWINDOWEXTEX, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETWINDOWEXTEX, SIZEL, szlExtent, 8, 8, 4); + TEST_TYPE_SIZE (EMRSETWINDOWEXTEX, 16) + TEST_TYPE_ALIGN (EMRSETWINDOWEXTEX, 4) + TEST_FIELD_SIZE (EMRSETWINDOWEXTEX, emr, 8) + TEST_FIELD_ALIGN (EMRSETWINDOWEXTEX, emr, 4) + TEST_FIELD_OFFSET(EMRSETWINDOWEXTEX, emr, 0) + TEST_FIELD_SIZE (EMRSETWINDOWEXTEX, szlExtent, 8) + TEST_FIELD_ALIGN (EMRSETWINDOWEXTEX, szlExtent, 4) + TEST_FIELD_OFFSET(EMRSETWINDOWEXTEX, szlExtent, 8) } static void test_pack_EMRSETWINDOWORGEX(void) { /* EMRSETWINDOWORGEX (pack 4) */ - TEST_TYPE(EMRSETWINDOWORGEX, 16, 4); - TEST_FIELD(EMRSETWINDOWORGEX, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETWINDOWORGEX, POINTL, ptlOrigin, 8, 8, 4); + TEST_TYPE_SIZE (EMRSETWINDOWORGEX, 16) + TEST_TYPE_ALIGN (EMRSETWINDOWORGEX, 4) + TEST_FIELD_SIZE (EMRSETWINDOWORGEX, emr, 8) + TEST_FIELD_ALIGN (EMRSETWINDOWORGEX, emr, 4) + TEST_FIELD_OFFSET(EMRSETWINDOWORGEX, emr, 0) + TEST_FIELD_SIZE (EMRSETWINDOWORGEX, ptlOrigin, 8) + TEST_FIELD_ALIGN (EMRSETWINDOWORGEX, ptlOrigin, 4) + TEST_FIELD_OFFSET(EMRSETWINDOWORGEX, ptlOrigin, 8) } static void test_pack_EMRSETWORLDTRANSFORM(void) { /* EMRSETWORLDTRANSFORM (pack 4) */ - TEST_TYPE(EMRSETWORLDTRANSFORM, 32, 4); - TEST_FIELD(EMRSETWORLDTRANSFORM, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSETWORLDTRANSFORM, XFORM, xform, 8, 24, 4); + TEST_TYPE_SIZE (EMRSETWORLDTRANSFORM, 32) + TEST_TYPE_ALIGN (EMRSETWORLDTRANSFORM, 4) + TEST_FIELD_SIZE (EMRSETWORLDTRANSFORM, emr, 8) + TEST_FIELD_ALIGN (EMRSETWORLDTRANSFORM, emr, 4) + TEST_FIELD_OFFSET(EMRSETWORLDTRANSFORM, emr, 0) + TEST_FIELD_SIZE (EMRSETWORLDTRANSFORM, xform, 24) + TEST_FIELD_ALIGN (EMRSETWORLDTRANSFORM, xform, 4) + TEST_FIELD_OFFSET(EMRSETWORLDTRANSFORM, xform, 8) } static void test_pack_EMRSTRETCHBLT(void) { /* EMRSTRETCHBLT (pack 4) */ - TEST_TYPE(EMRSTRETCHBLT, 108, 4); - TEST_FIELD(EMRSTRETCHBLT, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSTRETCHBLT, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRSTRETCHBLT, LONG, xDest, 24, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, LONG, yDest, 28, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, LONG, cxDest, 32, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, LONG, cyDest, 36, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, DWORD, dwRop, 40, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, LONG, xSrc, 44, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, LONG, ySrc, 48, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, XFORM, xformSrc, 52, 24, 4); - TEST_FIELD(EMRSTRETCHBLT, COLORREF, crBkColorSrc, 76, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, DWORD, iUsageSrc, 80, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, DWORD, offBmiSrc, 84, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, DWORD, cbBmiSrc, 88, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, DWORD, offBitsSrc, 92, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, DWORD, cbBitsSrc, 96, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, LONG, cxSrc, 100, 4, 4); - TEST_FIELD(EMRSTRETCHBLT, LONG, cySrc, 104, 4, 4); + TEST_TYPE_SIZE (EMRSTRETCHBLT, 108) + TEST_TYPE_ALIGN (EMRSTRETCHBLT, 4) + TEST_FIELD_SIZE (EMRSTRETCHBLT, emr, 8) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, emr, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, emr, 0) + TEST_FIELD_SIZE (EMRSTRETCHBLT, rclBounds, 16) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, rclBounds, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, rclBounds, 8) + TEST_FIELD_SIZE (EMRSTRETCHBLT, xDest, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, xDest, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, xDest, 24) + TEST_FIELD_SIZE (EMRSTRETCHBLT, yDest, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, yDest, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, yDest, 28) + TEST_FIELD_SIZE (EMRSTRETCHBLT, cxDest, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, cxDest, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, cxDest, 32) + TEST_FIELD_SIZE (EMRSTRETCHBLT, cyDest, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, cyDest, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, cyDest, 36) + TEST_FIELD_SIZE (EMRSTRETCHBLT, dwRop, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, dwRop, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, dwRop, 40) + TEST_FIELD_SIZE (EMRSTRETCHBLT, xSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, xSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, xSrc, 44) + TEST_FIELD_SIZE (EMRSTRETCHBLT, ySrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, ySrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, ySrc, 48) + TEST_FIELD_SIZE (EMRSTRETCHBLT, xformSrc, 24) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, xformSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, xformSrc, 52) + TEST_FIELD_SIZE (EMRSTRETCHBLT, crBkColorSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, crBkColorSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, crBkColorSrc, 76) + TEST_FIELD_SIZE (EMRSTRETCHBLT, iUsageSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, iUsageSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, iUsageSrc, 80) + TEST_FIELD_SIZE (EMRSTRETCHBLT, offBmiSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, offBmiSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, offBmiSrc, 84) + TEST_FIELD_SIZE (EMRSTRETCHBLT, cbBmiSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, cbBmiSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, cbBmiSrc, 88) + TEST_FIELD_SIZE (EMRSTRETCHBLT, offBitsSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, offBitsSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, offBitsSrc, 92) + TEST_FIELD_SIZE (EMRSTRETCHBLT, cbBitsSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, cbBitsSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, cbBitsSrc, 96) + TEST_FIELD_SIZE (EMRSTRETCHBLT, cxSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, cxSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, cxSrc, 100) + TEST_FIELD_SIZE (EMRSTRETCHBLT, cySrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHBLT, cySrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHBLT, cySrc, 104) } static void test_pack_EMRSTRETCHDIBITS(void) { /* EMRSTRETCHDIBITS (pack 4) */ - TEST_TYPE(EMRSTRETCHDIBITS, 80, 4); - TEST_FIELD(EMRSTRETCHDIBITS, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSTRETCHDIBITS, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(EMRSTRETCHDIBITS, LONG, xDest, 24, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, LONG, yDest, 28, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, LONG, xSrc, 32, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, LONG, ySrc, 36, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, LONG, cxSrc, 40, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, LONG, cySrc, 44, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, DWORD, offBmiSrc, 48, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, DWORD, cbBmiSrc, 52, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, DWORD, offBitsSrc, 56, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, DWORD, cbBitsSrc, 60, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, DWORD, iUsageSrc, 64, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, DWORD, dwRop, 68, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, LONG, cxDest, 72, 4, 4); - TEST_FIELD(EMRSTRETCHDIBITS, LONG, cyDest, 76, 4, 4); + TEST_TYPE_SIZE (EMRSTRETCHDIBITS, 80) + TEST_TYPE_ALIGN (EMRSTRETCHDIBITS, 4) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, emr, 8) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, emr, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, emr, 0) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, rclBounds, 16) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, rclBounds, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, rclBounds, 8) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, xDest, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, xDest, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, xDest, 24) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, yDest, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, yDest, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, yDest, 28) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, xSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, xSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, xSrc, 32) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, ySrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, ySrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, ySrc, 36) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, cxSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, cxSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, cxSrc, 40) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, cySrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, cySrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, cySrc, 44) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, offBmiSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, offBmiSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, offBmiSrc, 48) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, cbBmiSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, cbBmiSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, cbBmiSrc, 52) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, offBitsSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, offBitsSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, offBitsSrc, 56) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, cbBitsSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, cbBitsSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, cbBitsSrc, 60) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, iUsageSrc, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, iUsageSrc, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, iUsageSrc, 64) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, dwRop, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, dwRop, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, dwRop, 68) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, cxDest, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, cxDest, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, cxDest, 72) + TEST_FIELD_SIZE (EMRSTRETCHDIBITS, cyDest, 4) + TEST_FIELD_ALIGN (EMRSTRETCHDIBITS, cyDest, 4) + TEST_FIELD_OFFSET(EMRSTRETCHDIBITS, cyDest, 76) } static void test_pack_EMRSTROKEANDFILLPATH(void) { /* EMRSTROKEANDFILLPATH (pack 4) */ - TEST_TYPE(EMRSTROKEANDFILLPATH, 24, 4); - TEST_FIELD(EMRSTROKEANDFILLPATH, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSTROKEANDFILLPATH, RECTL, rclBounds, 8, 16, 4); + TEST_TYPE_SIZE (EMRSTROKEANDFILLPATH, 24) + TEST_TYPE_ALIGN (EMRSTROKEANDFILLPATH, 4) + TEST_FIELD_SIZE (EMRSTROKEANDFILLPATH, emr, 8) + TEST_FIELD_ALIGN (EMRSTROKEANDFILLPATH, emr, 4) + TEST_FIELD_OFFSET(EMRSTROKEANDFILLPATH, emr, 0) + TEST_FIELD_SIZE (EMRSTROKEANDFILLPATH, rclBounds, 16) + TEST_FIELD_ALIGN (EMRSTROKEANDFILLPATH, rclBounds, 4) + TEST_FIELD_OFFSET(EMRSTROKEANDFILLPATH, rclBounds, 8) } static void test_pack_EMRSTROKEPATH(void) { /* EMRSTROKEPATH (pack 4) */ - TEST_TYPE(EMRSTROKEPATH, 24, 4); - TEST_FIELD(EMRSTROKEPATH, EMR, emr, 0, 8, 4); - TEST_FIELD(EMRSTROKEPATH, RECTL, rclBounds, 8, 16, 4); + TEST_TYPE_SIZE (EMRSTROKEPATH, 24) + TEST_TYPE_ALIGN (EMRSTROKEPATH, 4) + TEST_FIELD_SIZE (EMRSTROKEPATH, emr, 8) + TEST_FIELD_ALIGN (EMRSTROKEPATH, emr, 4) + TEST_FIELD_OFFSET(EMRSTROKEPATH, emr, 0) + TEST_FIELD_SIZE (EMRSTROKEPATH, rclBounds, 16) + TEST_FIELD_ALIGN (EMRSTROKEPATH, rclBounds, 4) + TEST_FIELD_OFFSET(EMRSTROKEPATH, rclBounds, 8) } static void test_pack_EMRTEXT(void) { /* EMRTEXT (pack 4) */ - TEST_TYPE(EMRTEXT, 40, 4); - TEST_FIELD(EMRTEXT, POINTL, ptlReference, 0, 8, 4); - TEST_FIELD(EMRTEXT, DWORD, nChars, 8, 4, 4); - TEST_FIELD(EMRTEXT, DWORD, offString, 12, 4, 4); - TEST_FIELD(EMRTEXT, DWORD, fOptions, 16, 4, 4); - TEST_FIELD(EMRTEXT, RECTL, rcl, 20, 16, 4); - TEST_FIELD(EMRTEXT, DWORD, offDx, 36, 4, 4); + TEST_TYPE_SIZE (EMRTEXT, 40) + TEST_TYPE_ALIGN (EMRTEXT, 4) + TEST_FIELD_SIZE (EMRTEXT, ptlReference, 8) + TEST_FIELD_ALIGN (EMRTEXT, ptlReference, 4) + TEST_FIELD_OFFSET(EMRTEXT, ptlReference, 0) + TEST_FIELD_SIZE (EMRTEXT, nChars, 4) + TEST_FIELD_ALIGN (EMRTEXT, nChars, 4) + TEST_FIELD_OFFSET(EMRTEXT, nChars, 8) + TEST_FIELD_SIZE (EMRTEXT, offString, 4) + TEST_FIELD_ALIGN (EMRTEXT, offString, 4) + TEST_FIELD_OFFSET(EMRTEXT, offString, 12) + TEST_FIELD_SIZE (EMRTEXT, fOptions, 4) + TEST_FIELD_ALIGN (EMRTEXT, fOptions, 4) + TEST_FIELD_OFFSET(EMRTEXT, fOptions, 16) + TEST_FIELD_SIZE (EMRTEXT, rcl, 16) + TEST_FIELD_ALIGN (EMRTEXT, rcl, 4) + TEST_FIELD_OFFSET(EMRTEXT, rcl, 20) + TEST_FIELD_SIZE (EMRTEXT, offDx, 4) + TEST_FIELD_ALIGN (EMRTEXT, offDx, 4) + TEST_FIELD_OFFSET(EMRTEXT, offDx, 36) } static void test_pack_EMRWIDENPATH(void) { /* EMRWIDENPATH (pack 4) */ - TEST_TYPE(EMRWIDENPATH, 8, 4); - TEST_FIELD(EMRWIDENPATH, EMR, emr, 0, 8, 4); + TEST_TYPE_SIZE (EMRWIDENPATH, 8) + TEST_TYPE_ALIGN (EMRWIDENPATH, 4) + TEST_FIELD_SIZE (EMRWIDENPATH, emr, 8) + TEST_FIELD_ALIGN (EMRWIDENPATH, emr, 4) + TEST_FIELD_OFFSET(EMRWIDENPATH, emr, 0) } static void test_pack_ENHMETAHEADER(void) { /* ENHMETAHEADER (pack 4) */ - TEST_TYPE(ENHMETAHEADER, 108, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, iType, 0, 4, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, nSize, 4, 4, 4); - TEST_FIELD(ENHMETAHEADER, RECTL, rclBounds, 8, 16, 4); - TEST_FIELD(ENHMETAHEADER, RECTL, rclFrame, 24, 16, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, dSignature, 40, 4, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, nVersion, 44, 4, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, nBytes, 48, 4, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, nRecords, 52, 4, 4); - TEST_FIELD(ENHMETAHEADER, WORD, nHandles, 56, 2, 2); - TEST_FIELD(ENHMETAHEADER, WORD, sReserved, 58, 2, 2); - TEST_FIELD(ENHMETAHEADER, DWORD, nDescription, 60, 4, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, offDescription, 64, 4, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, nPalEntries, 68, 4, 4); - TEST_FIELD(ENHMETAHEADER, SIZEL, szlDevice, 72, 8, 4); - TEST_FIELD(ENHMETAHEADER, SIZEL, szlMillimeters, 80, 8, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, cbPixelFormat, 88, 4, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, offPixelFormat, 92, 4, 4); - TEST_FIELD(ENHMETAHEADER, DWORD, bOpenGL, 96, 4, 4); - TEST_FIELD(ENHMETAHEADER, SIZEL, szlMicrometers, 100, 8, 4); + TEST_TYPE_SIZE (ENHMETAHEADER, 108) + TEST_TYPE_ALIGN (ENHMETAHEADER, 4) + TEST_FIELD_SIZE (ENHMETAHEADER, iType, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, iType, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, iType, 0) + TEST_FIELD_SIZE (ENHMETAHEADER, nSize, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, nSize, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, nSize, 4) + TEST_FIELD_SIZE (ENHMETAHEADER, rclBounds, 16) + TEST_FIELD_ALIGN (ENHMETAHEADER, rclBounds, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, rclBounds, 8) + TEST_FIELD_SIZE (ENHMETAHEADER, rclFrame, 16) + TEST_FIELD_ALIGN (ENHMETAHEADER, rclFrame, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, rclFrame, 24) + TEST_FIELD_SIZE (ENHMETAHEADER, dSignature, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, dSignature, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, dSignature, 40) + TEST_FIELD_SIZE (ENHMETAHEADER, nVersion, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, nVersion, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, nVersion, 44) + TEST_FIELD_SIZE (ENHMETAHEADER, nBytes, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, nBytes, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, nBytes, 48) + TEST_FIELD_SIZE (ENHMETAHEADER, nRecords, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, nRecords, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, nRecords, 52) + TEST_FIELD_SIZE (ENHMETAHEADER, nHandles, 2) + TEST_FIELD_ALIGN (ENHMETAHEADER, nHandles, 2) + TEST_FIELD_OFFSET(ENHMETAHEADER, nHandles, 56) + TEST_FIELD_SIZE (ENHMETAHEADER, sReserved, 2) + TEST_FIELD_ALIGN (ENHMETAHEADER, sReserved, 2) + TEST_FIELD_OFFSET(ENHMETAHEADER, sReserved, 58) + TEST_FIELD_SIZE (ENHMETAHEADER, nDescription, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, nDescription, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, nDescription, 60) + TEST_FIELD_SIZE (ENHMETAHEADER, offDescription, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, offDescription, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, offDescription, 64) + TEST_FIELD_SIZE (ENHMETAHEADER, nPalEntries, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, nPalEntries, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, nPalEntries, 68) + TEST_FIELD_SIZE (ENHMETAHEADER, szlDevice, 8) + TEST_FIELD_ALIGN (ENHMETAHEADER, szlDevice, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, szlDevice, 72) + TEST_FIELD_SIZE (ENHMETAHEADER, szlMillimeters, 8) + TEST_FIELD_ALIGN (ENHMETAHEADER, szlMillimeters, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, szlMillimeters, 80) + TEST_FIELD_SIZE (ENHMETAHEADER, cbPixelFormat, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, cbPixelFormat, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, cbPixelFormat, 88) + TEST_FIELD_SIZE (ENHMETAHEADER, offPixelFormat, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, offPixelFormat, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, offPixelFormat, 92) + TEST_FIELD_SIZE (ENHMETAHEADER, bOpenGL, 4) + TEST_FIELD_ALIGN (ENHMETAHEADER, bOpenGL, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, bOpenGL, 96) + TEST_FIELD_SIZE (ENHMETAHEADER, szlMicrometers, 8) + TEST_FIELD_ALIGN (ENHMETAHEADER, szlMicrometers, 4) + TEST_FIELD_OFFSET(ENHMETAHEADER, szlMicrometers, 100) } static void test_pack_ENHMETARECORD(void) { /* ENHMETARECORD (pack 4) */ - TEST_TYPE(ENHMETARECORD, 12, 4); - TEST_FIELD(ENHMETARECORD, DWORD, iType, 0, 4, 4); - TEST_FIELD(ENHMETARECORD, DWORD, nSize, 4, 4, 4); - TEST_FIELD(ENHMETARECORD, DWORD[1], dParm, 8, 4, 4); + TEST_TYPE_SIZE (ENHMETARECORD, 12) + TEST_TYPE_ALIGN (ENHMETARECORD, 4) + TEST_FIELD_SIZE (ENHMETARECORD, iType, 4) + TEST_FIELD_ALIGN (ENHMETARECORD, iType, 4) + TEST_FIELD_OFFSET(ENHMETARECORD, iType, 0) + TEST_FIELD_SIZE (ENHMETARECORD, nSize, 4) + TEST_FIELD_ALIGN (ENHMETARECORD, nSize, 4) + TEST_FIELD_OFFSET(ENHMETARECORD, nSize, 4) + TEST_FIELD_SIZE (ENHMETARECORD, dParm, 4) + TEST_FIELD_ALIGN (ENHMETARECORD, dParm, 4) + TEST_FIELD_OFFSET(ENHMETARECORD, dParm, 8) } static void test_pack_ENHMFENUMPROC(void) { /* ENHMFENUMPROC */ - TEST_TYPE(ENHMFENUMPROC, 4, 4); + TEST_TYPE_SIZE (ENHMFENUMPROC, 4) + TEST_TYPE_ALIGN (ENHMFENUMPROC, 4) } static void test_pack_ENUMLOGFONTA(void) { /* ENUMLOGFONTA (pack 4) */ - TEST_TYPE(ENUMLOGFONTA, 156, 4); - TEST_FIELD(ENUMLOGFONTA, LOGFONTA, elfLogFont, 0, 60, 4); - TEST_FIELD(ENUMLOGFONTA, BYTE[LF_FULLFACESIZE], elfFullName, 60, 64, 1); - TEST_FIELD(ENUMLOGFONTA, BYTE[LF_FACESIZE], elfStyle, 124, 32, 1); + TEST_TYPE_SIZE (ENUMLOGFONTA, 156) + TEST_TYPE_ALIGN (ENUMLOGFONTA, 4) + TEST_FIELD_SIZE (ENUMLOGFONTA, elfLogFont, 60) + TEST_FIELD_ALIGN (ENUMLOGFONTA, elfLogFont, 4) + TEST_FIELD_OFFSET(ENUMLOGFONTA, elfLogFont, 0) + TEST_FIELD_SIZE (ENUMLOGFONTA, elfFullName, 64) + TEST_FIELD_ALIGN (ENUMLOGFONTA, elfFullName, 1) + TEST_FIELD_OFFSET(ENUMLOGFONTA, elfFullName, 60) + TEST_FIELD_SIZE (ENUMLOGFONTA, elfStyle, 32) + TEST_FIELD_ALIGN (ENUMLOGFONTA, elfStyle, 1) + TEST_FIELD_OFFSET(ENUMLOGFONTA, elfStyle, 124) } static void test_pack_ENUMLOGFONTEXA(void) { /* ENUMLOGFONTEXA (pack 4) */ - TEST_TYPE(ENUMLOGFONTEXA, 188, 4); - TEST_FIELD(ENUMLOGFONTEXA, LOGFONTA, elfLogFont, 0, 60, 4); - TEST_FIELD(ENUMLOGFONTEXA, BYTE[LF_FULLFACESIZE], elfFullName, 60, 64, 1); - TEST_FIELD(ENUMLOGFONTEXA, BYTE[LF_FACESIZE], elfStyle, 124, 32, 1); - TEST_FIELD(ENUMLOGFONTEXA, BYTE[LF_FACESIZE], elfScript, 156, 32, 1); + TEST_TYPE_SIZE (ENUMLOGFONTEXA, 188) + TEST_TYPE_ALIGN (ENUMLOGFONTEXA, 4) + TEST_FIELD_SIZE (ENUMLOGFONTEXA, elfLogFont, 60) + TEST_FIELD_ALIGN (ENUMLOGFONTEXA, elfLogFont, 4) + TEST_FIELD_OFFSET(ENUMLOGFONTEXA, elfLogFont, 0) + TEST_FIELD_SIZE (ENUMLOGFONTEXA, elfFullName, 64) + TEST_FIELD_ALIGN (ENUMLOGFONTEXA, elfFullName, 1) + TEST_FIELD_OFFSET(ENUMLOGFONTEXA, elfFullName, 60) + TEST_FIELD_SIZE (ENUMLOGFONTEXA, elfStyle, 32) + TEST_FIELD_ALIGN (ENUMLOGFONTEXA, elfStyle, 1) + TEST_FIELD_OFFSET(ENUMLOGFONTEXA, elfStyle, 124) + TEST_FIELD_SIZE (ENUMLOGFONTEXA, elfScript, 32) + TEST_FIELD_ALIGN (ENUMLOGFONTEXA, elfScript, 1) + TEST_FIELD_OFFSET(ENUMLOGFONTEXA, elfScript, 156) } static void test_pack_ENUMLOGFONTEXW(void) { /* ENUMLOGFONTEXW (pack 4) */ - TEST_TYPE(ENUMLOGFONTEXW, 348, 4); - TEST_FIELD(ENUMLOGFONTEXW, LOGFONTW, elfLogFont, 0, 92, 4); - TEST_FIELD(ENUMLOGFONTEXW, WCHAR[LF_FULLFACESIZE], elfFullName, 92, 128, 2); - TEST_FIELD(ENUMLOGFONTEXW, WCHAR[LF_FACESIZE], elfStyle, 220, 64, 2); - TEST_FIELD(ENUMLOGFONTEXW, WCHAR[LF_FACESIZE], elfScript, 284, 64, 2); + TEST_TYPE_SIZE (ENUMLOGFONTEXW, 348) + TEST_TYPE_ALIGN (ENUMLOGFONTEXW, 4) + TEST_FIELD_SIZE (ENUMLOGFONTEXW, elfLogFont, 92) + TEST_FIELD_ALIGN (ENUMLOGFONTEXW, elfLogFont, 4) + TEST_FIELD_OFFSET(ENUMLOGFONTEXW, elfLogFont, 0) + TEST_FIELD_SIZE (ENUMLOGFONTEXW, elfFullName, 128) + TEST_FIELD_ALIGN (ENUMLOGFONTEXW, elfFullName, 2) + TEST_FIELD_OFFSET(ENUMLOGFONTEXW, elfFullName, 92) + TEST_FIELD_SIZE (ENUMLOGFONTEXW, elfStyle, 64) + TEST_FIELD_ALIGN (ENUMLOGFONTEXW, elfStyle, 2) + TEST_FIELD_OFFSET(ENUMLOGFONTEXW, elfStyle, 220) + TEST_FIELD_SIZE (ENUMLOGFONTEXW, elfScript, 64) + TEST_FIELD_ALIGN (ENUMLOGFONTEXW, elfScript, 2) + TEST_FIELD_OFFSET(ENUMLOGFONTEXW, elfScript, 284) } static void test_pack_ENUMLOGFONTW(void) { /* ENUMLOGFONTW (pack 4) */ - TEST_TYPE(ENUMLOGFONTW, 284, 4); - TEST_FIELD(ENUMLOGFONTW, LOGFONTW, elfLogFont, 0, 92, 4); - TEST_FIELD(ENUMLOGFONTW, WCHAR[LF_FULLFACESIZE], elfFullName, 92, 128, 2); - TEST_FIELD(ENUMLOGFONTW, WCHAR[LF_FACESIZE], elfStyle, 220, 64, 2); + TEST_TYPE_SIZE (ENUMLOGFONTW, 284) + TEST_TYPE_ALIGN (ENUMLOGFONTW, 4) + TEST_FIELD_SIZE (ENUMLOGFONTW, elfLogFont, 92) + TEST_FIELD_ALIGN (ENUMLOGFONTW, elfLogFont, 4) + TEST_FIELD_OFFSET(ENUMLOGFONTW, elfLogFont, 0) + TEST_FIELD_SIZE (ENUMLOGFONTW, elfFullName, 128) + TEST_FIELD_ALIGN (ENUMLOGFONTW, elfFullName, 2) + TEST_FIELD_OFFSET(ENUMLOGFONTW, elfFullName, 92) + TEST_FIELD_SIZE (ENUMLOGFONTW, elfStyle, 64) + TEST_FIELD_ALIGN (ENUMLOGFONTW, elfStyle, 2) + TEST_FIELD_OFFSET(ENUMLOGFONTW, elfStyle, 220) } static void test_pack_EXTLOGFONTA(void) { /* EXTLOGFONTA (pack 4) */ - TEST_TYPE(EXTLOGFONTA, 192, 4); - TEST_FIELD(EXTLOGFONTA, LOGFONTA, elfLogFont, 0, 60, 4); - TEST_FIELD(EXTLOGFONTA, BYTE[LF_FULLFACESIZE], elfFullName, 60, 64, 1); - TEST_FIELD(EXTLOGFONTA, BYTE[LF_FACESIZE], elfStyle, 124, 32, 1); - TEST_FIELD(EXTLOGFONTA, DWORD, elfVersion, 156, 4, 4); - TEST_FIELD(EXTLOGFONTA, DWORD, elfStyleSize, 160, 4, 4); - TEST_FIELD(EXTLOGFONTA, DWORD, elfMatch, 164, 4, 4); - TEST_FIELD(EXTLOGFONTA, DWORD, elfReserved, 168, 4, 4); - TEST_FIELD(EXTLOGFONTA, BYTE[ELF_VENDOR_SIZE], elfVendorId, 172, 4, 1); - TEST_FIELD(EXTLOGFONTA, DWORD, elfCulture, 176, 4, 4); - TEST_FIELD(EXTLOGFONTA, PANOSE, elfPanose, 180, 10, 1); + TEST_TYPE_SIZE (EXTLOGFONTA, 192) + TEST_TYPE_ALIGN (EXTLOGFONTA, 4) + TEST_FIELD_SIZE (EXTLOGFONTA, elfLogFont, 60) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfLogFont, 4) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfLogFont, 0) + TEST_FIELD_SIZE (EXTLOGFONTA, elfFullName, 64) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfFullName, 1) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfFullName, 60) + TEST_FIELD_SIZE (EXTLOGFONTA, elfStyle, 32) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfStyle, 1) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfStyle, 124) + TEST_FIELD_SIZE (EXTLOGFONTA, elfVersion, 4) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfVersion, 4) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfVersion, 156) + TEST_FIELD_SIZE (EXTLOGFONTA, elfStyleSize, 4) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfStyleSize, 4) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfStyleSize, 160) + TEST_FIELD_SIZE (EXTLOGFONTA, elfMatch, 4) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfMatch, 4) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfMatch, 164) + TEST_FIELD_SIZE (EXTLOGFONTA, elfReserved, 4) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfReserved, 4) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfReserved, 168) + TEST_FIELD_SIZE (EXTLOGFONTA, elfVendorId, 4) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfVendorId, 1) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfVendorId, 172) + TEST_FIELD_SIZE (EXTLOGFONTA, elfCulture, 4) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfCulture, 4) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfCulture, 176) + TEST_FIELD_SIZE (EXTLOGFONTA, elfPanose, 10) + TEST_FIELD_ALIGN (EXTLOGFONTA, elfPanose, 1) + TEST_FIELD_OFFSET(EXTLOGFONTA, elfPanose, 180) } static void test_pack_EXTLOGFONTW(void) { /* EXTLOGFONTW (pack 4) */ - TEST_TYPE(EXTLOGFONTW, 320, 4); - TEST_FIELD(EXTLOGFONTW, LOGFONTW, elfLogFont, 0, 92, 4); - TEST_FIELD(EXTLOGFONTW, WCHAR[LF_FULLFACESIZE], elfFullName, 92, 128, 2); - TEST_FIELD(EXTLOGFONTW, WCHAR[LF_FACESIZE], elfStyle, 220, 64, 2); - TEST_FIELD(EXTLOGFONTW, DWORD, elfVersion, 284, 4, 4); - TEST_FIELD(EXTLOGFONTW, DWORD, elfStyleSize, 288, 4, 4); - TEST_FIELD(EXTLOGFONTW, DWORD, elfMatch, 292, 4, 4); - TEST_FIELD(EXTLOGFONTW, DWORD, elfReserved, 296, 4, 4); - TEST_FIELD(EXTLOGFONTW, BYTE[ELF_VENDOR_SIZE], elfVendorId, 300, 4, 1); - TEST_FIELD(EXTLOGFONTW, DWORD, elfCulture, 304, 4, 4); - TEST_FIELD(EXTLOGFONTW, PANOSE, elfPanose, 308, 10, 1); + TEST_TYPE_SIZE (EXTLOGFONTW, 320) + TEST_TYPE_ALIGN (EXTLOGFONTW, 4) + TEST_FIELD_SIZE (EXTLOGFONTW, elfLogFont, 92) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfLogFont, 4) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfLogFont, 0) + TEST_FIELD_SIZE (EXTLOGFONTW, elfFullName, 128) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfFullName, 2) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfFullName, 92) + TEST_FIELD_SIZE (EXTLOGFONTW, elfStyle, 64) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfStyle, 2) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfStyle, 220) + TEST_FIELD_SIZE (EXTLOGFONTW, elfVersion, 4) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfVersion, 4) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfVersion, 284) + TEST_FIELD_SIZE (EXTLOGFONTW, elfStyleSize, 4) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfStyleSize, 4) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfStyleSize, 288) + TEST_FIELD_SIZE (EXTLOGFONTW, elfMatch, 4) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfMatch, 4) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfMatch, 292) + TEST_FIELD_SIZE (EXTLOGFONTW, elfReserved, 4) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfReserved, 4) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfReserved, 296) + TEST_FIELD_SIZE (EXTLOGFONTW, elfVendorId, 4) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfVendorId, 1) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfVendorId, 300) + TEST_FIELD_SIZE (EXTLOGFONTW, elfCulture, 4) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfCulture, 4) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfCulture, 304) + TEST_FIELD_SIZE (EXTLOGFONTW, elfPanose, 10) + TEST_FIELD_ALIGN (EXTLOGFONTW, elfPanose, 1) + TEST_FIELD_OFFSET(EXTLOGFONTW, elfPanose, 308) } static void test_pack_EXTLOGPEN(void) { /* EXTLOGPEN (pack 4) */ - TEST_TYPE(EXTLOGPEN, 28, 4); - TEST_FIELD(EXTLOGPEN, DWORD, elpPenStyle, 0, 4, 4); - TEST_FIELD(EXTLOGPEN, DWORD, elpWidth, 4, 4, 4); - TEST_FIELD(EXTLOGPEN, UINT, elpBrushStyle, 8, 4, 4); - TEST_FIELD(EXTLOGPEN, COLORREF, elpColor, 12, 4, 4); - TEST_FIELD(EXTLOGPEN, ULONG_PTR, elpHatch, 16, 4, 4); - TEST_FIELD(EXTLOGPEN, DWORD, elpNumEntries, 20, 4, 4); - TEST_FIELD(EXTLOGPEN, DWORD[1], elpStyleEntry, 24, 4, 4); + TEST_TYPE_SIZE (EXTLOGPEN, 28) + TEST_TYPE_ALIGN (EXTLOGPEN, 4) + TEST_FIELD_SIZE (EXTLOGPEN, elpPenStyle, 4) + TEST_FIELD_ALIGN (EXTLOGPEN, elpPenStyle, 4) + TEST_FIELD_OFFSET(EXTLOGPEN, elpPenStyle, 0) + TEST_FIELD_SIZE (EXTLOGPEN, elpWidth, 4) + TEST_FIELD_ALIGN (EXTLOGPEN, elpWidth, 4) + TEST_FIELD_OFFSET(EXTLOGPEN, elpWidth, 4) + TEST_FIELD_SIZE (EXTLOGPEN, elpBrushStyle, 4) + TEST_FIELD_ALIGN (EXTLOGPEN, elpBrushStyle, 4) + TEST_FIELD_OFFSET(EXTLOGPEN, elpBrushStyle, 8) + TEST_FIELD_SIZE (EXTLOGPEN, elpColor, 4) + TEST_FIELD_ALIGN (EXTLOGPEN, elpColor, 4) + TEST_FIELD_OFFSET(EXTLOGPEN, elpColor, 12) + TEST_FIELD_SIZE (EXTLOGPEN, elpHatch, 4) + TEST_FIELD_ALIGN (EXTLOGPEN, elpHatch, 4) + TEST_FIELD_OFFSET(EXTLOGPEN, elpHatch, 16) + TEST_FIELD_SIZE (EXTLOGPEN, elpNumEntries, 4) + TEST_FIELD_ALIGN (EXTLOGPEN, elpNumEntries, 4) + TEST_FIELD_OFFSET(EXTLOGPEN, elpNumEntries, 20) + TEST_FIELD_SIZE (EXTLOGPEN, elpStyleEntry, 4) + TEST_FIELD_ALIGN (EXTLOGPEN, elpStyleEntry, 4) + TEST_FIELD_OFFSET(EXTLOGPEN, elpStyleEntry, 24) } static void test_pack_FIXED(void) { /* FIXED (pack 4) */ - TEST_TYPE(FIXED, 4, 2); - TEST_FIELD(FIXED, WORD, fract, 0, 2, 2); - TEST_FIELD(FIXED, SHORT, value, 2, 2, 2); + TEST_TYPE_SIZE (FIXED, 4) + TEST_TYPE_ALIGN (FIXED, 2) + TEST_FIELD_SIZE (FIXED, fract, 2) + TEST_FIELD_ALIGN (FIXED, fract, 2) + TEST_FIELD_OFFSET(FIXED, fract, 0) + TEST_FIELD_SIZE (FIXED, value, 2) + TEST_FIELD_ALIGN (FIXED, value, 2) + TEST_FIELD_OFFSET(FIXED, value, 2) } static void test_pack_FONTENUMPROCA(void) { /* FONTENUMPROCA */ - TEST_TYPE(FONTENUMPROCA, 4, 4); + TEST_TYPE_SIZE (FONTENUMPROCA, 4) + TEST_TYPE_ALIGN (FONTENUMPROCA, 4) } static void test_pack_FONTENUMPROCW(void) { /* FONTENUMPROCW */ - TEST_TYPE(FONTENUMPROCW, 4, 4); + TEST_TYPE_SIZE (FONTENUMPROCW, 4) + TEST_TYPE_ALIGN (FONTENUMPROCW, 4) } static void test_pack_FONTSIGNATURE(void) { /* FONTSIGNATURE (pack 4) */ - TEST_TYPE(FONTSIGNATURE, 24, 4); - TEST_FIELD(FONTSIGNATURE, DWORD[4], fsUsb, 0, 16, 4); - TEST_FIELD(FONTSIGNATURE, DWORD[2], fsCsb, 16, 8, 4); + TEST_TYPE_SIZE (FONTSIGNATURE, 24) + TEST_TYPE_ALIGN (FONTSIGNATURE, 4) + TEST_FIELD_SIZE (FONTSIGNATURE, fsUsb, 16) + TEST_FIELD_ALIGN (FONTSIGNATURE, fsUsb, 4) + TEST_FIELD_OFFSET(FONTSIGNATURE, fsUsb, 0) + TEST_FIELD_SIZE (FONTSIGNATURE, fsCsb, 8) + TEST_FIELD_ALIGN (FONTSIGNATURE, fsCsb, 4) + TEST_FIELD_OFFSET(FONTSIGNATURE, fsCsb, 16) } static void test_pack_FXPT16DOT16(void) { /* FXPT16DOT16 */ - TEST_TYPE(FXPT16DOT16, 4, 4); + TEST_TYPE_SIZE (FXPT16DOT16, 4) + TEST_TYPE_ALIGN (FXPT16DOT16, 4) } static void test_pack_FXPT2DOT30(void) { /* FXPT2DOT30 */ - TEST_TYPE(FXPT2DOT30, 4, 4); + TEST_TYPE_SIZE (FXPT2DOT30, 4) + TEST_TYPE_ALIGN (FXPT2DOT30, 4) } static void test_pack_GCP_RESULTSA(void) { /* GCP_RESULTSA (pack 4) */ - TEST_TYPE(GCP_RESULTSA, 36, 4); - TEST_FIELD(GCP_RESULTSA, DWORD, lStructSize, 0, 4, 4); - TEST_FIELD(GCP_RESULTSA, LPSTR, lpOutString, 4, 4, 4); - TEST_FIELD(GCP_RESULTSA, UINT *, lpOrder, 8, 4, 4); - TEST_FIELD(GCP_RESULTSA, INT *, lpDx, 12, 4, 4); - TEST_FIELD(GCP_RESULTSA, INT *, lpCaretPos, 16, 4, 4); - TEST_FIELD(GCP_RESULTSA, LPSTR, lpClass, 20, 4, 4); - TEST_FIELD(GCP_RESULTSA, LPWSTR, lpGlyphs, 24, 4, 4); - TEST_FIELD(GCP_RESULTSA, UINT, nGlyphs, 28, 4, 4); - TEST_FIELD(GCP_RESULTSA, UINT, nMaxFit, 32, 4, 4); + TEST_TYPE_SIZE (GCP_RESULTSA, 36) + TEST_TYPE_ALIGN (GCP_RESULTSA, 4) + TEST_FIELD_SIZE (GCP_RESULTSA, lStructSize, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, lStructSize, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, lStructSize, 0) + TEST_FIELD_SIZE (GCP_RESULTSA, lpOutString, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, lpOutString, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, lpOutString, 4) + TEST_FIELD_SIZE (GCP_RESULTSA, lpOrder, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, lpOrder, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, lpOrder, 8) + TEST_FIELD_SIZE (GCP_RESULTSA, lpDx, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, lpDx, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, lpDx, 12) + TEST_FIELD_SIZE (GCP_RESULTSA, lpCaretPos, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, lpCaretPos, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, lpCaretPos, 16) + TEST_FIELD_SIZE (GCP_RESULTSA, lpClass, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, lpClass, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, lpClass, 20) + TEST_FIELD_SIZE (GCP_RESULTSA, lpGlyphs, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, lpGlyphs, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, lpGlyphs, 24) + TEST_FIELD_SIZE (GCP_RESULTSA, nGlyphs, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, nGlyphs, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, nGlyphs, 28) + TEST_FIELD_SIZE (GCP_RESULTSA, nMaxFit, 4) + TEST_FIELD_ALIGN (GCP_RESULTSA, nMaxFit, 4) + TEST_FIELD_OFFSET(GCP_RESULTSA, nMaxFit, 32) } static void test_pack_GCP_RESULTSW(void) { /* GCP_RESULTSW (pack 4) */ - TEST_TYPE(GCP_RESULTSW, 36, 4); - TEST_FIELD(GCP_RESULTSW, DWORD, lStructSize, 0, 4, 4); - TEST_FIELD(GCP_RESULTSW, LPWSTR, lpOutString, 4, 4, 4); - TEST_FIELD(GCP_RESULTSW, UINT *, lpOrder, 8, 4, 4); - TEST_FIELD(GCP_RESULTSW, INT *, lpDx, 12, 4, 4); - TEST_FIELD(GCP_RESULTSW, INT *, lpCaretPos, 16, 4, 4); - TEST_FIELD(GCP_RESULTSW, LPSTR, lpClass, 20, 4, 4); - TEST_FIELD(GCP_RESULTSW, LPWSTR, lpGlyphs, 24, 4, 4); - TEST_FIELD(GCP_RESULTSW, UINT, nGlyphs, 28, 4, 4); - TEST_FIELD(GCP_RESULTSW, UINT, nMaxFit, 32, 4, 4); + TEST_TYPE_SIZE (GCP_RESULTSW, 36) + TEST_TYPE_ALIGN (GCP_RESULTSW, 4) + TEST_FIELD_SIZE (GCP_RESULTSW, lStructSize, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, lStructSize, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, lStructSize, 0) + TEST_FIELD_SIZE (GCP_RESULTSW, lpOutString, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, lpOutString, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, lpOutString, 4) + TEST_FIELD_SIZE (GCP_RESULTSW, lpOrder, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, lpOrder, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, lpOrder, 8) + TEST_FIELD_SIZE (GCP_RESULTSW, lpDx, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, lpDx, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, lpDx, 12) + TEST_FIELD_SIZE (GCP_RESULTSW, lpCaretPos, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, lpCaretPos, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, lpCaretPos, 16) + TEST_FIELD_SIZE (GCP_RESULTSW, lpClass, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, lpClass, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, lpClass, 20) + TEST_FIELD_SIZE (GCP_RESULTSW, lpGlyphs, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, lpGlyphs, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, lpGlyphs, 24) + TEST_FIELD_SIZE (GCP_RESULTSW, nGlyphs, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, nGlyphs, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, nGlyphs, 28) + TEST_FIELD_SIZE (GCP_RESULTSW, nMaxFit, 4) + TEST_FIELD_ALIGN (GCP_RESULTSW, nMaxFit, 4) + TEST_FIELD_OFFSET(GCP_RESULTSW, nMaxFit, 32) } static void test_pack_GLYPHMETRICS(void) { /* GLYPHMETRICS (pack 4) */ - TEST_TYPE(GLYPHMETRICS, 20, 4); - TEST_FIELD(GLYPHMETRICS, UINT, gmBlackBoxX, 0, 4, 4); - TEST_FIELD(GLYPHMETRICS, UINT, gmBlackBoxY, 4, 4, 4); - TEST_FIELD(GLYPHMETRICS, POINT, gmptGlyphOrigin, 8, 8, 4); - TEST_FIELD(GLYPHMETRICS, SHORT, gmCellIncX, 16, 2, 2); - TEST_FIELD(GLYPHMETRICS, SHORT, gmCellIncY, 18, 2, 2); + TEST_TYPE_SIZE (GLYPHMETRICS, 20) + TEST_TYPE_ALIGN (GLYPHMETRICS, 4) + TEST_FIELD_SIZE (GLYPHMETRICS, gmBlackBoxX, 4) + TEST_FIELD_ALIGN (GLYPHMETRICS, gmBlackBoxX, 4) + TEST_FIELD_OFFSET(GLYPHMETRICS, gmBlackBoxX, 0) + TEST_FIELD_SIZE (GLYPHMETRICS, gmBlackBoxY, 4) + TEST_FIELD_ALIGN (GLYPHMETRICS, gmBlackBoxY, 4) + TEST_FIELD_OFFSET(GLYPHMETRICS, gmBlackBoxY, 4) + TEST_FIELD_SIZE (GLYPHMETRICS, gmptGlyphOrigin, 8) + TEST_FIELD_ALIGN (GLYPHMETRICS, gmptGlyphOrigin, 4) + TEST_FIELD_OFFSET(GLYPHMETRICS, gmptGlyphOrigin, 8) + TEST_FIELD_SIZE (GLYPHMETRICS, gmCellIncX, 2) + TEST_FIELD_ALIGN (GLYPHMETRICS, gmCellIncX, 2) + TEST_FIELD_OFFSET(GLYPHMETRICS, gmCellIncX, 16) + TEST_FIELD_SIZE (GLYPHMETRICS, gmCellIncY, 2) + TEST_FIELD_ALIGN (GLYPHMETRICS, gmCellIncY, 2) + TEST_FIELD_OFFSET(GLYPHMETRICS, gmCellIncY, 18) } static void test_pack_GLYPHMETRICSFLOAT(void) { /* GLYPHMETRICSFLOAT (pack 4) */ - TEST_TYPE(GLYPHMETRICSFLOAT, 24, 4); - TEST_FIELD(GLYPHMETRICSFLOAT, FLOAT, gmfBlackBoxX, 0, 4, 4); - TEST_FIELD(GLYPHMETRICSFLOAT, FLOAT, gmfBlackBoxY, 4, 4, 4); - TEST_FIELD(GLYPHMETRICSFLOAT, POINTFLOAT, gmfptGlyphOrigin, 8, 8, 4); - TEST_FIELD(GLYPHMETRICSFLOAT, FLOAT, gmfCellIncX, 16, 4, 4); - TEST_FIELD(GLYPHMETRICSFLOAT, FLOAT, gmfCellIncY, 20, 4, 4); + TEST_TYPE_SIZE (GLYPHMETRICSFLOAT, 24) + TEST_TYPE_ALIGN (GLYPHMETRICSFLOAT, 4) + TEST_FIELD_SIZE (GLYPHMETRICSFLOAT, gmfBlackBoxX, 4) + TEST_FIELD_ALIGN (GLYPHMETRICSFLOAT, gmfBlackBoxX, 4) + TEST_FIELD_OFFSET(GLYPHMETRICSFLOAT, gmfBlackBoxX, 0) + TEST_FIELD_SIZE (GLYPHMETRICSFLOAT, gmfBlackBoxY, 4) + TEST_FIELD_ALIGN (GLYPHMETRICSFLOAT, gmfBlackBoxY, 4) + TEST_FIELD_OFFSET(GLYPHMETRICSFLOAT, gmfBlackBoxY, 4) + TEST_FIELD_SIZE (GLYPHMETRICSFLOAT, gmfptGlyphOrigin, 8) + TEST_FIELD_ALIGN (GLYPHMETRICSFLOAT, gmfptGlyphOrigin, 4) + TEST_FIELD_OFFSET(GLYPHMETRICSFLOAT, gmfptGlyphOrigin, 8) + TEST_FIELD_SIZE (GLYPHMETRICSFLOAT, gmfCellIncX, 4) + TEST_FIELD_ALIGN (GLYPHMETRICSFLOAT, gmfCellIncX, 4) + TEST_FIELD_OFFSET(GLYPHMETRICSFLOAT, gmfCellIncX, 16) + TEST_FIELD_SIZE (GLYPHMETRICSFLOAT, gmfCellIncY, 4) + TEST_FIELD_ALIGN (GLYPHMETRICSFLOAT, gmfCellIncY, 4) + TEST_FIELD_OFFSET(GLYPHMETRICSFLOAT, gmfCellIncY, 20) } static void test_pack_GOBJENUMPROC(void) { /* GOBJENUMPROC */ - TEST_TYPE(GOBJENUMPROC, 4, 4); + TEST_TYPE_SIZE (GOBJENUMPROC, 4) + TEST_TYPE_ALIGN (GOBJENUMPROC, 4) } static void test_pack_GRADIENT_RECT(void) { /* GRADIENT_RECT (pack 4) */ - TEST_TYPE(GRADIENT_RECT, 8, 4); - TEST_FIELD(GRADIENT_RECT, ULONG, UpperLeft, 0, 4, 4); - TEST_FIELD(GRADIENT_RECT, ULONG, LowerRight, 4, 4, 4); + TEST_TYPE_SIZE (GRADIENT_RECT, 8) + TEST_TYPE_ALIGN (GRADIENT_RECT, 4) + TEST_FIELD_SIZE (GRADIENT_RECT, UpperLeft, 4) + TEST_FIELD_ALIGN (GRADIENT_RECT, UpperLeft, 4) + TEST_FIELD_OFFSET(GRADIENT_RECT, UpperLeft, 0) + TEST_FIELD_SIZE (GRADIENT_RECT, LowerRight, 4) + TEST_FIELD_ALIGN (GRADIENT_RECT, LowerRight, 4) + TEST_FIELD_OFFSET(GRADIENT_RECT, LowerRight, 4) } static void test_pack_GRADIENT_TRIANGLE(void) { /* GRADIENT_TRIANGLE (pack 4) */ - TEST_TYPE(GRADIENT_TRIANGLE, 12, 4); - TEST_FIELD(GRADIENT_TRIANGLE, ULONG, Vertex1, 0, 4, 4); - TEST_FIELD(GRADIENT_TRIANGLE, ULONG, Vertex2, 4, 4, 4); - TEST_FIELD(GRADIENT_TRIANGLE, ULONG, Vertex3, 8, 4, 4); + TEST_TYPE_SIZE (GRADIENT_TRIANGLE, 12) + TEST_TYPE_ALIGN (GRADIENT_TRIANGLE, 4) + TEST_FIELD_SIZE (GRADIENT_TRIANGLE, Vertex1, 4) + TEST_FIELD_ALIGN (GRADIENT_TRIANGLE, Vertex1, 4) + TEST_FIELD_OFFSET(GRADIENT_TRIANGLE, Vertex1, 0) + TEST_FIELD_SIZE (GRADIENT_TRIANGLE, Vertex2, 4) + TEST_FIELD_ALIGN (GRADIENT_TRIANGLE, Vertex2, 4) + TEST_FIELD_OFFSET(GRADIENT_TRIANGLE, Vertex2, 4) + TEST_FIELD_SIZE (GRADIENT_TRIANGLE, Vertex3, 4) + TEST_FIELD_ALIGN (GRADIENT_TRIANGLE, Vertex3, 4) + TEST_FIELD_OFFSET(GRADIENT_TRIANGLE, Vertex3, 8) } static void test_pack_HANDLETABLE(void) { /* HANDLETABLE (pack 4) */ - TEST_TYPE(HANDLETABLE, 4, 4); - TEST_FIELD(HANDLETABLE, HGDIOBJ[1], objectHandle, 0, 4, 4); + TEST_TYPE_SIZE (HANDLETABLE, 4) + TEST_TYPE_ALIGN (HANDLETABLE, 4) + TEST_FIELD_SIZE (HANDLETABLE, objectHandle, 4) + TEST_FIELD_ALIGN (HANDLETABLE, objectHandle, 4) + TEST_FIELD_OFFSET(HANDLETABLE, objectHandle, 0) } static void test_pack_ICMENUMPROCA(void) { /* ICMENUMPROCA */ - TEST_TYPE(ICMENUMPROCA, 4, 4); + TEST_TYPE_SIZE (ICMENUMPROCA, 4) + TEST_TYPE_ALIGN (ICMENUMPROCA, 4) } static void test_pack_ICMENUMPROCW(void) { /* ICMENUMPROCW */ - TEST_TYPE(ICMENUMPROCW, 4, 4); + TEST_TYPE_SIZE (ICMENUMPROCW, 4) + TEST_TYPE_ALIGN (ICMENUMPROCW, 4) } static void test_pack_KERNINGPAIR(void) { /* KERNINGPAIR (pack 4) */ - TEST_TYPE(KERNINGPAIR, 8, 4); - TEST_FIELD(KERNINGPAIR, WORD, wFirst, 0, 2, 2); - TEST_FIELD(KERNINGPAIR, WORD, wSecond, 2, 2, 2); - TEST_FIELD(KERNINGPAIR, INT, iKernAmount, 4, 4, 4); + TEST_TYPE_SIZE (KERNINGPAIR, 8) + TEST_TYPE_ALIGN (KERNINGPAIR, 4) + TEST_FIELD_SIZE (KERNINGPAIR, wFirst, 2) + TEST_FIELD_ALIGN (KERNINGPAIR, wFirst, 2) + TEST_FIELD_OFFSET(KERNINGPAIR, wFirst, 0) + TEST_FIELD_SIZE (KERNINGPAIR, wSecond, 2) + TEST_FIELD_ALIGN (KERNINGPAIR, wSecond, 2) + TEST_FIELD_OFFSET(KERNINGPAIR, wSecond, 2) + TEST_FIELD_SIZE (KERNINGPAIR, iKernAmount, 4) + TEST_FIELD_ALIGN (KERNINGPAIR, iKernAmount, 4) + TEST_FIELD_OFFSET(KERNINGPAIR, iKernAmount, 4) } static void test_pack_LAYERPLANEDESCRIPTOR(void) { /* LAYERPLANEDESCRIPTOR (pack 4) */ - TEST_TYPE(LAYERPLANEDESCRIPTOR, 32, 4); - TEST_FIELD(LAYERPLANEDESCRIPTOR, WORD, nSize, 0, 2, 2); - TEST_FIELD(LAYERPLANEDESCRIPTOR, WORD, nVersion, 2, 2, 2); - TEST_FIELD(LAYERPLANEDESCRIPTOR, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, iPixelType, 8, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cColorBits, 9, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cRedBits, 10, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cRedShift, 11, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cGreenBits, 12, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cGreenShift, 13, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cBlueBits, 14, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cBlueShift, 15, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cAlphaBits, 16, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cAlphaShift, 17, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cAccumBits, 18, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cAccumRedBits, 19, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cAccumGreenBits, 20, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cAccumBlueBits, 21, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cAccumAlphaBits, 22, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cDepthBits, 23, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cStencilBits, 24, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, cAuxBuffers, 25, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, iLayerPlane, 26, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, BYTE, bReserved, 27, 1, 1); - TEST_FIELD(LAYERPLANEDESCRIPTOR, COLORREF, crTransparent, 28, 4, 4); + TEST_TYPE_SIZE (LAYERPLANEDESCRIPTOR, 32) + TEST_TYPE_ALIGN (LAYERPLANEDESCRIPTOR, 4) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, nSize, 2) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, nSize, 2) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, nSize, 0) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, nVersion, 2) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, nVersion, 2) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, nVersion, 2) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, dwFlags, 4) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, dwFlags, 4) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, dwFlags, 4) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, iPixelType, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, iPixelType, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, iPixelType, 8) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cColorBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cColorBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cColorBits, 9) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cRedBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cRedBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cRedBits, 10) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cRedShift, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cRedShift, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cRedShift, 11) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cGreenBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cGreenBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cGreenBits, 12) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cGreenShift, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cGreenShift, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cGreenShift, 13) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cBlueBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cBlueBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cBlueBits, 14) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cBlueShift, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cBlueShift, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cBlueShift, 15) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cAlphaBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cAlphaBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cAlphaBits, 16) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cAlphaShift, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cAlphaShift, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cAlphaShift, 17) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cAccumBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cAccumBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cAccumBits, 18) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cAccumRedBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cAccumRedBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cAccumRedBits, 19) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cAccumGreenBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cAccumGreenBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cAccumGreenBits, 20) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cAccumBlueBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cAccumBlueBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cAccumBlueBits, 21) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cAccumAlphaBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cAccumAlphaBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cAccumAlphaBits, 22) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cDepthBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cDepthBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cDepthBits, 23) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cStencilBits, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cStencilBits, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cStencilBits, 24) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, cAuxBuffers, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, cAuxBuffers, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, cAuxBuffers, 25) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, iLayerPlane, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, iLayerPlane, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, iLayerPlane, 26) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, bReserved, 1) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, bReserved, 1) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, bReserved, 27) + TEST_FIELD_SIZE (LAYERPLANEDESCRIPTOR, crTransparent, 4) + TEST_FIELD_ALIGN (LAYERPLANEDESCRIPTOR, crTransparent, 4) + TEST_FIELD_OFFSET(LAYERPLANEDESCRIPTOR, crTransparent, 28) } static void test_pack_LCSCSTYPE(void) { /* LCSCSTYPE */ - TEST_TYPE(LCSCSTYPE, 4, 4); + TEST_TYPE_SIZE (LCSCSTYPE, 4) + TEST_TYPE_ALIGN (LCSCSTYPE, 4) } static void test_pack_LCSGAMUTMATCH(void) { /* LCSGAMUTMATCH */ - TEST_TYPE(LCSGAMUTMATCH, 4, 4); + TEST_TYPE_SIZE (LCSGAMUTMATCH, 4) + TEST_TYPE_ALIGN (LCSGAMUTMATCH, 4) } static void test_pack_LINEDDAPROC(void) { /* LINEDDAPROC */ - TEST_TYPE(LINEDDAPROC, 4, 4); + TEST_TYPE_SIZE (LINEDDAPROC, 4) + TEST_TYPE_ALIGN (LINEDDAPROC, 4) } static void test_pack_LOCALESIGNATURE(void) { /* LOCALESIGNATURE (pack 4) */ - TEST_TYPE(LOCALESIGNATURE, 32, 4); - TEST_FIELD(LOCALESIGNATURE, DWORD[4], lsUsb, 0, 16, 4); - TEST_FIELD(LOCALESIGNATURE, DWORD[2], lsCsbDefault, 16, 8, 4); - TEST_FIELD(LOCALESIGNATURE, DWORD[2], lsCsbSupported, 24, 8, 4); + TEST_TYPE_SIZE (LOCALESIGNATURE, 32) + TEST_TYPE_ALIGN (LOCALESIGNATURE, 4) + TEST_FIELD_SIZE (LOCALESIGNATURE, lsUsb, 16) + TEST_FIELD_ALIGN (LOCALESIGNATURE, lsUsb, 4) + TEST_FIELD_OFFSET(LOCALESIGNATURE, lsUsb, 0) + TEST_FIELD_SIZE (LOCALESIGNATURE, lsCsbDefault, 8) + TEST_FIELD_ALIGN (LOCALESIGNATURE, lsCsbDefault, 4) + TEST_FIELD_OFFSET(LOCALESIGNATURE, lsCsbDefault, 16) + TEST_FIELD_SIZE (LOCALESIGNATURE, lsCsbSupported, 8) + TEST_FIELD_ALIGN (LOCALESIGNATURE, lsCsbSupported, 4) + TEST_FIELD_OFFSET(LOCALESIGNATURE, lsCsbSupported, 24) } static void test_pack_LOGBRUSH(void) { /* LOGBRUSH (pack 4) */ - TEST_TYPE(LOGBRUSH, 12, 4); - TEST_FIELD(LOGBRUSH, UINT, lbStyle, 0, 4, 4); - TEST_FIELD(LOGBRUSH, COLORREF, lbColor, 4, 4, 4); - TEST_FIELD(LOGBRUSH, ULONG_PTR, lbHatch, 8, 4, 4); + TEST_TYPE_SIZE (LOGBRUSH, 12) + TEST_TYPE_ALIGN (LOGBRUSH, 4) + TEST_FIELD_SIZE (LOGBRUSH, lbStyle, 4) + TEST_FIELD_ALIGN (LOGBRUSH, lbStyle, 4) + TEST_FIELD_OFFSET(LOGBRUSH, lbStyle, 0) + TEST_FIELD_SIZE (LOGBRUSH, lbColor, 4) + TEST_FIELD_ALIGN (LOGBRUSH, lbColor, 4) + TEST_FIELD_OFFSET(LOGBRUSH, lbColor, 4) + TEST_FIELD_SIZE (LOGBRUSH, lbHatch, 4) + TEST_FIELD_ALIGN (LOGBRUSH, lbHatch, 4) + TEST_FIELD_OFFSET(LOGBRUSH, lbHatch, 8) } static void test_pack_LOGCOLORSPACEA(void) { /* LOGCOLORSPACEA (pack 4) */ - TEST_TYPE(LOGCOLORSPACEA, 328, 4); - TEST_FIELD(LOGCOLORSPACEA, DWORD, lcsSignature, 0, 4, 4); - TEST_FIELD(LOGCOLORSPACEA, DWORD, lcsVersion, 4, 4, 4); - TEST_FIELD(LOGCOLORSPACEA, DWORD, lcsSize, 8, 4, 4); - TEST_FIELD(LOGCOLORSPACEA, LCSCSTYPE, lcsCSType, 12, 4, 4); - TEST_FIELD(LOGCOLORSPACEA, LCSGAMUTMATCH, lcsIntent, 16, 4, 4); - TEST_FIELD(LOGCOLORSPACEA, CIEXYZTRIPLE, lcsEndpoints, 20, 36, 4); - TEST_FIELD(LOGCOLORSPACEA, DWORD, lcsGammaRed, 56, 4, 4); - TEST_FIELD(LOGCOLORSPACEA, DWORD, lcsGammaGreen, 60, 4, 4); - TEST_FIELD(LOGCOLORSPACEA, DWORD, lcsGammaBlue, 64, 4, 4); - TEST_FIELD(LOGCOLORSPACEA, CHAR[MAX_PATH], lcsFilename, 68, 260, 1); + TEST_TYPE_SIZE (LOGCOLORSPACEA, 328) + TEST_TYPE_ALIGN (LOGCOLORSPACEA, 4) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsSignature, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsSignature, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsSignature, 0) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsVersion, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsVersion, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsVersion, 4) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsSize, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsSize, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsSize, 8) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsCSType, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsCSType, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsCSType, 12) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsIntent, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsIntent, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsIntent, 16) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsEndpoints, 36) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsEndpoints, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsEndpoints, 20) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsGammaRed, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsGammaRed, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsGammaRed, 56) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsGammaGreen, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsGammaGreen, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsGammaGreen, 60) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsGammaBlue, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsGammaBlue, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsGammaBlue, 64) + TEST_FIELD_SIZE (LOGCOLORSPACEA, lcsFilename, 260) + TEST_FIELD_ALIGN (LOGCOLORSPACEA, lcsFilename, 1) + TEST_FIELD_OFFSET(LOGCOLORSPACEA, lcsFilename, 68) } static void test_pack_LOGCOLORSPACEW(void) { /* LOGCOLORSPACEW (pack 4) */ - TEST_TYPE(LOGCOLORSPACEW, 588, 4); - TEST_FIELD(LOGCOLORSPACEW, DWORD, lcsSignature, 0, 4, 4); - TEST_FIELD(LOGCOLORSPACEW, DWORD, lcsVersion, 4, 4, 4); - TEST_FIELD(LOGCOLORSPACEW, DWORD, lcsSize, 8, 4, 4); - TEST_FIELD(LOGCOLORSPACEW, LCSCSTYPE, lcsCSType, 12, 4, 4); - TEST_FIELD(LOGCOLORSPACEW, LCSGAMUTMATCH, lcsIntent, 16, 4, 4); - TEST_FIELD(LOGCOLORSPACEW, CIEXYZTRIPLE, lcsEndpoints, 20, 36, 4); - TEST_FIELD(LOGCOLORSPACEW, DWORD, lcsGammaRed, 56, 4, 4); - TEST_FIELD(LOGCOLORSPACEW, DWORD, lcsGammaGreen, 60, 4, 4); - TEST_FIELD(LOGCOLORSPACEW, DWORD, lcsGammaBlue, 64, 4, 4); - TEST_FIELD(LOGCOLORSPACEW, WCHAR[MAX_PATH], lcsFilename, 68, 520, 2); + TEST_TYPE_SIZE (LOGCOLORSPACEW, 588) + TEST_TYPE_ALIGN (LOGCOLORSPACEW, 4) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsSignature, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsSignature, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsSignature, 0) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsVersion, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsVersion, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsVersion, 4) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsSize, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsSize, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsSize, 8) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsCSType, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsCSType, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsCSType, 12) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsIntent, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsIntent, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsIntent, 16) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsEndpoints, 36) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsEndpoints, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsEndpoints, 20) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsGammaRed, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsGammaRed, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsGammaRed, 56) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsGammaGreen, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsGammaGreen, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsGammaGreen, 60) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsGammaBlue, 4) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsGammaBlue, 4) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsGammaBlue, 64) + TEST_FIELD_SIZE (LOGCOLORSPACEW, lcsFilename, 520) + TEST_FIELD_ALIGN (LOGCOLORSPACEW, lcsFilename, 2) + TEST_FIELD_OFFSET(LOGCOLORSPACEW, lcsFilename, 68) } static void test_pack_LOGFONTA(void) { /* LOGFONTA (pack 4) */ - TEST_TYPE(LOGFONTA, 60, 4); - TEST_FIELD(LOGFONTA, LONG, lfHeight, 0, 4, 4); - TEST_FIELD(LOGFONTA, LONG, lfWidth, 4, 4, 4); - TEST_FIELD(LOGFONTA, LONG, lfEscapement, 8, 4, 4); - TEST_FIELD(LOGFONTA, LONG, lfOrientation, 12, 4, 4); - TEST_FIELD(LOGFONTA, LONG, lfWeight, 16, 4, 4); - TEST_FIELD(LOGFONTA, BYTE, lfItalic, 20, 1, 1); - TEST_FIELD(LOGFONTA, BYTE, lfUnderline, 21, 1, 1); - TEST_FIELD(LOGFONTA, BYTE, lfStrikeOut, 22, 1, 1); - TEST_FIELD(LOGFONTA, BYTE, lfCharSet, 23, 1, 1); - TEST_FIELD(LOGFONTA, BYTE, lfOutPrecision, 24, 1, 1); - TEST_FIELD(LOGFONTA, BYTE, lfClipPrecision, 25, 1, 1); - TEST_FIELD(LOGFONTA, BYTE, lfQuality, 26, 1, 1); - TEST_FIELD(LOGFONTA, BYTE, lfPitchAndFamily, 27, 1, 1); - TEST_FIELD(LOGFONTA, CHAR[LF_FACESIZE], lfFaceName, 28, 32, 1); + TEST_TYPE_SIZE (LOGFONTA, 60) + TEST_TYPE_ALIGN (LOGFONTA, 4) + TEST_FIELD_SIZE (LOGFONTA, lfHeight, 4) + TEST_FIELD_ALIGN (LOGFONTA, lfHeight, 4) + TEST_FIELD_OFFSET(LOGFONTA, lfHeight, 0) + TEST_FIELD_SIZE (LOGFONTA, lfWidth, 4) + TEST_FIELD_ALIGN (LOGFONTA, lfWidth, 4) + TEST_FIELD_OFFSET(LOGFONTA, lfWidth, 4) + TEST_FIELD_SIZE (LOGFONTA, lfEscapement, 4) + TEST_FIELD_ALIGN (LOGFONTA, lfEscapement, 4) + TEST_FIELD_OFFSET(LOGFONTA, lfEscapement, 8) + TEST_FIELD_SIZE (LOGFONTA, lfOrientation, 4) + TEST_FIELD_ALIGN (LOGFONTA, lfOrientation, 4) + TEST_FIELD_OFFSET(LOGFONTA, lfOrientation, 12) + TEST_FIELD_SIZE (LOGFONTA, lfWeight, 4) + TEST_FIELD_ALIGN (LOGFONTA, lfWeight, 4) + TEST_FIELD_OFFSET(LOGFONTA, lfWeight, 16) + TEST_FIELD_SIZE (LOGFONTA, lfItalic, 1) + TEST_FIELD_ALIGN (LOGFONTA, lfItalic, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfItalic, 20) + TEST_FIELD_SIZE (LOGFONTA, lfUnderline, 1) + TEST_FIELD_ALIGN (LOGFONTA, lfUnderline, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfUnderline, 21) + TEST_FIELD_SIZE (LOGFONTA, lfStrikeOut, 1) + TEST_FIELD_ALIGN (LOGFONTA, lfStrikeOut, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfStrikeOut, 22) + TEST_FIELD_SIZE (LOGFONTA, lfCharSet, 1) + TEST_FIELD_ALIGN (LOGFONTA, lfCharSet, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfCharSet, 23) + TEST_FIELD_SIZE (LOGFONTA, lfOutPrecision, 1) + TEST_FIELD_ALIGN (LOGFONTA, lfOutPrecision, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfOutPrecision, 24) + TEST_FIELD_SIZE (LOGFONTA, lfClipPrecision, 1) + TEST_FIELD_ALIGN (LOGFONTA, lfClipPrecision, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfClipPrecision, 25) + TEST_FIELD_SIZE (LOGFONTA, lfQuality, 1) + TEST_FIELD_ALIGN (LOGFONTA, lfQuality, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfQuality, 26) + TEST_FIELD_SIZE (LOGFONTA, lfPitchAndFamily, 1) + TEST_FIELD_ALIGN (LOGFONTA, lfPitchAndFamily, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfPitchAndFamily, 27) + TEST_FIELD_SIZE (LOGFONTA, lfFaceName, 32) + TEST_FIELD_ALIGN (LOGFONTA, lfFaceName, 1) + TEST_FIELD_OFFSET(LOGFONTA, lfFaceName, 28) } static void test_pack_LOGFONTW(void) { /* LOGFONTW (pack 4) */ - TEST_TYPE(LOGFONTW, 92, 4); - TEST_FIELD(LOGFONTW, LONG, lfHeight, 0, 4, 4); - TEST_FIELD(LOGFONTW, LONG, lfWidth, 4, 4, 4); - TEST_FIELD(LOGFONTW, LONG, lfEscapement, 8, 4, 4); - TEST_FIELD(LOGFONTW, LONG, lfOrientation, 12, 4, 4); - TEST_FIELD(LOGFONTW, LONG, lfWeight, 16, 4, 4); - TEST_FIELD(LOGFONTW, BYTE, lfItalic, 20, 1, 1); - TEST_FIELD(LOGFONTW, BYTE, lfUnderline, 21, 1, 1); - TEST_FIELD(LOGFONTW, BYTE, lfStrikeOut, 22, 1, 1); - TEST_FIELD(LOGFONTW, BYTE, lfCharSet, 23, 1, 1); - TEST_FIELD(LOGFONTW, BYTE, lfOutPrecision, 24, 1, 1); - TEST_FIELD(LOGFONTW, BYTE, lfClipPrecision, 25, 1, 1); - TEST_FIELD(LOGFONTW, BYTE, lfQuality, 26, 1, 1); - TEST_FIELD(LOGFONTW, BYTE, lfPitchAndFamily, 27, 1, 1); - TEST_FIELD(LOGFONTW, WCHAR[LF_FACESIZE], lfFaceName, 28, 64, 2); + TEST_TYPE_SIZE (LOGFONTW, 92) + TEST_TYPE_ALIGN (LOGFONTW, 4) + TEST_FIELD_SIZE (LOGFONTW, lfHeight, 4) + TEST_FIELD_ALIGN (LOGFONTW, lfHeight, 4) + TEST_FIELD_OFFSET(LOGFONTW, lfHeight, 0) + TEST_FIELD_SIZE (LOGFONTW, lfWidth, 4) + TEST_FIELD_ALIGN (LOGFONTW, lfWidth, 4) + TEST_FIELD_OFFSET(LOGFONTW, lfWidth, 4) + TEST_FIELD_SIZE (LOGFONTW, lfEscapement, 4) + TEST_FIELD_ALIGN (LOGFONTW, lfEscapement, 4) + TEST_FIELD_OFFSET(LOGFONTW, lfEscapement, 8) + TEST_FIELD_SIZE (LOGFONTW, lfOrientation, 4) + TEST_FIELD_ALIGN (LOGFONTW, lfOrientation, 4) + TEST_FIELD_OFFSET(LOGFONTW, lfOrientation, 12) + TEST_FIELD_SIZE (LOGFONTW, lfWeight, 4) + TEST_FIELD_ALIGN (LOGFONTW, lfWeight, 4) + TEST_FIELD_OFFSET(LOGFONTW, lfWeight, 16) + TEST_FIELD_SIZE (LOGFONTW, lfItalic, 1) + TEST_FIELD_ALIGN (LOGFONTW, lfItalic, 1) + TEST_FIELD_OFFSET(LOGFONTW, lfItalic, 20) + TEST_FIELD_SIZE (LOGFONTW, lfUnderline, 1) + TEST_FIELD_ALIGN (LOGFONTW, lfUnderline, 1) + TEST_FIELD_OFFSET(LOGFONTW, lfUnderline, 21) + TEST_FIELD_SIZE (LOGFONTW, lfStrikeOut, 1) + TEST_FIELD_ALIGN (LOGFONTW, lfStrikeOut, 1) + TEST_FIELD_OFFSET(LOGFONTW, lfStrikeOut, 22) + TEST_FIELD_SIZE (LOGFONTW, lfCharSet, 1) + TEST_FIELD_ALIGN (LOGFONTW, lfCharSet, 1) + TEST_FIELD_OFFSET(LOGFONTW, lfCharSet, 23) + TEST_FIELD_SIZE (LOGFONTW, lfOutPrecision, 1) + TEST_FIELD_ALIGN (LOGFONTW, lfOutPrecision, 1) + TEST_FIELD_OFFSET(LOGFONTW, lfOutPrecision, 24) + TEST_FIELD_SIZE (LOGFONTW, lfClipPrecision, 1) + TEST_FIELD_ALIGN (LOGFONTW, lfClipPrecision, 1) + TEST_FIELD_OFFSET(LOGFONTW, lfClipPrecision, 25) + TEST_FIELD_SIZE (LOGFONTW, lfQuality, 1) + TEST_FIELD_ALIGN (LOGFONTW, lfQuality, 1) + TEST_FIELD_OFFSET(LOGFONTW, lfQuality, 26) + TEST_FIELD_SIZE (LOGFONTW, lfPitchAndFamily, 1) + TEST_FIELD_ALIGN (LOGFONTW, lfPitchAndFamily, 1) + TEST_FIELD_OFFSET(LOGFONTW, lfPitchAndFamily, 27) + TEST_FIELD_SIZE (LOGFONTW, lfFaceName, 64) + TEST_FIELD_ALIGN (LOGFONTW, lfFaceName, 2) + TEST_FIELD_OFFSET(LOGFONTW, lfFaceName, 28) } static void test_pack_LOGPEN(void) { /* LOGPEN (pack 4) */ - TEST_TYPE(LOGPEN, 16, 4); - TEST_FIELD(LOGPEN, UINT, lopnStyle, 0, 4, 4); - TEST_FIELD(LOGPEN, POINT, lopnWidth, 4, 8, 4); - TEST_FIELD(LOGPEN, COLORREF, lopnColor, 12, 4, 4); + TEST_TYPE_SIZE (LOGPEN, 16) + TEST_TYPE_ALIGN (LOGPEN, 4) + TEST_FIELD_SIZE (LOGPEN, lopnStyle, 4) + TEST_FIELD_ALIGN (LOGPEN, lopnStyle, 4) + TEST_FIELD_OFFSET(LOGPEN, lopnStyle, 0) + TEST_FIELD_SIZE (LOGPEN, lopnWidth, 8) + TEST_FIELD_ALIGN (LOGPEN, lopnWidth, 4) + TEST_FIELD_OFFSET(LOGPEN, lopnWidth, 4) + TEST_FIELD_SIZE (LOGPEN, lopnColor, 4) + TEST_FIELD_ALIGN (LOGPEN, lopnColor, 4) + TEST_FIELD_OFFSET(LOGPEN, lopnColor, 12) } static void test_pack_LPABC(void) { /* LPABC */ - TEST_TYPE(LPABC, 4, 4); - TEST_TYPE_POINTER(LPABC, 12, 4); + TEST_TYPE_SIZE (LPABC, 4) + TEST_TYPE_ALIGN (LPABC, 4) + TEST_TARGET_SIZE (LPABC, 12) + TEST_TARGET_ALIGN(LPABC, 4) } static void test_pack_LPABCFLOAT(void) { /* LPABCFLOAT */ - TEST_TYPE(LPABCFLOAT, 4, 4); - TEST_TYPE_POINTER(LPABCFLOAT, 12, 4); + TEST_TYPE_SIZE (LPABCFLOAT, 4) + TEST_TYPE_ALIGN (LPABCFLOAT, 4) + TEST_TARGET_SIZE (LPABCFLOAT, 12) + TEST_TARGET_ALIGN(LPABCFLOAT, 4) } static void test_pack_LPBITMAP(void) { /* LPBITMAP */ - TEST_TYPE(LPBITMAP, 4, 4); - TEST_TYPE_POINTER(LPBITMAP, 24, 4); + TEST_TYPE_SIZE (LPBITMAP, 4) + TEST_TYPE_ALIGN (LPBITMAP, 4) + TEST_TARGET_SIZE (LPBITMAP, 24) + TEST_TARGET_ALIGN(LPBITMAP, 4) } static void test_pack_LPBITMAPCOREHEADER(void) { /* LPBITMAPCOREHEADER */ - TEST_TYPE(LPBITMAPCOREHEADER, 4, 4); - TEST_TYPE_POINTER(LPBITMAPCOREHEADER, 12, 4); + TEST_TYPE_SIZE (LPBITMAPCOREHEADER, 4) + TEST_TYPE_ALIGN (LPBITMAPCOREHEADER, 4) + TEST_TARGET_SIZE (LPBITMAPCOREHEADER, 12) + TEST_TARGET_ALIGN(LPBITMAPCOREHEADER, 4) } static void test_pack_LPBITMAPCOREINFO(void) { /* LPBITMAPCOREINFO */ - TEST_TYPE(LPBITMAPCOREINFO, 4, 4); - TEST_TYPE_POINTER(LPBITMAPCOREINFO, 16, 4); + TEST_TYPE_SIZE (LPBITMAPCOREINFO, 4) + TEST_TYPE_ALIGN (LPBITMAPCOREINFO, 4) + TEST_TARGET_SIZE (LPBITMAPCOREINFO, 16) + TEST_TARGET_ALIGN(LPBITMAPCOREINFO, 4) } static void test_pack_LPBITMAPFILEHEADER(void) { /* LPBITMAPFILEHEADER */ - TEST_TYPE(LPBITMAPFILEHEADER, 4, 4); - TEST_TYPE_POINTER(LPBITMAPFILEHEADER, 14, 2); + TEST_TYPE_SIZE (LPBITMAPFILEHEADER, 4) + TEST_TYPE_ALIGN (LPBITMAPFILEHEADER, 4) + TEST_TARGET_SIZE (LPBITMAPFILEHEADER, 14) + TEST_TARGET_ALIGN(LPBITMAPFILEHEADER, 2) } static void test_pack_LPBITMAPINFO(void) { /* LPBITMAPINFO */ - TEST_TYPE(LPBITMAPINFO, 4, 4); - TEST_TYPE_POINTER(LPBITMAPINFO, 44, 4); + TEST_TYPE_SIZE (LPBITMAPINFO, 4) + TEST_TYPE_ALIGN (LPBITMAPINFO, 4) + TEST_TARGET_SIZE (LPBITMAPINFO, 44) + TEST_TARGET_ALIGN(LPBITMAPINFO, 4) } static void test_pack_LPBITMAPINFOHEADER(void) { /* LPBITMAPINFOHEADER */ - TEST_TYPE(LPBITMAPINFOHEADER, 4, 4); - TEST_TYPE_POINTER(LPBITMAPINFOHEADER, 40, 4); + TEST_TYPE_SIZE (LPBITMAPINFOHEADER, 4) + TEST_TYPE_ALIGN (LPBITMAPINFOHEADER, 4) + TEST_TARGET_SIZE (LPBITMAPINFOHEADER, 40) + TEST_TARGET_ALIGN(LPBITMAPINFOHEADER, 4) } static void test_pack_LPBITMAPV5HEADER(void) { /* LPBITMAPV5HEADER */ - TEST_TYPE(LPBITMAPV5HEADER, 4, 4); - TEST_TYPE_POINTER(LPBITMAPV5HEADER, 124, 4); + TEST_TYPE_SIZE (LPBITMAPV5HEADER, 4) + TEST_TYPE_ALIGN (LPBITMAPV5HEADER, 4) + TEST_TARGET_SIZE (LPBITMAPV5HEADER, 124) + TEST_TARGET_ALIGN(LPBITMAPV5HEADER, 4) } static void test_pack_LPCHARSETINFO(void) { /* LPCHARSETINFO */ - TEST_TYPE(LPCHARSETINFO, 4, 4); - TEST_TYPE_POINTER(LPCHARSETINFO, 32, 4); + TEST_TYPE_SIZE (LPCHARSETINFO, 4) + TEST_TYPE_ALIGN (LPCHARSETINFO, 4) + TEST_TARGET_SIZE (LPCHARSETINFO, 32) + TEST_TARGET_ALIGN(LPCHARSETINFO, 4) } static void test_pack_LPCIEXYZ(void) { /* LPCIEXYZ */ - TEST_TYPE(LPCIEXYZ, 4, 4); - TEST_TYPE_POINTER(LPCIEXYZ, 12, 4); + TEST_TYPE_SIZE (LPCIEXYZ, 4) + TEST_TYPE_ALIGN (LPCIEXYZ, 4) + TEST_TARGET_SIZE (LPCIEXYZ, 12) + TEST_TARGET_ALIGN(LPCIEXYZ, 4) } static void test_pack_LPCIEXYZTRIPLE(void) { /* LPCIEXYZTRIPLE */ - TEST_TYPE(LPCIEXYZTRIPLE, 4, 4); - TEST_TYPE_POINTER(LPCIEXYZTRIPLE, 36, 4); + TEST_TYPE_SIZE (LPCIEXYZTRIPLE, 4) + TEST_TYPE_ALIGN (LPCIEXYZTRIPLE, 4) + TEST_TARGET_SIZE (LPCIEXYZTRIPLE, 36) + TEST_TARGET_ALIGN(LPCIEXYZTRIPLE, 4) } static void test_pack_LPCOLORADJUSTMENT(void) { /* LPCOLORADJUSTMENT */ - TEST_TYPE(LPCOLORADJUSTMENT, 4, 4); - TEST_TYPE_POINTER(LPCOLORADJUSTMENT, 24, 2); + TEST_TYPE_SIZE (LPCOLORADJUSTMENT, 4) + TEST_TYPE_ALIGN (LPCOLORADJUSTMENT, 4) + TEST_TARGET_SIZE (LPCOLORADJUSTMENT, 24) + TEST_TARGET_ALIGN(LPCOLORADJUSTMENT, 2) } static void test_pack_LPDEVMODEA(void) { /* LPDEVMODEA */ - TEST_TYPE(LPDEVMODEA, 4, 4); + TEST_TYPE_SIZE (LPDEVMODEA, 4) + TEST_TYPE_ALIGN (LPDEVMODEA, 4) } static void test_pack_LPDEVMODEW(void) { /* LPDEVMODEW */ - TEST_TYPE(LPDEVMODEW, 4, 4); + TEST_TYPE_SIZE (LPDEVMODEW, 4) + TEST_TYPE_ALIGN (LPDEVMODEW, 4) } static void test_pack_LPDIBSECTION(void) { /* LPDIBSECTION */ - TEST_TYPE(LPDIBSECTION, 4, 4); - TEST_TYPE_POINTER(LPDIBSECTION, 84, 4); + TEST_TYPE_SIZE (LPDIBSECTION, 4) + TEST_TYPE_ALIGN (LPDIBSECTION, 4) + TEST_TARGET_SIZE (LPDIBSECTION, 84) + TEST_TARGET_ALIGN(LPDIBSECTION, 4) } static void test_pack_LPDISPLAY_DEVICEA(void) { /* LPDISPLAY_DEVICEA */ - TEST_TYPE(LPDISPLAY_DEVICEA, 4, 4); - TEST_TYPE_POINTER(LPDISPLAY_DEVICEA, 424, 4); + TEST_TYPE_SIZE (LPDISPLAY_DEVICEA, 4) + TEST_TYPE_ALIGN (LPDISPLAY_DEVICEA, 4) + TEST_TARGET_SIZE (LPDISPLAY_DEVICEA, 424) + TEST_TARGET_ALIGN(LPDISPLAY_DEVICEA, 4) } static void test_pack_LPDISPLAY_DEVICEW(void) { /* LPDISPLAY_DEVICEW */ - TEST_TYPE(LPDISPLAY_DEVICEW, 4, 4); - TEST_TYPE_POINTER(LPDISPLAY_DEVICEW, 840, 4); + TEST_TYPE_SIZE (LPDISPLAY_DEVICEW, 4) + TEST_TYPE_ALIGN (LPDISPLAY_DEVICEW, 4) + TEST_TARGET_SIZE (LPDISPLAY_DEVICEW, 840) + TEST_TARGET_ALIGN(LPDISPLAY_DEVICEW, 4) } static void test_pack_LPDOCINFOA(void) { /* LPDOCINFOA */ - TEST_TYPE(LPDOCINFOA, 4, 4); - TEST_TYPE_POINTER(LPDOCINFOA, 20, 4); + TEST_TYPE_SIZE (LPDOCINFOA, 4) + TEST_TYPE_ALIGN (LPDOCINFOA, 4) + TEST_TARGET_SIZE (LPDOCINFOA, 20) + TEST_TARGET_ALIGN(LPDOCINFOA, 4) } static void test_pack_LPDOCINFOW(void) { /* LPDOCINFOW */ - TEST_TYPE(LPDOCINFOW, 4, 4); - TEST_TYPE_POINTER(LPDOCINFOW, 20, 4); + TEST_TYPE_SIZE (LPDOCINFOW, 4) + TEST_TYPE_ALIGN (LPDOCINFOW, 4) + TEST_TARGET_SIZE (LPDOCINFOW, 20) + TEST_TARGET_ALIGN(LPDOCINFOW, 4) } static void test_pack_LPENHMETAHEADER(void) { /* LPENHMETAHEADER */ - TEST_TYPE(LPENHMETAHEADER, 4, 4); - TEST_TYPE_POINTER(LPENHMETAHEADER, 108, 4); + TEST_TYPE_SIZE (LPENHMETAHEADER, 4) + TEST_TYPE_ALIGN (LPENHMETAHEADER, 4) + TEST_TARGET_SIZE (LPENHMETAHEADER, 108) + TEST_TARGET_ALIGN(LPENHMETAHEADER, 4) } static void test_pack_LPENHMETARECORD(void) { /* LPENHMETARECORD */ - TEST_TYPE(LPENHMETARECORD, 4, 4); - TEST_TYPE_POINTER(LPENHMETARECORD, 12, 4); + TEST_TYPE_SIZE (LPENHMETARECORD, 4) + TEST_TYPE_ALIGN (LPENHMETARECORD, 4) + TEST_TARGET_SIZE (LPENHMETARECORD, 12) + TEST_TARGET_ALIGN(LPENHMETARECORD, 4) } static void test_pack_LPENUMLOGFONTA(void) { /* LPENUMLOGFONTA */ - TEST_TYPE(LPENUMLOGFONTA, 4, 4); - TEST_TYPE_POINTER(LPENUMLOGFONTA, 156, 4); + TEST_TYPE_SIZE (LPENUMLOGFONTA, 4) + TEST_TYPE_ALIGN (LPENUMLOGFONTA, 4) + TEST_TARGET_SIZE (LPENUMLOGFONTA, 156) + TEST_TARGET_ALIGN(LPENUMLOGFONTA, 4) } static void test_pack_LPENUMLOGFONTEXA(void) { /* LPENUMLOGFONTEXA */ - TEST_TYPE(LPENUMLOGFONTEXA, 4, 4); - TEST_TYPE_POINTER(LPENUMLOGFONTEXA, 188, 4); + TEST_TYPE_SIZE (LPENUMLOGFONTEXA, 4) + TEST_TYPE_ALIGN (LPENUMLOGFONTEXA, 4) + TEST_TARGET_SIZE (LPENUMLOGFONTEXA, 188) + TEST_TARGET_ALIGN(LPENUMLOGFONTEXA, 4) } static void test_pack_LPENUMLOGFONTEXW(void) { /* LPENUMLOGFONTEXW */ - TEST_TYPE(LPENUMLOGFONTEXW, 4, 4); - TEST_TYPE_POINTER(LPENUMLOGFONTEXW, 348, 4); + TEST_TYPE_SIZE (LPENUMLOGFONTEXW, 4) + TEST_TYPE_ALIGN (LPENUMLOGFONTEXW, 4) + TEST_TARGET_SIZE (LPENUMLOGFONTEXW, 348) + TEST_TARGET_ALIGN(LPENUMLOGFONTEXW, 4) } static void test_pack_LPENUMLOGFONTW(void) { /* LPENUMLOGFONTW */ - TEST_TYPE(LPENUMLOGFONTW, 4, 4); - TEST_TYPE_POINTER(LPENUMLOGFONTW, 284, 4); + TEST_TYPE_SIZE (LPENUMLOGFONTW, 4) + TEST_TYPE_ALIGN (LPENUMLOGFONTW, 4) + TEST_TARGET_SIZE (LPENUMLOGFONTW, 284) + TEST_TARGET_ALIGN(LPENUMLOGFONTW, 4) } static void test_pack_LPEXTLOGFONTA(void) { /* LPEXTLOGFONTA */ - TEST_TYPE(LPEXTLOGFONTA, 4, 4); - TEST_TYPE_POINTER(LPEXTLOGFONTA, 192, 4); + TEST_TYPE_SIZE (LPEXTLOGFONTA, 4) + TEST_TYPE_ALIGN (LPEXTLOGFONTA, 4) + TEST_TARGET_SIZE (LPEXTLOGFONTA, 192) + TEST_TARGET_ALIGN(LPEXTLOGFONTA, 4) } static void test_pack_LPEXTLOGFONTW(void) { /* LPEXTLOGFONTW */ - TEST_TYPE(LPEXTLOGFONTW, 4, 4); - TEST_TYPE_POINTER(LPEXTLOGFONTW, 320, 4); + TEST_TYPE_SIZE (LPEXTLOGFONTW, 4) + TEST_TYPE_ALIGN (LPEXTLOGFONTW, 4) + TEST_TARGET_SIZE (LPEXTLOGFONTW, 320) + TEST_TARGET_ALIGN(LPEXTLOGFONTW, 4) } static void test_pack_LPEXTLOGPEN(void) { /* LPEXTLOGPEN */ - TEST_TYPE(LPEXTLOGPEN, 4, 4); - TEST_TYPE_POINTER(LPEXTLOGPEN, 28, 4); + TEST_TYPE_SIZE (LPEXTLOGPEN, 4) + TEST_TYPE_ALIGN (LPEXTLOGPEN, 4) + TEST_TARGET_SIZE (LPEXTLOGPEN, 28) + TEST_TARGET_ALIGN(LPEXTLOGPEN, 4) } static void test_pack_LPFONTSIGNATURE(void) { /* LPFONTSIGNATURE */ - TEST_TYPE(LPFONTSIGNATURE, 4, 4); - TEST_TYPE_POINTER(LPFONTSIGNATURE, 24, 4); + TEST_TYPE_SIZE (LPFONTSIGNATURE, 4) + TEST_TYPE_ALIGN (LPFONTSIGNATURE, 4) + TEST_TARGET_SIZE (LPFONTSIGNATURE, 24) + TEST_TARGET_ALIGN(LPFONTSIGNATURE, 4) } static void test_pack_LPGCP_RESULTSA(void) { /* LPGCP_RESULTSA */ - TEST_TYPE(LPGCP_RESULTSA, 4, 4); - TEST_TYPE_POINTER(LPGCP_RESULTSA, 36, 4); + TEST_TYPE_SIZE (LPGCP_RESULTSA, 4) + TEST_TYPE_ALIGN (LPGCP_RESULTSA, 4) + TEST_TARGET_SIZE (LPGCP_RESULTSA, 36) + TEST_TARGET_ALIGN(LPGCP_RESULTSA, 4) } static void test_pack_LPGCP_RESULTSW(void) { /* LPGCP_RESULTSW */ - TEST_TYPE(LPGCP_RESULTSW, 4, 4); - TEST_TYPE_POINTER(LPGCP_RESULTSW, 36, 4); + TEST_TYPE_SIZE (LPGCP_RESULTSW, 4) + TEST_TYPE_ALIGN (LPGCP_RESULTSW, 4) + TEST_TARGET_SIZE (LPGCP_RESULTSW, 36) + TEST_TARGET_ALIGN(LPGCP_RESULTSW, 4) } static void test_pack_LPGLYPHMETRICS(void) { /* LPGLYPHMETRICS */ - TEST_TYPE(LPGLYPHMETRICS, 4, 4); - TEST_TYPE_POINTER(LPGLYPHMETRICS, 20, 4); + TEST_TYPE_SIZE (LPGLYPHMETRICS, 4) + TEST_TYPE_ALIGN (LPGLYPHMETRICS, 4) + TEST_TARGET_SIZE (LPGLYPHMETRICS, 20) + TEST_TARGET_ALIGN(LPGLYPHMETRICS, 4) } static void test_pack_LPGLYPHMETRICSFLOAT(void) { /* LPGLYPHMETRICSFLOAT */ - TEST_TYPE(LPGLYPHMETRICSFLOAT, 4, 4); - TEST_TYPE_POINTER(LPGLYPHMETRICSFLOAT, 24, 4); + TEST_TYPE_SIZE (LPGLYPHMETRICSFLOAT, 4) + TEST_TYPE_ALIGN (LPGLYPHMETRICSFLOAT, 4) + TEST_TARGET_SIZE (LPGLYPHMETRICSFLOAT, 24) + TEST_TARGET_ALIGN(LPGLYPHMETRICSFLOAT, 4) } static void test_pack_LPGRADIENT_RECT(void) { /* LPGRADIENT_RECT */ - TEST_TYPE(LPGRADIENT_RECT, 4, 4); - TEST_TYPE_POINTER(LPGRADIENT_RECT, 8, 4); + TEST_TYPE_SIZE (LPGRADIENT_RECT, 4) + TEST_TYPE_ALIGN (LPGRADIENT_RECT, 4) + TEST_TARGET_SIZE (LPGRADIENT_RECT, 8) + TEST_TARGET_ALIGN(LPGRADIENT_RECT, 4) } static void test_pack_LPGRADIENT_TRIANGLE(void) { /* LPGRADIENT_TRIANGLE */ - TEST_TYPE(LPGRADIENT_TRIANGLE, 4, 4); - TEST_TYPE_POINTER(LPGRADIENT_TRIANGLE, 12, 4); + TEST_TYPE_SIZE (LPGRADIENT_TRIANGLE, 4) + TEST_TYPE_ALIGN (LPGRADIENT_TRIANGLE, 4) + TEST_TARGET_SIZE (LPGRADIENT_TRIANGLE, 12) + TEST_TARGET_ALIGN(LPGRADIENT_TRIANGLE, 4) } static void test_pack_LPHANDLETABLE(void) { /* LPHANDLETABLE */ - TEST_TYPE(LPHANDLETABLE, 4, 4); - TEST_TYPE_POINTER(LPHANDLETABLE, 4, 4); + TEST_TYPE_SIZE (LPHANDLETABLE, 4) + TEST_TYPE_ALIGN (LPHANDLETABLE, 4) + TEST_TARGET_SIZE (LPHANDLETABLE, 4) + TEST_TARGET_ALIGN(LPHANDLETABLE, 4) } static void test_pack_LPKERNINGPAIR(void) { /* LPKERNINGPAIR */ - TEST_TYPE(LPKERNINGPAIR, 4, 4); - TEST_TYPE_POINTER(LPKERNINGPAIR, 8, 4); + TEST_TYPE_SIZE (LPKERNINGPAIR, 4) + TEST_TYPE_ALIGN (LPKERNINGPAIR, 4) + TEST_TARGET_SIZE (LPKERNINGPAIR, 8) + TEST_TARGET_ALIGN(LPKERNINGPAIR, 4) } static void test_pack_LPLAYERPLANEDESCRIPTOR(void) { /* LPLAYERPLANEDESCRIPTOR */ - TEST_TYPE(LPLAYERPLANEDESCRIPTOR, 4, 4); - TEST_TYPE_POINTER(LPLAYERPLANEDESCRIPTOR, 32, 4); + TEST_TYPE_SIZE (LPLAYERPLANEDESCRIPTOR, 4) + TEST_TYPE_ALIGN (LPLAYERPLANEDESCRIPTOR, 4) + TEST_TARGET_SIZE (LPLAYERPLANEDESCRIPTOR, 32) + TEST_TARGET_ALIGN(LPLAYERPLANEDESCRIPTOR, 4) } static void test_pack_LPLOCALESIGNATURE(void) { /* LPLOCALESIGNATURE */ - TEST_TYPE(LPLOCALESIGNATURE, 4, 4); - TEST_TYPE_POINTER(LPLOCALESIGNATURE, 32, 4); + TEST_TYPE_SIZE (LPLOCALESIGNATURE, 4) + TEST_TYPE_ALIGN (LPLOCALESIGNATURE, 4) + TEST_TARGET_SIZE (LPLOCALESIGNATURE, 32) + TEST_TARGET_ALIGN(LPLOCALESIGNATURE, 4) } static void test_pack_LPLOGBRUSH(void) { /* LPLOGBRUSH */ - TEST_TYPE(LPLOGBRUSH, 4, 4); - TEST_TYPE_POINTER(LPLOGBRUSH, 12, 4); + TEST_TYPE_SIZE (LPLOGBRUSH, 4) + TEST_TYPE_ALIGN (LPLOGBRUSH, 4) + TEST_TARGET_SIZE (LPLOGBRUSH, 12) + TEST_TARGET_ALIGN(LPLOGBRUSH, 4) } static void test_pack_LPLOGCOLORSPACEA(void) { /* LPLOGCOLORSPACEA */ - TEST_TYPE(LPLOGCOLORSPACEA, 4, 4); - TEST_TYPE_POINTER(LPLOGCOLORSPACEA, 328, 4); + TEST_TYPE_SIZE (LPLOGCOLORSPACEA, 4) + TEST_TYPE_ALIGN (LPLOGCOLORSPACEA, 4) + TEST_TARGET_SIZE (LPLOGCOLORSPACEA, 328) + TEST_TARGET_ALIGN(LPLOGCOLORSPACEA, 4) } static void test_pack_LPLOGCOLORSPACEW(void) { /* LPLOGCOLORSPACEW */ - TEST_TYPE(LPLOGCOLORSPACEW, 4, 4); - TEST_TYPE_POINTER(LPLOGCOLORSPACEW, 588, 4); + TEST_TYPE_SIZE (LPLOGCOLORSPACEW, 4) + TEST_TYPE_ALIGN (LPLOGCOLORSPACEW, 4) + TEST_TARGET_SIZE (LPLOGCOLORSPACEW, 588) + TEST_TARGET_ALIGN(LPLOGCOLORSPACEW, 4) } static void test_pack_LPLOGFONTA(void) { /* LPLOGFONTA */ - TEST_TYPE(LPLOGFONTA, 4, 4); - TEST_TYPE_POINTER(LPLOGFONTA, 60, 4); + TEST_TYPE_SIZE (LPLOGFONTA, 4) + TEST_TYPE_ALIGN (LPLOGFONTA, 4) + TEST_TARGET_SIZE (LPLOGFONTA, 60) + TEST_TARGET_ALIGN(LPLOGFONTA, 4) } static void test_pack_LPLOGFONTW(void) { /* LPLOGFONTW */ - TEST_TYPE(LPLOGFONTW, 4, 4); - TEST_TYPE_POINTER(LPLOGFONTW, 92, 4); + TEST_TYPE_SIZE (LPLOGFONTW, 4) + TEST_TYPE_ALIGN (LPLOGFONTW, 4) + TEST_TARGET_SIZE (LPLOGFONTW, 92) + TEST_TARGET_ALIGN(LPLOGFONTW, 4) } static void test_pack_LPLOGPEN(void) { /* LPLOGPEN */ - TEST_TYPE(LPLOGPEN, 4, 4); - TEST_TYPE_POINTER(LPLOGPEN, 16, 4); + TEST_TYPE_SIZE (LPLOGPEN, 4) + TEST_TYPE_ALIGN (LPLOGPEN, 4) + TEST_TARGET_SIZE (LPLOGPEN, 16) + TEST_TARGET_ALIGN(LPLOGPEN, 4) } static void test_pack_LPMAT2(void) { /* LPMAT2 */ - TEST_TYPE(LPMAT2, 4, 4); - TEST_TYPE_POINTER(LPMAT2, 16, 2); + TEST_TYPE_SIZE (LPMAT2, 4) + TEST_TYPE_ALIGN (LPMAT2, 4) + TEST_TARGET_SIZE (LPMAT2, 16) + TEST_TARGET_ALIGN(LPMAT2, 2) } static void test_pack_LPMETAFILEPICT(void) { /* LPMETAFILEPICT */ - TEST_TYPE(LPMETAFILEPICT, 4, 4); - TEST_TYPE_POINTER(LPMETAFILEPICT, 16, 4); + TEST_TYPE_SIZE (LPMETAFILEPICT, 4) + TEST_TYPE_ALIGN (LPMETAFILEPICT, 4) + TEST_TARGET_SIZE (LPMETAFILEPICT, 16) + TEST_TARGET_ALIGN(LPMETAFILEPICT, 4) } static void test_pack_LPMETAHEADER(void) { /* LPMETAHEADER */ - TEST_TYPE(LPMETAHEADER, 4, 4); - TEST_TYPE_POINTER(LPMETAHEADER, 18, 2); + TEST_TYPE_SIZE (LPMETAHEADER, 4) + TEST_TYPE_ALIGN (LPMETAHEADER, 4) + TEST_TARGET_SIZE (LPMETAHEADER, 18) + TEST_TARGET_ALIGN(LPMETAHEADER, 2) } static void test_pack_LPMETARECORD(void) { /* LPMETARECORD */ - TEST_TYPE(LPMETARECORD, 4, 4); - TEST_TYPE_POINTER(LPMETARECORD, 8, 4); + TEST_TYPE_SIZE (LPMETARECORD, 4) + TEST_TYPE_ALIGN (LPMETARECORD, 4) + TEST_TARGET_SIZE (LPMETARECORD, 8) + TEST_TARGET_ALIGN(LPMETARECORD, 4) } static void test_pack_LPNEWTEXTMETRICA(void) { /* LPNEWTEXTMETRICA */ - TEST_TYPE(LPNEWTEXTMETRICA, 4, 4); - TEST_TYPE_POINTER(LPNEWTEXTMETRICA, 72, 4); + TEST_TYPE_SIZE (LPNEWTEXTMETRICA, 4) + TEST_TYPE_ALIGN (LPNEWTEXTMETRICA, 4) + TEST_TARGET_SIZE (LPNEWTEXTMETRICA, 72) + TEST_TARGET_ALIGN(LPNEWTEXTMETRICA, 4) } static void test_pack_LPNEWTEXTMETRICW(void) { /* LPNEWTEXTMETRICW */ - TEST_TYPE(LPNEWTEXTMETRICW, 4, 4); - TEST_TYPE_POINTER(LPNEWTEXTMETRICW, 76, 4); + TEST_TYPE_SIZE (LPNEWTEXTMETRICW, 4) + TEST_TYPE_ALIGN (LPNEWTEXTMETRICW, 4) + TEST_TARGET_SIZE (LPNEWTEXTMETRICW, 76) + TEST_TARGET_ALIGN(LPNEWTEXTMETRICW, 4) } static void test_pack_LPOUTLINETEXTMETRICA(void) { /* LPOUTLINETEXTMETRICA */ - TEST_TYPE(LPOUTLINETEXTMETRICA, 4, 4); - TEST_TYPE_POINTER(LPOUTLINETEXTMETRICA, 212, 4); + TEST_TYPE_SIZE (LPOUTLINETEXTMETRICA, 4) + TEST_TYPE_ALIGN (LPOUTLINETEXTMETRICA, 4) + TEST_TARGET_SIZE (LPOUTLINETEXTMETRICA, 212) + TEST_TARGET_ALIGN(LPOUTLINETEXTMETRICA, 4) } static void test_pack_LPOUTLINETEXTMETRICW(void) { /* LPOUTLINETEXTMETRICW */ - TEST_TYPE(LPOUTLINETEXTMETRICW, 4, 4); - TEST_TYPE_POINTER(LPOUTLINETEXTMETRICW, 216, 4); + TEST_TYPE_SIZE (LPOUTLINETEXTMETRICW, 4) + TEST_TYPE_ALIGN (LPOUTLINETEXTMETRICW, 4) + TEST_TARGET_SIZE (LPOUTLINETEXTMETRICW, 216) + TEST_TARGET_ALIGN(LPOUTLINETEXTMETRICW, 4) } static void test_pack_LPPANOSE(void) { /* LPPANOSE */ - TEST_TYPE(LPPANOSE, 4, 4); - TEST_TYPE_POINTER(LPPANOSE, 10, 1); + TEST_TYPE_SIZE (LPPANOSE, 4) + TEST_TYPE_ALIGN (LPPANOSE, 4) + TEST_TARGET_SIZE (LPPANOSE, 10) + TEST_TARGET_ALIGN(LPPANOSE, 1) } static void test_pack_LPPELARRAY(void) { /* LPPELARRAY */ - TEST_TYPE(LPPELARRAY, 4, 4); - TEST_TYPE_POINTER(LPPELARRAY, 20, 4); + TEST_TYPE_SIZE (LPPELARRAY, 4) + TEST_TYPE_ALIGN (LPPELARRAY, 4) + TEST_TARGET_SIZE (LPPELARRAY, 20) + TEST_TARGET_ALIGN(LPPELARRAY, 4) } static void test_pack_LPPIXELFORMATDESCRIPTOR(void) { /* LPPIXELFORMATDESCRIPTOR */ - TEST_TYPE(LPPIXELFORMATDESCRIPTOR, 4, 4); - TEST_TYPE_POINTER(LPPIXELFORMATDESCRIPTOR, 40, 4); + TEST_TYPE_SIZE (LPPIXELFORMATDESCRIPTOR, 4) + TEST_TYPE_ALIGN (LPPIXELFORMATDESCRIPTOR, 4) + TEST_TARGET_SIZE (LPPIXELFORMATDESCRIPTOR, 40) + TEST_TARGET_ALIGN(LPPIXELFORMATDESCRIPTOR, 4) } static void test_pack_LPPOINTFX(void) { /* LPPOINTFX */ - TEST_TYPE(LPPOINTFX, 4, 4); - TEST_TYPE_POINTER(LPPOINTFX, 8, 2); + TEST_TYPE_SIZE (LPPOINTFX, 4) + TEST_TYPE_ALIGN (LPPOINTFX, 4) + TEST_TARGET_SIZE (LPPOINTFX, 8) + TEST_TARGET_ALIGN(LPPOINTFX, 2) } static void test_pack_LPPOLYTEXTA(void) { /* LPPOLYTEXTA */ - TEST_TYPE(LPPOLYTEXTA, 4, 4); - TEST_TYPE_POINTER(LPPOLYTEXTA, 40, 4); + TEST_TYPE_SIZE (LPPOLYTEXTA, 4) + TEST_TYPE_ALIGN (LPPOLYTEXTA, 4) + TEST_TARGET_SIZE (LPPOLYTEXTA, 40) + TEST_TARGET_ALIGN(LPPOLYTEXTA, 4) } static void test_pack_LPPOLYTEXTW(void) { /* LPPOLYTEXTW */ - TEST_TYPE(LPPOLYTEXTW, 4, 4); - TEST_TYPE_POINTER(LPPOLYTEXTW, 40, 4); + TEST_TYPE_SIZE (LPPOLYTEXTW, 4) + TEST_TYPE_ALIGN (LPPOLYTEXTW, 4) + TEST_TARGET_SIZE (LPPOLYTEXTW, 40) + TEST_TARGET_ALIGN(LPPOLYTEXTW, 4) } static void test_pack_LPRASTERIZER_STATUS(void) { /* LPRASTERIZER_STATUS */ - TEST_TYPE(LPRASTERIZER_STATUS, 4, 4); - TEST_TYPE_POINTER(LPRASTERIZER_STATUS, 6, 2); + TEST_TYPE_SIZE (LPRASTERIZER_STATUS, 4) + TEST_TYPE_ALIGN (LPRASTERIZER_STATUS, 4) + TEST_TARGET_SIZE (LPRASTERIZER_STATUS, 6) + TEST_TARGET_ALIGN(LPRASTERIZER_STATUS, 2) } static void test_pack_LPRGBQUAD(void) { /* LPRGBQUAD */ - TEST_TYPE(LPRGBQUAD, 4, 4); - TEST_TYPE_POINTER(LPRGBQUAD, 4, 1); + TEST_TYPE_SIZE (LPRGBQUAD, 4) + TEST_TYPE_ALIGN (LPRGBQUAD, 4) + TEST_TARGET_SIZE (LPRGBQUAD, 4) + TEST_TARGET_ALIGN(LPRGBQUAD, 1) } static void test_pack_LPRGNDATA(void) { /* LPRGNDATA */ - TEST_TYPE(LPRGNDATA, 4, 4); - TEST_TYPE_POINTER(LPRGNDATA, 36, 4); + TEST_TYPE_SIZE (LPRGNDATA, 4) + TEST_TYPE_ALIGN (LPRGNDATA, 4) + TEST_TARGET_SIZE (LPRGNDATA, 36) + TEST_TARGET_ALIGN(LPRGNDATA, 4) } static void test_pack_LPTEXTMETRICA(void) { /* LPTEXTMETRICA */ - TEST_TYPE(LPTEXTMETRICA, 4, 4); - TEST_TYPE_POINTER(LPTEXTMETRICA, 56, 4); + TEST_TYPE_SIZE (LPTEXTMETRICA, 4) + TEST_TYPE_ALIGN (LPTEXTMETRICA, 4) + TEST_TARGET_SIZE (LPTEXTMETRICA, 56) + TEST_TARGET_ALIGN(LPTEXTMETRICA, 4) } static void test_pack_LPTEXTMETRICW(void) { /* LPTEXTMETRICW */ - TEST_TYPE(LPTEXTMETRICW, 4, 4); - TEST_TYPE_POINTER(LPTEXTMETRICW, 60, 4); + TEST_TYPE_SIZE (LPTEXTMETRICW, 4) + TEST_TYPE_ALIGN (LPTEXTMETRICW, 4) + TEST_TARGET_SIZE (LPTEXTMETRICW, 60) + TEST_TARGET_ALIGN(LPTEXTMETRICW, 4) } static void test_pack_LPTRIVERTEX(void) { /* LPTRIVERTEX */ - TEST_TYPE(LPTRIVERTEX, 4, 4); - TEST_TYPE_POINTER(LPTRIVERTEX, 16, 4); + TEST_TYPE_SIZE (LPTRIVERTEX, 4) + TEST_TYPE_ALIGN (LPTRIVERTEX, 4) + TEST_TARGET_SIZE (LPTRIVERTEX, 16) + TEST_TARGET_ALIGN(LPTRIVERTEX, 4) } static void test_pack_LPTTPOLYCURVE(void) { /* LPTTPOLYCURVE */ - TEST_TYPE(LPTTPOLYCURVE, 4, 4); - TEST_TYPE_POINTER(LPTTPOLYCURVE, 12, 2); + TEST_TYPE_SIZE (LPTTPOLYCURVE, 4) + TEST_TYPE_ALIGN (LPTTPOLYCURVE, 4) + TEST_TARGET_SIZE (LPTTPOLYCURVE, 12) + TEST_TARGET_ALIGN(LPTTPOLYCURVE, 2) } static void test_pack_LPTTPOLYGONHEADER(void) { /* LPTTPOLYGONHEADER */ - TEST_TYPE(LPTTPOLYGONHEADER, 4, 4); - TEST_TYPE_POINTER(LPTTPOLYGONHEADER, 16, 4); + TEST_TYPE_SIZE (LPTTPOLYGONHEADER, 4) + TEST_TYPE_ALIGN (LPTTPOLYGONHEADER, 4) + TEST_TARGET_SIZE (LPTTPOLYGONHEADER, 16) + TEST_TARGET_ALIGN(LPTTPOLYGONHEADER, 4) } static void test_pack_LPXFORM(void) { /* LPXFORM */ - TEST_TYPE(LPXFORM, 4, 4); - TEST_TYPE_POINTER(LPXFORM, 24, 4); + TEST_TYPE_SIZE (LPXFORM, 4) + TEST_TYPE_ALIGN (LPXFORM, 4) + TEST_TARGET_SIZE (LPXFORM, 24) + TEST_TARGET_ALIGN(LPXFORM, 4) } static void test_pack_MAT2(void) { /* MAT2 (pack 4) */ - TEST_TYPE(MAT2, 16, 2); - TEST_FIELD(MAT2, FIXED, eM11, 0, 4, 2); - TEST_FIELD(MAT2, FIXED, eM12, 4, 4, 2); - TEST_FIELD(MAT2, FIXED, eM21, 8, 4, 2); - TEST_FIELD(MAT2, FIXED, eM22, 12, 4, 2); + TEST_TYPE_SIZE (MAT2, 16) + TEST_TYPE_ALIGN (MAT2, 2) + TEST_FIELD_SIZE (MAT2, eM11, 4) + TEST_FIELD_ALIGN (MAT2, eM11, 2) + TEST_FIELD_OFFSET(MAT2, eM11, 0) + TEST_FIELD_SIZE (MAT2, eM12, 4) + TEST_FIELD_ALIGN (MAT2, eM12, 2) + TEST_FIELD_OFFSET(MAT2, eM12, 4) + TEST_FIELD_SIZE (MAT2, eM21, 4) + TEST_FIELD_ALIGN (MAT2, eM21, 2) + TEST_FIELD_OFFSET(MAT2, eM21, 8) + TEST_FIELD_SIZE (MAT2, eM22, 4) + TEST_FIELD_ALIGN (MAT2, eM22, 2) + TEST_FIELD_OFFSET(MAT2, eM22, 12) } static void test_pack_METAFILEPICT(void) { /* METAFILEPICT (pack 4) */ - TEST_TYPE(METAFILEPICT, 16, 4); - TEST_FIELD(METAFILEPICT, LONG, mm, 0, 4, 4); - TEST_FIELD(METAFILEPICT, LONG, xExt, 4, 4, 4); - TEST_FIELD(METAFILEPICT, LONG, yExt, 8, 4, 4); - TEST_FIELD(METAFILEPICT, HMETAFILE, hMF, 12, 4, 4); + TEST_TYPE_SIZE (METAFILEPICT, 16) + TEST_TYPE_ALIGN (METAFILEPICT, 4) + TEST_FIELD_SIZE (METAFILEPICT, mm, 4) + TEST_FIELD_ALIGN (METAFILEPICT, mm, 4) + TEST_FIELD_OFFSET(METAFILEPICT, mm, 0) + TEST_FIELD_SIZE (METAFILEPICT, xExt, 4) + TEST_FIELD_ALIGN (METAFILEPICT, xExt, 4) + TEST_FIELD_OFFSET(METAFILEPICT, xExt, 4) + TEST_FIELD_SIZE (METAFILEPICT, yExt, 4) + TEST_FIELD_ALIGN (METAFILEPICT, yExt, 4) + TEST_FIELD_OFFSET(METAFILEPICT, yExt, 8) + TEST_FIELD_SIZE (METAFILEPICT, hMF, 4) + TEST_FIELD_ALIGN (METAFILEPICT, hMF, 4) + TEST_FIELD_OFFSET(METAFILEPICT, hMF, 12) } static void test_pack_METAHEADER(void) { /* METAHEADER (pack 2) */ - TEST_TYPE(METAHEADER, 18, 2); - TEST_FIELD(METAHEADER, WORD, mtType, 0, 2, 2); - TEST_FIELD(METAHEADER, WORD, mtHeaderSize, 2, 2, 2); - TEST_FIELD(METAHEADER, WORD, mtVersion, 4, 2, 2); - TEST_FIELD(METAHEADER, DWORD, mtSize, 6, 4, 2); - TEST_FIELD(METAHEADER, WORD, mtNoObjects, 10, 2, 2); - TEST_FIELD(METAHEADER, DWORD, mtMaxRecord, 12, 4, 2); - TEST_FIELD(METAHEADER, WORD, mtNoParameters, 16, 2, 2); + TEST_TYPE_SIZE (METAHEADER, 18) + TEST_TYPE_ALIGN (METAHEADER, 2) + TEST_FIELD_SIZE (METAHEADER, mtType, 2) + TEST_FIELD_ALIGN (METAHEADER, mtType, 2) + TEST_FIELD_OFFSET(METAHEADER, mtType, 0) + TEST_FIELD_SIZE (METAHEADER, mtHeaderSize, 2) + TEST_FIELD_ALIGN (METAHEADER, mtHeaderSize, 2) + TEST_FIELD_OFFSET(METAHEADER, mtHeaderSize, 2) + TEST_FIELD_SIZE (METAHEADER, mtVersion, 2) + TEST_FIELD_ALIGN (METAHEADER, mtVersion, 2) + TEST_FIELD_OFFSET(METAHEADER, mtVersion, 4) + TEST_FIELD_SIZE (METAHEADER, mtSize, 4) + TEST_FIELD_ALIGN (METAHEADER, mtSize, 2) + TEST_FIELD_OFFSET(METAHEADER, mtSize, 6) + TEST_FIELD_SIZE (METAHEADER, mtNoObjects, 2) + TEST_FIELD_ALIGN (METAHEADER, mtNoObjects, 2) + TEST_FIELD_OFFSET(METAHEADER, mtNoObjects, 10) + TEST_FIELD_SIZE (METAHEADER, mtMaxRecord, 4) + TEST_FIELD_ALIGN (METAHEADER, mtMaxRecord, 2) + TEST_FIELD_OFFSET(METAHEADER, mtMaxRecord, 12) + TEST_FIELD_SIZE (METAHEADER, mtNoParameters, 2) + TEST_FIELD_ALIGN (METAHEADER, mtNoParameters, 2) + TEST_FIELD_OFFSET(METAHEADER, mtNoParameters, 16) } static void test_pack_METARECORD(void) { /* METARECORD (pack 4) */ - TEST_TYPE(METARECORD, 8, 4); - TEST_FIELD(METARECORD, DWORD, rdSize, 0, 4, 4); - TEST_FIELD(METARECORD, WORD, rdFunction, 4, 2, 2); - TEST_FIELD(METARECORD, WORD[1], rdParm, 6, 2, 2); + TEST_TYPE_SIZE (METARECORD, 8) + TEST_TYPE_ALIGN (METARECORD, 4) + TEST_FIELD_SIZE (METARECORD, rdSize, 4) + TEST_FIELD_ALIGN (METARECORD, rdSize, 4) + TEST_FIELD_OFFSET(METARECORD, rdSize, 0) + TEST_FIELD_SIZE (METARECORD, rdFunction, 2) + TEST_FIELD_ALIGN (METARECORD, rdFunction, 2) + TEST_FIELD_OFFSET(METARECORD, rdFunction, 4) + TEST_FIELD_SIZE (METARECORD, rdParm, 2) + TEST_FIELD_ALIGN (METARECORD, rdParm, 2) + TEST_FIELD_OFFSET(METARECORD, rdParm, 6) } static void test_pack_MFENUMPROC(void) { /* MFENUMPROC */ - TEST_TYPE(MFENUMPROC, 4, 4); + TEST_TYPE_SIZE (MFENUMPROC, 4) + TEST_TYPE_ALIGN (MFENUMPROC, 4) } static void test_pack_NEWTEXTMETRICA(void) { /* NEWTEXTMETRICA (pack 4) */ - TEST_TYPE(NEWTEXTMETRICA, 72, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmHeight, 0, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmAscent, 4, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmDescent, 8, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmInternalLeading, 12, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmExternalLeading, 16, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmAveCharWidth, 20, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmMaxCharWidth, 24, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmWeight, 28, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmOverhang, 32, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmDigitizedAspectX, 36, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, LONG, tmDigitizedAspectY, 40, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmFirstChar, 44, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmLastChar, 45, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmDefaultChar, 46, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmBreakChar, 47, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmItalic, 48, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmUnderlined, 49, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmStruckOut, 50, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmPitchAndFamily, 51, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, BYTE, tmCharSet, 52, 1, 1); - TEST_FIELD(NEWTEXTMETRICA, DWORD, ntmFlags, 56, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, UINT, ntmSizeEM, 60, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, UINT, ntmCellHeight, 64, 4, 4); - TEST_FIELD(NEWTEXTMETRICA, UINT, ntmAvgWidth, 68, 4, 4); + TEST_TYPE_SIZE (NEWTEXTMETRICA, 72) + TEST_TYPE_ALIGN (NEWTEXTMETRICA, 4) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmHeight, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmHeight, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmHeight, 0) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmAscent, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmAscent, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmAscent, 4) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmDescent, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmDescent, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmDescent, 8) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmInternalLeading, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmInternalLeading, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmInternalLeading, 12) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmExternalLeading, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmExternalLeading, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmExternalLeading, 16) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmAveCharWidth, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmAveCharWidth, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmAveCharWidth, 20) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmMaxCharWidth, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmMaxCharWidth, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmMaxCharWidth, 24) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmWeight, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmWeight, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmWeight, 28) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmOverhang, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmOverhang, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmOverhang, 32) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmDigitizedAspectX, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmDigitizedAspectX, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmDigitizedAspectX, 36) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmDigitizedAspectY, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmDigitizedAspectY, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmDigitizedAspectY, 40) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmFirstChar, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmFirstChar, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmFirstChar, 44) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmLastChar, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmLastChar, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmLastChar, 45) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmDefaultChar, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmDefaultChar, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmDefaultChar, 46) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmBreakChar, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmBreakChar, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmBreakChar, 47) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmItalic, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmItalic, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmItalic, 48) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmUnderlined, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmUnderlined, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmUnderlined, 49) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmStruckOut, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmStruckOut, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmStruckOut, 50) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmPitchAndFamily, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmPitchAndFamily, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmPitchAndFamily, 51) + TEST_FIELD_SIZE (NEWTEXTMETRICA, tmCharSet, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, tmCharSet, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, tmCharSet, 52) + TEST_FIELD_SIZE (NEWTEXTMETRICA, ntmFlags, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, ntmFlags, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, ntmFlags, 56) + TEST_FIELD_SIZE (NEWTEXTMETRICA, ntmSizeEM, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, ntmSizeEM, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, ntmSizeEM, 60) + TEST_FIELD_SIZE (NEWTEXTMETRICA, ntmCellHeight, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, ntmCellHeight, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, ntmCellHeight, 64) + TEST_FIELD_SIZE (NEWTEXTMETRICA, ntmAvgWidth, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICA, ntmAvgWidth, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICA, ntmAvgWidth, 68) } static void test_pack_NEWTEXTMETRICEXA(void) { /* NEWTEXTMETRICEXA (pack 4) */ - TEST_TYPE(NEWTEXTMETRICEXA, 96, 4); - TEST_FIELD(NEWTEXTMETRICEXA, NEWTEXTMETRICA, ntmTm, 0, 72, 4); - TEST_FIELD(NEWTEXTMETRICEXA, FONTSIGNATURE, ntmFontSig, 72, 24, 4); + TEST_TYPE_SIZE (NEWTEXTMETRICEXA, 96) + TEST_TYPE_ALIGN (NEWTEXTMETRICEXA, 4) + TEST_FIELD_SIZE (NEWTEXTMETRICEXA, ntmTm, 72) + TEST_FIELD_ALIGN (NEWTEXTMETRICEXA, ntmTm, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICEXA, ntmTm, 0) + TEST_FIELD_SIZE (NEWTEXTMETRICEXA, ntmFontSig, 24) + TEST_FIELD_ALIGN (NEWTEXTMETRICEXA, ntmFontSig, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICEXA, ntmFontSig, 72) } static void test_pack_NEWTEXTMETRICEXW(void) { /* NEWTEXTMETRICEXW (pack 4) */ - TEST_TYPE(NEWTEXTMETRICEXW, 100, 4); - TEST_FIELD(NEWTEXTMETRICEXW, NEWTEXTMETRICW, ntmTm, 0, 76, 4); - TEST_FIELD(NEWTEXTMETRICEXW, FONTSIGNATURE, ntmFontSig, 76, 24, 4); + TEST_TYPE_SIZE (NEWTEXTMETRICEXW, 100) + TEST_TYPE_ALIGN (NEWTEXTMETRICEXW, 4) + TEST_FIELD_SIZE (NEWTEXTMETRICEXW, ntmTm, 76) + TEST_FIELD_ALIGN (NEWTEXTMETRICEXW, ntmTm, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICEXW, ntmTm, 0) + TEST_FIELD_SIZE (NEWTEXTMETRICEXW, ntmFontSig, 24) + TEST_FIELD_ALIGN (NEWTEXTMETRICEXW, ntmFontSig, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICEXW, ntmFontSig, 76) } static void test_pack_NEWTEXTMETRICW(void) { /* NEWTEXTMETRICW (pack 4) */ - TEST_TYPE(NEWTEXTMETRICW, 76, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmHeight, 0, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmAscent, 4, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmDescent, 8, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmInternalLeading, 12, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmExternalLeading, 16, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmAveCharWidth, 20, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmMaxCharWidth, 24, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmWeight, 28, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmOverhang, 32, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmDigitizedAspectX, 36, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, LONG, tmDigitizedAspectY, 40, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, WCHAR, tmFirstChar, 44, 2, 2); - TEST_FIELD(NEWTEXTMETRICW, WCHAR, tmLastChar, 46, 2, 2); - TEST_FIELD(NEWTEXTMETRICW, WCHAR, tmDefaultChar, 48, 2, 2); - TEST_FIELD(NEWTEXTMETRICW, WCHAR, tmBreakChar, 50, 2, 2); - TEST_FIELD(NEWTEXTMETRICW, BYTE, tmItalic, 52, 1, 1); - TEST_FIELD(NEWTEXTMETRICW, BYTE, tmUnderlined, 53, 1, 1); - TEST_FIELD(NEWTEXTMETRICW, BYTE, tmStruckOut, 54, 1, 1); - TEST_FIELD(NEWTEXTMETRICW, BYTE, tmPitchAndFamily, 55, 1, 1); - TEST_FIELD(NEWTEXTMETRICW, BYTE, tmCharSet, 56, 1, 1); - TEST_FIELD(NEWTEXTMETRICW, DWORD, ntmFlags, 60, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, UINT, ntmSizeEM, 64, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, UINT, ntmCellHeight, 68, 4, 4); - TEST_FIELD(NEWTEXTMETRICW, UINT, ntmAvgWidth, 72, 4, 4); + TEST_TYPE_SIZE (NEWTEXTMETRICW, 76) + TEST_TYPE_ALIGN (NEWTEXTMETRICW, 4) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmHeight, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmHeight, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmHeight, 0) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmAscent, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmAscent, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmAscent, 4) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmDescent, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmDescent, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmDescent, 8) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmInternalLeading, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmInternalLeading, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmInternalLeading, 12) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmExternalLeading, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmExternalLeading, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmExternalLeading, 16) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmAveCharWidth, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmAveCharWidth, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmAveCharWidth, 20) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmMaxCharWidth, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmMaxCharWidth, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmMaxCharWidth, 24) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmWeight, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmWeight, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmWeight, 28) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmOverhang, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmOverhang, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmOverhang, 32) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmDigitizedAspectX, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmDigitizedAspectX, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmDigitizedAspectX, 36) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmDigitizedAspectY, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmDigitizedAspectY, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmDigitizedAspectY, 40) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmFirstChar, 2) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmFirstChar, 2) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmFirstChar, 44) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmLastChar, 2) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmLastChar, 2) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmLastChar, 46) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmDefaultChar, 2) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmDefaultChar, 2) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmDefaultChar, 48) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmBreakChar, 2) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmBreakChar, 2) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmBreakChar, 50) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmItalic, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmItalic, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmItalic, 52) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmUnderlined, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmUnderlined, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmUnderlined, 53) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmStruckOut, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmStruckOut, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmStruckOut, 54) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmPitchAndFamily, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmPitchAndFamily, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmPitchAndFamily, 55) + TEST_FIELD_SIZE (NEWTEXTMETRICW, tmCharSet, 1) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, tmCharSet, 1) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, tmCharSet, 56) + TEST_FIELD_SIZE (NEWTEXTMETRICW, ntmFlags, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, ntmFlags, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, ntmFlags, 60) + TEST_FIELD_SIZE (NEWTEXTMETRICW, ntmSizeEM, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, ntmSizeEM, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, ntmSizeEM, 64) + TEST_FIELD_SIZE (NEWTEXTMETRICW, ntmCellHeight, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, ntmCellHeight, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, ntmCellHeight, 68) + TEST_FIELD_SIZE (NEWTEXTMETRICW, ntmAvgWidth, 4) + TEST_FIELD_ALIGN (NEWTEXTMETRICW, ntmAvgWidth, 4) + TEST_FIELD_OFFSET(NEWTEXTMETRICW, ntmAvgWidth, 72) } static void test_pack_NPEXTLOGPEN(void) { /* NPEXTLOGPEN */ - TEST_TYPE(NPEXTLOGPEN, 4, 4); - TEST_TYPE_POINTER(NPEXTLOGPEN, 28, 4); + TEST_TYPE_SIZE (NPEXTLOGPEN, 4) + TEST_TYPE_ALIGN (NPEXTLOGPEN, 4) + TEST_TARGET_SIZE (NPEXTLOGPEN, 28) + TEST_TARGET_ALIGN(NPEXTLOGPEN, 4) } static void test_pack_OLDFONTENUMPROC(void) { /* OLDFONTENUMPROC */ - TEST_TYPE(OLDFONTENUMPROC, 4, 4); + TEST_TYPE_SIZE (OLDFONTENUMPROC, 4) + TEST_TYPE_ALIGN (OLDFONTENUMPROC, 4) } static void test_pack_OLDFONTENUMPROCA(void) { /* OLDFONTENUMPROCA */ - TEST_TYPE(OLDFONTENUMPROCA, 4, 4); + TEST_TYPE_SIZE (OLDFONTENUMPROCA, 4) + TEST_TYPE_ALIGN (OLDFONTENUMPROCA, 4) } static void test_pack_OLDFONTENUMPROCW(void) { /* OLDFONTENUMPROCW */ - TEST_TYPE(OLDFONTENUMPROCW, 4, 4); + TEST_TYPE_SIZE (OLDFONTENUMPROCW, 4) + TEST_TYPE_ALIGN (OLDFONTENUMPROCW, 4) } static void test_pack_OUTLINETEXTMETRICA(void) { /* OUTLINETEXTMETRICA (pack 4) */ - TEST_TYPE(OUTLINETEXTMETRICA, 212, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmSize, 0, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, TEXTMETRICA, otmTextMetrics, 4, 56, 4); - TEST_FIELD(OUTLINETEXTMETRICA, BYTE, otmFiller, 60, 1, 1); - TEST_FIELD(OUTLINETEXTMETRICA, PANOSE, otmPanoseNumber, 61, 10, 1); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmfsSelection, 72, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmfsType, 76, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmsCharSlopeRise, 80, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmsCharSlopeRun, 84, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmItalicAngle, 88, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmEMSquare, 92, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmAscent, 96, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmDescent, 100, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmLineGap, 104, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmsCapEmHeight, 108, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmsXHeight, 112, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, RECT, otmrcFontBox, 116, 16, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmMacAscent, 132, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmMacDescent, 136, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmMacLineGap, 140, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmusMinimumPPEM, 144, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, POINT, otmptSubscriptSize, 148, 8, 4); - TEST_FIELD(OUTLINETEXTMETRICA, POINT, otmptSubscriptOffset, 156, 8, 4); - TEST_FIELD(OUTLINETEXTMETRICA, POINT, otmptSuperscriptSize, 164, 8, 4); - TEST_FIELD(OUTLINETEXTMETRICA, POINT, otmptSuperscriptOffset, 172, 8, 4); - TEST_FIELD(OUTLINETEXTMETRICA, UINT, otmsStrikeoutSize, 180, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmsStrikeoutPosition, 184, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmsUnderscoreSize, 188, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, INT, otmsUnderscorePosition, 192, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, LPSTR, otmpFamilyName, 196, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, LPSTR, otmpFaceName, 200, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, LPSTR, otmpStyleName, 204, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICA, LPSTR, otmpFullName, 208, 4, 4); + TEST_TYPE_SIZE (OUTLINETEXTMETRICA, 212) + TEST_TYPE_ALIGN (OUTLINETEXTMETRICA, 4) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmSize, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmSize, 0) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmTextMetrics, 56) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmTextMetrics, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmTextMetrics, 4) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmFiller, 1) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmFiller, 1) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmFiller, 60) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmPanoseNumber, 10) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmPanoseNumber, 1) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmPanoseNumber, 61) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmfsSelection, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmfsSelection, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmfsSelection, 72) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmfsType, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmfsType, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmfsType, 76) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmsCharSlopeRise, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmsCharSlopeRise, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmsCharSlopeRise, 80) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmsCharSlopeRun, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmsCharSlopeRun, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmsCharSlopeRun, 84) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmItalicAngle, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmItalicAngle, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmItalicAngle, 88) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmEMSquare, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmEMSquare, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmEMSquare, 92) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmAscent, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmAscent, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmAscent, 96) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmDescent, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmDescent, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmDescent, 100) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmLineGap, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmLineGap, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmLineGap, 104) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmsCapEmHeight, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmsCapEmHeight, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmsCapEmHeight, 108) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmsXHeight, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmsXHeight, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmsXHeight, 112) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmrcFontBox, 16) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmrcFontBox, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmrcFontBox, 116) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmMacAscent, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmMacAscent, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmMacAscent, 132) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmMacDescent, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmMacDescent, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmMacDescent, 136) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmMacLineGap, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmMacLineGap, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmMacLineGap, 140) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmusMinimumPPEM, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmusMinimumPPEM, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmusMinimumPPEM, 144) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmptSubscriptSize, 8) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmptSubscriptSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmptSubscriptSize, 148) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmptSubscriptOffset, 8) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmptSubscriptOffset, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmptSubscriptOffset, 156) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmptSuperscriptSize, 8) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmptSuperscriptSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmptSuperscriptSize, 164) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmptSuperscriptOffset, 8) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmptSuperscriptOffset, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmptSuperscriptOffset, 172) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmsStrikeoutSize, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmsStrikeoutSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmsStrikeoutSize, 180) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmsStrikeoutPosition, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmsStrikeoutPosition, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmsStrikeoutPosition, 184) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmsUnderscoreSize, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmsUnderscoreSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmsUnderscoreSize, 188) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmsUnderscorePosition, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmsUnderscorePosition, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmsUnderscorePosition, 192) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmpFamilyName, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmpFamilyName, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName, 196) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmpFaceName, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmpFaceName, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName, 200) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmpStyleName, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmpStyleName, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName, 204) + TEST_FIELD_SIZE (OUTLINETEXTMETRICA, otmpFullName, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICA, otmpFullName, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName, 208) } static void test_pack_OUTLINETEXTMETRICW(void) { /* OUTLINETEXTMETRICW (pack 4) */ - TEST_TYPE(OUTLINETEXTMETRICW, 216, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmSize, 0, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, TEXTMETRICW, otmTextMetrics, 4, 60, 4); - TEST_FIELD(OUTLINETEXTMETRICW, BYTE, otmFiller, 64, 1, 1); - TEST_FIELD(OUTLINETEXTMETRICW, PANOSE, otmPanoseNumber, 65, 10, 1); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmfsSelection, 76, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmfsType, 80, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmsCharSlopeRise, 84, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmsCharSlopeRun, 88, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmItalicAngle, 92, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmEMSquare, 96, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmAscent, 100, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmDescent, 104, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmLineGap, 108, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmsCapEmHeight, 112, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmsXHeight, 116, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, RECT, otmrcFontBox, 120, 16, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmMacAscent, 136, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmMacDescent, 140, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmMacLineGap, 144, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmusMinimumPPEM, 148, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, POINT, otmptSubscriptSize, 152, 8, 4); - TEST_FIELD(OUTLINETEXTMETRICW, POINT, otmptSubscriptOffset, 160, 8, 4); - TEST_FIELD(OUTLINETEXTMETRICW, POINT, otmptSuperscriptSize, 168, 8, 4); - TEST_FIELD(OUTLINETEXTMETRICW, POINT, otmptSuperscriptOffset, 176, 8, 4); - TEST_FIELD(OUTLINETEXTMETRICW, UINT, otmsStrikeoutSize, 184, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmsStrikeoutPosition, 188, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmsUnderscoreSize, 192, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, INT, otmsUnderscorePosition, 196, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, LPSTR, otmpFamilyName, 200, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, LPSTR, otmpFaceName, 204, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, LPSTR, otmpStyleName, 208, 4, 4); - TEST_FIELD(OUTLINETEXTMETRICW, LPSTR, otmpFullName, 212, 4, 4); + TEST_TYPE_SIZE (OUTLINETEXTMETRICW, 216) + TEST_TYPE_ALIGN (OUTLINETEXTMETRICW, 4) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmSize, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmSize, 0) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmTextMetrics, 60) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmTextMetrics, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmTextMetrics, 4) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmFiller, 1) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmFiller, 1) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmFiller, 64) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmPanoseNumber, 10) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmPanoseNumber, 1) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmPanoseNumber, 65) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmfsSelection, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmfsSelection, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmfsSelection, 76) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmfsType, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmfsType, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmfsType, 80) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmsCharSlopeRise, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmsCharSlopeRise, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmsCharSlopeRise, 84) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmsCharSlopeRun, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmsCharSlopeRun, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmsCharSlopeRun, 88) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmItalicAngle, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmItalicAngle, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmItalicAngle, 92) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmEMSquare, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmEMSquare, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmEMSquare, 96) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmAscent, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmAscent, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmAscent, 100) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmDescent, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmDescent, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmDescent, 104) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmLineGap, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmLineGap, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmLineGap, 108) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmsCapEmHeight, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmsCapEmHeight, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmsCapEmHeight, 112) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmsXHeight, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmsXHeight, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmsXHeight, 116) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmrcFontBox, 16) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmrcFontBox, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmrcFontBox, 120) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmMacAscent, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmMacAscent, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmMacAscent, 136) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmMacDescent, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmMacDescent, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmMacDescent, 140) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmMacLineGap, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmMacLineGap, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmMacLineGap, 144) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmusMinimumPPEM, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmusMinimumPPEM, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmusMinimumPPEM, 148) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmptSubscriptSize, 8) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmptSubscriptSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmptSubscriptSize, 152) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmptSubscriptOffset, 8) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmptSubscriptOffset, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmptSubscriptOffset, 160) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmptSuperscriptSize, 8) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmptSuperscriptSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmptSuperscriptSize, 168) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmptSuperscriptOffset, 8) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmptSuperscriptOffset, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmptSuperscriptOffset, 176) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmsStrikeoutSize, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmsStrikeoutSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmsStrikeoutSize, 184) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmsStrikeoutPosition, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmsStrikeoutPosition, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmsStrikeoutPosition, 188) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmsUnderscoreSize, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmsUnderscoreSize, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmsUnderscoreSize, 192) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmsUnderscorePosition, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmsUnderscorePosition, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmsUnderscorePosition, 196) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmpFamilyName, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmpFamilyName, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmpFamilyName, 200) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmpFaceName, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmpFaceName, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmpFaceName, 204) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmpStyleName, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmpStyleName, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmpStyleName, 208) + TEST_FIELD_SIZE (OUTLINETEXTMETRICW, otmpFullName, 4) + TEST_FIELD_ALIGN (OUTLINETEXTMETRICW, otmpFullName, 4) + TEST_FIELD_OFFSET(OUTLINETEXTMETRICW, otmpFullName, 212) } static void test_pack_PABC(void) { /* PABC */ - TEST_TYPE(PABC, 4, 4); - TEST_TYPE_POINTER(PABC, 12, 4); + TEST_TYPE_SIZE (PABC, 4) + TEST_TYPE_ALIGN (PABC, 4) + TEST_TARGET_SIZE (PABC, 12) + TEST_TARGET_ALIGN(PABC, 4) } static void test_pack_PABCFLOAT(void) { /* PABCFLOAT */ - TEST_TYPE(PABCFLOAT, 4, 4); - TEST_TYPE_POINTER(PABCFLOAT, 12, 4); + TEST_TYPE_SIZE (PABCFLOAT, 4) + TEST_TYPE_ALIGN (PABCFLOAT, 4) + TEST_TARGET_SIZE (PABCFLOAT, 12) + TEST_TARGET_ALIGN(PABCFLOAT, 4) } static void test_pack_PANOSE(void) { /* PANOSE (pack 4) */ - TEST_TYPE(PANOSE, 10, 1); - TEST_FIELD(PANOSE, BYTE, bFamilyType, 0, 1, 1); - TEST_FIELD(PANOSE, BYTE, bSerifStyle, 1, 1, 1); - TEST_FIELD(PANOSE, BYTE, bWeight, 2, 1, 1); - TEST_FIELD(PANOSE, BYTE, bProportion, 3, 1, 1); - TEST_FIELD(PANOSE, BYTE, bContrast, 4, 1, 1); - TEST_FIELD(PANOSE, BYTE, bStrokeVariation, 5, 1, 1); - TEST_FIELD(PANOSE, BYTE, bArmStyle, 6, 1, 1); - TEST_FIELD(PANOSE, BYTE, bLetterform, 7, 1, 1); - TEST_FIELD(PANOSE, BYTE, bMidline, 8, 1, 1); - TEST_FIELD(PANOSE, BYTE, bXHeight, 9, 1, 1); + TEST_TYPE_SIZE (PANOSE, 10) + TEST_TYPE_ALIGN (PANOSE, 1) + TEST_FIELD_SIZE (PANOSE, bFamilyType, 1) + TEST_FIELD_ALIGN (PANOSE, bFamilyType, 1) + TEST_FIELD_OFFSET(PANOSE, bFamilyType, 0) + TEST_FIELD_SIZE (PANOSE, bSerifStyle, 1) + TEST_FIELD_ALIGN (PANOSE, bSerifStyle, 1) + TEST_FIELD_OFFSET(PANOSE, bSerifStyle, 1) + TEST_FIELD_SIZE (PANOSE, bWeight, 1) + TEST_FIELD_ALIGN (PANOSE, bWeight, 1) + TEST_FIELD_OFFSET(PANOSE, bWeight, 2) + TEST_FIELD_SIZE (PANOSE, bProportion, 1) + TEST_FIELD_ALIGN (PANOSE, bProportion, 1) + TEST_FIELD_OFFSET(PANOSE, bProportion, 3) + TEST_FIELD_SIZE (PANOSE, bContrast, 1) + TEST_FIELD_ALIGN (PANOSE, bContrast, 1) + TEST_FIELD_OFFSET(PANOSE, bContrast, 4) + TEST_FIELD_SIZE (PANOSE, bStrokeVariation, 1) + TEST_FIELD_ALIGN (PANOSE, bStrokeVariation, 1) + TEST_FIELD_OFFSET(PANOSE, bStrokeVariation, 5) + TEST_FIELD_SIZE (PANOSE, bArmStyle, 1) + TEST_FIELD_ALIGN (PANOSE, bArmStyle, 1) + TEST_FIELD_OFFSET(PANOSE, bArmStyle, 6) + TEST_FIELD_SIZE (PANOSE, bLetterform, 1) + TEST_FIELD_ALIGN (PANOSE, bLetterform, 1) + TEST_FIELD_OFFSET(PANOSE, bLetterform, 7) + TEST_FIELD_SIZE (PANOSE, bMidline, 1) + TEST_FIELD_ALIGN (PANOSE, bMidline, 1) + TEST_FIELD_OFFSET(PANOSE, bMidline, 8) + TEST_FIELD_SIZE (PANOSE, bXHeight, 1) + TEST_FIELD_ALIGN (PANOSE, bXHeight, 1) + TEST_FIELD_OFFSET(PANOSE, bXHeight, 9) } static void test_pack_PATTERN(void) { /* PATTERN */ - TEST_TYPE(PATTERN, 12, 4); + TEST_TYPE_SIZE (PATTERN, 12) + TEST_TYPE_ALIGN (PATTERN, 4) } static void test_pack_PBITMAP(void) { /* PBITMAP */ - TEST_TYPE(PBITMAP, 4, 4); - TEST_TYPE_POINTER(PBITMAP, 24, 4); + TEST_TYPE_SIZE (PBITMAP, 4) + TEST_TYPE_ALIGN (PBITMAP, 4) + TEST_TARGET_SIZE (PBITMAP, 24) + TEST_TARGET_ALIGN(PBITMAP, 4) } static void test_pack_PBITMAPCOREHEADER(void) { /* PBITMAPCOREHEADER */ - TEST_TYPE(PBITMAPCOREHEADER, 4, 4); - TEST_TYPE_POINTER(PBITMAPCOREHEADER, 12, 4); + TEST_TYPE_SIZE (PBITMAPCOREHEADER, 4) + TEST_TYPE_ALIGN (PBITMAPCOREHEADER, 4) + TEST_TARGET_SIZE (PBITMAPCOREHEADER, 12) + TEST_TARGET_ALIGN(PBITMAPCOREHEADER, 4) } static void test_pack_PBITMAPCOREINFO(void) { /* PBITMAPCOREINFO */ - TEST_TYPE(PBITMAPCOREINFO, 4, 4); - TEST_TYPE_POINTER(PBITMAPCOREINFO, 16, 4); + TEST_TYPE_SIZE (PBITMAPCOREINFO, 4) + TEST_TYPE_ALIGN (PBITMAPCOREINFO, 4) + TEST_TARGET_SIZE (PBITMAPCOREINFO, 16) + TEST_TARGET_ALIGN(PBITMAPCOREINFO, 4) } static void test_pack_PBITMAPFILEHEADER(void) { /* PBITMAPFILEHEADER */ - TEST_TYPE(PBITMAPFILEHEADER, 4, 4); - TEST_TYPE_POINTER(PBITMAPFILEHEADER, 14, 2); + TEST_TYPE_SIZE (PBITMAPFILEHEADER, 4) + TEST_TYPE_ALIGN (PBITMAPFILEHEADER, 4) + TEST_TARGET_SIZE (PBITMAPFILEHEADER, 14) + TEST_TARGET_ALIGN(PBITMAPFILEHEADER, 2) } static void test_pack_PBITMAPINFO(void) { /* PBITMAPINFO */ - TEST_TYPE(PBITMAPINFO, 4, 4); - TEST_TYPE_POINTER(PBITMAPINFO, 44, 4); + TEST_TYPE_SIZE (PBITMAPINFO, 4) + TEST_TYPE_ALIGN (PBITMAPINFO, 4) + TEST_TARGET_SIZE (PBITMAPINFO, 44) + TEST_TARGET_ALIGN(PBITMAPINFO, 4) } static void test_pack_PBITMAPINFOHEADER(void) { /* PBITMAPINFOHEADER */ - TEST_TYPE(PBITMAPINFOHEADER, 4, 4); - TEST_TYPE_POINTER(PBITMAPINFOHEADER, 40, 4); + TEST_TYPE_SIZE (PBITMAPINFOHEADER, 4) + TEST_TYPE_ALIGN (PBITMAPINFOHEADER, 4) + TEST_TARGET_SIZE (PBITMAPINFOHEADER, 40) + TEST_TARGET_ALIGN(PBITMAPINFOHEADER, 4) } static void test_pack_PBITMAPV4HEADER(void) { /* PBITMAPV4HEADER */ - TEST_TYPE(PBITMAPV4HEADER, 4, 4); - TEST_TYPE_POINTER(PBITMAPV4HEADER, 108, 4); + TEST_TYPE_SIZE (PBITMAPV4HEADER, 4) + TEST_TYPE_ALIGN (PBITMAPV4HEADER, 4) + TEST_TARGET_SIZE (PBITMAPV4HEADER, 108) + TEST_TARGET_ALIGN(PBITMAPV4HEADER, 4) } static void test_pack_PBITMAPV5HEADER(void) { /* PBITMAPV5HEADER */ - TEST_TYPE(PBITMAPV5HEADER, 4, 4); - TEST_TYPE_POINTER(PBITMAPV5HEADER, 124, 4); + TEST_TYPE_SIZE (PBITMAPV5HEADER, 4) + TEST_TYPE_ALIGN (PBITMAPV5HEADER, 4) + TEST_TARGET_SIZE (PBITMAPV5HEADER, 124) + TEST_TARGET_ALIGN(PBITMAPV5HEADER, 4) } static void test_pack_PBLENDFUNCTION(void) { /* PBLENDFUNCTION */ - TEST_TYPE(PBLENDFUNCTION, 4, 4); - TEST_TYPE_POINTER(PBLENDFUNCTION, 4, 1); + TEST_TYPE_SIZE (PBLENDFUNCTION, 4) + TEST_TYPE_ALIGN (PBLENDFUNCTION, 4) + TEST_TARGET_SIZE (PBLENDFUNCTION, 4) + TEST_TARGET_ALIGN(PBLENDFUNCTION, 1) } static void test_pack_PCHARSETINFO(void) { /* PCHARSETINFO */ - TEST_TYPE(PCHARSETINFO, 4, 4); - TEST_TYPE_POINTER(PCHARSETINFO, 32, 4); + TEST_TYPE_SIZE (PCHARSETINFO, 4) + TEST_TYPE_ALIGN (PCHARSETINFO, 4) + TEST_TARGET_SIZE (PCHARSETINFO, 32) + TEST_TARGET_ALIGN(PCHARSETINFO, 4) } static void test_pack_PCOLORADJUSTMENT(void) { /* PCOLORADJUSTMENT */ - TEST_TYPE(PCOLORADJUSTMENT, 4, 4); - TEST_TYPE_POINTER(PCOLORADJUSTMENT, 24, 2); + TEST_TYPE_SIZE (PCOLORADJUSTMENT, 4) + TEST_TYPE_ALIGN (PCOLORADJUSTMENT, 4) + TEST_TARGET_SIZE (PCOLORADJUSTMENT, 24) + TEST_TARGET_ALIGN(PCOLORADJUSTMENT, 2) } static void test_pack_PDEVMODEA(void) { /* PDEVMODEA */ - TEST_TYPE(PDEVMODEA, 4, 4); + TEST_TYPE_SIZE (PDEVMODEA, 4) + TEST_TYPE_ALIGN (PDEVMODEA, 4) } static void test_pack_PDEVMODEW(void) { /* PDEVMODEW */ - TEST_TYPE(PDEVMODEW, 4, 4); + TEST_TYPE_SIZE (PDEVMODEW, 4) + TEST_TYPE_ALIGN (PDEVMODEW, 4) } static void test_pack_PDIBSECTION(void) { /* PDIBSECTION */ - TEST_TYPE(PDIBSECTION, 4, 4); - TEST_TYPE_POINTER(PDIBSECTION, 84, 4); + TEST_TYPE_SIZE (PDIBSECTION, 4) + TEST_TYPE_ALIGN (PDIBSECTION, 4) + TEST_TARGET_SIZE (PDIBSECTION, 84) + TEST_TARGET_ALIGN(PDIBSECTION, 4) } static void test_pack_PDISPLAY_DEVICEA(void) { /* PDISPLAY_DEVICEA */ - TEST_TYPE(PDISPLAY_DEVICEA, 4, 4); - TEST_TYPE_POINTER(PDISPLAY_DEVICEA, 424, 4); + TEST_TYPE_SIZE (PDISPLAY_DEVICEA, 4) + TEST_TYPE_ALIGN (PDISPLAY_DEVICEA, 4) + TEST_TARGET_SIZE (PDISPLAY_DEVICEA, 424) + TEST_TARGET_ALIGN(PDISPLAY_DEVICEA, 4) } static void test_pack_PDISPLAY_DEVICEW(void) { /* PDISPLAY_DEVICEW */ - TEST_TYPE(PDISPLAY_DEVICEW, 4, 4); - TEST_TYPE_POINTER(PDISPLAY_DEVICEW, 840, 4); + TEST_TYPE_SIZE (PDISPLAY_DEVICEW, 4) + TEST_TYPE_ALIGN (PDISPLAY_DEVICEW, 4) + TEST_TARGET_SIZE (PDISPLAY_DEVICEW, 840) + TEST_TARGET_ALIGN(PDISPLAY_DEVICEW, 4) } static void test_pack_PELARRAY(void) { /* PELARRAY (pack 4) */ - TEST_TYPE(PELARRAY, 20, 4); - TEST_FIELD(PELARRAY, LONG, paXCount, 0, 4, 4); - TEST_FIELD(PELARRAY, LONG, paYCount, 4, 4, 4); - TEST_FIELD(PELARRAY, LONG, paXExt, 8, 4, 4); - TEST_FIELD(PELARRAY, LONG, paYExt, 12, 4, 4); - TEST_FIELD(PELARRAY, BYTE, paRGBs, 16, 1, 1); + TEST_TYPE_SIZE (PELARRAY, 20) + TEST_TYPE_ALIGN (PELARRAY, 4) + TEST_FIELD_SIZE (PELARRAY, paXCount, 4) + TEST_FIELD_ALIGN (PELARRAY, paXCount, 4) + TEST_FIELD_OFFSET(PELARRAY, paXCount, 0) + TEST_FIELD_SIZE (PELARRAY, paYCount, 4) + TEST_FIELD_ALIGN (PELARRAY, paYCount, 4) + TEST_FIELD_OFFSET(PELARRAY, paYCount, 4) + TEST_FIELD_SIZE (PELARRAY, paXExt, 4) + TEST_FIELD_ALIGN (PELARRAY, paXExt, 4) + TEST_FIELD_OFFSET(PELARRAY, paXExt, 8) + TEST_FIELD_SIZE (PELARRAY, paYExt, 4) + TEST_FIELD_ALIGN (PELARRAY, paYExt, 4) + TEST_FIELD_OFFSET(PELARRAY, paYExt, 12) + TEST_FIELD_SIZE (PELARRAY, paRGBs, 1) + TEST_FIELD_ALIGN (PELARRAY, paRGBs, 1) + TEST_FIELD_OFFSET(PELARRAY, paRGBs, 16) } static void test_pack_PEMR(void) { /* PEMR */ - TEST_TYPE(PEMR, 4, 4); - TEST_TYPE_POINTER(PEMR, 8, 4); + TEST_TYPE_SIZE (PEMR, 4) + TEST_TYPE_ALIGN (PEMR, 4) + TEST_TARGET_SIZE (PEMR, 8) + TEST_TARGET_ALIGN(PEMR, 4) } static void test_pack_PEMRABORTPATH(void) { /* PEMRABORTPATH */ - TEST_TYPE(PEMRABORTPATH, 4, 4); - TEST_TYPE_POINTER(PEMRABORTPATH, 8, 4); + TEST_TYPE_SIZE (PEMRABORTPATH, 4) + TEST_TYPE_ALIGN (PEMRABORTPATH, 4) + TEST_TARGET_SIZE (PEMRABORTPATH, 8) + TEST_TARGET_ALIGN(PEMRABORTPATH, 4) } static void test_pack_PEMRANGLEARC(void) { /* PEMRANGLEARC */ - TEST_TYPE(PEMRANGLEARC, 4, 4); - TEST_TYPE_POINTER(PEMRANGLEARC, 28, 4); + TEST_TYPE_SIZE (PEMRANGLEARC, 4) + TEST_TYPE_ALIGN (PEMRANGLEARC, 4) + TEST_TARGET_SIZE (PEMRANGLEARC, 28) + TEST_TARGET_ALIGN(PEMRANGLEARC, 4) } static void test_pack_PEMRARC(void) { /* PEMRARC */ - TEST_TYPE(PEMRARC, 4, 4); - TEST_TYPE_POINTER(PEMRARC, 40, 4); + TEST_TYPE_SIZE (PEMRARC, 4) + TEST_TYPE_ALIGN (PEMRARC, 4) + TEST_TARGET_SIZE (PEMRARC, 40) + TEST_TARGET_ALIGN(PEMRARC, 4) } static void test_pack_PEMRARCTO(void) { /* PEMRARCTO */ - TEST_TYPE(PEMRARCTO, 4, 4); - TEST_TYPE_POINTER(PEMRARCTO, 40, 4); + TEST_TYPE_SIZE (PEMRARCTO, 4) + TEST_TYPE_ALIGN (PEMRARCTO, 4) + TEST_TARGET_SIZE (PEMRARCTO, 40) + TEST_TARGET_ALIGN(PEMRARCTO, 4) } static void test_pack_PEMRBEGINPATH(void) { /* PEMRBEGINPATH */ - TEST_TYPE(PEMRBEGINPATH, 4, 4); - TEST_TYPE_POINTER(PEMRBEGINPATH, 8, 4); + TEST_TYPE_SIZE (PEMRBEGINPATH, 4) + TEST_TYPE_ALIGN (PEMRBEGINPATH, 4) + TEST_TARGET_SIZE (PEMRBEGINPATH, 8) + TEST_TARGET_ALIGN(PEMRBEGINPATH, 4) } static void test_pack_PEMRBITBLT(void) { /* PEMRBITBLT */ - TEST_TYPE(PEMRBITBLT, 4, 4); - TEST_TYPE_POINTER(PEMRBITBLT, 100, 4); + TEST_TYPE_SIZE (PEMRBITBLT, 4) + TEST_TYPE_ALIGN (PEMRBITBLT, 4) + TEST_TARGET_SIZE (PEMRBITBLT, 100) + TEST_TARGET_ALIGN(PEMRBITBLT, 4) } static void test_pack_PEMRCHORD(void) { /* PEMRCHORD */ - TEST_TYPE(PEMRCHORD, 4, 4); - TEST_TYPE_POINTER(PEMRCHORD, 40, 4); + TEST_TYPE_SIZE (PEMRCHORD, 4) + TEST_TYPE_ALIGN (PEMRCHORD, 4) + TEST_TARGET_SIZE (PEMRCHORD, 40) + TEST_TARGET_ALIGN(PEMRCHORD, 4) } static void test_pack_PEMRCLOSEFIGURE(void) { /* PEMRCLOSEFIGURE */ - TEST_TYPE(PEMRCLOSEFIGURE, 4, 4); - TEST_TYPE_POINTER(PEMRCLOSEFIGURE, 8, 4); + TEST_TYPE_SIZE (PEMRCLOSEFIGURE, 4) + TEST_TYPE_ALIGN (PEMRCLOSEFIGURE, 4) + TEST_TARGET_SIZE (PEMRCLOSEFIGURE, 8) + TEST_TARGET_ALIGN(PEMRCLOSEFIGURE, 4) } static void test_pack_PEMRCREATEBRUSHINDIRECT(void) { /* PEMRCREATEBRUSHINDIRECT */ - TEST_TYPE(PEMRCREATEBRUSHINDIRECT, 4, 4); - TEST_TYPE_POINTER(PEMRCREATEBRUSHINDIRECT, 24, 4); + TEST_TYPE_SIZE (PEMRCREATEBRUSHINDIRECT, 4) + TEST_TYPE_ALIGN (PEMRCREATEBRUSHINDIRECT, 4) + TEST_TARGET_SIZE (PEMRCREATEBRUSHINDIRECT, 24) + TEST_TARGET_ALIGN(PEMRCREATEBRUSHINDIRECT, 4) } static void test_pack_PEMRCREATECOLORSPACE(void) { /* PEMRCREATECOLORSPACE */ - TEST_TYPE(PEMRCREATECOLORSPACE, 4, 4); - TEST_TYPE_POINTER(PEMRCREATECOLORSPACE, 340, 4); + TEST_TYPE_SIZE (PEMRCREATECOLORSPACE, 4) + TEST_TYPE_ALIGN (PEMRCREATECOLORSPACE, 4) + TEST_TARGET_SIZE (PEMRCREATECOLORSPACE, 340) + TEST_TARGET_ALIGN(PEMRCREATECOLORSPACE, 4) } static void test_pack_PEMRCREATECOLORSPACEW(void) { /* PEMRCREATECOLORSPACEW */ - TEST_TYPE(PEMRCREATECOLORSPACEW, 4, 4); - TEST_TYPE_POINTER(PEMRCREATECOLORSPACEW, 612, 4); + TEST_TYPE_SIZE (PEMRCREATECOLORSPACEW, 4) + TEST_TYPE_ALIGN (PEMRCREATECOLORSPACEW, 4) + TEST_TARGET_SIZE (PEMRCREATECOLORSPACEW, 612) + TEST_TARGET_ALIGN(PEMRCREATECOLORSPACEW, 4) } static void test_pack_PEMRCREATEDIBPATTERNBRUSHPT(void) { /* PEMRCREATEDIBPATTERNBRUSHPT */ - TEST_TYPE(PEMRCREATEDIBPATTERNBRUSHPT, 4, 4); - TEST_TYPE_POINTER(PEMRCREATEDIBPATTERNBRUSHPT, 32, 4); + TEST_TYPE_SIZE (PEMRCREATEDIBPATTERNBRUSHPT, 4) + TEST_TYPE_ALIGN (PEMRCREATEDIBPATTERNBRUSHPT, 4) + TEST_TARGET_SIZE (PEMRCREATEDIBPATTERNBRUSHPT, 32) + TEST_TARGET_ALIGN(PEMRCREATEDIBPATTERNBRUSHPT, 4) } static void test_pack_PEMRCREATEMONOBRUSH(void) { /* PEMRCREATEMONOBRUSH */ - TEST_TYPE(PEMRCREATEMONOBRUSH, 4, 4); - TEST_TYPE_POINTER(PEMRCREATEMONOBRUSH, 32, 4); + TEST_TYPE_SIZE (PEMRCREATEMONOBRUSH, 4) + TEST_TYPE_ALIGN (PEMRCREATEMONOBRUSH, 4) + TEST_TARGET_SIZE (PEMRCREATEMONOBRUSH, 32) + TEST_TARGET_ALIGN(PEMRCREATEMONOBRUSH, 4) } static void test_pack_PEMRCREATEPALETTE(void) { /* PEMRCREATEPALETTE */ - TEST_TYPE(PEMRCREATEPALETTE, 4, 4); - TEST_TYPE_POINTER(PEMRCREATEPALETTE, 20, 4); + TEST_TYPE_SIZE (PEMRCREATEPALETTE, 4) + TEST_TYPE_ALIGN (PEMRCREATEPALETTE, 4) + TEST_TARGET_SIZE (PEMRCREATEPALETTE, 20) + TEST_TARGET_ALIGN(PEMRCREATEPALETTE, 4) } static void test_pack_PEMRCREATEPEN(void) { /* PEMRCREATEPEN */ - TEST_TYPE(PEMRCREATEPEN, 4, 4); - TEST_TYPE_POINTER(PEMRCREATEPEN, 28, 4); + TEST_TYPE_SIZE (PEMRCREATEPEN, 4) + TEST_TYPE_ALIGN (PEMRCREATEPEN, 4) + TEST_TARGET_SIZE (PEMRCREATEPEN, 28) + TEST_TARGET_ALIGN(PEMRCREATEPEN, 4) } static void test_pack_PEMRDELETECOLORSPACE(void) { /* PEMRDELETECOLORSPACE */ - TEST_TYPE(PEMRDELETECOLORSPACE, 4, 4); - TEST_TYPE_POINTER(PEMRDELETECOLORSPACE, 12, 4); + TEST_TYPE_SIZE (PEMRDELETECOLORSPACE, 4) + TEST_TYPE_ALIGN (PEMRDELETECOLORSPACE, 4) + TEST_TARGET_SIZE (PEMRDELETECOLORSPACE, 12) + TEST_TARGET_ALIGN(PEMRDELETECOLORSPACE, 4) } static void test_pack_PEMRDELETEOBJECT(void) { /* PEMRDELETEOBJECT */ - TEST_TYPE(PEMRDELETEOBJECT, 4, 4); - TEST_TYPE_POINTER(PEMRDELETEOBJECT, 12, 4); + TEST_TYPE_SIZE (PEMRDELETEOBJECT, 4) + TEST_TYPE_ALIGN (PEMRDELETEOBJECT, 4) + TEST_TARGET_SIZE (PEMRDELETEOBJECT, 12) + TEST_TARGET_ALIGN(PEMRDELETEOBJECT, 4) } static void test_pack_PEMRELLIPSE(void) { /* PEMRELLIPSE */ - TEST_TYPE(PEMRELLIPSE, 4, 4); - TEST_TYPE_POINTER(PEMRELLIPSE, 24, 4); + TEST_TYPE_SIZE (PEMRELLIPSE, 4) + TEST_TYPE_ALIGN (PEMRELLIPSE, 4) + TEST_TARGET_SIZE (PEMRELLIPSE, 24) + TEST_TARGET_ALIGN(PEMRELLIPSE, 4) } static void test_pack_PEMRENDPATH(void) { /* PEMRENDPATH */ - TEST_TYPE(PEMRENDPATH, 4, 4); - TEST_TYPE_POINTER(PEMRENDPATH, 8, 4); + TEST_TYPE_SIZE (PEMRENDPATH, 4) + TEST_TYPE_ALIGN (PEMRENDPATH, 4) + TEST_TARGET_SIZE (PEMRENDPATH, 8) + TEST_TARGET_ALIGN(PEMRENDPATH, 4) } static void test_pack_PEMREOF(void) { /* PEMREOF */ - TEST_TYPE(PEMREOF, 4, 4); - TEST_TYPE_POINTER(PEMREOF, 20, 4); + TEST_TYPE_SIZE (PEMREOF, 4) + TEST_TYPE_ALIGN (PEMREOF, 4) + TEST_TARGET_SIZE (PEMREOF, 20) + TEST_TARGET_ALIGN(PEMREOF, 4) } static void test_pack_PEMREXCLUDECLIPRECT(void) { /* PEMREXCLUDECLIPRECT */ - TEST_TYPE(PEMREXCLUDECLIPRECT, 4, 4); - TEST_TYPE_POINTER(PEMREXCLUDECLIPRECT, 24, 4); + TEST_TYPE_SIZE (PEMREXCLUDECLIPRECT, 4) + TEST_TYPE_ALIGN (PEMREXCLUDECLIPRECT, 4) + TEST_TARGET_SIZE (PEMREXCLUDECLIPRECT, 24) + TEST_TARGET_ALIGN(PEMREXCLUDECLIPRECT, 4) } static void test_pack_PEMREXTCREATEFONTINDIRECTW(void) { /* PEMREXTCREATEFONTINDIRECTW */ - TEST_TYPE(PEMREXTCREATEFONTINDIRECTW, 4, 4); - TEST_TYPE_POINTER(PEMREXTCREATEFONTINDIRECTW, 332, 4); + TEST_TYPE_SIZE (PEMREXTCREATEFONTINDIRECTW, 4) + TEST_TYPE_ALIGN (PEMREXTCREATEFONTINDIRECTW, 4) + TEST_TARGET_SIZE (PEMREXTCREATEFONTINDIRECTW, 332) + TEST_TARGET_ALIGN(PEMREXTCREATEFONTINDIRECTW, 4) } static void test_pack_PEMREXTCREATEPEN(void) { /* PEMREXTCREATEPEN */ - TEST_TYPE(PEMREXTCREATEPEN, 4, 4); - TEST_TYPE_POINTER(PEMREXTCREATEPEN, 56, 4); + TEST_TYPE_SIZE (PEMREXTCREATEPEN, 4) + TEST_TYPE_ALIGN (PEMREXTCREATEPEN, 4) + TEST_TARGET_SIZE (PEMREXTCREATEPEN, 56) + TEST_TARGET_ALIGN(PEMREXTCREATEPEN, 4) } static void test_pack_PEMREXTFLOODFILL(void) { /* PEMREXTFLOODFILL */ - TEST_TYPE(PEMREXTFLOODFILL, 4, 4); - TEST_TYPE_POINTER(PEMREXTFLOODFILL, 24, 4); + TEST_TYPE_SIZE (PEMREXTFLOODFILL, 4) + TEST_TYPE_ALIGN (PEMREXTFLOODFILL, 4) + TEST_TARGET_SIZE (PEMREXTFLOODFILL, 24) + TEST_TARGET_ALIGN(PEMREXTFLOODFILL, 4) } static void test_pack_PEMREXTSELECTCLIPRGN(void) { /* PEMREXTSELECTCLIPRGN */ - TEST_TYPE(PEMREXTSELECTCLIPRGN, 4, 4); - TEST_TYPE_POINTER(PEMREXTSELECTCLIPRGN, 20, 4); + TEST_TYPE_SIZE (PEMREXTSELECTCLIPRGN, 4) + TEST_TYPE_ALIGN (PEMREXTSELECTCLIPRGN, 4) + TEST_TARGET_SIZE (PEMREXTSELECTCLIPRGN, 20) + TEST_TARGET_ALIGN(PEMREXTSELECTCLIPRGN, 4) } static void test_pack_PEMREXTTEXTOUTA(void) { /* PEMREXTTEXTOUTA */ - TEST_TYPE(PEMREXTTEXTOUTA, 4, 4); - TEST_TYPE_POINTER(PEMREXTTEXTOUTA, 76, 4); + TEST_TYPE_SIZE (PEMREXTTEXTOUTA, 4) + TEST_TYPE_ALIGN (PEMREXTTEXTOUTA, 4) + TEST_TARGET_SIZE (PEMREXTTEXTOUTA, 76) + TEST_TARGET_ALIGN(PEMREXTTEXTOUTA, 4) } static void test_pack_PEMREXTTEXTOUTW(void) { /* PEMREXTTEXTOUTW */ - TEST_TYPE(PEMREXTTEXTOUTW, 4, 4); - TEST_TYPE_POINTER(PEMREXTTEXTOUTW, 76, 4); + TEST_TYPE_SIZE (PEMREXTTEXTOUTW, 4) + TEST_TYPE_ALIGN (PEMREXTTEXTOUTW, 4) + TEST_TARGET_SIZE (PEMREXTTEXTOUTW, 76) + TEST_TARGET_ALIGN(PEMREXTTEXTOUTW, 4) } static void test_pack_PEMRFILLPATH(void) { /* PEMRFILLPATH */ - TEST_TYPE(PEMRFILLPATH, 4, 4); - TEST_TYPE_POINTER(PEMRFILLPATH, 24, 4); + TEST_TYPE_SIZE (PEMRFILLPATH, 4) + TEST_TYPE_ALIGN (PEMRFILLPATH, 4) + TEST_TARGET_SIZE (PEMRFILLPATH, 24) + TEST_TARGET_ALIGN(PEMRFILLPATH, 4) } static void test_pack_PEMRFILLRGN(void) { /* PEMRFILLRGN */ - TEST_TYPE(PEMRFILLRGN, 4, 4); - TEST_TYPE_POINTER(PEMRFILLRGN, 36, 4); + TEST_TYPE_SIZE (PEMRFILLRGN, 4) + TEST_TYPE_ALIGN (PEMRFILLRGN, 4) + TEST_TARGET_SIZE (PEMRFILLRGN, 36) + TEST_TARGET_ALIGN(PEMRFILLRGN, 4) } static void test_pack_PEMRFLATTENPATH(void) { /* PEMRFLATTENPATH */ - TEST_TYPE(PEMRFLATTENPATH, 4, 4); - TEST_TYPE_POINTER(PEMRFLATTENPATH, 8, 4); + TEST_TYPE_SIZE (PEMRFLATTENPATH, 4) + TEST_TYPE_ALIGN (PEMRFLATTENPATH, 4) + TEST_TARGET_SIZE (PEMRFLATTENPATH, 8) + TEST_TARGET_ALIGN(PEMRFLATTENPATH, 4) } static void test_pack_PEMRFORMAT(void) { /* PEMRFORMAT */ - TEST_TYPE(PEMRFORMAT, 4, 4); - TEST_TYPE_POINTER(PEMRFORMAT, 16, 4); + TEST_TYPE_SIZE (PEMRFORMAT, 4) + TEST_TYPE_ALIGN (PEMRFORMAT, 4) + TEST_TARGET_SIZE (PEMRFORMAT, 16) + TEST_TARGET_ALIGN(PEMRFORMAT, 4) } static void test_pack_PEMRFRAMERGN(void) { /* PEMRFRAMERGN */ - TEST_TYPE(PEMRFRAMERGN, 4, 4); - TEST_TYPE_POINTER(PEMRFRAMERGN, 44, 4); + TEST_TYPE_SIZE (PEMRFRAMERGN, 4) + TEST_TYPE_ALIGN (PEMRFRAMERGN, 4) + TEST_TARGET_SIZE (PEMRFRAMERGN, 44) + TEST_TARGET_ALIGN(PEMRFRAMERGN, 4) } static void test_pack_PEMRGDICOMMENT(void) { /* PEMRGDICOMMENT */ - TEST_TYPE(PEMRGDICOMMENT, 4, 4); - TEST_TYPE_POINTER(PEMRGDICOMMENT, 16, 4); + TEST_TYPE_SIZE (PEMRGDICOMMENT, 4) + TEST_TYPE_ALIGN (PEMRGDICOMMENT, 4) + TEST_TARGET_SIZE (PEMRGDICOMMENT, 16) + TEST_TARGET_ALIGN(PEMRGDICOMMENT, 4) } static void test_pack_PEMRGLSBOUNDEDRECORD(void) { /* PEMRGLSBOUNDEDRECORD */ - TEST_TYPE(PEMRGLSBOUNDEDRECORD, 4, 4); - TEST_TYPE_POINTER(PEMRGLSBOUNDEDRECORD, 32, 4); + TEST_TYPE_SIZE (PEMRGLSBOUNDEDRECORD, 4) + TEST_TYPE_ALIGN (PEMRGLSBOUNDEDRECORD, 4) + TEST_TARGET_SIZE (PEMRGLSBOUNDEDRECORD, 32) + TEST_TARGET_ALIGN(PEMRGLSBOUNDEDRECORD, 4) } static void test_pack_PEMRGLSRECORD(void) { /* PEMRGLSRECORD */ - TEST_TYPE(PEMRGLSRECORD, 4, 4); - TEST_TYPE_POINTER(PEMRGLSRECORD, 16, 4); + TEST_TYPE_SIZE (PEMRGLSRECORD, 4) + TEST_TYPE_ALIGN (PEMRGLSRECORD, 4) + TEST_TARGET_SIZE (PEMRGLSRECORD, 16) + TEST_TARGET_ALIGN(PEMRGLSRECORD, 4) } static void test_pack_PEMRINTERSECTCLIPRECT(void) { /* PEMRINTERSECTCLIPRECT */ - TEST_TYPE(PEMRINTERSECTCLIPRECT, 4, 4); - TEST_TYPE_POINTER(PEMRINTERSECTCLIPRECT, 24, 4); + TEST_TYPE_SIZE (PEMRINTERSECTCLIPRECT, 4) + TEST_TYPE_ALIGN (PEMRINTERSECTCLIPRECT, 4) + TEST_TARGET_SIZE (PEMRINTERSECTCLIPRECT, 24) + TEST_TARGET_ALIGN(PEMRINTERSECTCLIPRECT, 4) } static void test_pack_PEMRINVERTRGN(void) { /* PEMRINVERTRGN */ - TEST_TYPE(PEMRINVERTRGN, 4, 4); - TEST_TYPE_POINTER(PEMRINVERTRGN, 32, 4); + TEST_TYPE_SIZE (PEMRINVERTRGN, 4) + TEST_TYPE_ALIGN (PEMRINVERTRGN, 4) + TEST_TARGET_SIZE (PEMRINVERTRGN, 32) + TEST_TARGET_ALIGN(PEMRINVERTRGN, 4) } static void test_pack_PEMRLINETO(void) { /* PEMRLINETO */ - TEST_TYPE(PEMRLINETO, 4, 4); - TEST_TYPE_POINTER(PEMRLINETO, 16, 4); + TEST_TYPE_SIZE (PEMRLINETO, 4) + TEST_TYPE_ALIGN (PEMRLINETO, 4) + TEST_TARGET_SIZE (PEMRLINETO, 16) + TEST_TARGET_ALIGN(PEMRLINETO, 4) } static void test_pack_PEMRMASKBLT(void) { /* PEMRMASKBLT */ - TEST_TYPE(PEMRMASKBLT, 4, 4); - TEST_TYPE_POINTER(PEMRMASKBLT, 128, 4); + TEST_TYPE_SIZE (PEMRMASKBLT, 4) + TEST_TYPE_ALIGN (PEMRMASKBLT, 4) + TEST_TARGET_SIZE (PEMRMASKBLT, 128) + TEST_TARGET_ALIGN(PEMRMASKBLT, 4) } static void test_pack_PEMRMODIFYWORLDTRANSFORM(void) { /* PEMRMODIFYWORLDTRANSFORM */ - TEST_TYPE(PEMRMODIFYWORLDTRANSFORM, 4, 4); - TEST_TYPE_POINTER(PEMRMODIFYWORLDTRANSFORM, 36, 4); + TEST_TYPE_SIZE (PEMRMODIFYWORLDTRANSFORM, 4) + TEST_TYPE_ALIGN (PEMRMODIFYWORLDTRANSFORM, 4) + TEST_TARGET_SIZE (PEMRMODIFYWORLDTRANSFORM, 36) + TEST_TARGET_ALIGN(PEMRMODIFYWORLDTRANSFORM, 4) } static void test_pack_PEMRMOVETOEX(void) { /* PEMRMOVETOEX */ - TEST_TYPE(PEMRMOVETOEX, 4, 4); - TEST_TYPE_POINTER(PEMRMOVETOEX, 16, 4); + TEST_TYPE_SIZE (PEMRMOVETOEX, 4) + TEST_TYPE_ALIGN (PEMRMOVETOEX, 4) + TEST_TARGET_SIZE (PEMRMOVETOEX, 16) + TEST_TARGET_ALIGN(PEMRMOVETOEX, 4) } static void test_pack_PEMROFFSETCLIPRGN(void) { /* PEMROFFSETCLIPRGN */ - TEST_TYPE(PEMROFFSETCLIPRGN, 4, 4); - TEST_TYPE_POINTER(PEMROFFSETCLIPRGN, 16, 4); + TEST_TYPE_SIZE (PEMROFFSETCLIPRGN, 4) + TEST_TYPE_ALIGN (PEMROFFSETCLIPRGN, 4) + TEST_TARGET_SIZE (PEMROFFSETCLIPRGN, 16) + TEST_TARGET_ALIGN(PEMROFFSETCLIPRGN, 4) } static void test_pack_PEMRPAINTRGN(void) { /* PEMRPAINTRGN */ - TEST_TYPE(PEMRPAINTRGN, 4, 4); - TEST_TYPE_POINTER(PEMRPAINTRGN, 32, 4); + TEST_TYPE_SIZE (PEMRPAINTRGN, 4) + TEST_TYPE_ALIGN (PEMRPAINTRGN, 4) + TEST_TARGET_SIZE (PEMRPAINTRGN, 32) + TEST_TARGET_ALIGN(PEMRPAINTRGN, 4) } static void test_pack_PEMRPIE(void) { /* PEMRPIE */ - TEST_TYPE(PEMRPIE, 4, 4); - TEST_TYPE_POINTER(PEMRPIE, 40, 4); + TEST_TYPE_SIZE (PEMRPIE, 4) + TEST_TYPE_ALIGN (PEMRPIE, 4) + TEST_TARGET_SIZE (PEMRPIE, 40) + TEST_TARGET_ALIGN(PEMRPIE, 4) } static void test_pack_PEMRPIXELFORMAT(void) { /* PEMRPIXELFORMAT */ - TEST_TYPE(PEMRPIXELFORMAT, 4, 4); - TEST_TYPE_POINTER(PEMRPIXELFORMAT, 48, 4); + TEST_TYPE_SIZE (PEMRPIXELFORMAT, 4) + TEST_TYPE_ALIGN (PEMRPIXELFORMAT, 4) + TEST_TARGET_SIZE (PEMRPIXELFORMAT, 48) + TEST_TARGET_ALIGN(PEMRPIXELFORMAT, 4) } static void test_pack_PEMRPLGBLT(void) { /* PEMRPLGBLT */ - TEST_TYPE(PEMRPLGBLT, 4, 4); - TEST_TYPE_POINTER(PEMRPLGBLT, 140, 4); + TEST_TYPE_SIZE (PEMRPLGBLT, 4) + TEST_TYPE_ALIGN (PEMRPLGBLT, 4) + TEST_TARGET_SIZE (PEMRPLGBLT, 140) + TEST_TARGET_ALIGN(PEMRPLGBLT, 4) } static void test_pack_PEMRPOLYBEZIER(void) { /* PEMRPOLYBEZIER */ - TEST_TYPE(PEMRPOLYBEZIER, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYBEZIER, 36, 4); + TEST_TYPE_SIZE (PEMRPOLYBEZIER, 4) + TEST_TYPE_ALIGN (PEMRPOLYBEZIER, 4) + TEST_TARGET_SIZE (PEMRPOLYBEZIER, 36) + TEST_TARGET_ALIGN(PEMRPOLYBEZIER, 4) } static void test_pack_PEMRPOLYBEZIER16(void) { /* PEMRPOLYBEZIER16 */ - TEST_TYPE(PEMRPOLYBEZIER16, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYBEZIER16, 32, 4); + TEST_TYPE_SIZE (PEMRPOLYBEZIER16, 4) + TEST_TYPE_ALIGN (PEMRPOLYBEZIER16, 4) + TEST_TARGET_SIZE (PEMRPOLYBEZIER16, 32) + TEST_TARGET_ALIGN(PEMRPOLYBEZIER16, 4) } static void test_pack_PEMRPOLYBEZIERTO(void) { /* PEMRPOLYBEZIERTO */ - TEST_TYPE(PEMRPOLYBEZIERTO, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYBEZIERTO, 36, 4); + TEST_TYPE_SIZE (PEMRPOLYBEZIERTO, 4) + TEST_TYPE_ALIGN (PEMRPOLYBEZIERTO, 4) + TEST_TARGET_SIZE (PEMRPOLYBEZIERTO, 36) + TEST_TARGET_ALIGN(PEMRPOLYBEZIERTO, 4) } static void test_pack_PEMRPOLYBEZIERTO16(void) { /* PEMRPOLYBEZIERTO16 */ - TEST_TYPE(PEMRPOLYBEZIERTO16, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYBEZIERTO16, 32, 4); + TEST_TYPE_SIZE (PEMRPOLYBEZIERTO16, 4) + TEST_TYPE_ALIGN (PEMRPOLYBEZIERTO16, 4) + TEST_TARGET_SIZE (PEMRPOLYBEZIERTO16, 32) + TEST_TARGET_ALIGN(PEMRPOLYBEZIERTO16, 4) } static void test_pack_PEMRPOLYDRAW(void) { /* PEMRPOLYDRAW */ - TEST_TYPE(PEMRPOLYDRAW, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYDRAW, 40, 4); + TEST_TYPE_SIZE (PEMRPOLYDRAW, 4) + TEST_TYPE_ALIGN (PEMRPOLYDRAW, 4) + TEST_TARGET_SIZE (PEMRPOLYDRAW, 40) + TEST_TARGET_ALIGN(PEMRPOLYDRAW, 4) } static void test_pack_PEMRPOLYDRAW16(void) { /* PEMRPOLYDRAW16 */ - TEST_TYPE(PEMRPOLYDRAW16, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYDRAW16, 36, 4); + TEST_TYPE_SIZE (PEMRPOLYDRAW16, 4) + TEST_TYPE_ALIGN (PEMRPOLYDRAW16, 4) + TEST_TARGET_SIZE (PEMRPOLYDRAW16, 36) + TEST_TARGET_ALIGN(PEMRPOLYDRAW16, 4) } static void test_pack_PEMRPOLYGON(void) { /* PEMRPOLYGON */ - TEST_TYPE(PEMRPOLYGON, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYGON, 36, 4); + TEST_TYPE_SIZE (PEMRPOLYGON, 4) + TEST_TYPE_ALIGN (PEMRPOLYGON, 4) + TEST_TARGET_SIZE (PEMRPOLYGON, 36) + TEST_TARGET_ALIGN(PEMRPOLYGON, 4) } static void test_pack_PEMRPOLYGON16(void) { /* PEMRPOLYGON16 */ - TEST_TYPE(PEMRPOLYGON16, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYGON16, 32, 4); + TEST_TYPE_SIZE (PEMRPOLYGON16, 4) + TEST_TYPE_ALIGN (PEMRPOLYGON16, 4) + TEST_TARGET_SIZE (PEMRPOLYGON16, 32) + TEST_TARGET_ALIGN(PEMRPOLYGON16, 4) } static void test_pack_PEMRPOLYLINE(void) { /* PEMRPOLYLINE */ - TEST_TYPE(PEMRPOLYLINE, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYLINE, 36, 4); + TEST_TYPE_SIZE (PEMRPOLYLINE, 4) + TEST_TYPE_ALIGN (PEMRPOLYLINE, 4) + TEST_TARGET_SIZE (PEMRPOLYLINE, 36) + TEST_TARGET_ALIGN(PEMRPOLYLINE, 4) } static void test_pack_PEMRPOLYLINE16(void) { /* PEMRPOLYLINE16 */ - TEST_TYPE(PEMRPOLYLINE16, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYLINE16, 32, 4); + TEST_TYPE_SIZE (PEMRPOLYLINE16, 4) + TEST_TYPE_ALIGN (PEMRPOLYLINE16, 4) + TEST_TARGET_SIZE (PEMRPOLYLINE16, 32) + TEST_TARGET_ALIGN(PEMRPOLYLINE16, 4) } static void test_pack_PEMRPOLYLINETO(void) { /* PEMRPOLYLINETO */ - TEST_TYPE(PEMRPOLYLINETO, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYLINETO, 36, 4); + TEST_TYPE_SIZE (PEMRPOLYLINETO, 4) + TEST_TYPE_ALIGN (PEMRPOLYLINETO, 4) + TEST_TARGET_SIZE (PEMRPOLYLINETO, 36) + TEST_TARGET_ALIGN(PEMRPOLYLINETO, 4) } static void test_pack_PEMRPOLYLINETO16(void) { /* PEMRPOLYLINETO16 */ - TEST_TYPE(PEMRPOLYLINETO16, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYLINETO16, 32, 4); + TEST_TYPE_SIZE (PEMRPOLYLINETO16, 4) + TEST_TYPE_ALIGN (PEMRPOLYLINETO16, 4) + TEST_TARGET_SIZE (PEMRPOLYLINETO16, 32) + TEST_TARGET_ALIGN(PEMRPOLYLINETO16, 4) } static void test_pack_PEMRPOLYPOLYGON(void) { /* PEMRPOLYPOLYGON */ - TEST_TYPE(PEMRPOLYPOLYGON, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYPOLYGON, 44, 4); + TEST_TYPE_SIZE (PEMRPOLYPOLYGON, 4) + TEST_TYPE_ALIGN (PEMRPOLYPOLYGON, 4) + TEST_TARGET_SIZE (PEMRPOLYPOLYGON, 44) + TEST_TARGET_ALIGN(PEMRPOLYPOLYGON, 4) } static void test_pack_PEMRPOLYPOLYGON16(void) { /* PEMRPOLYPOLYGON16 */ - TEST_TYPE(PEMRPOLYPOLYGON16, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYPOLYGON16, 40, 4); + TEST_TYPE_SIZE (PEMRPOLYPOLYGON16, 4) + TEST_TYPE_ALIGN (PEMRPOLYPOLYGON16, 4) + TEST_TARGET_SIZE (PEMRPOLYPOLYGON16, 40) + TEST_TARGET_ALIGN(PEMRPOLYPOLYGON16, 4) } static void test_pack_PEMRPOLYPOLYLINE(void) { /* PEMRPOLYPOLYLINE */ - TEST_TYPE(PEMRPOLYPOLYLINE, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYPOLYLINE, 44, 4); + TEST_TYPE_SIZE (PEMRPOLYPOLYLINE, 4) + TEST_TYPE_ALIGN (PEMRPOLYPOLYLINE, 4) + TEST_TARGET_SIZE (PEMRPOLYPOLYLINE, 44) + TEST_TARGET_ALIGN(PEMRPOLYPOLYLINE, 4) } static void test_pack_PEMRPOLYPOLYLINE16(void) { /* PEMRPOLYPOLYLINE16 */ - TEST_TYPE(PEMRPOLYPOLYLINE16, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYPOLYLINE16, 40, 4); + TEST_TYPE_SIZE (PEMRPOLYPOLYLINE16, 4) + TEST_TYPE_ALIGN (PEMRPOLYPOLYLINE16, 4) + TEST_TARGET_SIZE (PEMRPOLYPOLYLINE16, 40) + TEST_TARGET_ALIGN(PEMRPOLYPOLYLINE16, 4) } static void test_pack_PEMRPOLYTEXTOUTA(void) { /* PEMRPOLYTEXTOUTA */ - TEST_TYPE(PEMRPOLYTEXTOUTA, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYTEXTOUTA, 80, 4); + TEST_TYPE_SIZE (PEMRPOLYTEXTOUTA, 4) + TEST_TYPE_ALIGN (PEMRPOLYTEXTOUTA, 4) + TEST_TARGET_SIZE (PEMRPOLYTEXTOUTA, 80) + TEST_TARGET_ALIGN(PEMRPOLYTEXTOUTA, 4) } static void test_pack_PEMRPOLYTEXTOUTW(void) { /* PEMRPOLYTEXTOUTW */ - TEST_TYPE(PEMRPOLYTEXTOUTW, 4, 4); - TEST_TYPE_POINTER(PEMRPOLYTEXTOUTW, 80, 4); + TEST_TYPE_SIZE (PEMRPOLYTEXTOUTW, 4) + TEST_TYPE_ALIGN (PEMRPOLYTEXTOUTW, 4) + TEST_TARGET_SIZE (PEMRPOLYTEXTOUTW, 80) + TEST_TARGET_ALIGN(PEMRPOLYTEXTOUTW, 4) } static void test_pack_PEMRREALIZEPALETTE(void) { /* PEMRREALIZEPALETTE */ - TEST_TYPE(PEMRREALIZEPALETTE, 4, 4); - TEST_TYPE_POINTER(PEMRREALIZEPALETTE, 8, 4); + TEST_TYPE_SIZE (PEMRREALIZEPALETTE, 4) + TEST_TYPE_ALIGN (PEMRREALIZEPALETTE, 4) + TEST_TARGET_SIZE (PEMRREALIZEPALETTE, 8) + TEST_TARGET_ALIGN(PEMRREALIZEPALETTE, 4) } static void test_pack_PEMRRECTANGLE(void) { /* PEMRRECTANGLE */ - TEST_TYPE(PEMRRECTANGLE, 4, 4); - TEST_TYPE_POINTER(PEMRRECTANGLE, 24, 4); + TEST_TYPE_SIZE (PEMRRECTANGLE, 4) + TEST_TYPE_ALIGN (PEMRRECTANGLE, 4) + TEST_TARGET_SIZE (PEMRRECTANGLE, 24) + TEST_TARGET_ALIGN(PEMRRECTANGLE, 4) } static void test_pack_PEMRRESIZEPALETTE(void) { /* PEMRRESIZEPALETTE */ - TEST_TYPE(PEMRRESIZEPALETTE, 4, 4); - TEST_TYPE_POINTER(PEMRRESIZEPALETTE, 16, 4); + TEST_TYPE_SIZE (PEMRRESIZEPALETTE, 4) + TEST_TYPE_ALIGN (PEMRRESIZEPALETTE, 4) + TEST_TARGET_SIZE (PEMRRESIZEPALETTE, 16) + TEST_TARGET_ALIGN(PEMRRESIZEPALETTE, 4) } static void test_pack_PEMRRESTOREDC(void) { /* PEMRRESTOREDC */ - TEST_TYPE(PEMRRESTOREDC, 4, 4); - TEST_TYPE_POINTER(PEMRRESTOREDC, 12, 4); + TEST_TYPE_SIZE (PEMRRESTOREDC, 4) + TEST_TYPE_ALIGN (PEMRRESTOREDC, 4) + TEST_TARGET_SIZE (PEMRRESTOREDC, 12) + TEST_TARGET_ALIGN(PEMRRESTOREDC, 4) } static void test_pack_PEMRROUNDRECT(void) { /* PEMRROUNDRECT */ - TEST_TYPE(PEMRROUNDRECT, 4, 4); - TEST_TYPE_POINTER(PEMRROUNDRECT, 32, 4); + TEST_TYPE_SIZE (PEMRROUNDRECT, 4) + TEST_TYPE_ALIGN (PEMRROUNDRECT, 4) + TEST_TARGET_SIZE (PEMRROUNDRECT, 32) + TEST_TARGET_ALIGN(PEMRROUNDRECT, 4) } static void test_pack_PEMRSAVEDC(void) { /* PEMRSAVEDC */ - TEST_TYPE(PEMRSAVEDC, 4, 4); - TEST_TYPE_POINTER(PEMRSAVEDC, 8, 4); + TEST_TYPE_SIZE (PEMRSAVEDC, 4) + TEST_TYPE_ALIGN (PEMRSAVEDC, 4) + TEST_TARGET_SIZE (PEMRSAVEDC, 8) + TEST_TARGET_ALIGN(PEMRSAVEDC, 4) } static void test_pack_PEMRSCALEVIEWPORTEXTEX(void) { /* PEMRSCALEVIEWPORTEXTEX */ - TEST_TYPE(PEMRSCALEVIEWPORTEXTEX, 4, 4); - TEST_TYPE_POINTER(PEMRSCALEVIEWPORTEXTEX, 24, 4); + TEST_TYPE_SIZE (PEMRSCALEVIEWPORTEXTEX, 4) + TEST_TYPE_ALIGN (PEMRSCALEVIEWPORTEXTEX, 4) + TEST_TARGET_SIZE (PEMRSCALEVIEWPORTEXTEX, 24) + TEST_TARGET_ALIGN(PEMRSCALEVIEWPORTEXTEX, 4) } static void test_pack_PEMRSCALEWINDOWEXTEX(void) { /* PEMRSCALEWINDOWEXTEX */ - TEST_TYPE(PEMRSCALEWINDOWEXTEX, 4, 4); - TEST_TYPE_POINTER(PEMRSCALEWINDOWEXTEX, 24, 4); + TEST_TYPE_SIZE (PEMRSCALEWINDOWEXTEX, 4) + TEST_TYPE_ALIGN (PEMRSCALEWINDOWEXTEX, 4) + TEST_TARGET_SIZE (PEMRSCALEWINDOWEXTEX, 24) + TEST_TARGET_ALIGN(PEMRSCALEWINDOWEXTEX, 4) } static void test_pack_PEMRSELECTCLIPPATH(void) { /* PEMRSELECTCLIPPATH */ - TEST_TYPE(PEMRSELECTCLIPPATH, 4, 4); - TEST_TYPE_POINTER(PEMRSELECTCLIPPATH, 12, 4); + TEST_TYPE_SIZE (PEMRSELECTCLIPPATH, 4) + TEST_TYPE_ALIGN (PEMRSELECTCLIPPATH, 4) + TEST_TARGET_SIZE (PEMRSELECTCLIPPATH, 12) + TEST_TARGET_ALIGN(PEMRSELECTCLIPPATH, 4) } static void test_pack_PEMRSELECTCOLORSPACE(void) { /* PEMRSELECTCOLORSPACE */ - TEST_TYPE(PEMRSELECTCOLORSPACE, 4, 4); - TEST_TYPE_POINTER(PEMRSELECTCOLORSPACE, 12, 4); + TEST_TYPE_SIZE (PEMRSELECTCOLORSPACE, 4) + TEST_TYPE_ALIGN (PEMRSELECTCOLORSPACE, 4) + TEST_TARGET_SIZE (PEMRSELECTCOLORSPACE, 12) + TEST_TARGET_ALIGN(PEMRSELECTCOLORSPACE, 4) } static void test_pack_PEMRSELECTOBJECT(void) { /* PEMRSELECTOBJECT */ - TEST_TYPE(PEMRSELECTOBJECT, 4, 4); - TEST_TYPE_POINTER(PEMRSELECTOBJECT, 12, 4); + TEST_TYPE_SIZE (PEMRSELECTOBJECT, 4) + TEST_TYPE_ALIGN (PEMRSELECTOBJECT, 4) + TEST_TARGET_SIZE (PEMRSELECTOBJECT, 12) + TEST_TARGET_ALIGN(PEMRSELECTOBJECT, 4) } static void test_pack_PEMRSELECTPALETTE(void) { /* PEMRSELECTPALETTE */ - TEST_TYPE(PEMRSELECTPALETTE, 4, 4); - TEST_TYPE_POINTER(PEMRSELECTPALETTE, 12, 4); + TEST_TYPE_SIZE (PEMRSELECTPALETTE, 4) + TEST_TYPE_ALIGN (PEMRSELECTPALETTE, 4) + TEST_TARGET_SIZE (PEMRSELECTPALETTE, 12) + TEST_TARGET_ALIGN(PEMRSELECTPALETTE, 4) } static void test_pack_PEMRSETARCDIRECTION(void) { /* PEMRSETARCDIRECTION */ - TEST_TYPE(PEMRSETARCDIRECTION, 4, 4); - TEST_TYPE_POINTER(PEMRSETARCDIRECTION, 12, 4); + TEST_TYPE_SIZE (PEMRSETARCDIRECTION, 4) + TEST_TYPE_ALIGN (PEMRSETARCDIRECTION, 4) + TEST_TARGET_SIZE (PEMRSETARCDIRECTION, 12) + TEST_TARGET_ALIGN(PEMRSETARCDIRECTION, 4) } static void test_pack_PEMRSETBKCOLOR(void) { /* PEMRSETBKCOLOR */ - TEST_TYPE(PEMRSETBKCOLOR, 4, 4); - TEST_TYPE_POINTER(PEMRSETBKCOLOR, 12, 4); + TEST_TYPE_SIZE (PEMRSETBKCOLOR, 4) + TEST_TYPE_ALIGN (PEMRSETBKCOLOR, 4) + TEST_TARGET_SIZE (PEMRSETBKCOLOR, 12) + TEST_TARGET_ALIGN(PEMRSETBKCOLOR, 4) } static void test_pack_PEMRSETBKMODE(void) { /* PEMRSETBKMODE */ - TEST_TYPE(PEMRSETBKMODE, 4, 4); - TEST_TYPE_POINTER(PEMRSETBKMODE, 12, 4); + TEST_TYPE_SIZE (PEMRSETBKMODE, 4) + TEST_TYPE_ALIGN (PEMRSETBKMODE, 4) + TEST_TARGET_SIZE (PEMRSETBKMODE, 12) + TEST_TARGET_ALIGN(PEMRSETBKMODE, 4) } static void test_pack_PEMRSETBRUSHORGEX(void) { /* PEMRSETBRUSHORGEX */ - TEST_TYPE(PEMRSETBRUSHORGEX, 4, 4); - TEST_TYPE_POINTER(PEMRSETBRUSHORGEX, 16, 4); + TEST_TYPE_SIZE (PEMRSETBRUSHORGEX, 4) + TEST_TYPE_ALIGN (PEMRSETBRUSHORGEX, 4) + TEST_TARGET_SIZE (PEMRSETBRUSHORGEX, 16) + TEST_TARGET_ALIGN(PEMRSETBRUSHORGEX, 4) } static void test_pack_PEMRSETCOLORADJUSTMENT(void) { /* PEMRSETCOLORADJUSTMENT */ - TEST_TYPE(PEMRSETCOLORADJUSTMENT, 4, 4); - TEST_TYPE_POINTER(PEMRSETCOLORADJUSTMENT, 32, 4); + TEST_TYPE_SIZE (PEMRSETCOLORADJUSTMENT, 4) + TEST_TYPE_ALIGN (PEMRSETCOLORADJUSTMENT, 4) + TEST_TARGET_SIZE (PEMRSETCOLORADJUSTMENT, 32) + TEST_TARGET_ALIGN(PEMRSETCOLORADJUSTMENT, 4) } static void test_pack_PEMRSETCOLORSPACE(void) { /* PEMRSETCOLORSPACE */ - TEST_TYPE(PEMRSETCOLORSPACE, 4, 4); - TEST_TYPE_POINTER(PEMRSETCOLORSPACE, 12, 4); + TEST_TYPE_SIZE (PEMRSETCOLORSPACE, 4) + TEST_TYPE_ALIGN (PEMRSETCOLORSPACE, 4) + TEST_TARGET_SIZE (PEMRSETCOLORSPACE, 12) + TEST_TARGET_ALIGN(PEMRSETCOLORSPACE, 4) } static void test_pack_PEMRSETDIBITSTODEVICE(void) { /* PEMRSETDIBITSTODEVICE */ - TEST_TYPE(PEMRSETDIBITSTODEVICE, 4, 4); - TEST_TYPE_POINTER(PEMRSETDIBITSTODEVICE, 76, 4); + TEST_TYPE_SIZE (PEMRSETDIBITSTODEVICE, 4) + TEST_TYPE_ALIGN (PEMRSETDIBITSTODEVICE, 4) + TEST_TARGET_SIZE (PEMRSETDIBITSTODEVICE, 76) + TEST_TARGET_ALIGN(PEMRSETDIBITSTODEVICE, 4) } static void test_pack_PEMRSETICMMODE(void) { /* PEMRSETICMMODE */ - TEST_TYPE(PEMRSETICMMODE, 4, 4); - TEST_TYPE_POINTER(PEMRSETICMMODE, 12, 4); + TEST_TYPE_SIZE (PEMRSETICMMODE, 4) + TEST_TYPE_ALIGN (PEMRSETICMMODE, 4) + TEST_TARGET_SIZE (PEMRSETICMMODE, 12) + TEST_TARGET_ALIGN(PEMRSETICMMODE, 4) } static void test_pack_PEMRSETLAYOUT(void) { /* PEMRSETLAYOUT */ - TEST_TYPE(PEMRSETLAYOUT, 4, 4); - TEST_TYPE_POINTER(PEMRSETLAYOUT, 12, 4); + TEST_TYPE_SIZE (PEMRSETLAYOUT, 4) + TEST_TYPE_ALIGN (PEMRSETLAYOUT, 4) + TEST_TARGET_SIZE (PEMRSETLAYOUT, 12) + TEST_TARGET_ALIGN(PEMRSETLAYOUT, 4) } static void test_pack_PEMRSETMAPMODE(void) { /* PEMRSETMAPMODE */ - TEST_TYPE(PEMRSETMAPMODE, 4, 4); - TEST_TYPE_POINTER(PEMRSETMAPMODE, 12, 4); + TEST_TYPE_SIZE (PEMRSETMAPMODE, 4) + TEST_TYPE_ALIGN (PEMRSETMAPMODE, 4) + TEST_TARGET_SIZE (PEMRSETMAPMODE, 12) + TEST_TARGET_ALIGN(PEMRSETMAPMODE, 4) } static void test_pack_PEMRSETMAPPERFLAGS(void) { /* PEMRSETMAPPERFLAGS */ - TEST_TYPE(PEMRSETMAPPERFLAGS, 4, 4); - TEST_TYPE_POINTER(PEMRSETMAPPERFLAGS, 12, 4); + TEST_TYPE_SIZE (PEMRSETMAPPERFLAGS, 4) + TEST_TYPE_ALIGN (PEMRSETMAPPERFLAGS, 4) + TEST_TARGET_SIZE (PEMRSETMAPPERFLAGS, 12) + TEST_TARGET_ALIGN(PEMRSETMAPPERFLAGS, 4) } static void test_pack_PEMRSETMETARGN(void) { /* PEMRSETMETARGN */ - TEST_TYPE(PEMRSETMETARGN, 4, 4); - TEST_TYPE_POINTER(PEMRSETMETARGN, 8, 4); + TEST_TYPE_SIZE (PEMRSETMETARGN, 4) + TEST_TYPE_ALIGN (PEMRSETMETARGN, 4) + TEST_TARGET_SIZE (PEMRSETMETARGN, 8) + TEST_TARGET_ALIGN(PEMRSETMETARGN, 4) } static void test_pack_PEMRSETMITERLIMIT(void) { /* PEMRSETMITERLIMIT */ - TEST_TYPE(PEMRSETMITERLIMIT, 4, 4); - TEST_TYPE_POINTER(PEMRSETMITERLIMIT, 12, 4); + TEST_TYPE_SIZE (PEMRSETMITERLIMIT, 4) + TEST_TYPE_ALIGN (PEMRSETMITERLIMIT, 4) + TEST_TARGET_SIZE (PEMRSETMITERLIMIT, 12) + TEST_TARGET_ALIGN(PEMRSETMITERLIMIT, 4) } static void test_pack_PEMRSETPALETTEENTRIES(void) { /* PEMRSETPALETTEENTRIES */ - TEST_TYPE(PEMRSETPALETTEENTRIES, 4, 4); - TEST_TYPE_POINTER(PEMRSETPALETTEENTRIES, 24, 4); + TEST_TYPE_SIZE (PEMRSETPALETTEENTRIES, 4) + TEST_TYPE_ALIGN (PEMRSETPALETTEENTRIES, 4) + TEST_TARGET_SIZE (PEMRSETPALETTEENTRIES, 24) + TEST_TARGET_ALIGN(PEMRSETPALETTEENTRIES, 4) } static void test_pack_PEMRSETPIXELV(void) { /* PEMRSETPIXELV */ - TEST_TYPE(PEMRSETPIXELV, 4, 4); - TEST_TYPE_POINTER(PEMRSETPIXELV, 20, 4); + TEST_TYPE_SIZE (PEMRSETPIXELV, 4) + TEST_TYPE_ALIGN (PEMRSETPIXELV, 4) + TEST_TARGET_SIZE (PEMRSETPIXELV, 20) + TEST_TARGET_ALIGN(PEMRSETPIXELV, 4) } static void test_pack_PEMRSETPOLYFILLMODE(void) { /* PEMRSETPOLYFILLMODE */ - TEST_TYPE(PEMRSETPOLYFILLMODE, 4, 4); - TEST_TYPE_POINTER(PEMRSETPOLYFILLMODE, 12, 4); + TEST_TYPE_SIZE (PEMRSETPOLYFILLMODE, 4) + TEST_TYPE_ALIGN (PEMRSETPOLYFILLMODE, 4) + TEST_TARGET_SIZE (PEMRSETPOLYFILLMODE, 12) + TEST_TARGET_ALIGN(PEMRSETPOLYFILLMODE, 4) } static void test_pack_PEMRSETROP2(void) { /* PEMRSETROP2 */ - TEST_TYPE(PEMRSETROP2, 4, 4); - TEST_TYPE_POINTER(PEMRSETROP2, 12, 4); + TEST_TYPE_SIZE (PEMRSETROP2, 4) + TEST_TYPE_ALIGN (PEMRSETROP2, 4) + TEST_TARGET_SIZE (PEMRSETROP2, 12) + TEST_TARGET_ALIGN(PEMRSETROP2, 4) } static void test_pack_PEMRSETSTRETCHBLTMODE(void) { /* PEMRSETSTRETCHBLTMODE */ - TEST_TYPE(PEMRSETSTRETCHBLTMODE, 4, 4); - TEST_TYPE_POINTER(PEMRSETSTRETCHBLTMODE, 12, 4); + TEST_TYPE_SIZE (PEMRSETSTRETCHBLTMODE, 4) + TEST_TYPE_ALIGN (PEMRSETSTRETCHBLTMODE, 4) + TEST_TARGET_SIZE (PEMRSETSTRETCHBLTMODE, 12) + TEST_TARGET_ALIGN(PEMRSETSTRETCHBLTMODE, 4) } static void test_pack_PEMRSETTEXTALIGN(void) { /* PEMRSETTEXTALIGN */ - TEST_TYPE(PEMRSETTEXTALIGN, 4, 4); - TEST_TYPE_POINTER(PEMRSETTEXTALIGN, 12, 4); + TEST_TYPE_SIZE (PEMRSETTEXTALIGN, 4) + TEST_TYPE_ALIGN (PEMRSETTEXTALIGN, 4) + TEST_TARGET_SIZE (PEMRSETTEXTALIGN, 12) + TEST_TARGET_ALIGN(PEMRSETTEXTALIGN, 4) } static void test_pack_PEMRSETTEXTCOLOR(void) { /* PEMRSETTEXTCOLOR */ - TEST_TYPE(PEMRSETTEXTCOLOR, 4, 4); - TEST_TYPE_POINTER(PEMRSETTEXTCOLOR, 12, 4); + TEST_TYPE_SIZE (PEMRSETTEXTCOLOR, 4) + TEST_TYPE_ALIGN (PEMRSETTEXTCOLOR, 4) + TEST_TARGET_SIZE (PEMRSETTEXTCOLOR, 12) + TEST_TARGET_ALIGN(PEMRSETTEXTCOLOR, 4) } static void test_pack_PEMRSETVIEWPORTEXTEX(void) { /* PEMRSETVIEWPORTEXTEX */ - TEST_TYPE(PEMRSETVIEWPORTEXTEX, 4, 4); - TEST_TYPE_POINTER(PEMRSETVIEWPORTEXTEX, 16, 4); + TEST_TYPE_SIZE (PEMRSETVIEWPORTEXTEX, 4) + TEST_TYPE_ALIGN (PEMRSETVIEWPORTEXTEX, 4) + TEST_TARGET_SIZE (PEMRSETVIEWPORTEXTEX, 16) + TEST_TARGET_ALIGN(PEMRSETVIEWPORTEXTEX, 4) } static void test_pack_PEMRSETVIEWPORTORGEX(void) { /* PEMRSETVIEWPORTORGEX */ - TEST_TYPE(PEMRSETVIEWPORTORGEX, 4, 4); - TEST_TYPE_POINTER(PEMRSETVIEWPORTORGEX, 16, 4); + TEST_TYPE_SIZE (PEMRSETVIEWPORTORGEX, 4) + TEST_TYPE_ALIGN (PEMRSETVIEWPORTORGEX, 4) + TEST_TARGET_SIZE (PEMRSETVIEWPORTORGEX, 16) + TEST_TARGET_ALIGN(PEMRSETVIEWPORTORGEX, 4) } static void test_pack_PEMRSETWINDOWEXTEX(void) { /* PEMRSETWINDOWEXTEX */ - TEST_TYPE(PEMRSETWINDOWEXTEX, 4, 4); - TEST_TYPE_POINTER(PEMRSETWINDOWEXTEX, 16, 4); + TEST_TYPE_SIZE (PEMRSETWINDOWEXTEX, 4) + TEST_TYPE_ALIGN (PEMRSETWINDOWEXTEX, 4) + TEST_TARGET_SIZE (PEMRSETWINDOWEXTEX, 16) + TEST_TARGET_ALIGN(PEMRSETWINDOWEXTEX, 4) } static void test_pack_PEMRSETWINDOWORGEX(void) { /* PEMRSETWINDOWORGEX */ - TEST_TYPE(PEMRSETWINDOWORGEX, 4, 4); - TEST_TYPE_POINTER(PEMRSETWINDOWORGEX, 16, 4); + TEST_TYPE_SIZE (PEMRSETWINDOWORGEX, 4) + TEST_TYPE_ALIGN (PEMRSETWINDOWORGEX, 4) + TEST_TARGET_SIZE (PEMRSETWINDOWORGEX, 16) + TEST_TARGET_ALIGN(PEMRSETWINDOWORGEX, 4) } static void test_pack_PEMRSETWORLDTRANSFORM(void) { /* PEMRSETWORLDTRANSFORM */ - TEST_TYPE(PEMRSETWORLDTRANSFORM, 4, 4); - TEST_TYPE_POINTER(PEMRSETWORLDTRANSFORM, 32, 4); + TEST_TYPE_SIZE (PEMRSETWORLDTRANSFORM, 4) + TEST_TYPE_ALIGN (PEMRSETWORLDTRANSFORM, 4) + TEST_TARGET_SIZE (PEMRSETWORLDTRANSFORM, 32) + TEST_TARGET_ALIGN(PEMRSETWORLDTRANSFORM, 4) } static void test_pack_PEMRSTRETCHBLT(void) { /* PEMRSTRETCHBLT */ - TEST_TYPE(PEMRSTRETCHBLT, 4, 4); - TEST_TYPE_POINTER(PEMRSTRETCHBLT, 108, 4); + TEST_TYPE_SIZE (PEMRSTRETCHBLT, 4) + TEST_TYPE_ALIGN (PEMRSTRETCHBLT, 4) + TEST_TARGET_SIZE (PEMRSTRETCHBLT, 108) + TEST_TARGET_ALIGN(PEMRSTRETCHBLT, 4) } static void test_pack_PEMRSTRETCHDIBITS(void) { /* PEMRSTRETCHDIBITS */ - TEST_TYPE(PEMRSTRETCHDIBITS, 4, 4); - TEST_TYPE_POINTER(PEMRSTRETCHDIBITS, 80, 4); + TEST_TYPE_SIZE (PEMRSTRETCHDIBITS, 4) + TEST_TYPE_ALIGN (PEMRSTRETCHDIBITS, 4) + TEST_TARGET_SIZE (PEMRSTRETCHDIBITS, 80) + TEST_TARGET_ALIGN(PEMRSTRETCHDIBITS, 4) } static void test_pack_PEMRSTROKEANDFILLPATH(void) { /* PEMRSTROKEANDFILLPATH */ - TEST_TYPE(PEMRSTROKEANDFILLPATH, 4, 4); - TEST_TYPE_POINTER(PEMRSTROKEANDFILLPATH, 24, 4); + TEST_TYPE_SIZE (PEMRSTROKEANDFILLPATH, 4) + TEST_TYPE_ALIGN (PEMRSTROKEANDFILLPATH, 4) + TEST_TARGET_SIZE (PEMRSTROKEANDFILLPATH, 24) + TEST_TARGET_ALIGN(PEMRSTROKEANDFILLPATH, 4) } static void test_pack_PEMRSTROKEPATH(void) { /* PEMRSTROKEPATH */ - TEST_TYPE(PEMRSTROKEPATH, 4, 4); - TEST_TYPE_POINTER(PEMRSTROKEPATH, 24, 4); + TEST_TYPE_SIZE (PEMRSTROKEPATH, 4) + TEST_TYPE_ALIGN (PEMRSTROKEPATH, 4) + TEST_TARGET_SIZE (PEMRSTROKEPATH, 24) + TEST_TARGET_ALIGN(PEMRSTROKEPATH, 4) } static void test_pack_PEMRTEXT(void) { /* PEMRTEXT */ - TEST_TYPE(PEMRTEXT, 4, 4); - TEST_TYPE_POINTER(PEMRTEXT, 40, 4); + TEST_TYPE_SIZE (PEMRTEXT, 4) + TEST_TYPE_ALIGN (PEMRTEXT, 4) + TEST_TARGET_SIZE (PEMRTEXT, 40) + TEST_TARGET_ALIGN(PEMRTEXT, 4) } static void test_pack_PEMRWIDENPATH(void) { /* PEMRWIDENPATH */ - TEST_TYPE(PEMRWIDENPATH, 4, 4); - TEST_TYPE_POINTER(PEMRWIDENPATH, 8, 4); + TEST_TYPE_SIZE (PEMRWIDENPATH, 4) + TEST_TYPE_ALIGN (PEMRWIDENPATH, 4) + TEST_TARGET_SIZE (PEMRWIDENPATH, 8) + TEST_TARGET_ALIGN(PEMRWIDENPATH, 4) } static void test_pack_PENHMETAHEADER(void) { /* PENHMETAHEADER */ - TEST_TYPE(PENHMETAHEADER, 4, 4); - TEST_TYPE_POINTER(PENHMETAHEADER, 108, 4); + TEST_TYPE_SIZE (PENHMETAHEADER, 4) + TEST_TYPE_ALIGN (PENHMETAHEADER, 4) + TEST_TARGET_SIZE (PENHMETAHEADER, 108) + TEST_TARGET_ALIGN(PENHMETAHEADER, 4) } static void test_pack_PEXTLOGFONTA(void) { /* PEXTLOGFONTA */ - TEST_TYPE(PEXTLOGFONTA, 4, 4); - TEST_TYPE_POINTER(PEXTLOGFONTA, 192, 4); + TEST_TYPE_SIZE (PEXTLOGFONTA, 4) + TEST_TYPE_ALIGN (PEXTLOGFONTA, 4) + TEST_TARGET_SIZE (PEXTLOGFONTA, 192) + TEST_TARGET_ALIGN(PEXTLOGFONTA, 4) } static void test_pack_PEXTLOGFONTW(void) { /* PEXTLOGFONTW */ - TEST_TYPE(PEXTLOGFONTW, 4, 4); - TEST_TYPE_POINTER(PEXTLOGFONTW, 320, 4); + TEST_TYPE_SIZE (PEXTLOGFONTW, 4) + TEST_TYPE_ALIGN (PEXTLOGFONTW, 4) + TEST_TARGET_SIZE (PEXTLOGFONTW, 320) + TEST_TARGET_ALIGN(PEXTLOGFONTW, 4) } static void test_pack_PEXTLOGPEN(void) { /* PEXTLOGPEN */ - TEST_TYPE(PEXTLOGPEN, 4, 4); - TEST_TYPE_POINTER(PEXTLOGPEN, 28, 4); + TEST_TYPE_SIZE (PEXTLOGPEN, 4) + TEST_TYPE_ALIGN (PEXTLOGPEN, 4) + TEST_TARGET_SIZE (PEXTLOGPEN, 28) + TEST_TARGET_ALIGN(PEXTLOGPEN, 4) } static void test_pack_PFONTSIGNATURE(void) { /* PFONTSIGNATURE */ - TEST_TYPE(PFONTSIGNATURE, 4, 4); - TEST_TYPE_POINTER(PFONTSIGNATURE, 24, 4); + TEST_TYPE_SIZE (PFONTSIGNATURE, 4) + TEST_TYPE_ALIGN (PFONTSIGNATURE, 4) + TEST_TARGET_SIZE (PFONTSIGNATURE, 24) + TEST_TARGET_ALIGN(PFONTSIGNATURE, 4) } static void test_pack_PGLYPHMETRICSFLOAT(void) { /* PGLYPHMETRICSFLOAT */ - TEST_TYPE(PGLYPHMETRICSFLOAT, 4, 4); - TEST_TYPE_POINTER(PGLYPHMETRICSFLOAT, 24, 4); + TEST_TYPE_SIZE (PGLYPHMETRICSFLOAT, 4) + TEST_TYPE_ALIGN (PGLYPHMETRICSFLOAT, 4) + TEST_TARGET_SIZE (PGLYPHMETRICSFLOAT, 24) + TEST_TARGET_ALIGN(PGLYPHMETRICSFLOAT, 4) } static void test_pack_PGRADIENT_RECT(void) { /* PGRADIENT_RECT */ - TEST_TYPE(PGRADIENT_RECT, 4, 4); - TEST_TYPE_POINTER(PGRADIENT_RECT, 8, 4); + TEST_TYPE_SIZE (PGRADIENT_RECT, 4) + TEST_TYPE_ALIGN (PGRADIENT_RECT, 4) + TEST_TARGET_SIZE (PGRADIENT_RECT, 8) + TEST_TARGET_ALIGN(PGRADIENT_RECT, 4) } static void test_pack_PGRADIENT_TRIANGLE(void) { /* PGRADIENT_TRIANGLE */ - TEST_TYPE(PGRADIENT_TRIANGLE, 4, 4); - TEST_TYPE_POINTER(PGRADIENT_TRIANGLE, 12, 4); + TEST_TYPE_SIZE (PGRADIENT_TRIANGLE, 4) + TEST_TYPE_ALIGN (PGRADIENT_TRIANGLE, 4) + TEST_TARGET_SIZE (PGRADIENT_TRIANGLE, 12) + TEST_TARGET_ALIGN(PGRADIENT_TRIANGLE, 4) } static void test_pack_PHANDLETABLE(void) { /* PHANDLETABLE */ - TEST_TYPE(PHANDLETABLE, 4, 4); - TEST_TYPE_POINTER(PHANDLETABLE, 4, 4); + TEST_TYPE_SIZE (PHANDLETABLE, 4) + TEST_TYPE_ALIGN (PHANDLETABLE, 4) + TEST_TARGET_SIZE (PHANDLETABLE, 4) + TEST_TARGET_ALIGN(PHANDLETABLE, 4) } static void test_pack_PIXELFORMATDESCRIPTOR(void) { /* PIXELFORMATDESCRIPTOR (pack 4) */ - TEST_TYPE(PIXELFORMATDESCRIPTOR, 40, 4); - TEST_FIELD(PIXELFORMATDESCRIPTOR, WORD, nSize, 0, 2, 2); - TEST_FIELD(PIXELFORMATDESCRIPTOR, WORD, nVersion, 2, 2, 2); - TEST_FIELD(PIXELFORMATDESCRIPTOR, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, iPixelType, 8, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cColorBits, 9, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cRedBits, 10, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cRedShift, 11, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cGreenBits, 12, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cGreenShift, 13, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cBlueBits, 14, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cBlueShift, 15, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cAlphaBits, 16, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cAlphaShift, 17, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cAccumBits, 18, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cAccumRedBits, 19, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cAccumGreenBits, 20, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cAccumBlueBits, 21, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cAccumAlphaBits, 22, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cDepthBits, 23, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cStencilBits, 24, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, cAuxBuffers, 25, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, iLayerType, 26, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, BYTE, bReserved, 27, 1, 1); - TEST_FIELD(PIXELFORMATDESCRIPTOR, DWORD, dwLayerMask, 28, 4, 4); - TEST_FIELD(PIXELFORMATDESCRIPTOR, DWORD, dwVisibleMask, 32, 4, 4); - TEST_FIELD(PIXELFORMATDESCRIPTOR, DWORD, dwDamageMask, 36, 4, 4); + TEST_TYPE_SIZE (PIXELFORMATDESCRIPTOR, 40) + TEST_TYPE_ALIGN (PIXELFORMATDESCRIPTOR, 4) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, nSize, 2) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, nSize, 2) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, nSize, 0) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, nVersion, 2) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, nVersion, 2) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, nVersion, 2) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, dwFlags, 4) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, dwFlags, 4) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, dwFlags, 4) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, iPixelType, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, iPixelType, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, iPixelType, 8) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cColorBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cColorBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cColorBits, 9) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cRedBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cRedBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cRedBits, 10) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cRedShift, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cRedShift, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cRedShift, 11) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cGreenBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cGreenBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cGreenBits, 12) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cGreenShift, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cGreenShift, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cGreenShift, 13) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cBlueBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cBlueBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cBlueBits, 14) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cBlueShift, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cBlueShift, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cBlueShift, 15) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cAlphaBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cAlphaBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cAlphaBits, 16) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cAlphaShift, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cAlphaShift, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cAlphaShift, 17) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cAccumBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cAccumBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cAccumBits, 18) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cAccumRedBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cAccumRedBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cAccumRedBits, 19) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cAccumGreenBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cAccumGreenBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cAccumGreenBits, 20) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cAccumBlueBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cAccumBlueBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cAccumBlueBits, 21) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cAccumAlphaBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cAccumAlphaBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cAccumAlphaBits, 22) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cDepthBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cDepthBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cDepthBits, 23) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cStencilBits, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cStencilBits, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cStencilBits, 24) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, cAuxBuffers, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, cAuxBuffers, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, cAuxBuffers, 25) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, iLayerType, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, iLayerType, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, iLayerType, 26) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, bReserved, 1) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, bReserved, 1) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, bReserved, 27) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, dwLayerMask, 4) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, dwLayerMask, 4) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, dwLayerMask, 28) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, dwVisibleMask, 4) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, dwVisibleMask, 4) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, dwVisibleMask, 32) + TEST_FIELD_SIZE (PIXELFORMATDESCRIPTOR, dwDamageMask, 4) + TEST_FIELD_ALIGN (PIXELFORMATDESCRIPTOR, dwDamageMask, 4) + TEST_FIELD_OFFSET(PIXELFORMATDESCRIPTOR, dwDamageMask, 36) } static void test_pack_PLAYERPLANEDESCRIPTOR(void) { /* PLAYERPLANEDESCRIPTOR */ - TEST_TYPE(PLAYERPLANEDESCRIPTOR, 4, 4); - TEST_TYPE_POINTER(PLAYERPLANEDESCRIPTOR, 32, 4); + TEST_TYPE_SIZE (PLAYERPLANEDESCRIPTOR, 4) + TEST_TYPE_ALIGN (PLAYERPLANEDESCRIPTOR, 4) + TEST_TARGET_SIZE (PLAYERPLANEDESCRIPTOR, 32) + TEST_TARGET_ALIGN(PLAYERPLANEDESCRIPTOR, 4) } static void test_pack_PLOCALESIGNATURE(void) { /* PLOCALESIGNATURE */ - TEST_TYPE(PLOCALESIGNATURE, 4, 4); - TEST_TYPE_POINTER(PLOCALESIGNATURE, 32, 4); + TEST_TYPE_SIZE (PLOCALESIGNATURE, 4) + TEST_TYPE_ALIGN (PLOCALESIGNATURE, 4) + TEST_TARGET_SIZE (PLOCALESIGNATURE, 32) + TEST_TARGET_ALIGN(PLOCALESIGNATURE, 4) } static void test_pack_PLOGBRUSH(void) { /* PLOGBRUSH */ - TEST_TYPE(PLOGBRUSH, 4, 4); - TEST_TYPE_POINTER(PLOGBRUSH, 12, 4); + TEST_TYPE_SIZE (PLOGBRUSH, 4) + TEST_TYPE_ALIGN (PLOGBRUSH, 4) + TEST_TARGET_SIZE (PLOGBRUSH, 12) + TEST_TARGET_ALIGN(PLOGBRUSH, 4) } static void test_pack_PLOGFONTA(void) { /* PLOGFONTA */ - TEST_TYPE(PLOGFONTA, 4, 4); - TEST_TYPE_POINTER(PLOGFONTA, 60, 4); + TEST_TYPE_SIZE (PLOGFONTA, 4) + TEST_TYPE_ALIGN (PLOGFONTA, 4) + TEST_TARGET_SIZE (PLOGFONTA, 60) + TEST_TARGET_ALIGN(PLOGFONTA, 4) } static void test_pack_PLOGFONTW(void) { /* PLOGFONTW */ - TEST_TYPE(PLOGFONTW, 4, 4); - TEST_TYPE_POINTER(PLOGFONTW, 92, 4); + TEST_TYPE_SIZE (PLOGFONTW, 4) + TEST_TYPE_ALIGN (PLOGFONTW, 4) + TEST_TARGET_SIZE (PLOGFONTW, 92) + TEST_TARGET_ALIGN(PLOGFONTW, 4) } static void test_pack_PMETAHEADER(void) { /* PMETAHEADER */ - TEST_TYPE(PMETAHEADER, 4, 4); - TEST_TYPE_POINTER(PMETAHEADER, 18, 2); + TEST_TYPE_SIZE (PMETAHEADER, 4) + TEST_TYPE_ALIGN (PMETAHEADER, 4) + TEST_TARGET_SIZE (PMETAHEADER, 18) + TEST_TARGET_ALIGN(PMETAHEADER, 2) } static void test_pack_PMETARECORD(void) { /* PMETARECORD */ - TEST_TYPE(PMETARECORD, 4, 4); - TEST_TYPE_POINTER(PMETARECORD, 8, 4); + TEST_TYPE_SIZE (PMETARECORD, 4) + TEST_TYPE_ALIGN (PMETARECORD, 4) + TEST_TARGET_SIZE (PMETARECORD, 8) + TEST_TARGET_ALIGN(PMETARECORD, 4) } static void test_pack_PNEWTEXTMETRICA(void) { /* PNEWTEXTMETRICA */ - TEST_TYPE(PNEWTEXTMETRICA, 4, 4); - TEST_TYPE_POINTER(PNEWTEXTMETRICA, 72, 4); + TEST_TYPE_SIZE (PNEWTEXTMETRICA, 4) + TEST_TYPE_ALIGN (PNEWTEXTMETRICA, 4) + TEST_TARGET_SIZE (PNEWTEXTMETRICA, 72) + TEST_TARGET_ALIGN(PNEWTEXTMETRICA, 4) } static void test_pack_PNEWTEXTMETRICW(void) { /* PNEWTEXTMETRICW */ - TEST_TYPE(PNEWTEXTMETRICW, 4, 4); - TEST_TYPE_POINTER(PNEWTEXTMETRICW, 76, 4); + TEST_TYPE_SIZE (PNEWTEXTMETRICW, 4) + TEST_TYPE_ALIGN (PNEWTEXTMETRICW, 4) + TEST_TARGET_SIZE (PNEWTEXTMETRICW, 76) + TEST_TARGET_ALIGN(PNEWTEXTMETRICW, 4) } static void test_pack_POINTFLOAT(void) { /* POINTFLOAT (pack 4) */ - TEST_TYPE(POINTFLOAT, 8, 4); - TEST_FIELD(POINTFLOAT, FLOAT, x, 0, 4, 4); - TEST_FIELD(POINTFLOAT, FLOAT, y, 4, 4, 4); + TEST_TYPE_SIZE (POINTFLOAT, 8) + TEST_TYPE_ALIGN (POINTFLOAT, 4) + TEST_FIELD_SIZE (POINTFLOAT, x, 4) + TEST_FIELD_ALIGN (POINTFLOAT, x, 4) + TEST_FIELD_OFFSET(POINTFLOAT, x, 0) + TEST_FIELD_SIZE (POINTFLOAT, y, 4) + TEST_FIELD_ALIGN (POINTFLOAT, y, 4) + TEST_FIELD_OFFSET(POINTFLOAT, y, 4) } static void test_pack_POINTFX(void) { /* POINTFX (pack 4) */ - TEST_TYPE(POINTFX, 8, 2); - TEST_FIELD(POINTFX, FIXED, x, 0, 4, 2); - TEST_FIELD(POINTFX, FIXED, y, 4, 4, 2); + TEST_TYPE_SIZE (POINTFX, 8) + TEST_TYPE_ALIGN (POINTFX, 2) + TEST_FIELD_SIZE (POINTFX, x, 4) + TEST_FIELD_ALIGN (POINTFX, x, 2) + TEST_FIELD_OFFSET(POINTFX, x, 0) + TEST_FIELD_SIZE (POINTFX, y, 4) + TEST_FIELD_ALIGN (POINTFX, y, 2) + TEST_FIELD_OFFSET(POINTFX, y, 4) } static void test_pack_POLYTEXTA(void) { /* POLYTEXTA (pack 4) */ - TEST_TYPE(POLYTEXTA, 40, 4); - TEST_FIELD(POLYTEXTA, INT, x, 0, 4, 4); - TEST_FIELD(POLYTEXTA, INT, y, 4, 4, 4); - TEST_FIELD(POLYTEXTA, UINT, n, 8, 4, 4); - TEST_FIELD(POLYTEXTA, LPCSTR, lpstr, 12, 4, 4); - TEST_FIELD(POLYTEXTA, UINT, uiFlags, 16, 4, 4); - TEST_FIELD(POLYTEXTA, RECT, rcl, 20, 16, 4); - TEST_FIELD(POLYTEXTA, INT *, pdx, 36, 4, 4); + TEST_TYPE_SIZE (POLYTEXTA, 40) + TEST_TYPE_ALIGN (POLYTEXTA, 4) + TEST_FIELD_SIZE (POLYTEXTA, x, 4) + TEST_FIELD_ALIGN (POLYTEXTA, x, 4) + TEST_FIELD_OFFSET(POLYTEXTA, x, 0) + TEST_FIELD_SIZE (POLYTEXTA, y, 4) + TEST_FIELD_ALIGN (POLYTEXTA, y, 4) + TEST_FIELD_OFFSET(POLYTEXTA, y, 4) + TEST_FIELD_SIZE (POLYTEXTA, n, 4) + TEST_FIELD_ALIGN (POLYTEXTA, n, 4) + TEST_FIELD_OFFSET(POLYTEXTA, n, 8) + TEST_FIELD_SIZE (POLYTEXTA, lpstr, 4) + TEST_FIELD_ALIGN (POLYTEXTA, lpstr, 4) + TEST_FIELD_OFFSET(POLYTEXTA, lpstr, 12) + TEST_FIELD_SIZE (POLYTEXTA, uiFlags, 4) + TEST_FIELD_ALIGN (POLYTEXTA, uiFlags, 4) + TEST_FIELD_OFFSET(POLYTEXTA, uiFlags, 16) + TEST_FIELD_SIZE (POLYTEXTA, rcl, 16) + TEST_FIELD_ALIGN (POLYTEXTA, rcl, 4) + TEST_FIELD_OFFSET(POLYTEXTA, rcl, 20) + TEST_FIELD_SIZE (POLYTEXTA, pdx, 4) + TEST_FIELD_ALIGN (POLYTEXTA, pdx, 4) + TEST_FIELD_OFFSET(POLYTEXTA, pdx, 36) } static void test_pack_POLYTEXTW(void) { /* POLYTEXTW (pack 4) */ - TEST_TYPE(POLYTEXTW, 40, 4); - TEST_FIELD(POLYTEXTW, INT, x, 0, 4, 4); - TEST_FIELD(POLYTEXTW, INT, y, 4, 4, 4); - TEST_FIELD(POLYTEXTW, UINT, n, 8, 4, 4); - TEST_FIELD(POLYTEXTW, LPCWSTR, lpstr, 12, 4, 4); - TEST_FIELD(POLYTEXTW, UINT, uiFlags, 16, 4, 4); - TEST_FIELD(POLYTEXTW, RECT, rcl, 20, 16, 4); - TEST_FIELD(POLYTEXTW, INT *, pdx, 36, 4, 4); + TEST_TYPE_SIZE (POLYTEXTW, 40) + TEST_TYPE_ALIGN (POLYTEXTW, 4) + TEST_FIELD_SIZE (POLYTEXTW, x, 4) + TEST_FIELD_ALIGN (POLYTEXTW, x, 4) + TEST_FIELD_OFFSET(POLYTEXTW, x, 0) + TEST_FIELD_SIZE (POLYTEXTW, y, 4) + TEST_FIELD_ALIGN (POLYTEXTW, y, 4) + TEST_FIELD_OFFSET(POLYTEXTW, y, 4) + TEST_FIELD_SIZE (POLYTEXTW, n, 4) + TEST_FIELD_ALIGN (POLYTEXTW, n, 4) + TEST_FIELD_OFFSET(POLYTEXTW, n, 8) + TEST_FIELD_SIZE (POLYTEXTW, lpstr, 4) + TEST_FIELD_ALIGN (POLYTEXTW, lpstr, 4) + TEST_FIELD_OFFSET(POLYTEXTW, lpstr, 12) + TEST_FIELD_SIZE (POLYTEXTW, uiFlags, 4) + TEST_FIELD_ALIGN (POLYTEXTW, uiFlags, 4) + TEST_FIELD_OFFSET(POLYTEXTW, uiFlags, 16) + TEST_FIELD_SIZE (POLYTEXTW, rcl, 16) + TEST_FIELD_ALIGN (POLYTEXTW, rcl, 4) + TEST_FIELD_OFFSET(POLYTEXTW, rcl, 20) + TEST_FIELD_SIZE (POLYTEXTW, pdx, 4) + TEST_FIELD_ALIGN (POLYTEXTW, pdx, 4) + TEST_FIELD_OFFSET(POLYTEXTW, pdx, 36) } static void test_pack_POUTLINETEXTMETRICA(void) { /* POUTLINETEXTMETRICA */ - TEST_TYPE(POUTLINETEXTMETRICA, 4, 4); - TEST_TYPE_POINTER(POUTLINETEXTMETRICA, 212, 4); + TEST_TYPE_SIZE (POUTLINETEXTMETRICA, 4) + TEST_TYPE_ALIGN (POUTLINETEXTMETRICA, 4) + TEST_TARGET_SIZE (POUTLINETEXTMETRICA, 212) + TEST_TARGET_ALIGN(POUTLINETEXTMETRICA, 4) } static void test_pack_POUTLINETEXTMETRICW(void) { /* POUTLINETEXTMETRICW */ - TEST_TYPE(POUTLINETEXTMETRICW, 4, 4); - TEST_TYPE_POINTER(POUTLINETEXTMETRICW, 216, 4); + TEST_TYPE_SIZE (POUTLINETEXTMETRICW, 4) + TEST_TYPE_ALIGN (POUTLINETEXTMETRICW, 4) + TEST_TARGET_SIZE (POUTLINETEXTMETRICW, 216) + TEST_TARGET_ALIGN(POUTLINETEXTMETRICW, 4) } static void test_pack_PPELARRAY(void) { /* PPELARRAY */ - TEST_TYPE(PPELARRAY, 4, 4); - TEST_TYPE_POINTER(PPELARRAY, 20, 4); + TEST_TYPE_SIZE (PPELARRAY, 4) + TEST_TYPE_ALIGN (PPELARRAY, 4) + TEST_TARGET_SIZE (PPELARRAY, 20) + TEST_TARGET_ALIGN(PPELARRAY, 4) } static void test_pack_PPIXELFORMATDESCRIPTOR(void) { /* PPIXELFORMATDESCRIPTOR */ - TEST_TYPE(PPIXELFORMATDESCRIPTOR, 4, 4); - TEST_TYPE_POINTER(PPIXELFORMATDESCRIPTOR, 40, 4); + TEST_TYPE_SIZE (PPIXELFORMATDESCRIPTOR, 4) + TEST_TYPE_ALIGN (PPIXELFORMATDESCRIPTOR, 4) + TEST_TARGET_SIZE (PPIXELFORMATDESCRIPTOR, 40) + TEST_TARGET_ALIGN(PPIXELFORMATDESCRIPTOR, 4) } static void test_pack_PPOINTFLOAT(void) { /* PPOINTFLOAT */ - TEST_TYPE(PPOINTFLOAT, 4, 4); - TEST_TYPE_POINTER(PPOINTFLOAT, 8, 4); + TEST_TYPE_SIZE (PPOINTFLOAT, 4) + TEST_TYPE_ALIGN (PPOINTFLOAT, 4) + TEST_TARGET_SIZE (PPOINTFLOAT, 8) + TEST_TARGET_ALIGN(PPOINTFLOAT, 4) } static void test_pack_PPOLYTEXTA(void) { /* PPOLYTEXTA */ - TEST_TYPE(PPOLYTEXTA, 4, 4); - TEST_TYPE_POINTER(PPOLYTEXTA, 40, 4); + TEST_TYPE_SIZE (PPOLYTEXTA, 4) + TEST_TYPE_ALIGN (PPOLYTEXTA, 4) + TEST_TARGET_SIZE (PPOLYTEXTA, 40) + TEST_TARGET_ALIGN(PPOLYTEXTA, 4) } static void test_pack_PPOLYTEXTW(void) { /* PPOLYTEXTW */ - TEST_TYPE(PPOLYTEXTW, 4, 4); - TEST_TYPE_POINTER(PPOLYTEXTW, 40, 4); + TEST_TYPE_SIZE (PPOLYTEXTW, 4) + TEST_TYPE_ALIGN (PPOLYTEXTW, 4) + TEST_TARGET_SIZE (PPOLYTEXTW, 40) + TEST_TARGET_ALIGN(PPOLYTEXTW, 4) } static void test_pack_PRGNDATA(void) { /* PRGNDATA */ - TEST_TYPE(PRGNDATA, 4, 4); - TEST_TYPE_POINTER(PRGNDATA, 36, 4); + TEST_TYPE_SIZE (PRGNDATA, 4) + TEST_TYPE_ALIGN (PRGNDATA, 4) + TEST_TARGET_SIZE (PRGNDATA, 36) + TEST_TARGET_ALIGN(PRGNDATA, 4) } static void test_pack_PRGNDATAHEADER(void) { /* PRGNDATAHEADER */ - TEST_TYPE(PRGNDATAHEADER, 4, 4); - TEST_TYPE_POINTER(PRGNDATAHEADER, 32, 4); + TEST_TYPE_SIZE (PRGNDATAHEADER, 4) + TEST_TYPE_ALIGN (PRGNDATAHEADER, 4) + TEST_TARGET_SIZE (PRGNDATAHEADER, 32) + TEST_TARGET_ALIGN(PRGNDATAHEADER, 4) } static void test_pack_PTEXTMETRICA(void) { /* PTEXTMETRICA */ - TEST_TYPE(PTEXTMETRICA, 4, 4); - TEST_TYPE_POINTER(PTEXTMETRICA, 56, 4); + TEST_TYPE_SIZE (PTEXTMETRICA, 4) + TEST_TYPE_ALIGN (PTEXTMETRICA, 4) + TEST_TARGET_SIZE (PTEXTMETRICA, 56) + TEST_TARGET_ALIGN(PTEXTMETRICA, 4) } static void test_pack_PTEXTMETRICW(void) { /* PTEXTMETRICW */ - TEST_TYPE(PTEXTMETRICW, 4, 4); - TEST_TYPE_POINTER(PTEXTMETRICW, 60, 4); + TEST_TYPE_SIZE (PTEXTMETRICW, 4) + TEST_TYPE_ALIGN (PTEXTMETRICW, 4) + TEST_TARGET_SIZE (PTEXTMETRICW, 60) + TEST_TARGET_ALIGN(PTEXTMETRICW, 4) } static void test_pack_PTRIVERTEX(void) { /* PTRIVERTEX */ - TEST_TYPE(PTRIVERTEX, 4, 4); - TEST_TYPE_POINTER(PTRIVERTEX, 16, 4); + TEST_TYPE_SIZE (PTRIVERTEX, 4) + TEST_TYPE_ALIGN (PTRIVERTEX, 4) + TEST_TARGET_SIZE (PTRIVERTEX, 16) + TEST_TARGET_ALIGN(PTRIVERTEX, 4) } static void test_pack_PXFORM(void) { /* PXFORM */ - TEST_TYPE(PXFORM, 4, 4); - TEST_TYPE_POINTER(PXFORM, 24, 4); + TEST_TYPE_SIZE (PXFORM, 4) + TEST_TYPE_ALIGN (PXFORM, 4) + TEST_TARGET_SIZE (PXFORM, 24) + TEST_TARGET_ALIGN(PXFORM, 4) } static void test_pack_RASTERIZER_STATUS(void) { /* RASTERIZER_STATUS (pack 4) */ - TEST_TYPE(RASTERIZER_STATUS, 6, 2); - TEST_FIELD(RASTERIZER_STATUS, SHORT, nSize, 0, 2, 2); - TEST_FIELD(RASTERIZER_STATUS, SHORT, wFlags, 2, 2, 2); - TEST_FIELD(RASTERIZER_STATUS, SHORT, nLanguageID, 4, 2, 2); + TEST_TYPE_SIZE (RASTERIZER_STATUS, 6) + TEST_TYPE_ALIGN (RASTERIZER_STATUS, 2) + TEST_FIELD_SIZE (RASTERIZER_STATUS, nSize, 2) + TEST_FIELD_ALIGN (RASTERIZER_STATUS, nSize, 2) + TEST_FIELD_OFFSET(RASTERIZER_STATUS, nSize, 0) + TEST_FIELD_SIZE (RASTERIZER_STATUS, wFlags, 2) + TEST_FIELD_ALIGN (RASTERIZER_STATUS, wFlags, 2) + TEST_FIELD_OFFSET(RASTERIZER_STATUS, wFlags, 2) + TEST_FIELD_SIZE (RASTERIZER_STATUS, nLanguageID, 2) + TEST_FIELD_ALIGN (RASTERIZER_STATUS, nLanguageID, 2) + TEST_FIELD_OFFSET(RASTERIZER_STATUS, nLanguageID, 4) } static void test_pack_RGBQUAD(void) { /* RGBQUAD (pack 4) */ - TEST_TYPE(RGBQUAD, 4, 1); - TEST_FIELD(RGBQUAD, BYTE, rgbBlue, 0, 1, 1); - TEST_FIELD(RGBQUAD, BYTE, rgbGreen, 1, 1, 1); - TEST_FIELD(RGBQUAD, BYTE, rgbRed, 2, 1, 1); - TEST_FIELD(RGBQUAD, BYTE, rgbReserved, 3, 1, 1); + TEST_TYPE_SIZE (RGBQUAD, 4) + TEST_TYPE_ALIGN (RGBQUAD, 1) + TEST_FIELD_SIZE (RGBQUAD, rgbBlue, 1) + TEST_FIELD_ALIGN (RGBQUAD, rgbBlue, 1) + TEST_FIELD_OFFSET(RGBQUAD, rgbBlue, 0) + TEST_FIELD_SIZE (RGBQUAD, rgbGreen, 1) + TEST_FIELD_ALIGN (RGBQUAD, rgbGreen, 1) + TEST_FIELD_OFFSET(RGBQUAD, rgbGreen, 1) + TEST_FIELD_SIZE (RGBQUAD, rgbRed, 1) + TEST_FIELD_ALIGN (RGBQUAD, rgbRed, 1) + TEST_FIELD_OFFSET(RGBQUAD, rgbRed, 2) + TEST_FIELD_SIZE (RGBQUAD, rgbReserved, 1) + TEST_FIELD_ALIGN (RGBQUAD, rgbReserved, 1) + TEST_FIELD_OFFSET(RGBQUAD, rgbReserved, 3) } static void test_pack_RGBTRIPLE(void) { /* RGBTRIPLE (pack 4) */ - TEST_TYPE(RGBTRIPLE, 3, 1); - TEST_FIELD(RGBTRIPLE, BYTE, rgbtBlue, 0, 1, 1); - TEST_FIELD(RGBTRIPLE, BYTE, rgbtGreen, 1, 1, 1); - TEST_FIELD(RGBTRIPLE, BYTE, rgbtRed, 2, 1, 1); + TEST_TYPE_SIZE (RGBTRIPLE, 3) + TEST_TYPE_ALIGN (RGBTRIPLE, 1) + TEST_FIELD_SIZE (RGBTRIPLE, rgbtBlue, 1) + TEST_FIELD_ALIGN (RGBTRIPLE, rgbtBlue, 1) + TEST_FIELD_OFFSET(RGBTRIPLE, rgbtBlue, 0) + TEST_FIELD_SIZE (RGBTRIPLE, rgbtGreen, 1) + TEST_FIELD_ALIGN (RGBTRIPLE, rgbtGreen, 1) + TEST_FIELD_OFFSET(RGBTRIPLE, rgbtGreen, 1) + TEST_FIELD_SIZE (RGBTRIPLE, rgbtRed, 1) + TEST_FIELD_ALIGN (RGBTRIPLE, rgbtRed, 1) + TEST_FIELD_OFFSET(RGBTRIPLE, rgbtRed, 2) } static void test_pack_RGNDATA(void) { /* RGNDATA (pack 4) */ - TEST_TYPE(RGNDATA, 36, 4); - TEST_FIELD(RGNDATA, RGNDATAHEADER, rdh, 0, 32, 4); - TEST_FIELD(RGNDATA, char[1], Buffer, 32, 1, 1); + TEST_TYPE_SIZE (RGNDATA, 36) + TEST_TYPE_ALIGN (RGNDATA, 4) + TEST_FIELD_SIZE (RGNDATA, rdh, 32) + TEST_FIELD_ALIGN (RGNDATA, rdh, 4) + TEST_FIELD_OFFSET(RGNDATA, rdh, 0) + TEST_FIELD_SIZE (RGNDATA, Buffer, 1) + TEST_FIELD_ALIGN (RGNDATA, Buffer, 1) + TEST_FIELD_OFFSET(RGNDATA, Buffer, 32) } static void test_pack_RGNDATAHEADER(void) { /* RGNDATAHEADER (pack 4) */ - TEST_TYPE(RGNDATAHEADER, 32, 4); - TEST_FIELD(RGNDATAHEADER, DWORD, dwSize, 0, 4, 4); - TEST_FIELD(RGNDATAHEADER, DWORD, iType, 4, 4, 4); - TEST_FIELD(RGNDATAHEADER, DWORD, nCount, 8, 4, 4); - TEST_FIELD(RGNDATAHEADER, DWORD, nRgnSize, 12, 4, 4); - TEST_FIELD(RGNDATAHEADER, RECT, rcBound, 16, 16, 4); + TEST_TYPE_SIZE (RGNDATAHEADER, 32) + TEST_TYPE_ALIGN (RGNDATAHEADER, 4) + TEST_FIELD_SIZE (RGNDATAHEADER, dwSize, 4) + TEST_FIELD_ALIGN (RGNDATAHEADER, dwSize, 4) + TEST_FIELD_OFFSET(RGNDATAHEADER, dwSize, 0) + TEST_FIELD_SIZE (RGNDATAHEADER, iType, 4) + TEST_FIELD_ALIGN (RGNDATAHEADER, iType, 4) + TEST_FIELD_OFFSET(RGNDATAHEADER, iType, 4) + TEST_FIELD_SIZE (RGNDATAHEADER, nCount, 4) + TEST_FIELD_ALIGN (RGNDATAHEADER, nCount, 4) + TEST_FIELD_OFFSET(RGNDATAHEADER, nCount, 8) + TEST_FIELD_SIZE (RGNDATAHEADER, nRgnSize, 4) + TEST_FIELD_ALIGN (RGNDATAHEADER, nRgnSize, 4) + TEST_FIELD_OFFSET(RGNDATAHEADER, nRgnSize, 12) + TEST_FIELD_SIZE (RGNDATAHEADER, rcBound, 16) + TEST_FIELD_ALIGN (RGNDATAHEADER, rcBound, 4) + TEST_FIELD_OFFSET(RGNDATAHEADER, rcBound, 16) } static void test_pack_TEXTMETRICA(void) { /* TEXTMETRICA (pack 4) */ - TEST_TYPE(TEXTMETRICA, 56, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmHeight, 0, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmAscent, 4, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmDescent, 8, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmInternalLeading, 12, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmExternalLeading, 16, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmAveCharWidth, 20, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmMaxCharWidth, 24, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmWeight, 28, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmOverhang, 32, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmDigitizedAspectX, 36, 4, 4); - TEST_FIELD(TEXTMETRICA, LONG, tmDigitizedAspectY, 40, 4, 4); - TEST_FIELD(TEXTMETRICA, BYTE, tmFirstChar, 44, 1, 1); - TEST_FIELD(TEXTMETRICA, BYTE, tmLastChar, 45, 1, 1); - TEST_FIELD(TEXTMETRICA, BYTE, tmDefaultChar, 46, 1, 1); - TEST_FIELD(TEXTMETRICA, BYTE, tmBreakChar, 47, 1, 1); - TEST_FIELD(TEXTMETRICA, BYTE, tmItalic, 48, 1, 1); - TEST_FIELD(TEXTMETRICA, BYTE, tmUnderlined, 49, 1, 1); - TEST_FIELD(TEXTMETRICA, BYTE, tmStruckOut, 50, 1, 1); - TEST_FIELD(TEXTMETRICA, BYTE, tmPitchAndFamily, 51, 1, 1); - TEST_FIELD(TEXTMETRICA, BYTE, tmCharSet, 52, 1, 1); + TEST_TYPE_SIZE (TEXTMETRICA, 56) + TEST_TYPE_ALIGN (TEXTMETRICA, 4) + TEST_FIELD_SIZE (TEXTMETRICA, tmHeight, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmHeight, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmHeight, 0) + TEST_FIELD_SIZE (TEXTMETRICA, tmAscent, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmAscent, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmAscent, 4) + TEST_FIELD_SIZE (TEXTMETRICA, tmDescent, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmDescent, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmDescent, 8) + TEST_FIELD_SIZE (TEXTMETRICA, tmInternalLeading, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmInternalLeading, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmInternalLeading, 12) + TEST_FIELD_SIZE (TEXTMETRICA, tmExternalLeading, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmExternalLeading, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmExternalLeading, 16) + TEST_FIELD_SIZE (TEXTMETRICA, tmAveCharWidth, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmAveCharWidth, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmAveCharWidth, 20) + TEST_FIELD_SIZE (TEXTMETRICA, tmMaxCharWidth, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmMaxCharWidth, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmMaxCharWidth, 24) + TEST_FIELD_SIZE (TEXTMETRICA, tmWeight, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmWeight, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmWeight, 28) + TEST_FIELD_SIZE (TEXTMETRICA, tmOverhang, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmOverhang, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmOverhang, 32) + TEST_FIELD_SIZE (TEXTMETRICA, tmDigitizedAspectX, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmDigitizedAspectX, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmDigitizedAspectX, 36) + TEST_FIELD_SIZE (TEXTMETRICA, tmDigitizedAspectY, 4) + TEST_FIELD_ALIGN (TEXTMETRICA, tmDigitizedAspectY, 4) + TEST_FIELD_OFFSET(TEXTMETRICA, tmDigitizedAspectY, 40) + TEST_FIELD_SIZE (TEXTMETRICA, tmFirstChar, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmFirstChar, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmFirstChar, 44) + TEST_FIELD_SIZE (TEXTMETRICA, tmLastChar, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmLastChar, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmLastChar, 45) + TEST_FIELD_SIZE (TEXTMETRICA, tmDefaultChar, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmDefaultChar, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmDefaultChar, 46) + TEST_FIELD_SIZE (TEXTMETRICA, tmBreakChar, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmBreakChar, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmBreakChar, 47) + TEST_FIELD_SIZE (TEXTMETRICA, tmItalic, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmItalic, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmItalic, 48) + TEST_FIELD_SIZE (TEXTMETRICA, tmUnderlined, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmUnderlined, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmUnderlined, 49) + TEST_FIELD_SIZE (TEXTMETRICA, tmStruckOut, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmStruckOut, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmStruckOut, 50) + TEST_FIELD_SIZE (TEXTMETRICA, tmPitchAndFamily, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmPitchAndFamily, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmPitchAndFamily, 51) + TEST_FIELD_SIZE (TEXTMETRICA, tmCharSet, 1) + TEST_FIELD_ALIGN (TEXTMETRICA, tmCharSet, 1) + TEST_FIELD_OFFSET(TEXTMETRICA, tmCharSet, 52) } static void test_pack_TEXTMETRICW(void) { /* TEXTMETRICW (pack 4) */ - TEST_TYPE(TEXTMETRICW, 60, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmHeight, 0, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmAscent, 4, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmDescent, 8, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmInternalLeading, 12, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmExternalLeading, 16, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmAveCharWidth, 20, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmMaxCharWidth, 24, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmWeight, 28, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmOverhang, 32, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmDigitizedAspectX, 36, 4, 4); - TEST_FIELD(TEXTMETRICW, LONG, tmDigitizedAspectY, 40, 4, 4); - TEST_FIELD(TEXTMETRICW, WCHAR, tmFirstChar, 44, 2, 2); - TEST_FIELD(TEXTMETRICW, WCHAR, tmLastChar, 46, 2, 2); - TEST_FIELD(TEXTMETRICW, WCHAR, tmDefaultChar, 48, 2, 2); - TEST_FIELD(TEXTMETRICW, WCHAR, tmBreakChar, 50, 2, 2); - TEST_FIELD(TEXTMETRICW, BYTE, tmItalic, 52, 1, 1); - TEST_FIELD(TEXTMETRICW, BYTE, tmUnderlined, 53, 1, 1); - TEST_FIELD(TEXTMETRICW, BYTE, tmStruckOut, 54, 1, 1); - TEST_FIELD(TEXTMETRICW, BYTE, tmPitchAndFamily, 55, 1, 1); - TEST_FIELD(TEXTMETRICW, BYTE, tmCharSet, 56, 1, 1); + TEST_TYPE_SIZE (TEXTMETRICW, 60) + TEST_TYPE_ALIGN (TEXTMETRICW, 4) + TEST_FIELD_SIZE (TEXTMETRICW, tmHeight, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmHeight, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmHeight, 0) + TEST_FIELD_SIZE (TEXTMETRICW, tmAscent, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmAscent, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmAscent, 4) + TEST_FIELD_SIZE (TEXTMETRICW, tmDescent, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmDescent, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmDescent, 8) + TEST_FIELD_SIZE (TEXTMETRICW, tmInternalLeading, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmInternalLeading, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmInternalLeading, 12) + TEST_FIELD_SIZE (TEXTMETRICW, tmExternalLeading, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmExternalLeading, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmExternalLeading, 16) + TEST_FIELD_SIZE (TEXTMETRICW, tmAveCharWidth, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmAveCharWidth, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmAveCharWidth, 20) + TEST_FIELD_SIZE (TEXTMETRICW, tmMaxCharWidth, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmMaxCharWidth, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmMaxCharWidth, 24) + TEST_FIELD_SIZE (TEXTMETRICW, tmWeight, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmWeight, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmWeight, 28) + TEST_FIELD_SIZE (TEXTMETRICW, tmOverhang, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmOverhang, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmOverhang, 32) + TEST_FIELD_SIZE (TEXTMETRICW, tmDigitizedAspectX, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmDigitizedAspectX, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmDigitizedAspectX, 36) + TEST_FIELD_SIZE (TEXTMETRICW, tmDigitizedAspectY, 4) + TEST_FIELD_ALIGN (TEXTMETRICW, tmDigitizedAspectY, 4) + TEST_FIELD_OFFSET(TEXTMETRICW, tmDigitizedAspectY, 40) + TEST_FIELD_SIZE (TEXTMETRICW, tmFirstChar, 2) + TEST_FIELD_ALIGN (TEXTMETRICW, tmFirstChar, 2) + TEST_FIELD_OFFSET(TEXTMETRICW, tmFirstChar, 44) + TEST_FIELD_SIZE (TEXTMETRICW, tmLastChar, 2) + TEST_FIELD_ALIGN (TEXTMETRICW, tmLastChar, 2) + TEST_FIELD_OFFSET(TEXTMETRICW, tmLastChar, 46) + TEST_FIELD_SIZE (TEXTMETRICW, tmDefaultChar, 2) + TEST_FIELD_ALIGN (TEXTMETRICW, tmDefaultChar, 2) + TEST_FIELD_OFFSET(TEXTMETRICW, tmDefaultChar, 48) + TEST_FIELD_SIZE (TEXTMETRICW, tmBreakChar, 2) + TEST_FIELD_ALIGN (TEXTMETRICW, tmBreakChar, 2) + TEST_FIELD_OFFSET(TEXTMETRICW, tmBreakChar, 50) + TEST_FIELD_SIZE (TEXTMETRICW, tmItalic, 1) + TEST_FIELD_ALIGN (TEXTMETRICW, tmItalic, 1) + TEST_FIELD_OFFSET(TEXTMETRICW, tmItalic, 52) + TEST_FIELD_SIZE (TEXTMETRICW, tmUnderlined, 1) + TEST_FIELD_ALIGN (TEXTMETRICW, tmUnderlined, 1) + TEST_FIELD_OFFSET(TEXTMETRICW, tmUnderlined, 53) + TEST_FIELD_SIZE (TEXTMETRICW, tmStruckOut, 1) + TEST_FIELD_ALIGN (TEXTMETRICW, tmStruckOut, 1) + TEST_FIELD_OFFSET(TEXTMETRICW, tmStruckOut, 54) + TEST_FIELD_SIZE (TEXTMETRICW, tmPitchAndFamily, 1) + TEST_FIELD_ALIGN (TEXTMETRICW, tmPitchAndFamily, 1) + TEST_FIELD_OFFSET(TEXTMETRICW, tmPitchAndFamily, 55) + TEST_FIELD_SIZE (TEXTMETRICW, tmCharSet, 1) + TEST_FIELD_ALIGN (TEXTMETRICW, tmCharSet, 1) + TEST_FIELD_OFFSET(TEXTMETRICW, tmCharSet, 56) } static void test_pack_TRIVERTEX(void) { /* TRIVERTEX (pack 4) */ - TEST_TYPE(TRIVERTEX, 16, 4); - TEST_FIELD(TRIVERTEX, LONG, x, 0, 4, 4); - TEST_FIELD(TRIVERTEX, LONG, y, 4, 4, 4); - TEST_FIELD(TRIVERTEX, COLOR16, Red, 8, 2, 2); - TEST_FIELD(TRIVERTEX, COLOR16, Green, 10, 2, 2); - TEST_FIELD(TRIVERTEX, COLOR16, Blue, 12, 2, 2); - TEST_FIELD(TRIVERTEX, COLOR16, Alpha, 14, 2, 2); + TEST_TYPE_SIZE (TRIVERTEX, 16) + TEST_TYPE_ALIGN (TRIVERTEX, 4) + TEST_FIELD_SIZE (TRIVERTEX, x, 4) + TEST_FIELD_ALIGN (TRIVERTEX, x, 4) + TEST_FIELD_OFFSET(TRIVERTEX, x, 0) + TEST_FIELD_SIZE (TRIVERTEX, y, 4) + TEST_FIELD_ALIGN (TRIVERTEX, y, 4) + TEST_FIELD_OFFSET(TRIVERTEX, y, 4) + TEST_FIELD_SIZE (TRIVERTEX, Red, 2) + TEST_FIELD_ALIGN (TRIVERTEX, Red, 2) + TEST_FIELD_OFFSET(TRIVERTEX, Red, 8) + TEST_FIELD_SIZE (TRIVERTEX, Green, 2) + TEST_FIELD_ALIGN (TRIVERTEX, Green, 2) + TEST_FIELD_OFFSET(TRIVERTEX, Green, 10) + TEST_FIELD_SIZE (TRIVERTEX, Blue, 2) + TEST_FIELD_ALIGN (TRIVERTEX, Blue, 2) + TEST_FIELD_OFFSET(TRIVERTEX, Blue, 12) + TEST_FIELD_SIZE (TRIVERTEX, Alpha, 2) + TEST_FIELD_ALIGN (TRIVERTEX, Alpha, 2) + TEST_FIELD_OFFSET(TRIVERTEX, Alpha, 14) } static void test_pack_TTPOLYCURVE(void) { /* TTPOLYCURVE (pack 4) */ - TEST_TYPE(TTPOLYCURVE, 12, 2); - TEST_FIELD(TTPOLYCURVE, WORD, wType, 0, 2, 2); - TEST_FIELD(TTPOLYCURVE, WORD, cpfx, 2, 2, 2); - TEST_FIELD(TTPOLYCURVE, POINTFX[1], apfx, 4, 8, 2); + TEST_TYPE_SIZE (TTPOLYCURVE, 12) + TEST_TYPE_ALIGN (TTPOLYCURVE, 2) + TEST_FIELD_SIZE (TTPOLYCURVE, wType, 2) + TEST_FIELD_ALIGN (TTPOLYCURVE, wType, 2) + TEST_FIELD_OFFSET(TTPOLYCURVE, wType, 0) + TEST_FIELD_SIZE (TTPOLYCURVE, cpfx, 2) + TEST_FIELD_ALIGN (TTPOLYCURVE, cpfx, 2) + TEST_FIELD_OFFSET(TTPOLYCURVE, cpfx, 2) + TEST_FIELD_SIZE (TTPOLYCURVE, apfx, 8) + TEST_FIELD_ALIGN (TTPOLYCURVE, apfx, 2) + TEST_FIELD_OFFSET(TTPOLYCURVE, apfx, 4) } static void test_pack_TTPOLYGONHEADER(void) { /* TTPOLYGONHEADER (pack 4) */ - TEST_TYPE(TTPOLYGONHEADER, 16, 4); - TEST_FIELD(TTPOLYGONHEADER, DWORD, cb, 0, 4, 4); - TEST_FIELD(TTPOLYGONHEADER, DWORD, dwType, 4, 4, 4); - TEST_FIELD(TTPOLYGONHEADER, POINTFX, pfxStart, 8, 8, 2); + TEST_TYPE_SIZE (TTPOLYGONHEADER, 16) + TEST_TYPE_ALIGN (TTPOLYGONHEADER, 4) + TEST_FIELD_SIZE (TTPOLYGONHEADER, cb, 4) + TEST_FIELD_ALIGN (TTPOLYGONHEADER, cb, 4) + TEST_FIELD_OFFSET(TTPOLYGONHEADER, cb, 0) + TEST_FIELD_SIZE (TTPOLYGONHEADER, dwType, 4) + TEST_FIELD_ALIGN (TTPOLYGONHEADER, dwType, 4) + TEST_FIELD_OFFSET(TTPOLYGONHEADER, dwType, 4) + TEST_FIELD_SIZE (TTPOLYGONHEADER, pfxStart, 8) + TEST_FIELD_ALIGN (TTPOLYGONHEADER, pfxStart, 2) + TEST_FIELD_OFFSET(TTPOLYGONHEADER, pfxStart, 8) } static void test_pack_XFORM(void) { /* XFORM (pack 4) */ - TEST_TYPE(XFORM, 24, 4); - TEST_FIELD(XFORM, FLOAT, eM11, 0, 4, 4); - TEST_FIELD(XFORM, FLOAT, eM12, 4, 4, 4); - TEST_FIELD(XFORM, FLOAT, eM21, 8, 4, 4); - TEST_FIELD(XFORM, FLOAT, eM22, 12, 4, 4); - TEST_FIELD(XFORM, FLOAT, eDx, 16, 4, 4); - TEST_FIELD(XFORM, FLOAT, eDy, 20, 4, 4); + TEST_TYPE_SIZE (XFORM, 24) + TEST_TYPE_ALIGN (XFORM, 4) + TEST_FIELD_SIZE (XFORM, eM11, 4) + TEST_FIELD_ALIGN (XFORM, eM11, 4) + TEST_FIELD_OFFSET(XFORM, eM11, 0) + TEST_FIELD_SIZE (XFORM, eM12, 4) + TEST_FIELD_ALIGN (XFORM, eM12, 4) + TEST_FIELD_OFFSET(XFORM, eM12, 4) + TEST_FIELD_SIZE (XFORM, eM21, 4) + TEST_FIELD_ALIGN (XFORM, eM21, 4) + TEST_FIELD_OFFSET(XFORM, eM21, 8) + TEST_FIELD_SIZE (XFORM, eM22, 4) + TEST_FIELD_ALIGN (XFORM, eM22, 4) + TEST_FIELD_OFFSET(XFORM, eM22, 12) + TEST_FIELD_SIZE (XFORM, eDx, 4) + TEST_FIELD_ALIGN (XFORM, eDx, 4) + TEST_FIELD_OFFSET(XFORM, eDx, 16) + TEST_FIELD_SIZE (XFORM, eDy, 4) + TEST_FIELD_ALIGN (XFORM, eDy, 4) + TEST_FIELD_OFFSET(XFORM, eDy, 20) } static void test_pack(void) @@ -4366,5 +7049,9 @@ static void test_pack(void) START_TEST(generated) { +#ifdef _WIN64 + ok(0, "The type size / alignment tests don't support Win64 yet\n"); +#else test_pack(); +#endif } diff --git a/rostests/winetests/gdi32/icm.c b/rostests/winetests/gdi32/icm.c index 9d89828ffc7..06812aa055b 100644 --- a/rostests/winetests/gdi32/icm.c +++ b/rostests/winetests/gdi32/icm.c @@ -39,7 +39,7 @@ static void test_GetICMProfileA( HDC dc ) ret = GetICMProfileA( NULL, NULL, NULL ); if ( !ret && ( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED ) ) { - skip( "GetICMProfileA is not implemented\n" ); + win_skip( "GetICMProfileA is not implemented\n" ); return; } ok( !ret, "GetICMProfileA succeeded\n" ); @@ -51,20 +51,28 @@ static void test_GetICMProfileA( HDC dc ) ret = GetICMProfileA( dc, &size, NULL ); ok( !ret, "GetICMProfileA succeeded\n" ); - ret = GetICMProfileA( dc, NULL, filename ); - ok( !ret, "GetICMProfileA succeeded\n" ); - size = MAX_PATH; ret = GetICMProfileA( NULL, &size, filename ); ok( !ret, "GetICMProfileA succeeded\n" ); size = 0; + filename[0] = 0; SetLastError(0xdeadbeef); ret = GetICMProfileA( dc, &size, filename ); error = GetLastError(); ok( !ret, "GetICMProfileA succeeded\n" ); ok( size, "expected size > 0\n" ); - ok( error == ERROR_INSUFFICIENT_BUFFER, "got %d, expected ERROR_INSUFFICIENT_BUFFER\n", error ); + ok( filename[0] == 0, "Expected filename to be empty\n" ); + ok( error == ERROR_INSUFFICIENT_BUFFER || + error == ERROR_SUCCESS, /* Win95 */ + "got %d, expected ERROR_INSUFFICIENT_BUFFER or ERROR_SUCCESS(Win95)\n", error ); + + /* Next test will crash on Win95 */ + if ( error == ERROR_INSUFFICIENT_BUFFER ) + { + ret = GetICMProfileA( dc, NULL, filename ); + ok( !ret, "GetICMProfileA succeeded\n" ); + } size = MAX_PATH; ret = GetICMProfileA( dc, &size, filename ); @@ -83,7 +91,7 @@ static void test_GetICMProfileW( HDC dc ) ret = GetICMProfileW( NULL, NULL, NULL ); if ( !ret && ( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED ) ) { - skip( "GetICMProfileW is not implemented\n" ); + win_skip( "GetICMProfileW is not implemented\n" ); return; } ok( !ret, "GetICMProfileW succeeded\n" ); @@ -122,6 +130,15 @@ static void test_GetICMProfileW( HDC dc ) static void test_SetICMMode( HDC dc ) { INT ret, knob, save; + BOOL impl; + + SetLastError( 0xdeadbeef ); + impl = GetICMProfileA( NULL, NULL, NULL ); + if ( !impl && ( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED ) ) + { + win_skip( "On NT4 where SetICMMode is not implemented but this is not advertised\n" ); + return; + } SetLastError( 0xdeadbeef ); ret = SetICMMode( NULL, 0 ); @@ -148,7 +165,7 @@ static void test_SetICMMode( HDC dc ) dc = CreateDCW( displayW, NULL, NULL, NULL ); if ( !dc && ( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED ) ) { - skip( "CreateDCW is not implemented\n" ); + win_skip( "CreateDCW is not implemented\n" ); return; } ok( dc != NULL, "CreateDCW failed (%d)\n", GetLastError() ); diff --git a/rostests/winetests/gdi32/mapping.c b/rostests/winetests/gdi32/mapping.c index 91e487a6468..8c53e2fea87 100644 --- a/rostests/winetests/gdi32/mapping.c +++ b/rostests/winetests/gdi32/mapping.c @@ -2,6 +2,7 @@ * Unit tests for mapping functions * * Copyright (c) 2005 Huw Davies + * Copyright (c) 2008 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +29,193 @@ #include "winuser.h" #include "winerror.h" +#define rough_match(got, expected) (abs((got) - (expected)) <= 5) + +#define expect_LPtoDP(_hdc, _x, _y) \ +{ \ + POINT _pt = { 1000, 1000 }; \ + LPtoDP(_hdc, &_pt, 1); \ + ok(rough_match(_pt.x, _x), "expected x %d, got %d\n", (_x), _pt.x); \ + ok(rough_match(_pt.y, _y), "expected y %d, got %d\n", (_y), _pt.y); \ +} + +#define expect_world_trasform(_hdc, _em11, _em22) \ +{ \ + BOOL _ret; \ + XFORM _xform; \ + SetLastError(0xdeadbeef); \ + _ret = GetWorldTransform(_hdc, &_xform); \ + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) \ + { \ + ok(_ret, "GetWorldTransform error %u\n", GetLastError()); \ + ok(_xform.eM11 == (_em11), "expected %f, got %f\n", (_em11), _xform.eM11); \ + ok(_xform.eM12 == 0.0, "expected 0.0, got %f\n", _xform.eM12); \ + ok(_xform.eM21 == 0.0, "expected 0.0, got %f\n", _xform.eM21); \ + ok(_xform.eM22 == (_em22), "expected %f, got %f\n", (_em22), _xform.eM22); \ + ok(_xform.eDx == 0.0, "expected 0.0, got %f\n", _xform.eDx); \ + ok(_xform.eDy == 0.0, "expected 0.0, got %f\n", _xform.eDy); \ + } \ +} + +#define expect_dc_ext(_func, _hdc, _cx, _cy) \ +{ \ + BOOL _ret; \ + SIZE _size; \ + SetLastError(0xdeadbeef); \ + _ret = _func(_hdc, &_size); \ + ok(_ret, #_func " error %u\n", GetLastError()); \ + ok(_size.cx == (_cx), "expected cx %d, got %d\n", (_cx), _size.cx); \ + ok(_size.cy == (_cy), "expected cy %d, got %d\n", (_cy), _size.cy); \ +} + +#define expect_viewport_ext(_hdc, _cx, _cy) expect_dc_ext(GetViewportExtEx, _hdc, _cx, _cy) +#define expect_window_ext(_hdc, _cx, _cy) expect_dc_ext(GetWindowExtEx, _hdc, _cx, _cy) + +static void test_world_transform(void) +{ + BOOL is_win9x; + HDC hdc; + INT ret, size_cx, size_cy, res_x, res_y, dpi_x, dpi_y; + XFORM xform; + SIZE size; + + SetLastError(0xdeadbeef); + GetWorldTransform(0, NULL); + is_win9x = GetLastError() == ERROR_CALL_NOT_IMPLEMENTED; + + hdc = CreateCompatibleDC(0); + + xform.eM11 = 1.0f; + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = 1.0f; + xform.eDx = 0.0f; + xform.eDy = 0.0f; + ret = SetWorldTransform(hdc, &xform); + ok(!ret, "SetWorldTransform should fail in GM_COMPATIBLE mode\n"); + + size_cx = GetDeviceCaps(hdc, HORZSIZE); + size_cy = GetDeviceCaps(hdc, VERTSIZE); + res_x = GetDeviceCaps(hdc, HORZRES); + res_y = GetDeviceCaps(hdc, VERTRES); + dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); + dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); + trace("dc size %d x %d, resolution %d x %d dpi %d x %d\n", + size_cx, size_cy, res_x, res_y, dpi_x, dpi_y ); + + expect_viewport_ext(hdc, 1, 1); + expect_window_ext(hdc, 1, 1); + expect_world_trasform(hdc, 1.0, 1.0); + expect_LPtoDP(hdc, 1000, 1000); + + SetLastError(0xdeadbeef); + ret = SetMapMode(hdc, MM_LOMETRIC); + ok(ret == MM_TEXT, "expected MM_TEXT, got %d\n", ret); + + if (is_win9x) + { + expect_viewport_ext(hdc, dpi_x, dpi_y); + expect_window_ext(hdc, 254, -254); + } + else + { + expect_viewport_ext(hdc, res_x, -res_y); + ok( GetWindowExtEx( hdc, &size ), "GetWindowExtEx failed\n" ); + ok( size.cx == size_cx * 10 || + size.cx == MulDiv( res_x, 254, dpi_x ), /* Vista uses a more precise method */ + "expected cx %d or %d, got %d\n", size_cx * 10, MulDiv( res_x, 254, dpi_x ), size.cx ); + ok( size.cy == size_cy * 10 || + size.cy == MulDiv( res_y, 254, dpi_y ), /* Vista uses a more precise method */ + "expected cy %d or %d, got %d\n", size_cy * 10, MulDiv( res_y, 254, dpi_y ), size.cy ); + } + expect_world_trasform(hdc, 1.0, 1.0); + expect_LPtoDP(hdc, MulDiv(1000 / 10, res_x, size_cx), -MulDiv(1000 / 10, res_y, size_cy)); + + SetLastError(0xdeadbeef); + ret = SetMapMode(hdc, MM_TEXT); + ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d\n", ret); + + expect_viewport_ext(hdc, 1, 1); + expect_window_ext(hdc, 1, 1); + expect_world_trasform(hdc, 1.0, 1.0); + expect_LPtoDP(hdc, 1000, 1000); + + ret = SetGraphicsMode(hdc, GM_ADVANCED); + if (!ret) + { + DeleteDC(hdc); + skip("GM_ADVANCED is not supported on this platform\n"); + return; + } + + expect_viewport_ext(hdc, 1, 1); + expect_window_ext(hdc, 1, 1); + expect_world_trasform(hdc, 1.0, 1.0); + expect_LPtoDP(hdc, 1000, 1000); + + /* The transform must conform to (eM11 * eM22 != eM12 * eM21) requirement */ + xform.eM11 = 1.0f; + xform.eM12 = 2.0f; + xform.eM21 = 1.0f; + xform.eM22 = 2.0f; + xform.eDx = 0.0f; + xform.eDy = 0.0f; + ret = SetWorldTransform(hdc, &xform); + ok(!ret || + broken(ret), /* NT4 */ + "SetWorldTransform should fail with an invalid xform\n"); + + xform.eM11 = 20.0f; + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = 20.0f; + xform.eDx = 0.0f; + xform.eDy = 0.0f; + SetLastError(0xdeadbeef); + ret = SetWorldTransform(hdc, &xform); + ok(ret, "SetWorldTransform error %u\n", GetLastError()); + + expect_viewport_ext(hdc, 1, 1); + expect_window_ext(hdc, 1, 1); + expect_world_trasform(hdc, 20.0, 20.0); + expect_LPtoDP(hdc, 20000, 20000); + + SetLastError(0xdeadbeef); + ret = SetMapMode(hdc, MM_LOMETRIC); + ok(ret == MM_TEXT, "expected MM_TEXT, got %d\n", ret); + + expect_viewport_ext(hdc, res_x, -res_y); + ok( GetWindowExtEx( hdc, &size ), "GetWindowExtEx failed\n" ); + ok( size.cx == size_cx * 10 || + size.cx == MulDiv( res_x, 254, dpi_x ), /* Vista uses a more precise method */ + "expected cx %d or %d, got %d\n", size_cx * 10, MulDiv( res_x, 254, dpi_x ), size.cx ); + ok( size.cy == size_cy * 10 || + size.cy == MulDiv( res_y, 254, dpi_y ), /* Vista uses a more precise method */ + "expected cy %d or %d, got %d\n", size_cy * 10, MulDiv( res_y, 254, dpi_y ), size.cy ); + expect_world_trasform(hdc, 20.0, 20.0); + expect_LPtoDP(hdc, MulDiv(20000, res_x, size.cx), -MulDiv(20000, res_y, size.cy)); + + SetLastError(0xdeadbeef); + ret = SetMapMode(hdc, MM_TEXT); + ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d\n", ret); + + expect_viewport_ext(hdc, 1, 1); + expect_window_ext(hdc, 1, 1); + expect_world_trasform(hdc, 20.0, 20.0); + expect_LPtoDP(hdc, 20000, 20000); + + ret = SetGraphicsMode(hdc, GM_COMPATIBLE); + ok(ret, "SetGraphicsMode(GM_COMPATIBLE) should not fail if DC has't an identity transform\n"); + ret = GetGraphicsMode(hdc); + ok(ret == GM_COMPATIBLE, "expected GM_COMPATIBLE, got %d\n", ret); + + expect_viewport_ext(hdc, 1, 1); + expect_window_ext(hdc, 1, 1); + expect_world_trasform(hdc, 20.0, 20.0); + expect_LPtoDP(hdc, 20000, 20000); + + DeleteDC(hdc); +} static void test_modify_world_transform(void) { @@ -38,6 +226,7 @@ static void test_modify_world_transform(void) if(!ret) /* running in win9x so quit */ { ReleaseDC(0, hdc); + skip("GM_ADVANCED is not supported on this platform\n"); return; } @@ -53,8 +242,6 @@ static void test_modify_world_transform(void) ReleaseDC(0, hdc); } -#define rough_match(got, expected) ((got >= expected - 2) && (got <= expected + 2)) - static void test_SetWindowExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy) { SIZE windowExt, viewportExt; @@ -155,8 +342,227 @@ static void test_isotropic_mapping(void) ReleaseDC(0, hdc); } +static void test_setvirtualresolution(void) +{ + HDC hdc = CreateICA("DISPLAY", NULL, NULL, NULL); + DWORD r; + DWORD (WINAPI *pSetVirtualResolution)(HDC, DWORD, DWORD, DWORD, DWORD); + INT horz_res = GetDeviceCaps(hdc, HORZRES); + INT horz_size = GetDeviceCaps(hdc, HORZSIZE); + INT log_pixels_x = GetDeviceCaps(hdc, LOGPIXELSX); + SIZE orig_lometric_vp, orig_lometric_wnd; + + pSetVirtualResolution = (void *)GetProcAddress(GetModuleHandleA("gdi32.dll"), "SetVirtualResolution"); + + if(!pSetVirtualResolution) + { + win_skip("Don't have SetVirtualResolution\n"); + return; + } + + /* Get the true resolution limits */ + SetMapMode(hdc, MM_LOMETRIC); + GetViewportExtEx(hdc, &orig_lometric_vp); + GetWindowExtEx(hdc, &orig_lometric_wnd); + SetMapMode(hdc, MM_TEXT); + + r = pSetVirtualResolution(hdc, 4000, 1000, 400, 200); /* 10 pix/mm x 5 pix/mm */ + ok(r == TRUE, "got %d\n", r); + expect_LPtoDP(hdc, 1000, 1000); + expect_viewport_ext(hdc, 1, 1); + expect_window_ext(hdc, 1, 1); + + SetMapMode(hdc, MM_LOMETRIC); + expect_LPtoDP(hdc, 1000, -500); + expect_viewport_ext(hdc, 4000, -1000); + expect_window_ext(hdc, 4000, 2000); + + /* Doesn't change the device caps */ + ok(horz_res == GetDeviceCaps(hdc, HORZRES), "horz_res changed\n"); + ok(horz_size == GetDeviceCaps(hdc, HORZSIZE), "horz_size changed\n"); + ok(log_pixels_x == GetDeviceCaps(hdc, LOGPIXELSX), "log_pixels_x changed\n"); + + r = pSetVirtualResolution(hdc, 8000, 1000, 400, 200); /* 20 pix/mm x 5 pix/mm */ + ok(r == TRUE, "got %d\n", r); + expect_LPtoDP(hdc, 1000, -500); /* No change, need to re-set the mapping mode */ + SetMapMode(hdc, MM_TEXT); + SetMapMode(hdc, MM_LOMETRIC); + expect_LPtoDP(hdc, 2000, -500); + expect_viewport_ext(hdc, 8000, -1000); + expect_window_ext(hdc, 4000, 2000); + + r = pSetVirtualResolution(hdc, 8000, 1000, 200, 200); /* 40 pix/mm x 5 pix/mm */ + ok(r == TRUE, "got %d\n", r); + SetMapMode(hdc, MM_TEXT); + SetMapMode(hdc, MM_LOMETRIC); + expect_LPtoDP(hdc, 4000, -500); + expect_viewport_ext(hdc, 8000, -1000); + expect_window_ext(hdc, 2000, 2000); + + r = pSetVirtualResolution(hdc, 8000, 1000, 200, 200); /* 40 pix/mm x 5 pix/mm */ + ok(r == TRUE, "got %d\n", r); + SetMapMode(hdc, MM_TEXT); + SetMapMode(hdc, MM_LOMETRIC); + expect_LPtoDP(hdc, 4000, -500); + expect_viewport_ext(hdc, 8000, -1000); + expect_window_ext(hdc, 2000, 2000); + + r = pSetVirtualResolution(hdc, 8000, 2000, 200, 200); /* 40 pix/mm x 10 pix/mm */ + ok(r == TRUE, "got %d\n", r); + SetMapMode(hdc, MM_TEXT); + SetMapMode(hdc, MM_LOMETRIC); + expect_LPtoDP(hdc, 4000, -1000); + expect_viewport_ext(hdc, 8000, -2000); + expect_window_ext(hdc, 2000, 2000); + + r = pSetVirtualResolution(hdc, 0, 0, 10, 0); /* Error */ + ok(r == FALSE, "got %d\n", r); + SetMapMode(hdc, MM_TEXT); + SetMapMode(hdc, MM_LOMETRIC); + expect_LPtoDP(hdc, 4000, -1000); + expect_viewport_ext(hdc, 8000, -2000); + expect_window_ext(hdc, 2000, 2000); + + r = pSetVirtualResolution(hdc, 0, 0, 0, 0); /* Reset to true resolution */ + ok(r == TRUE, "got %d\n", r); + SetMapMode(hdc, MM_TEXT); + SetMapMode(hdc, MM_LOMETRIC); + expect_viewport_ext(hdc, orig_lometric_vp.cx, orig_lometric_vp.cy); + expect_window_ext(hdc, orig_lometric_wnd.cx, orig_lometric_wnd.cy); + + DeleteDC(hdc); +} + + +static inline void expect_identity(int line, XFORM *xf) +{ + ok(xf->eM11 == 1.0, "%d: got %f\n", line, xf->eM11); + ok(xf->eM12 == 0.0, "%d: got %f\n", line, xf->eM12); + ok(xf->eM21 == 0.0, "%d: got %f\n", line, xf->eM21); + ok(xf->eM22 == 1.0, "%d: got %f\n", line, xf->eM22); + ok(xf->eDx == 0.0, "%d: got %f\n", line, xf->eDx); + ok(xf->eDy == 0.0, "%d: got %f\n", line, xf->eDy); +} + +static inline void xform_near_match(int line, XFORM *got, XFORM *expect) +{ + ok(fabs(got->eM11 - expect->eM11) < 0.001, "%d: got %f expect %f\n", line, got->eM11, expect->eM11); + ok(fabs(got->eM12 - expect->eM12) < 0.001, "%d: got %f expect %f\n", line, got->eM12, expect->eM12); + ok(fabs(got->eM21 - expect->eM21) < 0.001, "%d: got %f expect %f\n", line, got->eM21, expect->eM21); + ok(fabs(got->eM22 - expect->eM22) < 0.001, "%d: got %f expect %f\n", line, got->eM22, expect->eM22); + ok(fabs(got->eDx - expect->eDx) < 0.001, "%d: got %f expect %f\n", line, got->eDx, expect->eDx); + ok(fabs(got->eDy - expect->eDy) < 0.001, "%d: got %f expect %f\n", line, got->eDy, expect->eDy); +} + + +static void test_gettransform(void) +{ + HDC hdc = CreateICA("DISPLAY", NULL, NULL, NULL); + BOOL (WINAPI *pGetTransform)(HDC, DWORD, XFORM *); + XFORM xform, expect; + BOOL r; + SIZE lometric_vp, lometric_wnd; + + pGetTransform = (void *)GetProcAddress(GetModuleHandleA("gdi32.dll"), "GetTransform"); + + if(!pGetTransform) + { + win_skip("Don't have GetTransform\n"); + return; + } + + r = pGetTransform(hdc, 0x203, &xform); /* World -> Page */ + ok(r == TRUE, "got %d\n", r); + expect_identity(__LINE__, &xform); + r = pGetTransform(hdc, 0x304, &xform); /* Page -> Device */ + ok(r == TRUE, "got %d\n", r); + expect_identity(__LINE__, &xform); + r = pGetTransform(hdc, 0x204, &xform); /* World -> Device */ + ok(r == TRUE, "got %d\n", r); + expect_identity(__LINE__, &xform); + r = pGetTransform(hdc, 0x402, &xform); /* Device -> World */ + ok(r == TRUE, "got %d\n", r); + expect_identity(__LINE__, &xform); + + SetMapMode(hdc, MM_LOMETRIC); + GetViewportExtEx(hdc, &lometric_vp); + GetWindowExtEx(hdc, &lometric_wnd); + + r = pGetTransform(hdc, 0x203, &xform); /* World -> Page */ + ok(r == TRUE, "got %d\n", r); + expect_identity(__LINE__, &xform); + + r = pGetTransform(hdc, 0x304, &xform); /* Page -> Device */ + ok(r == TRUE, "got %d\n", r); + expect.eM11 = (FLOAT) lometric_vp.cx / lometric_wnd.cx; + expect.eM12 = expect.eM21 = 0.0; + expect.eM22 = (FLOAT) lometric_vp.cy / lometric_wnd.cy; + expect.eDx = expect.eDy = 0.0; + xform_near_match(__LINE__, &xform, &expect); + + r = pGetTransform(hdc, 0x204, &xform); /* World -> Device */ + ok(r == TRUE, "got %d\n", r); + xform_near_match(__LINE__, &xform, &expect); + + r = pGetTransform(hdc, 0x402, &xform); /* Device -> World */ + ok(r == TRUE, "got %d\n", r); + expect.eM11 = (FLOAT) lometric_wnd.cx / lometric_vp.cx; + expect.eM22 = (FLOAT) lometric_wnd.cy / lometric_vp.cy; + xform_near_match(__LINE__, &xform, &expect); + + + SetGraphicsMode(hdc, GM_ADVANCED); + + expect.eM11 = 10.0; + expect.eM22 = 20.0; + SetWorldTransform(hdc, &expect); + r = pGetTransform(hdc, 0x203, &xform); /* World -> Page */ + ok(r == TRUE, "got %d\n", r); + xform_near_match(__LINE__, &xform, &expect); + + r = pGetTransform(hdc, 0x304, &xform); /* Page -> Device */ + ok(r == TRUE, "got %d\n", r); + expect.eM11 = (FLOAT) lometric_vp.cx / lometric_wnd.cx; + expect.eM22 = (FLOAT) lometric_vp.cy / lometric_wnd.cy; + xform_near_match(__LINE__, &xform, &expect); + + r = pGetTransform(hdc, 0x204, &xform); /* World -> Device */ + ok(r == TRUE, "got %d\n", r); + expect.eM11 *= 10.0; + expect.eM22 *= 20.0; + xform_near_match(__LINE__, &xform, &expect); + + r = pGetTransform(hdc, 0x402, &xform); /* Device -> World */ + ok(r == TRUE, "got %d\n", r); + expect.eM11 = 1 / expect.eM11; + expect.eM22 = 1 / expect.eM22; + xform_near_match(__LINE__, &xform, &expect); + + r = pGetTransform(hdc, 0x102, &xform); + ok(r == FALSE, "got %d\n", r); + r = pGetTransform(hdc, 0x103, &xform); + ok(r == FALSE, "got %d\n", r); + r = pGetTransform(hdc, 0x104, &xform); + ok(r == FALSE, "got %d\n", r); + r = pGetTransform(hdc, 0x202, &xform); + ok(r == FALSE, "got %d\n", r); + r = pGetTransform(hdc, 0x302, &xform); + ok(r == FALSE, "got %d\n", r); + r = pGetTransform(hdc, 0x303, &xform); + ok(r == FALSE, "got %d\n", r); + r = pGetTransform(hdc, 0x403, &xform); + ok(r == FALSE, "got %d\n", r); + r = pGetTransform(hdc, 0x404, &xform); + ok(r == FALSE, "got %d\n", r); + r = pGetTransform(hdc, 0xffff, &xform); + ok(r == FALSE, "got %d\n", r); +} + START_TEST(mapping) { test_modify_world_transform(); + test_world_transform(); test_isotropic_mapping(); + test_setvirtualresolution(); + test_gettransform(); } diff --git a/rostests/winetests/gdi32/metafile.c b/rostests/winetests/gdi32/metafile.c index 78bbd8b1a25..d0eba53c744 100755 --- a/rostests/winetests/gdi32/metafile.c +++ b/rostests/winetests/gdi32/metafile.c @@ -121,8 +121,11 @@ static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, const EMREXTTEXTOUTW *emr_ExtTextOutW = (const EMREXTTEXTOUTW *)emr; dx = (const INT *)((const char *)emr + emr_ExtTextOutW->emrtext.offDx); + SetLastError(0xdeadbeef); ret = GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(device_lf), &device_lf); - ok( ret == sizeof(device_lf), "GetObjectA error %d\n", GetLastError()); + ok( ret == sizeof(device_lf) || + broken(ret == (sizeof(device_lf) - LF_FACESIZE + strlen(device_lf.lfFaceName) + 1)), /* NT4 */ + "GetObjectA error %d\n", GetLastError()); /* compare up to lfOutPrecision, other values are not interesting, * and in fact sometimes arbitrary adapted by Win9x. @@ -327,6 +330,7 @@ static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, SIZE size; static int save_state; static int restore_no; + static int select_no; trace("hdc %p, emr->iType %d, emr->nSize %d, param %p\n", hdc, emr->iType, emr->nSize, (void *)param); @@ -372,6 +376,7 @@ static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, save_state = 0; restore_no = 0; + select_no = 0; check_dc_state(hdc, restore_no, 0, 0, 1, 1, 0, 0, 1, 1); break; } @@ -435,8 +440,16 @@ static int CALLBACK savedc_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, save_state += restoredc->iRelative; break; } + case EMR_SELECTOBJECT: + { + const EMRSELECTOBJECT *selectobj = (const EMRSELECTOBJECT*)emr; + trace("EMR_SELECTOBJECT: %x\n",selectobj->ihObject); + select_no ++; + break; + } case EMR_EOF: ok(save_state == 0, "EOF save_state %d\n", save_state); + ok(select_no == 3, "Too many/few selects %i\n",select_no); break; } @@ -469,6 +482,9 @@ static void test_SaveDC(void) HENHMETAFILE hMetafile; HWND hwnd; int ret; + POINT pt; + SIZE size; + HFONT hFont,hFont2,hFontOld,hFontCheck; static const RECT rc = { 0, 0, 150, 150 }; /* Win9x doesn't play EMFs on invisible windows */ @@ -495,6 +511,190 @@ static void test_SaveDC(void) /* Force Win9x to update DC state */ SetPixelV(hdcMetafile, 50, 50, 0); + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx); + ret = SaveDC(hdcMetafile); + ok(ret == 1, "ret = %d\n", ret); + + SetWindowOrgEx(hdcMetafile, -1, -1, NULL); + SetViewportOrgEx(hdcMetafile, 10, 10, NULL); + SetWindowExtEx(hdcMetafile, 150, 150, NULL ); + SetViewportExtEx(hdcMetafile, 200, 200, NULL ); + + /* Force Win9x to update DC state */ + SetPixelV(hdcMetafile, 50, 50, 0); + + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 10,"Expecting ViewportOrg x of 10, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 200,"Expecting ViewportExt cx of 200, got %i\n",size.cx); + ret = SaveDC(hdcMetafile); + ok(ret == 2, "ret = %d\n", ret); + + SetWindowOrgEx(hdcMetafile, -2, -2, NULL); + SetViewportOrgEx(hdcMetafile, 20, 20, NULL); + SetWindowExtEx(hdcMetafile, 120, 120, NULL ); + SetViewportExtEx(hdcMetafile, 300, 300, NULL ); + SetPolyFillMode( hdcMetafile, ALTERNATE ); + SetBkColor( hdcMetafile, 0 ); + + /* Force Win9x to update DC state */ + SetPixelV(hdcMetafile, 50, 50, 0); + + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx); + ret = SaveDC(hdcMetafile); + ok(ret == 3, "ret = %d\n", ret); + + SetWindowOrgEx(hdcMetafile, -3, -3, NULL); + SetViewportOrgEx(hdcMetafile, 30, 30, NULL); + SetWindowExtEx(hdcMetafile, 200, 200, NULL ); + SetViewportExtEx(hdcMetafile, 400, 400, NULL ); + + SetPolyFillMode( hdcMetafile, WINDING ); + SetBkColor( hdcMetafile, 0x123456 ); + ok( GetPolyFillMode( hdcMetafile ) == WINDING, "PolyFillMode not restored\n" ); + ok( GetBkColor( hdcMetafile ) == 0x123456, "Background color not restored\n" ); + + /* Force Win9x to update DC state */ + SetPixelV(hdcMetafile, 50, 50, 0); + + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 30,"Expecting ViewportOrg x of 30, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 400,"Expecting ViewportExt cx of 400, got %i\n",size.cx); + ret = RestoreDC(hdcMetafile, -1); + ok(ret, "ret = %d\n", ret); + + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx); + ok( GetPolyFillMode( hdcMetafile ) == ALTERNATE, "PolyFillMode not restored\n" ); + ok( GetBkColor( hdcMetafile ) == 0, "Background color not restored\n" ); + ret = SaveDC(hdcMetafile); + ok(ret == 3, "ret = %d\n", ret); + + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 20,"Expecting ViewportOrg x of 20, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 300,"Expecting ViewportExt cx of 300, got %i\n",size.cx); + ret = RestoreDC(hdcMetafile, 1); + ok(ret, "ret = %d\n", ret); + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 0,"Expecting ViewportOrg x of 0, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 120,"Expecting ViewportExt cx of 120, got %i\n",size.cx); + + SetWindowOrgEx(hdcMetafile, -4, -4, NULL); + SetViewportOrgEx(hdcMetafile, 40, 40, NULL); + SetWindowExtEx(hdcMetafile, 500, 500, NULL ); + SetViewportExtEx(hdcMetafile, 50, 50, NULL ); + + /* Force Win9x to update DC state */ + SetPixelV(hdcMetafile, 50, 50, 0); + + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx); + ret = SaveDC(hdcMetafile); + ok(ret == 1, "ret = %d\n", ret); + + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx); + ret = SaveDC(hdcMetafile); + ok(ret == 2, "ret = %d\n", ret); + + memset(&orig_lf, 0, sizeof(orig_lf)); + orig_lf.lfCharSet = ANSI_CHARSET; + orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + orig_lf.lfWeight = FW_DONTCARE; + orig_lf.lfHeight = 7; + orig_lf.lfQuality = DEFAULT_QUALITY; + lstrcpyA(orig_lf.lfFaceName, "Arial"); + hFont = CreateFontIndirectA(&orig_lf); + ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError()); + + hFontOld = SelectObject(hdcMetafile, hFont); + + hFont2 = CreateFontIndirectA(&orig_lf); + ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError()); + hFontCheck = SelectObject(hdcMetafile, hFont2); + ok(hFontCheck == hFont, "Font not selected\n"); + + /* Force Win9x to update DC state */ + SetPixelV(hdcMetafile, 50, 50, 0); + + ret = RestoreDC(hdcMetafile, 1); + ok(ret, "ret = %d\n", ret); + ret = GetViewportOrgEx(hdcMetafile, &pt); + ok(pt.x == 40,"Expecting ViewportOrg x of 40, got %i\n",pt.x); + ret = GetViewportExtEx(hdcMetafile, &size); + ok(size.cx == 50,"Expecting ViewportExt cx of 50, got %i\n",size.cx); + + hFontCheck = SelectObject(hdcMetafile, hFontOld); + ok(hFontOld == hFontCheck && hFontCheck != hFont && hFontCheck != hFont2, + "Font not reverted with DC Restore\n"); + + ret = RestoreDC(hdcMetafile, -20); + ok(!ret, "ret = %d\n", ret); + ret = RestoreDC(hdcMetafile, 20); + ok(!ret, "ret = %d\n", ret); + + hMetafile = CloseEnhMetaFile(hdcMetafile); + ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError()); + + ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc); + ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret); + + ret = DeleteObject(hFont); + ok( ret, "DeleteObject error %d\n", GetLastError()); + ret = DeleteObject(hFont2); + ok( ret, "DeleteObject error %d\n", GetLastError()); + ret = DeleteEnhMetaFile(hMetafile); + ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError()); + ret = ReleaseDC(hwnd, hdcDisplay); + ok( ret, "ReleaseDC error %d\n", GetLastError()); + DestroyWindow(hwnd); +} + +static void test_mf_SaveDC(void) +{ + HDC hdcMetafile; + HMETAFILE hMetafile; + int ret; + POINT pt; + SIZE size; + HFONT hFont,hFont2,hFontOld,hFontCheck; + + hdcMetafile = CreateMetaFileA(NULL); + ok(hdcMetafile != 0, "CreateMetaFileA error %d\n", GetLastError()); + + ret = SetMapMode(hdcMetafile, MM_ANISOTROPIC); + ok (ret, "SetMapMode should not fail\n"); + + /* Need to write something to the emf, otherwise Windows won't play it back */ + LineTo(hdcMetafile, 150, 150); + + SetWindowOrgEx(hdcMetafile, 0, 0, NULL); + SetViewportOrgEx(hdcMetafile, 0, 0, NULL); + SetWindowExtEx(hdcMetafile, 110, 110, NULL ); + SetViewportExtEx(hdcMetafile, 120, 120, NULL ); + + /* Force Win9x to update DC state */ + SetPixelV(hdcMetafile, 50, 50, 0); + + ret = GetViewportOrgEx(hdcMetafile, &pt); + todo_wine ok (!ret, "GetViewportOrgEx should fail\n"); + ret = GetViewportExtEx(hdcMetafile, &size); + todo_wine ok (!ret, "GetViewportExtEx should fail\n"); ret = SaveDC(hdcMetafile); ok(ret == 1, "ret = %d\n", ret); @@ -507,7 +707,7 @@ static void test_SaveDC(void) SetPixelV(hdcMetafile, 50, 50, 0); ret = SaveDC(hdcMetafile); - ok(ret == 2, "ret = %d\n", ret); + ok(ret == 1, "ret = %d\n", ret); SetWindowOrgEx(hdcMetafile, -2, -2, NULL); SetViewportOrgEx(hdcMetafile, 20, 20, NULL); @@ -516,15 +716,22 @@ static void test_SaveDC(void) /* Force Win9x to update DC state */ SetPixelV(hdcMetafile, 50, 50, 0); + SetPolyFillMode( hdcMetafile, ALTERNATE ); + SetBkColor( hdcMetafile, 0 ); ret = SaveDC(hdcMetafile); - ok(ret == 3, "ret = %d\n", ret); + ok(ret == 1, "ret = %d\n", ret); SetWindowOrgEx(hdcMetafile, -3, -3, NULL); SetViewportOrgEx(hdcMetafile, 30, 30, NULL); SetWindowExtEx(hdcMetafile, 200, 200, NULL ); SetViewportExtEx(hdcMetafile, 400, 400, NULL ); + SetPolyFillMode( hdcMetafile, WINDING ); + SetBkColor( hdcMetafile, 0x123456 ); + todo_wine ok( !GetPolyFillMode( hdcMetafile ), "GetPolyFillMode succeeded\n" ); + todo_wine ok( GetBkColor( hdcMetafile ) == CLR_INVALID, "GetBkColor succeeded\n" ); + /* Force Win9x to update DC state */ SetPixelV(hdcMetafile, 50, 50, 0); @@ -532,7 +739,7 @@ static void test_SaveDC(void) ok(ret, "ret = %d\n", ret); ret = SaveDC(hdcMetafile); - ok(ret == 3, "ret = %d\n", ret); + ok(ret == 1, "ret = %d\n", ret); ret = RestoreDC(hdcMetafile, 1); ok(ret, "ret = %d\n", ret); @@ -549,21 +756,54 @@ static void test_SaveDC(void) ok(ret == 1, "ret = %d\n", ret); ret = SaveDC(hdcMetafile); - ok(ret == 2, "ret = %d\n", ret); + ok(ret == 1, "ret = %d\n", ret); - hMetafile = CloseEnhMetaFile(hdcMetafile); + memset(&orig_lf, 0, sizeof(orig_lf)); + orig_lf.lfCharSet = ANSI_CHARSET; + orig_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + orig_lf.lfWeight = FW_DONTCARE; + orig_lf.lfHeight = 7; + orig_lf.lfQuality = DEFAULT_QUALITY; + lstrcpyA(orig_lf.lfFaceName, "Arial"); + hFont = CreateFontIndirectA(&orig_lf); + ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError()); + + hFontOld = SelectObject(hdcMetafile, hFont); + + hFont2 = CreateFontIndirectA(&orig_lf); + ok(hFont2 != 0, "CreateFontIndirectA error %d\n", GetLastError()); + hFontCheck = SelectObject(hdcMetafile, hFont2); + ok(hFontCheck == hFont, "Font not selected\n"); + + /* Force Win9x to update DC state */ + SetPixelV(hdcMetafile, 50, 50, 0); + + ret = RestoreDC(hdcMetafile, 1); + ok(ret, "ret = %d\n", ret); + + hFontCheck = SelectObject(hdcMetafile, hFontOld); + ok(hFontOld != hFontCheck && hFontCheck == hFont2, "Font incorrectly reverted with DC Restore\n"); + + /* restore level is ignored */ + ret = RestoreDC(hdcMetafile, -20); + ok(ret, "ret = %d\n", ret); + ret = RestoreDC(hdcMetafile, 20); + ok(ret, "ret = %d\n", ret); + ret = RestoreDC(hdcMetafile, 0); + ok(ret, "ret = %d\n", ret); + + hMetafile = CloseMetaFile(hdcMetafile); ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError()); - ret = EnumEnhMetaFile(hdcDisplay, hMetafile, savedc_emf_enum_proc, 0, &rc); - ok( ret == 1, "EnumEnhMetaFile rets %d\n", ret); - - ret = DeleteEnhMetaFile(hMetafile); - ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError()); - ret = ReleaseDC(hwnd, hdcDisplay); - ok( ret, "ReleaseDC error %d\n", GetLastError()); - DestroyWindow(hwnd); + ret = DeleteMetaFile(hMetafile); + ok( ret, "DeleteMetaFile error %d\n", GetLastError()); + ret = DeleteObject(hFont); + ok( ret, "DeleteObject error %d\n", GetLastError()); + ret = DeleteObject(hFont2); + ok( ret, "DeleteObject error %d\n", GetLastError()); } + /* Win-format metafile (mfdrv) tests */ /* These tests compare the generated metafiles byte-by-byte */ /* with the nominal results. */ @@ -975,34 +1215,32 @@ static void dump_emf_record(const ENHMETARECORD *emr, const char *desc) printf ("};\n"); } +static void dump_EMREXTTEXTOUT(const EMREXTTEXTOUTW *eto) +{ + trace("rclBounds %d,%d - %d,%d\n", eto->rclBounds.left, eto->rclBounds.top, + eto->rclBounds.right, eto->rclBounds.bottom); + trace("iGraphicsMode %u\n", eto->iGraphicsMode); + trace("exScale: %f\n", eto->exScale); + trace("eyScale: %f\n", eto->eyScale); + trace("emrtext.ptlReference %d,%d\n", eto->emrtext.ptlReference.x, eto->emrtext.ptlReference.y); + trace("emrtext.nChars %u\n", eto->emrtext.nChars); + trace("emrtext.offString %#x\n", eto->emrtext.offString); + trace("emrtext.fOptions %#x\n", eto->emrtext.fOptions); + trace("emrtext.rcl %d,%d - %d,%d\n", eto->emrtext.rcl.left, eto->emrtext.rcl.top, + eto->emrtext.rcl.right, eto->emrtext.rcl.bottom); + trace("emrtext.offDx %#x\n", eto->emrtext.offDx); +} + static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr2, - const char *desc, BOOL todo) + const char *desc, BOOL ignore_scaling) { int diff; - if (emr1->iType != emr2->iType && todo) - { - todo_wine - { ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n", desc, emr1->iType, emr2->iType); - } - } - else - ok(emr1->iType == emr2->iType, "%s: emr->iType %u != %u\n", - desc, emr1->iType, emr2->iType); - if (emr1->nSize != emr2->nSize && todo) - { - todo_wine - { ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n", desc, emr1->nSize, emr2->nSize); - } - } - else - ok(emr1->nSize == emr2->nSize, "%s: emr->nSize %u != %u\n", - desc, emr1->nSize, emr2->nSize); /* iType and nSize mismatches are fatal */ if (emr1->iType != emr2->iType || emr1->nSize != emr2->nSize) return FALSE; @@ -1010,13 +1248,58 @@ static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr /* contents of EMR_GDICOMMENT are not interesting */ if (emr1->iType == EMR_GDICOMMENT) return TRUE; - diff = memcmp(emr1->dParm, emr2->dParm, emr1->nSize - sizeof(EMR)); - if (diff && todo) + /* different Windows versions setup DC scaling differently when + * converting an old style metafile to an EMF. + */ + if (ignore_scaling && (emr1->iType == EMR_SETWINDOWEXTEX || + emr1->iType == EMR_SETVIEWPORTEXTEX)) + return TRUE; + + if (emr1->iType == EMR_EXTTEXTOUTW || emr1->iType == EMR_EXTTEXTOUTA) { - todo_wine - ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType); + EMREXTTEXTOUTW *eto1, *eto2; + + eto1 = HeapAlloc(GetProcessHeap(), 0, emr1->nSize); + memcpy(eto1, emr1, emr1->nSize); + eto2 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize); + memcpy(eto2, emr2, emr2->nSize); + + /* different Windows versions setup DC scaling differently */ + eto1->exScale = eto1->eyScale = 0.0; + eto2->exScale = eto2->eyScale = 0.0; + + diff = memcmp(eto1, eto2, emr1->nSize); + if (diff) + { + dump_EMREXTTEXTOUT(eto1); + dump_EMREXTTEXTOUT(eto2); + } + HeapFree(GetProcessHeap(), 0, eto1); + HeapFree(GetProcessHeap(), 0, eto2); + } + else if (emr1->iType == EMR_EXTSELECTCLIPRGN && !lstrcmpA(desc, "emf_clipping")) + { + /* We have to take care of NT4 differences here */ + diff = memcmp(emr1, emr2, emr1->nSize); + if (diff) + { + ENHMETARECORD *emr_nt4; + + emr_nt4 = HeapAlloc(GetProcessHeap(), 0, emr2->nSize); + memcpy(emr_nt4, emr2, emr2->nSize); + /* Correct the nRgnSize field */ + emr_nt4->dParm[5] = sizeof(RECT); + + diff = memcmp(emr1, emr_nt4, emr1->nSize); + if (!diff) + win_skip("Catered for NT4 differences\n"); + + HeapFree(GetProcessHeap(), 0, emr_nt4); + } } else + diff = memcmp(emr1, emr2, emr1->nSize); + ok(diff == 0, "%s: contents of record %u don't match\n", desc, emr1->iType); if (diff) @@ -1025,7 +1308,7 @@ static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr dump_emf_record(emr2, "actual bits"); } - return diff == 0 || todo; /* report all non-fatal record mismatches */ + return diff == 0; /* report all non-fatal record mismatches */ } /* Compare the EMF produced by a test function with the @@ -1035,26 +1318,28 @@ static BOOL match_emf_record(const ENHMETARECORD *emr1, const ENHMETARECORD *emr * otherwise returns the number of non-matching bytes. */ static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits, - UINT bsize, const char *desc, BOOL todo) + UINT bsize, const char *desc, + BOOL ignore_scaling) { unsigned char buf[MF_BUFSIZE]; - UINT mfsize, offset; + UINT mfsize, offset1, offset2, diff_nt4, diff_9x; const ENHMETAHEADER *emh1, *emh2; mfsize = GetEnhMetaFileBits(mf, MF_BUFSIZE, buf); ok (mfsize > 0, "%s: GetEnhMetaFileBits error %d\n", desc, GetLastError()); + /* ENHMETAHEADER size could differ, depending on platform */ + diff_nt4 = sizeof(SIZEL); + diff_9x = sizeof(SIZEL) + 3 * sizeof(DWORD); + if (mfsize < MF_BUFSIZE) { - if (mfsize != bsize && todo) - { - todo_wine - ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize); + ok(mfsize == bsize || + broken(mfsize == bsize - diff_nt4) || /* NT4 */ + broken(mfsize == bsize - diff_9x), /* Win9x/WinME */ + "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize); } else - ok(mfsize == bsize, "%s: mfsize=%d, bsize=%d\n", desc, mfsize, bsize); - } - else ok(bsize >= MF_BUFSIZE, "%s: mfsize > bufsize (%d bytes), bsize=%d\n", desc, mfsize, bsize); @@ -1067,35 +1352,32 @@ static int compare_emf_bits(const HENHMETAFILE mf, const unsigned char *bits, ok(emh1->dSignature == ENHMETA_SIGNATURE, "expected ENHMETA_SIGNATURE, got %u\n", emh1->dSignature); ok(emh1->iType == emh2->iType, "expected EMR_HEADER, got %u\n", emh2->iType); - ok(emh1->nSize == emh2->nSize, "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize); + ok(emh1->nSize == emh2->nSize || + broken(emh1->nSize - diff_nt4 == emh2->nSize) || + broken(emh1->nSize - diff_9x == emh2->nSize), + "expected nSize %u, got %u\n", emh1->nSize, emh2->nSize); ok(emh1->dSignature == emh2->dSignature, "expected dSignature %u, got %u\n", emh1->dSignature, emh2->dSignature); - if (todo && emh1->nBytes != emh2->nBytes) + ok(emh1->nBytes == emh2->nBytes || + broken(emh1->nBytes - diff_nt4 == emh2->nBytes) || + broken(emh1->nBytes - diff_9x == emh2->nBytes), + "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes); + ok(emh1->nRecords == emh2->nRecords, "expected nRecords %u, got %u\n", emh1->nRecords, emh2->nRecords); + + offset1 = emh1->nSize; + offset2 = emh2->nSize; /* Needed for Win9x/WinME/NT4 */ + while (offset1 < emh1->nBytes) { - todo_wine - ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes); - } - else - ok(emh1->nBytes == emh2->nBytes, "expected nBytes %u, got %u\n", emh1->nBytes, emh2->nBytes); - if (todo && emh1->nRecords != emh2->nRecords) - { - todo_wine - ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords); - } - else - ok(emh1->nRecords == emh2->nRecords, "expected nBytes %u, got %u\n", emh1->nRecords, emh2->nRecords); + const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset1); + const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset2); - offset = emh1->nSize; - while (offset < emh1->nBytes) - { - const ENHMETARECORD *emr1 = (const ENHMETARECORD *)(bits + offset); - const ENHMETARECORD *emr2 = (const ENHMETARECORD *)(buf + offset); + trace("%s: EMF record %u, size %u/record %u, size %u\n", + desc, emr1->iType, emr1->nSize, emr2->iType, emr2->nSize); - trace("EMF record %u, size %u/record %u, size %u\n", - emr1->iType, emr1->nSize, emr2->iType, emr2->nSize); + if (!match_emf_record(emr1, emr2, desc, ignore_scaling)) return -1; - if (!match_emf_record(emr1, emr2, desc, todo)) return -1; - - offset += emr1->nSize; + /* We have already bailed out if iType or nSize don't match */ + offset1 += emr1->nSize; + offset2 += emr2->nSize; } return 0; } @@ -1175,8 +1457,8 @@ static void test_CopyMetaFile(void) if (compare_mf_disk_bits(mf_name, MF_BLANK_BITS, sizeof(MF_BLANK_BITS), "mf_blank") != 0) { - dump_mf_bits(hMetafile, "mf_Blank"); - EnumMetaFile(0, hMetafile, mf_enum_proc, 0); + dump_mf_bits(hmf_copy, "mf_Blank"); + EnumMetaFile(0, hmf_copy, mf_enum_proc, 0); } ret = DeleteMetaFile(hmf_copy); @@ -1194,6 +1476,7 @@ static void test_SetMetaFileBits(void) METAHEADER *mh; hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), MF_GRAPHICS_BITS); + trace("hmf %p\n", hmf); ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError()); type = GetObjectType(hmf); ok(type == OBJ_METAFILE, "SetMetaFileBitsEx created object with type %d\n", type); @@ -1210,19 +1493,23 @@ static void test_SetMetaFileBits(void) /* NULL data crashes XP SP1 */ /*hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), NULL);*/ - /* Now with not zero size */ + /* Now with zero size */ SetLastError(0xdeadbeef); hmf = SetMetaFileBitsEx(0, MF_GRAPHICS_BITS); + trace("hmf %p\n", hmf); ok(!hmf, "SetMetaFileBitsEx should fail\n"); - ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_DATA || + broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */ + "wrong error %d\n", GetLastError()); - /* Now with not even size */ + /* Now with odd size */ SetLastError(0xdeadbeef); hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS) - 1, MF_GRAPHICS_BITS); + trace("hmf %p\n", hmf); ok(!hmf, "SetMetaFileBitsEx should fail\n"); ok(GetLastError() == 0xdeadbeef /* XP SP1 */, "wrong error %d\n", GetLastError()); - /* Now with zeroed out or faked some header fields */ + /* Now with zeroed out header fields */ assert(sizeof(buf) >= sizeof(MF_GRAPHICS_BITS)); memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS)); mh = (METAHEADER *)buf; @@ -1232,8 +1519,11 @@ static void test_SetMetaFileBits(void) mh->mtHeaderSize = 0; SetLastError(0xdeadbeef); hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf); + trace("hmf %p\n", hmf); ok(!hmf, "SetMetaFileBitsEx should fail\n"); - ok(GetLastError() == ERROR_INVALID_DATA, "wrong error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_DATA || + broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */ + "wrong error %d\n", GetLastError()); /* Now with corrupted mtSize field */ memcpy(buf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS)); @@ -1241,6 +1531,7 @@ static void test_SetMetaFileBits(void) /* corruption of mtSize doesn't lead to a failure */ mh->mtSize *= 2; hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf); + trace("hmf %p\n", hmf); ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError()); if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0) @@ -1258,6 +1549,7 @@ static void test_SetMetaFileBits(void) /* zeroing mtSize doesn't lead to a failure */ mh->mtSize = 0; hmf = SetMetaFileBitsEx(sizeof(MF_GRAPHICS_BITS), buf); + trace("hmf %p\n", hmf); ok(hmf != 0, "SetMetaFileBitsEx error %d\n", GetLastError()); if (compare_mf_bits(hmf, MF_GRAPHICS_BITS, sizeof(MF_GRAPHICS_BITS), "mf_Graphics") != 0) @@ -1433,7 +1725,7 @@ static void test_emf_ExtTextOut_on_path(void) * are there, but their contents don't match for different reasons. */ if (compare_emf_bits(hMetafile, EMF_TEXTOUT_ON_PATH_BITS, sizeof(EMF_TEXTOUT_ON_PATH_BITS), - "emf_TextOut_on_path", TRUE) != 0) + "emf_TextOut_on_path", FALSE) != 0) { dump_emf_bits(hMetafile, "emf_TextOut_on_path"); dump_emf_records(hMetafile, "emf_TextOut_on_path"); @@ -1488,6 +1780,15 @@ static void translate( POINT *pt, UINT count, const XFORM *xform ) } } +/* Compare rectangles allowing rounding errors */ +static BOOL is_equal_rect(const RECT *rc1, const RECT *rc2) +{ + return abs(rc1->left - rc2->left) <= 1 && + abs(rc1->top - rc2->top) <= 1 && + abs(rc1->right - rc2->right) <= 1 && + abs(rc1->bottom - rc2->bottom) <= 1; +} + static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, const ENHMETARECORD *emr, int n_objs, LPARAM param) { @@ -1534,7 +1835,9 @@ static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, ok(rgn1->data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn1->data.rdh.dwSize); ok(rgn1->data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn1->data.rdh.iType); ok(rgn1->data.rdh.nCount == 1, "expected 1, got %u\n", rgn1->data.rdh.nCount); - ok(rgn1->data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize); + ok(rgn1->data.rdh.nRgnSize == sizeof(RECT) || + broken(rgn1->data.rdh.nRgnSize == 168), /* NT4 */ + "expected sizeof(RECT), got %u\n", rgn1->data.rdh.nRgnSize); hrgn = CreateRectRgn(0, 0, 0, 0); @@ -1553,7 +1856,7 @@ static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, PlayEnhMetaFileRecord(hdc, handle_table, emr, n_objs); ret = GetClipRgn(hdc, hrgn); - ok(ret == 1, "GetClipRgn returned %d, expected 0\n", ret); + ok(ret == 1, "GetClipRgn returned %d, expected 1\n", ret); /* Win9x returns empty clipping region */ if (is_win9x) return 1; @@ -1574,7 +1877,7 @@ static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, translate((POINT *)&rc_transformed, 2, &xform); trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top, rc_transformed.right, rc_transformed.bottom); - ok(EqualRect(&rect, &rc_transformed), "rects don't match\n"); + ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n"); rect = *(const RECT *)rgn2.data.Buffer; trace("rect (%d,%d-%d,%d)\n", rect.left, rect.top, rect.right, rect.bottom); @@ -1582,12 +1885,14 @@ static int CALLBACK clip_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table, translate((POINT *)&rc_transformed, 2, &xform); trace("transformed (%d,%d-%d,%d)\n", rc_transformed.left, rc_transformed.top, rc_transformed.right, rc_transformed.bottom); - ok(EqualRect(&rect, &rc_transformed), "rects don't match\n"); + ok(is_equal_rect(&rect, &rc_transformed), "rects don't match\n"); ok(rgn2.data.rdh.dwSize == sizeof(rgn1->data.rdh), "expected sizeof(rdh), got %u\n", rgn2.data.rdh.dwSize); ok(rgn2.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn2.data.rdh.iType); ok(rgn2.data.rdh.nCount == 1, "expected 1, got %u\n", rgn2.data.rdh.nCount); - ok(rgn2.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize); + ok(rgn2.data.rdh.nRgnSize == sizeof(RECT) || + broken(rgn2.data.rdh.nRgnSize == 168), /* NT4 */ + "expected sizeof(RECT), got %u\n", rgn2.data.rdh.nRgnSize); DeleteObject(hrgn); } @@ -1603,6 +1908,7 @@ static void test_emf_clipping(void) HENHMETAFILE hemf; HRGN hrgn; INT ret; + RECT rc_res, rc_sclip; SetLastError(0xdeadbeef); hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL); @@ -1620,7 +1926,7 @@ static void test_emf_clipping(void) ok(hemf != 0, "CloseEnhMetaFile error %d\n", GetLastError()); if (compare_emf_bits(hemf, EMF_CLIPPING, sizeof(EMF_CLIPPING), - "emf_clipping", TRUE) != 0) + "emf_clipping", FALSE) != 0) { dump_emf_bits(hemf, "emf_clipping"); dump_emf_records(hemf, "emf_clipping"); @@ -1641,6 +1947,22 @@ static void test_emf_clipping(void) DeleteEnhMetaFile(hemf); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); + + hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL); + + SetRect(&rc_sclip, 100, 100, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); + hrgn = CreateRectRgn(rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom); + SelectClipRgn(hdc, hrgn); + GetClipBox(hdc, &rc_res); + todo_wine ok(EqualRect(&rc_res, &rc_sclip), + "expected rc_res (%d, %d) - (%d, %d), got (%d, %d) - (%d, %d)\n", + rc_sclip.left, rc_sclip.top, rc_sclip.right, rc_sclip.bottom, + rc_res.left, rc_res.top, rc_res.right, rc_res.bottom); + + hemf = CloseEnhMetaFile(hdc); + DeleteEnhMetaFile(hemf); + DeleteObject(hrgn); + DeleteDC(hdc); } static INT CALLBACK EmfEnumProc(HDC hdc, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, INT nObj, LPARAM lpData) @@ -1686,6 +2008,7 @@ static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp) { HDC hdcMf; HMETAFILE hmf; + HENHMETAFILE hemf; BOOL ret; UINT size; LPBYTE pBits; @@ -1708,7 +2031,9 @@ static HENHMETAFILE create_converted_emf(const METAFILEPICT *mfp) pBits = HeapAlloc(GetProcessHeap(), 0, size); GetMetaFileBitsEx(hmf, size, pBits); DeleteMetaFile(hmf); - return SetWinMetaFileBits(size, pBits, NULL, mfp); + hemf = SetWinMetaFileBits(size, pBits, NULL, mfp); + HeapFree(GetProcessHeap(), 0, pBits); + return hemf; } static void test_mf_conversions(void) @@ -1920,12 +2245,17 @@ static void test_SetWinMetaFileBits(void) ok(diffx <= 1, "SetWinMetaFileBits (MM_ISOTROPIC): Reference bounds are not isotropic\n"); dc = CreateCompatibleDC(NULL); + + /* Allow 1 mm difference (rounding errors) */ + diffx = rclBoundsAnisotropic.right - GetDeviceCaps(dc, HORZRES) / 2; + diffy = rclBoundsAnisotropic.bottom - GetDeviceCaps(dc, VERTRES) / 2; + if (diffx < 0) diffx = -diffx; + if (diffy < 0) diffy = -diffy; todo_wine { - ok(rclBoundsAnisotropic.right == GetDeviceCaps(dc, HORZRES) / 2 - 1 && - rclBoundsAnisotropic.bottom == GetDeviceCaps(dc, VERTRES) / 2 - 1, + ok(diffx <= 1 && diffy <= 1, "SetWinMetaFileBits (MM_ANISOTROPIC): Reference bounds: The whole device surface must be used (%dx%d), but got (%dx%d)\n", - GetDeviceCaps(dc, HORZRES) / 2 - 1, GetDeviceCaps(dc, VERTRES) / 2 - 1, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom); + GetDeviceCaps(dc, HORZRES) / 2, GetDeviceCaps(dc, VERTRES) / 2, rclBoundsAnisotropic.right, rclBoundsAnisotropic.bottom); } /* Allow 1 mm difference (rounding errors) */ @@ -1995,6 +2325,198 @@ static void test_SetWinMetaFileBits(void) HeapFree(GetProcessHeap(), 0, buffer); } +static BOOL near_match(int x, int y) +{ + int epsilon = min(abs(x), abs(y)); + + epsilon = max(epsilon/100, 2); + + if(x < y - epsilon || x > y + epsilon) return FALSE; + return TRUE; +} + +static void getwinmetafilebits(UINT mode, int scale, RECT *rc) +{ + HENHMETAFILE emf; + HDC display_dc, emf_dc; + ENHMETAHEADER *enh_header; + UINT size, emf_size, i; + WORD check = 0; + DWORD rec_num = 0; + METAHEADER *mh = NULL; + METARECORD *rec; + INT horz_res, vert_res, horz_size, vert_size; + + display_dc = GetDC(NULL); + ok(display_dc != NULL, "display_dc is NULL\n"); + + horz_res = GetDeviceCaps(display_dc, HORZRES); + vert_res = GetDeviceCaps(display_dc, VERTRES); + horz_size = GetDeviceCaps(display_dc, HORZSIZE); + vert_size = GetDeviceCaps(display_dc, VERTSIZE); + + emf_dc = CreateEnhMetaFileA(display_dc, NULL, rc, NULL); + ok(emf_dc != NULL, "emf_dc is NULL\n"); + for(i = 0; i < 3000; i++) /* This is enough to take emf_size > 0xffff */ + Rectangle(emf_dc, 0, 0, 1000, 20); + emf = CloseEnhMetaFile(emf_dc); + ok(emf != NULL, "emf is NULL\n"); + + emf_size = GetEnhMetaFileBits(emf, 0, NULL); + enh_header = HeapAlloc(GetProcessHeap(), 0, emf_size); + emf_size = GetEnhMetaFileBits(emf, emf_size, (BYTE*)enh_header); + DeleteEnhMetaFile(emf); + /* multiply szlDevice.cx by scale, when scale != 1 the recording and playback dcs + have different resolutions */ + enh_header->szlDevice.cx *= scale; + emf = SetEnhMetaFileBits(emf_size, (BYTE*)enh_header); + ok(emf != NULL, "emf is NULL\n"); + ok(EqualRect((RECT*)&enh_header->rclFrame, rc), "Frame rectangles differ\n"); + + size = GetWinMetaFileBits(emf, 0, NULL, mode, display_dc); + ok(size || + broken(size == 0), /* some versions of winxp fail for some reason */ + "GetWinMetaFileBits returns 0\n"); + if(!size) goto end; + mh = HeapAlloc(GetProcessHeap(), 0, size); + GetWinMetaFileBits(emf, size, (BYTE*)mh, mode, display_dc); + + for(i = 0; i < size / 2; i++) check += ((WORD*)mh)[i]; + ok(check == 0, "check %04x\n", check); + + rec = (METARECORD*)(mh + 1); + + while(rec->rdSize && rec->rdFunction) + { + const DWORD chunk_size = 0x2000; + DWORD mfcomment_chunks = (emf_size + chunk_size - 1) / chunk_size; + + if(rec_num < mfcomment_chunks) + { + DWORD this_chunk_size = chunk_size; + + if(rec_num == mfcomment_chunks - 1) + this_chunk_size = emf_size - rec_num * chunk_size; + + ok(rec->rdSize == (this_chunk_size + 44) / 2, "%04x: got %04x expected %04x\n", rec_num, rec->rdSize, (this_chunk_size + 44) / 2); + ok(rec->rdFunction == META_ESCAPE, "%04x: got %04x\n", rec_num, rec->rdFunction); + if(rec->rdSize < (this_chunk_size + 44) / 2) break; + ok(rec->rdParm[0] == MFCOMMENT, "got %04x\n", rec->rdParm[0]); + ok(rec->rdParm[1] == this_chunk_size + 34, "got %04x %x\n", rec->rdParm[1], emf_size + 34); + ok(rec->rdParm[2] == 0x4d57, "got %04x\n", rec->rdParm[2]); /* WMFC */ + ok(rec->rdParm[3] == 0x4346, "got %04x\n", rec->rdParm[3]); /* " */ + ok(rec->rdParm[4] == 1, "got %04x\n", rec->rdParm[4]); + ok(rec->rdParm[5] == 0, "got %04x\n", rec->rdParm[5]); + ok(rec->rdParm[6] == 0, "got %04x\n", rec->rdParm[6]); + ok(rec->rdParm[7] == 1, "got %04x\n", rec->rdParm[7]); + /* parm[8] is the checksum, tested above */ + if(rec_num > 0) ok(rec->rdParm[8] == 0, "got %04x\n", rec->rdParm[8]); + ok(rec->rdParm[9] == 0, "got %04x\n", rec->rdParm[9]); + ok(rec->rdParm[10] == 0, "got %04x\n", rec->rdParm[10]); + ok(rec->rdParm[11] == mfcomment_chunks, "got %04x\n", rec->rdParm[11]); /* num chunks */ + ok(rec->rdParm[12] == 0, "got %04x\n", rec->rdParm[12]); + ok(rec->rdParm[13] == this_chunk_size, "got %04x expected %04x\n", rec->rdParm[13], this_chunk_size); + ok(rec->rdParm[14] == 0, "got %04x\n", rec->rdParm[14]); + ok(*(DWORD*)(rec->rdParm + 15) == emf_size - this_chunk_size - rec_num * chunk_size, "got %08x\n", *(DWORD*)(rec->rdParm + 15)); /* DWORD size remaining after current chunk */ + ok(*(DWORD*)(rec->rdParm + 17) == emf_size, "got %08x emf_size %08x\n", *(DWORD*)(rec->rdParm + 17), emf_size); + ok(!memcmp(rec->rdParm + 19, (char*)enh_header + rec_num * chunk_size, this_chunk_size), "bits mismatch\n"); + } + + else if(rec_num == mfcomment_chunks) + { + ok(rec->rdFunction == META_SETMAPMODE, "got %04x\n", rec->rdFunction); + ok(rec->rdParm[0] == mode, "got %04x\n", rec->rdParm[0]); + } + else if(rec_num == mfcomment_chunks + 1) + { + POINT pt; + ok(rec->rdFunction == META_SETWINDOWORG, "got %04x\n", rec->rdFunction); + switch(mode) + { + case MM_TEXT: + case MM_ISOTROPIC: + case MM_ANISOTROPIC: + pt.y = MulDiv(rc->top, vert_res, vert_size * 100) + 1; + pt.x = MulDiv(rc->left, horz_res, horz_size * 100); + break; + case MM_LOMETRIC: + pt.y = MulDiv(-rc->top, 1, 10) + 1; + pt.x = MulDiv( rc->left, 1, 10); + break; + case MM_HIMETRIC: + pt.y = -rc->top + 1; + pt.x = (rc->left >= 0) ? rc->left : rc->left + 1; /* strange but true */ + break; + case MM_LOENGLISH: + pt.y = MulDiv(-rc->top, 10, 254) + 1; + pt.x = MulDiv( rc->left, 10, 254); + break; + case MM_HIENGLISH: + pt.y = MulDiv(-rc->top, 100, 254) + 1; + pt.x = MulDiv( rc->left, 100, 254); + break; + case MM_TWIPS: + pt.y = MulDiv(-rc->top, 72 * 20, 2540) + 1; + pt.x = MulDiv( rc->left, 72 * 20, 2540); + break; + default: + pt.x = pt.y = 0; + } + ok(near_match((short)rec->rdParm[0], pt.y), "got %d expect %d\n", (short)rec->rdParm[0], pt.y); + ok(near_match((short)rec->rdParm[1], pt.x), "got %d expect %d\n", (short)rec->rdParm[1], pt.x); + } + if(rec_num == mfcomment_chunks + 2) + { + ok(rec->rdFunction == META_SETWINDOWEXT, "got %04x\n", rec->rdFunction); + ok(near_match((short)rec->rdParm[0], MulDiv(rc->bottom - rc->top, vert_res, vert_size * 100)), + "got %d\n", (short)rec->rdParm[0]); + ok(near_match((short)rec->rdParm[1], MulDiv(rc->right - rc->left, horz_res, horz_size * 100)), + "got %d\n", (short)rec->rdParm[1]); + } + + rec_num++; + rec = (METARECORD*)((WORD*)rec + rec->rdSize); + } + +end: + HeapFree(GetProcessHeap(), 0, mh); + HeapFree(GetProcessHeap(), 0, enh_header); + DeleteEnhMetaFile(emf); + + ReleaseDC(NULL, display_dc); +} + +static void test_GetWinMetaFileBits(void) +{ + UINT mode; + RECT frames[] = + { + { 1000, 2000, 3000, 6000}, + {-1000, 2000, 3000, 6000}, + { 1000, -2000, 3000, 6000}, + { 1005, 2005, 3000, 6000}, + {-1005, -2005, 3000, 6000}, + {-1005, -2010, 3000, 6000}, + {-1005, 2010, 3000, 6000}, + { 0, 0, 1, 1}, + { -1, -1, 1, 1}, + { 0, 0, 0, 0} + }; + + for(mode = MM_MIN; mode <= MM_MAX; mode++) + { + RECT *rc; + trace("mode %d\n", mode); + + for(rc = frames; rc->right - rc->left > 0; rc++) + { + trace("frame %d,%d - %d,%d\n", rc->left, rc->top, rc->right, rc->bottom); + getwinmetafilebits(mode, 1, rc); + getwinmetafilebits(mode, 2, rc); + } + } +} + static BOOL (WINAPI *pGdiIsMetaPrintDC)(HDC); static BOOL (WINAPI *pGdiIsMetaFileDC)(HDC); static BOOL (WINAPI *pGdiIsPlayMetafileDC)(HDC); @@ -2012,9 +2534,11 @@ static void test_gdiis(void) pGdiIsMetaFileDC = (void*) GetProcAddress(hgdi32, "GdiIsMetaFileDC"); pGdiIsPlayMetafileDC = (void*) GetProcAddress(hgdi32, "GdiIsPlayMetafileDC"); - /* they should all exist or none should exist */ - if(!pGdiIsMetaPrintDC) + if(!pGdiIsMetaPrintDC || !pGdiIsMetaFileDC || !pGdiIsPlayMetafileDC) + { + win_skip("Needed GdiIs* functions are not available\n"); return; + } /* try with nothing */ ok(!pGdiIsMetaPrintDC(NULL), "ismetaprint with NULL parameter\n"); @@ -2053,7 +2577,9 @@ static void test_SetEnhMetaFileBits(void) SetLastError(0xdeadbeef); hemf = SetEnhMetaFileBits(sizeof(data), data); ok(!hemf, "SetEnhMetaFileBits should fail\n"); - ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA, got %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_DATA || + GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */ + "expected ERROR_INVALID_DATA or ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); emh = (ENHMETAHEADER *)data; memset(emh, 0, sizeof(*emh)); @@ -2075,15 +2601,21 @@ static void test_SetEnhMetaFileBits(void) emh->nBytes++; SetLastError(0xdeadbeef); hemf = SetEnhMetaFileBits(emh->nBytes, data); - ok(!hemf, "SetEnhMetaFileBits should fail\n"); - /* XP doesn't set error in this case */ + ok(!hemf || + broken(hemf != NULL), /* Win9x, WinMe */ + "SetEnhMetaFileBits should fail\n"); + ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError()); + DeleteEnhMetaFile(hemf); emh->dSignature = 0; emh->nBytes--; SetLastError(0xdeadbeef); hemf = SetEnhMetaFileBits(emh->nBytes, data); - ok(!hemf, "SetEnhMetaFileBits should fail\n"); - /* XP doesn't set error in this case */ + ok(!hemf || + broken(hemf != NULL), /* Win9x, WinMe */ + "SetEnhMetaFileBits should fail\n"); + ok(GetLastError() == 0xdeadbeef, "Expected deadbeef, got %u\n", GetLastError()); + DeleteEnhMetaFile(hemf); } START_TEST(metafile) @@ -2095,6 +2627,7 @@ START_TEST(metafile) test_SaveDC(); /* For win-format metafiles (mfdrv) */ + test_mf_SaveDC(); test_mf_Blank(); test_mf_Graphics(); test_mf_PatternBrush(); @@ -2107,6 +2640,7 @@ START_TEST(metafile) /* For metafile conversions */ test_mf_conversions(); test_SetWinMetaFileBits(); + test_GetWinMetaFileBits(); test_gdiis(); test_SetEnhMetaFileBits(); diff --git a/rostests/winetests/gdi32/palette.c b/rostests/winetests/gdi32/palette.c index c9455cab659..851c3213e14 100644 --- a/rostests/winetests/gdi32/palette.c +++ b/rostests/winetests/gdi32/palette.c @@ -110,7 +110,9 @@ static void test_DIB_PAL_COLORS(void) { SetPixel( memhdc, 0, 0, setColor ); chkColor = RGB( logpalettedata[3].peRed, logpalettedata[3].peGreen, logpalettedata[3].peBlue ); getColor = GetPixel( memhdc, 0, 0 ); - ok( getColor == chkColor, "getColor=%08X\n", (UINT)getColor ); + ok( getColor == chkColor || + broken(getColor == 0), /* win9x */ + "getColor=%08X\n", (UINT)getColor ); SelectPalette( memhdc, hpalOld, FALSE ); DeleteObject( hpal ); diff --git a/rostests/winetests/gdi32/path.c b/rostests/winetests/gdi32/path.c index 58e84677fcf..4a8ea6d4743 100644 --- a/rostests/winetests/gdi32/path.c +++ b/rostests/winetests/gdi32/path.c @@ -238,7 +238,7 @@ static void test_arcto(void) GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { /* ArcTo is only available on Win2k and later */ - skip("ArcTo is not available\n"); + win_skip("ArcTo is not available\n"); goto done; } SetArcDirection(hdc, AD_COUNTERCLOCKWISE); @@ -282,7 +282,7 @@ static void test_anglearc(void) GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { /* AngleArc is only available on Win2k and later */ - skip("AngleArc is not available\n"); + win_skip("AngleArc is not available\n"); goto done; } AngleArc(hdc, 300, 300, 80, 150.0, -180.0); @@ -355,7 +355,7 @@ static void test_polydraw(void) GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { /* PolyDraw is only available on Win2k and later */ - skip("PolyDraw is not available\n"); + win_skip("PolyDraw is not available\n"); goto done; } expect(TRUE, retb); diff --git a/rostests/winetests/gdi32/pen.c b/rostests/winetests/gdi32/pen.c index fcd79e636d3..460288d9cd3 100644 --- a/rostests/winetests/gdi32/pen.c +++ b/rostests/winetests/gdi32/pen.c @@ -29,6 +29,8 @@ #include "wine/test.h" #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) +#define expect2(expected, alt, got) ok(got == expected || got == alt, \ + "Expected %.8x or %.8x, got %.8x\n", expected, alt, got) static void test_logpen(void) { @@ -59,6 +61,7 @@ static void test_logpen(void) LOGPEN lp; EXTLOGPEN elp; LOGBRUSH lb; + DWORD_PTR unset_hatch; DWORD obj_type, user_style[2] = { 0xabc, 0xdef }; struct { @@ -68,7 +71,7 @@ static void test_logpen(void) for (i = 0; i < sizeof(pen)/sizeof(pen[0]); i++) { - trace("testing style %u\n", pen[i].style); + trace("%d: testing style %u\n", i, pen[i].style); /********************** cosmetic pens **********************/ /* CreatePenIndirect behaviour */ @@ -88,9 +91,19 @@ static void test_logpen(void) size = GetObject(hpen, sizeof(lp), &lp); ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError()); + if (pen[i].style == PS_USERSTYLE || pen[i].style == PS_ALTERNATE) + { + if (lp.lopnStyle == pen[i].style) + { + win_skip("Skipping PS_USERSTYLE and PS_ALTERNATE tests on Win9x\n"); + continue; + } + } ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle); ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x); - ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y); + ok(lp.lopnWidth.y == 0 || + broken(lp.lopnWidth.y == 0xb), /* Win9x */ + "expected 0, got %d\n", lp.lopnWidth.y); ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor); DeleteObject(hpen); @@ -111,12 +124,14 @@ static void test_logpen(void) memset(&lp, 0xb0, sizeof(lp)); SetLastError(0xdeadbeef); size = GetObject(hpen, sizeof(lp.lopnStyle), &lp); - ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError()); + ok(!size || + broken(size == sizeof(lp.lopnStyle)), /* Win9x */ + "GetObject should fail: size %d, error %d\n", size, GetLastError()); /* see how larger buffer sizes are handled */ memset(&lp, 0xb0, sizeof(lp)); SetLastError(0xdeadbeef); - size = GetObject(hpen, sizeof(lp) * 2, &lp); + size = GetObject(hpen, sizeof(lp) * 4, &lp); ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError()); /* see how larger buffer sizes are handled */ @@ -142,6 +157,7 @@ static void test_logpen(void) /* for some reason XP differentiates PS_NULL here */ if (pen[i].style == PS_NULL) { + ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n"); ok(size == sizeof(EXTLOGPEN), "GetObject returned %d, error %d\n", size, GetLastError()); ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, elp.elpPenStyle); ok(elp.elpWidth == 0, "expected 0, got %u\n", elp.elpWidth); @@ -204,7 +220,10 @@ static void test_logpen(void) obj_type = GetObjectType(hpen); /* for some reason XP differentiates PS_NULL here */ if (pen[i].style == PS_NULL) + { ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type); + ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n"); + } else ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type); @@ -219,12 +238,17 @@ static void test_logpen(void) break; case PS_USERSTYLE: - ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style), + ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style) || + broken(size == 0 && GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */ "GetObject returned %d, error %d\n", size, GetLastError()); break; default: - ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry), + ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) || + broken(size == sizeof(LOGPEN)) || /* Win9x */ + broken(pen[i].style == PS_ALTERNATE && + size == 0 && + GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */ "GetObject returned %d, error %d\n", size, GetLastError()); break; } @@ -233,7 +257,9 @@ static void test_logpen(void) memset(&elp, 0xb0, sizeof(elp)); SetLastError(0xdeadbeef); size = GetObject(hpen, sizeof(elp.elpPenStyle), &elp); - ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError()); + ok(!size || + broken(size == sizeof(elp.elpPenStyle)), /* Win9x */ + "GetObject should fail: size %d, error %d\n", size, GetLastError()); /* see how larger buffer sizes are handled */ memset(&ext_pen, 0xb0, sizeof(ext_pen)); @@ -252,11 +278,12 @@ static void test_logpen(void) /* for PS_NULL it also works this way */ memset(&elp, 0xb0, sizeof(elp)); + memset(&unset_hatch, 0xb0, sizeof(unset_hatch)); SetLastError(0xdeadbeef); size = GetObject(hpen, sizeof(elp), &elp); ok(size == sizeof(EXTLOGPEN), "GetObject returned %d, error %d\n", size, GetLastError()); - ok(ext_pen.elp.elpHatch == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen.elp.elpHatch); + ok(ext_pen.elp.elpHatch == unset_hatch, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen.elp.elpHatch); ok(ext_pen.elp.elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %x\n", ext_pen.elp.elpNumEntries); break; @@ -270,7 +297,11 @@ static void test_logpen(void) break; default: - ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry), + ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) || + broken(size == sizeof(LOGPEN)) || /* Win9x */ + broken(pen[i].style == PS_ALTERNATE && + size == 0 && + GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */ "GetObject returned %d, error %d\n", size, GetLastError()); ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch); ok(ext_pen.elp.elpNumEntries == 0, "expected 0, got %x\n", ext_pen.elp.elpNumEntries); @@ -498,13 +529,18 @@ static void test_ps_userstyle(void) pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 3, NULL); ok(pen == 0, "ExtCreatePen should fail\n"); + if (pen == 0 && GetLastError() == 0xdeadbeef) + { + win_skip("Looks like 9x, skipping PS_USERSTYLE tests\n"); + return; + } expect(ERROR_INVALID_PARAMETER, GetLastError()); DeleteObject(pen); SetLastError(0xdeadbeef); pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 0, style); ok(pen == 0, "ExtCreatePen should fail\n"); - expect(0xdeadbeef, GetLastError()); + expect2(0xdeadbeef, ERROR_INVALID_PARAMETER, GetLastError()); DeleteObject(pen); SetLastError(0xdeadbeef); @@ -536,7 +572,7 @@ static void test_ps_userstyle(void) ok(pen != 0, "ExtCreatePen should not fail\n"); size = GetObject(pen, sizeof(ext_pen), &ext_pen); - expect(88, size); + expect(FIELD_OFFSET(EXTLOGPEN,elpStyleEntry[16]), size); for(i = 0; i < 16; i++) expect(style[i], ext_pen.elp.elpStyleEntry[i]); diff --git a/rostests/winetests/gdiplus/brush.c b/rostests/winetests/gdiplus/brush.c index 70eac03ef8d..b6fbe3044ef 100644 --- a/rostests/winetests/gdiplus/brush.c +++ b/rostests/winetests/gdiplus/brush.c @@ -21,8 +21,10 @@ #include "windows.h" #include "gdiplus.h" #include "wine/test.h" +#include #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) +#define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got) static void test_constructor_destructor(void) { @@ -49,11 +51,447 @@ static void test_type(void) GdipCreateSolidFill((ARGB)0xdeadbeef, &brush); status = GdipGetBrushType((GpBrush*)brush, &bt); - expect(status, Ok); - expect(bt, BrushTypeSolidColor); + expect(Ok, status); + expect(BrushTypeSolidColor, bt); GdipDeleteBrush((GpBrush*) brush); } +static GpPointF blendcount_ptf[] = {{0.0, 0.0}, + {50.0, 50.0}}; +static void test_gradientblendcount(void) +{ + GpStatus status; + GpPathGradient *brush; + INT count; + + status = GdipCreatePathGradient(blendcount_ptf, 2, WrapModeClamp, &brush); + expect(Ok, status); + + status = GdipGetPathGradientBlendCount(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetPathGradientBlendCount(NULL, &count); + expect(InvalidParameter, status); + status = GdipGetPathGradientBlendCount(brush, NULL); + expect(InvalidParameter, status); + + status = GdipGetPathGradientBlendCount(brush, &count); + expect(Ok, status); + expect(1, count); + + GdipDeleteBrush((GpBrush*) brush); +} + +static GpPointF getblend_ptf[] = {{0.0, 0.0}, + {50.0, 50.0}}; +static void test_getblend(void) +{ + GpStatus status; + GpPathGradient *brush; + REAL blends[4]; + REAL pos[4]; + + status = GdipCreatePathGradient(getblend_ptf, 2, WrapModeClamp, &brush); + expect(Ok, status); + + /* check some invalid parameters combinations */ + status = GdipGetPathGradientBlend(NULL, NULL, NULL, -1); + expect(InvalidParameter, status); + status = GdipGetPathGradientBlend(brush,NULL, NULL, -1); + expect(InvalidParameter, status); + status = GdipGetPathGradientBlend(NULL, blends,NULL, -1); + expect(InvalidParameter, status); + status = GdipGetPathGradientBlend(NULL, NULL, pos, -1); + expect(InvalidParameter, status); + status = GdipGetPathGradientBlend(NULL, NULL, NULL, 1); + expect(InvalidParameter, status); + + blends[0] = (REAL)0xdeadbeef; + pos[0] = (REAL)0xdeadbeef; + status = GdipGetPathGradientBlend(brush, blends, pos, 1); + expect(Ok, status); + expectf(1.0, blends[0]); + expectf((REAL)0xdeadbeef, pos[0]); + + GdipDeleteBrush((GpBrush*) brush); +} + +static GpPointF getbounds_ptf[] = {{0.0, 20.0}, + {50.0, 50.0}, + {21.0, 25.0}, + {25.0, 46.0}}; +static void test_getbounds(void) +{ + GpStatus status; + GpPathGradient *brush; + GpRectF bounds; + + status = GdipCreatePathGradient(getbounds_ptf, 4, WrapModeClamp, &brush); + expect(Ok, status); + + status = GdipGetPathGradientRect(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetPathGradientRect(brush, NULL); + expect(InvalidParameter, status); + status = GdipGetPathGradientRect(NULL, &bounds); + expect(InvalidParameter, status); + + status = GdipGetPathGradientRect(brush, &bounds); + expect(Ok, status); + expectf(0.0, bounds.X); + expectf(20.0, bounds.Y); + expectf(50.0, bounds.Width); + expectf(30.0, bounds.Height); + + GdipDeleteBrush((GpBrush*) brush); +} + +static void test_getgamma(void) +{ + GpStatus status; + GpLineGradient *line; + GpPointF start, end; + BOOL gamma; + + start.X = start.Y = 0.0; + end.X = end.Y = 100.0; + + status = GdipCreateLineBrush(&start, &end, (ARGB)0xdeadbeef, 0xdeadbeef, WrapModeTile, &line); + expect(Ok, status); + + /* NULL arguments */ + status = GdipGetLineGammaCorrection(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetLineGammaCorrection(line, NULL); + expect(InvalidParameter, status); + status = GdipGetLineGammaCorrection(NULL, &gamma); + expect(InvalidParameter, status); + + GdipDeleteBrush((GpBrush*)line); +} + +static void test_transform(void) +{ + GpStatus status; + GpTexture *texture; + GpGraphics *graphics = NULL; + GpBitmap *bitmap; + HDC hdc = GetDC(0); + GpMatrix *m, *m1; + BOOL res; + + status = GdipCreateMatrix2(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, &m); + expect(Ok, status); + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + status = GdipCreateBitmapFromGraphics(1, 1, graphics, &bitmap); + expect(Ok, status); + + status = GdipCreateTexture((GpImage*)bitmap, WrapModeTile, &texture); + expect(Ok, status); + + /* NULL */ + status = GdipGetTextureTransform(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetTextureTransform(texture, NULL); + expect(InvalidParameter, status); + + /* get default value - identity matrix */ + status = GdipGetTextureTransform(texture, m); + expect(Ok, status); + status = GdipIsMatrixIdentity(m, &res); + expect(Ok, status); + expect(TRUE, res); + /* set and get then */ + status = GdipCreateMatrix2(2.0, 0.0, 0.0, 2.0, 0.0, 0.0, &m1); + expect(Ok, status); + status = GdipSetTextureTransform(texture, m1); + expect(Ok, status); + status = GdipGetTextureTransform(texture, m); + expect(Ok, status); + status = GdipIsMatrixEqual(m, m1, &res); + expect(Ok, status); + expect(TRUE, res); + /* reset */ + status = GdipResetTextureTransform(texture); + expect(Ok, status); + status = GdipGetTextureTransform(texture, m); + expect(Ok, status); + status = GdipIsMatrixIdentity(m, &res); + expect(Ok, status); + expect(TRUE, res); + + status = GdipDeleteBrush((GpBrush*)texture); + expect(Ok, status); + + status = GdipDeleteMatrix(m1); + expect(Ok, status); + status = GdipDeleteMatrix(m); + expect(Ok, status); + status = GdipDisposeImage((GpImage*)bitmap); + expect(Ok, status); + status = GdipDeleteGraphics(graphics); + expect(Ok, status); + ReleaseDC(0, hdc); +} + +static void test_texturewrap(void) +{ + GpStatus status; + GpTexture *texture; + GpGraphics *graphics = NULL; + GpBitmap *bitmap; + HDC hdc = GetDC(0); + GpWrapMode wrap; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + status = GdipCreateBitmapFromGraphics(1, 1, graphics, &bitmap); + expect(Ok, status); + + status = GdipCreateTexture((GpImage*)bitmap, WrapModeTile, &texture); + expect(Ok, status); + + /* NULL */ + status = GdipGetTextureWrapMode(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetTextureWrapMode(texture, NULL); + expect(InvalidParameter, status); + status = GdipGetTextureWrapMode(NULL, &wrap); + expect(InvalidParameter, status); + + /* get */ + wrap = WrapModeClamp; + status = GdipGetTextureWrapMode(texture, &wrap); + expect(Ok, status); + expect(WrapModeTile, wrap); + /* set, then get */ + wrap = WrapModeClamp; + status = GdipSetTextureWrapMode(texture, wrap); + expect(Ok, status); + wrap = WrapModeTile; + status = GdipGetTextureWrapMode(texture, &wrap); + expect(Ok, status); + expect(WrapModeClamp, wrap); + + status = GdipDeleteBrush((GpBrush*)texture); + expect(Ok, status); + status = GdipDisposeImage((GpImage*)bitmap); + expect(Ok, status); + status = GdipDeleteGraphics(graphics); + expect(Ok, status); + ReleaseDC(0, hdc); +} + +static void test_gradientgetrect(void) +{ + GpLineGradient *brush; + GpRectF rectf; + GpStatus status; + GpPointF pt1, pt2; + + pt1.X = pt1.Y = 1.0; + pt2.X = pt2.Y = 100.0; + status = GdipCreateLineBrush(&pt1, &pt2, 0, 0, WrapModeTile, &brush); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(brush, &rectf); + expect(Ok, status); + expectf(1.0, rectf.X); + expectf(1.0, rectf.Y); + expectf(99.0, rectf.Width); + expectf(99.0, rectf.Height); + status = GdipDeleteBrush((GpBrush*)brush); + /* vertical gradient */ + pt1.X = pt1.Y = pt2.X = 0.0; + pt2.Y = 10.0; + status = GdipCreateLineBrush(&pt1, &pt2, 0, 0, WrapModeTile, &brush); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(brush, &rectf); + expect(Ok, status); + todo_wine expectf(-5.0, rectf.X); + expectf(0.0, rectf.Y); + todo_wine expectf(10.0, rectf.Width); + expectf(10.0, rectf.Height); + status = GdipDeleteBrush((GpBrush*)brush); + /* horizontal gradient */ + pt1.X = pt1.Y = pt2.Y = 0.0; + pt2.X = 10.0; + status = GdipCreateLineBrush(&pt1, &pt2, 0, 0, WrapModeTile, &brush); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(brush, &rectf); + expect(Ok, status); + expectf(0.0, rectf.X); + todo_wine expectf(-5.0, rectf.Y); + expectf(10.0, rectf.Width); + todo_wine expectf(10.0, rectf.Height); + status = GdipDeleteBrush((GpBrush*)brush); + /* slope = -1 */ + pt1.X = pt1.Y = 0.0; + pt2.X = 20.0; + pt2.Y = -20.0; + status = GdipCreateLineBrush(&pt1, &pt2, 0, 0, WrapModeTile, &brush); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(brush, &rectf); + expect(Ok, status); + expectf(0.0, rectf.X); + expectf(-20.0, rectf.Y); + expectf(20.0, rectf.Width); + expectf(20.0, rectf.Height); + status = GdipDeleteBrush((GpBrush*)brush); + /* slope = 1/100 */ + pt1.X = pt1.Y = 0.0; + pt2.X = 100.0; + pt2.Y = 1.0; + status = GdipCreateLineBrush(&pt1, &pt2, 0, 0, WrapModeTile, &brush); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(brush, &rectf); + expect(Ok, status); + expectf(0.0, rectf.X); + expectf(0.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(1.0, rectf.Height); + status = GdipDeleteBrush((GpBrush*)brush); + /* from rect with LinearGradientModeHorizontal */ + rectf.X = rectf.Y = 10.0; + rectf.Width = rectf.Height = 100.0; + status = GdipCreateLineBrushFromRect(&rectf, 0, 0, LinearGradientModeHorizontal, + WrapModeTile, &brush); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(brush, &rectf); + expect(Ok, status); + expectf(10.0, rectf.X); + expectf(10.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(100.0, rectf.Height); + status = GdipDeleteBrush((GpBrush*)brush); + /* passing negative Width/Height to LinearGradientModeHorizontal */ + rectf.X = rectf.Y = 10.0; + rectf.Width = rectf.Height = -100.0; + status = GdipCreateLineBrushFromRect(&rectf, 0, 0, LinearGradientModeHorizontal, + WrapModeTile, &brush); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(brush, &rectf); + expect(Ok, status); + expectf(10.0, rectf.X); + expectf(10.0, rectf.Y); + expectf(-100.0, rectf.Width); + expectf(-100.0, rectf.Height); + status = GdipDeleteBrush((GpBrush*)brush); +} + +static void test_lineblend(void) +{ + GpLineGradient *brush; + GpStatus status; + GpPointF pt1, pt2; + INT count=10; + int i; + const REAL factors[5] = {0.0f, 0.1f, 0.5f, 0.9f, 1.0f}; + const REAL positions[5] = {0.0f, 0.2f, 0.5f, 0.8f, 1.0f}; + REAL res_factors[6] = {0.3f, 0.0f, 0.0f, 0.0f, 0.0f}; + REAL res_positions[6] = {0.3f, 0.0f, 0.0f, 0.0f, 0.0f}; + + pt1.X = pt1.Y = 1.0; + pt2.X = pt2.Y = 100.0; + status = GdipCreateLineBrush(&pt1, &pt2, 0, 0, WrapModeTile, &brush); + expect(Ok, status); + + status = GdipGetLineBlendCount(NULL, &count); + expect(InvalidParameter, status); + + status = GdipGetLineBlendCount(brush, NULL); + expect(InvalidParameter, status); + + status = GdipGetLineBlendCount(brush, &count); + expect(Ok, status); + expect(1, count); + + status = GdipGetLineBlend(NULL, res_factors, res_positions, 1); + expect(InvalidParameter, status); + + status = GdipGetLineBlend(brush, NULL, res_positions, 1); + expect(InvalidParameter, status); + + status = GdipGetLineBlend(brush, res_factors, NULL, 1); + expect(InvalidParameter, status); + + status = GdipGetLineBlend(brush, res_factors, res_positions, 0); + expect(InvalidParameter, status); + + status = GdipGetLineBlend(brush, res_factors, res_positions, -1); + expect(InvalidParameter, status); + + status = GdipGetLineBlend(brush, res_factors, res_positions, 1); + expect(Ok, status); + + status = GdipGetLineBlend(brush, res_factors, res_positions, 2); + expect(Ok, status); + + status = GdipSetLineBlend(NULL, factors, positions, 5); + expect(InvalidParameter, status); + + status = GdipSetLineBlend(brush, NULL, positions, 5); + expect(InvalidParameter, status); + + status = GdipSetLineBlend(brush, factors, NULL, 5); + expect(InvalidParameter, status); + + status = GdipSetLineBlend(brush, factors, positions, 0); + expect(InvalidParameter, status); + + status = GdipSetLineBlend(brush, factors, positions, -1); + expect(InvalidParameter, status); + + /* leave off the 0.0 position */ + status = GdipSetLineBlend(brush, &factors[1], &positions[1], 4); + expect(InvalidParameter, status); + + /* leave off the 1.0 position */ + status = GdipSetLineBlend(brush, factors, positions, 4); + expect(InvalidParameter, status); + + status = GdipSetLineBlend(brush, factors, positions, 5); + expect(Ok, status); + + status = GdipGetLineBlendCount(brush, &count); + expect(Ok, status); + expect(5, count); + + status = GdipGetLineBlend(brush, res_factors, res_positions, 4); + expect(InsufficientBuffer, status); + + status = GdipGetLineBlend(brush, res_factors, res_positions, 5); + expect(Ok, status); + + for (i=0; i<5; i++) + { + expectf(factors[i], res_factors[i]); + expectf(positions[i], res_positions[i]); + } + + status = GdipGetLineBlend(brush, res_factors, res_positions, 6); + expect(Ok, status); + + status = GdipSetLineBlend(brush, factors, positions, 1); + expect(Ok, status); + + status = GdipGetLineBlendCount(brush, &count); + expect(Ok, status); + expect(1, count); + + status = GdipGetLineBlend(brush, res_factors, res_positions, 1); + expect(Ok, status); + + status = GdipDeleteBrush((GpBrush*)brush); + expect(Ok, status); +} START_TEST(brush) { @@ -69,6 +507,14 @@ START_TEST(brush) test_constructor_destructor(); test_type(); + test_gradientblendcount(); + test_getblend(); + test_getbounds(); + test_getgamma(); + test_transform(); + test_texturewrap(); + test_gradientgetrect(); + test_lineblend(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/customlinecap.c b/rostests/winetests/gdiplus/customlinecap.c new file mode 100644 index 00000000000..78a8c704830 --- /dev/null +++ b/rostests/winetests/gdiplus/customlinecap.c @@ -0,0 +1,202 @@ +/* + * Unit test suite for customlinecap + * + * Copyright (C) 2008 Nikolay Sivov + * + * 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 + */ + +#include "windows.h" +#include "gdiplus.h" +#include "wine/test.h" + +#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) +#define expectf(expected, got) ok(got == expected, "Expected %.2f, got %.2f\n", expected, got) + +static void test_constructor_destructor(void) +{ + GpCustomLineCap *custom; + GpPath *path, *path2; + GpStatus stat; + + stat = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, stat); + stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0); + expect(Ok, stat); + + stat = GdipCreatePath(FillModeAlternate, &path2); + expect(Ok, stat); + stat = GdipAddPathRectangle(path2, 5.0, 5.0, 10.0, 10.0); + expect(Ok, stat); + + /* NULL args */ + stat = GdipCreateCustomLineCap(NULL, NULL, LineCapFlat, 0.0, NULL); + expect(InvalidParameter, stat); + stat = GdipCreateCustomLineCap(path, NULL, LineCapFlat, 0.0, NULL); + expect(InvalidParameter, stat); + stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, NULL); + expect(InvalidParameter, stat); + stat = GdipCreateCustomLineCap(NULL, NULL, LineCapFlat, 0.0, &custom); + expect(InvalidParameter, stat); + stat = GdipDeleteCustomLineCap(NULL); + expect(InvalidParameter, stat); + + /* valid args */ + stat = GdipCreateCustomLineCap(NULL, path2, LineCapFlat, 0.0, &custom); + expect(Ok, stat); + stat = GdipDeleteCustomLineCap(custom); + expect(Ok, stat); + /* it's strange but native returns NotImplemented on stroke == NULL */ + stat = GdipCreateCustomLineCap(path, NULL, LineCapFlat, 10.0, &custom); + todo_wine expect(NotImplemented, stat); + + GdipDeletePath(path2); + GdipDeletePath(path); +} + +static void test_linejoin(void) +{ + GpCustomLineCap *custom; + GpPath *path; + GpLineJoin join; + GpStatus stat; + + stat = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, stat); + stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0); + expect(Ok, stat); + + stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom); + expect(Ok, stat); + + /* NULL args */ + stat = GdipGetCustomLineCapStrokeJoin(NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipGetCustomLineCapStrokeJoin(custom, NULL); + expect(InvalidParameter, stat); + stat = GdipGetCustomLineCapStrokeJoin(NULL, &join); + expect(InvalidParameter, stat); + stat = GdipSetCustomLineCapStrokeJoin(NULL, LineJoinBevel); + expect(InvalidParameter, stat); + + /* LineJoinMiter is default */ + stat = GdipGetCustomLineCapStrokeJoin(custom, &join); + expect(Ok, stat); + expect(LineJoinMiter, join); + + /* set/get */ + stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinBevel); + expect(Ok, stat); + stat = GdipGetCustomLineCapStrokeJoin(custom, &join); + expect(Ok, stat); + expect(LineJoinBevel, join); + stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinRound); + expect(Ok, stat); + stat = GdipGetCustomLineCapStrokeJoin(custom, &join); + expect(Ok, stat); + expect(LineJoinRound, join); + stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinMiterClipped); + expect(Ok, stat); + stat = GdipGetCustomLineCapStrokeJoin(custom, &join); + expect(Ok, stat); + expect(LineJoinMiterClipped, join); + + GdipDeleteCustomLineCap(custom); + GdipDeletePath(path); +} + +static void test_inset(void) +{ + GpCustomLineCap *custom; + GpPath *path; + REAL inset; + GpStatus stat; + + stat = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, stat); + stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0); + expect(Ok, stat); + + stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom); + expect(Ok, stat); + + /* NULL args */ + stat = GdipGetCustomLineCapBaseInset(NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipGetCustomLineCapBaseInset(NULL, &inset); + expect(InvalidParameter, stat); + stat = GdipGetCustomLineCapBaseInset(custom, NULL); + expect(InvalidParameter, stat); + /* valid args */ + inset = (REAL)0xdeadbeef; + stat = GdipGetCustomLineCapBaseInset(custom, &inset); + expect(Ok, stat); + expectf(0.0, inset); + + GdipDeleteCustomLineCap(custom); + GdipDeletePath(path); +} + +static void test_scale(void) +{ + GpCustomLineCap *custom; + GpPath *path; + REAL scale; + GpStatus stat; + + stat = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, stat); + stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0); + expect(Ok, stat); + + stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom); + expect(Ok, stat); + + /* NULL args */ + stat = GdipGetCustomLineCapWidthScale(NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipGetCustomLineCapWidthScale(NULL, &scale); + expect(InvalidParameter, stat); + stat = GdipGetCustomLineCapWidthScale(custom, NULL); + expect(InvalidParameter, stat); + /* valid args */ + scale = (REAL)0xdeadbeef; + stat = GdipGetCustomLineCapWidthScale(custom, &scale); + expect(Ok, stat); + expectf(1.0, scale); + + GdipDeleteCustomLineCap(custom); + GdipDeletePath(path); +} + +START_TEST(customlinecap) +{ + struct GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + + gdiplusStartupInput.GdiplusVersion = 1; + gdiplusStartupInput.DebugEventCallback = NULL; + gdiplusStartupInput.SuppressBackgroundThread = 0; + gdiplusStartupInput.SuppressExternalCodecs = 0; + + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + test_constructor_destructor(); + test_linejoin(); + test_inset(); + test_scale(); + + GdiplusShutdown(gdiplusToken); +} diff --git a/rostests/winetests/gdiplus/font.c b/rostests/winetests/gdiplus/font.c index 59a8d532177..7f334531dce 100644 --- a/rostests/winetests/gdiplus/font.c +++ b/rostests/winetests/gdiplus/font.c @@ -25,7 +25,7 @@ #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) static const WCHAR arial[] = {'A','r','i','a','l','\0'}; -static const WCHAR nonexistant[] = {'T','h','i','s','F','o','n','t','s','h','o','u','l','d','N','o','t','E','x','i','s','t','\0'}; +static const WCHAR nonexistent[] = {'T','h','i','s','F','o','n','t','s','h','o','u','l','d','N','o','t','E','x','i','s','t','\0'}; static const WCHAR MSSansSerif[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; static const WCHAR MicrosoftSansSerif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'}; @@ -41,18 +41,24 @@ static const char *debugstr_w(LPCWSTR str) static void test_createfont(void) { - GpFontFamily* fontfamily = NULL; + GpFontFamily* fontfamily = NULL, *fontfamily2; GpFont* font = NULL; GpStatus stat; Unit unit; UINT i; REAL size; + WCHAR familyname[LF_FACESIZE]; - stat = GdipCreateFontFamilyFromName(nonexistant, NULL, &fontfamily); + stat = GdipCreateFontFamilyFromName(nonexistent, NULL, &fontfamily); expect (FontFamilyNotFound, stat); stat = GdipDeleteFont(font); expect (InvalidParameter, stat); stat = GdipCreateFontFamilyFromName(arial, NULL, &fontfamily); + if(stat == FontFamilyNotFound) + { + skip("Arial not installed\n"); + return; + } expect (Ok, stat); stat = GdipCreateFont(fontfamily, 12, FontStyleRegular, UnitPoint, &font); expect (Ok, stat); @@ -60,6 +66,15 @@ static void test_createfont(void) expect (Ok, stat); expect (UnitPoint, unit); + stat = GdipGetFamily(font, &fontfamily2); + expect(Ok, stat); + stat = GdipGetFamilyName(fontfamily2, familyname, 0); + expect(Ok, stat); + ok (lstrcmpiW(arial, familyname) == 0, "Expected arial, got %s\n", + debugstr_w(familyname)); + stat = GdipDeleteFontFamily(fontfamily2); + expect(Ok, stat); + /* Test to see if returned size is based on unit (its not) */ GdipGetFontSize(font, &size); ok (size == 12, "Expected 12, got %f\n", size); @@ -76,69 +91,88 @@ static void test_createfont(void) expect (i, unit); GdipDeleteFont(font); } + + GdipDeleteFontFamily(fontfamily); } static void test_logfont(void) { - LOGFONTW lfw, lfw2; + LOGFONTA lfa, lfa2; GpFont *font; GpStatus stat; GpGraphics *graphics; HDC hdc = GetDC(0); + INT style; GdipCreateFromHDC(hdc, &graphics); - memset(&lfw, 0, sizeof(LOGFONTW)); - memset(&lfw2, 0xff, sizeof(LOGFONTW)); - memcpy(&lfw.lfFaceName, arial, 6 * sizeof(WCHAR)); + memset(&lfa, 0, sizeof(LOGFONTA)); + memset(&lfa2, 0xff, sizeof(LOGFONTA)); - stat = GdipCreateFontFromLogfontW(hdc, &lfw, &font); + /* empty FaceName */ + lfa.lfFaceName[0] = 0; + stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); + expect(NotTrueTypeFont, stat); + + lstrcpyA(lfa.lfFaceName, "Arial"); + + stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); + if (stat == FileNotFound) + { + skip("Arial not installed.\n"); + return; + } expect(Ok, stat); - stat = GdipGetLogFontW(font, graphics, &lfw2); + stat = GdipGetLogFontA(font, graphics, &lfa2); expect(Ok, stat); - ok(lfw2.lfHeight < 0, "Expected negative height\n"); - expect(0, lfw2.lfWidth); - expect(0, lfw2.lfEscapement); - expect(0, lfw2.lfOrientation); - ok((lfw2.lfWeight >= 100) && (lfw2.lfWeight <= 900), "Expected weight to be set\n"); - expect(0, lfw2.lfItalic); - expect(0, lfw2.lfUnderline); - expect(0, lfw2.lfStrikeOut); - expect(0, lfw2.lfCharSet); - expect(0, lfw2.lfOutPrecision); - expect(0, lfw2.lfClipPrecision); - expect(0, lfw2.lfQuality); - expect(0, lfw2.lfPitchAndFamily); + ok(lfa2.lfHeight < 0, "Expected negative height\n"); + expect(0, lfa2.lfWidth); + expect(0, lfa2.lfEscapement); + expect(0, lfa2.lfOrientation); + ok((lfa2.lfWeight >= 100) && (lfa2.lfWeight <= 900), "Expected weight to be set\n"); + expect(0, lfa2.lfItalic); + expect(0, lfa2.lfUnderline); + expect(0, lfa2.lfStrikeOut); + expect(GetTextCharset(hdc), lfa2.lfCharSet); + expect(0, lfa2.lfOutPrecision); + expect(0, lfa2.lfClipPrecision); + expect(0, lfa2.lfQuality); + expect(0, lfa2.lfPitchAndFamily); GdipDeleteFont(font); - memset(&lfw, 0, sizeof(LOGFONTW)); - lfw.lfHeight = 25; - lfw.lfWidth = 25; - lfw.lfEscapement = lfw.lfOrientation = 50; - lfw.lfItalic = lfw.lfUnderline = lfw.lfStrikeOut = TRUE; + memset(&lfa, 0, sizeof(LOGFONTA)); + lfa.lfHeight = 25; + lfa.lfWidth = 25; + lfa.lfEscapement = lfa.lfOrientation = 50; + lfa.lfItalic = lfa.lfUnderline = lfa.lfStrikeOut = TRUE; - memset(&lfw2, 0xff, sizeof(LOGFONTW)); - memcpy(&lfw.lfFaceName, arial, 6 * sizeof(WCHAR)); + memset(&lfa2, 0xff, sizeof(LOGFONTA)); + lstrcpyA(lfa.lfFaceName, "Arial"); - stat = GdipCreateFontFromLogfontW(hdc, &lfw, &font); + stat = GdipCreateFontFromLogfontA(hdc, &lfa, &font); expect(Ok, stat); - stat = GdipGetLogFontW(font, graphics, &lfw2); + stat = GdipGetLogFontA(font, graphics, &lfa2); expect(Ok, stat); - ok(lfw2.lfHeight < 0, "Expected negative height\n"); - expect(0, lfw2.lfWidth); - expect(0, lfw2.lfEscapement); - expect(0, lfw2.lfOrientation); - ok((lfw2.lfWeight >= 100) && (lfw2.lfWeight <= 900), "Expected weight to be set\n"); - expect(TRUE, lfw2.lfItalic); - expect(TRUE, lfw2.lfUnderline); - expect(TRUE, lfw2.lfStrikeOut); - expect(0, lfw2.lfCharSet); - expect(0, lfw2.lfOutPrecision); - expect(0, lfw2.lfClipPrecision); - expect(0, lfw2.lfQuality); - expect(0, lfw2.lfPitchAndFamily); + ok(lfa2.lfHeight < 0, "Expected negative height\n"); + expect(0, lfa2.lfWidth); + expect(0, lfa2.lfEscapement); + expect(0, lfa2.lfOrientation); + ok((lfa2.lfWeight >= 100) && (lfa2.lfWeight <= 900), "Expected weight to be set\n"); + expect(TRUE, lfa2.lfItalic); + expect(TRUE, lfa2.lfUnderline); + expect(TRUE, lfa2.lfStrikeOut); + expect(GetTextCharset(hdc), lfa2.lfCharSet); + expect(0, lfa2.lfOutPrecision); + expect(0, lfa2.lfClipPrecision); + expect(0, lfa2.lfQuality); + expect(0, lfa2.lfPitchAndFamily); + + stat = GdipGetFontStyle(font, &style); + expect(Ok, stat); + ok (style == (FontStyleItalic | FontStyleUnderline | FontStyleStrikeout), + "Expected , got %d\n", style); GdipDeleteFont(font); @@ -148,91 +182,175 @@ static void test_logfont(void) static void test_fontfamily (void) { - GpFontFamily** family = NULL; + GpFontFamily *family, *clonedFontFamily; WCHAR itsName[LF_FACESIZE]; GpStatus stat; /* FontFamily can not be NULL */ - stat = GdipCreateFontFamilyFromName (arial , NULL, family); + stat = GdipCreateFontFamilyFromName (arial , NULL, NULL); expect (InvalidParameter, stat); - family = GdipAlloc (sizeof (GpFontFamily*)); - /* FontFamily must be able to actually find the family. - * If it can't, any subsequent calls should fail - * - * We currently fail (meaning we don't) because we don't actually - * test to see if we can successfully get a family + * If it can't, any subsequent calls should fail. */ - stat = GdipCreateFontFamilyFromName (nonexistant, NULL, family); + stat = GdipCreateFontFamilyFromName (nonexistent, NULL, &family); expect (FontFamilyNotFound, stat); - stat = GdipGetFamilyName (*family,itsName, LANG_NEUTRAL); - expect (InvalidParameter, stat); - ok ((lstrcmpiW(itsName,nonexistant) != 0), - "Expected a non-zero value for nonexistant font!\n"); - stat = GdipDeleteFontFamily(*family); - expect (InvalidParameter, stat); - stat = GdipCreateFontFamilyFromName (arial, NULL, family); + /* Bitmap fonts are not found */ +todo_wine +{ + stat = GdipCreateFontFamilyFromName (MSSansSerif, NULL, &family); + expect (FontFamilyNotFound, stat); +} + + stat = GdipCreateFontFamilyFromName (arial, NULL, &family); + if(stat == FontFamilyNotFound) + { + skip("Arial not installed\n"); + return; + } expect (Ok, stat); - stat = GdipGetFamilyName (*family, itsName, LANG_NEUTRAL); + stat = GdipGetFamilyName (family, itsName, LANG_NEUTRAL); expect (Ok, stat); expect (0, lstrcmpiW(itsName,arial)); if (0) { /* Crashes on Windows XP SP2, Vista, and so Wine as well */ - stat = GdipGetFamilyName (*family, NULL, LANG_NEUTRAL); + stat = GdipGetFamilyName (family, NULL, LANG_NEUTRAL); expect (Ok, stat); } - stat = GdipDeleteFontFamily(*family); + /* Make sure we don't read old data */ + ZeroMemory (itsName, sizeof(itsName)); + stat = GdipCloneFontFamily(family, &clonedFontFamily); expect (Ok, stat); + GdipDeleteFontFamily(family); + stat = GdipGetFamilyName(clonedFontFamily, itsName, LANG_NEUTRAL); + expect(Ok, stat); + expect(0, lstrcmpiW(itsName, arial)); - GdipFree (family); + GdipDeleteFontFamily(clonedFontFamily); } +static void test_fontfamily_properties (void) +{ + GpFontFamily* FontFamily = NULL; + GpStatus stat; + UINT16 result = 0; + + stat = GdipCreateFontFamilyFromName(arial, NULL, &FontFamily); + if(stat == FontFamilyNotFound) + skip("Arial not installed\n"); + else + { + stat = GdipGetLineSpacing(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok (result == 2355, "Expected 2355, got %d\n", result); + result = 0; + stat = GdipGetEmHeight(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok(result == 2048, "Expected 2048, got %d\n", result); + result = 0; + stat = GdipGetCellAscent(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok(result == 1854, "Expected 1854, got %d\n", result); + result = 0; + stat = GdipGetCellDescent(FontFamily, FontStyleRegular, &result); + ok(result == 434, "Expected 434, got %d\n", result); + GdipDeleteFontFamily(FontFamily); + } + + stat = GdipCreateFontFamilyFromName(TimesNewRoman, NULL, &FontFamily); + if(stat == FontFamilyNotFound) + skip("Times New Roman not installed\n"); + else + { + result = 0; + stat = GdipGetLineSpacing(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok(result == 2355, "Expected 2355, got %d\n", result); + result = 0; + stat = GdipGetEmHeight(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok(result == 2048, "Expected 2048, got %d\n", result); + result = 0; + stat = GdipGetCellAscent(FontFamily, FontStyleRegular, &result); + expect(Ok, stat); + ok(result == 1825, "Expected 1825, got %d\n", result); + result = 0; + stat = GdipGetCellDescent(FontFamily, FontStyleRegular, &result); + ok(result == 443, "Expected 443 got %d\n", result); + GdipDeleteFontFamily(FontFamily); + } +} static void test_getgenerics (void) { GpStatus stat; - GpFontFamily** family; + GpFontFamily* family; WCHAR familyName[LF_FACESIZE]; ZeroMemory(familyName, sizeof(familyName)/sizeof(WCHAR)); - family = GdipAlloc (sizeof (GpFontFamily*)); - - stat = GdipGetGenericFontFamilySansSerif (family); + stat = GdipGetGenericFontFamilySansSerif (&family); + if (stat == FontFamilyNotFound) + { + skip("Microsoft Sans Serif not installed\n"); + goto serif; + } expect (Ok, stat); - stat = GdipGetFamilyName (*family, familyName, LANG_NEUTRAL); + stat = GdipGetFamilyName (family, familyName, LANG_NEUTRAL); expect (Ok, stat); ok ((lstrcmpiW(familyName, MicrosoftSansSerif) == 0) || (lstrcmpiW(familyName,MSSansSerif) == 0), "Expected Microsoft Sans Serif or MS Sans Serif, got %s\n", debugstr_w(familyName)); - stat = GdipDeleteFontFamily (*family); + stat = GdipDeleteFontFamily (family); expect (Ok, stat); - stat = GdipGetGenericFontFamilySerif (family); +serif: + stat = GdipGetGenericFontFamilySerif (&family); + if (stat == FontFamilyNotFound) + { + skip("Times New Roman not installed\n"); + goto monospace; + } expect (Ok, stat); - stat = GdipGetFamilyName (*family, familyName, LANG_NEUTRAL); + stat = GdipGetFamilyName (family, familyName, LANG_NEUTRAL); expect (Ok, stat); ok (lstrcmpiW(familyName, TimesNewRoman) == 0, "Expected Times New Roman, got %s\n", debugstr_w(familyName)); - stat = GdipDeleteFontFamily (*family); + stat = GdipDeleteFontFamily (family); expect (Ok, stat); - stat = GdipGetGenericFontFamilyMonospace (family); +monospace: + stat = GdipGetGenericFontFamilyMonospace (&family); + if (stat == FontFamilyNotFound) + { + skip("Courier New not installed\n"); + return; + } expect (Ok, stat); - stat = GdipGetFamilyName (*family, familyName, LANG_NEUTRAL); + stat = GdipGetFamilyName (family, familyName, LANG_NEUTRAL); expect (Ok, stat); ok (lstrcmpiW(familyName, CourierNew) == 0, "Expected Courier New, got %s\n", debugstr_w(familyName)); - stat = GdipDeleteFontFamily (*family); + stat = GdipDeleteFontFamily (family); expect (Ok, stat); +} - GdipFree (family); +static void test_installedfonts (void) +{ + GpStatus stat; + GpFontCollection* collection=NULL; + + stat = GdipNewInstalledFontCollection(NULL); + expect (InvalidParameter, stat); + + stat = GdipNewInstalledFontCollection(&collection); + expect (Ok, stat); + ok (collection != NULL, "got NULL font collection\n"); } START_TEST(font) @@ -250,7 +368,9 @@ START_TEST(font) test_createfont(); test_logfont(); test_fontfamily(); + test_fontfamily_properties(); test_getgenerics(); + test_installedfonts(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/gdiplus.rbuild b/rostests/winetests/gdiplus/gdiplus.rbuild index 3b295ffb5a5..588629eef2e 100644 --- a/rostests/winetests/gdiplus/gdiplus.rbuild +++ b/rostests/winetests/gdiplus/gdiplus.rbuild @@ -3,9 +3,9 @@ . - 0x600 - 0x600 + brush.c + customlinecap.c font.c graphics.c graphicspath.c @@ -20,7 +20,7 @@ gdiplus user32 gdi32 - kernel32 + ole32 ntdll diff --git a/rostests/winetests/gdiplus/graphics.c b/rostests/winetests/gdiplus/graphics.c index 168eae35523..ae3b8013695 100644 --- a/rostests/winetests/gdiplus/graphics.c +++ b/rostests/winetests/gdiplus/graphics.c @@ -22,8 +22,10 @@ #include "gdiplus.h" #include "wingdi.h" #include "wine/test.h" +#include #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) +#define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got) #define TABLE_LEN (23) static void test_constructor_destructor(void) @@ -130,11 +132,9 @@ static void test_save_restore(void) GdipCreateFromHDC(hdc, &graphics1); GdipSetInterpolationMode(graphics1, InterpolationModeBilinear); stat = GdipSaveGraphics(graphics1, &state_a); - todo_wine expect(Ok, stat); GdipSetInterpolationMode(graphics1, InterpolationModeBicubic); stat = GdipRestoreGraphics(graphics1, state_a); - todo_wine expect(Ok, stat); GdipGetInterpolationMode(graphics1, &mode); todo_wine @@ -151,7 +151,6 @@ static void test_save_restore(void) GdipSaveGraphics(graphics1, &state_b); GdipSetInterpolationMode(graphics1, InterpolationModeNearestNeighbor); stat = GdipRestoreGraphics(graphics1, 0xdeadbeef); - todo_wine expect(Ok, stat); GdipRestoreGraphics(graphics1, state_b); GdipGetInterpolationMode(graphics1, &mode); @@ -277,6 +276,8 @@ static void test_GdipDrawArc(void) expect(Ok, status); GdipDeletePen(pen); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); } @@ -321,6 +322,8 @@ static void test_GdipDrawArcI(void) expect(Ok, status); GdipDeletePen(pen); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); } @@ -359,6 +362,8 @@ static void test_GdipDrawBezierI(void) expect(Ok, status); GdipDeletePen(pen); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); } @@ -397,6 +402,8 @@ static void test_GdipDrawLineI(void) expect(Ok, status); GdipDeletePen(pen); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); } @@ -449,9 +456,628 @@ static void test_GdipDrawLinesI(void) GdipFree(ptf); GdipDeletePen(pen); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); } +static void test_Get_Release_DC(void) +{ + GpStatus status; + GpGraphics *graphics = NULL; + GpPen *pen; + GpSolidFill *brush; + GpPath *path; + HDC hdc = GetDC(0); + HDC retdc; + REAL r; + CompositingQuality quality; + CompositingMode compmode; + InterpolationMode intmode; + GpMatrix *m; + GpRegion *region; + GpUnit unit; + PixelOffsetMode offsetmode; + SmoothingMode smoothmode; + TextRenderingHint texthint; + GpPointF ptf[5]; + GpPoint pt[5]; + GpRectF rectf[2]; + GpRect rect[2]; + GpRegion *clip; + INT i; + BOOL res; + ARGB color = 0x00000000; + HRGN hrgn = CreateRectRgn(0, 0, 10, 10); + + pt[0].X = 10; + pt[0].Y = 10; + pt[1].X = 20; + pt[1].Y = 15; + pt[2].X = 40; + pt[2].Y = 80; + pt[3].X = -20; + pt[3].Y = 20; + pt[4].X = 50; + pt[4].Y = 110; + + for(i = 0; i < 5;i++){ + ptf[i].X = (REAL)pt[i].X; + ptf[i].Y = (REAL)pt[i].Y; + } + + rect[0].X = 0; + rect[0].Y = 0; + rect[0].Width = 50; + rect[0].Height = 70; + rect[1].X = 0; + rect[1].Y = 0; + rect[1].Width = 10; + rect[1].Height = 20; + + for(i = 0; i < 2;i++){ + rectf[i].X = (REAL)rect[i].X; + rectf[i].Y = (REAL)rect[i].Y; + rectf[i].Height = (REAL)rect[i].Height; + rectf[i].Width = (REAL)rect[i].Width; + } + + GdipCreateMatrix(&m); + GdipCreateRegion(®ion); + GdipCreateSolidFill((ARGB)0xdeadbeef, &brush); + GdipCreatePath(FillModeAlternate, &path); + GdipCreateRegion(&clip); + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + ok(graphics != NULL, "Expected graphics to be initialized\n"); + status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); + expect(Ok, status); + + /* NULL arguments */ + status = GdipGetDC(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetDC(graphics, NULL); + expect(InvalidParameter, status); + status = GdipGetDC(NULL, &retdc); + expect(InvalidParameter, status); + + status = GdipReleaseDC(NULL, NULL); + expect(InvalidParameter, status); + status = GdipReleaseDC(graphics, NULL); + expect(InvalidParameter, status); + status = GdipReleaseDC(NULL, (HDC)0xdeadbeef); + expect(InvalidParameter, status); + + /* Release without Get */ + status = GdipReleaseDC(graphics, hdc); + expect(InvalidParameter, status); + + retdc = NULL; + status = GdipGetDC(graphics, &retdc); + expect(Ok, status); + ok(retdc == hdc, "Invalid HDC returned\n"); + /* call it once more */ + status = GdipGetDC(graphics, &retdc); + expect(ObjectBusy, status); + + /* try all Graphics calls here */ + status = Ok; + status = GdipDrawArc(graphics, pen, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawArcI(graphics, pen, 0, 0, 1, 1, 0.0, 0.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawBezier(graphics, pen, 0.0, 10.0, 20.0, 15.0, 35.0, -10.0, 10.0, 10.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawBezierI(graphics, pen, 0, 0, 0, 0, 0, 0, 0, 0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawBeziers(graphics, pen, ptf, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawBeziersI(graphics, pen, pt, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawClosedCurve(graphics, pen, ptf, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawClosedCurveI(graphics, pen, pt, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawClosedCurve2(graphics, pen, ptf, 5, 1.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawClosedCurve2I(graphics, pen, pt, 5, 1.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawCurve(graphics, pen, ptf, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawCurveI(graphics, pen, pt, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawCurve2(graphics, pen, ptf, 5, 1.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawCurve2I(graphics, pen, pt, 5, 1.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawEllipse(graphics, pen, 0.0, 0.0, 100.0, 50.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawEllipseI(graphics, pen, 0, 0, 100, 50); + expect(ObjectBusy, status); status = Ok; + /* GdipDrawImage/GdipDrawImageI */ + /* GdipDrawImagePointsRect/GdipDrawImagePointsRectI */ + /* GdipDrawImageRectRect/GdipDrawImageRectRectI */ + /* GdipDrawImageRect/GdipDrawImageRectI */ + status = GdipDrawLine(graphics, pen, 0.0, 0.0, 100.0, 200.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawLineI(graphics, pen, 0, 0, 100, 200); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawLines(graphics, pen, ptf, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawLinesI(graphics, pen, pt, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawPath(graphics, pen, path); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawPie(graphics, pen, 0.0, 0.0, 100.0, 100.0, 0.0, 90.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawPieI(graphics, pen, 0, 0, 100, 100, 0.0, 90.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawRectangle(graphics, pen, 0.0, 0.0, 100.0, 300.0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawRectangleI(graphics, pen, 0, 0, 100, 300); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawRectangles(graphics, pen, rectf, 2); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawRectanglesI(graphics, pen, rect, 2); + expect(ObjectBusy, status); status = Ok; + /* GdipDrawString */ + status = GdipFillClosedCurve2(graphics, (GpBrush*)brush, ptf, 5, 1.0, FillModeAlternate); + expect(ObjectBusy, status); status = Ok; + status = GdipFillClosedCurve2I(graphics, (GpBrush*)brush, pt, 5, 1.0, FillModeAlternate); + expect(ObjectBusy, status); status = Ok; + status = GdipFillEllipse(graphics, (GpBrush*)brush, 0.0, 0.0, 100.0, 100.0); + expect(ObjectBusy, status); status = Ok; + status = GdipFillEllipseI(graphics, (GpBrush*)brush, 0, 0, 100, 100); + expect(ObjectBusy, status); status = Ok; + status = GdipFillPath(graphics, (GpBrush*)brush, path); + expect(ObjectBusy, status); status = Ok; + status = GdipFillPie(graphics, (GpBrush*)brush, 0.0, 0.0, 100.0, 100.0, 0.0, 15.0); + expect(ObjectBusy, status); status = Ok; + status = GdipFillPieI(graphics, (GpBrush*)brush, 0, 0, 100, 100, 0.0, 15.0); + expect(ObjectBusy, status); status = Ok; + status = GdipFillPolygon(graphics, (GpBrush*)brush, ptf, 5, FillModeAlternate); + expect(ObjectBusy, status); status = Ok; + status = GdipFillPolygonI(graphics, (GpBrush*)brush, pt, 5, FillModeAlternate); + expect(ObjectBusy, status); status = Ok; + status = GdipFillPolygon2(graphics, (GpBrush*)brush, ptf, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipFillPolygon2I(graphics, (GpBrush*)brush, pt, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipFillRectangle(graphics, (GpBrush*)brush, 0.0, 0.0, 100.0, 100.0); + expect(ObjectBusy, status); status = Ok; + status = GdipFillRectangleI(graphics, (GpBrush*)brush, 0, 0, 100, 100); + expect(ObjectBusy, status); status = Ok; + status = GdipFillRectangles(graphics, (GpBrush*)brush, rectf, 2); + expect(ObjectBusy, status); status = Ok; + status = GdipFillRectanglesI(graphics, (GpBrush*)brush, rect, 2); + expect(ObjectBusy, status); status = Ok; + status = GdipFillRegion(graphics, (GpBrush*)brush, region); + expect(ObjectBusy, status); status = Ok; + status = GdipFlush(graphics, FlushIntentionFlush); + expect(ObjectBusy, status); status = Ok; + status = GdipGetClipBounds(graphics, rectf); + expect(ObjectBusy, status); status = Ok; + status = GdipGetClipBoundsI(graphics, rect); + expect(ObjectBusy, status); status = Ok; + status = GdipGetCompositingMode(graphics, &compmode); + expect(ObjectBusy, status); status = Ok; + status = GdipGetCompositingQuality(graphics, &quality); + expect(ObjectBusy, status); status = Ok; + status = GdipGetInterpolationMode(graphics, &intmode); + expect(ObjectBusy, status); status = Ok; + status = GdipGetNearestColor(graphics, &color); + expect(ObjectBusy, status); status = Ok; + status = GdipGetPageScale(graphics, &r); + expect(ObjectBusy, status); status = Ok; + status = GdipGetPageUnit(graphics, &unit); + expect(ObjectBusy, status); status = Ok; + status = GdipGetPixelOffsetMode(graphics, &offsetmode); + expect(ObjectBusy, status); status = Ok; + status = GdipGetSmoothingMode(graphics, &smoothmode); + expect(ObjectBusy, status); status = Ok; + status = GdipGetTextRenderingHint(graphics, &texthint); + expect(ObjectBusy, status); status = Ok; + status = GdipGetWorldTransform(graphics, m); + expect(ObjectBusy, status); status = Ok; + status = GdipGraphicsClear(graphics, 0xdeadbeef); + expect(ObjectBusy, status); status = Ok; + status = GdipIsVisiblePoint(graphics, 0.0, 0.0, &res); + expect(ObjectBusy, status); status = Ok; + status = GdipIsVisiblePointI(graphics, 0, 0, &res); + expect(ObjectBusy, status); status = Ok; + /* GdipMeasureCharacterRanges */ + /* GdipMeasureString */ + status = GdipResetClip(graphics); + expect(ObjectBusy, status); status = Ok; + status = GdipResetWorldTransform(graphics); + expect(ObjectBusy, status); status = Ok; + /* GdipRestoreGraphics */ + status = GdipRotateWorldTransform(graphics, 15.0, MatrixOrderPrepend); + expect(ObjectBusy, status); status = Ok; + /* GdipSaveGraphics */ + status = GdipScaleWorldTransform(graphics, 1.0, 1.0, MatrixOrderPrepend); + expect(ObjectBusy, status); status = Ok; + status = GdipSetCompositingMode(graphics, CompositingModeSourceOver); + expect(ObjectBusy, status); status = Ok; + status = GdipSetCompositingQuality(graphics, CompositingQualityDefault); + expect(ObjectBusy, status); status = Ok; + status = GdipSetInterpolationMode(graphics, InterpolationModeDefault); + expect(ObjectBusy, status); status = Ok; + status = GdipSetPageScale(graphics, 1.0); + expect(ObjectBusy, status); status = Ok; + status = GdipSetPageUnit(graphics, UnitWorld); + expect(ObjectBusy, status); status = Ok; + status = GdipSetPixelOffsetMode(graphics, PixelOffsetModeDefault); + expect(ObjectBusy, status); status = Ok; + status = GdipSetSmoothingMode(graphics, SmoothingModeDefault); + expect(ObjectBusy, status); status = Ok; + status = GdipSetTextRenderingHint(graphics, TextRenderingHintSystemDefault); + expect(ObjectBusy, status); status = Ok; + status = GdipSetWorldTransform(graphics, m); + expect(ObjectBusy, status); status = Ok; + status = GdipTranslateWorldTransform(graphics, 0.0, 0.0, MatrixOrderPrepend); + expect(ObjectBusy, status); status = Ok; + status = GdipSetClipHrgn(graphics, hrgn, CombineModeReplace); + expect(ObjectBusy, status); status = Ok; + status = GdipSetClipPath(graphics, path, CombineModeReplace); + expect(ObjectBusy, status); status = Ok; + status = GdipSetClipRect(graphics, 0.0, 0.0, 10.0, 10.0, CombineModeReplace); + expect(ObjectBusy, status); status = Ok; + status = GdipSetClipRectI(graphics, 0, 0, 10, 10, CombineModeReplace); + expect(ObjectBusy, status); status = Ok; + status = GdipSetClipRegion(graphics, clip, CombineModeReplace); + expect(ObjectBusy, status); status = Ok; + status = GdipTranslateClip(graphics, 0.0, 0.0); + expect(ObjectBusy, status); status = Ok; + status = GdipTranslateClipI(graphics, 0, 0); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawPolygon(graphics, pen, ptf, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipDrawPolygonI(graphics, pen, pt, 5); + expect(ObjectBusy, status); status = Ok; + status = GdipGetDpiX(graphics, &r); + expect(ObjectBusy, status); status = Ok; + status = GdipGetDpiY(graphics, &r); + expect(ObjectBusy, status); status = Ok; + status = GdipMultiplyWorldTransform(graphics, m, MatrixOrderPrepend); + status = GdipGetClip(graphics, region); + expect(ObjectBusy, status); status = Ok; + status = GdipTransformPoints(graphics, CoordinateSpacePage, CoordinateSpaceWorld, ptf, 5); + expect(ObjectBusy, status); status = Ok; + /* try to delete before release */ + status = GdipDeleteGraphics(graphics); + expect(ObjectBusy, status); + + status = GdipReleaseDC(graphics, retdc); + expect(Ok, status); + + GdipDeletePen(pen); + GdipDeleteGraphics(graphics); + + GdipDeletePath(path); + GdipDeleteBrush((GpBrush*)brush); + GdipDeleteRegion(region); + GdipDeleteMatrix(m); + DeleteObject(hrgn); + + ReleaseDC(0, hdc); +} + +static void test_transformpoints(void) +{ + GpStatus status; + GpGraphics *graphics = NULL; + HDC hdc = GetDC(0); + GpPointF ptf[2]; + GpPoint pt[2]; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + + /* NULL arguments */ + status = GdipTransformPoints(NULL, CoordinateSpacePage, CoordinateSpaceWorld, NULL, 0); + expect(InvalidParameter, status); + status = GdipTransformPoints(graphics, CoordinateSpacePage, CoordinateSpaceWorld, NULL, 0); + expect(InvalidParameter, status); + status = GdipTransformPoints(graphics, CoordinateSpacePage, CoordinateSpaceWorld, ptf, 0); + expect(InvalidParameter, status); + status = GdipTransformPoints(graphics, CoordinateSpacePage, CoordinateSpaceWorld, ptf, -1); + expect(InvalidParameter, status); + + ptf[0].X = 1.0; + ptf[0].Y = 0.0; + ptf[1].X = 0.0; + ptf[1].Y = 1.0; + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, ptf, 2); + expect(Ok, status); + expectf(1.0, ptf[0].X); + expectf(0.0, ptf[0].Y); + expectf(0.0, ptf[1].X); + expectf(1.0, ptf[1].Y); + + status = GdipTranslateWorldTransform(graphics, 5.0, 5.0, MatrixOrderAppend); + expect(Ok, status); + status = GdipSetPageUnit(graphics, UnitPixel); + expect(Ok, status); + status = GdipSetPageScale(graphics, 3.0); + expect(Ok, status); + + ptf[0].X = 1.0; + ptf[0].Y = 0.0; + ptf[1].X = 0.0; + ptf[1].Y = 1.0; + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, ptf, 2); + expect(Ok, status); + expectf(18.0, ptf[0].X); + expectf(15.0, ptf[0].Y); + expectf(15.0, ptf[1].X); + expectf(18.0, ptf[1].Y); + + ptf[0].X = 1.0; + ptf[0].Y = 0.0; + ptf[1].X = 0.0; + ptf[1].Y = 1.0; + status = GdipTransformPoints(graphics, CoordinateSpacePage, CoordinateSpaceWorld, ptf, 2); + expect(Ok, status); + expectf(6.0, ptf[0].X); + expectf(5.0, ptf[0].Y); + expectf(5.0, ptf[1].X); + expectf(6.0, ptf[1].Y); + + ptf[0].X = 1.0; + ptf[0].Y = 0.0; + ptf[1].X = 0.0; + ptf[1].Y = 1.0; + status = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpacePage, ptf, 2); + expect(Ok, status); + expectf(3.0, ptf[0].X); + expectf(0.0, ptf[0].Y); + expectf(0.0, ptf[1].X); + expectf(3.0, ptf[1].Y); + + ptf[0].X = 18.0; + ptf[0].Y = 15.0; + ptf[1].X = 15.0; + ptf[1].Y = 18.0; + status = GdipTransformPoints(graphics, CoordinateSpaceWorld, CoordinateSpaceDevice, ptf, 2); + expect(Ok, status); + expectf(1.0, ptf[0].X); + expectf(0.0, ptf[0].Y); + expectf(0.0, ptf[1].X); + expectf(1.0, ptf[1].Y); + + ptf[0].X = 6.0; + ptf[0].Y = 5.0; + ptf[1].X = 5.0; + ptf[1].Y = 6.0; + status = GdipTransformPoints(graphics, CoordinateSpaceWorld, CoordinateSpacePage, ptf, 2); + expect(Ok, status); + expectf(1.0, ptf[0].X); + expectf(0.0, ptf[0].Y); + expectf(0.0, ptf[1].X); + expectf(1.0, ptf[1].Y); + + ptf[0].X = 3.0; + ptf[0].Y = 0.0; + ptf[1].X = 0.0; + ptf[1].Y = 3.0; + status = GdipTransformPoints(graphics, CoordinateSpacePage, CoordinateSpaceDevice, ptf, 2); + expect(Ok, status); + expectf(1.0, ptf[0].X); + expectf(0.0, ptf[0].Y); + expectf(0.0, ptf[1].X); + expectf(1.0, ptf[1].Y); + + pt[0].X = 1; + pt[0].Y = 0; + pt[1].X = 0; + pt[1].Y = 1; + status = GdipTransformPointsI(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 2); + expect(Ok, status); + expect(18, pt[0].X); + expect(15, pt[0].Y); + expect(15, pt[1].X); + expect(18, pt[1].Y); + + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); +} + +static void test_get_set_clip(void) +{ + GpStatus status; + GpGraphics *graphics = NULL; + HDC hdc = GetDC(0); + GpRegion *clip; + GpRectF rect; + BOOL res; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + + rect.X = rect.Y = 0.0; + rect.Height = rect.Width = 100.0; + + status = GdipCreateRegionRect(&rect, &clip); + + /* NULL arguments */ + status = GdipGetClip(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetClip(graphics, NULL); + expect(InvalidParameter, status); + status = GdipGetClip(NULL, clip); + expect(InvalidParameter, status); + + status = GdipSetClipRegion(NULL, NULL, CombineModeReplace); + expect(InvalidParameter, status); + status = GdipSetClipRegion(graphics, NULL, CombineModeReplace); + expect(InvalidParameter, status); + + status = GdipSetClipPath(NULL, NULL, CombineModeReplace); + expect(InvalidParameter, status); + status = GdipSetClipPath(graphics, NULL, CombineModeReplace); + expect(InvalidParameter, status); + + res = FALSE; + status = GdipGetClip(graphics, clip); + expect(Ok, status); + status = GdipIsInfiniteRegion(clip, graphics, &res); + expect(Ok, status); + expect(TRUE, res); + + /* remains infinite after reset */ + res = FALSE; + status = GdipResetClip(graphics); + expect(Ok, status); + status = GdipGetClip(graphics, clip); + expect(Ok, status); + status = GdipIsInfiniteRegion(clip, graphics, &res); + expect(Ok, status); + expect(TRUE, res); + + /* set to empty and then reset to infinite */ + status = GdipSetEmpty(clip); + expect(Ok, status); + status = GdipSetClipRegion(graphics, clip, CombineModeReplace); + expect(Ok, status); + + status = GdipGetClip(graphics, clip); + expect(Ok, status); + res = FALSE; + status = GdipIsEmptyRegion(clip, graphics, &res); + expect(Ok, status); + expect(TRUE, res); + status = GdipResetClip(graphics); + expect(Ok, status); + status = GdipGetClip(graphics, clip); + expect(Ok, status); + res = FALSE; + status = GdipIsInfiniteRegion(clip, graphics, &res); + expect(Ok, status); + expect(TRUE, res); + + GdipDeleteRegion(clip); + + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); +} + +static void test_isempty(void) +{ + GpStatus status; + GpGraphics *graphics = NULL; + HDC hdc = GetDC(0); + GpRegion *clip; + BOOL res; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + + status = GdipCreateRegion(&clip); + expect(Ok, status); + + /* NULL */ + status = GdipIsClipEmpty(NULL, NULL); + expect(InvalidParameter, status); + status = GdipIsClipEmpty(graphics, NULL); + expect(InvalidParameter, status); + status = GdipIsClipEmpty(NULL, &res); + expect(InvalidParameter, status); + + /* default is infinite */ + res = TRUE; + status = GdipIsClipEmpty(graphics, &res); + expect(Ok, status); + expect(FALSE, res); + + GdipDeleteRegion(clip); + + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); +} + +static void test_clear(void) +{ + GpStatus status; + + status = GdipGraphicsClear(NULL, 0xdeadbeef); + expect(InvalidParameter, status); +} + +static void test_textcontrast(void) +{ + GpStatus status; + HDC hdc = GetDC(0); + GpGraphics *graphics; + UINT contrast; + + status = GdipGetTextContrast(NULL, NULL); + expect(InvalidParameter, status); + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + + status = GdipGetTextContrast(graphics, NULL); + expect(InvalidParameter, status); + status = GdipGetTextContrast(graphics, &contrast); + expect(4, contrast); + + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); +} + +static void test_GdipDrawString(void) +{ + GpStatus status; + GpGraphics *graphics = NULL; + GpFont *fnt = NULL; + RectF rect; + GpStringFormat *format; + GpBrush *brush; + LOGFONTA logfont; + HDC hdc = GetDC(0); + static const WCHAR string[] = {'T','e','s','t',0}; + + memset(&logfont,0,sizeof(logfont)); + strcpy(logfont.lfFaceName,"Arial"); + logfont.lfHeight = 12; + logfont.lfCharSet = DEFAULT_CHARSET; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + + status = GdipCreateFontFromLogfontA(hdc, &logfont, &fnt); + if (status == FileNotFound) + { + skip("Arial not installed.\n"); + return; + } + expect(Ok, status); + + status = GdipCreateSolidFill((ARGB)0xdeadbeef, (GpSolidFill**)&brush); + expect(Ok, status); + + status = GdipCreateStringFormat(0,0,&format); + expect(Ok, status); + + rect.X = 0; + rect.Y = 0; + rect.Width = 0; + rect.Height = 12; + + status = GdipDrawString(graphics, string, 4, fnt, &rect, format, brush); + expect(Ok, status); + + GdipDeleteGraphics(graphics); + GdipDeleteBrush(brush); + GdipDeleteFont(fnt); + GdipDeleteStringFormat(format); + + ReleaseDC(0, hdc); +} + + START_TEST(graphics) { struct GdiplusStartupInput gdiplusStartupInput; @@ -471,6 +1097,13 @@ START_TEST(graphics) test_GdipDrawArcI(); test_GdipDrawLineI(); test_GdipDrawLinesI(); + test_GdipDrawString(); + test_Get_Release_DC(); + test_transformpoints(); + test_get_set_clip(); + test_isempty(); + test_clear(); + test_textcontrast(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/graphicspath.c b/rostests/winetests/gdiplus/graphicspath.c index 9f9af9cd50c..6e257eb8008 100644 --- a/rostests/winetests/gdiplus/graphicspath.c +++ b/rostests/winetests/gdiplus/graphicspath.c @@ -214,6 +214,8 @@ static void test_line2(void) expect(Ok, status); ok_path(path, line2_path, sizeof(line2_path)/sizeof(path_test_t), FALSE); + + GdipDeletePath(path); } static path_test_t arc_path[] = { @@ -283,6 +285,8 @@ static void test_arc(void) expect(Ok, status); ok_path(path, arc_path, sizeof(arc_path)/sizeof(path_test_t), FALSE); + + GdipDeletePath(path); } static void test_worldbounds(void) @@ -696,6 +700,415 @@ static void test_lastpoint(void) GdipDeletePath(path); } +static path_test_t addcurve_path[] = { + {0.0, 0.0, PathPointTypeStart, 0, 0}, /*0*/ + {3.3, 3.3, PathPointTypeBezier, 0, 0}, /*1*/ + {6.7, 3.3, PathPointTypeBezier, 0, 0}, /*2*/ + {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*3*/ + {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*4*/ + {3.3, 20.0, PathPointTypeBezier, 0, 0}, /*5*/ + {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*6*/ + {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*7*/ + {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*8*/ + {30.0, 10.0, PathPointTypeBezier, 0, 0} /*9*/ + }; +static path_test_t addcurve_path2[] = { + {100.0,120.0,PathPointTypeStart, 0, 0}, /*0*/ + {123.0,10.0, PathPointTypeLine, 0, 0}, /*1*/ + {0.0, 0.0, PathPointTypeLine, 0, 0}, /*2*/ + {3.3, 3.3, PathPointTypeBezier, 0, 0}, /*3*/ + {6.7, 3.3, PathPointTypeBezier, 0, 0}, /*4*/ + {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*5*/ + {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*6*/ + {3.3, 20.0, PathPointTypeBezier, 0, 0}, /*7*/ + {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*8*/ + {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*9*/ + {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*10*/ + {30.0, 10.0, PathPointTypeBezier, 0, 0} /*11*/ + }; +static path_test_t addcurve_path3[] = { + {10.0, 10.0, PathPointTypeStart, 0, 0}, /*0*/ + {13.3, 16.7, PathPointTypeBezier, 0, 1}, /*1*/ + {3.3, 20.0, PathPointTypeBezier, 0, 0}, /*2*/ + {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*3*/ + {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*4*/ + {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*5*/ + {30.0, 10.0, PathPointTypeBezier, 0, 0} /*6*/ + }; +static void test_addcurve(void) +{ + GpStatus status; + GpPath *path; + GpPointF points[4]; + + points[0].X = 0.0; + points[0].Y = 0.0; + points[1].X = 10.0; + points[1].Y = 10.0; + points[2].X = 10.0; + points[2].Y = 20.0; + points[3].X = 30.0; + points[3].Y = 10.0; + + GdipCreatePath(FillModeAlternate, &path); + + /* NULL args */ + status = GdipAddPathCurve2(NULL, NULL, 0, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve2(path, NULL, 0, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve2(path, points, -1, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve2(path, points, 1, 1.0); + expect(InvalidParameter, status); + + /* add to empty path */ + status = GdipAddPathCurve2(path, points, 4, 1.0); + expect(Ok, status); + ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE); + GdipDeletePath(path); + + /* add to notempty path and opened figure */ + GdipCreatePath(FillModeAlternate, &path); + GdipAddPathLine(path, 100.0, 120.0, 123.0, 10.0); + status = GdipAddPathCurve2(path, points, 4, 1.0); + expect(Ok, status); + ok_path(path, addcurve_path2, sizeof(addcurve_path2)/sizeof(path_test_t), FALSE); + + /* NULL args */ + GdipResetPath(path); + status = GdipAddPathCurve3(NULL, NULL, 0, 0, 0, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve3(path, NULL, 0, 0, 0, 0.0); + expect(InvalidParameter, status); + /* wrong count, offset.. */ + status = GdipAddPathCurve3(path, points, 0, 0, 0, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve3(path, points, 4, 0, 0, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve3(path, points, 4, 0, 4, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve3(path, points, 4, 1, 3, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve3(path, points, 4, 1, 0, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathCurve3(path, points, 4, 3, 1, 0.0); + expect(InvalidParameter, status); + + /* use all points */ + status = GdipAddPathCurve3(path, points, 4, 0, 3, 1.0); + expect(Ok, status); + ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE); + GdipResetPath(path); + + status = GdipAddPathCurve3(path, points, 4, 1, 2, 1.0); + expect(Ok, status); + ok_path(path, addcurve_path3, sizeof(addcurve_path3)/sizeof(path_test_t), FALSE); + + GdipDeletePath(path); +} + +static path_test_t addclosedcurve_path[] = { + {0.0, 0.0, PathPointTypeStart, 0, 0}, /*0*/ + {-6.7, 0.0, PathPointTypeBezier, 0, 0}, /*1*/ + {6.7, 3.3, PathPointTypeBezier, 0, 0}, /*2*/ + {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*3*/ + {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*4*/ + {3.3, 20.0, PathPointTypeBezier, 0, 0}, /*5*/ + {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*6*/ + {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*7*/ + {33.3, 16.7, PathPointTypeBezier, 0, 0}, /*8*/ + {30.0, 10.0, PathPointTypeBezier, 0, 0}, /*9*/ + {26.7, 3.3, PathPointTypeBezier, 0, 0}, /*10*/ + {6.7, 0.0, PathPointTypeBezier, 0, 0}, /*11*/ + {0.0, 0.0, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0} /*12*/ + }; +static void test_addclosedcurve(void) +{ + GpStatus status; + GpPath *path; + GpPointF points[4]; + + points[0].X = 0.0; + points[0].Y = 0.0; + points[1].X = 10.0; + points[1].Y = 10.0; + points[2].X = 10.0; + points[2].Y = 20.0; + points[3].X = 30.0; + points[3].Y = 10.0; + + GdipCreatePath(FillModeAlternate, &path); + + /* NULL args */ + status = GdipAddPathClosedCurve2(NULL, NULL, 0, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathClosedCurve2(path, NULL, 0, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathClosedCurve2(path, points, -1, 0.0); + expect(InvalidParameter, status); + status = GdipAddPathClosedCurve2(path, points, 1, 1.0); + expect(InvalidParameter, status); + + /* add to empty path */ + status = GdipAddPathClosedCurve2(path, points, 4, 1.0); + expect(Ok, status); + ok_path(path, addclosedcurve_path, sizeof(addclosedcurve_path)/sizeof(path_test_t), FALSE); + GdipDeletePath(path); +} + +static path_test_t reverse_path[] = { + {0.0, 20.0, PathPointTypeStart, 0, 0}, /*0*/ + {25.0, 25.0, PathPointTypeLine, 0, 0}, /*1*/ + {0.0, 30.0, PathPointTypeLine, 0, 0}, /*2*/ + {15.0, 35.0, PathPointTypeStart, 0, 0}, /*3*/ + {0.0, 40.0, PathPointTypeLine, 0, 0}, /*4*/ + {5.0, 45.0, PathPointTypeLine, 0, 0}, /*5*/ + {0.0, 50.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0} /*6*/ + }; + +static void test_reverse(void) +{ + GpStatus status; + GpPath *path; + GpPointF pts[7]; + INT i; + + for(i = 0; i < 7; i++){ + pts[i].X = i * 5.0 * (REAL)(i % 2); + pts[i].Y = 50.0 - i * 5.0; + } + + GdipCreatePath(FillModeAlternate, &path); + + /* NULL argument */ + status = GdipReversePath(NULL); + expect(InvalidParameter, status); + + /* empty path */ + status = GdipReversePath(path); + expect(Ok, status); + + GdipAddPathLine2(path, pts, 4); + GdipClosePathFigure(path); + GdipAddPathLine2(path, &(pts[4]), 3); + + status = GdipReversePath(path); + expect(Ok, status); + ok_path(path, reverse_path, sizeof(reverse_path)/sizeof(path_test_t), FALSE); + + GdipDeletePath(path); +} + +static path_test_t addpie_path[] = { + {50.0, 25.0, PathPointTypeStart, 0, 0}, /*0*/ + {97.2, 33.3, PathPointTypeLine, 0, 0}, /*1*/ + {91.8, 40.9, PathPointTypeBezier,0, 0}, /*2*/ + {79.4, 46.8, PathPointTypeBezier,0, 0}, /*3*/ + {63.9, 49.0, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0} /*4*/ + }; +static path_test_t addpie_path2[] = { + {0.0, 30.0, PathPointTypeStart | PathPointTypeCloseSubpath, 0, 0} /*0*/ + }; +static path_test_t addpie_path3[] = { + {30.0, 0.0, PathPointTypeStart | PathPointTypeCloseSubpath, 0, 0} /*0*/ + }; +static void test_addpie(void) +{ + GpStatus status; + GpPath *path; + + GdipCreatePath(FillModeAlternate, &path); + + /* NULL argument */ + status = GdipAddPathPie(NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + expect(InvalidParameter, status); + + status = GdipAddPathPie(path, 0.0, 0.0, 100.0, 50.0, 10.0, 50.0); + expect(Ok, status); + ok_path(path, addpie_path, sizeof(addpie_path)/sizeof(path_test_t), FALSE); + status = GdipResetPath(path); + expect(Ok, status); + + /* zero width base ellipse */ + status = GdipAddPathPie(path, 0.0, 0.0, 0.0, 60.0, -90.0, 24.0); + expect(InvalidParameter, status); + ok_path(path, addpie_path2, sizeof(addpie_path2)/sizeof(path_test_t), FALSE); + status = GdipResetPath(path); + expect(Ok, status); + + /* zero height base ellipse */ + status = GdipAddPathPie(path, 0.0, 0.0, 60.0, 0.0 , -90.0, 24.0); + expect(InvalidParameter, status); + ok_path(path, addpie_path3, sizeof(addpie_path3)/sizeof(path_test_t), FALSE); + + GdipDeletePath(path); +} + +static path_test_t flattenellipse_path[] = { + {100.0, 25.0,PathPointTypeStart, 0, 0}, /*0*/ + {99.0, 30.0, PathPointTypeLine, 0, 0}, /*1*/ + {96.0, 34.8, PathPointTypeLine, 0, 0}, /*2*/ + {91.5, 39.0, PathPointTypeLine, 0, 0}, /*3*/ + {85.5, 42.8, PathPointTypeLine, 0, 0}, /*4*/ + {69.5, 48.0, PathPointTypeLine, 0, 1}, /*5*/ + {50.0, 50.0, PathPointTypeLine, 0, 1}, /*6*/ + {30.5, 48.0, PathPointTypeLine, 0, 1}, /*7*/ + {14.8, 42.8, PathPointTypeLine, 0, 1}, /*8*/ + {8.5, 39.0, PathPointTypeLine, 0, 1}, /*9*/ + {4.0, 34.8, PathPointTypeLine, 0, 1}, /*10*/ + {1.0, 30.0, PathPointTypeLine, 0, 1}, /*11*/ + {0.0, 25.0, PathPointTypeLine, 0, 1}, /*12*/ + {1.0, 20.0, PathPointTypeLine, 0, 1}, /*13*/ + {4.0, 15.3, PathPointTypeLine, 0, 1}, /*14*/ + {8.5, 11.0, PathPointTypeLine, 0, 1}, /*15*/ + {14.8, 7.3, PathPointTypeLine, 0, 1}, /*16*/ + {30.5, 2.0, PathPointTypeLine, 0, 1}, /*17*/ + {50.0, 0.0, PathPointTypeLine, 0, 1}, /*18*/ + {69.5, 2.0, PathPointTypeLine, 0, 1}, /*19*/ + {85.5, 7.3, PathPointTypeLine, 0, 1}, /*20*/ + {91.5, 11.0, PathPointTypeLine, 0, 1}, /*21*/ + {96.0, 15.3, PathPointTypeLine, 0, 1}, /*22*/ + {99.0, 20.0, PathPointTypeLine, 0, 1}, /*23*/ + {100.0,25.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 1} /*24*/ + }; + +static path_test_t flattenline_path[] = { + {5.0, 10.0,PathPointTypeStart, 0, 0}, /*0*/ + {50.0, 100.0, PathPointTypeLine, 0, 0} /*1*/ + }; + +static path_test_t flattenarc_path[] = { + {100.0, 25.0,PathPointTypeStart, 0, 0}, /*0*/ + {99.0, 30.0, PathPointTypeLine, 0, 0}, /*1*/ + {96.0, 34.8, PathPointTypeLine, 0, 0}, /*2*/ + {91.5, 39.0, PathPointTypeLine, 0, 0}, /*3*/ + {85.5, 42.8, PathPointTypeLine, 0, 0}, /*4*/ + {69.5, 48.0, PathPointTypeLine, 0, 1}, /*5*/ + {50.0, 50.0, PathPointTypeLine, 0, 1} /*6*/ + }; + +static path_test_t flattenquater_path[] = { + {100.0, 50.0,PathPointTypeStart, 0, 0}, /*0*/ + {99.0, 60.0, PathPointTypeLine, 0, 0}, /*1*/ + {96.0, 69.5, PathPointTypeLine, 0, 0}, /*2*/ + {91.5, 78.0, PathPointTypeLine, 0, 0}, /*3*/ + {85.5, 85.5, PathPointTypeLine, 0, 0}, /*4*/ + {78.0, 91.5, PathPointTypeLine, 0, 0}, /*5*/ + {69.5, 96.0, PathPointTypeLine, 0, 0}, /*6*/ + {60.0, 99.0, PathPointTypeLine, 0, 0}, /*7*/ + {50.0, 100.0,PathPointTypeLine, 0, 0} /*8*/ + }; + +static void test_flatten(void) +{ + GpStatus status; + GpPath *path; + GpMatrix *m; + + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + status = GdipCreateMatrix(&m); + expect(Ok, status); + + /* NULL arguments */ + status = GdipFlattenPath(NULL, NULL, 0.0); + expect(InvalidParameter, status); + status = GdipFlattenPath(NULL, m, 0.0); + expect(InvalidParameter, status); + + /* flatten empty path */ + status = GdipFlattenPath(path, NULL, 1.0); + expect(Ok, status); + + status = GdipAddPathEllipse(path, 0.0, 0.0, 100.0, 50.0); + expect(Ok, status); + + status = GdipFlattenPath(path, NULL, 1.0); + expect(Ok, status); + ok_path(path, flattenellipse_path, sizeof(flattenellipse_path)/sizeof(path_test_t), TRUE); + + status = GdipResetPath(path); + expect(Ok, status); + status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 100.0); + expect(Ok, status); + status = GdipFlattenPath(path, NULL, 1.0); + expect(Ok, status); + ok_path(path, flattenline_path, sizeof(flattenline_path)/sizeof(path_test_t), FALSE); + + status = GdipResetPath(path); + expect(Ok, status); + status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 50.0, 0.0, 90.0); + expect(Ok, status); + status = GdipFlattenPath(path, NULL, 1.0); + expect(Ok, status); + ok_path(path, flattenarc_path, sizeof(flattenarc_path)/sizeof(path_test_t), TRUE); + + /* easy case - quater of a full circle */ + status = GdipResetPath(path); + expect(Ok, status); + status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 100.0, 0.0, 90.0); + expect(Ok, status); + status = GdipFlattenPath(path, NULL, 1.0); + expect(Ok, status); + ok_path(path, flattenquater_path, sizeof(flattenquater_path)/sizeof(path_test_t), FALSE); + + GdipDeleteMatrix(m); + GdipDeletePath(path); +} + +static void test_isvisible(void) +{ + GpPath *path; + GpGraphics *graphics = NULL; + HDC hdc = GetDC(0); + BOOL result; + GpStatus status; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + + /* NULL */ + status = GdipIsVisiblePathPoint(NULL, 0.0, 0.0, NULL, NULL); + expect(InvalidParameter, status); + status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, NULL); + expect(InvalidParameter, status); + status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, NULL); + expect(InvalidParameter, status); + status = GdipIsVisiblePathPoint(path, 0.0, 0.0, graphics, NULL); + expect(InvalidParameter, status); + + /* empty path */ + result = TRUE; + status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, &result); + expect(Ok, status); + expect(FALSE, result); + /* rect */ + status = GdipAddPathRectangle(path, 0.0, 0.0, 10.0, 10.0); + expect(Ok, status); + result = FALSE; + status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, &result); + expect(Ok, status); + expect(TRUE, result); + result = TRUE; + status = GdipIsVisiblePathPoint(path, 11.0, 11.0, NULL, &result); + expect(Ok, status); + expect(FALSE, result); + /* not affected by clipping */ + status = GdipSetClipRect(graphics, 5.0, 5.0, 5.0, 5.0, CombineModeReplace); + expect(Ok, status); + result = FALSE; + status = GdipIsVisiblePathPoint(path, 0.0, 0.0, graphics, &result); + expect(Ok, status); + expect(TRUE, result); + + GdipDeletePath(path); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); +} + START_TEST(graphicspath) { struct GdiplusStartupInput gdiplusStartupInput; @@ -719,6 +1132,12 @@ START_TEST(graphicspath) test_rect(); test_polygon(); test_lastpoint(); + test_addcurve(); + test_addclosedcurve(); + test_reverse(); + test_addpie(); + test_flatten(); + test_isvisible(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/image.c b/rostests/winetests/gdiplus/image.c index 38a58b9c689..4443f88822a 100644 --- a/rostests/winetests/gdiplus/image.c +++ b/rostests/winetests/gdiplus/image.c @@ -18,13 +18,69 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS + +#include + +#include "initguid.h" #include "windows.h" #include "gdiplus.h" #include "wine/test.h" -#include -#include "wingdi.h" #define expect(expected, got) ok(((UINT)got) == ((UINT)expected), "Expected %.8x, got %.8x\n", (UINT)expected, (UINT)got) +#define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got) + +static void expect_rawformat(REFGUID expected, GpImage *img, int line, BOOL todo) +{ + GUID raw; + WCHAR bufferW[39]; + char buffer[39]; + char buffer2[39]; + GpStatus stat; + + stat = GdipGetImageRawFormat(img, &raw); + ok_(__FILE__, line)(stat == Ok, "GdipGetImageRawFormat failed with %d\n", stat); + if(stat != Ok) return; + StringFromGUID2(&raw, bufferW, sizeof(bufferW)/sizeof(bufferW[0])); + WideCharToMultiByte(CP_ACP, 0, bufferW, sizeof(bufferW)/sizeof(bufferW[0]), buffer, sizeof(buffer), NULL, NULL); + StringFromGUID2(expected, bufferW, sizeof(bufferW)/sizeof(bufferW[0])); + WideCharToMultiByte(CP_ACP, 0, bufferW, sizeof(bufferW)/sizeof(bufferW[0]), buffer2, sizeof(buffer2), NULL, NULL); + if(todo) + todo_wine ok_(__FILE__, line)(IsEqualGUID(&raw, expected), "Expected format %s, got %s\n", buffer2, buffer); + else + ok_(__FILE__, line)(IsEqualGUID(&raw, expected), "Expected format %s, got %s\n", buffer2, buffer); +} + +static void test_bufferrawformat(void* buff, int size, REFGUID expected, int line, BOOL todo) +{ + LPSTREAM stream; + HGLOBAL hglob; + LPBYTE data; + HRESULT hres; + GpStatus stat; + GpBitmap *bmp; + + hglob = GlobalAlloc (0, size); + data = GlobalLock (hglob); + memcpy(data, buff, size); + GlobalUnlock(hglob); data = NULL; + + hres = CreateStreamOnHGlobal(hglob, TRUE, &stream); + ok_(__FILE__, line)(hres == S_OK, "Failed to create a stream\n"); + if(hres != S_OK) return; + + stat = GdipCreateBitmapFromStream(stream, &bmp); + ok_(__FILE__, line)(stat == Ok, "Failed to create a Bitmap\n"); + if(stat != Ok){ + IStream_Release(stream); + return; + } + + expect_rawformat(expected, (GpImage*)bmp, line, todo); + + GdipDisposeImage((GpImage*)bmp); + IStream_Release(stream); +} static void test_Scan0(void) { @@ -42,20 +98,17 @@ static void test_Scan0(void) bm = (GpBitmap*)0xdeadbeef; stat = GdipCreateBitmapFromScan0(10, -10, 10, PixelFormat24bppRGB, NULL, &bm); expect(InvalidParameter, stat); - - expect(NULL, bm); + ok( !bm, "expected null bitmap\n" ); bm = (GpBitmap*)0xdeadbeef; stat = GdipCreateBitmapFromScan0(-10, 10, 10, PixelFormat24bppRGB, NULL, &bm); expect(InvalidParameter, stat); - - expect(NULL, bm); + ok( !bm, "expected null bitmap\n" ); bm = (GpBitmap*)0xdeadbeef; stat = GdipCreateBitmapFromScan0(10, 0, 10, PixelFormat24bppRGB, NULL, &bm); expect(InvalidParameter, stat); - - expect(NULL, bm); + ok( !bm, "expected null bitmap\n" ); bm = NULL; stat = GdipCreateBitmapFromScan0(10, 10, 12, PixelFormat24bppRGB, buff, &bm); @@ -67,12 +120,24 @@ static void test_Scan0(void) bm = (GpBitmap*) 0xdeadbeef; stat = GdipCreateBitmapFromScan0(10, 10, 10, PixelFormat24bppRGB, buff, &bm); expect(InvalidParameter, stat); - expect(NULL, bm); + ok( !bm, "expected null bitmap\n" ); bm = (GpBitmap*)0xdeadbeef; stat = GdipCreateBitmapFromScan0(10, 10, 0, PixelFormat24bppRGB, buff, &bm); expect(InvalidParameter, stat); - expect(0xdeadbeef, bm); + ok( bm == (GpBitmap*)0xdeadbeef, "expected deadbeef bitmap\n" ); + + bm = NULL; + stat = GdipCreateBitmapFromScan0(10, 10, -8, PixelFormat24bppRGB, buff, &bm); + expect(Ok, stat); + ok(NULL != bm, "Expected bitmap to be initialized\n"); + if (stat == Ok) + GdipDisposeImage((GpImage*)bm); + + bm = (GpBitmap*)0xdeadbeef; + stat = GdipCreateBitmapFromScan0(10, 10, -10, PixelFormat24bppRGB, buff, &bm); + expect(InvalidParameter, stat); + ok( !bm, "expected null bitmap\n" ); } static void test_GetImageDimension(void) @@ -101,8 +166,8 @@ static void test_GetImageDimension(void) h = -1; stat = GdipGetImageDimension((GpImage*)bm,&w,&h); expect(Ok, stat); - ok(fabs(WIDTH - w) < 0.0001, "Width wrong\n"); - ok(fabs(HEIGHT - h) < 0.0001, "Height wrong\n"); + expectf(WIDTH, w); + expectf(HEIGHT, h); GdipDisposeImage((GpImage*)bm); } @@ -164,6 +229,7 @@ static void test_SavingImages(void) const REAL WIDTH = 10.0, HEIGHT = 20.0; REAL w, h; ImageCodecInfo *codecs; + static const CHAR filenameA[] = "a.bmp"; static const WCHAR filename[] = { 'a','.','b','m','p',0 }; codecs = NULL; @@ -208,14 +274,14 @@ static void test_SavingImages(void) stat = GdipGetImageDimension((GpImage*)bm, &w, &h); if (stat != Ok) goto cleanup; - ok((fabs(w - WIDTH) < 0.01) && (fabs(h - HEIGHT) < 0.01), - "Saved image dimensions are different!\n"); + expectf(WIDTH, w); + expectf(HEIGHT, h); cleanup: GdipFree(codecs); if (bm) GdipDisposeImage((GpImage*)bm); - ok(DeleteFileW(filename), "Delete failed.\n"); + ok(DeleteFileA(filenameA), "Delete failed.\n"); } static void test_encoders(void) @@ -227,7 +293,7 @@ static void test_encoders(void) int i; int bmp_found; - static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; + static const CHAR bmp_format[] = "BMP"; stat = GdipGetImageEncodersSize(&n, &s); expect(stat, Ok); @@ -254,8 +320,13 @@ static void test_encoders(void) bmp_found = FALSE; for (i = 0; i < n; i++) { - if (CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, - codecs[i].FormatDescription, -1, + CHAR desc[32]; + + WideCharToMultiByte(CP_ACP, 0, codecs[i].FormatDescription, -1, + desc, 32, 0, 0); + + if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, + desc, -1, bmp_format, -1) == CSTR_EQUAL) { bmp_found = TRUE; break; @@ -405,21 +476,24 @@ static void test_GdipCreateBitmapFromHBITMAP(void) stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm); expect(Ok, stat); expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height)); - ok(fabs(WIDTH1 - width) < .0001, "width wrong\n"); - ok(fabs(HEIGHT1 - height) < .0001, "height wrong\n"); + expectf(WIDTH1, width); + expectf(HEIGHT1, height); if (stat == Ok) GdipDisposeImage((GpImage*)gpbm); - GlobalFree(hbm); + DeleteObject(hbm); hbm = CreateBitmap(WIDTH2, HEIGHT2, 1, 1, &buff); stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm); expect(Ok, stat); + /* raw format */ + expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)gpbm, __LINE__, TRUE); + expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height)); - ok(fabs(WIDTH2 - width) < .0001, "width wrong\n"); - ok(fabs(HEIGHT2 - height) < .0001, "height wrong\n"); + expectf(WIDTH2, width); + expectf(HEIGHT2, height); if (stat == Ok) GdipDisposeImage((GpImage*)gpbm); - GlobalFree(hbm); + DeleteObject(hbm); hdc = CreateCompatibleDC(0); ok(hdc != NULL, "CreateCompatibleDC failed\n"); @@ -436,15 +510,15 @@ static void test_GdipCreateBitmapFromHBITMAP(void) stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, &gpbm); expect(Ok, stat); expect(Ok, GdipGetImageDimension((GpImage*) gpbm, &width, &height)); - ok(fabs(WIDTH1 - width) < .0001, "width wrong\n"); - ok(fabs(HEIGHT1 - height) < .0001, "height wrong\n"); + expectf(WIDTH1, width); + expectf(HEIGHT1, height); if (stat == Ok) GdipDisposeImage((GpImage*)gpbm); LogPal = GdipAlloc(sizeof(LOGPALETTE)); ok(LogPal != NULL, "unable to allocate LOGPALETTE\n"); LogPal->palVersion = 0x300; - hpal = CreatePalette((const LOGPALETTE*) LogPal); + hpal = CreatePalette(LogPal); ok(hpal != NULL, "CreatePalette failed\n"); GdipFree(LogPal); @@ -456,8 +530,8 @@ static void test_GdipCreateBitmapFromHBITMAP(void) if (stat == Ok) GdipDisposeImage((GpImage*)gpbm); - GlobalFree(hpal); - GlobalFree(hbm); + DeleteObject(hpal); + DeleteObject(hbm); } static void test_GdipGetImageFlags(void) @@ -490,21 +564,181 @@ static void test_GdipCloneImage(void) /* Create an image, clone it, delete the original, make sure the copy works */ stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm); expect(Ok, stat); -todo_wine -{ + expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)bm, __LINE__, TRUE); + image_src = ((GpImage*)bm); stat = GdipCloneImage(image_src, &image_dest); expect(Ok, stat); -} + expect_rawformat(&ImageFormatMemoryBMP, image_dest, __LINE__, TRUE); + stat = GdipDisposeImage((GpImage*)bm); expect(Ok, stat); -todo_wine -{ stat = GdipGetImageBounds(image_dest, &rectF, &unit); expect(Ok, stat); + + /* Treat FP values carefully */ + expectf((REAL)WIDTH, rectF.Width); + expectf((REAL)HEIGHT, rectF.Height); + stat = GdipDisposeImage(image_dest); expect(Ok, stat); } + +static void test_testcontrol(void) +{ + GpStatus stat; + DWORD param; + + param = 0; + stat = GdipTestControl(TestControlGetBuildNumber, ¶m); + expect(Ok, stat); + ok(param != 0, "Build number expected, got %u\n", param); +} + +static void test_fromhicon(void) +{ + static const BYTE bmp_bits[1024]; + HBITMAP hbmMask, hbmColor; + ICONINFO info; + HICON hIcon; + GpStatus stat; + GpBitmap *bitmap = NULL; + UINT dim; + ImageType type; + PixelFormat format; + + /* NULL */ + stat = GdipCreateBitmapFromHICON(NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipCreateBitmapFromHICON(NULL, &bitmap); + expect(InvalidParameter, stat); + + /* color icon 1 bit */ + hbmMask = CreateBitmap(16, 16, 1, 1, bmp_bits); + ok(hbmMask != 0, "CreateBitmap failed\n"); + hbmColor = CreateBitmap(16, 16, 1, 1, bmp_bits); + ok(hbmColor != 0, "CreateBitmap failed\n"); + info.fIcon = TRUE; + info.xHotspot = 8; + info.yHotspot = 8; + info.hbmMask = hbmMask; + info.hbmColor = hbmColor; + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + DeleteObject(hbmMask); + DeleteObject(hbmColor); + + stat = GdipCreateBitmapFromHICON(hIcon, &bitmap); + ok(stat == Ok || + broken(stat == InvalidParameter), /* Win98 */ + "Expected Ok, got %.8x\n", stat); + if(stat == Ok){ + /* check attributes */ + stat = GdipGetImageHeight((GpImage*)bitmap, &dim); + expect(Ok, stat); + expect(16, dim); + stat = GdipGetImageWidth((GpImage*)bitmap, &dim); + expect(Ok, stat); + expect(16, dim); + stat = GdipGetImageType((GpImage*)bitmap, &type); + expect(Ok, stat); + expect(ImageTypeBitmap, type); + stat = GdipGetImagePixelFormat((GpImage*)bitmap, &format); + expect(PixelFormat32bppARGB, format); + /* raw format */ + expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)bitmap, __LINE__, TRUE); + GdipDisposeImage((GpImage*)bitmap); + } + DestroyIcon(hIcon); + + /* color icon 8 bpp */ + hbmMask = CreateBitmap(16, 16, 1, 8, bmp_bits); + ok(hbmMask != 0, "CreateBitmap failed\n"); + hbmColor = CreateBitmap(16, 16, 1, 8, bmp_bits); + ok(hbmColor != 0, "CreateBitmap failed\n"); + info.fIcon = TRUE; + info.xHotspot = 8; + info.yHotspot = 8; + info.hbmMask = hbmMask; + info.hbmColor = hbmColor; + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + DeleteObject(hbmMask); + DeleteObject(hbmColor); + + stat = GdipCreateBitmapFromHICON(hIcon, &bitmap); + expect(Ok, stat); + if(stat == Ok){ + /* check attributes */ + stat = GdipGetImageHeight((GpImage*)bitmap, &dim); + expect(Ok, stat); + expect(16, dim); + stat = GdipGetImageWidth((GpImage*)bitmap, &dim); + expect(Ok, stat); + expect(16, dim); + stat = GdipGetImageType((GpImage*)bitmap, &type); + expect(Ok, stat); + expect(ImageTypeBitmap, type); + stat = GdipGetImagePixelFormat((GpImage*)bitmap, &format); + expect(PixelFormat32bppARGB, format); + /* raw format */ + expect_rawformat(&ImageFormatMemoryBMP, (GpImage*)bitmap, __LINE__, TRUE); + GdipDisposeImage((GpImage*)bitmap); + } + DestroyIcon(hIcon); +} + +/* 1x1 pixel png */ +static const unsigned char pngimage[285] = { +0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53, +0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b, +0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5, +0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41, +0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59, +0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; +/* 1x1 pixel gif */ +static const unsigned char gifimage[35] = { +0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff, +0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44, +0x01,0x00,0x3b +}; +/* 1x1 pixel bmp */ +static const unsigned char bmpimage[66] = { +0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00, +0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, +0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00, +0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00, +0x00,0x00 +}; +/* 1x1 pixel jpg */ +static const unsigned char jpgimage[285] = { +0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c, +0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05, +0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b, +0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13, +0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17, +0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05, +0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e, +0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, +0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, +0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0, +0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11, +0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4, +0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01, +0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9 +}; +static void test_getrawformat(void) +{ + test_bufferrawformat((void*)pngimage, sizeof(pngimage), &ImageFormatPNG, __LINE__, TRUE); + test_bufferrawformat((void*)gifimage, sizeof(gifimage), &ImageFormatGIF, __LINE__, TRUE); + test_bufferrawformat((void*)bmpimage, sizeof(bmpimage), &ImageFormatBMP, __LINE__, FALSE); + test_bufferrawformat((void*)jpgimage, sizeof(jpgimage), &ImageFormatJPEG, __LINE__, TRUE); } START_TEST(image) @@ -529,6 +763,9 @@ START_TEST(image) test_GdipCreateBitmapFromHBITMAP(); test_GdipGetImageFlags(); test_GdipCloneImage(); + test_testcontrol(); + test_fromhicon(); + test_getrawformat(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/matrix.c b/rostests/winetests/gdiplus/matrix.c index cc5348879f1..16ce85a6bec 100644 --- a/rostests/winetests/gdiplus/matrix.c +++ b/rostests/winetests/gdiplus/matrix.c @@ -21,6 +21,7 @@ #include #include "windows.h" +#include #include "gdiplus.h" #include "wine/test.h" @@ -89,6 +90,136 @@ static void test_transform(void) GdipDeleteMatrix(matrix); } +static void test_isinvertible(void) +{ + GpStatus status; + GpMatrix *matrix = NULL; + BOOL result; + + /* NULL arguments */ + status = GdipIsMatrixInvertible(NULL, &result); + expect(InvalidParameter, status); + status = GdipIsMatrixInvertible((GpMatrix*)0xdeadbeef, NULL); + expect(InvalidParameter, status); + status = GdipIsMatrixInvertible(NULL, NULL); + expect(InvalidParameter, status); + + /* invertible */ + GdipCreateMatrix2(1.0, 1.2, 2.3, -1.0, 2.0, 3.0, &matrix); + status = GdipIsMatrixInvertible(matrix, &result); + expect(Ok, status); + expect(TRUE, result); + GdipDeleteMatrix(matrix); + + /* noninvertible */ + GdipCreateMatrix2(2.0, -1.0, 6.0, -3.0, 2.2, 3.0, &matrix); + status = GdipIsMatrixInvertible(matrix, &result); + expect(Ok, status); + expect(FALSE, result); + GdipDeleteMatrix(matrix); +} + +static void test_invert(void) +{ + GpStatus status; + GpMatrix *matrix = NULL; + GpMatrix *inverted = NULL; + BOOL equal = FALSE; + + /* NULL */ + status = GdipInvertMatrix(NULL); + expect(InvalidParameter, status); + + /* noninvertible */ + GdipCreateMatrix2(2.0, -1.0, 6.0, -3.0, 2.2, 3.0, &matrix); + status = GdipInvertMatrix(matrix); + expect(InvalidParameter, status); + GdipDeleteMatrix(matrix); + + /* invertible */ + GdipCreateMatrix2(3.0, -2.0, 5.0, 2.0, 6.0, 3.0, &matrix); + status = GdipInvertMatrix(matrix); + expect(Ok, status); + GdipCreateMatrix2(2.0/16.0, 2.0/16.0, -5.0/16.0, 3.0/16.0, 3.0/16.0, -21.0/16.0, &inverted); + GdipIsMatrixEqual(matrix, inverted, &equal); + expect(TRUE, equal); + + GdipDeleteMatrix(inverted); + GdipDeleteMatrix(matrix); +} + +static void test_shear(void) +{ + GpStatus status; + GpMatrix *matrix = NULL; + GpMatrix *sheared = NULL; + BOOL equal; + + /* NULL */ + status = GdipShearMatrix(NULL, 0.0, 0.0, MatrixOrderPrepend); + expect(InvalidParameter, status); + + /* X only shearing, MatrixOrderPrepend */ + GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix); + status = GdipShearMatrix(matrix, 1.5, 0.0, MatrixOrderPrepend); + expect(Ok, status); + GdipCreateMatrix2(1.0, 2.0, 5.5, 2.0, 6.0, 3.0, &sheared); + GdipIsMatrixEqual(matrix, sheared, &equal); + expect(TRUE, equal); + GdipDeleteMatrix(sheared); + GdipDeleteMatrix(matrix); + + /* X only shearing, MatrixOrderAppend */ + GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix); + status = GdipShearMatrix(matrix, 1.5, 0.0, MatrixOrderAppend); + expect(Ok, status); + GdipCreateMatrix2(4.0, 2.0, 2.5, -1.0, 10.5, 3.0, &sheared); + GdipIsMatrixEqual(matrix, sheared, &equal); + expect(TRUE, equal); + GdipDeleteMatrix(sheared); + GdipDeleteMatrix(matrix); + + /* Y only shearing, MatrixOrderPrepend */ + GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix); + status = GdipShearMatrix(matrix, 0.0, 1.5, MatrixOrderPrepend); + expect(Ok, status); + GdipCreateMatrix2(7.0, 0.5, 4.0, -1.0, 6.0, 3.0, &sheared); + GdipIsMatrixEqual(matrix, sheared, &equal); + expect(TRUE, equal); + GdipDeleteMatrix(sheared); + GdipDeleteMatrix(matrix); + + /* Y only shearing, MatrixOrderAppend */ + GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix); + status = GdipShearMatrix(matrix, 0.0, 1.5, MatrixOrderAppend); + expect(Ok, status); + GdipCreateMatrix2(1.0, 3.5, 4.0, 5.0, 6.0, 12.0, &sheared); + GdipIsMatrixEqual(matrix, sheared, &equal); + expect(TRUE, equal); + GdipDeleteMatrix(sheared); + GdipDeleteMatrix(matrix); + + /* X,Y shearing, MatrixOrderPrepend */ + GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix); + status = GdipShearMatrix(matrix, 4.0, 1.5, MatrixOrderPrepend); + expect(Ok, status); + GdipCreateMatrix2(7.0, 0.5, 8.0, 7.0, 6.0, 3.0, &sheared); + GdipIsMatrixEqual(matrix, sheared, &equal); + expect(TRUE, equal); + GdipDeleteMatrix(sheared); + GdipDeleteMatrix(matrix); + + /* X,Y shearing, MatrixOrderAppend */ + GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix); + status = GdipShearMatrix(matrix, 4.0, 1.5, MatrixOrderAppend); + expect(Ok, status); + GdipCreateMatrix2(9.0, 3.5, 0.0, 5.0, 18.0, 12.0, &sheared); + GdipIsMatrixEqual(matrix, sheared, &equal); + expect(TRUE, equal); + GdipDeleteMatrix(sheared); + GdipDeleteMatrix(matrix); +} + START_TEST(matrix) { struct GdiplusStartupInput gdiplusStartupInput; @@ -103,6 +234,9 @@ START_TEST(matrix) test_constructor_destructor(); test_transform(); + test_isinvertible(); + test_invert(); + test_shear(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/pathiterator.c b/rostests/winetests/gdiplus/pathiterator.c index baeb22ba6f2..eddb24e89fd 100644 --- a/rostests/winetests/gdiplus/pathiterator.c +++ b/rostests/winetests/gdiplus/pathiterator.c @@ -37,7 +37,7 @@ static void test_constructor_destructor(void) stat = GdipCreatePathIter(NULL, NULL); expect(InvalidParameter, stat); stat = GdipCreatePathIter(&iter, NULL); - expect(InvalidParameter, stat); + expect(Ok, stat); stat = GdipCreatePathIter(NULL, path); expect(InvalidParameter, stat); stat = GdipDeletePathIter(NULL); @@ -90,6 +90,467 @@ static void test_hascurve(void) GdipDeletePath(path); } +static void test_nextmarker(void) +{ + GpPath *path; + GpPathIterator *iter; + GpStatus stat; + INT start, end; + INT result; + + /* NULL args + BOOL out argument is local in wrapper class method, + so it always has not-NULL address */ + stat = GdipPathIterNextMarker(NULL, &result, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextMarker(NULL, &result, &start, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextMarker(NULL, &result, NULL, &end); + expect(InvalidParameter, stat); + + GdipCreatePath(FillModeAlternate, &path); + GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0); + + /* no markers */ + GdipCreatePathIter(&iter, path); + start = end = result = (INT)0xdeadbeef; + stat = GdipPathIterNextMarker(iter, &result, &start, &end); + expect(Ok, stat); + expect(0, start); + expect(3, end); + expect(4, result); + start = end = result = (INT)0xdeadbeef; + stat = GdipPathIterNextMarker(iter, &result, &start, &end); + /* start/end remain unchanged */ + expect((INT)0xdeadbeef, start); + expect((INT)0xdeadbeef, end); + expect(0, result); + GdipDeletePathIter(iter); + + /* one marker */ + GdipSetPathMarker(path); + GdipCreatePathIter(&iter, path); + start = end = result = (INT)0xdeadbeef; + stat = GdipPathIterNextMarker(iter, &result, &start, &end); + expect(Ok, stat); + expect(0, start); + expect(3, end); + expect(4, result); + start = end = result = (INT)0xdeadbeef; + stat = GdipPathIterNextMarker(iter, &result, &start, &end); + expect(Ok, stat); + expect((INT)0xdeadbeef, start); + expect((INT)0xdeadbeef, end); + expect(0, result); + GdipDeletePathIter(iter); + + /* two markers */ + GdipAddPathLine(path, 0.0, 0.0, 10.0, 30.0); + GdipSetPathMarker(path); + GdipCreatePathIter(&iter, path); + start = end = result = (INT)0xdeadbeef; + stat = GdipPathIterNextMarker(iter, &result, &start, &end); + expect(Ok, stat); + expect(0, start); + expect(3, end); + expect(4, result); + start = end = result = (INT)0xdeadbeef; + stat = GdipPathIterNextMarker(iter, &result, &start, &end); + expect(Ok, stat); + expect(4, start); + expect(5, end); + expect(2, result); + start = end = result = (INT)0xdeadbeef; + stat = GdipPathIterNextMarker(iter, &result, &start, &end); + expect(Ok, stat); + expect((INT)0xdeadbeef, start); + expect((INT)0xdeadbeef, end); + expect(0, result); + GdipDeletePathIter(iter); + + GdipDeletePath(path); +} + +static void test_nextmarkerpath(void) +{ + GpPath *path, *retpath; + GpPathIterator *iter; + GpStatus stat; + INT result, count; + + GdipCreatePath(FillModeAlternate, &path); + + /* NULL */ + stat = GdipPathIterNextMarkerPath(NULL, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextMarkerPath(NULL, &result, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextMarkerPath(NULL, &result, path); + expect(InvalidParameter, stat); + + GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0); + + /* no markers */ + GdipCreatePath(FillModeAlternate, &retpath); + GdipCreatePathIter(&iter, path); + result = -1; + stat = GdipPathIterNextMarkerPath(iter, &result, retpath); + expect(Ok, stat); + expect(4, result); + count = -1; + GdipGetPointCount(retpath, &count); + expect(4, count); + result = -1; + stat = GdipPathIterNextMarkerPath(iter, &result, retpath); + expect(Ok, stat); + expect(0, result); + count = -1; + GdipGetPointCount(retpath, &count); + expect(4, count); + GdipDeletePathIter(iter); + GdipDeletePath(retpath); + + /* one marker */ + GdipSetPathMarker(path); + GdipCreatePath(FillModeAlternate, &retpath); + GdipCreatePathIter(&iter, path); + result = -1; + stat = GdipPathIterNextMarkerPath(iter, &result, retpath); + expect(Ok, stat); + expect(4, result); + count = -1; + GdipGetPointCount(retpath, &count); + expect(4, count); + result = -1; + stat = GdipPathIterNextMarkerPath(iter, &result, retpath); + expect(Ok, stat); + expect(0, result); + count = -1; + GdipGetPointCount(retpath, &count); + expect(4, count); + GdipDeletePathIter(iter); + GdipDeletePath(retpath); + + /* two markers */ + GdipAddPathLine(path, 0.0, 0.0, 10.0, 30.0); + GdipSetPathMarker(path); + GdipCreatePath(FillModeAlternate, &retpath); + GdipCreatePathIter(&iter, path); + result = -1; + stat = GdipPathIterNextMarkerPath(iter, &result, retpath); + expect(Ok, stat); + expect(4, result); + result = -1; + stat = GdipPathIterNextMarkerPath(iter, &result, retpath); + expect(Ok, stat); + expect(2, result); + result = -1; + stat = GdipPathIterNextMarkerPath(iter, &result, retpath); + expect(Ok, stat); + expect(0, result); + GdipDeletePathIter(iter); + GdipDeletePath(retpath); + + GdipDeletePath(path); +} + +static void test_getsubpathcount(void) +{ + GpPath *path; + GpPathIterator *iter; + GpStatus stat; + INT count; + + /* NULL args */ + stat = GdipPathIterGetSubpathCount(NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterGetSubpathCount(NULL, &count); + expect(InvalidParameter, stat); + + GdipCreatePath(FillModeAlternate, &path); + + /* empty path */ + GdipCreatePathIter(&iter, path); + stat = GdipPathIterGetSubpathCount(iter, &count); + expect(Ok, stat); + expect(0, count); + GdipDeletePathIter(iter); + + GdipAddPathLine(path, 5.0, 5.0, 100.0, 50.0); + + /* open figure */ + GdipCreatePathIter(&iter, path); + stat = GdipPathIterGetSubpathCount(iter, &count); + expect(Ok, stat); + expect(1, count); + GdipDeletePathIter(iter); + + /* manually start new figure */ + GdipStartPathFigure(path); + GdipAddPathLine(path, 50.0, 50.0, 110.0, 40.0); + GdipCreatePathIter(&iter, path); + stat = GdipPathIterGetSubpathCount(iter, &count); + expect(Ok, stat); + expect(2, count); + GdipDeletePathIter(iter); + + GdipDeletePath(path); +} + +static void test_isvalid(void) +{ + GpPath *path; + GpPathIterator *iter; + GpStatus stat; + BOOL isvalid; + INT start, end, result; + + GdipCreatePath(FillModeAlternate, &path); + + /* NULL args */ + GdipCreatePathIter(&iter, path); + stat = GdipPathIterIsValid(NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterIsValid(iter, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterIsValid(NULL, &isvalid); + expect(InvalidParameter, stat); + GdipDeletePathIter(iter); + + /* on empty path */ + GdipCreatePathIter(&iter, path); + isvalid = FALSE; + stat = GdipPathIterIsValid(iter, &isvalid); + expect(Ok, stat); + expect(TRUE, isvalid); + GdipDeletePathIter(iter); + + /* no markers */ + GdipAddPathLine(path, 50.0, 50.0, 110.0, 40.0); + GdipCreatePathIter(&iter, path); + GdipPathIterNextMarker(iter, &result, &start, &end); + isvalid = FALSE; + stat = GdipPathIterIsValid(iter, &isvalid); + expect(Ok, stat); + expect(TRUE, isvalid); + GdipDeletePathIter(iter); + + GdipDeletePath(path); +} + +static void test_nextsubpathpath(void) +{ + GpPath *path, *retpath; + GpPathIterator *iter; + GpStatus stat; + BOOL closed; + INT count, result; + + GdipCreatePath(FillModeAlternate, &path); + + /* NULL args */ + GdipCreatePath(FillModeAlternate, &retpath); + GdipCreatePathIter(&iter, path); + stat = GdipPathIterNextSubpathPath(NULL, NULL, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextSubpathPath(iter, NULL, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextSubpathPath(NULL, &result, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextSubpathPath(iter, &result, NULL, &closed); + expect(Ok, stat); + stat = GdipPathIterNextSubpathPath(iter, NULL, NULL, &closed); + expect(InvalidParameter, stat); + stat = GdipPathIterNextSubpathPath(iter, NULL, retpath, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextSubpathPath(iter, &result, retpath, NULL); + expect(InvalidParameter, stat); + GdipDeletePathIter(iter); + GdipDeletePath(retpath); + + /* empty path */ + GdipCreatePath(FillModeAlternate, &retpath); + GdipCreatePathIter(&iter, path); + result = -2; + closed = TRUE; + stat = GdipPathIterNextSubpathPath(iter, &result, retpath, &closed); + expect(Ok, stat); + expect(0, result); + expect(TRUE, closed); + count = -1; + GdipGetPointCount(retpath, &count); + expect(0, count); + GdipDeletePathIter(iter); + GdipDeletePath(retpath); + + /* open figure */ + GdipAddPathLine(path, 5.0, 5.0, 100.0, 50.0); + + GdipCreatePath(FillModeAlternate, &retpath); + GdipCreatePathIter(&iter, path); + result = -2; + closed = TRUE; + stat = GdipPathIterNextSubpathPath(iter, &result, retpath, &closed); + expect(Ok, stat); + expect(2, result); + expect(FALSE, closed); + count = -1; + GdipGetPointCount(retpath, &count); + expect(2, count); + /* subsequent call */ + result = -2; + closed = TRUE; + stat = GdipPathIterNextSubpathPath(iter, &result, retpath, &closed); + expect(Ok, stat); + expect(0, result); + expect(TRUE, closed); + count = -1; + GdipGetPointCount(retpath, &count); + expect(2, count); + GdipDeletePathIter(iter); + + /* closed figure, check does it extend retpath or reset it */ + GdipAddPathLine(retpath, 50.0, 55.0, 200.0, 150.0); + + GdipClosePathFigure(path); + GdipAddPathLine(path, 50.0, 55.0, 200.0, 150.0); + GdipClosePathFigure(path); + + GdipCreatePathIter(&iter, path); + result = -2; + closed = FALSE; + stat = GdipPathIterNextSubpathPath(iter, &result, retpath, &closed); + expect(Ok, stat); + expect(2, result); + expect(TRUE, closed); + count = -1; + GdipGetPointCount(retpath, &count); + expect(2, count); + /* subsequent call */ + result = -2; + closed = FALSE; + stat = GdipPathIterNextSubpathPath(iter, &result, retpath, &closed); + expect(Ok, stat); + expect(2, result); + expect(TRUE, closed); + count = -1; + GdipGetPointCount(retpath, &count); + expect(2, count); + result = -2; + closed = FALSE; + stat = GdipPathIterNextSubpathPath(iter, &result, retpath, &closed); + expect(Ok, stat); + expect(0, result); + expect(TRUE, closed); + count = -1; + GdipGetPointCount(retpath, &count); + expect(2, count); + GdipDeletePathIter(iter); + + GdipDeletePath(retpath); + GdipDeletePath(path); +} + +static void test_nextsubpath(void) +{ + GpPath *path; + GpPathIterator *iter; + GpStatus stat; + INT start, end, result; + BOOL closed; + + /* empty path */ + GdipCreatePath(FillModeAlternate, &path); + GdipCreatePathIter(&iter, path); + + result = -2; + closed = TRUE; + stat = GdipPathIterNextSubpath(iter, &result, &start, &end, &closed); + expect(Ok, stat); + expect(0, result); + expect(TRUE, closed); + + GdipDeletePathIter(iter); + GdipDeletePath(path); +} + +static void test_nextpathtype(void) +{ + GpPath *path; + GpPathIterator *iter; + GpStatus stat; + INT start, end, result; + BYTE type; + + GdipCreatePath(FillModeAlternate, &path); + GdipCreatePathIter(&iter, path); + + /* NULL arguments */ + stat = GdipPathIterNextPathType(NULL, NULL, NULL, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextPathType(iter, NULL, NULL, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextPathType(iter, &result, NULL, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextPathType(iter, NULL, &type, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipPathIterNextPathType(iter, NULL, NULL, &start, &end); + expect(InvalidParameter, stat); + stat = GdipPathIterNextPathType(iter, NULL, &type, &start, &end); + expect(InvalidParameter, stat); + stat = GdipPathIterNextPathType(iter, &result, &type, NULL, NULL); + expect(InvalidParameter, stat); + + /* empty path */ + start = end = result = (INT)0xdeadbeef; + stat = GdipPathIterNextPathType(iter, &result, &type, &start, &end); + todo_wine expect(Ok, stat); + expect((INT)0xdeadbeef, start); + expect((INT)0xdeadbeef, end); + todo_wine expect(0, result); + GdipDeletePathIter(iter); + + /* single figure */ + GdipAddPathLine(path, 0.0, 0.0, 10.0, 30.0); + GdipCreatePathIter(&iter, path); + start = end = result = (INT)0xdeadbeef; + type = 255; /* out of range */ + stat = GdipPathIterNextPathType(iter, &result, &type, &start, &end); + todo_wine expect(Ok, stat); + expect((INT)0xdeadbeef, start); + expect((INT)0xdeadbeef, end); + expect(255, type); + todo_wine expect(0, result); + GdipDeletePathIter(iter); + + GdipAddPathEllipse(path, 0.0, 0.0, 35.0, 70.0); + GdipCreatePathIter(&iter, path); + start = end = result = (INT)0xdeadbeef; + type = 255; /* out of range */ + stat = GdipPathIterNextPathType(iter, &result, &type, &start, &end); + todo_wine expect(Ok, stat); + expect((INT)0xdeadbeef, start); + expect((INT)0xdeadbeef, end); + expect(255, type); + todo_wine expect(0, result); + GdipDeletePathIter(iter); + + /* closed */ + GdipClosePathFigure(path); + GdipCreatePathIter(&iter, path); + start = end = result = (INT)0xdeadbeef; + type = 255; /* out of range */ + stat = GdipPathIterNextPathType(iter, &result, &type, &start, &end); + todo_wine expect(Ok, stat); + expect((INT)0xdeadbeef, start); + expect((INT)0xdeadbeef, end); + expect(255, type); + todo_wine expect(0, result); + GdipDeletePathIter(iter); + + GdipDeletePath(path); +} + START_TEST(pathiterator) { struct GdiplusStartupInput gdiplusStartupInput; @@ -104,6 +565,13 @@ START_TEST(pathiterator) test_constructor_destructor(); test_hascurve(); + test_nextmarker(); + test_nextmarkerpath(); + test_getsubpathcount(); + test_isvalid(); + test_nextsubpathpath(); + test_nextsubpath(); + test_nextpathtype(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/pen.c b/rostests/winetests/gdiplus/pen.c index ad484ce4776..d2f33f0f4ad 100644 --- a/rostests/winetests/gdiplus/pen.c +++ b/rostests/winetests/gdiplus/pen.c @@ -226,6 +226,132 @@ static void test_dasharray(void) GdipDeletePen(pen); } +static void test_customcap(void) +{ + GpPen *pen; + GpStatus status; + GpCustomLineCap *custom; + + status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); + expect(Ok, status); + + /* NULL args */ + status = GdipGetPenCustomStartCap(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetPenCustomStartCap(pen, NULL); + expect(InvalidParameter, status); + status = GdipGetPenCustomStartCap(NULL, &custom); + expect(InvalidParameter, status); + + status = GdipGetPenCustomEndCap(NULL, NULL); + expect(InvalidParameter, status); + status = GdipGetPenCustomEndCap(pen, NULL); + expect(InvalidParameter, status); + status = GdipGetPenCustomEndCap(NULL, &custom); + expect(InvalidParameter, status); + + /* native crashes on pen == NULL, custom != NULL */ + status = GdipSetPenCustomStartCap(NULL, NULL); + expect(InvalidParameter, status); + status = GdipSetPenCustomStartCap(pen, NULL); + expect(InvalidParameter, status); + + status = GdipSetPenCustomEndCap(NULL, NULL); + expect(InvalidParameter, status); + status = GdipSetPenCustomEndCap(pen, NULL); + expect(InvalidParameter, status); + + /* get without setting previously */ + custom = (GpCustomLineCap*)0xdeadbeef; + status = GdipGetPenCustomEndCap(pen, &custom); + expect(Ok, status); + ok(custom == NULL,"Expect CustomCap == NULL\n"); + + custom = (GpCustomLineCap*)0xdeadbeef; + status = GdipGetPenCustomStartCap(pen, &custom); + expect(Ok, status); + ok(custom == NULL,"Expect CustomCap == NULL\n"); + + GdipDeletePen(pen); +} + +static void test_penfilltype(void) +{ + GpPen *pen; + GpSolidFill *solid; + GpLineGradient *line; + GpPointF a, b; + GpStatus status; + GpPenType type; + + /* NULL */ + status = GdipGetPenFillType(NULL, NULL); + expect(InvalidParameter, status); + + status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); + expect(Ok, status); + status = GdipGetPenFillType(pen, NULL); + expect(InvalidParameter, status); + + /* created with GdipCreatePen1() */ + status = GdipGetPenFillType(pen, &type); + expect(Ok, status); + expect(PenTypeSolidColor, type); + GdipDeletePen(pen); + + /* based on SolidBrush */ + status = GdipCreateSolidFill((ARGB)0xffff00ff, &solid); + expect(Ok, status); + status = GdipCreatePen2((GpBrush*)solid, 10.0f, UnitPixel, &pen); + expect(Ok, status); + status = GdipGetPenFillType(pen, &type); + expect(Ok, status); + expect(PenTypeSolidColor, type); + GdipDeletePen(pen); + GdipDeleteBrush((GpBrush*)solid); + + /* based on LinearGradientBrush */ + a.X = a.Y = 0.0; + b.X = b.Y = 10.0; + status = GdipCreateLineBrush(&a, &b, (ARGB)0xffff00ff, (ARGB)0xffff0000, + WrapModeTile, &line); + expect(Ok, status); + status = GdipCreatePen2((GpBrush*)line, 10.0f, UnitPixel, &pen); + expect(Ok, status); + status = GdipGetPenFillType(pen, &type); + expect(Ok, status); + expect(PenTypeLinearGradient, type); + GdipDeletePen(pen); + GdipDeleteBrush((GpBrush*)line); +} + +static void test_compoundarray(void) +{ + GpStatus status; + GpPen *pen; + static const REAL testvalues[] = {0.2, 0.4, 0.6, 0.8}; + + status = GdipSetPenCompoundArray(NULL, testvalues, 4); + expect(InvalidParameter, status); + + status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); + expect(Ok, status); + + status = GdipSetPenCompoundArray(pen, NULL, 4); + expect(InvalidParameter, status); + status = GdipSetPenCompoundArray(pen, testvalues, 3); + expect(InvalidParameter, status); + status = GdipSetPenCompoundArray(pen, testvalues, 0); + expect(InvalidParameter, status); + status = GdipSetPenCompoundArray(pen, testvalues, -2); + expect(InvalidParameter, status); + + status = GdipSetPenCompoundArray(pen, testvalues, 4); + todo_wine expect(Ok, status); + + GdipDeletePen(pen); +} + START_TEST(pen) { struct GdiplusStartupInput gdiplusStartupInput; @@ -244,6 +370,9 @@ START_TEST(pen) test_constructor_destructor2(); test_brushfill(); test_dasharray(); + test_customcap(); + test_penfilltype(); + test_compoundarray(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/region.c b/rostests/winetests/gdiplus/region.c index 166df2d17d9..d48554c48b6 100644 --- a/rostests/winetests/gdiplus/region.c +++ b/rostests/winetests/gdiplus/region.c @@ -23,10 +23,19 @@ #include "wingdi.h" #include "wine/test.h" -static inline void expect_dword(DWORD *value, DWORD expected) -{ - ok(*value == expected, "expected %08x got %08x\n", expected, *value); -} +#define RGNDATA_RECT 0x10000000 +#define RGNDATA_PATH 0x10000001 +#define RGNDATA_EMPTY_RECT 0x10000002 +#define RGNDATA_INFINITE_RECT 0x10000003 + +#define RGNDATA_MAGIC 0xdbc01001 +#define RGNDATA_MAGIC2 0xdbc01002 + +#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) + +#define expect_magic(value) ok(*value == RGNDATA_MAGIC || *value == RGNDATA_MAGIC2, "Expected a known magic value, got %8x\n", *value) + +#define expect_dword(value, expected) ok(*(value) == expected, "expected %08x got %08x\n", expected, *(value)) static inline void expect_float(DWORD *value, FLOAT expected) { @@ -34,59 +43,117 @@ static inline void expect_float(DWORD *value, FLOAT expected) ok(valuef == expected, "expected %f got %f\n", expected, valuef); } -static void test_create_rgn(void) +/* We get shorts back, not INTs like a GpPoint */ +typedef struct RegionDataPoint +{ + short X, Y; +} RegionDataPoint; + +static void verify_region(HRGN hrgn, const RECT *rc) +{ + union + { + RGNDATA data; + char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)]; + } rgn; + const RECT *rect; + DWORD ret; + + ret = GetRegionData(hrgn, 0, NULL); + if (IsRectEmpty(rc)) + ok(ret == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", ret); + else + ok(ret == sizeof(rgn.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret); + + if (!ret) return; + + ret = GetRegionData(hrgn, sizeof(rgn), &rgn.data); + if (IsRectEmpty(rc)) + ok(ret == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", ret); + else + ok(ret == sizeof(rgn.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret); + + trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n", + rgn.data.rdh.dwSize, rgn.data.rdh.iType, + rgn.data.rdh.nCount, rgn.data.rdh.nRgnSize, + rgn.data.rdh.rcBound.left, rgn.data.rdh.rcBound.top, + rgn.data.rdh.rcBound.right, rgn.data.rdh.rcBound.bottom); + if (rgn.data.rdh.nCount != 0) + { + rect = (const RECT *)rgn.data.Buffer; + trace("rect (%d,%d-%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom); + ok(EqualRect(rect, rc), "rects don't match\n"); + } + + ok(rgn.data.rdh.dwSize == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", rgn.data.rdh.dwSize); + ok(rgn.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn.data.rdh.iType); + if (IsRectEmpty(rc)) + { + ok(rgn.data.rdh.nCount == 0, "expected 0, got %u\n", rgn.data.rdh.nCount); + ok(rgn.data.rdh.nRgnSize == 0, "expected 0, got %u\n", rgn.data.rdh.nRgnSize); + } + else + { + ok(rgn.data.rdh.nCount == 1, "expected 1, got %u\n", rgn.data.rdh.nCount); + ok(rgn.data.rdh.nRgnSize == sizeof(RECT), "expected sizeof(RECT), got %u\n", rgn.data.rdh.nRgnSize); + } + ok(EqualRect(&rgn.data.rdh.rcBound, rc), "rects don't match\n"); +} + +static void test_getregiondata(void) { GpStatus status; GpRegion *region, *region2; + RegionDataPoint *point; UINT needed; DWORD buf[100]; GpRect rect; + GpPath *path; + + memset(buf, 0xee, sizeof(buf)); status = GdipCreateRegion(®ion); -todo_wine ok(status == Ok, "status %08x\n", status); - if(status != Ok) return; - status = GdipGetRegionDataSize(region, &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 20, "got %d\n", needed); + expect(20, needed); status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 20, "got %d\n", needed); + expect(20, needed); expect_dword(buf, 12); trace("buf[1] = %08x\n", buf[1]); - expect_dword(buf + 2, 0xdbc01001); + expect_magic((DWORD*)(buf + 2)); expect_dword(buf + 3, 0); - expect_dword(buf + 4, 0x10000003); + expect_dword(buf + 4, RGNDATA_INFINITE_RECT); status = GdipSetEmpty(region); ok(status == Ok, "status %08x\n", status); status = GdipGetRegionDataSize(region, &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 20, "got %d\n", needed); + expect(20, needed); status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 20, "got %d\n", needed); + expect(20, needed); expect_dword(buf, 12); trace("buf[1] = %08x\n", buf[1]); - expect_dword(buf + 2, 0xdbc01001); + expect_magic((DWORD*)(buf + 2)); expect_dword(buf + 3, 0); - expect_dword(buf + 4, 0x10000002); + expect_dword(buf + 4, RGNDATA_EMPTY_RECT); status = GdipSetInfinite(region); ok(status == Ok, "status %08x\n", status); status = GdipGetRegionDataSize(region, &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 20, "got %d\n", needed); + expect(20, needed); status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 20, "got %d\n", needed); + expect(20, needed); expect_dword(buf, 12); trace("buf[1] = %08x\n", buf[1]); - expect_dword(buf + 2, 0xdbc01001); + expect_magic((DWORD*)(buf + 2)); expect_dword(buf + 3, 0); - expect_dword(buf + 4, 0x10000003); + expect_dword(buf + 4, RGNDATA_INFINITE_RECT); status = GdipDeleteRegion(region); ok(status == Ok, "status %08x\n", status); @@ -99,15 +166,15 @@ todo_wine ok(status == Ok, "status %08x\n", status); status = GdipGetRegionDataSize(region, &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 36, "got %d\n", needed); + expect(36, needed); status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 36, "got %d\n", needed); + expect(36, needed); expect_dword(buf, 28); trace("buf[1] = %08x\n", buf[1]); - expect_dword(buf + 2, 0xdbc01001); + expect_magic((DWORD*)(buf + 2)); expect_dword(buf + 3, 0); - expect_dword(buf + 4, 0x10000000); + expect_dword(buf + 4, RGNDATA_RECT); expect_float(buf + 5, 10.0); expect_float(buf + 6, 20.0); expect_float(buf + 7, 100.0); @@ -151,56 +218,969 @@ todo_wine status = GdipGetRegionDataSize(region, &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 156, "got %d\n", needed); + expect(156, needed); status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); ok(status == Ok, "status %08x\n", status); - ok(needed == 156, "got %d\n", needed); + expect(156, needed); expect_dword(buf, 148); trace("buf[1] = %08x\n", buf[1]); - expect_dword(buf + 2, 0xdbc01001); + expect_magic((DWORD*)(buf + 2)); expect_dword(buf + 3, 10); expect_dword(buf + 4, CombineModeExclude); expect_dword(buf + 5, CombineModeComplement); expect_dword(buf + 6, CombineModeXor); expect_dword(buf + 7, CombineModeIntersect); - expect_dword(buf + 8, 0x10000000); + expect_dword(buf + 8, RGNDATA_RECT); expect_float(buf + 9, 10.0); expect_float(buf + 10, 20.0); expect_float(buf + 11, 100.0); expect_float(buf + 12, 200.0); - expect_dword(buf + 13, 0x10000000); + expect_dword(buf + 13, RGNDATA_RECT); expect_float(buf + 14, 50.0); expect_float(buf + 15, 30.0); expect_float(buf + 16, 10.0); expect_float(buf + 17, 20.0); - expect_dword(buf + 18, 0x10000000); + expect_dword(buf + 18, RGNDATA_RECT); expect_float(buf + 19, 100.0); expect_float(buf + 20, 300.0); expect_float(buf + 21, 30.0); expect_float(buf + 22, 50.0); expect_dword(buf + 23, CombineModeUnion); - expect_dword(buf + 24, 0x10000000); + expect_dword(buf + 24, RGNDATA_RECT); expect_float(buf + 25, 200.0); expect_float(buf + 26, 100.0); expect_float(buf + 27, 133.0); expect_float(buf + 28, 266.0); - expect_dword(buf + 29, 0x10000000); + expect_dword(buf + 29, RGNDATA_RECT); expect_float(buf + 30, 20.0); expect_float(buf + 31, 10.0); expect_float(buf + 32, 40.0); expect_float(buf + 33, 66.0); - expect_dword(buf + 34, 0x10000000); + expect_dword(buf + 34, RGNDATA_RECT); expect_float(buf + 35, 400.0); expect_float(buf + 36, 500.0); expect_float(buf + 37, 22.0); expect_float(buf + 38, 55.0); - status = GdipDeleteRegion(region2); ok(status == Ok, "status %08x\n", status); status = GdipDeleteRegion(region); ok(status == Ok, "status %08x\n", status); + /* Try some paths */ + + status = GdipCreatePath(FillModeAlternate, &path); + ok(status == Ok, "status %08x\n", status); + GdipAddPathRectangle(path, 12.5, 13.0, 14.0, 15.0); + + status = GdipCreateRegionPath(path, ®ion); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionDataSize(region, &needed); + ok(status == Ok, "status %08x\n", status); + expect(72, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + ok(status == Ok, "status %08x\n", status); + expect(72, needed); + expect_dword(buf, 64); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_PATH); + expect_dword(buf + 5, 0x00000030); + expect_magic((DWORD*)(buf + 6)); + expect_dword(buf + 7, 0x00000004); + expect_dword(buf + 8, 0x00000000); + expect_float(buf + 9, 12.5); + expect_float(buf + 10, 13.0); + expect_float(buf + 11, 26.5); + expect_float(buf + 12, 13.0); + expect_float(buf + 13, 26.5); + expect_float(buf + 14, 28.0); + expect_float(buf + 15, 12.5); + expect_float(buf + 16, 28.0); + expect_dword(buf + 17, 0x81010100); + + + rect.X = 50; + rect.Y = 30; + rect.Width = 10; + rect.Height = 20; + status = GdipCombineRegionRectI(region, &rect, CombineModeIntersect); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionDataSize(region, &needed); + ok(status == Ok, "status %08x\n", status); + expect(96, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + ok(status == Ok, "status %08x\n", status); + expect(96, needed); + expect_dword(buf, 88); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 2); + expect_dword(buf + 4, CombineModeIntersect); + expect_dword(buf + 5, RGNDATA_PATH); + expect_dword(buf + 6, 0x00000030); + expect_magic((DWORD*)(buf + 7)); + expect_dword(buf + 8, 0x00000004); + expect_dword(buf + 9, 0x00000000); + expect_float(buf + 10, 12.5); + expect_float(buf + 11, 13.0); + expect_float(buf + 12, 26.5); + expect_float(buf + 13, 13.0); + expect_float(buf + 14, 26.5); + expect_float(buf + 15, 28.0); + expect_float(buf + 16, 12.5); + expect_float(buf + 17, 28.0); + expect_dword(buf + 18, 0x81010100); + expect_dword(buf + 19, RGNDATA_RECT); + expect_float(buf + 20, 50.0); + expect_float(buf + 21, 30.0); + expect_float(buf + 22, 10.0); + expect_float(buf + 23, 20.0); + + status = GdipDeleteRegion(region); + ok(status == Ok, "status %08x\n", status); + status = GdipDeletePath(path); + ok(status == Ok, "status %08x\n", status); + + /* Test an empty path */ + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + status = GdipCreateRegionPath(path, ®ion); + expect(Ok, status); + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(36, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + expect(36, needed); + expect_dword(buf, 28); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_PATH); + + /* Second signature for pathdata */ + expect_dword(buf + 5, 12); + expect_magic((DWORD*)(buf + 6)); + expect_dword(buf + 7, 0); + expect_dword(buf + 8, 0x00004000); + + status = GdipDeleteRegion(region); + expect(Ok, status); + + /* Test a simple triangle of INTs */ + status = GdipAddPathLine(path, 5, 6, 7, 8); + expect(Ok, status); + status = GdipAddPathLine(path, 8, 1, 5, 6); + expect(Ok, status); + status = GdipClosePathFigure(path); + expect(Ok, status); + status = GdipCreateRegionPath(path, ®ion); + expect(Ok, status); + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(56, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + expect(56, needed); + expect_dword(buf, 48); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3 , 0); + expect_dword(buf + 4 , RGNDATA_PATH); + + expect_dword(buf + 5, 32); + expect_magic((DWORD*)(buf + 6)); + expect_dword(buf + 7, 4); + expect_dword(buf + 8, 0x00004000); /* ?? */ + + point = (RegionDataPoint*)buf + 9; + expect(5, point[0].X); + expect(6, point[0].Y); + expect(7, point[1].X); /* buf + 10 */ + expect(8, point[1].Y); + expect(8, point[2].X); /* buf + 11 */ + expect(1, point[2].Y); + expect(5, point[3].X); /* buf + 12 */ + expect(6, point[3].Y); + expect_dword(buf + 13, 0x81010100); /* 0x01010100 if we don't close the path */ + + status = GdipDeletePath(path); + expect(Ok, status); + status = GdipDeleteRegion(region); + expect(Ok, status); + + /* Test a floating-point triangle */ + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + status = GdipAddPathLine(path, 5.6, 6.2, 7.2, 8.9); + expect(Ok, status); + status = GdipAddPathLine(path, 8.1, 1.6, 5.6, 6.2); + expect(Ok, status); + status = GdipCreateRegionPath(path, ®ion); + expect(Ok, status); + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(72, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + expect(72, needed); + expect_dword(buf, 64); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_PATH); + + expect_dword(buf + 5, 48); + expect_magic((DWORD*)(buf + 6)); + expect_dword(buf + 7, 4); + expect_dword(buf + 8, 0); + expect_float(buf + 9, 5.6); + expect_float(buf + 10, 6.2); + expect_float(buf + 11, 7.2); + expect_float(buf + 12, 8.9); + expect_float(buf + 13, 8.1); + expect_float(buf + 14, 1.6); + expect_float(buf + 15, 5.6); + expect_float(buf + 16, 6.2); + + status = GdipDeletePath(path); + expect(Ok, status); + status = GdipDeleteRegion(region); + expect(Ok, status); + + /* Test for a path with > 4 points, and CombineRegionPath */ + GdipCreatePath(FillModeAlternate, &path); + status = GdipAddPathLine(path, 50, 70.2, 60, 102.8); + expect(Ok, status); + status = GdipAddPathLine(path, 55.4, 122.4, 40.4, 60.2); + expect(Ok, status); + status = GdipAddPathLine(path, 45.6, 20.2, 50, 70.2); + expect(Ok, status); + rect.X = 20; + rect.Y = 25; + rect.Width = 60; + rect.Height = 120; + status = GdipCreateRegionRectI(&rect, ®ion); + expect(Ok, status); + status = GdipCombineRegionPath(region, path, CombineModeUnion); + expect(Ok, status); + + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(116, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + expect(116, needed); + expect_dword(buf, 108); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 2); + expect_dword(buf + 4, CombineModeUnion); + expect_dword(buf + 5, RGNDATA_RECT); + expect_float(buf + 6, 20); + expect_float(buf + 7, 25); + expect_float(buf + 8, 60); + expect_float(buf + 9, 120); + expect_dword(buf + 10, RGNDATA_PATH); + + expect_dword(buf + 11, 68); + expect_magic((DWORD*)(buf + 12)); + expect_dword(buf + 13, 6); + expect_float(buf + 14, 0x0); + + expect_float(buf + 15, 50); + expect_float(buf + 16, 70.2); + expect_float(buf + 17, 60); + expect_float(buf + 18, 102.8); + expect_float(buf + 19, 55.4); + expect_float(buf + 20, 122.4); + expect_float(buf + 21, 40.4); + expect_float(buf + 22, 60.2); + expect_float(buf + 23, 45.6); + expect_float(buf + 24, 20.2); + expect_float(buf + 25, 50); + expect_float(buf + 26, 70.2); + expect_dword(buf + 27, 0x01010100); + expect_dword(buf + 28, 0x00000101); + + status = GdipDeletePath(path); + expect(Ok, status); + status = GdipDeleteRegion(region); + expect(Ok, status); +} + +static void test_isinfinite(void) +{ + GpStatus status; + GpRegion *region; + GpGraphics *graphics = NULL; + GpMatrix *m; + HDC hdc = GetDC(0); + BOOL res; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + GdipCreateRegion(®ion); + + GdipCreateMatrix2(3.0, 0.0, 0.0, 1.0, 20.0, 30.0, &m); + + /* NULL arguments */ + status = GdipIsInfiniteRegion(NULL, NULL, NULL); + expect(InvalidParameter, status); + status = GdipIsInfiniteRegion(region, NULL, NULL); + expect(InvalidParameter, status); + status = GdipIsInfiniteRegion(NULL, graphics, NULL); + expect(InvalidParameter, status); + status = GdipIsInfiniteRegion(NULL, NULL, &res); + expect(InvalidParameter, status); + status = GdipIsInfiniteRegion(region, NULL, &res); + expect(InvalidParameter, status); + + res = FALSE; + status = GdipIsInfiniteRegion(region, graphics, &res); + expect(Ok, status); + expect(TRUE, res); + + /* after world transform */ + status = GdipSetWorldTransform(graphics, m); + expect(Ok, status); + + res = FALSE; + status = GdipIsInfiniteRegion(region, graphics, &res); + expect(Ok, status); + expect(TRUE, res); + + GdipDeleteMatrix(m); + GdipDeleteRegion(region); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); +} + +static void test_isempty(void) +{ + GpStatus status; + GpRegion *region; + GpGraphics *graphics = NULL; + HDC hdc = GetDC(0); + BOOL res; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + GdipCreateRegion(®ion); + + /* NULL arguments */ + status = GdipIsEmptyRegion(NULL, NULL, NULL); + expect(InvalidParameter, status); + status = GdipIsEmptyRegion(region, NULL, NULL); + expect(InvalidParameter, status); + status = GdipIsEmptyRegion(NULL, graphics, NULL); + expect(InvalidParameter, status); + status = GdipIsEmptyRegion(NULL, NULL, &res); + expect(InvalidParameter, status); + status = GdipIsEmptyRegion(region, NULL, &res); + expect(InvalidParameter, status); + + /* default is infinite */ + res = TRUE; + status = GdipIsEmptyRegion(region, graphics, &res); + expect(Ok, status); + expect(FALSE, res); + + status = GdipSetEmpty(region); + expect(Ok, status); + + res = FALSE; + status = GdipIsEmptyRegion(region, graphics, &res); + expect(Ok, status); + expect(TRUE, res); + + GdipDeleteRegion(region); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); +} + +static void test_combinereplace(void) +{ + GpStatus status; + GpRegion *region, *region2; + GpPath *path; + GpRectF rectf; + UINT needed; + DWORD buf[50]; + + rectf.X = rectf.Y = 0.0; + rectf.Width = rectf.Height = 100.0; + + status = GdipCreateRegionRect(&rectf, ®ion); + expect(Ok, status); + + /* replace with the same rectangle */ + status = GdipCombineRegionRect(region, &rectf,CombineModeReplace); + expect(Ok, status); + + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(36, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + expect(36, needed); + expect_dword(buf, 28); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_RECT); + + /* replace with path */ + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + status = GdipAddPathEllipse(path, 0.0, 0.0, 100.0, 250.0); + expect(Ok, status); + status = GdipCombineRegionPath(region, path, CombineModeReplace); + expect(Ok, status); + + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(156, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + expect(156, needed); + expect_dword(buf, 148); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_PATH); + GdipDeletePath(path); + + /* replace with infinite rect */ + status = GdipCreateRegion(®ion2); + expect(Ok, status); + status = GdipCombineRegionRegion(region, region2, CombineModeReplace); + expect(Ok, status); + + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(20, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + expect(20, needed); + expect_dword(buf, 12); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_INFINITE_RECT); + GdipDeleteRegion(region2); + + /* more complex case : replace with a combined region */ + status = GdipCreateRegionRect(&rectf, ®ion2); + expect(Ok, status); + status = GdipCreatePath(FillModeAlternate, &path); + expect(Ok, status); + status = GdipAddPathEllipse(path, 0.0, 0.0, 100.0, 250.0); + expect(Ok, status); + status = GdipCombineRegionPath(region2, path, CombineModeUnion); + expect(Ok, status); + GdipDeletePath(path); + status = GdipCombineRegionRegion(region, region2, CombineModeReplace); + expect(Ok, status); + GdipDeleteRegion(region2); + + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(180, needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + expect(180, needed); + expect_dword(buf, 172); + trace("buf[1] = %08x\n", buf[1]); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 2); + expect_dword(buf + 4, CombineModeUnion); + + GdipDeleteRegion(region); +} + +static void test_fromhrgn(void) +{ + GpStatus status; + GpRegion *region; + HRGN hrgn; + UINT needed; + DWORD buf[220]; + RegionDataPoint *point; + GpGraphics *graphics = NULL; + HDC hdc; + BOOL res; + + /* NULL */ + status = GdipCreateRegionHrgn(NULL, NULL); + expect(InvalidParameter, status); + status = GdipCreateRegionHrgn(NULL, ®ion); + expect(InvalidParameter, status); + status = GdipCreateRegionHrgn((HRGN)0xdeadbeef, ®ion); + expect(InvalidParameter, status); + + /* empty rectangle */ + hrgn = CreateRectRgn(0, 0, 0, 0); + status = GdipCreateRegionHrgn(hrgn, ®ion); + expect(Ok, status); + if(status == Ok) { + + hdc = GetDC(0); + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + res = FALSE; + status = GdipIsEmptyRegion(region, graphics, &res); + expect(Ok, status); + expect(TRUE, res); + GdipDeleteGraphics(graphics); + ReleaseDC(0, hdc); + GdipDeleteRegion(region); + + } + DeleteObject(hrgn); + + /* rectangle */ + hrgn = CreateRectRgn(0, 0, 100, 10); + status = GdipCreateRegionHrgn(hrgn, ®ion); + expect(Ok, status); + + status = GdipGetRegionDataSize(region, &needed); + expect(Ok, status); + expect(56, needed); + + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + expect(Ok, status); + + if(status == Ok){ + + expect(56, needed); + expect_dword(buf, 48); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_PATH); + expect_dword(buf + 5, 0x00000020); + expect_magic((DWORD*)(buf + 6)); + expect_dword(buf + 7, 0x00000004); + todo_wine expect_dword(buf + 8, 0x00006000); /* ?? */ + + point = (RegionDataPoint*)buf + 9; + + expect(0, point[0].X); + expect(0, point[0].Y); + + expect(100,point[1].X); /* buf + 10 */ + expect(0, point[1].Y); + expect(100,point[2].X); /* buf + 11 */ + expect(10, point[2].Y); + + expect(0, point[3].X); /* buf + 12 */ + + expect(10, point[3].Y); + expect_dword(buf + 13, 0x81010100); /* closed */ + + } + + GdipDeleteRegion(region); + DeleteObject(hrgn); + + /* ellipse */ + hrgn = CreateEllipticRgn(0, 0, 100, 10); + status = GdipCreateRegionHrgn(hrgn, ®ion); + todo_wine expect(Ok, status); + + status = GdipGetRegionDataSize(region, &needed); +todo_wine{ + expect(Ok, status); + ok(needed == 216 || + needed == 196, /* win98 */ + "Got %.8x\n", needed); +} + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + todo_wine expect(Ok, status); + + if(status == Ok && needed == 216) /* Don't try to test win98 layout */ + { +todo_wine{ + expect(Ok, status); + expect(216, needed); + expect_dword(buf, 208); + expect_magic((DWORD*)(buf + 2)); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_PATH); + expect_dword(buf + 5, 0x000000C0); + expect_magic((DWORD*)(buf + 6)); + expect_dword(buf + 7, 0x00000024); + expect_dword(buf + 8, 0x00006000); /* ?? */ +} + } + + GdipDeleteRegion(region); + DeleteObject(hrgn); +} + +static void test_gethrgn(void) +{ + GpStatus status; + GpRegion *region, *region2; + GpPath *path; + GpGraphics *graphics; + HRGN hrgn; + HDC hdc=GetDC(0); + static const RECT empty_rect = {0,0,0,0}; + static const RECT test_rect = {10, 11, 20, 21}; + static const GpRectF test_rectF = {10.0, 11.0, 10.0, 10.0}; + static const RECT scaled_rect = {20, 22, 40, 42}; + static const RECT test_rect2 = {10, 21, 20, 31}; + static const GpRectF test_rect2F = {10.0, 21.0, 10.0, 10.0}; + static const RECT test_rect3 = {10, 11, 20, 31}; + static const GpRectF test_rect3F = {10.0, 11.0, 10.0, 20.0}; + + status = GdipCreateFromHDC(hdc, &graphics); + ok(status == Ok, "status %08x\n", status); + + status = GdipCreateRegion(®ion); + ok(status == Ok, "status %08x\n", status); + + status = GdipGetRegionHRgn(NULL, graphics, &hrgn); + ok(status == InvalidParameter, "status %08x\n", status); + status = GdipGetRegionHRgn(region, graphics, NULL); + ok(status == InvalidParameter, "status %08x\n", status); + + status = GdipGetRegionHRgn(region, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + ok(hrgn == NULL, "hrgn=%p\n", hrgn); + DeleteObject(hrgn); + + status = GdipGetRegionHRgn(region, graphics, &hrgn); + ok(status == Ok, "status %08x\n", status); + ok(hrgn == NULL, "hrgn=%p\n", hrgn); + DeleteObject(hrgn); + + status = GdipSetEmpty(region); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &empty_rect); + DeleteObject(hrgn); + + status = GdipCreatePath(FillModeAlternate, &path); + ok(status == Ok, "status %08x\n", status); + status = GdipAddPathRectangle(path, 10.0, 11.0, 10.0, 10.0); + ok(status == Ok, "status %08x\n", status); + + status = GdipCreateRegionPath(path, ®ion2); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region2, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &test_rect); + DeleteObject(hrgn); + + /* resulting HRGN is in device coordinates */ + status = GdipScaleWorldTransform(graphics, 2.0, 2.0, MatrixOrderPrepend); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region2, graphics, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &scaled_rect); + DeleteObject(hrgn); + + status = GdipCombineRegionRect(region2, &test_rectF, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region2, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &test_rect); + DeleteObject(hrgn); + + status = GdipGetRegionHRgn(region2, graphics, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &scaled_rect); + DeleteObject(hrgn); + + status = GdipSetInfinite(region); + ok(status == Ok, "status %08x\n", status); + status = GdipCombineRegionRect(region, &test_rectF, CombineModeIntersect); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &test_rect); + DeleteObject(hrgn); + + status = GdipCombineRegionRect(region, &test_rectF, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + status = GdipCombineRegionRect(region, &test_rect2F, CombineModeUnion); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &test_rect3); + DeleteObject(hrgn); + + status = GdipCombineRegionRect(region, &test_rect3F, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + status = GdipCombineRegionRect(region, &test_rect2F, CombineModeXor); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &test_rect); + DeleteObject(hrgn); + + status = GdipCombineRegionRect(region, &test_rect3F, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + status = GdipCombineRegionRect(region, &test_rectF, CombineModeExclude); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &test_rect2); + DeleteObject(hrgn); + + status = GdipCombineRegionRect(region, &test_rectF, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + status = GdipCombineRegionRect(region, &test_rect3F, CombineModeComplement); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionHRgn(region, NULL, &hrgn); + ok(status == Ok, "status %08x\n", status); + verify_region(hrgn, &test_rect2); + DeleteObject(hrgn); + + status = GdipDeletePath(path); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteRegion(region); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteRegion(region2); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteGraphics(graphics); + ok(status == Ok, "status %08x\n", status); + ReleaseDC(0, hdc); +} + +static void test_isequal(void) +{ + GpRegion *region1, *region2; + GpGraphics *graphics; + GpRectF rectf; + GpStatus status; + HDC hdc = GetDC(0); + BOOL res; + + status = GdipCreateFromHDC(hdc, &graphics); + ok(status == Ok, "status %08x\n", status); + + status = GdipCreateRegion(®ion1); + ok(status == Ok, "status %08x\n", status); + status = GdipCreateRegion(®ion2); + ok(status == Ok, "status %08x\n", status); + + /* NULL */ + status = GdipIsEqualRegion(NULL, NULL, NULL, NULL); + ok(status == InvalidParameter, "status %08x\n", status); + status = GdipIsEqualRegion(region1, region2, NULL, NULL); + ok(status == InvalidParameter, "status %08x\n", status); + status = GdipIsEqualRegion(region1, region2, graphics, NULL); + ok(status == InvalidParameter, "status %08x\n", status); + status = GdipIsEqualRegion(region1, region2, NULL, &res); + ok(status == InvalidParameter, "status %08x\n", status); + + /* infinite regions */ + res = FALSE; + status = GdipIsEqualRegion(region1, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(res, "Expected to be equal.\n"); + /* empty regions */ + status = GdipSetEmpty(region1); + ok(status == Ok, "status %08x\n", status); + status = GdipSetEmpty(region2); + ok(status == Ok, "status %08x\n", status); + res = FALSE; + status = GdipIsEqualRegion(region1, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(res, "Expected to be equal.\n"); + /* empty & infinite */ + status = GdipSetInfinite(region1); + ok(status == Ok, "status %08x\n", status); + res = TRUE; + status = GdipIsEqualRegion(region1, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(!res, "Expected to be unequal.\n"); + /* rect & (inf/empty) */ + rectf.X = rectf.Y = 0.0; + rectf.Width = rectf.Height = 100.0; + status = GdipCombineRegionRect(region1, &rectf, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + res = TRUE; + status = GdipIsEqualRegion(region1, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(!res, "Expected to be unequal.\n"); + status = GdipSetInfinite(region2); + ok(status == Ok, "status %08x\n", status); + res = TRUE; + status = GdipIsEqualRegion(region1, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(!res, "Expected to be unequal.\n"); + /* roughly equal rectangles */ + rectf.X = rectf.Y = 0.0; + rectf.Width = rectf.Height = 100.001; + status = GdipCombineRegionRect(region2, &rectf, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + res = FALSE; + status = GdipIsEqualRegion(region1, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(res, "Expected to be equal.\n"); + /* equal rectangles */ + rectf.X = rectf.Y = 0.0; + rectf.Width = rectf.Height = 100.0; + status = GdipCombineRegionRect(region2, &rectf, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + res = FALSE; + status = GdipIsEqualRegion(region1, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(res, "Expected to be equal.\n"); + + /* cleanup */ + status = GdipDeleteRegion(region1); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteRegion(region2); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteGraphics(graphics); + ok(status == Ok, "status %08x\n", status); + ReleaseDC(0, hdc); +} + +static void test_translate(void) +{ + GpRegion *region, *region2; + GpGraphics *graphics; + GpPath *path; + GpRectF rectf; + GpStatus status; + HDC hdc = GetDC(0); + BOOL res; + + status = GdipCreateFromHDC(hdc, &graphics); + ok(status == Ok, "status %08x\n", status); + + status = GdipCreatePath(FillModeAlternate, &path); + ok(status == Ok, "status %08x\n", status); + + status = GdipCreateRegion(®ion); + ok(status == Ok, "status %08x\n", status); + status = GdipCreateRegion(®ion2); + ok(status == Ok, "status %08x\n", status); + + /* NULL */ + status = GdipTranslateRegion(NULL, 0.0, 0.0); + ok(status == InvalidParameter, "status %08x\n", status); + + /* infinite */ + status = GdipTranslateRegion(region, 10.0, 10.0); + ok(status == Ok, "status %08x\n", status); + /* empty */ + status = GdipSetEmpty(region); + ok(status == Ok, "status %08x\n", status); + status = GdipTranslateRegion(region, 10.0, 10.0); + ok(status == Ok, "status %08x\n", status); + /* rect */ + rectf.X = 10.0; rectf.Y = 0.0; + rectf.Width = rectf.Height = 100.0; + status = GdipCombineRegionRect(region, &rectf, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + rectf.X = 15.0; rectf.Y = -2.0; + rectf.Width = rectf.Height = 100.0; + status = GdipCombineRegionRect(region2, &rectf, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + status = GdipTranslateRegion(region, 5.0, -2.0); + ok(status == Ok, "status %08x\n", status); + res = FALSE; + status = GdipIsEqualRegion(region, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(res, "Expected to be equal.\n"); + /* path */ + status = GdipAddPathEllipse(path, 0.0, 10.0, 100.0, 150.0); + ok(status == Ok, "status %08x\n", status); + status = GdipCombineRegionPath(region, path, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + status = GdipResetPath(path); + ok(status == Ok, "status %08x\n", status); + status = GdipAddPathEllipse(path, 10.0, 21.0, 100.0, 150.0); + ok(status == Ok, "status %08x\n", status); + status = GdipCombineRegionPath(region2, path, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + status = GdipTranslateRegion(region, 10.0, 11.0); + ok(status == Ok, "status %08x\n", status); + res = FALSE; + status = GdipIsEqualRegion(region, region2, graphics, &res); + ok(status == Ok, "status %08x\n", status); + ok(res, "Expected to be equal.\n"); + + status = GdipDeleteRegion(region); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteRegion(region2); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteGraphics(graphics); + ok(status == Ok, "status %08x\n", status); + status = GdipDeletePath(path); + ok(status == Ok, "status %08x\n", status); + ReleaseDC(0, hdc); +} + +static void test_getbounds(void) +{ + GpRegion *region; + GpGraphics *graphics; + GpStatus status; + GpRectF rectf; + HDC hdc = GetDC(0); + + status = GdipCreateFromHDC(hdc, &graphics); + ok(status == Ok, "status %08x\n", status); + status = GdipCreateRegion(®ion); + ok(status == Ok, "status %08x\n", status); + + /* NULL */ + status = GdipGetRegionBounds(NULL, NULL, NULL); + ok(status == InvalidParameter, "status %08x\n", status); + status = GdipGetRegionBounds(region, NULL, NULL); + ok(status == InvalidParameter, "status %08x\n", status); + status = GdipGetRegionBounds(region, graphics, NULL); + ok(status == InvalidParameter, "status %08x\n", status); + /* infinite */ + rectf.X = rectf.Y = 0.0; + rectf.Height = rectf.Width = 100.0; + status = GdipGetRegionBounds(region, graphics, &rectf); + ok(status == Ok, "status %08x\n", status); + ok(rectf.X == -(REAL)(1 << 22), "Expected X = %.2f, got %.2f\n", -(REAL)(1 << 22), rectf.X); + ok(rectf.Y == -(REAL)(1 << 22), "Expected Y = %.2f, got %.2f\n", -(REAL)(1 << 22), rectf.Y); + ok(rectf.Width == (REAL)(1 << 23), "Expected width = %.2f, got %.2f\n", (REAL)(1 << 23), rectf.Width); + ok(rectf.Height == (REAL)(1 << 23), "Expected height = %.2f, got %.2f\n",(REAL)(1 << 23), rectf.Height); + /* empty */ + rectf.X = rectf.Y = 0.0; + rectf.Height = rectf.Width = 100.0; + status = GdipSetEmpty(region); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionBounds(region, graphics, &rectf); + ok(status == Ok, "status %08x\n", status); + ok(rectf.X == 0.0, "Expected X = 0.0, got %.2f\n", rectf.X); + ok(rectf.Y == 0.0, "Expected Y = 0.0, got %.2f\n", rectf.Y); + ok(rectf.Width == 0.0, "Expected width = 0.0, got %.2f\n", rectf.Width); + ok(rectf.Height == 0.0, "Expected height = 0.0, got %.2f\n", rectf.Height); + /* rect */ + rectf.X = 10.0; rectf.Y = 0.0; + rectf.Width = rectf.Height = 100.0; + status = GdipCombineRegionRect(region, &rectf, CombineModeReplace); + ok(status == Ok, "status %08x\n", status); + rectf.X = rectf.Y = 0.0; + rectf.Height = rectf.Width = 0.0; + status = GdipGetRegionBounds(region, graphics, &rectf); + ok(status == Ok, "status %08x\n", status); + ok(rectf.X == 10.0, "Expected X = 0.0, got %.2f\n", rectf.X); + ok(rectf.Y == 0.0, "Expected Y = 0.0, got %.2f\n", rectf.Y); + ok(rectf.Width == 100.0, "Expected width = 0.0, got %.2f\n", rectf.Width); + ok(rectf.Height == 100.0, "Expected height = 0.0, got %.2f\n", rectf.Height); + + status = GdipDeleteRegion(region); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteGraphics(graphics); + ok(status == Ok, "status %08x\n", status); + ReleaseDC(0, hdc); } START_TEST(region) @@ -215,8 +1195,15 @@ START_TEST(region) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); - test_create_rgn(); + test_getregiondata(); + test_isinfinite(); + test_isempty(); + test_combinereplace(); + test_fromhrgn(); + test_gethrgn(); + test_isequal(); + test_translate(); + test_getbounds(); GdiplusShutdown(gdiplusToken); - } diff --git a/rostests/winetests/gdiplus/stringformat.c b/rostests/winetests/gdiplus/stringformat.c index 9cf46a43297..b28dbc6d355 100644 --- a/rostests/winetests/gdiplus/stringformat.c +++ b/rostests/winetests/gdiplus/stringformat.c @@ -23,6 +23,7 @@ #include "wine/test.h" #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) +#define expectf(expected, got) ok(got == expected, "Expected %.2f, got %.2f\n", expected, got) static void test_constructor(void) { @@ -31,19 +32,348 @@ static void test_constructor(void) INT n; StringAlignment align, valign; StringTrimming trimming; + StringDigitSubstitute digitsub; + LANGID digitlang; - stat = GdipCreateStringFormat(0, 0, &format); + stat = GdipCreateStringFormat(0, LANG_NEUTRAL, &format); expect(Ok, stat); GdipGetStringFormatAlign(format, &align); GdipGetStringFormatLineAlign(format, &valign); GdipGetStringFormatHotkeyPrefix(format, &n); GdipGetStringFormatTrimming(format, &trimming); + GdipGetStringFormatDigitSubstitution(format, &digitlang, &digitsub); expect(HotkeyPrefixNone, n); expect(StringAlignmentNear, align); expect(StringAlignmentNear, align); expect(StringTrimmingCharacter, trimming); + expect(StringDigitSubstituteUser, digitsub); + expect(LANG_NEUTRAL, digitlang); + + stat = GdipDeleteStringFormat(format); + expect(Ok, stat); +} + +static void test_characterrange(void) +{ + CharacterRange ranges[3]; + INT count; + GpStringFormat* format; + GpStatus stat; + + stat = GdipCreateStringFormat(0, LANG_NEUTRAL, &format); + expect(Ok, stat); +todo_wine +{ + stat = GdipSetStringFormatMeasurableCharacterRanges(format, 3, ranges); + expect(Ok, stat); + stat = GdipGetStringFormatMeasurableCharacterRangeCount(format, &count); + expect(Ok, stat); + if (stat == Ok) expect(3, count); +} + stat= GdipDeleteStringFormat(format); + expect(Ok, stat); +} + +static void test_digitsubstitution(void) +{ + GpStringFormat *format; + GpStatus stat; + StringDigitSubstitute digitsub; + LANGID digitlang; + + stat = GdipCreateStringFormat(0, LANG_RUSSIAN, &format); + expect(Ok, stat); + + /* NULL arguments */ + stat = GdipGetStringFormatDigitSubstitution(NULL, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatDigitSubstitution(format, NULL, NULL); + expect(Ok, stat); + stat = GdipGetStringFormatDigitSubstitution(NULL, &digitlang, NULL); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatDigitSubstitution(NULL, NULL, &digitsub); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatDigitSubstitution(NULL, &digitlang, &digitsub); + expect(InvalidParameter, stat); + stat = GdipSetStringFormatDigitSubstitution(NULL, LANG_NEUTRAL, StringDigitSubstituteNone); + expect(InvalidParameter, stat); + + /* try to get both and one by one */ + stat = GdipGetStringFormatDigitSubstitution(format, &digitlang, &digitsub); + expect(Ok, stat); + expect(StringDigitSubstituteUser, digitsub); + expect(LANG_NEUTRAL, digitlang); + + digitsub = StringDigitSubstituteNone; + stat = GdipGetStringFormatDigitSubstitution(format, NULL, &digitsub); + expect(Ok, stat); + expect(StringDigitSubstituteUser, digitsub); + + digitlang = LANG_RUSSIAN; + stat = GdipGetStringFormatDigitSubstitution(format, &digitlang, NULL); + expect(Ok, stat); + expect(LANG_NEUTRAL, digitlang); + + /* set/get */ + stat = GdipSetStringFormatDigitSubstitution(format, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL), + StringDigitSubstituteUser); + expect(Ok, stat); + digitsub = StringDigitSubstituteNone; + digitlang = LANG_RUSSIAN; + stat = GdipGetStringFormatDigitSubstitution(format, &digitlang, &digitsub); + expect(Ok, stat); + expect(StringDigitSubstituteUser, digitsub); + expect(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL), digitlang); + + stat = GdipDeleteStringFormat(format); + expect(Ok, stat); +} + +static void test_getgenerictypographic(void) +{ + GpStringFormat *format; + GpStatus stat; + INT flags; + INT n; + StringAlignment align, valign; + StringTrimming trimming; + StringDigitSubstitute digitsub; + LANGID digitlang; + INT tabcount; + + /* NULL arg */ + stat = GdipStringFormatGetGenericTypographic(NULL); + expect(InvalidParameter, stat); + + stat = GdipStringFormatGetGenericTypographic(&format); + expect(Ok, stat); + + GdipGetStringFormatFlags(format, &flags); + GdipGetStringFormatAlign(format, &align); + GdipGetStringFormatLineAlign(format, &valign); + GdipGetStringFormatHotkeyPrefix(format, &n); + GdipGetStringFormatTrimming(format, &trimming); + GdipGetStringFormatDigitSubstitution(format, &digitlang, &digitsub); + GdipGetStringFormatTabStopCount(format, &tabcount); + + expect((StringFormatFlagsNoFitBlackBox |StringFormatFlagsLineLimit | StringFormatFlagsNoClip), + flags); + expect(HotkeyPrefixNone, n); + expect(StringAlignmentNear, align); + expect(StringAlignmentNear, align); + expect(StringTrimmingNone, trimming); + expect(StringDigitSubstituteUser, digitsub); + expect(LANG_NEUTRAL, digitlang); + expect(0, tabcount); + + stat = GdipDeleteStringFormat(format); + expect(Ok, stat); +} + +static REAL tabstops[] = {0.0, 10.0, 2.0}; +static void test_tabstops(void) +{ + GpStringFormat *format; + GpStatus stat; + INT count; + REAL tabs[3]; + REAL firsttab; + + stat = GdipCreateStringFormat(0, LANG_NEUTRAL, &format); + expect(Ok, stat); + + /* NULL */ + stat = GdipGetStringFormatTabStopCount(NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatTabStopCount(NULL, &count); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatTabStopCount(format, NULL); + expect(InvalidParameter, stat); + + stat = GdipSetStringFormatTabStops(NULL, 0.0, 0, NULL); + expect(InvalidParameter, stat); + stat = GdipSetStringFormatTabStops(format, 0.0, 0, NULL); + expect(InvalidParameter, stat); + stat = GdipSetStringFormatTabStops(NULL, 0.0, 0, tabstops); + expect(InvalidParameter, stat); + + stat = GdipGetStringFormatTabStops(NULL, 0, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatTabStops(format, 0, NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatTabStops(NULL, 0, &firsttab, NULL); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatTabStops(NULL, 0, NULL, tabs); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatTabStops(format, 0, &firsttab, NULL); + expect(InvalidParameter, stat); + stat = GdipGetStringFormatTabStops(format, 0, NULL, tabs); + expect(InvalidParameter, stat); + + /* not NULL */ + stat = GdipGetStringFormatTabStopCount(format, &count); + expect(Ok, stat); + expect(0, count); + /* negative tabcount */ + stat = GdipSetStringFormatTabStops(format, 0.0, -1, tabstops); + expect(Ok, stat); + count = -1; + stat = GdipGetStringFormatTabStopCount(format, &count); + expect(Ok, stat); + expect(0, count); + + stat = GdipSetStringFormatTabStops(format, -10.0, 0, tabstops); + expect(Ok, stat); + stat = GdipSetStringFormatTabStops(format, -10.0, 1, tabstops); + expect(NotImplemented, stat); + + firsttab = -1.0; + tabs[0] = tabs[1] = tabs[2] = -1.0; + stat = GdipGetStringFormatTabStops(format, 0, &firsttab, tabs); + expect(Ok, stat); + expectf(-1.0, tabs[0]); + expectf(-1.0, tabs[1]); + expectf(-1.0, tabs[2]); + expectf(0.0, firsttab); + + stat = GdipSetStringFormatTabStops(format, +0.0, 3, tabstops); + expect(Ok, stat); + count = 0; + stat = GdipGetStringFormatTabStopCount(format, &count); + expect(Ok, stat); + expect(3, count); + + firsttab = -1.0; + tabs[0] = tabs[1] = tabs[2] = -1.0; + stat = GdipGetStringFormatTabStops(format, 3, &firsttab, tabs); + expect(Ok, stat); + expectf(0.0, tabs[0]); + expectf(10.0, tabs[1]); + expectf(2.0, tabs[2]); + expectf(0.0, firsttab); + + stat = GdipSetStringFormatTabStops(format, 10.0, 3, tabstops); + expect(Ok, stat); + firsttab = -1.0; + tabs[0] = tabs[1] = tabs[2] = -1.0; + stat = GdipGetStringFormatTabStops(format, 0, &firsttab, tabs); + expect(Ok, stat); + expectf(-1.0, tabs[0]); + expectf(-1.0, tabs[1]); + expectf(-1.0, tabs[2]); + expectf(10.0, firsttab); + + /* zero tabcount, after valid setting to 3 */ + stat = GdipSetStringFormatTabStops(format, 0.0, 0, tabstops); + expect(Ok, stat); + count = 0; + stat = GdipGetStringFormatTabStopCount(format, &count); + expect(Ok, stat); + expect(3, count); + + stat = GdipDeleteStringFormat(format); + expect(Ok, stat); +} + +static void test_getgenericdefault(void) +{ + GpStringFormat *format; + GpStatus stat; + + INT flags; + INT n; + StringAlignment align, valign; + StringTrimming trimming; + StringDigitSubstitute digitsub; + LANGID digitlang; + INT tabcount; + + /* NULL arg */ + stat = GdipStringFormatGetGenericDefault(NULL); + expect(InvalidParameter, stat); + + stat = GdipStringFormatGetGenericDefault(&format); + expect(Ok, stat); + + GdipGetStringFormatFlags(format, &flags); + GdipGetStringFormatAlign(format, &align); + GdipGetStringFormatLineAlign(format, &valign); + GdipGetStringFormatHotkeyPrefix(format, &n); + GdipGetStringFormatTrimming(format, &trimming); + GdipGetStringFormatDigitSubstitution(format, &digitlang, &digitsub); + GdipGetStringFormatTabStopCount(format, &tabcount); + + expect(0, flags); + expect(HotkeyPrefixNone, n); + expect(StringAlignmentNear, align); + expect(StringAlignmentNear, align); + expect(StringTrimmingCharacter, trimming); + expect(StringDigitSubstituteUser, digitsub); + expect(LANG_NEUTRAL, digitlang); + expect(0, tabcount); + + stat = GdipDeleteStringFormat(format); + expect(Ok, stat); +} + +static void test_stringformatflags(void) +{ + GpStringFormat *format; + GpStatus stat; + + INT flags; + + stat = GdipCreateStringFormat(0, LANG_NEUTRAL, &format); + expect(Ok, stat); + + /* NULL args */ + stat = GdipSetStringFormatFlags(NULL, 0); + expect(InvalidParameter, stat); + + stat = GdipSetStringFormatFlags(format, 0); + expect(Ok, stat); + stat = GdipGetStringFormatFlags(format, &flags); + expect(Ok, stat); + expect(0, flags); + + /* Check some valid flags */ + stat = GdipSetStringFormatFlags(format, StringFormatFlagsDirectionRightToLeft); + expect(Ok, stat); + stat = GdipGetStringFormatFlags(format, &flags); + expect(Ok, stat); + expect(StringFormatFlagsDirectionRightToLeft, flags); + + stat = GdipSetStringFormatFlags(format, StringFormatFlagsNoFontFallback); + expect(Ok, stat); + stat = GdipGetStringFormatFlags(format, &flags); + expect(Ok, stat); + expect(StringFormatFlagsNoFontFallback, flags); + + /* Check some flag combinations */ + stat = GdipSetStringFormatFlags(format, StringFormatFlagsDirectionVertical + | StringFormatFlagsNoFitBlackBox); + expect(Ok, stat); + stat = GdipGetStringFormatFlags(format, &flags); + expect(Ok, stat); + expect((StringFormatFlagsDirectionVertical + | StringFormatFlagsNoFitBlackBox), flags); + + stat = GdipSetStringFormatFlags(format, StringFormatFlagsDisplayFormatControl + | StringFormatFlagsMeasureTrailingSpaces); + expect(Ok, stat); + stat = GdipGetStringFormatFlags(format, &flags); + expect(Ok, stat); + expect((StringFormatFlagsDisplayFormatControl + | StringFormatFlagsMeasureTrailingSpaces), flags); + + /* Check invalid flags */ + stat = GdipSetStringFormatFlags(format, 0xdeadbeef); + expect(Ok, stat); + stat = GdipGetStringFormatFlags(format, &flags); + expect(Ok, stat); + expect(0xdeadbeef, flags); stat = GdipDeleteStringFormat(format); expect(Ok, stat); @@ -62,6 +392,12 @@ START_TEST(stringformat) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); test_constructor(); + test_characterrange(); + test_digitsubstitution(); + test_getgenerictypographic(); + test_tabstops(); + test_getgenericdefault(); + test_stringformatflags(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/testlist.c b/rostests/winetests/gdiplus/testlist.c index 450488199e6..05456c6b9f7 100644 --- a/rostests/winetests/gdiplus/testlist.c +++ b/rostests/winetests/gdiplus/testlist.c @@ -7,6 +7,7 @@ #include "wine/test.h" extern void func_brush(void); +extern void func_customlinecap(void); extern void func_font(void); extern void func_graphics(void); extern void func_graphicspath(void); @@ -20,6 +21,7 @@ extern void func_stringformat(void); const struct test winetest_testlist[] = { { "brush", func_brush }, + { "customlinecap", func_customlinecap }, { "font", func_font }, { "graphics", func_graphics }, { "graphicspath", func_graphicspath }, diff --git a/rostests/winetests/hlink/hlink.c b/rostests/winetests/hlink/hlink.c index 6c3dff0591a..5e07359fdf5 100644 --- a/rostests/winetests/hlink/hlink.c +++ b/rostests/winetests/hlink/hlink.c @@ -23,6 +23,7 @@ #include +#include #include #include @@ -157,6 +158,13 @@ static void test_reference(void) ok(r == S_OK, "failed\n"); ok(str == NULL, "string should be null\n"); + /* Unimplented functions checks */ + r = IHlink_GetAdditionalParams(lnk, NULL); + ok(r == E_NOTIMPL, "failed\n"); + + r = IHlink_SetAdditionalParams(lnk, NULL); + ok(r == E_NOTIMPL, "failed\n"); + IHlink_Release(lnk); } @@ -174,6 +182,23 @@ static const unsigned char expected_hlink_data[] = 0x00,0x00, }; +/* url only (IE7) */ +static const unsigned char expected_hlink_data_ie7[] = +{ + 0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11, + 0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b, + 0x3e,0x00,0x00,0x00,0x68,0x00,0x74,0x00, + 0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00, + 0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00, + 0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00, + 0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00, + 0x00,0x00,0x79,0x58,0x81,0xf4,0x3b,0x1d, + 0x7f,0x48,0xaf,0x2c,0x82,0x5d,0xc4,0x85, + 0x27,0x63,0x00,0x00,0x00,0x00,0xa5,0xab, + 0x00,0x00, +}; + /* url + friendly name */ static const unsigned char expected_hlink_data2[] = { @@ -190,6 +215,25 @@ static const unsigned char expected_hlink_data2[] = 0x67,0x00,0x2f,0x00,0x00,0x00, }; +/* url + friendly name (IE7) */ +static const unsigned char expected_hlink_data2_ie7[] = +{ + 0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00, + 0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00, + 0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79, + 0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa, + 0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00, + 0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00, + 0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00, + 0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00, + 0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00, + 0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58, + 0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c, + 0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00, + 0x00,0x00,0xa5,0xab,0x00,0x00, +}; + /* url + friendly name + location */ static const unsigned char expected_hlink_data3[] = { @@ -208,6 +252,27 @@ static const unsigned char expected_hlink_data3[] = 0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00, }; +/* url + friendly name + location (IE7) */ +static const unsigned char expected_hlink_data3_ie7[] = +{ + 0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00, + 0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00, + 0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79, + 0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa, + 0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00, + 0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00, + 0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00, + 0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00, + 0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00, + 0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58, + 0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c, + 0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00, + 0x00,0x00,0xa5,0xab,0x00,0x00,0x07,0x00, + 0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00, + 0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00, +}; + /* relative url */ static const unsigned char expected_hlink_data4[] = { @@ -238,6 +303,25 @@ static const unsigned char expected_hlink_data5[] = 0x2f,0x00,0x00,0x00, }; +/* url + target frame name (IE7) */ +static const unsigned char expected_hlink_data5_ie7[] = +{ + 0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00, + 0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00, + 0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba, + 0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b, + 0xa9,0x0b,0x3e,0x00,0x00,0x00,0x68,0x00, + 0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00, + 0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00, + 0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00, + 0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00, + 0x2f,0x00,0x00,0x00,0x79,0x58,0x81,0xf4, + 0x3b,0x1d,0x7f,0x48,0xaf,0x2c,0x82,0x5d, + 0xc4,0x85,0x27,0x63,0x00,0x00,0x00,0x00, + 0xa5,0xab,0x00,0x00, +}; + /* filename */ static const unsigned char expected_hlink_data6[] = { @@ -255,7 +339,9 @@ static const unsigned char expected_hlink_data6[] = static void test_persist_save_data(const char *testname, IHlink *lnk, const unsigned char *expected_data, - unsigned int expected_data_size) + unsigned int expected_data_size, + const unsigned char *expected_data_alt, + unsigned int expected_data_alt_size) { HRESULT hr; IStream *stream; @@ -265,6 +351,7 @@ static void test_persist_save_data(const char *testname, IHlink *lnk, const unsigned char *data; DWORD i; BOOL same; + unsigned int expected_data_win9x_size = 0; hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps); ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr); @@ -282,10 +369,15 @@ static void test_persist_save_data(const char *testname, IHlink *lnk, data = GlobalLock(hglobal); + if (expected_data_size % 4) + expected_data_win9x_size = 4 * ((expected_data_size / 4) + 1); + /* first check we have the right amount of data */ - ok(data_size == expected_data_size, - "%s: Size of saved data differs (expected %d, actual %d)\n", - testname, expected_data_size, data_size); + ok((data_size == expected_data_size) || + (data_size == expected_data_alt_size) || + broken(data_size == expected_data_win9x_size), /* Win9x and WinMe */ + "%s: Size of saved data differs (expected %d or %d, actual %d)\n", + testname, expected_data_size, expected_data_alt_size, data_size); same = TRUE; /* then do a byte-by-byte comparison */ @@ -301,6 +393,23 @@ static void test_persist_save_data(const char *testname, IHlink *lnk, } } + if (!same && (expected_data_alt != expected_data)) + { + /* then try the alternate data */ + same = TRUE; + for (i = 0; i < min(data_size, expected_data_alt_size); i++) + { + if ((expected_data_alt[i] != data[i]) && + (((expected_data_alt != expected_hlink_data2) && + (expected_data_alt != expected_hlink_data3)) || + ((i < 52 || i >= 56) && (i < 80 || i >= 84)))) + { + same = FALSE; + break; + } + } + } + ok(same, "%s: Saved data differs\n", testname); if (!same) { @@ -337,25 +446,33 @@ static void test_persist(void) skip("Can't create lnk, skipping test_persist. Was wineprefixcreate run properly?\n"); return; } - test_persist_save_data("url only", lnk, expected_hlink_data, sizeof(expected_hlink_data)); + test_persist_save_data("url only", lnk, + expected_hlink_data, sizeof(expected_hlink_data), + expected_hlink_data_ie7, sizeof(expected_hlink_data_ie7)); IHlink_Release(lnk); hr = HlinkCreateFromString(url, NULL, friendly_name, NULL, 0, NULL, &IID_IHlink, (LPVOID*) &lnk); ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr); - test_persist_save_data("url + friendly name", lnk, expected_hlink_data2, sizeof(expected_hlink_data2)); + test_persist_save_data("url + friendly name", lnk, + expected_hlink_data2, sizeof(expected_hlink_data2), + expected_hlink_data2_ie7, sizeof(expected_hlink_data2_ie7)); IHlink_Release(lnk); hr = HlinkCreateFromString(url, location, friendly_name, NULL, 0, NULL, &IID_IHlink, (LPVOID*) &lnk); ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr); - test_persist_save_data("url + friendly_name + location", lnk, expected_hlink_data3, sizeof(expected_hlink_data3)); + test_persist_save_data("url + friendly_name + location", lnk, + expected_hlink_data3, sizeof(expected_hlink_data3), + expected_hlink_data3_ie7, sizeof(expected_hlink_data3_ie7)); IHlink_Release(lnk); hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (LPVOID*) &lnk); ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr); - test_persist_save_data("relative url", lnk, expected_hlink_data4, sizeof(expected_hlink_data4)); + test_persist_save_data("relative url", lnk, + expected_hlink_data4, sizeof(expected_hlink_data4), + expected_hlink_data4, sizeof(expected_hlink_data4)); IHlink_Release(lnk); hr = HlinkCreateFromString(url, NULL, NULL, NULL, @@ -363,13 +480,17 @@ static void test_persist(void) ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr); hr = IHlink_SetTargetFrameName(lnk, target_frame_name); ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr); - test_persist_save_data("url + target frame name", lnk, expected_hlink_data5, sizeof(expected_hlink_data5)); + test_persist_save_data("url + target frame name", lnk, + expected_hlink_data5, sizeof(expected_hlink_data5), + expected_hlink_data5_ie7, sizeof(expected_hlink_data5_ie7)); IHlink_Release(lnk); hr = HlinkCreateFromString(filename, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (LPVOID*) &lnk); ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr); - test_persist_save_data("filename", lnk, expected_hlink_data6, sizeof(expected_hlink_data6)); + test_persist_save_data("filename", lnk, + expected_hlink_data6, sizeof(expected_hlink_data6), + expected_hlink_data6, sizeof(expected_hlink_data6)); IHlink_Release(lnk); } diff --git a/rostests/winetests/hlink/hlink.rbuild b/rostests/winetests/hlink/hlink.rbuild index fd3031ef982..771cae3a8a3 100644 --- a/rostests/winetests/hlink/hlink.rbuild +++ b/rostests/winetests/hlink/hlink.rbuild @@ -3,14 +3,12 @@ . - 0x600 - 0x600 + hlink.c testlist.c wine hlink ole32 - kernel32 uuid ntdll diff --git a/rostests/winetests/icmp/icmp.rbuild b/rostests/winetests/icmp/icmp.rbuild index 6dea820a32b..e575d9a4bee 100644 --- a/rostests/winetests/icmp/icmp.rbuild +++ b/rostests/winetests/icmp/icmp.rbuild @@ -1,13 +1,10 @@ - . - - kernel32 + ntdll icmp icmp.c testlist.c - diff --git a/rostests/winetests/imm32/imm32.c b/rostests/winetests/imm32/imm32.c index 591feb337fd..d8ca8094123 100644 --- a/rostests/winetests/imm32/imm32.c +++ b/rostests/winetests/imm32/imm32.c @@ -135,6 +135,7 @@ static HWND hwnd; static int init(void) { WNDCLASSEX wc; + HIMC imc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; @@ -158,6 +159,14 @@ static int init(void) { if (!hwnd) return 0; + imc = ImmGetContext(hwnd); + if (!imc) + { + win_skip("IME support not implemented\n"); + return 0; + } + ImmReleaseContext(hwnd, imc); + ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); @@ -173,7 +182,7 @@ static void cleanup(void) { UnregisterClass(wndcls, GetModuleHandle(0)); } -static int test_ImmNotifyIME(void) { +static void test_ImmNotifyIME(void) { static const char string[] = "wine"; char resstr[16] = ""; HIMC imc; @@ -216,12 +225,88 @@ static int test_ImmNotifyIME(void) { msg_spy_flush_msgs(); ImmReleaseContext(hwnd, imc); +} - return 0; +static void test_ImmGetCompositionString(void) +{ + HIMC imc; + static const WCHAR string[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e}; + char cstring[20]; + WCHAR wstring[20]; + DWORD len; + DWORD alen,wlen; + + imc = ImmGetContext(hwnd); + ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL,0); + alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20); + wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20); + /* windows machines without any IME installed just return 0 above */ + if( alen && wlen) + { + len = ImmGetCompositionStringW(imc, GCS_COMPATTR, NULL, 0); + ok(len*sizeof(WCHAR)==wlen,"GCS_COMPATTR(W) not returning correct count\n"); + len = ImmGetCompositionStringA(imc, GCS_COMPATTR, NULL, 0); + ok(len==alen,"GCS_COMPATTR(A) not returning correct count\n"); +} + ImmReleaseContext(hwnd, imc); +} + +static void test_ImmSetCompositionString(void) +{ + HIMC imc; + BOOL ret; + + SetLastError(0xdeadbeef); + imc = ImmGetContext(hwnd); + ok(imc != 0, "ImmGetContext() failed. Last error: %u\n", GetLastError()); + if (!imc) + return; + + ret = ImmSetCompositionStringW(imc, SCS_SETSTR, NULL, 0, NULL, 0); + todo_wine + ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); + + ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGEATTR, + NULL, 0, NULL, 0); + todo_wine + ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); + + ret = ImmSetCompositionStringW(imc, SCS_SETSTR | SCS_CHANGECLAUSE, + NULL, 0, NULL, 0); + todo_wine + ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); + + ret = ImmSetCompositionStringW(imc, SCS_CHANGEATTR | SCS_CHANGECLAUSE, + NULL, 0, NULL, 0); + todo_wine + ok(!ret, "ImmSetCompositionStringW() succeeded.\n"); + + ImmReleaseContext(hwnd, imc); +} + +static void test_ImmIME(void) +{ + HIMC imc; + + imc = ImmGetContext(hwnd); + if (imc) + { + BOOL rc; + rc = ImmConfigureIMEA(imc, NULL, IME_CONFIG_REGISTERWORD, NULL); + ok (rc == 0, "ImmConfigureIMEA did not fail\n"); + rc = ImmConfigureIMEW(imc, NULL, IME_CONFIG_REGISTERWORD, NULL); + ok (rc == 0, "ImmConfigureIMEW did not fail\n"); + } + ImmReleaseContext(hwnd,imc); } START_TEST(imm32) { if (init()) + { test_ImmNotifyIME(); + test_ImmGetCompositionString(); + test_ImmSetCompositionString(); + test_ImmIME(); + } cleanup(); } diff --git a/rostests/winetests/imm32/imm32.rbuild b/rostests/winetests/imm32/imm32.rbuild index 989963cf3ff..94abb2a8262 100644 --- a/rostests/winetests/imm32/imm32.rbuild +++ b/rostests/winetests/imm32/imm32.rbuild @@ -3,14 +3,12 @@ . - 0x600 - 0x600 + imm32.c testlist.c wine imm32 user32 - kernel32 ntdll diff --git a/rostests/winetests/inetcomm/inetcomm.rbuild b/rostests/winetests/inetcomm/inetcomm.rbuild new file mode 100644 index 00000000000..ae1daf3c188 --- /dev/null +++ b/rostests/winetests/inetcomm/inetcomm.rbuild @@ -0,0 +1,12 @@ + + . + + mimeintl.c + mimeole.c + testlist.c + wine + inetcomm + oleaut32 + ole32 + ntdll + diff --git a/rostests/winetests/inetcomm/mimeintl.c b/rostests/winetests/inetcomm/mimeintl.c new file mode 100644 index 00000000000..563943f663b --- /dev/null +++ b/rostests/winetests/inetcomm/mimeintl.c @@ -0,0 +1,304 @@ +/* + * MimeInternational tests + * + * Copyright 2008 Huw Davies + * + * 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 + */ + +#define COBJMACROS +#define NONAMELESSUNION + +#include "windows.h" +#include "ole2.h" +#include "ocidl.h" + +#include "mimeole.h" + +#include "initguid.h" +#include "mlang.h" + +#include +#include + +#include "wine/test.h" + +static void test_create(void) +{ + IMimeInternational *internat, *internat2; + HRESULT hr; + ULONG ref; + + hr = MimeOleGetInternat(&internat); + ok(hr == S_OK, "ret %08x\n", hr); + hr = MimeOleGetInternat(&internat2); + ok(hr == S_OK, "ret %08x\n", hr); + + /* Under w2k8 it's no longer a singleton */ + if(internat == internat2) + { + /* test to show that the object is a singleton with + a reference held by the dll. */ + ref = IMimeInternational_Release(internat2); + ok(ref == 2 || + ref == 1, /* win95 - object is a static singleton */ + "got %d\n", ref); + + ref = IMimeInternational_Release(internat); + ok(ref == 1, "got %d\n", ref); + } + else + { + ref = IMimeInternational_Release(internat2); + ok(ref == 0, "got %d\n", ref); + + ref = IMimeInternational_Release(internat); + ok(ref == 0, "got %d\n", ref); + } + +} + +static inline HRESULT get_mlang(IMultiLanguage **ml) +{ + return CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + &IID_IMultiLanguage, (void **)ml); +} + +static HRESULT mlang_getcsetinfo(const char *charset, MIMECSETINFO *mlang_info) +{ + DWORD len = MultiByteToWideChar(CP_ACP, 0, charset, -1, NULL, 0); + BSTR bstr = SysAllocStringLen(NULL, len - 1); + HRESULT hr; + IMultiLanguage *ml; + + MultiByteToWideChar(CP_ACP, 0, charset, -1, bstr, len); + + hr = get_mlang(&ml); + + if(SUCCEEDED(hr)) + { + hr = IMultiLanguage_GetCharsetInfo(ml, bstr, mlang_info); + IMultiLanguage_Release(ml); + } + SysFreeString(bstr); + if(FAILED(hr)) hr = MIME_E_NOT_FOUND; + return hr; +} + +static HRESULT mlang_getcodepageinfo(UINT cp, MIMECPINFO *mlang_cp_info) +{ + HRESULT hr; + IMultiLanguage *ml; + + hr = get_mlang(&ml); + + if(SUCCEEDED(hr)) + { + hr = IMultiLanguage_GetCodePageInfo(ml, cp, mlang_cp_info); + IMultiLanguage_Release(ml); + } + return hr; +} + +static HRESULT mlang_getcsetinfo_from_cp(UINT cp, CHARSETTYPE charset_type, MIMECSETINFO *mlang_info) +{ + MIMECPINFO mlang_cp_info; + WCHAR *charset_name; + HRESULT hr; + IMultiLanguage *ml; + + hr = mlang_getcodepageinfo(cp, &mlang_cp_info); + if(FAILED(hr)) return hr; + + switch(charset_type) + { + case CHARSET_BODY: + charset_name = mlang_cp_info.wszBodyCharset; + break; + case CHARSET_HEADER: + charset_name = mlang_cp_info.wszHeaderCharset; + break; + case CHARSET_WEB: + charset_name = mlang_cp_info.wszWebCharset; + break; + } + + hr = get_mlang(&ml); + + if(SUCCEEDED(hr)) + { + hr = IMultiLanguage_GetCharsetInfo(ml, charset_name, mlang_info); + IMultiLanguage_Release(ml); + } + return hr; +} + +static void test_charset(void) +{ + IMimeInternational *internat; + HRESULT hr; + HCHARSET hcs, hcs_windows_1252, hcs_windows_1251; + INETCSETINFO cs_info; + MIMECSETINFO mlang_cs_info; + + hr = MimeOleGetInternat(&internat); + ok(hr == S_OK, "ret %08x\n", hr); + + hr = IMimeInternational_FindCharset(internat, "non-existent", &hcs); + ok(hr == MIME_E_NOT_FOUND, "got %08x\n", hr); + + hr = IMimeInternational_FindCharset(internat, "windows-1252", &hcs_windows_1252); + ok(hr == S_OK, "got %08x\n", hr); + hr = IMimeInternational_FindCharset(internat, "windows-1252", &hcs); + ok(hr == S_OK, "got %08x\n", hr); + ok(hcs_windows_1252 == hcs, "got different hcharsets for the same name\n"); + hr = IMimeInternational_FindCharset(internat, "WiNdoWs-1252", &hcs); + ok(hr == S_OK, "got %08x\n", hr); + ok(hcs_windows_1252 == hcs, "got different hcharsets for the same name\n"); + + hr = IMimeInternational_FindCharset(internat, "windows-1251", &hcs_windows_1251); + ok(hr == S_OK, "got %08x\n", hr); + ok(hcs_windows_1252 != hcs_windows_1251, "got the same hcharset for the different names\n"); + + hr = IMimeInternational_GetCharsetInfo(internat, hcs_windows_1252, &cs_info); + ok(hr == S_OK, "got %08x\n", hr); + + hr = mlang_getcsetinfo("windows-1252", &mlang_cs_info); + ok(hr == S_OK, "got %08x\n", hr); + ok(cs_info.cpiWindows == mlang_cs_info.uiCodePage, "cpiWindows %d while mlang uiCodePage %d\n", + cs_info.cpiWindows, mlang_cs_info.uiCodePage); + ok(cs_info.cpiInternet == mlang_cs_info.uiInternetEncoding, "cpiInternet %d while mlang uiInternetEncoding %d\n", + cs_info.cpiInternet, mlang_cs_info.uiInternetEncoding); + ok(cs_info.hCharset == hcs_windows_1252, "hCharset doesn't match requested\n"); + ok(!strcmp(cs_info.szName, "windows-1252"), "szName doesn't match requested\n"); + + hr = IMimeInternational_GetCodePageCharset(internat, 1252, CHARSET_BODY, &hcs); + ok(hr == S_OK, "got %08x\n", hr); + hr = IMimeInternational_GetCharsetInfo(internat, hcs, &cs_info); + ok(hr == S_OK, "got %08x\n", hr); + + hr = mlang_getcsetinfo_from_cp(1252, CHARSET_BODY, &mlang_cs_info); + ok(hr == S_OK, "got %08x\n", hr); + ok(cs_info.cpiWindows == mlang_cs_info.uiCodePage, "cpiWindows %d while mlang uiCodePage %d\n", + cs_info.cpiWindows, mlang_cs_info.uiCodePage); + ok(cs_info.cpiInternet == mlang_cs_info.uiInternetEncoding, "cpiInternet %d while mlang uiInternetEncoding %d\n", + cs_info.cpiInternet, mlang_cs_info.uiInternetEncoding); + + IMimeInternational_Release(internat); +} + +static void test_defaultcharset(void) +{ + IMimeInternational *internat; + HRESULT hr; + HCHARSET hcs_default, hcs, hcs_windows_1251; + + hr = MimeOleGetInternat(&internat); + ok(hr == S_OK, "ret %08x\n", hr); + + hr = IMimeInternational_GetDefaultCharset(internat, &hcs_default); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeInternational_GetCodePageCharset(internat, GetACP(), CHARSET_BODY, &hcs); + ok(hr == S_OK, "ret %08x\n", hr); + ok(hcs_default == hcs, "Unexpected default charset\n"); + + hr = IMimeInternational_FindCharset(internat, "windows-1251", &hcs_windows_1251); + ok(hr == S_OK, "got %08x\n", hr); + hr = IMimeInternational_SetDefaultCharset(internat, hcs_windows_1251); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeInternational_GetDefaultCharset(internat, &hcs); + ok(hr == S_OK, "ret %08x\n", hr); + ok(hcs == hcs_windows_1251, "didn't retrieve recently set default\n"); + /* Set the old default back again */ + hr = IMimeInternational_SetDefaultCharset(internat, hcs_default); + ok(hr == S_OK, "ret %08x\n", hr); + + IMimeInternational_Release(internat); +} + +static void test_convert(void) +{ + IMimeInternational *internat; + HRESULT hr; + BLOB src, dst; + ULONG read; + PROPVARIANT prop_in, prop_out; + static char test_string[] = "test string"; + static WCHAR test_stringW[] = {'t','e','s','t',' ','s','t','r','i','n','g',0}; + + hr = MimeOleGetInternat(&internat); + ok(hr == S_OK, "ret %08x\n", hr); + + src.pBlobData = (BYTE*)test_string; + src.cbSize = sizeof(test_string); + hr = IMimeInternational_ConvertBuffer(internat, 1252, 28591, &src, &dst, &read); + ok(hr == S_OK, "ret %08x\n", hr); + ok(read == sizeof(test_string), "got %d\n", read); + ok(dst.cbSize == sizeof(test_string), "got %d\n", dst.cbSize); + CoTaskMemFree(dst.pBlobData); + + src.cbSize = 2; + hr = IMimeInternational_ConvertBuffer(internat, 1252, 28591, &src, &dst, &read); + ok(hr == S_OK, "ret %08x\n", hr); + ok(read == 2, "got %d\n", read); + ok(dst.cbSize == 2, "got %d\n", dst.cbSize); + CoTaskMemFree(dst.pBlobData); + + prop_in.vt = VT_LPWSTR; + prop_in.u.pwszVal = test_stringW; + hr = IMimeInternational_ConvertString(internat, CP_UNICODE, 1252, &prop_in, &prop_out); + ok(hr == S_OK, "ret %08x\n", hr); + ok(prop_out.vt == VT_LPSTR, "got %d\n", prop_out.vt); + ok(!strcmp(prop_out.u.pszVal, test_string), "got %s\n", prop_out.u.pszVal); + PropVariantClear(&prop_out); + + /* If in.vt is VT_LPWSTR, ignore cpiSrc */ + prop_in.vt = VT_LPWSTR; + prop_in.u.pwszVal = test_stringW; + hr = IMimeInternational_ConvertString(internat, 28591, 1252, &prop_in, &prop_out); + ok(hr == S_OK, "ret %08x\n", hr); + ok(prop_out.vt == VT_LPSTR, "got %d\n", prop_out.vt); + ok(!strcmp(prop_out.u.pszVal, test_string), "got %s\n", prop_out.u.pszVal); + PropVariantClear(&prop_out); + + prop_in.vt = VT_LPSTR; + prop_in.u.pszVal = test_string; + hr = IMimeInternational_ConvertString(internat, 28591, CP_UNICODE, &prop_in, &prop_out); + ok(hr == S_OK, "ret %08x\n", hr); + ok(prop_out.vt == VT_LPWSTR, "got %d\n", prop_out.vt); + ok(!lstrcmpW(prop_out.u.pwszVal, test_stringW), "mismatched strings\n"); + PropVariantClear(&prop_out); + + /* If in.vt is VT_LPSTR and cpiSrc is CP_UNICODE, use another multibyte codepage (probably GetACP()) */ + prop_in.vt = VT_LPSTR; + prop_in.u.pszVal = test_string; + hr = IMimeInternational_ConvertString(internat, CP_UNICODE, CP_UNICODE, &prop_in, &prop_out); + ok(hr == S_OK, "ret %08x\n", hr); + ok(prop_out.vt == VT_LPWSTR, "got %d\n", prop_out.vt); + ok(!lstrcmpW(prop_out.u.pwszVal, test_stringW), "mismatched strings\n"); + PropVariantClear(&prop_out); + + IMimeInternational_Release(internat); +} + +START_TEST(mimeintl) +{ + OleInitialize(NULL); + test_create(); + test_charset(); + test_defaultcharset(); + test_convert(); + OleUninitialize(); +} diff --git a/rostests/winetests/inetcomm/mimeole.c b/rostests/winetests/inetcomm/mimeole.c new file mode 100644 index 00000000000..7edef676f50 --- /dev/null +++ b/rostests/winetests/inetcomm/mimeole.c @@ -0,0 +1,344 @@ +/* + * MimeOle tests + * + * Copyright 2007 Huw Davies + * + * 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 + */ + +#define COBJMACROS +#define NONAMELESSUNION + +#include "initguid.h" +#include "windows.h" +#include "ole2.h" +#include "ocidl.h" + +#include "mimeole.h" + +#include +#include + +#include "wine/test.h" + +static char msg1[] = + "MIME-Version: 1.0\r\n" + "Content-Type: multipart/mixed;\r\n" + " boundary=\"------------1.5.0.6\";\r\n" + " stuff=\"du;nno\";\r\n" + " morestuff=\"so\\\\me\\\"thing\\\"\"\r\n" + "foo: bar\r\n" + "From: Huw Davies \r\n" + "From: Me \r\n" + "To: wine-patches \r\n" + "Cc: Huw Davies ,\r\n" + " \"Fred Bloggs\" \r\n" + "foo: baz\r\n" + "bar: fum\r\n" + "\r\n" + "This is a multi-part message in MIME format.\r\n" + "--------------1.5.0.6\r\n" + "Content-Type: text/plain; format=fixed; charset=UTF-8\r\n" + "Content-Transfer-Encoding: 8bit\r\n" + "\r\n" + "Stuff\r\n" + "--------------1.5.0.6\r\n" + "Content-Type: text/plain; charset=\"us-ascii\"\r\n" + "Content-Transfer-Encoding: 7bit\r\n" + "\r\n" + "More stuff\r\n" + "--------------1.5.0.6--\r\n"; + +static void test_CreateVirtualStream(void) +{ + HRESULT hr; + IStream *pstm; + + hr = MimeOleCreateVirtualStream(&pstm); + ok(hr == S_OK, "ret %08x\n", hr); + + IStream_Release(pstm); +} + +static void test_CreateSecurity(void) +{ + HRESULT hr; + IMimeSecurity *sec; + + hr = MimeOleCreateSecurity(&sec); + ok(hr == S_OK, "ret %08x\n", hr); + + IMimeSecurity_Release(sec); +} + +static void test_CreateBody(void) +{ + HRESULT hr; + IMimeBody *body; + HBODY handle = (void *)0xdeadbeef; + IStream *in; + LARGE_INTEGER off; + ULARGE_INTEGER pos; + ENCODINGTYPE enc; + ULONG count, found_param, i; + MIMEPARAMINFO *param_info; + IMimeAllocator *alloc; + BODYOFFSETS offsets; + + hr = CoCreateInstance(&CLSID_IMimeBody, NULL, CLSCTX_INPROC_SERVER, &IID_IMimeBody, (void**)&body); + ok(hr == S_OK, "ret %08x\n", hr); + + hr = IMimeBody_GetHandle(body, &handle); + ok(hr == MIME_E_NO_DATA, "ret %08x\n", hr); + ok(handle == NULL, "handle %p\n", handle); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &in); + ok(hr == S_OK, "ret %08x\n", hr); + IStream_Write(in, msg1, sizeof(msg1) - 1, NULL); + off.QuadPart = 0; + IStream_Seek(in, off, STREAM_SEEK_SET, NULL); + + /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */ + hr = IMimeBody_InitNew(body); + ok(hr == S_OK, "ret %08x\n", hr); + + hr = IMimeBody_GetCurrentEncoding(body, &enc); + ok(hr == S_OK, "ret %08x\n", hr); + ok(enc == IET_7BIT, "encoding %d\n", enc); + + hr = IMimeBody_Load(body, in); + ok(hr == S_OK, "ret %08x\n", hr); + off.QuadPart = 0; + IStream_Seek(in, off, STREAM_SEEK_CUR, &pos); + ok(pos.u.LowPart == 359, "pos %u\n", pos.u.LowPart); + + hr = IMimeBody_IsContentType(body, "multipart", "mixed"); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeBody_IsContentType(body, "text", "plain"); + ok(hr == S_FALSE, "ret %08x\n", hr); + hr = IMimeBody_IsContentType(body, NULL, "mixed"); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeBody_IsType(body, IBT_EMPTY); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IMimeBody_SetData(body, IET_8BIT, "text", "plain", &IID_IStream, in); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeBody_IsContentType(body, "text", "plain"); + todo_wine + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeBody_GetCurrentEncoding(body, &enc); + ok(hr == S_OK, "ret %08x\n", hr); + ok(enc == IET_8BIT, "encoding %d\n", enc); + + memset(&offsets, 0xcc, sizeof(offsets)); + hr = IMimeBody_GetOffsets(body, &offsets); + ok(hr == MIME_E_NO_DATA, "ret %08x\n", hr); + ok(offsets.cbBoundaryStart == 0, "got %d\n", offsets.cbBoundaryStart); + ok(offsets.cbHeaderStart == 0, "got %d\n", offsets.cbHeaderStart); + ok(offsets.cbBodyStart == 0, "got %d\n", offsets.cbBodyStart); + ok(offsets.cbBodyEnd == 0, "got %d\n", offsets.cbBodyEnd); + + hr = IMimeBody_IsType(body, IBT_EMPTY); + ok(hr == S_FALSE, "got %08x\n", hr); + + hr = MimeOleGetAllocator(&alloc); + ok(hr == S_OK, "ret %08x\n", hr); + + hr = IMimeBody_GetParameters(body, "nothere", &count, ¶m_info); + ok(hr == MIME_E_NOT_FOUND, "ret %08x\n", hr); + ok(count == 0, "got %d\n", count); + ok(!param_info, "got %p\n", param_info); + + hr = IMimeBody_GetParameters(body, "bar", &count, ¶m_info); + ok(hr == S_OK, "ret %08x\n", hr); + ok(count == 0, "got %d\n", count); + ok(!param_info, "got %p\n", param_info); + + hr = IMimeBody_GetParameters(body, "Content-Type", &count, ¶m_info); + ok(hr == S_OK, "ret %08x\n", hr); + todo_wine /* native adds a charset parameter */ + ok(count == 4, "got %d\n", count); + ok(param_info != NULL, "got %p\n", param_info); + + found_param = 0; + for(i = 0; i < count; i++) + { + if(!strcmp(param_info[i].pszName, "morestuff")) + { + found_param++; + ok(!strcmp(param_info[i].pszData, "so\\me\"thing\""), + "got %s\n", param_info[i].pszData); + } + else if(!strcmp(param_info[i].pszName, "stuff")) + { + found_param++; + ok(!strcmp(param_info[i].pszData, "du;nno"), + "got %s\n", param_info[i].pszData); + } + } + ok(found_param == 2, "matched %d params\n", found_param); + + hr = IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE); + ok(hr == S_OK, "ret %08x\n", hr); + IMimeAllocator_Release(alloc); + + IStream_Release(in); + IMimeBody_Release(body); +} + +static void test_Allocator(void) +{ + HRESULT hr; + IMimeAllocator *alloc; + + hr = MimeOleGetAllocator(&alloc); + ok(hr == S_OK, "ret %08x\n", hr); + IMimeAllocator_Release(alloc); +} + +static void test_CreateMessage(void) +{ + HRESULT hr; + IMimeMessage *msg; + IStream *stream; + LARGE_INTEGER pos; + LONG ref; + HBODY hbody; + IMimeBody *body; + BODYOFFSETS offsets; + ULONG count; + FINDBODY find_struct; + HCHARSET hcs; + + char text[] = "text"; + HBODY *body_list; + PROPVARIANT prop; + static char att_pritype[] = "att:pri-content-type"; + + hr = MimeOleCreateMessage(NULL, &msg); + ok(hr == S_OK, "ret %08x\n", hr); + + CreateStreamOnHGlobal(NULL, TRUE, &stream); + IStream_Write(stream, msg1, sizeof(msg1) - 1, NULL); + pos.QuadPart = 0; + IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL); + + hr = IMimeMessage_Load(msg, stream); + ok(hr == S_OK, "ret %08x\n", hr); + + hr = IMimeMessage_CountBodies(msg, HBODY_ROOT, TRUE, &count); + ok(hr == S_OK, "ret %08x\n", hr); + ok(count == 3, "got %d\n", count); + + hr = IMimeMessage_CountBodies(msg, HBODY_ROOT, FALSE, &count); + ok(hr == S_OK, "ret %08x\n", hr); + ok(count == 3, "got %d\n", count); + + hr = IMimeMessage_BindToObject(msg, HBODY_ROOT, &IID_IMimeBody, (void**)&body); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeBody_GetOffsets(body, &offsets); + ok(hr == S_OK, "ret %08x\n", hr); + ok(offsets.cbBoundaryStart == 0, "got %d\n", offsets.cbBoundaryStart); + ok(offsets.cbHeaderStart == 0, "got %d\n", offsets.cbHeaderStart); + ok(offsets.cbBodyStart == 359, "got %d\n", offsets.cbBodyStart); + ok(offsets.cbBodyEnd == 666, "got %d\n", offsets.cbBodyEnd); + IMimeBody_Release(body); + + hr = IMimeMessage_GetBody(msg, IBL_ROOT, NULL, &hbody); + + PropVariantInit(&prop); + hr = IMimeMessage_GetBodyProp(msg, hbody, att_pritype, 0, &prop); + ok(hr == S_OK, "ret %08x\n", hr); + ok(prop.vt == VT_LPSTR, "vt %08x\n", prop.vt); + ok(!strcasecmp(prop.u.pszVal, "multipart"), "got %s\n", prop.u.pszVal); + PropVariantClear(&prop); + + hr = IMimeMessage_GetBody(msg, IBL_FIRST, hbody, &hbody); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeMessage_BindToObject(msg, hbody, &IID_IMimeBody, (void**)&body); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeBody_GetOffsets(body, &offsets); + ok(hr == S_OK, "ret %08x\n", hr); + ok(offsets.cbBoundaryStart == 405, "got %d\n", offsets.cbBoundaryStart); + ok(offsets.cbHeaderStart == 428, "got %d\n", offsets.cbHeaderStart); + ok(offsets.cbBodyStart == 518, "got %d\n", offsets.cbBodyStart); + ok(offsets.cbBodyEnd == 523, "got %d\n", offsets.cbBodyEnd); + + hr = IMimeBody_GetCharset(body, &hcs); + ok(hr == S_OK, "ret %08x\n", hr); + todo_wine + { + ok(hcs != NULL, "Expected non-NULL charset\n"); + } + + IMimeBody_Release(body); + + hr = IMimeMessage_GetBody(msg, IBL_NEXT, hbody, &hbody); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeMessage_BindToObject(msg, hbody, &IID_IMimeBody, (void**)&body); + ok(hr == S_OK, "ret %08x\n", hr); + hr = IMimeBody_GetOffsets(body, &offsets); + ok(hr == S_OK, "ret %08x\n", hr); + ok(offsets.cbBoundaryStart == 525, "got %d\n", offsets.cbBoundaryStart); + ok(offsets.cbHeaderStart == 548, "got %d\n", offsets.cbHeaderStart); + ok(offsets.cbBodyStart == 629, "got %d\n", offsets.cbBodyStart); + ok(offsets.cbBodyEnd == 639, "got %d\n", offsets.cbBodyEnd); + IMimeBody_Release(body); + + find_struct.pszPriType = text; + find_struct.pszSubType = NULL; + + hr = IMimeMessage_FindFirst(msg, &find_struct, &hbody); + ok(hr == S_OK, "ret %08x\n", hr); + + hr = IMimeMessage_FindNext(msg, &find_struct, &hbody); + ok(hr == S_OK, "ret %08x\n", hr); + + hr = IMimeMessage_FindNext(msg, &find_struct, &hbody); + ok(hr == MIME_E_NOT_FOUND, "ret %08x\n", hr); + + hr = IMimeMessage_GetAttachments(msg, &count, &body_list); + ok(hr == S_OK, "ret %08x\n", hr); + ok(count == 2, "got %d\n", count); + CoTaskMemFree(body_list); + + hr = IMimeMessage_GetCharset(body, &hcs); + ok(hr == S_OK, "ret %08x\n", hr); + todo_wine + { + ok(hcs != NULL, "Expected non-NULL charset\n"); + } + + IMimeMessage_Release(msg); + + ref = IStream_AddRef(stream); + ok(ref == 2 || + broken(ref == 1), /* win95 */ + "ref %d\n", ref); + IStream_Release(stream); + + IStream_Release(stream); +} + +START_TEST(mimeole) +{ + OleInitialize(NULL); + test_CreateVirtualStream(); + test_CreateSecurity(); + test_CreateBody(); + test_Allocator(); + test_CreateMessage(); + OleUninitialize(); +} diff --git a/rostests/winetests/inetcomm/testlist.c b/rostests/winetests/inetcomm/testlist.c new file mode 100644 index 00000000000..fd53432c649 --- /dev/null +++ b/rostests/winetests/inetcomm/testlist.c @@ -0,0 +1,17 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_mimeintl(void); +extern void func_mimeole(void); + +const struct test winetest_testlist[] = +{ + { "mimeintl", func_mimeintl }, + { "mimeole", func_mimeole }, + { 0, 0 } +}; diff --git a/rostests/winetests/inetmib1/inetmib1.rbuild b/rostests/winetests/inetmib1/inetmib1.rbuild new file mode 100644 index 00000000000..467cfb35fed --- /dev/null +++ b/rostests/winetests/inetmib1/inetmib1.rbuild @@ -0,0 +1,9 @@ + + . + + main.c + testlist.c + wine + snmpapi + ntdll + diff --git a/rostests/winetests/inetmib1/main.c b/rostests/winetests/inetmib1/main.c new file mode 100644 index 00000000000..6c83d58e7fd --- /dev/null +++ b/rostests/winetests/inetmib1/main.c @@ -0,0 +1,477 @@ +/* + * Copyright 2008 Juan Lang + * + * 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 + */ +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static HMODULE inetmib1; + +static void testInit(void) +{ + BOOL (WINAPI *pInit)(DWORD, HANDLE *, AsnObjectIdentifier *); + BOOL ret; + HANDLE event; + AsnObjectIdentifier oid; + + pInit = (void *)GetProcAddress(inetmib1, "SnmpExtensionInit"); + if (!pInit) + { + win_skip("no SnmpExtensionInit\n"); + return; + } + /* Crash + ret = pInit(0, NULL, NULL); + ret = pInit(0, NULL, &oid); + ret = pInit(0, &event, NULL); + */ + ret = pInit(0, &event, &oid); + ok(ret, "SnmpExtensionInit failed: %d\n", GetLastError()); + ok(!strcmp("1.3.6.1.2.1.1", SnmpUtilOidToA(&oid)), + "Expected 1.3.6.1.2.1.1, got %s\n", SnmpUtilOidToA(&oid)); +} + +static void testQuery(void) +{ + BOOL (WINAPI *pQuery)(BYTE, SnmpVarBindList *, AsnInteger32 *, + AsnInteger32 *); + BOOL ret, moreData, noChange; + SnmpVarBindList list; + AsnInteger32 error, index; + UINT bogus[] = { 1,2,3,4 }; + UINT mib2System[] = { 1,3,6,1,2,1,1 }; + UINT mib2If[] = { 1,3,6,1,2,1,2 }; + UINT mib2IfTable[] = { 1,3,6,1,2,1,2,2 }; + UINT mib2IfDescr[] = { 1,3,6,1,2,1,2,2,1,2 }; + UINT mib2IfAdminStatus[] = { 1,3,6,1,2,1,2,2,1,7 }; + UINT mib2IfOperStatus[] = { 1,3,6,1,2,1,2,2,1,8 }; + UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1,1 }; + UINT mib2IpRouteTable[] = { 1,3,6,1,2,1,4,21,1,1 }; + UINT mib2UdpTable[] = { 1,3,6,1,2,1,7,5,1,1 }; + SnmpVarBind vars[3], vars2[3], vars3[3]; + UINT entry; + + pQuery = (void *)GetProcAddress(inetmib1, "SnmpExtensionQuery"); + if (!pQuery) + { + win_skip("couldn't find SnmpExtensionQuery\n"); + return; + } + /* Crash + ret = pQuery(0, NULL, NULL, NULL); + ret = pQuery(0, NULL, &error, NULL); + ret = pQuery(0, NULL, NULL, &index); + ret = pQuery(0, &list, NULL, NULL); + ret = pQuery(0, &list, &error, NULL); + */ + + /* An empty list succeeds */ + list.len = 0; + error = 0xdeadbeef; + index = 0xdeadbeef; + ret = pQuery(SNMP_PDU_GET, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + ok(error == SNMP_ERRORSTATUS_NOERROR, + "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); + ok(index == 0, "expected index 0, got %d\n", index); + + /* Oddly enough, this "succeeds," even though the OID is clearly + * unsupported. + */ + vars[0].name.idLength = sizeof(bogus) / sizeof(bogus[0]); + vars[0].name.ids = bogus; + vars[0].value.asnType = 0; + list.len = 1; + list.list = vars; + SetLastError(0xdeadbeef); + error = 0xdeadbeef; + index = 0xdeadbeef; + ret = pQuery(SNMP_PDU_GET, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + ok(error == SNMP_ERRORSTATUS_NOERROR || + error == ERROR_FILE_NOT_FOUND /* Win9x */, + "expected SNMP_ERRORSTATUS_NOERROR or ERROR_FILE_NOT_FOUND, got %d\n", + error); + if (error == SNMP_ERRORSTATUS_NOERROR) + ok(index == 0, "expected index 0, got %d\n", index); + else if (error == ERROR_FILE_NOT_FOUND) + ok(index == 1, "expected index 1, got %d\n", index); + /* The OID isn't changed either: */ + ok(!strcmp("1.2.3.4", SnmpUtilOidToA(&vars[0].name)), + "expected 1.2.3.4, got %s\n", SnmpUtilOidToA(&vars[0].name)); + + /* The table is not an accessible variable, so it fails */ + vars[0].name.idLength = sizeof(mib2IfTable) / sizeof(mib2IfTable[0]); + vars[0].name.ids = mib2IfTable; + SetLastError(0xdeadbeef); + error = 0xdeadbeef; + index = 0xdeadbeef; + ret = pQuery(SNMP_PDU_GET, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + ok(error == SNMP_ERRORSTATUS_NOSUCHNAME, + "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error); + /* The index is 1-based rather than 0-based */ + ok(index == 1, "expected index 1, got %d\n", index); + + /* A Get fails on something that specifies a table (but not a particular + * entry in it)... + */ + vars[0].name.idLength = sizeof(mib2IfDescr) / sizeof(mib2IfDescr[0]); + vars[0].name.ids = mib2IfDescr; + vars[1].name.idLength = + sizeof(mib2IfAdminStatus) / sizeof(mib2IfAdminStatus[0]); + vars[1].name.ids = mib2IfAdminStatus; + vars[2].name.idLength = + sizeof(mib2IfOperStatus) / sizeof(mib2IfOperStatus[0]); + vars[2].name.ids = mib2IfOperStatus; + list.len = 3; + SetLastError(0xdeadbeef); + error = 0xdeadbeef; + index = 0xdeadbeef; + ret = pQuery(SNMP_PDU_GET, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + ok(error == SNMP_ERRORSTATUS_NOSUCHNAME, + "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error); + ok(index == 1, "expected index 1, got %d\n", index); + /* but a GetNext succeeds with the same values, because GetNext gets the + * entry after the specified OID, not the entry specified by it. The + * successor to the table is the first entry in the table. + * The OIDs need to be allocated, because GetNext modifies them to indicate + * the end of data. + */ + SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); + SnmpUtilOidCpy(&vars2[1].name, &vars[1].name); + SnmpUtilOidCpy(&vars2[2].name, &vars[2].name); + list.list = vars2; + moreData = TRUE; + noChange = FALSE; + entry = 0; + do { + SetLastError(0xdeadbeef); + error = 0xdeadbeef; + index = 0xdeadbeef; + ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + ok(error == SNMP_ERRORSTATUS_NOERROR, + "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); + ok(index == 0, "expected index 0, got %d\n", index); + if (!ret) + moreData = FALSE; + else if (error) + moreData = FALSE; + else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, + vars[0].name.idLength)) + moreData = FALSE; + else if (SnmpUtilOidNCmp(&vars2[1].name, &vars[1].name, + vars[1].name.idLength)) + moreData = FALSE; + else if (SnmpUtilOidNCmp(&vars2[2].name, &vars[2].name, + vars[2].name.idLength)) + moreData = FALSE; + else if (!SnmpUtilOidCmp(&vars[0].name, &vars2[0].name) || + !SnmpUtilOidCmp(&vars[0].name, &vars2[0].name) || + !SnmpUtilOidCmp(&vars[0].name, &vars2[0].name)) + { + /* If the OID isn't modified, the function isn't implemented on this + * platform, skip the remaining tests. + */ + noChange = TRUE; + } + if (moreData) + { + UINT lastID; + + /* Check the OIDs. For these types of values (display strings and + * integers) they should increase by 1 for each element of the table + * according to RFC 1158. Windows sometimes has a weird value in the + * table, so allow any value as long as it's greater than the previous + * value on Windows. + */ + ok(vars2[0].name.idLength == vars[0].name.idLength + 1, + "expected length %d, got %d\n", vars[0].name.idLength + 1, + vars2[0].name.idLength); + lastID = vars2[0].name.ids[vars2[0].name.idLength - 1]; + ok(lastID == entry + 1 || broken(lastID > entry), + "expected %d, got %d\n", entry + 1, lastID); + ok(vars2[1].name.idLength == vars[1].name.idLength + 1, + "expected length %d, got %d\n", vars[1].name.idLength + 1, + vars2[1].name.idLength); + lastID = vars2[1].name.ids[vars2[1].name.idLength - 1]; + ok(lastID == entry + 1 || broken(lastID > entry), + "expected %d, got %d\n", entry + 1, lastID); + ok(vars2[2].name.idLength == vars[2].name.idLength + 1, + "expected length %d, got %d\n", vars[2].name.idLength + 1, + vars2[2].name.idLength); + lastID = vars2[2].name.ids[vars2[2].name.idLength - 1]; + ok(lastID == entry + 1 || broken(lastID > entry), + "expected %d, got %d\n", entry + 1, lastID); + entry = lastID; + /* Check the types while we're at it */ + ok(vars2[0].value.asnType == ASN_OCTETSTRING, + "expected ASN_OCTETSTRING, got %02x\n", vars2[0].value.asnType); + ok(vars2[1].value.asnType == ASN_INTEGER, + "expected ASN_INTEGER, got %02x\n", vars2[1].value.asnType); + ok(vars2[2].value.asnType == ASN_INTEGER, + "expected ASN_INTEGER, got %02x\n", vars2[2].value.asnType); + } + else if (noChange) + skip("no change in OID, no MIB2 IF table implementation\n"); + } while (moreData && !noChange); + SnmpUtilVarBindFree(&vars2[0]); + SnmpUtilVarBindFree(&vars2[1]); + SnmpUtilVarBindFree(&vars2[2]); + + /* Even though SnmpExtensionInit says this DLL supports the MIB2 system + * variables, on recent systems (at least Win2k) the first variable it + * returns a value for is the first interface. + */ + vars[0].name.idLength = sizeof(mib2System) / sizeof(mib2System[0]); + vars[0].name.ids = mib2System; + SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); + vars2[0].value.asnType = 0; + list.len = 1; + list.list = vars2; + moreData = TRUE; + noChange = FALSE; + ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + ok(error == SNMP_ERRORSTATUS_NOERROR, + "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); + ok(index == 0, "expected index 0, got %d\n", index); + vars3[0].name.idLength = sizeof(mib2If) / sizeof(mib2If[0]); + vars3[0].name.ids = mib2If; + ok(!SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength) || + !SnmpUtilOidNCmp(&vars2[0].name, &vars3[0].name, vars3[0].name.idLength), + "expected 1.3.6.1.2.1.1 or 1.3.6.1.2.1.2, got %s\n", + SnmpUtilOidToA(&vars2[0].name)); + SnmpUtilVarBindFree(&vars2[0]); + + /* Check the type and OIDs of the IP address table */ + vars[0].name.idLength = sizeof(mib2IpAddr) / sizeof(mib2IpAddr[0]); + vars[0].name.ids = mib2IpAddr; + SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); + vars2[0].value.asnType = 0; + list.len = 1; + list.list = vars2; + moreData = TRUE; + do { + ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + ok(error == SNMP_ERRORSTATUS_NOERROR, + "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); + ok(index == 0, "expected index 0, got %d\n", index); + if (!ret) + moreData = FALSE; + else if (error) + moreData = FALSE; + else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, + vars[0].name.idLength)) + moreData = FALSE; + else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) + { + /* If the OID isn't modified, the function isn't implemented on this + * platform, skip the remaining tests. + */ + noChange = TRUE; + } + if (moreData) + { + /* Make sure the size of the OID is right. + * FIXME: don't know if IPv6 addrs are shared with this table. + * Don't think so, but I'm not certain. + */ + ok(vars2[0].name.idLength == vars[0].name.idLength + 4, + "expected length %d, got %d\n", vars[0].name.idLength + 4, + vars2[0].name.idLength); + /* Make sure the type is right */ + ok(vars2[0].value.asnType == ASN_IPADDRESS, + "expected type ASN_IPADDRESS, got %02x\n", + vars2[0].value.asnType); + if (vars2[0].value.asnType == ASN_IPADDRESS) + { + UINT i; + + /* This looks uglier than it is: the base OID for the IP + * address, 1.3.6.1.2.1.4.20.1.1, is appended with the IP + * address of the entry. So e.g. the loopback address is + * identified in MIB2 as 1.3.6.1.2.1.4.20.1.1.127.0.0.1 + */ + for (i = 0; i < vars2[0].value.asnValue.address.length; i++) + { + ok(vars2[0].value.asnValue.address.stream[i] == + vars2[0].name.ids[vars2[0].name.idLength - 4 + i], + "expected ident byte %d to be %d, got %d\n", i, + vars2[0].value.asnValue.address.stream[i], + vars2[0].name.ids[vars2[0].name.idLength - 4 + i]); + } + } + } + else if (noChange) + skip("no change in OID, no MIB2 IP address table implementation\n"); + } while (moreData && !noChange); + SnmpUtilVarBindFree(&vars2[0]); + + /* Check the type and OIDs of the IP route table */ + vars[0].name.idLength = DEFINE_SIZEOF(mib2IpRouteTable); + vars[0].name.ids = mib2IpRouteTable; + SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); + vars2[0].value.asnType = 0; + list.len = 1; + list.list = vars2; + moreData = TRUE; + noChange = FALSE; + do { + ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + ok(error == SNMP_ERRORSTATUS_NOERROR, + "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); + ok(index == 0, "expected index 0, got %d\n", index); + if (!ret) + moreData = FALSE; + else if (error) + moreData = FALSE; + else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, + vars[0].name.idLength)) + moreData = FALSE; + else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) + { + /* If the OID isn't modified, the function isn't implemented on this + * platform, skip the remaining tests. + */ + noChange = TRUE; + } + if (moreData) + { + /* Make sure the size of the OID is right. + * FIXME: don't know if IPv6 addrs are shared with this table. + * Don't think so, but I'm not certain. + */ + ok(vars2[0].name.idLength == vars[0].name.idLength + 4, + "expected length %d, got %d\n", vars[0].name.idLength + 4, + vars2[0].name.idLength); + /* Make sure the type is right */ + ok(vars2[0].value.asnType == ASN_IPADDRESS, + "expected type ASN_IPADDRESS, got %02x\n", + vars2[0].value.asnType); + if (vars2[0].value.asnType == ASN_IPADDRESS) + { + UINT i; + + /* The base OID for the route table, 1.3.6.1.2.1.4.21.1.1, is + * appended with the dest IP address of the entry. So e.g. a + * route entry for 224.0.0.0 is identified in MIB2 as + * 1.3.6.1.2.1.4.21.1.1.224.0.0.0 + */ + for (i = 0; i < vars2[0].value.asnValue.address.length; i++) + { + ok(vars2[0].value.asnValue.address.stream[i] == + vars2[0].name.ids[vars2[0].name.idLength - 4 + i], + "expected ident byte %d to be %d, got %d\n", i, + vars2[0].value.asnValue.address.stream[i], + vars2[0].name.ids[vars2[0].name.idLength - 4 + i]); + } + } + } + else if (noChange) + skip("no change in OID, no MIB2 IP route table implementation\n"); + } while (moreData && !noChange); + SnmpUtilVarBindFree(&vars2[0]); + + /* Check the type and OIDs of the UDP table */ + vars[0].name.idLength = DEFINE_SIZEOF(mib2UdpTable); + vars[0].name.ids = mib2UdpTable; + SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); + vars2[0].value.asnType = 0; + list.len = 1; + list.list = vars2; + moreData = TRUE; + noChange = FALSE; + do { + ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + /* FIXME: error and index aren't checked here because the UDP table is + * the last OID currently supported by Wine, so the last GetNext fails. + * todo_wine is also not effective because it will succeed for all but + * the last GetNext. Remove the if (0) if any later OID is supported + * by Wine. + */ + if (0) { + ok(error == SNMP_ERRORSTATUS_NOERROR, + "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); + ok(index == 0, "expected index 0, got %d\n", index); + } + if (!ret) + moreData = FALSE; + else if (error) + moreData = FALSE; + else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, + vars[0].name.idLength)) + moreData = FALSE; + else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) + { + /* If the OID isn't modified, the function isn't implemented on this + * platform, skip the remaining tests. + */ + noChange = TRUE; + } + if (moreData) + { + /* Make sure the size of the OID is right. */ + ok(vars2[0].name.idLength == vars[0].name.idLength + 5, + "expected length %d, got %d\n", vars[0].name.idLength + 5, + vars2[0].name.idLength); + /* Make sure the type is right */ + ok(vars2[0].value.asnType == ASN_IPADDRESS, + "expected type ASN_IPADDRESS, got %02x\n", + vars2[0].value.asnType); + if (vars2[0].value.asnType == ASN_IPADDRESS) + { + UINT i; + + /* Again with the ugly: the base OID for the UDP table, + * 1.3.6.1.2.1.7.5.1, is appended with the local IP address and + * port number of the entry. So e.g. an entry for + * 192.168.1.1:4000 is identified in MIB2 as + * 1.3.6.1.2.1.7.5.1.192.168.1.1.4000 + */ + for (i = 0; i < vars2[0].value.asnValue.address.length; i++) + { + ok(vars2[0].value.asnValue.address.stream[i] == + vars2[0].name.ids[vars2[0].name.idLength - 5 + i], + "expected ident byte %d to be %d, got %d\n", i, + vars2[0].value.asnValue.address.stream[i], + vars2[0].name.ids[vars2[0].name.idLength - 5 + i]); + } + } + } + else if (noChange) + skip("no change in OID, no MIB2 UDP table implementation\n"); + } while (moreData && !noChange); + SnmpUtilVarBindFree(&vars2[0]); +} + +START_TEST(main) +{ + inetmib1 = LoadLibraryA("inetmib1"); + testInit(); + testQuery(); + FreeLibrary(inetmib1); +} diff --git a/rostests/winetests/inetmib1/testlist.c b/rostests/winetests/inetmib1/testlist.c new file mode 100644 index 00000000000..6f0c3974819 --- /dev/null +++ b/rostests/winetests/inetmib1/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_main(void); + +const struct test winetest_testlist[] = +{ + { "main", func_main }, + { 0, 0 } +}; diff --git a/rostests/winetests/iphlpapi/iphlpapi.c b/rostests/winetests/iphlpapi/iphlpapi.c new file mode 100644 index 00000000000..cd2e45200a3 --- /dev/null +++ b/rostests/winetests/iphlpapi/iphlpapi.c @@ -0,0 +1,904 @@ +/* + * iphlpapi dll test + * + * Copyright (C) 2003 Juan Lang + * + * 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 + */ + +/* + * Some observations that an automated test can't produce: + * An adapter index is a key for an adapter. That is, if an index is returned + * from one API, that same index may be used successfully in another API, as + * long as the adapter remains present. + * If the adapter is removed and reinserted, however, the index may change (and + * indeed it does change on Win2K). + * + * The Name field of the IP_ADAPTER_INDEX_MAP entries returned by + * GetInterfaceInfo is declared as a wide string, but the bytes are actually + * an ASCII string on some versions of the IP helper API under Win9x. This was + * apparently an MS bug, it's corrected in later versions. + * + * The DomainName field of FIXED_INFO isn't NULL-terminated on Win98. + */ + +#include +#include "winsock2.h" +#include "windef.h" +#include "winbase.h" +#include "iphlpapi.h" +#include "iprtrmib.h" +#include "wine/test.h" +#include +#include + +#undef htonl +#undef htons +#undef ntohl +#undef ntohs + +#define htonl(l) ((u_long)(l)) +#define htons(s) ((u_short)(s)) +#define ntohl(l) ((u_long)(l)) +#define ntohs(s) ((u_short)(s)) + +static HMODULE hLibrary = NULL; + +typedef DWORD (WINAPI *GetNumberOfInterfacesFunc)(PDWORD); +typedef DWORD (WINAPI *GetIpAddrTableFunc)(PMIB_IPADDRTABLE,PULONG,BOOL); +typedef DWORD (WINAPI *GetIfEntryFunc)(PMIB_IFROW); +typedef DWORD (WINAPI *GetFriendlyIfIndexFunc)(DWORD); +typedef DWORD (WINAPI *GetIfTableFunc)(PMIB_IFTABLE,PULONG,BOOL); +typedef DWORD (WINAPI *GetIpForwardTableFunc)(PMIB_IPFORWARDTABLE,PULONG,BOOL); +typedef DWORD (WINAPI *GetIpNetTableFunc)(PMIB_IPNETTABLE,PULONG,BOOL); +typedef DWORD (WINAPI *GetInterfaceInfoFunc)(PIP_INTERFACE_INFO,PULONG); +typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO,PULONG); +typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO,PULONG); +typedef DWORD (WINAPI *GetIcmpStatisticsFunc)(PMIB_ICMP); +typedef DWORD (WINAPI *GetIpStatisticsFunc)(PMIB_IPSTATS); +typedef DWORD (WINAPI *GetTcpStatisticsFunc)(PMIB_TCPSTATS); +typedef DWORD (WINAPI *GetUdpStatisticsFunc)(PMIB_UDPSTATS); +typedef DWORD (WINAPI *GetTcpTableFunc)(PMIB_TCPTABLE,PDWORD,BOOL); +typedef DWORD (WINAPI *GetUdpTableFunc)(PMIB_UDPTABLE,PDWORD,BOOL); +typedef DWORD (WINAPI *GetPerAdapterInfoFunc)(ULONG,PIP_PER_ADAPTER_INFO,PULONG); +typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(ULONG,ULONG,PVOID,PIP_ADAPTER_ADDRESSES,PULONG); + +static GetNumberOfInterfacesFunc gGetNumberOfInterfaces = NULL; +static GetIpAddrTableFunc gGetIpAddrTable = NULL; +static GetIfEntryFunc gGetIfEntry = NULL; +static GetFriendlyIfIndexFunc gGetFriendlyIfIndex = NULL; +static GetIfTableFunc gGetIfTable = NULL; +static GetIpForwardTableFunc gGetIpForwardTable = NULL; +static GetIpNetTableFunc gGetIpNetTable = NULL; +static GetInterfaceInfoFunc gGetInterfaceInfo = NULL; +static GetAdaptersInfoFunc gGetAdaptersInfo = NULL; +static GetNetworkParamsFunc gGetNetworkParams = NULL; +static GetIcmpStatisticsFunc gGetIcmpStatistics = NULL; +static GetIpStatisticsFunc gGetIpStatistics = NULL; +static GetTcpStatisticsFunc gGetTcpStatistics = NULL; +static GetUdpStatisticsFunc gGetUdpStatistics = NULL; +static GetTcpTableFunc gGetTcpTable = NULL; +static GetUdpTableFunc gGetUdpTable = NULL; +static GetPerAdapterInfoFunc gGetPerAdapterInfo = NULL; +static GetAdaptersAddressesFunc gGetAdaptersAddresses = NULL; + +static void loadIPHlpApi(void) +{ + hLibrary = LoadLibraryA("iphlpapi.dll"); + if (hLibrary) { + gGetNumberOfInterfaces = (GetNumberOfInterfacesFunc)GetProcAddress( + hLibrary, "GetNumberOfInterfaces"); + gGetIpAddrTable = (GetIpAddrTableFunc)GetProcAddress( + hLibrary, "GetIpAddrTable"); + gGetIfEntry = (GetIfEntryFunc)GetProcAddress( + hLibrary, "GetIfEntry"); + gGetFriendlyIfIndex = (GetFriendlyIfIndexFunc)GetProcAddress( + hLibrary, "GetFriendlyIfIndex"); + gGetIfTable = (GetIfTableFunc)GetProcAddress( + hLibrary, "GetIfTable"); + gGetIpForwardTable = (GetIpForwardTableFunc)GetProcAddress( + hLibrary, "GetIpForwardTable"); + gGetIpNetTable = (GetIpNetTableFunc)GetProcAddress( + hLibrary, "GetIpNetTable"); + gGetInterfaceInfo = (GetInterfaceInfoFunc)GetProcAddress( + hLibrary, "GetInterfaceInfo"); + gGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress( + hLibrary, "GetAdaptersInfo"); + gGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress( + hLibrary, "GetNetworkParams"); + gGetIcmpStatistics = (GetIcmpStatisticsFunc)GetProcAddress( + hLibrary, "GetIcmpStatistics"); + gGetIpStatistics = (GetIpStatisticsFunc)GetProcAddress( + hLibrary, "GetIpStatistics"); + gGetTcpStatistics = (GetTcpStatisticsFunc)GetProcAddress( + hLibrary, "GetTcpStatistics"); + gGetUdpStatistics = (GetUdpStatisticsFunc)GetProcAddress( + hLibrary, "GetUdpStatistics"); + gGetTcpTable = (GetTcpTableFunc)GetProcAddress( + hLibrary, "GetTcpTable"); + gGetUdpTable = (GetUdpTableFunc)GetProcAddress( + hLibrary, "GetUdpTable"); + gGetPerAdapterInfo = (GetPerAdapterInfoFunc)GetProcAddress(hLibrary, "GetPerAdapterInfo"); + gGetAdaptersAddresses = (GetAdaptersAddressesFunc)GetProcAddress(hLibrary, "GetAdaptersAddresses"); + } +} + +static void freeIPHlpApi(void) +{ + if (hLibrary) { + gGetNumberOfInterfaces = NULL; + gGetIpAddrTable = NULL; + gGetIfEntry = NULL; + gGetFriendlyIfIndex = NULL; + gGetIfTable = NULL; + gGetIpForwardTable = NULL; + gGetIpNetTable = NULL; + gGetInterfaceInfo = NULL; + gGetAdaptersInfo = NULL; + gGetNetworkParams = NULL; + gGetIcmpStatistics = NULL; + gGetIpStatistics = NULL; + gGetTcpStatistics = NULL; + gGetUdpStatistics = NULL; + gGetTcpTable = NULL; + gGetUdpTable = NULL; + FreeLibrary(hLibrary); + hLibrary = NULL; + } +} + +/* replacement for inet_ntoa */ +static const char *ntoa( DWORD ip ) +{ + static char buffer[40]; + + ip = htonl(ip); + sprintf( buffer, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff ); + return buffer; +} + +/* +still-to-be-tested 98-only functions: +GetUniDirectionalAdapterInfo +*/ +static void testWin98OnlyFunctions(void) +{ +} + +static void testGetNumberOfInterfaces(void) +{ + if (gGetNumberOfInterfaces) { + DWORD apiReturn, numInterfaces; + + /* Crashes on Vista */ + if (0) { + apiReturn = gGetNumberOfInterfaces(NULL), numInterfaces; + if (apiReturn == ERROR_NOT_SUPPORTED) + return; + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetNumberOfInterfaces(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + } + + apiReturn = gGetNumberOfInterfaces(&numInterfaces); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetNumberOfInterfaces is not supported\n"); + return; + } + ok(apiReturn == NO_ERROR, + "GetNumberOfInterfaces returned %d, expected 0\n", apiReturn); + } +} + +static void testGetIfEntry(DWORD index) +{ + if (gGetIfEntry) { + DWORD apiReturn; + MIB_IFROW row; + + memset(&row, 0, sizeof(row)); + apiReturn = gGetIfEntry(NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetIfEntry is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetIfEntry(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + row.dwIndex = -1; /* hope that's always bogus! */ + apiReturn = gGetIfEntry(&row); + ok(apiReturn == ERROR_INVALID_DATA || + apiReturn == ERROR_FILE_NOT_FOUND /* Vista */, + "GetIfEntry(bogus row) returned %d, expected ERROR_INVALID_DATA or ERROR_FILE_NOT_FOUND\n", + apiReturn); + row.dwIndex = index; + apiReturn = gGetIfEntry(&row); + ok(apiReturn == NO_ERROR, + "GetIfEntry returned %d, expected NO_ERROR\n", apiReturn); + } +} + +static void testGetIpAddrTable(void) +{ + if (gGetIpAddrTable) { + DWORD apiReturn; + ULONG dwSize = 0; + + apiReturn = gGetIpAddrTable(NULL, NULL, FALSE); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetIpAddrTable is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetIpAddrTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetIpAddrTable(NULL, &dwSize, FALSE); + ok(apiReturn == ERROR_INSUFFICIENT_BUFFER, + "GetIpAddrTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n", + apiReturn); + if (apiReturn == ERROR_INSUFFICIENT_BUFFER) { + PMIB_IPADDRTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize); + + apiReturn = gGetIpAddrTable(buf, &dwSize, FALSE); + ok(apiReturn == NO_ERROR, + "GetIpAddrTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n", + apiReturn); + if (apiReturn == NO_ERROR && buf->dwNumEntries) + testGetIfEntry(buf->table[0].dwIndex); + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +static void testGetIfTable(void) +{ + if (gGetIfTable) { + DWORD apiReturn; + ULONG dwSize = 0; + + apiReturn = gGetIfTable(NULL, NULL, FALSE); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetIfTable is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetIfTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetIfTable(NULL, &dwSize, FALSE); + ok(apiReturn == ERROR_INSUFFICIENT_BUFFER, + "GetIfTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n", + apiReturn); + if (apiReturn == ERROR_INSUFFICIENT_BUFFER) { + PMIB_IFTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize); + + apiReturn = gGetIfTable(buf, &dwSize, FALSE); + ok(apiReturn == NO_ERROR, + "GetIfTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n\n", + apiReturn); + + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + DWORD i, j; + char name[MAX_INTERFACE_NAME_LEN]; + + trace( "interface table: %u entries\n", buf->dwNumEntries ); + for (i = 0; i < buf->dwNumEntries; i++) + { + MIB_IFROW *row = &buf->table[i]; + WideCharToMultiByte( CP_ACP, 0, row->wszName, -1, name, MAX_INTERFACE_NAME_LEN, NULL, NULL ); + trace( "%u: '%s' type %u mtu %u speed %u phys", + row->dwIndex, name, row->dwType, row->dwMtu, row->dwSpeed ); + for (j = 0; j < row->dwPhysAddrLen; j++) + printf( " %02x", row->bPhysAddr[j] ); + printf( "\n" ); + trace( " in: bytes %u upkts %u nupkts %u disc %u err %u unk %u\n", + row->dwInOctets, row->dwInUcastPkts, row->dwInNUcastPkts, + row->dwInDiscards, row->dwInErrors, row->dwInUnknownProtos ); + trace( " out: bytes %u upkts %u nupkts %u disc %u err %u\n", + row->dwOutOctets, row->dwOutUcastPkts, row->dwOutNUcastPkts, + row->dwOutDiscards, row->dwOutErrors ); + } + } + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +static void testGetIpForwardTable(void) +{ + if (gGetIpForwardTable) { + DWORD apiReturn; + ULONG dwSize = 0; + + apiReturn = gGetIpForwardTable(NULL, NULL, FALSE); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetIpForwardTable is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetIpForwardTable(NULL, &dwSize, FALSE); + ok(apiReturn == ERROR_INSUFFICIENT_BUFFER, + "GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n", + apiReturn); + if (apiReturn == ERROR_INSUFFICIENT_BUFFER) { + PMIB_IPFORWARDTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize); + + apiReturn = gGetIpForwardTable(buf, &dwSize, FALSE); + ok(apiReturn == NO_ERROR, + "GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n", + apiReturn); + + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + DWORD i; + + trace( "IP forward table: %u entries\n", buf->dwNumEntries ); + for (i = 0; i < buf->dwNumEntries; i++) + { + char buffer[40]; + sprintf( buffer, "dest %s", ntoa( buf->table[i].dwForwardDest )); + sprintf( buffer + strlen(buffer), " mask %s", ntoa( buf->table[i].dwForwardMask )); + trace( "%u: %s gw %s if %u type %u\n", i, buffer, + ntoa( buf->table[i].dwForwardNextHop ), + buf->table[i].dwForwardIfIndex, buf->table[i].dwForwardType ); + } + } + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +static void testGetIpNetTable(void) +{ + if (gGetIpNetTable) { + DWORD apiReturn; + ULONG dwSize = 0; + + apiReturn = gGetIpNetTable(NULL, NULL, FALSE); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetIpNetTable is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetIpNetTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetIpNetTable(NULL, &dwSize, FALSE); + ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_INSUFFICIENT_BUFFER, + "GetIpNetTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_NO_DATA or ERROR_INSUFFICIENT_BUFFER\n", + apiReturn); + if (apiReturn == ERROR_NO_DATA) + ; /* empty ARP table's okay */ + else if (apiReturn == ERROR_INSUFFICIENT_BUFFER) { + PMIB_IPNETTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize); + + apiReturn = gGetIpNetTable(buf, &dwSize, FALSE); + ok(apiReturn == NO_ERROR || + apiReturn == ERROR_NO_DATA, /* empty ARP table's okay */ + "GetIpNetTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n", + apiReturn); + + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + DWORD i, j; + + trace( "IP net table: %u entries\n", buf->dwNumEntries ); + for (i = 0; i < buf->dwNumEntries; i++) + { + trace( "%u: idx %u type %u addr %s phys", + i, buf->table[i].dwIndex, buf->table[i].dwType, ntoa( buf->table[i].dwAddr )); + for (j = 0; j < buf->table[i].dwPhysAddrLen; j++) + printf( " %02x", buf->table[i].bPhysAddr[j] ); + printf( "\n" ); + } + } + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +static void testGetIcmpStatistics(void) +{ + if (gGetIcmpStatistics) { + DWORD apiReturn; + MIB_ICMP stats; + + /* Crashes on Vista */ + if (0) { + apiReturn = gGetIcmpStatistics(NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) + return; + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetIcmpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + } + + apiReturn = gGetIcmpStatistics(&stats); + if (apiReturn == ERROR_NOT_SUPPORTED) + { + skip("GetIcmpStatistics is not supported\n"); + return; + } + ok(apiReturn == NO_ERROR, + "GetIcmpStatistics returned %d, expected NO_ERROR\n", apiReturn); + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + trace( "ICMP stats: %8s %8s\n", "in", "out" ); + trace( " dwMsgs: %8u %8u\n", stats.stats.icmpInStats.dwMsgs, stats.stats.icmpOutStats.dwMsgs ); + trace( " dwErrors: %8u %8u\n", stats.stats.icmpInStats.dwErrors, stats.stats.icmpOutStats.dwErrors ); + trace( " dwDestUnreachs: %8u %8u\n", stats.stats.icmpInStats.dwDestUnreachs, stats.stats.icmpOutStats.dwDestUnreachs ); + trace( " dwTimeExcds: %8u %8u\n", stats.stats.icmpInStats.dwTimeExcds, stats.stats.icmpOutStats.dwTimeExcds ); + trace( " dwParmProbs: %8u %8u\n", stats.stats.icmpInStats.dwParmProbs, stats.stats.icmpOutStats.dwParmProbs ); + trace( " dwSrcQuenchs: %8u %8u\n", stats.stats.icmpInStats.dwSrcQuenchs, stats.stats.icmpOutStats.dwSrcQuenchs ); + trace( " dwRedirects: %8u %8u\n", stats.stats.icmpInStats.dwRedirects, stats.stats.icmpOutStats.dwRedirects ); + trace( " dwEchos: %8u %8u\n", stats.stats.icmpInStats.dwEchos, stats.stats.icmpOutStats.dwEchos ); + trace( " dwEchoReps: %8u %8u\n", stats.stats.icmpInStats.dwEchoReps, stats.stats.icmpOutStats.dwEchoReps ); + trace( " dwTimestamps: %8u %8u\n", stats.stats.icmpInStats.dwTimestamps, stats.stats.icmpOutStats.dwTimestamps ); + trace( " dwTimestampReps: %8u %8u\n", stats.stats.icmpInStats.dwTimestampReps, stats.stats.icmpOutStats.dwTimestampReps ); + trace( " dwAddrMasks: %8u %8u\n", stats.stats.icmpInStats.dwAddrMasks, stats.stats.icmpOutStats.dwAddrMasks ); + trace( " dwAddrMaskReps: %8u %8u\n", stats.stats.icmpInStats.dwAddrMaskReps, stats.stats.icmpOutStats.dwAddrMaskReps ); + } + } +} + +static void testGetIpStatistics(void) +{ + if (gGetIpStatistics) { + DWORD apiReturn; + MIB_IPSTATS stats; + + apiReturn = gGetIpStatistics(NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetIpStatistics is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetIpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetIpStatistics(&stats); + ok(apiReturn == NO_ERROR, + "GetIpStatistics returned %d, expected NO_ERROR\n", apiReturn); + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + trace( "IP stats:\n" ); + trace( " dwForwarding: %u\n", stats.dwForwarding ); + trace( " dwDefaultTTL: %u\n", stats.dwDefaultTTL ); + trace( " dwInReceives: %u\n", stats.dwInReceives ); + trace( " dwInHdrErrors: %u\n", stats.dwInHdrErrors ); + trace( " dwInAddrErrors: %u\n", stats.dwInAddrErrors ); + trace( " dwForwDatagrams: %u\n", stats.dwForwDatagrams ); + trace( " dwInUnknownProtos: %u\n", stats.dwInUnknownProtos ); + trace( " dwInDiscards: %u\n", stats.dwInDiscards ); + trace( " dwInDelivers: %u\n", stats.dwInDelivers ); + trace( " dwOutRequests: %u\n", stats.dwOutRequests ); + trace( " dwRoutingDiscards: %u\n", stats.dwRoutingDiscards ); + trace( " dwOutDiscards: %u\n", stats.dwOutDiscards ); + trace( " dwOutNoRoutes: %u\n", stats.dwOutNoRoutes ); + trace( " dwReasmTimeout: %u\n", stats.dwReasmTimeout ); + trace( " dwReasmReqds: %u\n", stats.dwReasmReqds ); + trace( " dwReasmOks: %u\n", stats.dwReasmOks ); + trace( " dwReasmFails: %u\n", stats.dwReasmFails ); + trace( " dwFragOks: %u\n", stats.dwFragOks ); + trace( " dwFragFails: %u\n", stats.dwFragFails ); + trace( " dwFragCreates: %u\n", stats.dwFragCreates ); + trace( " dwNumIf: %u\n", stats.dwNumIf ); + trace( " dwNumAddr: %u\n", stats.dwNumAddr ); + trace( " dwNumRoutes: %u\n", stats.dwNumRoutes ); + } + } +} + +static void testGetTcpStatistics(void) +{ + if (gGetTcpStatistics) { + DWORD apiReturn; + MIB_TCPSTATS stats; + + apiReturn = gGetTcpStatistics(NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetTcpStatistics is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetTcpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetTcpStatistics(&stats); + ok(apiReturn == NO_ERROR, + "GetTcpStatistics returned %d, expected NO_ERROR\n", apiReturn); + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + trace( "TCP stats:\n" ); + trace( " dwRtoAlgorithm: %u\n", stats.dwRtoAlgorithm ); + trace( " dwRtoMin: %u\n", stats.dwRtoMin ); + trace( " dwRtoMax: %u\n", stats.dwRtoMax ); + trace( " dwMaxConn: %u\n", stats.dwMaxConn ); + trace( " dwActiveOpens: %u\n", stats.dwActiveOpens ); + trace( " dwPassiveOpens: %u\n", stats.dwPassiveOpens ); + trace( " dwAttemptFails: %u\n", stats.dwAttemptFails ); + trace( " dwEstabResets: %u\n", stats.dwEstabResets ); + trace( " dwCurrEstab: %u\n", stats.dwCurrEstab ); + trace( " dwInSegs: %u\n", stats.dwInSegs ); + trace( " dwOutSegs: %u\n", stats.dwOutSegs ); + trace( " dwRetransSegs: %u\n", stats.dwRetransSegs ); + trace( " dwInErrs: %u\n", stats.dwInErrs ); + trace( " dwOutRsts: %u\n", stats.dwOutRsts ); + trace( " dwNumConns: %u\n", stats.dwNumConns ); + } + } +} + +static void testGetUdpStatistics(void) +{ + if (gGetUdpStatistics) { + DWORD apiReturn; + MIB_UDPSTATS stats; + + apiReturn = gGetUdpStatistics(NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetUdpStatistics is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetUdpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetUdpStatistics(&stats); + ok(apiReturn == NO_ERROR, + "GetUdpStatistics returned %d, expected NO_ERROR\n", apiReturn); + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + trace( "UDP stats:\n" ); + trace( " dwInDatagrams: %u\n", stats.dwInDatagrams ); + trace( " dwNoPorts: %u\n", stats.dwNoPorts ); + trace( " dwInErrors: %u\n", stats.dwInErrors ); + trace( " dwOutDatagrams: %u\n", stats.dwOutDatagrams ); + trace( " dwNumAddrs: %u\n", stats.dwNumAddrs ); + } + } +} + +static void testGetTcpTable(void) +{ + if (gGetTcpTable) { + DWORD apiReturn; + ULONG dwSize = 0; + + apiReturn = gGetTcpTable(NULL, &dwSize, FALSE); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetTcpTable is not supported\n"); + return; + } + ok(apiReturn == ERROR_INSUFFICIENT_BUFFER || + broken(apiReturn == ERROR_NO_DATA), /* win95 */ + "GetTcpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n", + apiReturn); + if (apiReturn == ERROR_INSUFFICIENT_BUFFER) { + PMIB_TCPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize); + + apiReturn = gGetTcpTable(buf, &dwSize, FALSE); + ok(apiReturn == NO_ERROR, + "GetTcpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n", + apiReturn); + + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + DWORD i; + trace( "TCP table: %u entries\n", buf->dwNumEntries ); + for (i = 0; i < buf->dwNumEntries; i++) + { + char buffer[40]; + sprintf( buffer, "local %s:%u", + ntoa(buf->table[i].dwLocalAddr), ntohs(buf->table[i].dwLocalPort) ); + trace( "%u: %s remote %s:%u state %u\n", + i, buffer, ntoa( buf->table[i].dwRemoteAddr ), + ntohs(buf->table[i].dwRemotePort), buf->table[i].dwState ); + } + } + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +static void testGetUdpTable(void) +{ + if (gGetUdpTable) { + DWORD apiReturn; + ULONG dwSize = 0; + + apiReturn = gGetUdpTable(NULL, &dwSize, FALSE); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetUdpTable is not supported\n"); + return; + } + ok(apiReturn == ERROR_INSUFFICIENT_BUFFER, + "GetUdpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n", + apiReturn); + if (apiReturn == ERROR_INSUFFICIENT_BUFFER) { + PMIB_UDPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize); + + apiReturn = gGetUdpTable(buf, &dwSize, FALSE); + ok(apiReturn == NO_ERROR, + "GetUdpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n", + apiReturn); + + if (apiReturn == NO_ERROR && winetest_debug > 1) + { + DWORD i; + trace( "UDP table: %u entries\n", buf->dwNumEntries ); + for (i = 0; i < buf->dwNumEntries; i++) + trace( "%u: %s:%u\n", + i, ntoa( buf->table[i].dwLocalAddr ), ntohs(buf->table[i].dwLocalPort) ); + } + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +/* +still-to-be-tested NT4-onward functions: +CreateIpForwardEntry +DeleteIpForwardEntry +CreateIpNetEntry +DeleteIpNetEntry +GetFriendlyIfIndex +GetRTTAndHopCount +SetIfEntry +SetIpForwardEntry +SetIpNetEntry +SetIpStatistics +SetIpTTL +SetTcpEntry +*/ +static void testWinNT4Functions(void) +{ + testGetNumberOfInterfaces(); + testGetIpAddrTable(); + testGetIfTable(); + testGetIpForwardTable(); + testGetIpNetTable(); + testGetIcmpStatistics(); + testGetIpStatistics(); + testGetTcpStatistics(); + testGetUdpStatistics(); + testGetTcpTable(); + testGetUdpTable(); +} + +static void testGetInterfaceInfo(void) +{ + if (gGetInterfaceInfo) { + DWORD apiReturn; + ULONG len = 0; + + apiReturn = gGetInterfaceInfo(NULL, NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetInterfaceInfo is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetInterfaceInfo returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetInterfaceInfo(NULL, &len); + ok(apiReturn == ERROR_INSUFFICIENT_BUFFER, + "GetInterfaceInfo returned %d, expected ERROR_INSUFFICIENT_BUFFER\n", + apiReturn); + if (apiReturn == ERROR_INSUFFICIENT_BUFFER) { + PIP_INTERFACE_INFO buf = HeapAlloc(GetProcessHeap(), 0, len); + + apiReturn = gGetInterfaceInfo(buf, &len); + ok(apiReturn == NO_ERROR, + "GetInterfaceInfo(buf, &dwSize) returned %d, expected NO_ERROR\n", + apiReturn); + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +static void testGetAdaptersInfo(void) +{ + if (gGetAdaptersInfo) { + DWORD apiReturn; + ULONG len = 0; + + apiReturn = gGetAdaptersInfo(NULL, NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetAdaptersInfo is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetAdaptersInfo returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetAdaptersInfo(NULL, &len); + ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_BUFFER_OVERFLOW, + "GetAdaptersInfo returned %d, expected ERROR_NO_DATA or ERROR_BUFFER_OVERFLOW\n", + apiReturn); + if (apiReturn == ERROR_NO_DATA) + ; /* no adapter's, that's okay */ + else if (apiReturn == ERROR_BUFFER_OVERFLOW) { + PIP_ADAPTER_INFO buf = HeapAlloc(GetProcessHeap(), 0, len); + + apiReturn = gGetAdaptersInfo(buf, &len); + ok(apiReturn == NO_ERROR, + "GetAdaptersInfo(buf, &dwSize) returned %d, expected NO_ERROR\n", + apiReturn); + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +static void testGetNetworkParams(void) +{ + if (gGetNetworkParams) { + DWORD apiReturn; + ULONG len = 0; + + apiReturn = gGetNetworkParams(NULL, NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("GetNetworkParams is not supported\n"); + return; + } + ok(apiReturn == ERROR_INVALID_PARAMETER, + "GetNetworkParams returned %d, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + apiReturn = gGetNetworkParams(NULL, &len); + ok(apiReturn == ERROR_BUFFER_OVERFLOW, + "GetNetworkParams returned %d, expected ERROR_BUFFER_OVERFLOW\n", + apiReturn); + if (apiReturn == ERROR_BUFFER_OVERFLOW) { + PFIXED_INFO buf = HeapAlloc(GetProcessHeap(), 0, len); + + apiReturn = gGetNetworkParams(buf, &len); + ok(apiReturn == NO_ERROR, + "GetNetworkParams(buf, &dwSize) returned %d, expected NO_ERROR\n", + apiReturn); + HeapFree(GetProcessHeap(), 0, buf); + } + } +} + +/* +still-to-be-tested 98-onward functions: +GetBestInterface +GetBestRoute +IpReleaseAddress +IpRenewAddress +*/ +static void testWin98Functions(void) +{ + testGetInterfaceInfo(); + testGetAdaptersInfo(); + testGetNetworkParams(); +} + +static void testGetPerAdapterInfo(void) +{ + DWORD ret, needed; + void *buffer; + + if (!gGetPerAdapterInfo) return; + ret = gGetPerAdapterInfo(1, NULL, NULL); + if (ret == ERROR_NOT_SUPPORTED) { + skip("GetPerAdapterInfo is not supported\n"); + return; + } + ok( ret == ERROR_INVALID_PARAMETER, "got %u instead of ERROR_INVALID_PARAMETER\n", ret ); + needed = 0xdeadbeef; + ret = gGetPerAdapterInfo(1, NULL, &needed); + if (ret == ERROR_NO_DATA) return; /* no such adapter */ + ok( ret == ERROR_BUFFER_OVERFLOW, "got %u instead of ERROR_BUFFER_OVERFLOW\n", ret ); + ok( needed != 0xdeadbeef, "needed not set\n" ); + buffer = HeapAlloc( GetProcessHeap(), 0, needed ); + ret = gGetPerAdapterInfo(1, buffer, &needed); + ok( ret == NO_ERROR, "got %u instead of NO_ERROR\n", ret ); + HeapFree( GetProcessHeap(), 0, buffer ); +} + +/* +still-to-be-tested 2K-onward functions: +AddIPAddress +CreateProxyArpEntry +DeleteIPAddress +DeleteProxyArpEntry +EnableRouter +FlushIpNetTable +GetAdapterIndex +NotifyAddrChange +NotifyRouteChange +SendARP +UnenableRouter +*/ +static void testWin2KFunctions(void) +{ + testGetPerAdapterInfo(); +} + +static void test_GetAdaptersAddresses(void) +{ + ULONG ret, size; + IP_ADAPTER_ADDRESSES *aa; + IP_ADAPTER_UNICAST_ADDRESS *ua; + + if (!gGetAdaptersAddresses) + { + win_skip("GetAdaptersAddresses not present\n"); + return; + } + + ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", ret); + + ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size); + ok(ret == ERROR_BUFFER_OVERFLOW, "expected ERROR_BUFFER_OVERFLOW, got %u\n", ret); + if (ret != ERROR_BUFFER_OVERFLOW) return; + + aa = HeapAlloc(GetProcessHeap(), 0, size); + ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, aa, &size); + ok(!ret, "expected ERROR_SUCCESS got %u\n", ret); + + while (!ret && winetest_debug > 1 && aa) + { + trace("Length: %u\n", aa->Length); + trace("IfIndex: %u\n", aa->IfIndex); + trace("Next: %p\n", aa->Next); + trace("AdapterName: %s\n", aa->AdapterName); + trace("FirstUnicastAddress: %p\n", aa->FirstUnicastAddress); + ua = aa->FirstUnicastAddress; + while (ua) + { + trace("\tLength: %u\n", ua->Length); + trace("\tFlags: 0x%08x\n", ua->Flags); + trace("\tNext: %p\n", ua->Next); + trace("\tAddress.lpSockaddr: %p\n", ua->Address.lpSockaddr); + trace("\tAddress.iSockaddrLength: %d\n", ua->Address.iSockaddrLength); + trace("\tPrefixOrigin: %u\n", ua->PrefixOrigin); + trace("\tSuffixOrigin: %u\n", ua->SuffixOrigin); + trace("\tDadState: %u\n", ua->DadState); + trace("\tValidLifetime: 0x%08x\n", ua->ValidLifetime); + trace("\tPreferredLifetime: 0x%08x\n", ua->PreferredLifetime); + trace("\tLeaseLifetime: 0x%08x\n", ua->LeaseLifetime); + trace("\n"); + ua = ua->Next; + } + trace("FirstAnycastAddress: %p\n", aa->FirstAnycastAddress); + trace("FirstMulticastAddress: %p\n", aa->FirstMulticastAddress); + trace("FirstDnsServerAddress: %p\n", aa->FirstDnsServerAddress); + trace("DnsSuffix: %p\n", aa->DnsSuffix); + trace("Description: %p\n", aa->Description); + trace("FriendlyName: %p\n", aa->FriendlyName); + trace("PhysicalAddress: %02x\n", aa->PhysicalAddress[0]); + trace("PhysicalAddressLength: %u\n", aa->PhysicalAddressLength); + trace("Flags: 0x%08x\n", aa->Flags); + trace("Mtu: %u\n", aa->Mtu); + trace("IfType: %u\n", aa->IfType); + trace("OperStatus: %u\n", aa->OperStatus); + trace("\n"); + aa = aa->Next; + } + HeapFree(GetProcessHeap(), 0, aa); +} + +START_TEST(iphlpapi) +{ + + loadIPHlpApi(); + if (hLibrary) { + testWin98OnlyFunctions(); + testWinNT4Functions(); + testWin98Functions(); + testWin2KFunctions(); + test_GetAdaptersAddresses(); + freeIPHlpApi(); + } +} diff --git a/rostests/winetests/iphlpapi/iphlpapi.rbuild b/rostests/winetests/iphlpapi/iphlpapi.rbuild new file mode 100644 index 00000000000..ced63e68810 --- /dev/null +++ b/rostests/winetests/iphlpapi/iphlpapi.rbuild @@ -0,0 +1,12 @@ + + + + + . + + iphlpapi.c + testlist.c + wine + ntdll + + diff --git a/rostests/winetests/iphlpapi/testlist.c b/rostests/winetests/iphlpapi/testlist.c new file mode 100644 index 00000000000..4905dfc12a7 --- /dev/null +++ b/rostests/winetests/iphlpapi/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_iphlpapi(void); + +const struct test winetest_testlist[] = +{ + { "iphlpapi", func_iphlpapi }, + { 0, 0 } +}; diff --git a/rostests/winetests/itss/data.chm b/rostests/winetests/itss/data.chm new file mode 100644 index 00000000000..53b32804221 Binary files /dev/null and b/rostests/winetests/itss/data.chm differ diff --git a/rostests/winetests/itss/itss.rbuild b/rostests/winetests/itss/itss.rbuild new file mode 100644 index 00000000000..f143add644f --- /dev/null +++ b/rostests/winetests/itss/itss.rbuild @@ -0,0 +1,10 @@ + + . + + protocol.c + rsrc.rc + testlist.c + wine + ole32 + ntdll + diff --git a/rostests/winetests/itss/protocol.c b/rostests/winetests/itss/protocol.c new file mode 100644 index 00000000000..b52e3d32224 --- /dev/null +++ b/rostests/winetests/itss/protocol.c @@ -0,0 +1,690 @@ +/* + * Copyright 2006 Jacek Caban for CodeWeavers + * + * 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 + */ + +#define COBJMACROS + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "initguid.h" +#include "ole2.h" +#include "urlmon.h" +#include "shlwapi.h" + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + expect_ ## func = FALSE; \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define SET_CALLED(func) \ + expect_ ## func = called_ ## func = FALSE + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + SET_CALLED(func); \ + }while(0) + +DEFINE_GUID(CLSID_ITSProtocol,0x9d148291,0xb9c8,0x11d0,0xa4,0xcc,0x00,0x00,0xf8,0x01,0x49,0xf6); + +DEFINE_EXPECT(GetBindInfo); +DEFINE_EXPECT(ReportProgress_BEGINDOWNLOADDATA); +DEFINE_EXPECT(ReportProgress_SENDINGREQUEST); +DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE); +DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAIABLE); +DEFINE_EXPECT(ReportProgress_DIRECTBIND); +DEFINE_EXPECT(ReportData); +DEFINE_EXPECT(ReportResult); + +static HRESULT expect_hrResult; +static IInternetProtocol *read_protocol = NULL; +static DWORD bindf; + +static const WCHAR blank_url1[] = {'i','t','s',':', + 't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR blank_url2[] = {'m','S','-','i','T','s',':', + 't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR blank_url3[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':', + 't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR blank_url4[] = {'i','t','s',':', + 't','e','s','t','.','c','h','m',':',':','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR blank_url5[] = {'i','t','s',':', + 't','e','s','t','.','c','h','m',':',':','\\','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR blank_url6[] = {'i','t','s',':', + 't','e','s','t','.','c','h','m',':',':','/','%','6','2','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR blank_url7[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':', + 't','e','s','t','.','c','h','m',':',':','\\','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR blank_url8[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':', + 't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l','/',0}; + +static enum { + ITS_PROTOCOL, + MK_PROTOCOL +} test_protocol; + +static const WCHAR cache_file1[] = + {'t','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR cache_file2[] = + {'t','e','s','t','.','c','h','m',':',':','\\','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR cache_file3[] = + {'t','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l','/',0}; +static const WCHAR *cache_file = cache_file1; + +static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocolSink, riid)) { + *ppv = iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI ProtocolSink_AddRef(IInternetProtocolSink *iface) +{ + return 2; +} + +static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface) +{ + return 1; +} + +static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode, + LPCWSTR szStatusText) +{ + static const WCHAR blank_html[] = {'b','l','a','n','k','.','h','t','m','l',0}; + static const WCHAR text_html[] = {'t','e','x','t','/','h','t','m','l',0}; + + switch(ulStatusCode) { + case BINDSTATUS_BEGINDOWNLOADDATA: + CHECK_EXPECT(ReportProgress_BEGINDOWNLOADDATA); + ok(!szStatusText, "szStatusText != NULL\n"); + break; + case BINDSTATUS_SENDINGREQUEST: + CHECK_EXPECT(ReportProgress_SENDINGREQUEST); + if(test_protocol == ITS_PROTOCOL) + ok(!lstrcmpW(szStatusText, blank_html), "unexpected szStatusText\n"); + else + ok(szStatusText == NULL, "szStatusText != NULL\n"); + break; + case BINDSTATUS_MIMETYPEAVAILABLE: + CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + ok(!lstrcmpW(szStatusText, text_html), "unexpected szStatusText\n"); + break; + case BINDSTATUS_CACHEFILENAMEAVAILABLE: + CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAIABLE); + ok(!lstrcmpW(szStatusText, cache_file), "unexpected szStatusText\n"); + break; + case BINDSTATUS_DIRECTBIND: + CHECK_EXPECT(ReportProgress_DIRECTBIND); + ok(!szStatusText, "szStatusText != NULL\n"); + break; + default: + ok(0, "unexpected ulStatusCode %d\n", ulStatusCode); + break; + } + + return S_OK; +} + +static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF, ULONG ulProgress, + ULONG ulProgressMax) +{ + CHECK_EXPECT(ReportData); + + ok(ulProgress == ulProgressMax, "ulProgress != ulProgressMax\n"); + if(test_protocol == ITS_PROTOCOL) + ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE), "grcf = %08x\n", grfBSCF); + else + ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION), "grcf = %08x\n", grfBSCF); + + if(read_protocol) { + BYTE buf[100]; + DWORD cb = 0xdeadbeef; + HRESULT hres; + + hres = IInternetProtocol_Read(read_protocol, buf, sizeof(buf), &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + ok(cb == 13, "cb=%u expected 13\n", cb); + ok(!memcmp(buf, "", 13), "unexpected data\n"); + } + + return S_OK; +} + +static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult, + DWORD dwError, LPCWSTR szResult) +{ + CHECK_EXPECT(ReportResult); + + ok(hrResult == expect_hrResult, "expected: %08x got: %08x\n", expect_hrResult, hrResult); + ok(dwError == 0, "dwError = %d\n", dwError); + ok(!szResult, "szResult != NULL\n"); + + return S_OK; +} + +static IInternetProtocolSinkVtbl protocol_sink_vtbl = { + ProtocolSink_QueryInterface, + ProtocolSink_AddRef, + ProtocolSink_Release, + ProtocolSink_Switch, + ProtocolSink_ReportProgress, + ProtocolSink_ReportData, + ProtocolSink_ReportResult +}; + +static IInternetProtocolSink protocol_sink = { + &protocol_sink_vtbl +}; + +static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInfo, riid)) { + *ppv = iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface) +{ + return 2; +} + +static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface) +{ + return 1; +} + +static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) +{ + CHECK_EXPECT(GetBindInfo); + + ok(grfBINDF != NULL, "grfBINDF == NULL\n"); + if(grfBINDF) + ok(!*grfBINDF, "*grfBINDF != 0\n"); + ok(pbindinfo != NULL, "pbindinfo == NULL\n"); + ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo: %d\n", pbindinfo->cbSize); + + *grfBINDF = bindf; + return S_OK; +} + +static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulStringType, LPOLESTR *ppwzStr, + ULONG cEl, ULONG *pcElFetched) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IInternetBindInfoVtbl bind_info_vtbl = { + BindInfo_QueryInterface, + BindInfo_AddRef, + BindInfo_Release, + BindInfo_GetBindInfo, + BindInfo_GetBindString +}; + +static IInternetBindInfo bind_info = { + &bind_info_vtbl +}; + +static void test_protocol_fail(IInternetProtocol *protocol, LPCWSTR url, HRESULT expected_hres) +{ + HRESULT hres; + + SET_EXPECT(GetBindInfo); + SET_EXPECT(ReportResult); + + expect_hrResult = expected_hres; + hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0); + ok(hres == expected_hres, "expected: %08x got: %08x\n", expected_hres, hres); + + CHECK_CALLED(GetBindInfo); + CHECK_CALLED(ReportResult); +} + +#define protocol_start(p,u,e) _protocol_start(__LINE__,p,u,e) +static HRESULT _protocol_start(unsigned line, IInternetProtocol *protocol, LPCWSTR url, BOOL expect_mime) +{ + HRESULT hres; + + SET_EXPECT(GetBindInfo); + if(test_protocol == MK_PROTOCOL) + SET_EXPECT(ReportProgress_DIRECTBIND); + SET_EXPECT(ReportProgress_SENDINGREQUEST); + if(expect_mime) + SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + if(test_protocol == MK_PROTOCOL) + SET_EXPECT(ReportProgress_CACHEFILENAMEAVAIABLE); + SET_EXPECT(ReportData); + if(test_protocol == ITS_PROTOCOL) + SET_EXPECT(ReportProgress_BEGINDOWNLOADDATA); + SET_EXPECT(ReportResult); + expect_hrResult = S_OK; + + hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0); + + if(FAILED(hres)) { + SET_CALLED(GetBindInfo); + if(test_protocol == MK_PROTOCOL) + SET_CALLED(ReportProgress_DIRECTBIND); + SET_CALLED(ReportProgress_SENDINGREQUEST); + if(expect_mime) + SET_CALLED(ReportProgress_MIMETYPEAVAILABLE); + if(test_protocol == MK_PROTOCOL) + SET_EXPECT(ReportProgress_CACHEFILENAMEAVAIABLE); + SET_CALLED(ReportData); + if(test_protocol == ITS_PROTOCOL) + SET_CALLED(ReportProgress_BEGINDOWNLOADDATA); + SET_CALLED(ReportResult); + }else { + CHECK_CALLED(GetBindInfo); + if(test_protocol == MK_PROTOCOL) + SET_CALLED(ReportProgress_DIRECTBIND); + CHECK_CALLED(ReportProgress_SENDINGREQUEST); + if(expect_mime) + CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + if(test_protocol == MK_PROTOCOL) + SET_EXPECT(ReportProgress_CACHEFILENAMEAVAIABLE); + CHECK_CALLED(ReportData); + if(test_protocol == ITS_PROTOCOL) + CHECK_CALLED(ReportProgress_BEGINDOWNLOADDATA); + CHECK_CALLED(ReportResult); + } + + return hres; +} + +static void test_protocol_url(IClassFactory *factory, LPCWSTR url, BOOL expect_mime) +{ + IInternetProtocol *protocol; + BYTE buf[512]; + ULONG cb, ref; + HRESULT hres; + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = protocol_start(protocol, url, expect_mime); + if(FAILED(hres)) { + IInternetProtocol_Release(protocol); + return; + } + + hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + ok(cb == 13, "cb=%u expected 13\n", cb); + ok(!memcmp(buf, "", 13), "unexpected data\n"); + ref = IInternetProtocol_Release(protocol); + ok(!ref, "protocol ref=%d\n", ref); + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); + if(FAILED(hres)) + return; + + cb = 0xdeadbeef; + hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb); + ok(hres == (test_protocol == ITS_PROTOCOL ? INET_E_DATA_NOT_AVAILABLE : E_FAIL), + "Read returned %08x\n", hres); + ok(cb == 0xdeadbeef, "cb=%u expected 0xdeadbeef\n", cb); + + protocol_start(protocol, url, expect_mime); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + ok(cb == 2, "cb=%u expected 2\n", cb); + hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + ok(cb == 11, "cb=%u, expected 11\n", cb); + hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb); + ok(hres == S_FALSE, "Read failed: %08x expected S_FALSE\n", hres); + ok(cb == 0, "cb=%u expected 0\n", cb); + hres = IInternetProtocol_UnlockRequest(protocol); + ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); + ref = IInternetProtocol_Release(protocol); + ok(!ref, "protocol ref=%d\n", ref); + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); + if(FAILED(hres)) + return; + + protocol_start(protocol, url, expect_mime); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + hres = IInternetProtocol_LockRequest(protocol, 0); + ok(hres == S_OK, "LockRequest failed: %08x\n", hres); + hres = IInternetProtocol_UnlockRequest(protocol); + ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); + hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + ok(cb == 11, "cb=%u, expected 11\n", cb); + ref = IInternetProtocol_Release(protocol); + ok(!ref, "protocol ref=%d\n", ref); + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); + if(FAILED(hres)) + return; + + protocol_start(protocol, url, expect_mime); + hres = IInternetProtocol_LockRequest(protocol, 0); + ok(hres == S_OK, "LockRequest failed: %08x\n", hres); + hres = IInternetProtocol_Terminate(protocol, 0); + ok(hres == S_OK, "Terminate failed: %08x\n", hres); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + ok(cb == 2, "cb=%u, expected 2\n", cb); + hres = IInternetProtocol_UnlockRequest(protocol); + ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + ok(cb == 2, "cb=%u, expected 2\n", cb); + hres = IInternetProtocol_Terminate(protocol, 0); + ok(hres == S_OK, "Terminate failed: %08x\n", hres); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08x\n", hres); + ok(cb == 2, "cb=%u expected 2\n", cb); + ref = IInternetProtocol_Release(protocol); + ok(!ref, "protocol ref=%d\n", ref); + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&read_protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); + if(FAILED(hres)) + return; + + protocol_start(read_protocol, url, expect_mime); + ref = IInternetProtocol_Release(read_protocol); + ok(!ref, "protocol ref=%d\n", ref); + read_protocol = NULL; +} + +static const WCHAR rel_url1[] = + {'t','e','s','t','.','h','t','m','l',0}; +static const WCHAR rel_url2[] = + {'t','e','s','t','.','c','h','m',':',':','/','t','e','s','t','.','h','t','m','l',0}; +static const WCHAR rel_url3[] = + {'/','t','e','s','t','.','h','t','m','l',0}; +static const WCHAR rel_url4[] = + {'t','e',':','t','.','h','t','m','l',0}; +static const WCHAR rel_url5[] = + {'d','i','r','/','t','e','s','t','.','h','t','m','l',0}; + +static const WCHAR base_url1[] = {'i','t','s',':', + 't','e','s','t',':','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR base_url2[] = {'i','t','s',':','t','e','s','t','.','c','h','m', + ':',':','/','d','i','r','/','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR base_url3[] = {'m','s','-','i','t','s',':','t','e','s','t','.','c','h','m', + ':',':','/','d','i','r','/','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR base_url4[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':', + 't','e','s','t','.','c','h','m',':',':','/','d','i','r','/', + 'b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR base_url5[] = {'x','x','x',':','t','e','s','t','.','c','h','m', + ':',':','/','d','i','r','/','b','l','a','n','k','.','h','t','m','l',0}; + +static const WCHAR combined_url1[] = {'i','t','s',':', + 't','e','s','t','.','c','h','m',':',':','/','t','e','s','t','.','h','t','m','l',0}; +static const WCHAR combined_url2[] = {'i','t','s',':', + 't','e','s','t','.','c','h','m',':',':','/','d','i','r','/','t','e','s','t','.','h','t','m','l',0}; +static const WCHAR combined_url3[] = {'i','t','s',':', + 't','e','s','t',':','.','c','h','m',':',':','/','t','e','s','t','.','h','t','m','l',0}; +static const WCHAR combined_url4[] = {'i','t','s',':','t','e','s','t','.','c','h','m', + ':',':','b','l','a','n','k','.','h','t','m','l','t','e','s','t','.','h','t','m','l',0}; +static const WCHAR combined_url5[] = {'m','s','-','i','t','s',':', + 't','e','s','t','.','c','h','m',':',':','/','d','i','r','/','t','e','s','t','.','h','t','m','l',0}; +static const WCHAR combined_url6[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':', + 't','e','s','t','.','c','h','m',':',':','/','d','i','r','/','t','e','s','t','.','h','t','m','l',0}; + +static const struct { + LPCWSTR base_url; + LPCWSTR rel_url; + DWORD flags; + HRESULT hres; + LPCWSTR combined_url; +} combine_tests[] = { + {blank_url1, blank_url1, 0, STG_E_INVALIDNAME, NULL}, + {blank_url2, blank_url2, 0, STG_E_INVALIDNAME, NULL}, + {blank_url1, rel_url1, 0, S_OK, combined_url1}, + {blank_url1, rel_url2, 0, STG_E_INVALIDNAME, NULL}, + {blank_url1, rel_url3, 0, S_OK, combined_url1}, + {blank_url1, rel_url4, 0, STG_E_INVALIDNAME, NULL}, + {blank_url1, rel_url3, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO, S_OK, combined_url1}, + {blank_url1, rel_url5, 0, S_OK, combined_url2}, + {rel_url1, rel_url2, 0, 0x80041001, NULL}, + {base_url1, rel_url1, 0, S_OK, combined_url3}, + {base_url2, rel_url1, 0, S_OK, combined_url2}, + {blank_url4, rel_url1, 0, S_OK, combined_url4}, + {base_url3, rel_url1, 0, S_OK, combined_url5}, + {base_url4, rel_url1, 0, S_OK, combined_url6}, + {base_url5, rel_url1, 0, INET_E_USE_DEFAULT_PROTOCOLHANDLER, NULL}, + {base_url2, rel_url3, 0, S_OK, combined_url1}, +}; + +static void test_its_protocol_info(IInternetProtocol *protocol) +{ + IInternetProtocolInfo *info; + WCHAR buf[1024]; + DWORD size, i; + HRESULT hres; + + hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolInfo, (void**)&info); + ok(hres == S_OK, "Could not get IInternetProtocolInfo interface: %08x\n", hres); + if(FAILED(hres)) + return; + + for(i = PARSE_CANONICALIZE; i <= PARSE_UNESCAPE; i++) { + if(i != PARSE_CANONICALIZE && i != PARSE_SECURITY_URL) { + hres = IInternetProtocolInfo_ParseUrl(info, blank_url1, i, 0, buf, + sizeof(buf)/sizeof(buf[0]), &size, 0); + ok(hres == INET_E_DEFAULT_ACTION, + "[%d] failed: %08x, expected INET_E_DEFAULT_ACTION\n", i, hres); + } + } + + for(i=0; i < sizeof(combine_tests)/sizeof(combine_tests[0]); i++) { + size = 0xdeadbeef; + memset(buf, 0xfe, sizeof(buf)); + hres = IInternetProtocolInfo_CombineUrl(info, combine_tests[i].base_url, + combine_tests[i].rel_url, combine_tests[i].flags, buf, + sizeof(buf)/sizeof(WCHAR), &size, 0); + ok(hres == combine_tests[i].hres, "[%d] CombineUrl returned %08x, expected %08x\n", + i, hres, combine_tests[i].hres); + ok(size == (combine_tests[i].combined_url ? lstrlenW(combine_tests[i].combined_url)+1 + : 0xdeadbeef), "[%d] unexpected size=%d\n", i, size); + if(combine_tests[i].combined_url) + ok(!lstrcmpW(combine_tests[i].combined_url, buf), "[%d] unexpected result\n", i); + else + ok(buf[0] == 0xfefe, "buf changed\n"); + } + + size = 0xdeadbeef; + memset(buf, 0xfe, sizeof(buf)); + hres = IInternetProtocolInfo_CombineUrl(info, blank_url1, rel_url1, 0, buf, + 1, &size, 0); + ok(hres == E_OUTOFMEMORY, "CombineUrl failed: %08x\n", hres); + ok(size == sizeof(combined_url1)/sizeof(WCHAR), "size=%d\n", size); + ok(buf[0] == 0xfefe, "buf changed\n"); + + IInternetProtocolInfo_Release(info); +} + +static void test_its_protocol(void) +{ + IInternetProtocolInfo *info; + IClassFactory *factory; + IUnknown *unk; + ULONG ref; + HRESULT hres; + + static const WCHAR wrong_url1[] = + {'i','t','s',':','t','e','s','t','.','c','h','m',':',':','/','b','l','a','n','.','h','t','m','l',0}; + static const WCHAR wrong_url2[] = + {'i','t','s',':','t','e','s','.','c','h','m',':',':','b','/','l','a','n','k','.','h','t','m','l',0}; + static const WCHAR wrong_url3[] = + {'i','t','s',':','t','e','s','t','.','c','h','m','/','b','l','a','n','k','.','h','t','m','l',0}; + static const WCHAR wrong_url4[] = {'m','k',':','@','M','S','I','T','S','t','o','r',':', + 't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; + static const WCHAR wrong_url5[] = {'f','i','l','e',':', + 't','e','s','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; + + test_protocol = ITS_PROTOCOL; + + hres = CoGetClassObject(&CLSID_ITSProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK || + broken(hres == REGDB_E_CLASSNOTREG), /* Some W95 and NT4 */ + "CoGetClassObject failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&info); + ok(hres == E_NOINTERFACE, "Could not get IInternetProtocolInfo: %08x\n", hres); + + hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory); + ok(hres == S_OK, "Could not get IClassFactory interface\n"); + if(SUCCEEDED(hres)) { + IInternetProtocol *protocol; + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); + if(SUCCEEDED(hres)) { + test_its_protocol_info(protocol); + + test_protocol_fail(protocol, wrong_url1, STG_E_FILENOTFOUND); + test_protocol_fail(protocol, wrong_url2, STG_E_FILENOTFOUND); + test_protocol_fail(protocol, wrong_url3, STG_E_FILENOTFOUND); + + hres = IInternetProtocol_Start(protocol, wrong_url4, &protocol_sink, &bind_info, 0, 0); + ok(hres == INET_E_USE_DEFAULT_PROTOCOLHANDLER, + "Start failed: %08x, expected INET_E_USE_DEFAULT_PROTOCOLHANDLER\n", hres); + + hres = IInternetProtocol_Start(protocol, wrong_url5, &protocol_sink, &bind_info, 0, 0); + ok(hres == INET_E_USE_DEFAULT_PROTOCOLHANDLER, + "Start failed: %08x, expected INET_E_USE_DEFAULT_PROTOCOLHANDLER\n", hres); + + ref = IInternetProtocol_Release(protocol); + ok(!ref, "protocol ref=%d\n", ref); + + test_protocol_url(factory, blank_url1, TRUE); + test_protocol_url(factory, blank_url2, TRUE); + test_protocol_url(factory, blank_url3, TRUE); + test_protocol_url(factory, blank_url4, TRUE); + test_protocol_url(factory, blank_url5, TRUE); + test_protocol_url(factory, blank_url6, TRUE); + test_protocol_url(factory, blank_url8, TRUE); + bindf = BINDF_FROMURLMON | BINDF_NEEDFILE; + test_protocol_url(factory, blank_url1, TRUE); + } + + IClassFactory_Release(factory); + } + + IUnknown_Release(unk); +} + +static void test_mk_protocol(void) +{ + IClassFactory *cf; + HRESULT hres; + + test_protocol = MK_PROTOCOL; + + hres = CoGetClassObject(&CLSID_MkProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, + (void**)&cf); + ok(hres == S_OK || + broken(hres == REGDB_E_CLASSNOTREG), /* Some W95 and NT4 */ + "CoGetClassObject failed: %08x\n", hres); + if(FAILED(hres)) + return; + + cache_file = cache_file1; + test_protocol_url(cf, blank_url3, TRUE); + cache_file = cache_file2; + test_protocol_url(cf, blank_url7, TRUE); + cache_file = cache_file3; + test_protocol_url(cf, blank_url8, FALSE); + + IClassFactory_Release(cf); +} + +static BOOL create_chm(void) +{ + HANDLE file; + HRSRC src; + DWORD size; + + file = CreateFileA("test.chm", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "Could not create test.chm file\n"); + if(file == INVALID_HANDLE_VALUE) + return FALSE; + + src = FindResourceA(NULL, MAKEINTRESOURCEA(60), MAKEINTRESOURCEA(60)); + + WriteFile(file, LoadResource(NULL, src), SizeofResource(NULL, src), &size, NULL); + CloseHandle(file); + + return TRUE; +} + +static void delete_chm(void) +{ + BOOL ret; + + ret = DeleteFileA("test.chm"); + ok(ret, "DeleteFileA failed: %d\n", GetLastError()); +} + +START_TEST(protocol) +{ + OleInitialize(NULL); + + if(!create_chm()) + return; + + test_its_protocol(); + test_mk_protocol(); + + delete_chm(); + OleUninitialize(); +} diff --git a/rostests/winetests/itss/rsrc.rc b/rostests/winetests/itss/rsrc.rc new file mode 100644 index 00000000000..0e8eba03916 --- /dev/null +++ b/rostests/winetests/itss/rsrc.rc @@ -0,0 +1,33 @@ +/* + * Copyright 2006 Jacek Caban for CodeWeavers + * + * 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 + */ + +#include "winbase.h" +#include "windef.h" + +/* + * This is a simple .chm file compiled by hhc.exe from files: + * ----------------- test.hhp: + * [FILES] + * blank.html + * ----------------- blank.html: + * + * ----------------- + */ + +/* @makedep: data.chm */ +60 60 data.chm diff --git a/rostests/winetests/itss/testlist.c b/rostests/winetests/itss/testlist.c new file mode 100644 index 00000000000..8794b7ca517 --- /dev/null +++ b/rostests/winetests/itss/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_protocol(void); + +const struct test winetest_testlist[] = +{ + { "protocol", func_protocol }, + { 0, 0 } +}; diff --git a/rostests/winetests/jscript/api.js b/rostests/winetests/jscript/api.js new file mode 100644 index 00000000000..be85566f587 --- /dev/null +++ b/rostests/winetests/jscript/api.js @@ -0,0 +1,1944 @@ +/* + * Copyright 2008 Jacek Caban for CodeWeavers + * + * 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 + */ + +var tmp, i; + +i = parseInt("0"); +ok(i === 0, "parseInt('0') = " + i); +i = parseInt("123"); +ok(i === 123, "parseInt('123') = " + i); +i = parseInt("-123"); +ok(i === -123, "parseInt('-123') = " + i); +i = parseInt("0xff"); +ok(i === 0xff, "parseInt('0xff') = " + i); +i = parseInt("11", 8); +ok(i === 9, "parseInt('11', 8) = " + i); +i = parseInt("1j", 22); +ok(i === 41, "parseInt('1j', 32) = " + i); +i = parseInt("123", 0); +ok(i === 123, "parseInt('123', 0) = " + i); +i = parseInt("123", 10, "test"); +ok(i === 123, "parseInt('123', 10, 'test') = " + i); +i = parseInt("11", "8"); +ok(i === 9, "parseInt('11', '8') = " + i); + +tmp = encodeURI("abc"); +ok(tmp === "abc", "encodeURI('abc') = " + tmp); +tmp = encodeURI("{abc}"); +ok(tmp === "%7Babc%7D", "encodeURI('{abc}') = " + tmp); +tmp = encodeURI(""); +ok(tmp === "", "encodeURI('') = " + tmp); +tmp = encodeURI("\01\02\03\04"); +ok(tmp === "%01%02%03%04", "encodeURI('\\01\\02\\03\\04') = " + tmp); +tmp = encodeURI("{#@}"); +ok(tmp === "%7B#@%7D", "encodeURI('{#@}') = " + tmp); +tmp = encodeURI("\xa1 "); +ok(tmp === "%C2%A1%20", "encodeURI(\\xa1 ) = " + tmp); +tmp = encodeURI("\xffff"); +ok(tmp.length === 8, "encodeURI('\\xffff').length = " + tmp.length); +tmp = encodeURI("abcABC123;/?:@&=+$,-_.!~*'()"); +ok(tmp === "abcABC123;/?:@&=+$,-_.!~*'()", "encodeURI('abcABC123;/?:@&=+$,-_.!~*'()') = " + tmp); +tmp = encodeURI(); +ok(tmp === "undefined", "encodeURI() = " + tmp); +tmp = encodeURI("abc", "test"); +ok(tmp === "abc", "encodeURI('abc') = " + tmp); + +tmp = escape("abc"); +ok(tmp === "abc", "escape('abc') = " + tmp); +tmp = escape(""); +ok(tmp === "", "escape('') = " + tmp); +tmp = escape("a1b c!d+e@*-_+./,"); +ok(tmp === "a1b%20c%21d+e@*-_+./%2C", "escape('a1b c!d+e@*-_+./,') = " + tmp); +tmp = escape(); +ok(tmp === "undefined", "escape() = " + tmp); +tmp = escape('\u1234\123\xf3'); +ok(tmp == "%u1234S%F3", "escape('\u1234\123\xf3') = " + tmp); + +tmp = unescape("abc"); +ok(tmp === "abc", "unescape('abc') = " + tmp); +tmp = unescape(""); +ok(tmp === "", "unescape('') = " + tmp); +tmp = unescape("%%%"); +ok(tmp === "%%%", "unescape('%%%') = " + tmp); +tmp = unescape(); +ok(tmp === "undefined", "unescape() = " + tmp); +tmp = unescape("%54%65s%u0074"); +ok(tmp === "Test", "unescape('%54%65s%u0074') = " + tmp); + +tmp = "aA1~`!@#$%^&*()_+=-][{}';:/.,<>?\|"; +ok(escape(tmp) === "aA1%7E%60%21@%23%24%25%5E%26*%28%29_+%3D-%5D%5B%7B%7D%27%3B%3A/.%2C%3C%3E%3F%7C", "escape('" + tmp + "') = " + escape(tmp)); +ok(unescape(escape(tmp)) === tmp, "unescape(escape('" + tmp + "')) = " + unescape(escape(tmp))); + +tmp = "" + new Object(); +ok(tmp === "[object Object]", "'' + new Object() = " + tmp); +(tmp = new Array).f = Object.prototype.toString; +ok(tmp.f() === "[object Array]", "tmp.f() = " + tmp.f()); +(tmp = new Boolean).f = Object.prototype.toString; +ok(tmp.f() === "[object Boolean]", "tmp.f() = " + tmp.f()); +(tmp = new Date).f = Object.prototype.toString; +ok(tmp.f() === "[object Date]", "tmp.f() = " + tmp.f()); +(tmp = function() {}).f = Object.prototype.toString; +ok(tmp.f() === "[object Function]", "tmp.f() = " + tmp.f()); +Math.f = Object.prototype.toString; +ok(Math.f() === "[object Math]", "tmp.f() = " + tmp.f()); +(tmp = new Number).f = Object.prototype.toString; +ok(tmp.f() === "[object Number]", "tmp.f() = " + tmp.f()); +(tmp = new RegExp("")).f = Object.prototype.toString; +ok(tmp.f() === "[object RegExp]", "tmp.f() = " + tmp.f()); +(tmp = new String).f = Object.prototype.toString; +ok(tmp.f() === "[object String]", "tmp.f() = " + tmp.f()); +tmp = Object.prototype.toString.call(testObj); +ok(tmp === "[object Object]", "toString.call(testObj) = " + tmp); +tmp = Object.prototype.toString.call(this); +ok(tmp === "[object Object]", "toString.call(this) = " + tmp); +(function () { tmp = Object.prototype.toString.call(arguments); })(); +ok(tmp === "[object Object]", "toString.call(arguments) = " + tmp); + +ok(Object(1) instanceof Number, "Object(1) is not instance of Number"); +ok(Object("") instanceof String, "Object('') is not instance of String"); +ok(Object(false) instanceof Boolean, "Object(false) is not instance of Boolean"); + +obj = new Object(); +ok(Object(obj) === obj, "Object(obj) !== obj"); + +ok(typeof(Object()) === "object", "typeof(Object()) !== 'object'"); +ok(typeof(Object(undefined)) === "object", "typeof(Object(undefined)) !== 'object'"); +ok(typeof(Object(null)) === "object", "typeof(Object(null)) !== 'object'"); + +var obj = new Object(); +obj.toString = function (x) { + ok(arguments.length === 0, "arguments.length = " + arguments.length); + return "test"; +}; +ok((tmp = obj.toLocaleString()) === "test", "obj.toLocaleString() = " + tmp); +ok((tmp = obj.toLocaleString(1)) === "test", "obj.toLocaleString(1) = " + tmp); +ok(obj === obj.valueOf(), "obj !== obj.valueOf"); + +ok("".length === 0, "\"\".length = " + "".length); +ok(getVT("".length) == "VT_I4", "\"\".length = " + "".length); +ok("abc".length === 3, "\"abc\".length = " + "abc".length); +ok(String.prototype.length === 0, "String.prototype.length = " + String.prototype.length); + +tmp = "".toString(); +ok(tmp === "", "''.toString() = " + tmp); +tmp = "test".toString(); +ok(tmp === "test", "''.toString() = " + tmp); +tmp = "test".toString(3); +ok(tmp === "test", "''.toString(3) = " + tmp); + +tmp = "".valueOf(); +ok(tmp === "", "''.valueOf() = " + tmp); +tmp = "test".valueOf(); +ok(tmp === "test", "''.valueOf() = " + tmp); +tmp = "test".valueOf(3); +ok(tmp === "test", "''.valueOf(3) = " + tmp); + +var str = new String("test"); +ok(str.toString() === "test", "str.toString() = " + str.toString()); +var str = new String(); +ok(str.toString() === "", "str.toString() = " + str.toString()); +var str = new String("test", "abc"); +ok(str.toString() === "test", "str.toString() = " + str.toString()); + +var strObj = new Object(); +strObj.toString = function() { return "abcd" }; +strObj.substr = String.prototype.substr; +strObj.lastIndexOf = String.prototype.lastIndexOf; + +tmp = "value " + str; +ok(tmp === "value test", "'value ' + str = " + tmp); + +tmp = String(); +ok(tmp === "", "String() = " + tmp); +tmp = String(false); +ok(tmp === "false", "String(false) = " + tmp); +tmp = String(null); +ok(tmp === "null", "String(null) = " + tmp); +tmp = String("test"); +ok(tmp === "test", "String('test') = " + tmp); +tmp = String("test", "abc"); +ok(tmp === "test", "String('test','abc') = " + tmp); + +tmp = "abc".charAt(0); +ok(tmp === "a", "'abc',charAt(0) = " + tmp); +tmp = "abc".charAt(1); +ok(tmp === "b", "'abc',charAt(1) = " + tmp); +tmp = "abc".charAt(2); +ok(tmp === "c", "'abc',charAt(2) = " + tmp); +tmp = "abc".charAt(3); +ok(tmp === "", "'abc',charAt(3) = " + tmp); +tmp = "abc".charAt(4); +ok(tmp === "", "'abc',charAt(4) = " + tmp); +tmp = "abc".charAt(); +ok(tmp === "a", "'abc',charAt() = " + tmp); +tmp = "abc".charAt(-1); +ok(tmp === "", "'abc',charAt(-1) = " + tmp); +tmp = "abc".charAt(0,2); +ok(tmp === "a", "'abc',charAt(0.2) = " + tmp); + +tmp = "abc".charCodeAt(0); +ok(tmp === 0x61, "'abc'.charCodeAt(0) = " + tmp); +tmp = "abc".charCodeAt(1); +ok(tmp === 0x62, "'abc'.charCodeAt(1) = " + tmp); +tmp = "abc".charCodeAt(2); +ok(tmp === 0x63, "'abc'.charCodeAt(2) = " + tmp); +tmp = "abc".charCodeAt(); +ok(tmp === 0x61, "'abc'.charCodeAt() = " + tmp); +tmp = "abc".charCodeAt(true); +ok(tmp === 0x62, "'abc'.charCodeAt(true) = " + tmp); +tmp = "abc".charCodeAt(0,2); +ok(tmp === 0x61, "'abc'.charCodeAt(0,2) = " + tmp); +tmp = "\u49F4".charCodeAt(0); +ok(tmp === 0x49F4, "'\u49F4'.charCodeAt(0) = " + tmp); +tmp = "\052".charCodeAt(0); +ok(tmp === 0x2A, "'\052'.charCodeAt(0) = " + tmp); +tmp = "\xa2".charCodeAt(0); +ok(tmp === 0xA2, "'\xa2'.charCodeAt(0) = " + tmp); + +tmp = "abcd".substring(1,3); +ok(tmp === "bc", "'abcd'.substring(1,3) = " + tmp); +tmp = "abcd".substring(-1,3); +ok(tmp === "abc", "'abcd'.substring(-1,3) = " + tmp); +tmp = "abcd".substring(1,6); +ok(tmp === "bcd", "'abcd'.substring(1,6) = " + tmp); +tmp = "abcd".substring(3,1); +ok(tmp === "bc", "'abcd'.substring(3,1) = " + tmp); +tmp = "abcd".substring(2,2); +ok(tmp === "", "'abcd'.substring(2,2) = " + tmp); +tmp = "abcd".substring(true,"3"); +ok(tmp === "bc", "'abcd'.substring(true,'3') = " + tmp); +tmp = "abcd".substring(1,3,2); +ok(tmp === "bc", "'abcd'.substring(1,3,2) = " + tmp); +tmp = "abcd".substring(); +ok(tmp === "abcd", "'abcd'.substring() = " + tmp); + +tmp = "abcd".substr(1,3); +ok(tmp === "bcd", "'abcd'.substr(1,3) = " + tmp); +tmp = "abcd".substr(-1,3); +ok(tmp === "abc", "'abcd'.substr(-1,3) = " + tmp); +tmp = "abcd".substr(1,6); +ok(tmp === "bcd", "'abcd'.substr(1,6) = " + tmp); +tmp = "abcd".substr(2,-1); +ok(tmp === "", "'abcd'.substr(3,1) = " + tmp); +tmp = "abcd".substr(2,0); +ok(tmp === "", "'abcd'.substr(2,2) = " + tmp); +tmp = "abcd".substr(true,"3"); +ok(tmp === "bcd", "'abcd'.substr(true,'3') = " + tmp); +tmp = "abcd".substr(1,3,2); +ok(tmp === "bcd", "'abcd'.substr(1,3,2) = " + tmp); +tmp = "abcd".substr(); +ok(tmp === "abcd", "'abcd'.substr() = " + tmp); +tmp = strObj.substr(1,1); +ok(tmp === "b", "'abcd'.substr(1,3) = " + tmp); + +tmp = "abcd".slice(1,3); +ok(tmp === "bc", "'abcd'.slice(1,3) = " + tmp); +tmp = "abcd".slice(1,-1); +ok(tmp === "bc", "'abcd'.slice(1,-1) = " + tmp); +tmp = "abcd".slice(-3,3); +ok(tmp === "bc", "'abcd'.slice(-3,3) = " + tmp); +tmp = "abcd".slice(-6,3); +ok(tmp === "abc", "'abcd'.slice(-6,3) = " + tmp); +tmp = "abcd".slice(3,1); +ok(tmp === "", "'abcd'.slice(3,1) = " + tmp); +tmp = "abcd".slice(true,3); +ok(tmp === "bc", "'abcd'.slice(true,3) = " + tmp); +tmp = "abcd".slice(); +ok(tmp === "abcd", "'abcd'.slice() = " + tmp); +tmp = "abcd".slice(1); +ok(tmp === "bcd", "'abcd'.slice(1) = " + tmp); + +tmp = "abc".concat(["d",1],2,false); +ok(tmp === "abcd,12false", "concat returned " + tmp); +var arr = new Array(2,"a"); +arr.concat = String.prototype.concat; +tmp = arr.concat("d"); +ok(tmp === "2,ad", "arr.concat = " + tmp); + +m = "a+bcabc".match("a+"); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 1, "m.length is not 1"); +ok(m["0"] === "a", "m[0] is not \"ab\""); + +r = "- [test] -".replace("[test]", "success"); +ok(r === "- success -", "r = " + r + " expected '- success -'"); + +r = "- [test] -".replace("[test]", "success", "test"); +ok(r === "- success -", "r = " + r + " expected '- success -'"); + +r = "test".replace(); +ok(r === "test", "r = " + r + " expected 'test'"); + +function replaceFunc3(m, off, str) { + ok(arguments.length === 3, "arguments.length = " + arguments.length); + ok(m === "[test]", "m = " + m + " expected [test1]"); + ok(off === 1, "off = " + off + " expected 0"); + ok(str === "-[test]-", "str = " + arguments[3]); + return "ret"; +} + +r = "-[test]-".replace("[test]", replaceFunc3); +ok(r === "-ret-", "r = " + r + " expected '-ret-'"); + +r = "-[test]-".replace("[test]", replaceFunc3, "test"); +ok(r === "-ret-", "r = " + r + " expected '-ret-'"); + +r = "1,2,3".split(","); +ok(typeof(r) === "object", "typeof(r) = " + typeof(r)); +ok(r.length === 3, "r.length = " + r.length); +ok(r[0] === "1", "r[0] = " + r[0]); +ok(r[1] === "2", "r[1] = " + r[1]); +ok(r[2] === "3", "r[2] = " + r[2]); + + +r = "1,2,3".split(",*"); +ok(r.length === 1, "r.length = " + r.length); +ok(r[0] === "1,2,3", "r[0] = " + r[0]); + +r = "123".split(""); +ok(r.length === 3, "r.length = " + r.length); +ok(r[0] === "1", "r[0] = " + r[0]); +ok(r[1] === "2", "r[1] = " + r[1]); +ok(r[2] === "3", "r[2] = " + r[2]); + +r = "123".split(2); +ok(r.length === 2, "r.length = " + r.length); +ok(r[0] === "1", "r[0] = " + r[0]); +ok(r[1] === "3", "r[1] = " + r[1]); + +r = "1,2,".split(","); +ok(typeof(r) === "object", "typeof(r) = " + typeof(r)); +ok(r.length === 3, "r.length = " + r.length); +ok(r[0] === "1", "r[0] = " + r[0]); +ok(r[1] === "2", "r[1] = " + r[1]); +ok(r[2] === "", "r[2] = " + r[2]); + +tmp = "abcd".indexOf("bc",0); +ok(tmp === 1, "indexOf = " + tmp); +tmp = "abcd".indexOf("bc",1); +ok(tmp === 1, "indexOf = " + tmp); +tmp = "abcd".indexOf("bc"); +ok(tmp === 1, "indexOf = " + tmp); +tmp = "abcd".indexOf("ac"); +ok(tmp === -1, "indexOf = " + tmp); +tmp = "abcd".indexOf("bc",2); +ok(tmp === -1, "indexOf = " + tmp); +tmp = "abcd".indexOf("a",0); +ok(tmp === 0, "indexOf = " + tmp); +tmp = "abcd".indexOf("bc",0,"test"); +ok(tmp === 1, "indexOf = " + tmp); +tmp = "abcd".indexOf(); +ok(tmp == -1, "indexOf = " + tmp); + +tmp = "abcd".lastIndexOf("bc",1); +ok(tmp === 1, "lastIndexOf = " + tmp); +tmp = "abcd".lastIndexOf("bc",2); +ok(tmp === 1, "lastIndexOf = " + tmp); +tmp = "abcd".lastIndexOf("bc"); +ok(tmp === 1, "lastIndexOf = " + tmp); +tmp = "abcd".lastIndexOf("ac"); +ok(tmp === -1, "lastIndexOf = " + tmp); +tmp = "abcd".lastIndexOf("d",10); +ok(tmp === 3, "lastIndexOf = " + tmp); +tmp = "abcd".lastIndexOf("bc",0,"test"); +ok(tmp === -1, "lastIndexOf = " + tmp); +tmp = "abcd".lastIndexOf(); +ok(tmp === -1, "lastIndexOf = " + tmp); +tmp = "aaaa".lastIndexOf("a",2); +ok(tmp == 2, "lastIndexOf = " + tmp); +tmp = strObj.lastIndexOf("b"); +ok(tmp === 1, "lastIndexOf = " + tmp); + +tmp = "".toLowerCase(); +ok(tmp === "", "''.toLowerCase() = " + tmp); +tmp = "test".toLowerCase(); +ok(tmp === "test", "''.toLowerCase() = " + tmp); +tmp = "test".toLowerCase(3); +ok(tmp === "test", "''.toLowerCase(3) = " + tmp); +tmp = "tEsT".toLowerCase(); +ok(tmp === "test", "''.toLowerCase() = " + tmp); +tmp = "tEsT".toLowerCase(3); +ok(tmp === "test", "''.toLowerCase(3) = " + tmp); + +tmp = "".toUpperCase(); +ok(tmp === "", "''.toUpperCase() = " + tmp); +tmp = "TEST".toUpperCase(); +ok(tmp === "TEST", "''.toUpperCase() = " + tmp); +tmp = "TEST".toUpperCase(3); +ok(tmp === "TEST", "''.toUpperCase(3) = " + tmp); +tmp = "tEsT".toUpperCase(); +ok(tmp === "TEST", "''.toUpperCase() = " + tmp); +tmp = "tEsT".toUpperCase(3); +ok(tmp === "TEST", "''.toUpperCase(3) = " + tmp); + +tmp = "".anchor(); +ok(tmp === "", "''.anchor() = " + tmp); +tmp = "".anchor(3); +ok(tmp === "", "''.anchor(3) = " + tmp); +tmp = "".anchor("red"); +ok(tmp === "", "''.anchor('red') = " + tmp); +tmp = "test".anchor(); +ok(tmp === "test", "'test'.anchor() = " + tmp); +tmp = "test".anchor(3); +ok(tmp === "test", "'test'.anchor(3) = " + tmp); +tmp = "test".anchor("green"); +ok(tmp === "test", "'test'.anchor('green') = " + tmp); + +tmp = "".big(); +ok(tmp === "", "''.big() = " + tmp); +tmp = "".big(3); +ok(tmp === "", "''.big(3) = " + tmp); +tmp = "test".big(); +ok(tmp === "test", "'test'.big() = " + tmp); +tmp = "test".big(3); +ok(tmp === "test", "'test'.big(3) = " + tmp); + +tmp = "".blink(); +ok(tmp === "", "''.blink() = " + tmp); +tmp = "".blink(3); +ok(tmp === "", "''.blink(3) = " + tmp); +tmp = "test".blink(); +ok(tmp === "test", "'test'.blink() = " + tmp); +tmp = "test".blink(3); +ok(tmp === "test", "'test'.blink(3) = " + tmp); + +tmp = "".bold(); +ok(tmp === "", "''.bold() = " + tmp); +tmp = "".bold(3); +ok(tmp === "", "''.bold(3) = " + tmp); +tmp = "test".bold(); +ok(tmp === "test", "'test'.bold() = " + tmp); +tmp = "test".bold(3); +ok(tmp === "test", "'test'.bold(3) = " + tmp); + +tmp = "".fixed(); +ok(tmp === "", "''.fixed() = " + tmp); +tmp = "".fixed(3); +ok(tmp === "", "''.fixed(3) = " + tmp); +tmp = "test".fixed(); +ok(tmp === "test", "'test'.fixed() = " + tmp); +tmp = "test".fixed(3); +ok(tmp === "test", "'test'.fixed(3) = " + tmp); + +tmp = "".fontcolor(); +ok(tmp === "", "''.fontcolor() = " + tmp); +tmp = "".fontcolor(3); +ok(tmp === "", "''.fontcolor(3) = " + tmp); +tmp = "".fontcolor("red"); +ok(tmp === "", "''.fontcolor('red') = " + tmp); +tmp = "test".fontcolor(); +ok(tmp === "test", "'test'.fontcolor() = " + tmp); +tmp = "test".fontcolor(3); +ok(tmp === "test", "'test'.fontcolor(3) = " + tmp); +tmp = "test".fontcolor("green"); +ok(tmp === "test", "'test'.fontcolor('green') = " + tmp); + +tmp = "".fontsize(); +ok(tmp === "", "''.fontsize() = " + tmp); +tmp = "".fontsize(3); +ok(tmp === "", "''.fontsize(3) = " + tmp); +tmp = "".fontsize("red"); +ok(tmp === "", "''.fontsize('red') = " + tmp); +tmp = "test".fontsize(); +ok(tmp === "test", "'test'.fontsize() = " + tmp); +tmp = "test".fontsize(3); +ok(tmp === "test", "'test'.fontsize(3) = " + tmp); +tmp = "test".fontsize("green"); +ok(tmp === "test", "'test'.fontsize('green') = " + tmp); + +tmp = ("".fontcolor()).fontsize(); +ok(tmp === "", "(''.fontcolor()).fontsize() = " + tmp); + +tmp = "".italics(); +ok(tmp === "", "''.italics() = " + tmp); +tmp = "".italics(3); +ok(tmp === "", "''.italics(3) = " + tmp); +tmp = "test".italics(); +ok(tmp === "test", "'test'.italics() = " + tmp); +tmp = "test".italics(3); +ok(tmp === "test", "'test'.italics(3) = " + tmp); + +tmp = "".link(); +ok(tmp === "", "''.link() = " + tmp); +tmp = "".link(3); +ok(tmp === "", "''.link(3) = " + tmp); +tmp = "".link("red"); +ok(tmp === "", "''.link('red') = " + tmp); +tmp = "test".link(); +ok(tmp === "test", "'test'.link() = " + tmp); +tmp = "test".link(3); +ok(tmp === "test", "'test'.link(3) = " + tmp); +tmp = "test".link("green"); +ok(tmp === "test", "'test'.link('green') = " + tmp); + +tmp = "".small(); +ok(tmp === "", "''.small() = " + tmp); +tmp = "".small(3); +ok(tmp === "", "''.small(3) = " + tmp); +tmp = "test".small(); +ok(tmp === "test", "'test'.small() = " + tmp); +tmp = "test".small(3); +ok(tmp === "test", "'test'.small(3) = " + tmp); + +tmp = "".strike(); +ok(tmp === "", "''.strike() = " + tmp); +tmp = "".strike(3); +ok(tmp === "", "''.strike(3) = " + tmp); +tmp = "test".strike(); +ok(tmp === "test", "'test'.strike() = " + tmp); +tmp = "test".strike(3); +ok(tmp === "test", "'test'.strike(3) = " + tmp); + +tmp = "".sub(); +ok(tmp === "", "''.sub() = " + tmp); +tmp = "".sub(3); +ok(tmp === "", "''.sub(3) = " + tmp); +tmp = "test".sub(); +ok(tmp === "test", "'test'.sub() = " + tmp); +tmp = "test".sub(3); +ok(tmp === "test", "'test'.sub(3) = " + tmp); + +tmp = "".sup(); +ok(tmp === "", "''.sup() = " + tmp); +tmp = "".sup(3); +ok(tmp === "", "''.sup(3) = " + tmp); +tmp = "test".sup(); +ok(tmp === "test", "'test'.sup() = " + tmp); +tmp = "test".sup(3); +ok(tmp === "test", "'test'.sup(3) = " + tmp); + +ok(String.fromCharCode() === "", "String.fromCharCode() = " + String.fromCharCode()); +ok(String.fromCharCode(65,"66",67) === "ABC", "String.fromCharCode(65,'66',67) = " + String.fromCharCode(65,"66",67)); +ok(String.fromCharCode(1024*64+65, -1024*64+65) === "AA", + "String.fromCharCode(1024*64+65, -1024*64+65) = " + String.fromCharCode(1024*64+65, -1024*64+65)); +ok(String.fromCharCode(65, NaN, undefined).length === 3, + "String.fromCharCode(65, NaN, undefined).length = " + String.fromCharCode(65, NaN, undefined).length); + +var arr = new Array(); +ok(typeof(arr) === "object", "arr () is not object"); +ok((arr.length === 0), "arr.length is not 0"); +ok(arr["0"] === undefined, "arr[0] is not undefined"); + +var arr = new Array(1, 2, "test"); +ok(typeof(arr) === "object", "arr (1,2,test) is not object"); +ok((arr.length === 3), "arr.length is not 3"); +ok(arr["0"] === 1, "arr[0] is not 1"); +ok(arr["1"] === 2, "arr[1] is not 2"); +ok(arr["2"] === "test", "arr[2] is not \"test\""); + +arr["7"] = true; +ok((arr.length === 8), "arr.length is not 8"); + +tmp = "" + []; +ok(tmp === "", "'' + [] = " + tmp); +tmp = "" + [1,true]; +ok(tmp === "1,true", "'' + [1,true] = " + tmp); + +var arr = new Array(6); +ok(typeof(arr) === "object", "arr (6) is not object"); +ok((arr.length === 6), "arr.length is not 6"); +ok(arr["0"] === undefined, "arr[0] is not undefined"); + +ok(arr.push() === 6, "arr.push() !== 6"); +ok(arr.push(1) === 7, "arr.push(1) !== 7"); +ok(arr[6] === 1, "arr[6] != 1"); +ok(arr.length === 7, "arr.length != 10"); +ok(arr.push(true, 'b', false) === 10, "arr.push(true, 'b', false) !== 10"); +ok(arr[8] === "b", "arr[8] != 'b'"); +ok(arr.length === 10, "arr.length != 10"); + +var arr = new Object(); +arr.push = Array.prototype.push; + +arr.length = 6; + +ok(arr.push() === 6, "arr.push() !== 6"); +ok(arr.push(1) === 7, "arr.push(1) !== 7"); +ok(arr[6] === 1, "arr[6] != 1"); +ok(arr.length === 7, "arr.length != 10"); +ok(arr.push(true, 'b', false) === 10, "arr.push(true, 'b', false) !== 10"); +ok(arr[8] === "b", "arr[8] != 'b'"); +ok(arr.length === 10, "arr.length != 10"); + +arr = [3,4,5]; +tmp = arr.pop(); +ok(arr.length === 2, "arr.length = " + arr.length); +ok(tmp === 5, "pop() = " + tmp); +tmp = arr.pop(2); +ok(arr.length === 1, "arr.length = " + arr.length); +ok(tmp === 4, "pop() = " + tmp); +tmp = arr.pop(); +ok(arr.length === 0, "arr.length = " + arr.length); +ok(tmp === 3, "pop() = " + tmp); +for(tmp in arr) + ok(false, "not deleted " + tmp); +tmp = arr.pop(); +ok(arr.length === 0, "arr.length = " + arr.length); +ok(tmp === undefined, "tmp = " + tmp); +arr = [,,,,,]; +tmp = arr.pop(); +ok(arr.length === 5, "arr.length = " + arr.length); +ok(tmp === undefined, "tmp = " + tmp); + +arr = [1,2,null,false,undefined,,"a"]; + +tmp = arr.join(); +ok(tmp === "1,2,,false,,,a", "arr.join() = " + tmp); +tmp = arr.join(";"); +ok(tmp === "1;2;;false;;;a", "arr.join(';') = " + tmp); +tmp = arr.join(";","test"); +ok(tmp === "1;2;;false;;;a", "arr.join(';') = " + tmp); +tmp = arr.join(""); +ok(tmp === "12falsea", "arr.join('') = " + tmp); + +tmp = arr.toString(); +ok(tmp === "1,2,,false,,,a", "arr.toString() = " + tmp); +tmp = arr.toString("test"); +ok(tmp === "1,2,,false,,,a", "arr.toString() = " + tmp); + +arr = [5,true,2,-1,3,false,"2.5"]; +tmp = arr.sort(function(x,y) { return y-x; }); +ok(tmp === arr, "tmp !== arr"); +tmp = [5,3,"2.5",2,true,false,-1]; +for(var i=0; i < arr.length; i++) + ok(arr[i] === tmp[i], "arr[" + i + "] = " + arr[i] + " expected " + tmp[i]); + +arr = [5,false,2,0,"abc",3,"a",-1]; +tmp = arr.sort(); +ok(tmp === arr, "tmp !== arr"); +tmp = [-1,0,2,3,5,"a","abc",false]; +for(var i=0; i < arr.length; i++) + ok(arr[i] === tmp[i], "arr[" + i + "] = " + arr[i] + " expected " + tmp[i]); + +arr = ["a", "b", "ab"]; +tmp = ["a", "ab", "b"]; +ok(arr.sort() === arr, "arr.sort() !== arr"); +for(var i=0; i < arr.length; i++) + ok(arr[i] === tmp[i], "arr[" + i + "] = " + arr[i] + " expected " + tmp[i]); + +arr = ["1", "2", "3"]; +arr.length = 1; +ok(arr.length === 1, "arr.length = " + arr.length); +arr.length = 3; +ok(arr.length === 3, "arr.length = " + arr.length); +ok(arr.toString() === "1,,", "arr.toString() = " + arr.toString()); + +arr = Array("a","b","c"); +ok(arr.toString() === "a,b,c", "arr.toString() = " + arr.toString()); + +ok(arr.valueOf === Object.prototype.valueOf, "arr.valueOf !== Object.prototype.valueOf"); +ok(arr === arr.valueOf(), "arr !== arr.valueOf"); + +arr = [1,2,3]; +tmp = arr.unshift(0); +ok(tmp === undefined, "[1,2,3].unshift(0) returned " +tmp); +ok(arr.length === 4, "arr.length = " + arr.length); +ok(arr.toString() === "0,1,2,3", "arr.toString() = " + arr.toString()); + +arr = new Array(3); +arr[0] = 1; +arr[2] = 3; +tmp = arr.unshift(-1,0); +ok(tmp === undefined, "unshift returned " +tmp); +ok(arr.length === 5, "arr.length = " + arr.length); +ok(arr.toString() === "-1,0,1,,3", "arr.toString() = " + arr.toString()); + +arr = [1,2,3]; +tmp = arr.unshift(); +ok(tmp === undefined, "unshift returned " +tmp); +ok(arr.length === 3, "arr.length = " + arr.length); +ok(arr.toString() === "1,2,3", "arr.toString() = " + arr.toString()); + +arr = new Object(); +arr.length = 2; +arr[0] = 1; +arr[1] = 2; +tmp = Array.prototype.unshift.call(arr, 0); +ok(tmp === undefined, "unshift returned " +tmp); +ok(arr.length === 3, "arr.length = " + arr.length); +ok(arr[0] === 0 && arr[1] === 1 && arr[2] === 2, "unexpected array"); + +arr = [1,2,,4]; +tmp = arr.shift(); +ok(tmp === 1, "[1,2,,4].shift() = " + tmp); +ok(arr.toString() === "2,,4", "arr = " + arr.toString()); + +arr = []; +tmp = arr.shift(); +ok(tmp === undefined, "[].shift() = " + tmp); +ok(arr.toString() === "", "arr = " + arr.toString()); + +arr = [1,2,,4]; +tmp = arr.shift(2); +ok(tmp === 1, "[1,2,,4].shift(2) = " + tmp); +ok(arr.toString() === "2,,4", "arr = " + arr.toString()); + +arr = [1,]; +tmp = arr.shift(); +ok(tmp === 1, "[1,].shift() = " + tmp); +ok(arr.toString() === "", "arr = " + arr.toString()); + +obj = new Object(); +obj[0] = "test"; +obj[2] = 3; +obj.length = 3; +tmp = Array.prototype.shift.call(obj); +ok(tmp === "test", "obj.shift() = " + tmp); +ok(obj.length == 2, "obj.length = " + obj.length); +ok(obj[1] === 3, "obj[1] = " + obj[1]); + +var num = new Number(6); +arr = [0,1,2]; +tmp = arr.concat(3, [4,5], num); +ok(tmp !== arr, "tmp === arr"); +for(var i=0; i<6; i++) + ok(tmp[i] === i, "tmp[" + i + "] = " + tmp[i]); +ok(tmp[6] === num, "tmp[6] !== num"); +ok(tmp.length === 7, "tmp.length = " + tmp.length); + +arr = [].concat(); +ok(arr.length === 0, "arr.length = " + arr.length); + +arr = [1,]; +tmp = arr.concat([2]); +ok(tmp.length === 3, "tmp.length = " + tmp.length); +ok(tmp[1] === undefined, "tmp[1] = " + tmp[1]); + +arr = [1,false,'a',null,undefined,'a']; +ok(arr.slice(0,6).toString() === "1,false,a,,,a", "arr.slice(0,6).toString() = " + arr.slice(0,6)); +ok(arr.slice(0,6).length === 6, "arr.slice(0,6).length = " + arr.slice(0,6).length); +ok(arr.slice().toString() === "1,false,a,,,a", "arr.slice().toString() = " + arr.slice()); +ok(arr.slice("abc").toString() === "1,false,a,,,a", "arr.slice(\"abc\").toString() = " + arr.slice("abc")); +ok(arr.slice(3,8).toString() === ",,a", "arr.slice(3,8).toString() = " + arr.slice(3,8)); +ok(arr.slice(3,8).length === 3, "arr.slice(3,8).length = " + arr.slice(3,8).length); +ok(arr.slice(1).toString() === "false,a,,,a", "arr.slice(1).toString() = " + arr.slice(1)); +ok(arr.slice(-2).toString() === ",a", "arr.slice(-2).toString() = " + arr.slice(-2)); +ok(arr.slice(3,1).toString() === "", "arr.slice(3,1).toString() = " + arr.slice(3,1)); +tmp = arr.slice(0,6); +for(var i=0; i < arr.length; i++) + ok(arr[i] === tmp[i], "arr[" + i + "] = " + arr[i] + " expected " + tmp[i]); +arr[12] = 2; +ok(arr.slice(5).toString() === "a,,,,,,,2", "arr.slice(5).toString() = " + arr.slice(5).toString()); +ok(arr.slice(5).length === 8, "arr.slice(5).length = " + arr.slice(5).length); + +arr = [1,2,3,4,5]; +tmp = arr.splice(2,2); +ok(tmp.toString() == "3,4", "arr.splice(2,2) returned " + tmp.toString()); +ok(arr.toString() == "1,2,5", "arr.splice(2,2) is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(2,2,"a"); +ok(tmp.toString() == "3,4", "arr.splice(2,2,'a') returned " + tmp.toString()); +ok(arr.toString() == "1,2,a,5", "arr.splice(2,2,'a') is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(2,2,'a','b','c'); +ok(tmp.toString() == "3,4", "arr.splice(2,2,'a','b','c') returned " + tmp.toString()); +ok(arr.toString() == "1,2,a,b,c,5", "arr.splice(2,2,'a','b','c') is " + arr.toString()); + +arr = [1,2,3,4,]; +tmp = arr.splice(2,2,'a','b','c'); +ok(tmp.toString() == "3,4", "arr.splice(2,2,'a','b','c') returned " + tmp.toString()); +ok(arr.toString() == "1,2,a,b,c,", "arr.splice(2,2,'a','b','c') is " + arr.toString()); + +arr = [1,2,3,4,]; +arr.splice(2,2,'a','b','c'); +ok(arr.toString() == "1,2,a,b,c,", "arr.splice(2,2,'a','b','c') is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(2,2,'a','b'); +ok(tmp.toString() == "3,4", "arr.splice(2,2,'a','b') returned " + tmp.toString()); +ok(arr.toString() == "1,2,a,b,5", "arr.splice(2,2,'a','b') is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(-1,2); +ok(tmp.toString() == "5", "arr.splice(-1,2) returned " + tmp.toString()); +ok(arr.toString() == "1,2,3,4", "arr.splice(-1,2) is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(-10,3); +ok(tmp.toString() == "1,2,3", "arr.splice(-10,3) returned " + tmp.toString()); +ok(arr.toString() == "4,5", "arr.splice(-10,3) is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(-10,100); +ok(tmp.toString() == "1,2,3,4,5", "arr.splice(-10,100) returned " + tmp.toString()); +ok(arr.toString() == "", "arr.splice(-10,100) is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(2,-1); +ok(tmp.toString() == "", "arr.splice(2,-1) returned " + tmp.toString()); +ok(arr.toString() == "1,2,3,4,5", "arr.splice(2,-1) is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(2); +ok(tmp.toString() == "", "arr.splice(2,-1) returned " + tmp.toString()); +ok(arr.toString() == "1,2,3,4,5", "arr.splice(2,-1) is " + arr.toString()); + +arr = [1,2,3,4,5]; +tmp = arr.splice(); +ok(tmp.toString() == "", "arr.splice(2,-1) returned " + tmp.toString()); +ok(arr.toString() == "1,2,3,4,5", "arr.splice(2,-1) is " + arr.toString()); + +obj = new Object(); +obj.length = 3; +obj[0] = 1; +obj[1] = 2; +obj[2] = 3; +tmp = Array.prototype.splice.call(obj, 1, 1, 'a', 'b'); +ok(tmp.toString() === "2", "obj.splice returned " + tmp); +ok(obj.length === 4, "obj.length = " + obj.length); +ok(obj[0] === 1, "obj[0] = " + obj[0]); +ok(obj[1] === 'a', "obj[1] = " + obj[1]); +ok(obj[2] === 'b', "obj[2] = " + obj[2]); +ok(obj[3] === 3, "obj[3] = " + obj[3]); + +obj = new Object(); +obj.length = 3; +obj[0] = 1; +obj[1] = 2; +obj[2] = 3; +tmp = Array.prototype.slice.call(obj, 1, 2); +ok(tmp.length === 1, "tmp.length = " + tmp.length); +ok(tmp[0] === 2, "tmp[0] = " + tmp[0]); + +var num = new Number(2); +ok(num.toString() === "2", "num(2).toString !== 2"); +var num = new Number(); +ok(num.toString() === "0", "num().toString !== 0"); + +ok(Number() === 0, "Number() = " + Number()); +ok(Number(false) === 0, "Number(false) = " + Number(false)); +ok(Number("43") === 43, "Number('43') = " + Number("43")); + +tmp = (new Number(1)).valueOf(); +ok(tmp === 1, "(new Number(1)).valueOf = " + tmp); +tmp = (new Number(1,2)).valueOf(); +ok(tmp === 1, "(new Number(1,2)).valueOf = " + tmp); +tmp = (new Number()).valueOf(); +ok(tmp === 0, "(new Number()).valueOf = " + tmp); +tmp = Number.prototype.valueOf(); +ok(tmp === 0, "Number.prototype.valueOf = " + tmp); + +function equals(val, base) { + var i; + var num = 0; + var str = val.toString(base); + + for(i=0; ival-val/1000 && num +#include +#include +#include +#include + +#include "wine/test.h" + +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + +static const CLSID CLSID_JScript = + {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}}; + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define SET_CALLED(func) \ + called_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(GetLCID); +DEFINE_EXPECT(OnStateChange_STARTED); +DEFINE_EXPECT(OnStateChange_CONNECTED); +DEFINE_EXPECT(OnStateChange_DISCONNECTED); +DEFINE_EXPECT(OnStateChange_CLOSED); +DEFINE_EXPECT(OnStateChange_INITIALIZED); +DEFINE_EXPECT(OnEnterScript); +DEFINE_EXPECT(OnLeaveScript); + +static BSTR a2bstr(const char *str) +{ + BSTR ret; + int len; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = SysAllocStringLen(NULL, len-1); + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + + return ret; +} + +#define test_state(s,ss) _test_state(__LINE__,s,ss) +static void _test_state(unsigned line, IActiveScript *script, SCRIPTSTATE exstate) +{ + SCRIPTSTATE state = -1; + HRESULT hres; + + hres = IActiveScript_GetScriptState(script, &state); + ok_(__FILE__,line) (hres == S_OK, "GetScriptState failed: %08x\n", hres); + ok_(__FILE__,line) (state == exstate, "state=%d, expected %d\n", state, exstate); +} + +static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid)) + *ppv = iface; + else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) + *ppv = iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface) +{ + return 2; +} + +static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface) +{ + return 1; +} + +static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid) +{ + CHECK_EXPECT(GetLCID); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName, + DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface, + const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState) +{ + switch(ssScriptState) { + case SCRIPTSTATE_STARTED: + CHECK_EXPECT(OnStateChange_STARTED); + return S_OK; + case SCRIPTSTATE_CONNECTED: + CHECK_EXPECT(OnStateChange_CONNECTED); + return S_OK; + case SCRIPTSTATE_DISCONNECTED: + CHECK_EXPECT(OnStateChange_DISCONNECTED); + return S_OK; + case SCRIPTSTATE_CLOSED: + CHECK_EXPECT(OnStateChange_CLOSED); + return S_OK; + case SCRIPTSTATE_INITIALIZED: + CHECK_EXPECT(OnStateChange_INITIALIZED); + return S_OK; + default: + ok(0, "unexpected call %d\n", ssScriptState); + } + + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface) +{ + CHECK_EXPECT(OnEnterScript); + return S_OK; +} + +static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface) +{ + CHECK_EXPECT(OnLeaveScript); + return S_OK; +} + +#undef ACTSCPSITE_THIS + +static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = { + ActiveScriptSite_QueryInterface, + ActiveScriptSite_AddRef, + ActiveScriptSite_Release, + ActiveScriptSite_GetLCID, + ActiveScriptSite_GetItemInfo, + ActiveScriptSite_GetDocVersionString, + ActiveScriptSite_OnScriptTerminate, + ActiveScriptSite_OnStateChange, + ActiveScriptSite_OnScriptError, + ActiveScriptSite_OnEnterScript, + ActiveScriptSite_OnLeaveScript +}; + +static IActiveScriptSite ActiveScriptSite = { &ActiveScriptSiteVtbl }; + +static void test_script_dispatch(IActiveScript *script, BOOL initialized) +{ + IDispatchEx *dispex; + IDispatch *disp; + BSTR str; + DISPID id; + HRESULT hres; + + disp = (void*)0xdeadbeef; + hres = IActiveScript_GetScriptDispatch(script, NULL, &disp); + if(!initialized) { + ok(hres == E_UNEXPECTED, "hres = %08x, expected E_UNEXPECTED\n", hres); + ok(!disp, "disp != NULL\n"); + return; + } + + ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres); + if(FAILED(hres)) + return; + + ok(disp != NULL, "disp == NULL\n"); + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + IDispatch_Release(disp); + ok(hres == S_OK, "Could not get IDispatchEx interface: %08x\n", hres); + + str = a2bstr("ActiveXObject"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &id); + SysFreeString(str); + ok(hres == S_OK, "GetDispID failed: %08x\n", hres); + + IDispatchEx_Release(dispex); +} + +static void test_safety(IUnknown *unk) +{ + IObjectSafety *safety; + DWORD supported, enabled; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IObjectSafety, (void**)&safety); + ok(hres == S_OK, "Could not get IObjectSafety: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_NULL, &supported, NULL); + ok(hres == E_POINTER, "GetInterfaceSafetyOptions failed: %08x, expected E_POINTER\n", hres); + hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_NULL, NULL, &enabled); + ok(hres == E_POINTER, "GetInterfaceSafetyOptions failed: %08x, expected E_POINTER\n", hres); + + supported = enabled = 0xdeadbeef; + hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_NULL, &supported, &enabled); + ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres); + ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER), + "supported=%x\n", supported); + ok(enabled == INTERFACE_USES_DISPEX, "enabled=%x\n", enabled); + + supported = enabled = 0xdeadbeef; + hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScript, &supported, &enabled); + ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres); + ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER), + "supported=%x\n", supported); + ok(enabled == INTERFACE_USES_DISPEX, "enabled=%x\n", enabled); + + supported = enabled = 0xdeadbeef; + hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported, &enabled); + ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres); + ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER), + "supported=%x\n", supported); + ok(enabled == INTERFACE_USES_DISPEX, "enabled=%x\n", enabled); + + hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, + INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER + |INTERFACESAFE_FOR_UNTRUSTED_CALLER, + INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER); + ok(hres == E_FAIL, "SetInterfaceSafetyOptions failed: %08x, expected E_FAIL\n", hres); + + hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, + INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER, + INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER); + ok(hres == S_OK, "SetInterfaceSafetyOptions failed: %08x\n", hres); + + supported = enabled = 0xdeadbeef; + hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported, &enabled); + ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres); + ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER), + "supported=%x\n", supported); + ok(enabled == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER), + "enabled=%x\n", enabled); + + IObjectSafety_Release(safety); +} + +static void test_jscript(void) +{ + IActiveScriptParse *parse; + IActiveScript *script; + IUnknown *unk; + ULONG ref; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_JScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IActiveScript, (void**)&script); + ok(hres == S_OK, "Could not get IActiveScript: %08x\n", hres); + + hres = IUnknown_QueryInterface(unk, &IID_IActiveScriptParse, (void**)&parse); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres); + if (FAILED(hres)) + { + IActiveScript_Release(script); + return; + } + + test_state(script, SCRIPTSTATE_UNINITIALIZED); + test_safety(unk); + + hres = IActiveScriptParse64_InitNew(parse); + ok(hres == S_OK, "InitNew failed: %08x\n", hres); + + hres = IActiveScriptParse64_InitNew(parse); + ok(hres == E_UNEXPECTED, "InitNew failed: %08x, expected E_UNEXPECTED\n", hres); + + hres = IActiveScript_SetScriptSite(script, NULL); + ok(hres == E_POINTER, "SetScriptSite failed: %08x, expected E_POINTER\n", hres); + + test_state(script, SCRIPTSTATE_UNINITIALIZED); + test_script_dispatch(script, FALSE); + + SET_EXPECT(GetLCID); + SET_EXPECT(OnStateChange_INITIALIZED); + hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite); + ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres); + CHECK_CALLED(GetLCID); + CHECK_CALLED(OnStateChange_INITIALIZED); + + test_state(script, SCRIPTSTATE_INITIALIZED); + + hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite); + ok(hres == E_UNEXPECTED, "SetScriptSite failed: %08x, expected E_UNEXPECTED\n", hres); + + test_script_dispatch(script, TRUE); + + SET_EXPECT(OnStateChange_STARTED); + hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres); + CHECK_CALLED(OnStateChange_STARTED); + + test_state(script, SCRIPTSTATE_STARTED); + + SET_EXPECT(OnStateChange_CLOSED); + hres = IActiveScript_Close(script); + ok(hres == S_OK, "Close failed: %08x\n", hres); + CHECK_CALLED(OnStateChange_CLOSED); + + test_state(script, SCRIPTSTATE_CLOSED); + test_script_dispatch(script, FALSE); + + IUnknown_Release(parse); + IActiveScript_Release(script); + + ref = IUnknown_Release(unk); + ok(!ref, "ref = %d\n", ref); +} + +static void test_jscript2(void) +{ + IActiveScriptParse *parse; + IActiveScript *script; + IUnknown *unk; + ULONG ref; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_JScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IActiveScript, (void**)&script); + ok(hres == S_OK, "Could not get IActiveScript: %08x\n", hres); + + hres = IUnknown_QueryInterface(unk, &IID_IActiveScriptParse, (void**)&parse); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres); + if (FAILED(hres)) + { + IActiveScript_Release(script); + return; + } + + test_state(script, SCRIPTSTATE_UNINITIALIZED); + + SET_EXPECT(GetLCID); + hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite); + ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres); + CHECK_CALLED(GetLCID); + + test_state(script, SCRIPTSTATE_UNINITIALIZED); + + SET_EXPECT(OnStateChange_INITIALIZED); + hres = IActiveScriptParse64_InitNew(parse); + ok(hres == S_OK, "InitNew failed: %08x\n", hres); + CHECK_CALLED(OnStateChange_INITIALIZED); + + hres = IActiveScriptParse64_InitNew(parse); + ok(hres == E_UNEXPECTED, "InitNew failed: %08x, expected E_UNEXPECTED\n", hres); + + SET_EXPECT(OnStateChange_CONNECTED); + hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hres); + CHECK_CALLED(OnStateChange_CONNECTED); + + test_state(script, SCRIPTSTATE_CONNECTED); + + SET_EXPECT(OnStateChange_DISCONNECTED); + SET_EXPECT(OnStateChange_INITIALIZED); + SET_EXPECT(OnStateChange_CLOSED); + hres = IActiveScript_Close(script); + ok(hres == S_OK, "Close failed: %08x\n", hres); + CHECK_CALLED(OnStateChange_DISCONNECTED); + CHECK_CALLED(OnStateChange_INITIALIZED); + CHECK_CALLED(OnStateChange_CLOSED); + + test_state(script, SCRIPTSTATE_CLOSED); + test_script_dispatch(script, FALSE); + + IUnknown_Release(parse); + IActiveScript_Release(script); + + ref = IUnknown_Release(unk); + ok(!ref, "ref = %d\n", ref); +} + +START_TEST(jscript) +{ + CoInitialize(NULL); + + test_jscript(); + test_jscript2(); + + CoUninitialize(); +} diff --git a/rostests/winetests/jscript/jscript.rbuild b/rostests/winetests/jscript/jscript.rbuild new file mode 100644 index 00000000000..e679b74c6fd --- /dev/null +++ b/rostests/winetests/jscript/jscript.rbuild @@ -0,0 +1,16 @@ + + + + + . + + jscript.c + run.c + testlist.c + rsrc.rc + wine + ole32 + oleaut32 + ntdll + + diff --git a/rostests/winetests/jscript/lang.js b/rostests/winetests/jscript/lang.js new file mode 100644 index 00000000000..353dcd7c73c --- /dev/null +++ b/rostests/winetests/jscript/lang.js @@ -0,0 +1,972 @@ +/* + * Copyright 2008 Jacek Caban for CodeWeavers + * + * 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 + */ + +var tmp; + +ok(true, "true is not true?"); +ok(!false, "!false is not true"); +ok(!undefined, "!undefined is not true"); +ok(!null, "!null is not true"); +ok(!0, "!0 is not true"); +ok(!0.0, "!0.0 is not true"); + +ok(1 === 1, "1 === 1 is false"); +ok(!(1 === 2), "!(1 === 2) is false"); +ok(1.0 === 1, "1.0 === 1 is false"); +ok("abc" === "abc", "\"abc\" === \"abc\" is false"); +ok(true === true, "true === true is false"); +ok(null === null, "null === null is false"); +ok(undefined === undefined, "undefined === undefined is false"); +ok(!(undefined === null), "!(undefined === null) is false"); +ok(1E0 === 1, "1E0 === 1 is false"); +ok(1000000*1000000 === 1000000000000, "1000000*1000000 === 1000000000000 is false"); +ok(8.64e15 === 8640000000000000, "8.64e15 !== 8640000000000000"); +ok(1e2147483648 === Infinity, "1e2147483648 !== Infinity"); + +ok(1 !== 2, "1 !== 2 is false"); +ok(null !== undefined, "null !== undefined is false"); + +ok(1 == 1, "1 == 1 is false"); +ok(!(1 == 2), "!(1 == 2) is false"); +ok(1.0 == 1, "1.0 == 1 is false"); +ok("abc" == "abc", "\"abc\" == \"abc\" is false"); +ok(true == true, "true == true is false"); +ok(null == null, "null == null is false"); +ok(undefined == undefined, "undefined == undefined is false"); +ok(undefined == null, "undefined == null is false"); +ok(true == 1, "true == 1 is false"); +ok(!(true == 2), "true == 2"); +ok(0 == false, "0 == false is false"); + +ok(1 != 2, "1 != 2 is false"); +ok(false != 1, "false != 1 is false"); + +var trueVar = true; +ok(trueVar, "trueVar is not true"); + +ok(ScriptEngine.length === 0, "ScriptEngine.length is not 0"); + +function testFunc1(x, y) { + ok(this !== undefined, "this is undefined"); + ok(x === true, "x is not true"); + ok(y === "test", "y is not \"test\""); + ok(arguments.length === 2, "arguments.length is not 2"); + ok(arguments["0"] === true, "arguments[0] is not true"); + ok(arguments["1"] === "test", "arguments[1] is not \"test\""); + ok(arguments.callee === testFunc1, "arguments.calee !== testFunc1"); + + return true; +} + +ok(testFunc1.length === 2, "testFunc1.length is not 2"); + +ok(Object.prototype !== undefined, "Object.prototype is undefined"); +ok(Object.prototype.prototype === undefined, "Object.prototype is not undefined"); +ok(String.prototype !== undefined, "String.prototype is undefined"); +ok(Array.prototype !== undefined, "Array.prototype is undefined"); +ok(Boolean.prototype !== undefined, "Boolean.prototype is undefined"); +ok(Number.prototype !== undefined, "Number.prototype is undefined"); +ok(RegExp.prototype !== undefined, "RegExp.prototype is undefined"); +ok(Math !== undefined, "Math is undefined"); +ok(Math.prototype === undefined, "Math.prototype is not undefined"); +ok(Function.prototype !== undefined, "Function.prototype is undefined"); +ok(Function.prototype.prototype === undefined, "Function.prototype.prototype is not undefined"); +ok(Date.prototype !== undefined, "Date.prototype is undefined"); +ok(Date.prototype.prototype === undefined, "Date.prototype is not undefined"); + +Function.prototype.test = true; +ok(testFunc1.test === true, "testFunc1.test !== true"); +ok(Function.test === true, "Function.test !== true"); + +ok(typeof(0) === "number", "typeof(0) is not number"); +ok(typeof(1.5) === "number", "typeof(1.5) is not number"); +ok(typeof("abc") === "string", "typeof(\"abc\") is not string"); +ok(typeof("") === "string", "typeof(\"\") is not string"); +ok(typeof(true) === "boolean", "typeof(true) is not boolean"); +ok(typeof(null) === "object", "typeof(null) is not object"); +ok(typeof(undefined) === "undefined", "typeof(undefined) is not undefined"); +ok(typeof(Math) === "object", "typeof(Math) is not object"); +ok(typeof(String.prototype) === "object", "typeof(String.prototype) is not object"); +ok(typeof(testFunc1) === "function", "typeof(testFunc1) is not function"); +ok(typeof(String) === "function", "typeof(String) is not function"); +ok(typeof(ScriptEngine) === "function", "typeof(ScriptEngine) is not function"); +ok(typeof(this) === "object", "typeof(this) is not object"); + +ok(testFunc1(true, "test") === true, "testFunc1 not returned true"); + +var obj1 = new Object(); +ok(typeof(obj1) === "object", "typeof(obj1) is not object"); +obj1.test = true; +obj1.func = function () { + ok(this === obj1, "this is not obj1"); + ok(this.test === true, "this.test is not true"); + ok(arguments.length === 1, "arguments.length is not 1"); + ok(arguments["0"] === true, "arguments[0] is not true"); + ok(typeof(arguments.callee) === "function", "typeof(arguments.calee) = " + typeof(arguments.calee)); + + return "test"; +}; + +ok(obj1.func(true) === "test", "obj1.func(true) is not \"test\""); + +function testConstr1() { + this.var1 = 1; + + ok(this !== undefined, "this is undefined"); + ok(arguments.length === 1, "arguments.length is not 1"); + ok(arguments["0"] === true, "arguments[0] is not 1"); + ok(arguments.callee === testConstr1, "arguments.calee !== testConstr1"); + + return false; +} + +testConstr1.prototype.pvar = 1; + +var obj2 = new testConstr1(true); +ok(typeof(obj2) === "object", "typeof(obj2) is not object"); +ok(obj2.pvar === 1, "obj2.pvar is not 1"); + +testConstr1.prototype.pvar = 2; +ok(obj2.pvar === 2, "obj2.pvar is not 2"); + +obj2.pvar = 3; +testConstr1.prototype.pvar = 1; +ok(obj2.pvar === 3, "obj2.pvar is not 3"); + +var obj3 = new Object; +ok(typeof(obj3) === "object", "typeof(obj3) is not object"); + +for(var iter in "test") + ok(false, "unexpected forin call, test = " + iter); + +for(var iter in null) + ok(false, "unexpected forin call, test = " + iter); + +for(var iter in false) + ok(false, "unexpected forin call, test = " + iter); + +tmp = 0; +if(true) + tmp = 1; +else + ok(false, "else evaluated"); +ok(tmp === 1, "tmp !== 1, if not evaluated?"); + +tmp = 0; +if(1 === 0) + ok(false, "if evaluated"); +else + tmp = 1; +ok(tmp === 1, "tmp !== 1, if not evaluated?"); + +if(false) + ok(false, "if(false) evaluated"); + +tmp = 0; +if(true) + tmp = 1; +ok(tmp === 1, "tmp !== 1, if(true) not evaluated?"); + +if(false) { +}else { +} + +var obj3 = { prop1: 1, prop2: typeof(false) }; +ok(obj3.prop1 === 1, "obj3.prop1 is not 1"); +ok(obj3.prop2 === "boolean", "obj3.prop2 is not \"boolean\""); + +{ + var blockVar = 1; + blockVar = 2; +} +ok(blockVar === 2, "blockVar !== 2"); + +ok((true ? 1 : 2) === 1, "conditional expression true is not 1"); +ok((0 === 2 ? 1 : 2) === 2, "conditional expression true is not 2"); + +ok(getVT(undefined) === "VT_EMPTY", "getVT(undefined) is not VT_EMPTY"); +ok(getVT(null) === "VT_NULL", "getVT(null) is not VT_NULL"); +ok(getVT(0) === "VT_I4", "getVT(0) is not VT_I4"); +ok(getVT(0.5) === "VT_R8", "getVT(1.5) is not VT_R8"); +ok(getVT("test") === "VT_BSTR", "getVT(\"test\") is not VT_BSTR"); +ok(getVT(Math) === "VT_DISPATCH", "getVT(Math) is not VT_DISPATCH"); +ok(getVT(false) === "VT_BOOL", "getVT(false) is not VT_BOOL"); + +tmp = 2+2; +ok(tmp === 4, "2+2 !== 4"); +ok(getVT(tmp) === "VT_I4", "getVT(2+2) !== VT_I4"); + +tmp = 2+2.5; +ok(tmp === 4.5, "2+2.5 !== 4.5"); +ok(getVT(tmp) === "VT_R8", "getVT(2+2.5) !== VT_R8"); + +tmp = 1.5+2.5; +ok(tmp === 4, "1.4+2.5 !== 4"); +ok(getVT(tmp) === "VT_I4", "getVT(1.5+2.5) !== VT_I4"); + +tmp = 4-2; +ok(tmp === 2, "4-2 !== 2"); +ok(getVT(tmp) === "VT_I4", "getVT(4-2) !== VT_I4"); + +tmp = 4.5-2; +ok(tmp === 2.5, "4.5-2 !== 2.5"); +ok(getVT(tmp) === "VT_R8", "getVT(4-2) !== VT_R8"); + +tmp = -2; +ok(tmp === 0-2, "-2 !== 0-2"); +ok(getVT(tmp) === "VT_I4", "getVT(-2) !== VT_I4"); + +tmp = 2*3; +ok(tmp === 6, "2*3 !== 6"); +ok(getVT(tmp) === "VT_I4", "getVT(2*3) !== VT_I4"); + +tmp = 2*3.5; +ok(tmp === 7, "2*3.5 !== 7"); +ok(getVT(tmp) === "VT_I4", "getVT(2*3.5) !== VT_I4"); + +tmp = 2.5*3.5; +ok(tmp === 8.75, "2.5*3.5 !== 8.75"); +ok(getVT(tmp) === "VT_R8", "getVT(2.5*3.5) !== VT_R8"); + +tmp = 4/2; +ok(tmp === 2, "4/2 !== 2"); +ok(getVT(tmp) === "VT_I4", "getVT(4/2) !== VT_I4"); + +tmp = 4.5/1.5; +ok(tmp === 3, "4.5/1.5 !== 3"); +ok(getVT(tmp) === "VT_I4", "getVT(4.5/1.5) !== VT_I4"); + +tmp = 3/2; +ok(tmp === 1.5, "3/2 !== 1.5"); +ok(getVT(tmp) === "VT_R8", "getVT(3/2) !== VT_R8"); + +tmp = 3%2; +ok(tmp === 1, "3%2 = " + tmp); + +tmp = 4%2; +ok(tmp ===0, "4%2 = " + tmp); + +tmp = 3.5%1.5; +ok(tmp === 0.5, "3.5%1.5 = " + tmp); + +tmp = 3%true; +ok(tmp === 0, "3%true = " + tmp); + +tmp = "ab" + "cd"; +ok(tmp === "abcd", "\"ab\" + \"cd\" !== \"abcd\""); + +tmp = 1; +ok((tmp += 1) === 2, "tmp += 1 !== 2"); +ok(tmp === 2, "tmp !== 2"); + +tmp = 2; +ok((tmp -= 1) === 1, "tmp -= 1 !== 1"); +ok(tmp === 1, "tmp !=== 1"); + +tmp = 2; +ok((tmp *= 1.5) === 3, "tmp *= 1.5 !== 3"); +ok(tmp === 3, "tmp !=== 3"); + +tmp = 5; +ok((tmp /= 2) === 2.5, "tmp /= 2 !== 2.5"); +ok(tmp === 2.5, "tmp !=== 2.5"); + +tmp = 3; +ok((tmp %= 2) === 1, "tmp %= 2 !== 1"); +ok(tmp === 1, "tmp !== 1"); + +tmp = 8; +ok((tmp <<= 1) === 16, "tmp <<= 1 !== 16"); + +tmp = 8; +ok((tmp >>= 1) === 4, "tmp >>= 1 !== 4"); + +tmp = 8; +ok((tmp >>>= 1) === 4, "tmp >>>= 1 !== 4"); + +tmp = 3 || ok(false, "second or expression called"); +ok(tmp === 3, "3 || (...) is not 3"); + +tmp = false || 2; +ok(tmp === 2, "false || 2 is not 2"); + +tmp = 0 && ok(false, "second and expression called"); +ok(tmp === 0, "0 && (...) is not 0"); + +tmp = true && "test"; +ok(tmp === "test", "true && \"test\" is not \"test\""); + +tmp = true && 0; +ok(tmp === 0, "true && 0 is not 0"); + +tmp = 3 | 4; +ok(tmp === 7, "3 | 4 !== 7"); +ok(getVT(tmp) === "VT_I4", "getVT(3|4) = " + getVT(tmp)); + +tmp = 3.5 | 0; +ok(tmp === 3, "3.5 | 0 !== 3"); +ok(getVT(tmp) === "VT_I4", "getVT(3.5|0) = " + getVT(tmp)); + +tmp = -3.5 | 0; +ok(tmp === -3, "-3.5 | 0 !== -3"); +ok(getVT(tmp) === "VT_I4", "getVT(3.5|0) = " + getVT(tmp)); + +tmp = 10; +ok((tmp |= 0x10) === 26, "tmp(10) |= 0x10 !== 26"); +ok(getVT(tmp) === "VT_I4", "getVT(tmp |= 10) = " + getVT(tmp)); + +tmp = 3 & 5; +ok(tmp === 1, "3 & 5 !== 1"); +ok(getVT(tmp) === "VT_I4", "getVT(3|5) = " + getVT(tmp)); + +tmp = 3.5 & 0xffff; +ok(tmp === 3, "3.5 & 0xffff !== 3 "); +ok(getVT(tmp) === "VT_I4", "getVT(3.5&0xffff) = " + getVT(tmp)); + +tmp = (-3.5) & 0xffffffff; +ok(tmp === -3, "-3.5 & 0xffff !== -3"); +ok(getVT(tmp) === "VT_I4", "getVT(3.5&0xffff) = " + getVT(tmp)); + +tmp = 2 << 3; +ok(tmp === 16, "2 << 3 = " + tmp); + +tmp = 2 << 35; +ok(tmp === 16, "2 << 35 = " + tmp); + +tmp = 8 >> 2; +ok(tmp === 2, "8 >> 2 = " + tmp); + +tmp = -64 >> 4; +ok(tmp === -4, "-64 >> 4 = " + tmp); + +tmp = 8 >>> 2; +ok(tmp === 2, "8 >> 2 = " + tmp); + +tmp = -64 >>> 4; +ok(tmp === 0x0ffffffc, "-64 >>> 4 = " + tmp); + +tmp = 10; +ok((tmp &= 8) === 8, "tmp(10) &= 8 !== 8"); +ok(getVT(tmp) === "VT_I4", "getVT(tmp &= 8) = " + getVT(tmp)); + +tmp = 0xf0f0^0xff00; +ok(tmp === 0x0ff0, "0xf0f0^0xff00 !== 0x0ff0"); +ok(getVT(tmp) === "VT_I4", "getVT(0xf0f0^0xff00) = " + getVT(tmp)); + +tmp = 5; +ok((tmp ^= 3) === 6, "tmp(5) ^= 3 !== 6"); +ok(getVT(tmp) === "VT_I4", "getVT(tmp ^= 3) = " + getVT(tmp)); + +tmp = ~1; +ok(tmp === -2, "~1 !== -2"); +ok(getVT(tmp) === "VT_I4", "getVT(~1) = " + getVT(tmp)); + +ok((3,4) === 4, "(3,4) !== 4"); + +ok(+3 === 3, "+3 !== 3"); +ok(+true === 1, "+true !== 1"); +ok(+false === 0, "+false !== 0"); +ok(+null === 0, "+null !== 0"); +ok(+"0" === 0, "+'0' !== 0"); +ok(+"3" === 3, "+'3' !== 3"); +ok(+"-3" === -3, "+'-3' !== -3"); +ok(+"0xff" === 255, "+'0xff' !== 255"); +ok(+"3e3" === 3000, "+'3e3' !== 3000"); + +tmp = new Number(1); +ok(+tmp === 1, "+(new Number(1)) = " + (+tmp)); +tmp = new String("1"); +ok(+tmp === 1, "+(new String('1')) = " + (+tmp)); + +ok("" + 0 === "0", "\"\" + 0 !== \"0\""); +ok("" + 123 === "123", "\"\" + 123 !== \"123\""); +ok("" + (-5) === "-5", "\"\" + (-5) !== \"-5\""); +ok("" + null === "null", "\"\" + null !== \"null\""); +ok("" + undefined === "undefined", "\"\" + undefined !== \"undefined\""); +ok("" + true === "true", "\"\" + true !== \"true\""); +ok("" + false === "false", "\"\" + false !== \"false\""); +ok("" + 0.5 === "0.5", "'' + 0.5 = " + 0.5); +ok("" + (-0.5432) === "-0.5432", "'' + (-0.5432) = " + (-0.5432)); + +ok(1 < 3.4, "1 < 3.4 failed"); +ok(!(3.4 < 1), "3.4 < 1"); +ok("abc" < "abcd", "abc < abcd failed"); +ok("abcd" < "abce", "abce < abce failed"); +ok("" < "x", "\"\" < \"x\" failed"); +ok(!(0 < 0), "0 < 0"); + +ok(1 <= 3.4, "1 <= 3.4 failed"); +ok(!(3.4 <= 1), "3.4 <= 1"); +ok("abc" <= "abcd", "abc <= abcd failed"); +ok("abcd" <= "abce", "abce <= abce failed"); +ok("" <= "x", "\"\" <= \"x\" failed"); +ok(0 <= 0, "0 <= 0 failed"); + +ok(3.4 > 1, "3.4 > 1 failed"); +ok(!(1 > 3.4), "1 > 3.4"); +ok("abcd" > "abc", "abc > abcd failed"); +ok("abce" > "abcd", "abce > abce failed"); +ok("x" > "", "\"x\" > \"\" failed"); +ok(!(0 > 0), "0 > 0"); + +ok(3.4 >= 1, "3.4 >= 1 failed"); +ok(!(1 >= 3.4), "1 >= 3.4"); +ok("abcd" >= "abc", "abc >= abcd failed"); +ok("abce" >= "abcd", "abce >= abce failed"); +ok("x" >= "", "\"x\" >= \"\" failed"); +ok(0 >= 0, "0 >= 0"); + +tmp = 1; +ok(++tmp === 2, "++tmp (1) is not 2"); +ok(tmp === 2, "incremented tmp is not 2"); +ok(--tmp === 1, "--tmp (2) is not 1"); +ok(tmp === 1, "decremented tmp is not 1"); +ok(tmp++ === 1, "tmp++ (1) is not 1"); +ok(tmp === 2, "incremented tmp(1) is not 2"); +ok(tmp-- === 2, "tmp-- (2) is not 2"); +ok(tmp === 1, "decremented tmp is not 1"); + +String.prototype.test = true; +ok("".test === true, "\"\".test is not true"); + +Boolean.prototype.test = true; +ok(true.test === true, "true.test is not true"); + +Number.prototype.test = true; +ok((0).test === true, "(0).test is not true"); +ok((0.5).test === true, "(0.5).test is not true"); + +var state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; +}catch(ex) { + ok(false, "unexpected catch"); +} +ok(state === "try", "state = " + state + " expected try"); + +state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; +}finally { + ok(state === "try", "finally: state = " + state); + state = "finally"; +} +ok(state === "finally", "state = " + state + " expected finally"); + +state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; +}catch(ex) { + ok(false, "unexpected catch"); +}finally { + ok(state === "try", "finally: state = " + state); + state = "finally"; +} +ok(state === "finally", "state = " + state + " expected finally"); + +var state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; + throw "except"; +}catch(ex) { + ok(state === "try", "catch: state = " + state); + ok(ex === "except", "ex is not \"except\""); + state = "catch"; +} +ok(state === "catch", "state = " + state + " expected catch"); + +var state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; + throw true; +}catch(ex) { + ok(state === "try", "catch: state = " + state); + ok(ex === true, "ex is not true"); + state = "catch"; +}finally { + ok(state === "catch", "finally: state = " + state); + state = "finally"; +} +ok(state === "finally", "state = " + state + " expected finally"); + +var state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; + try { throw true; } finally {} +}catch(ex) { + ok(state === "try", "catch: state = " + state); + ok(ex === true, "ex is not true"); + state = "catch"; +}finally { + ok(state === "catch", "finally: state = " + state); + state = "finally"; +} +ok(state === "finally", "state = " + state + " expected finally"); + +var state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; + try { throw "except"; } catch(ex) { throw true; } +}catch(ex) { + ok(state === "try", "catch: state = " + state); + ok(ex === true, "ex is not true"); + state = "catch"; +}finally { + ok(state === "catch", "finally: state = " + state); + state = "finally"; +} +ok(state === "finally", "state = " + state + " expected finally"); + +function throwFunc(x) { + throw x; +} + +var state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; + throwFunc(true); +}catch(ex) { + ok(state === "try", "catch: state = " + state); + ok(ex === true, "ex is not true"); + state = "catch"; +}finally { + ok(state === "catch", "finally: state = " + state); + state = "finally"; +} +ok(state === "finally", "state = " + state + " expected finally"); + +state = ""; +switch(1) { +case "1": + ok(false, "unexpected case \"1\""); +case 1: + ok(state === "", "case 1: state = " + state); + state = "1"; +default: + ok(state === "1", "default: state = " + state); + state = "default"; +case false: + ok(state === "default", "case false: state = " + state); + state = "false"; +} +ok(state === "false", "state = " + state); + +state = ""; +switch("") { +case "1": +case 1: + ok(false, "unexpected case 1"); +default: + ok(state === "", "default: state = " + state); + state = "default"; +case false: + ok(state === "default", "case false: state = " + state); + state = "false"; +} +ok(state === "false", "state = " + state); + +state = ""; +switch(1) { +case "1": + ok(false, "unexpected case \"1\""); +case 1: + ok(state === "", "case 1: state = " + state); + state = "1"; +default: + ok(state === "1", "default: state = " + state); + state = "default"; + break; +case false: + ok(false, "unexpected case false"); +} +ok(state === "default", "state = " + state); + +tmp = eval("1"); +ok(tmp === 1, "eval(\"1\") !== 1"); +eval("{ ok(tmp === 1, 'eval: tmp !== 1'); } tmp = 2;"); +ok(tmp === 2, "tmp !== 2"); + +ok(eval(false) === false, "eval(false) !== false"); +ok(eval() === undefined, "eval() !== undefined"); + +tmp = eval("1", "2"); +ok(tmp === 1, "eval(\"1\", \"2\") !== 1"); + +var state = ""; +try { + ok(state === "", "try: state = " + state); + state = "try"; + eval("throwFunc(true);"); +}catch(ex) { + ok(state === "try", "catch: state = " + state); + ok(ex === true, "ex is not true"); + state = "catch"; +}finally { + ok(state === "catch", "finally: state = " + state); + state = "finally"; +} +ok(state === "finally", "state = " + state + " expected finally"); + +tmp = [,,1,2,,,true]; +ok(tmp.length === 7, "tmp.length !== 7"); +ok(tmp["0"] === undefined, "tmp[0] is not undefined"); +ok(tmp["3"] === 2, "tmp[3] !== 2"); +ok(tmp["6"] === true, "tmp[6] !== true"); +ok(tmp[2] === 1, "tmp[2] !== 1"); + +ok([1,].length === 2, "[1,].length !== 2"); +ok([,,].length === 3, "[,,].length !== 3"); +ok([,].length === 2, "[].length != 2"); +ok([].length === 0, "[].length != 0"); + +tmp = 0; +while(tmp < 4) { + ok(tmp < 4, "tmp >= 4"); + tmp++; +} +ok(tmp === 4, "tmp !== 4"); + +tmp = 0; +while(true) { + ok(tmp < 4, "tmp >= 4"); + tmp++; + if(tmp === 4) { + break; + ok(false, "break did not break"); + } +} +ok(tmp === 4, "tmp !== 4"); + +tmp = 0; +do { + ok(tmp < 4, "tmp >= 4"); + tmp++; +} while(tmp < 4); +ok(tmp === 4, "tmp !== 4"); + +tmp = 0; +do { + ok(tmp === 0, "tmp !=== 0"); + tmp++; +} while(false); +ok(tmp === 1, "tmp !== 1"); + +tmp = 0; +do { + ok(tmp < 4, "tmp >= 4"); + tmp++; +} while(tmp < 4) +ok(tmp === 4, "tmp !== 4") + +tmp = 0; +while(tmp < 4) { + tmp++; + if(tmp === 2) { + continue; + ok(false, "break did not break"); + } + ok(tmp <= 4 && tmp != 2, "tmp = " + tmp); +} +ok(tmp === 4, "tmp !== 4"); + +for(tmp=0; tmp < 4; tmp++) + ok(tmp < 4, "tmp = " + tmp); +ok(tmp === 4, "tmp !== 4"); + +for(tmp=0; tmp < 4; tmp++) { + if(tmp === 2) + break; + ok(tmp < 2, "tmp = " + tmp); +} +ok(tmp === 2, "tmp !== 2"); + +for(tmp=0; tmp < 4; tmp++) { + if(tmp === 2) + continue; + ok(tmp < 4 && tmp != 2, "tmp = " + tmp); +} +ok(tmp === 4, "tmp !== 4"); + +for(var fi=0; fi < 4; fi++) + ok(fi < 4, "fi = " + fi); +ok(fi === 4, "fi !== 4"); + +ok((void 1) === undefined, "(void 1) !== undefined"); + +var inobj = new Object(); + +for(var iter in inobj) + ok(false, "unexpected iter = " + iter); + +inobj.test = true; +tmp = 0; +for(iter in inobj) { + ok(iter == "test", "unexpected iter = " + iter); + tmp++; +} +ok(tmp === 1, "for..in tmp = " + tmp); + +function forinTestObj() {} + +forinTestObj.prototype.test3 = true; + +var arr = new Array(); +inobj = new forinTestObj(); +inobj.test1 = true; +inobj.test2 = true; + +tmp = 0; +for(iter in inobj) { + arr[iter] = true; + tmp++; +} + +ok(tmp === 3, "for..in tmp = " + tmp); +ok(arr["test1"] === true, "arr[test1] !== true"); +ok(arr["test2"] === true, "arr[test2] !== true"); +ok(arr["test3"] === true, "arr[test3] !== true"); + +tmp = new Object(); +tmp.test = false; +ok((delete tmp.test) === true, "delete returned false"); +ok(typeof(tmp.test) === "undefined", "tmp.test type = " + typeof(tmp.test)); +for(iter in tmp) + ok(false, "tmp has prop " + iter); + +tmp.testWith = true; +with(tmp) + ok(testWith === true, "testWith !== true"); + +if(false) { + var varTest1 = true; +} + +ok(varTest1 === undefined, "varTest1 = " + varTest1); +ok(varTest2 === undefined, "varTest2 = " + varTest1); + +var varTest2; + +function varTestFunc(varTest3) { + var varTest3; + + ok(varTest3 === 3, "varTest3 = " + varTest3); + ok(varTest4 === undefined, "varTest4 = " + varTest4); + + var varTest4; +} + +varTestFunc(3); + +deleteTest = 1; +delete deleteTest; +try { + tmp = deleteTest; + ok(false, "deleteTest not throwed exception?"); +}catch(ex) {} + +if (false) + if (true) + ok(false, "if evaluated"); + else + ok(false, "else should be associated with nearest if statement"); + +if (true) + if (false) + ok(false, "if evaluated"); + else + ok(true, "else should be associated with nearest if statement"); + +function instanceOfTest() {} +tmp = new instanceOfTest(); + +ok((tmp instanceof instanceOfTest) === true, "tmp is not instance of instanceOfTest"); +ok((tmp instanceof Object) === true, "tmp is not instance of Object"); +ok((tmp instanceof String) === false, "tmp is instance of String"); + +instanceOfTest.prototype = new Object(); +ok((tmp instanceof instanceOfTest) === false, "tmp is instance of instanceOfTest"); +ok((tmp instanceof Object) === true, "tmp is not instance of Object"); + +ok((1 instanceof Object) === false, "1 is instance of Object"); +ok((false instanceof Boolean) === false, "false is instance of Boolean"); +ok(("" instanceof Object) === false, "'' is instance of Object"); + +(function () { + ok((arguments instanceof Object) === true, "argument is not instance of Object"); + ok((arguments instanceof Array) === false, "argument is not instance of Array"); + ok(arguments.toString() === "[object Object]", "arguments.toString() = " + arguments.toString()); +})(1,2); + +obj = new String(); +ok(("length" in obj) === true, "length is not in obj"); +ok(("isPrototypeOf" in obj) === true, "isPrototypeOf is not in obj"); +ok(("abc" in obj) === false, "test is in obj"); +obj.abc = 1; +ok(("abc" in obj) === true, "test is not in obj"); +ok(("1" in obj) === false, "1 is in obj"); + +obj = [1,2,3]; +ok((1 in obj) === true, "1 is not in obj"); + +ok(isNaN(NaN) === true, "isNaN(NaN) !== true"); +ok(isNaN(0.5) === false, "isNaN(0.5) !== false"); +ok(isNaN(Infinity) === false, "isNaN(Infinity) !== false"); +ok(isNaN() === true, "isNaN() !== true"); +ok(isNaN(NaN, 0) === true, "isNaN(NaN, 0) !== true"); +ok(isNaN(0.5, NaN) === false, "isNaN(0.5, NaN) !== false"); +ok(isNaN(+undefined) === true, "isNaN(+undefined) !== true"); + +ok(isFinite(0.5) === true, "isFinite(0.5) !== true"); +ok(isFinite(Infinity) === false, "isFinite(Infinity) !== false"); +ok(isFinite(-Infinity) === false, "isFinite(Infinity) !== false"); +ok(isFinite(NaN) === false, "isFinite(NaN) !== false"); +ok(isFinite(0.5, NaN) === true, "isFinite(0.5, NaN) !== true"); +ok(isFinite(NaN, 0.5) === false, "isFinite(NaN, 0.5) !== false"); +ok(isFinite() === false, "isFinite() !== false"); + +ok((1 < NaN) === false, "(1 < NaN) !== false"); +ok((1 > NaN) === false, "(1 > NaN) !== false"); +ok((1 <= NaN) === false, "(1 <= NaN) !== false"); +ok((1 >= NaN) === false, "(1 >= NaN) !== false"); +ok((NaN < 1) === false, "(NaN < 1) !== false"); +ok((NaN > 1) === false, "(NaN > 1) !== false"); +ok((NaN <= 1) === false, "(NaN <= 1) !== false"); +ok((NaN >= 1) === false, "(NaN >= 1) !== false"); +ok((Infinity < 2) === false, "(Infinity < 2) !== false"); +ok((Infinity > 2) === true, "(Infinity > 2) !== true"); +ok((-Infinity < 2) === true, "(-Infinity < 2) !== true"); + +ok(isNaN(+"test") === true, "isNaN(+'test') !== true"); +ok(isNaN(+"123t") === true, "isNaN(+'123t') !== true"); +ok(isNaN(+"Infinity x") === true, "isNaN(+'Infinity x') !== true"); +ok(+"Infinity" === Infinity, "+'Infinity' !== Infinity"); +ok(+" Infinity " === Infinity, "+' Infinity ' !== Infinity"); +ok(+"-Infinity" === -Infinity, "+'-Infinity' !== -Infinity"); + +ok((NaN !== NaN) === true, "(NaN !== NaN) !== true"); +ok((NaN === NaN) === false, "(NaN === NaN) !== false"); +ok((Infinity !== NaN) === true, "(Infinity !== NaN) !== true"); +ok((Infinity !== NaN) === true, "(Infinity !== NaN) !== true"); +ok((0 === NaN) === false, "(0 === NaN) !== false"); + +ok((NaN != NaN) === true, "(NaN !== NaN) != true"); +ok((NaN == NaN) === false, "(NaN === NaN) != false"); +ok((Infinity != NaN) === true, "(Infinity != NaN) !== true"); +ok((Infinity != NaN) === true, "(Infinity != NaN) !== true"); +ok((0 == NaN) === false, "(0 === NaN) != false"); + + +ok(typeof(testFunc2) === "function", "typeof(testFunc2) = " + typeof(testFunc2)); +tmp = testFunc2(1); +ok(tmp === 2, "testFunc2(1) = " + tmp); +function testFunc2(x) { return x+1; } + +ok(typeof(testFunc3) === "function", "typeof(testFunc3) = " + typeof(testFunc3)); +tmp = testFunc3(1); +ok(tmp === 3, "testFunc3(1) = " + tmp); +tmp = function testFunc3(x) { return x+2; }; + +tmp = testFunc4(1); +ok(tmp === 5, "testFunc4(1) = " + tmp); +tmp = function testFunc4(x) { return x+3; }; +tmp = testFunc4(1); +testFunc4 = 1; +ok(testFunc4 === 1, "testFunc4 = " + testFunc4); +ok(tmp === 5, "testFunc4(1) = " + tmp); +tmp = function testFunc4(x) { return x+4; }; +ok(testFunc4 === 1, "testFunc4 = " + testFunc4); + +function testEmbededFunctions() { + ok(typeof(testFunc5) === "function", "typeof(testFunc5) = " + typeof(testFunc5)); + tmp = testFunc5(1); + ok(tmp === 3, "testFunc5(1) = " + tmp); + tmp = function testFunc5(x) { return x+2; }; + + tmp = testFunc6(1); + ok(tmp === 5, "testFunc6(1) = " + tmp); + tmp = function testFunc6(x) { return x+3; }; + tmp = testFunc6(1); + ok(tmp === 5, "testFunc6(1) = " + tmp); + tmp = function testFunc6(x) { return x+4; }; + testFunc6 = 1; + ok(testFunc6 === 1, "testFunc4 = " + testFunc6); +} + +testEmbededFunctions(); + +date = new Date(); +date.toString = function() { return "toString"; } +ok(""+date === "toString", "''+date = " + date); +date.toString = function() { return this; } +ok(""+date === ""+date.valueOf(), "''+date = " + date); + +str = new String("test"); +str.valueOf = function() { return "valueOf"; } +ok(""+str === "valueOf", "''+str = " + str); +str.valueOf = function() { return new Date(); } +ok(""+str === "test", "''+str = " + str); + +ok((function (){return 1;})() === 1, "(function (){return 1;})() = " + (function (){return 1;})()); + +var re = /=(\?|%3F)/g; +ok(re.source === "=(\\?|%3F)", "re.source = " + re.source); + +ok(createNullBSTR() === '', "createNullBSTR() !== ''"); + +ok(getVT(nullDisp) === "VT_DISPATCH", "getVT(nullDisp) = " + getVT(nullDisp)); +ok(typeof(nullDisp) === "object", "typeof(nullDisp) = " + typeof(nullDisp)); +ok(nullDisp === nullDisp, "nullDisp !== nullDisp"); +ok(nullDisp !== re, "nullDisp === re"); +ok(nullDisp === null, "nullDisp === null"); +ok(nullDisp == null, "nullDisp == null"); +ok(getVT(true && nullDisp) === "VT_DISPATCH", + "getVT(0 && nullDisp) = " + getVT(true && nullDisp)); +ok(!nullDisp === true, "!nullDisp = " + !nullDisp); +ok(String(nullDisp) === "null", "String(nullDisp) = " + String(nullDisp)); +ok(nullDisp != new Object(), "nullDisp == new Object()"); +ok(new Object() != nullDisp, "new Object() == nullDisp"); +ok((typeof Object(nullDisp)) === "object", "typeof Object(nullDisp) !== 'object'"); +tmp = getVT(Object(nullDisp)); +ok(tmp === "VT_DISPATCH", "getVT(Object(nullDisp) = " + tmp); +tmp = Object(nullDisp).toString(); +ok(tmp === "[object Object]", "Object(nullDisp).toString() = " + tmp); + +function do_test() {} +function nosemicolon() {} nosemicolon(); +function () {} nosemicolon(); + +if(false) { + function in_if_false() { return true; } ok(false, "!?"); +} + +ok(in_if_false(), "in_if_false failed"); + +ok(typeof(doesnotexist) === "undefined", "typeof(doesnotexist) = " + typeof(doesnotexist)); + +(function() { newValue = 1; })(); +ok(newValue === 1, "newValue = " + newValue); + +reportSuccess(); diff --git a/rostests/winetests/jscript/regexp.js b/rostests/winetests/jscript/regexp.js new file mode 100644 index 00000000000..ff98b484072 --- /dev/null +++ b/rostests/winetests/jscript/regexp.js @@ -0,0 +1,301 @@ +/* + * Copyright 2008 Jacek Caban for CodeWeavers + * + * 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 + */ + + +var m, re, b; + +re = /a+/; +ok(re.lastIndex === 0, "re.lastIndex = " + re.lastIndex); + +m = re.exec(" aabaaa"); +ok(re.lastIndex === 3, "re.lastIndex = " + re.lastIndex); +ok(m.index === 1, "m.index = " + m.index); +ok(m.input === " aabaaa", "m.input = " + m.input); +ok(m.length === 1, "m.length = " + m.length); +ok(m[0] === "aa", "m[0] = " + m[0]); + +m = re.exec(" aabaaa"); +ok(re.lastIndex === 3, "re.lastIndex = " + re.lastIndex); +ok(m.index === 1, "m.index = " + m.index); +ok(m.input === " aabaaa", "m.input = " + m.input); +ok(m.length === 1, "m.length = " + m.length); +ok(m[0] === "aa", "m[0] = " + m[0]); + +re = /a+/g; +ok(re.lastIndex === 0, "re.lastIndex = " + re.lastIndex); + +m = re.exec(" aabaaa"); +ok(re.lastIndex === 3, "re.lastIndex = " + re.lastIndex); +ok(m.index === 1, "m.index = " + m.index); +ok(m.input === " aabaaa", "m.input = " + m.input); +ok(m.length === 1, "m.length = " + m.length); +ok(m[0] === "aa", "m[0] = " + m[0]); + +m = re.exec(" aabaaa"); +ok(re.lastIndex === 7, "re.lastIndex = " + re.lastIndex); +ok(m.index === 4, "m.index = " + m.index); +ok(m.input === " aabaaa", "m.input = " + m.input); +ok(m.length === 1, "m.length = " + m.length); +ok(m[0] === "aaa", "m[0] = " + m[0]); + +m = re.exec(" aabaaa"); +ok(re.lastIndex === 0, "re.lastIndex = " + re.lastIndex); +ok(m === null, "m is not null"); + +re.exec(" a"); +ok(re.lastIndex === 16, "re.lastIndex = " + re.lastIndex); + +m = re.exec(" a"); +ok(m === null, "m is not null"); +ok(re.lastIndex === 0, "re.lastIndex = " + re.lastIndex); + +m = re.exec(" a"); +ok(re.lastIndex === 2, "re.lastIndex = " + re.lastIndex); + +m = re.exec(); +ok(m === null, "m is not null"); +ok(re.lastIndex === 0, "re.lastIndex = " + re.lastIndex); + +b = re.test(" a "); +ok(b === true, "re.test(' a ') returned " + b); +ok(re.lastIndex === 3, "re.lastIndex = " + re.lastIndex); + +b = re.test(" a "); +ok(b === false, "re.test(' a ') returned " + b); +ok(re.lastIndex === 0, "re.lastIndex = " + re.lastIndex); + +re = /\[([^\[]+)\]/g; +m = re.exec(" [test] "); +ok(re.lastIndex === 7, "re.lastIndex = " + re.lastIndex); +ok(m.index === 1, "m.index = " + m.index); +ok(m.input === " [test] ", "m.input = " + m.input); +ok(m.length === 2, "m.length = " + m.length); +ok(m[0] === "[test]", "m[0] = " + m[0]); +ok(m[1] === "test", "m[1] = " + m[1]); + +b = /a*/.test(); +ok(b === true, "/a*/.test() returned " + b); + +m = "abcabc".match(/ca/); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 1, "m.length is not 1"); +ok(m["0"] === "ca", "m[0] is not \"ca\""); + +m = "abcabc".match(/ab/); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 1, "m.length is not 1"); +ok(m["0"] === "ab", "m[0] is not \"ab\""); + +m = "abcabc".match(/ab/g); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 2, "m.length is not 2"); +ok(m["0"] === "ab", "m[0] is not \"ab\""); +ok(m["1"] === "ab", "m[1] is not \"ab\""); + +m = "abcabc".match(/Ab/g); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m === null, "m is not null"); + +m = "abcabc".match(/Ab/gi); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 2, "m.length is not 2"); +ok(m["0"] === "ab", "m[0] is not \"ab\""); +ok(m["1"] === "ab", "m[1] is not \"ab\""); + +m = "aaabcabc".match(/a+b/g); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 2, "m.length is not 2"); +ok(m["0"] === "aaab", "m[0] is not \"ab\""); +ok(m["1"] === "ab", "m[1] is not \"ab\""); + +m = "aaa\\\\cabc".match(/\\/g); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 2, "m.length is not 2"); +ok(m["0"] === "\\", "m[0] is not \"\\\""); +ok(m["1"] === "\\", "m[1] is not \"\\\""); + +m = "abcabc".match(new RegExp("ab")); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 1, "m.length is not 1"); +ok(m["0"] === "ab", "m[0] is not \"ab\""); + +m = "abcabc".match(new RegExp("ab","g")); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 2, "m.length is not 2"); +ok(m["0"] === "ab", "m[0] is not \"ab\""); +ok(m["1"] === "ab", "m[1] is not \"ab\""); + +m = "abcabc".match(new RegExp(/ab/g)); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 2, "m.length is not 2"); +ok(m["0"] === "ab", "m[0] is not \"ab\""); +ok(m["1"] === "ab", "m[1] is not \"ab\""); + +m = "abcabc".match(new RegExp("ab","g", "test")); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 2, "m.length is not 2"); +ok(m["0"] === "ab", "m[0] is not \"ab\""); +ok(m["1"] === "ab", "m[1] is not \"ab\""); + +m = "abcabcg".match("ab", "g"); +ok(typeof(m) === "object", "typeof m is not object"); +ok(m.length === 1, "m.length is not 1"); +ok(m["0"] === "ab", "m[0] is not \"ab\""); + +m = "abcabc".match(); +ok(m === null, "m is not null"); + +r = "- [test] -".replace(/\[([^\[]+)\]/g, "success"); +ok(r === "- success -", "r = " + r + " expected '- success -'"); + +r = "[test] [test]".replace(/\[([^\[]+)\]/g, "aa"); +ok(r === "aa aa", "r = " + r + "aa aa"); + +r = "[test] [test]".replace(/\[([^\[]+)\]/, "aa"); +ok(r === "aa [test]", "r = " + r + " expected 'aa [test]'"); + +r = "- [test] -".replace(/\[([^\[]+)\]/g); +ok(r === "- undefined -", "r = " + r + " expected '- undefined -'"); + +r = "- [test] -".replace(/\[([^\[]+)\]/g, true); +ok(r === "- true -", "r = " + r + " expected '- true -'"); + +r = "- [test] -".replace(/\[([^\[]+)\]/g, true, "test"); +ok(r === "- true -", "r = " + r + " expected '- true -'"); + +var tmp = 0; + +function replaceFunc1(m, off, str) { + ok(arguments.length === 3, "arguments.length = " + arguments.length); + + switch(tmp) { + case 0: + ok(m === "[test1]", "m = " + m + " expected [test1]"); + ok(off === 0, "off = " + off + " expected 0"); + break; + case 1: + ok(m === "[test2]", "m = " + m + " expected [test2]"); + ok(off === 8, "off = " + off + " expected 8"); + break; + default: + ok(false, "unexpected call"); + } + + ok(str === "[test1] [test2]", "str = " + arguments[3]); + return "r" + tmp++; +} + +r = "[test1] [test2]".replace(/\[[^\[]+\]/g, replaceFunc1); +ok(r === "r0 r1", "r = " + r + " expected 'r0 r1'"); + +tmp = 0; + +function replaceFunc2(m, subm, off, str) { + ok(arguments.length === 4, "arguments.length = " + arguments.length); + + switch(tmp) { + case 0: + ok(subm === "test1", "subm = " + subm); + ok(m === "[test1]", "m = " + m + " expected [test1]"); + ok(off === 0, "off = " + off + " expected 0"); + break; + case 1: + ok(subm === "test2", "subm = " + subm); + ok(m === "[test2]", "m = " + m + " expected [test2]"); + ok(off === 8, "off = " + off + " expected 8"); + break; + default: + ok(false, "unexpected call"); + } + + ok(str === "[test1] [test2]", "str = " + arguments[3]); + return "r" + tmp++; +} + +r = "[test1] [test2]".replace(/\[([^\[]+)\]/g, replaceFunc2); +ok(r === "r0 r1", "r = '" + r + "' expected 'r0 r1'"); + +r = "$1,$2".replace(/(\$(\d))/g, "$$1-$1$2"); +ok(r === "$1-$11,$1-$22", "r = '" + r + "' expected '$1-$11,$1-$22'"); + +r = "abc &1 123".replace(/(\&(\d))/g, "$&"); +ok(r === "abc &1 123", "r = '" + r + "' expected 'abc &1 123'"); + +r = "abc &1 123".replace(/(\&(\d))/g, "$'"); +ok(r === "abc 123 123", "r = '" + r + "' expected 'abc 123 123'"); + +r = "abc &1 123".replace(/(\&(\d))/g, "$`"); +ok(r === "abc abc 123", "r = '" + r + "' expected 'abc abc 123'"); + +r = "abc &1 123".replace(/(\&(\d))/g, "$3"); +ok(r === "abc $3 123", "r = '" + r + "' expected 'abc $3 123'"); + +r = "abc &1 123".replace(/(\&(\d))/g, "$"); +ok(r === "abc $ 123", "r = '" + r + "' expected 'abc $ 123'"); + +r = "abc &1 123".replace(/(\&(\d))/g, "$a"); +ok(r === "abc $a 123", "r = '" + r + "' expected 'abc $a 123'"); + +r = "abc &1 123".replace(/(\&(\d))/g, "$11"); +ok(r === "abc &11 123", "r = '" + r + "' expected 'abc &11 123'"); + +r = "abc &1 123".replace(/(\&(\d))/g, "$0"); +ok(r === "abc $0 123", "r = '" + r + "' expected 'abc $0 123'"); + +r = "1 2 3".replace("2", "$&"); +ok(r === "1 $& 3", "r = '" + r + "' expected '1 $& 3'"); + +r = "1 2 3".replace("2", "$'"); +ok(r === "1 $' 3", "r = '" + r + "' expected '1 $' 3'"); + +r = "1,,2,3".split(/,+/g); +ok(r.length === 3, "r.length = " + r.length); +ok(r[0] === "1", "r[0] = " + r[0]); +ok(r[1] === "2", "r[1] = " + r[1]); +ok(r[2] === "3", "r[2] = " + r[2]); + +r = "1,,2,3".split(/,+/); +ok(r.length === 3, "r.length = " + r.length); +ok(r[0] === "1", "r[0] = " + r[0]); +ok(r[1] === "2", "r[1] = " + r[1]); +ok(r[2] === "3", "r[2] = " + r[2]); + +r = "1,,2,".split(/,+/); +ok(r.length === 2, "r.length = " + r.length); +ok(r[0] === "1", "r[0] = " + r[0]); +ok(r[1] === "2", "r[1] = " + r[1]); + +re = /abc[^d]/g; +ok(re.source === "abc[^d]", "re.source = '" + re.source + "', expected 'abc[^d]'"); + +re = /a\bc[^d]/g; +ok(re.source === "a\\bc[^d]", "re.source = '" + re.source + "', expected 'a\\bc[^d]'"); + +re = /abc/; +ok(re === RegExp(re), "re !== RegExp(re)"); + +re = RegExp("abc[^d]", "g"); +ok(re.source === "abc[^d]", "re.source = '" + re.source + "', expected 'abc[^d]'"); + +re = /abc/; +ok(re === RegExp(re, undefined), "re !== RegExp(re, undefined)"); + +re = /abc/; +ok(re === RegExp(re, undefined, 1), "re !== RegExp(re, undefined, 1)"); + +reportSuccess(); diff --git a/rostests/winetests/jscript/rsrc.rc b/rostests/winetests/jscript/rsrc.rc new file mode 100644 index 00000000000..ecb421289d2 --- /dev/null +++ b/rostests/winetests/jscript/rsrc.rc @@ -0,0 +1,26 @@ +/* + * Copyright 2008 Jacek Caban for CodeWeavers + * + * 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 + */ + +/* @makedep: api.js */ +api.js 40 "api.js" + +/* @makedep: lang.js */ +lang.js 40 "lang.js" + +/* @makedep: regexp.js */ +regexp.js 40 "regexp.js" diff --git a/rostests/winetests/jscript/run.c b/rostests/winetests/jscript/run.c new file mode 100644 index 00000000000..cf34b2f1abd --- /dev/null +++ b/rostests/winetests/jscript/run.c @@ -0,0 +1,1028 @@ +/* + * Copyright 2008 Jacek Caban for CodeWeavers + * + * 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 + */ + +#include + +#define COBJMACROS +#define CONST_VTABLE + +#include +#include +#include + +#include "wine/test.h" + +static const CLSID CLSID_JScript = + {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}}; + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define SET_CALLED(func) \ + called_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(global_propget_d); +DEFINE_EXPECT(global_propget_i); +DEFINE_EXPECT(global_propput_d); +DEFINE_EXPECT(global_propput_i); +DEFINE_EXPECT(global_success_d); +DEFINE_EXPECT(global_success_i); +DEFINE_EXPECT(global_notexists_d); +DEFINE_EXPECT(testobj_delete); +DEFINE_EXPECT(testobj_value); +DEFINE_EXPECT(testobj_prop_d); +DEFINE_EXPECT(testobj_noprop_d); +DEFINE_EXPECT(GetItemInfo_testVal); + +#define DISPID_GLOBAL_TESTPROPGET 0x1000 +#define DISPID_GLOBAL_TESTPROPPUT 0x1001 +#define DISPID_GLOBAL_REPORTSUCCESS 0x1002 +#define DISPID_GLOBAL_TRACE 0x1003 +#define DISPID_GLOBAL_OK 0x1004 +#define DISPID_GLOBAL_GETVT 0x1005 +#define DISPID_GLOBAL_TESTOBJ 0x1006 +#define DISPID_GLOBAL_NULL_BSTR 0x1007 +#define DISPID_GLOBAL_NULL_DISP 0x1008 +#define DISPID_GLOBAL_TESTTHIS 0x1009 +#define DISPID_GLOBAL_TESTTHIS2 0x100a + +#define DISPID_TESTOBJ_PROP 0x2000 + +static const WCHAR testW[] = {'t','e','s','t',0}; +static const CHAR testA[] = "test"; +static const WCHAR test_valW[] = {'t','e','s','t','V','a','l',0}; +static const CHAR test_valA[] = "testVal"; + +static BOOL strict_dispid_check; +static const char *test_name = "(null)"; +static IDispatch *script_disp; + +static BSTR a2bstr(const char *str) +{ + BSTR ret; + int len; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = SysAllocStringLen(NULL, len-1); + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + + return ret; +} + +static int strcmp_wa(LPCWSTR strw, const char *stra) +{ + CHAR buf[512]; + WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), 0, 0); + return lstrcmpA(buf, stra); +} + +static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDispatch) + || IsEqualGUID(riid, &IID_IDispatchEx)) + *ppv = iface; + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) +{ + return 2; +} + +static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) +{ + return 1; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) +{ + ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testObj_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + if(!strcmp_wa(bstrName, "prop")) { + CHECK_EXPECT(testobj_prop_d); + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_TESTOBJ_PROP; + return S_OK; + } + if(!strcmp_wa(bstrName, "noprop")) { + CHECK_EXPECT(testobj_noprop_d); + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + return DISP_E_UNKNOWNNAME; + } + + ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName)); + return E_NOTIMPL; +} + +static HRESULT WINAPI testObj_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + switch(id) { + case DISPID_VALUE: + CHECK_EXPECT(testobj_value); + + ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgvarg, "rgvarg != NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + ok(pei != NULL, "pei == NULL\n"); + + V_VT(pvarRes) = VT_I4; + V_I4(pvarRes) = 1; + return S_OK; + } + + ok(0, "unexpected call %x\n", id); + return DISP_E_MEMBERNOTFOUND; +} + +static HRESULT WINAPI testObj_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) +{ + CHECK_EXPECT(testobj_delete); + + ok(!strcmp_wa(bstrName, "deleteTest"), "unexpected name %s\n", wine_dbgstr_w(bstrName)); + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + return S_OK; +} + +static IDispatchExVtbl testObjVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + testObj_GetDispID, + testObj_InvokeEx, + testObj_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx testObj = { &testObjVtbl }; + +static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + if(!strcmp_wa(bstrName, "ok")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_OK; + return S_OK; + } + if(!strcmp_wa(bstrName, "trace")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_TRACE; + return S_OK; + } + if(!strcmp_wa(bstrName, "reportSuccess")) { + CHECK_EXPECT(global_success_d); + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_REPORTSUCCESS; + return S_OK; + } + if(!strcmp_wa(bstrName, "testPropGet")) { + CHECK_EXPECT(global_propget_d); + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_TESTPROPGET; + return S_OK; + } + if(!strcmp_wa(bstrName, "testPropPut")) { + CHECK_EXPECT(global_propput_d); + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_TESTPROPPUT; + return S_OK; + } + if(!strcmp_wa(bstrName, "getVT")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_GETVT; + return S_OK; + } + if(!strcmp_wa(bstrName, "testObj")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_TESTOBJ; + return S_OK; + } + if(!strcmp_wa(bstrName, "createNullBSTR")) { + *pid = DISPID_GLOBAL_NULL_BSTR; + return S_OK; + } + if(!strcmp_wa(bstrName, "nullDisp")) { + *pid = DISPID_GLOBAL_NULL_DISP; + return S_OK; + } + if(!strcmp_wa(bstrName, "notExists")) { + CHECK_EXPECT(global_notexists_d); + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + return DISP_E_UNKNOWNNAME; + } + + if(!strcmp_wa(bstrName, "testThis")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_TESTTHIS; + return S_OK; + } + + if(!strcmp_wa(bstrName, "testThis2")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_GLOBAL_TESTTHIS2; + return S_OK; + } + + if(strict_dispid_check) + ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName)); + return DISP_E_UNKNOWNNAME; +} + +static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + switch(id) { + case DISPID_GLOBAL_OK: + ok(wFlags == INVOKE_FUNC || wFlags == (INVOKE_FUNC|INVOKE_PROPERTYGET), "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + if(wFlags & INVOKE_PROPERTYGET) + ok(pvarRes != NULL, "pvarRes == NULL\n"); + else + ok(!pvarRes, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + + ok(V_VT(pdp->rgvarg) == VT_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg)); + ok(V_VT(pdp->rgvarg+1) == VT_BOOL, "V_VT(psp->rgvargs+1) = %d\n", V_VT(pdp->rgvarg)); + ok(V_BOOL(pdp->rgvarg+1), "%s: %s\n", test_name, wine_dbgstr_w(V_BSTR(pdp->rgvarg))); + + return S_OK; + + case DISPID_GLOBAL_TRACE: + ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(!pvarRes, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + + ok(V_VT(pdp->rgvarg) == VT_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg)); + if(V_VT(pdp->rgvarg) == VT_BSTR) + trace("%s: %s\n", test_name, wine_dbgstr_w(V_BSTR(pdp->rgvarg))); + + return S_OK; + + case DISPID_GLOBAL_REPORTSUCCESS: + CHECK_EXPECT(global_success_i); + + ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 0, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(!pvarRes, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + + return S_OK; + + case DISPID_GLOBAL_TESTPROPGET: + CHECK_EXPECT(global_propget_i); + + ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgvarg, "rgvarg != NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + ok(pei != NULL, "pei == NULL\n"); + + V_VT(pvarRes) = VT_I4; + V_I4(pvarRes) = 1; + + return S_OK; + + case DISPID_GLOBAL_TESTPROPPUT: + CHECK_EXPECT(global_propput_i); + + ok(wFlags == INVOKE_PROPERTYPUT, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pdp->rgdispidNamedArgs[0] == DISPID_PROPERTYPUT, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]); + ok(!pvarRes, "pvarRes != NULL\n"); + + ok(V_VT(pdp->rgvarg) == VT_I4, "V_VT(pdp->rgvarg)=%d\n", V_VT(pdp->rgvarg)); + ok(V_I4(pdp->rgvarg) == 1, "V_I4(pdp->rgvarg)=%d\n", V_I4(pdp->rgvarg)); + return S_OK; + + case DISPID_GLOBAL_GETVT: + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + ok(pei != NULL, "pei == NULL\n"); + + V_VT(pvarRes) = VT_BSTR; + switch(V_VT(pdp->rgvarg)) { + case VT_EMPTY: + V_BSTR(pvarRes) = a2bstr("VT_EMPTY"); + break; + case VT_NULL: + V_BSTR(pvarRes) = a2bstr("VT_NULL"); + break; + case VT_I4: + V_BSTR(pvarRes) = a2bstr("VT_I4"); + break; + case VT_R8: + V_BSTR(pvarRes) = a2bstr("VT_R8"); + break; + case VT_BSTR: + V_BSTR(pvarRes) = a2bstr("VT_BSTR"); + break; + case VT_DISPATCH: + V_BSTR(pvarRes) = a2bstr("VT_DISPATCH"); + break; + case VT_BOOL: + V_BSTR(pvarRes) = a2bstr("VT_BOOL"); + break; + default: + ok(0, "unknown vt %d\n", V_VT(pdp->rgvarg)); + return E_FAIL; + } + + return S_OK; + + case DISPID_GLOBAL_TESTOBJ: + ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgvarg, "rgvarg != NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + ok(pei != NULL, "pei == NULL\n"); + + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = (IDispatch*)&testObj; + return S_OK; + + case DISPID_GLOBAL_NULL_BSTR: + if(pvarRes) { + V_VT(pvarRes) = VT_BSTR; + V_BSTR(pvarRes) = NULL; + } + return S_OK; + + case DISPID_GLOBAL_NULL_DISP: + ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgvarg, "rgvarg != NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + ok(pei != NULL, "pei == NULL\n"); + + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = NULL; + return S_OK; + + case DISPID_GLOBAL_TESTTHIS: + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes == NULL, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + + ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(arg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_DISPATCH(pdp->rgvarg) == (IDispatch*)iface, "disp != iface\n"); + + return S_OK; + + case DISPID_GLOBAL_TESTTHIS2: + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->rgvarg != NULL, "rgvarg == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pvarRes == NULL, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + + ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(arg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_DISPATCH(pdp->rgvarg) != (IDispatch*)iface, "disp == iface\n"); + ok(V_DISPATCH(pdp->rgvarg) == script_disp, "disp != script_disp\n"); + + return S_OK; + } + + ok(0, "unexpected call %x\n", id); + return DISP_E_MEMBERNOTFOUND; +} + +static IDispatchExVtbl GlobalVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + Global_GetDispID, + Global_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx Global = { &GlobalVtbl }; + +static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid)) + *ppv = iface; + else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) + *ppv = iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface) +{ + return 2; +} + +static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface) +{ + return 1; +} + +static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid) +{ + *plcid = GetUserDefaultLCID(); + return S_OK; +} + +static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName, + DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti) +{ + ok(dwReturnMask == SCRIPTINFO_IUNKNOWN, "unexpected dwReturnMask %x\n", dwReturnMask); + ok(!ppti, "ppti != NULL\n"); + + if(!strcmp_wa(pstrName, test_valA)) + CHECK_EXPECT(GetItemInfo_testVal); + else if(strcmp_wa(pstrName, testA)) + ok(0, "unexpected pstrName %s\n", wine_dbgstr_w(pstrName)); + + *ppiunkItem = (IUnknown*)&Global; + return S_OK; +} + +static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface, + const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface) +{ + return E_NOTIMPL; +} + +#undef ACTSCPSITE_THIS + +static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = { + ActiveScriptSite_QueryInterface, + ActiveScriptSite_AddRef, + ActiveScriptSite_Release, + ActiveScriptSite_GetLCID, + ActiveScriptSite_GetItemInfo, + ActiveScriptSite_GetDocVersionString, + ActiveScriptSite_OnScriptTerminate, + ActiveScriptSite_OnStateChange, + ActiveScriptSite_OnScriptError, + ActiveScriptSite_OnEnterScript, + ActiveScriptSite_OnLeaveScript +}; + +static IActiveScriptSite ActiveScriptSite = { &ActiveScriptSiteVtbl }; + +static IActiveScript *create_script(void) +{ + IActiveScript *script; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_JScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IActiveScript, (void**)&script); + ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); + + return script; +} + +static void parse_script(DWORD flags, BSTR script_str) +{ + IActiveScriptParse *parser; + IActiveScript *engine; + HRESULT hres; + + engine = create_script(); + if(!engine) + return; + + hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres); + if (FAILED(hres)) + { + IActiveScript_Release(engine); + return; + } + + hres = IActiveScriptParse64_InitNew(parser); + ok(hres == S_OK, "InitNew failed: %08x\n", hres); + + hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite); + ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres); + + hres = IActiveScript_AddNamedItem(engine, testW, + SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|flags); + ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres); + + hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres); + + hres = IActiveScript_GetScriptDispatch(engine, NULL, &script_disp); + ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres); + ok(script_disp != NULL, "script_disp == NULL\n"); + ok(script_disp != (IDispatch*)&Global, "script_disp == Global\n"); + + hres = IActiveScriptParse64_ParseScriptText(parser, script_str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + + IDispatch_Release(script_disp); + IActiveScript_Release(engine); + IUnknown_Release(parser); +} + +static HRESULT parse_htmlscript(BSTR script_str) +{ + IActiveScriptParse *parser; + IActiveScript *engine; + HRESULT hres; + BSTR tmp = a2bstr(""); + + engine = create_script(); + if(!engine) + return E_FAIL; + + hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres); + if (FAILED(hres)) + { + IActiveScript_Release(engine); + return E_FAIL; + } + + hres = IActiveScriptParse64_InitNew(parser); + ok(hres == S_OK, "InitNew failed: %08x\n", hres); + + hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite); + ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres); + + hres = IActiveScript_AddNamedItem(engine, testW, + SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS); + ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres); + + hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres); + + hres = IActiveScriptParse64_ParseScriptText(parser, script_str, NULL, NULL, tmp, 0, 0, 0, NULL, NULL); + + IActiveScript_Release(engine); + IUnknown_Release(parser); + SysFreeString(tmp); + + return hres; +} + +static void parse_script_af(DWORD flags, const char *src) +{ + BSTR tmp = a2bstr(src); + parse_script(flags, tmp); + SysFreeString(tmp); +} + +static void parse_script_a(const char *src) +{ + parse_script_af(SCRIPTITEM_GLOBALMEMBERS, src); +} + +static HRESULT parse_htmlscript_a(const char *src) +{ + HRESULT hres; + BSTR tmp = a2bstr(src); + hres = parse_htmlscript(tmp); + SysFreeString(tmp); + + return hres; +} + +static BSTR get_script_from_file(const char *filename) +{ + DWORD size, len; + HANDLE file, map; + const char *file_map; + BSTR ret; + + file = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + if(file == INVALID_HANDLE_VALUE) { + trace("Could not open file: %u\n", GetLastError()); + return NULL; + } + + size = GetFileSize(file, NULL); + + map = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); + CloseHandle(file); + if(map == INVALID_HANDLE_VALUE) { + trace("Could not create file mapping: %u\n", GetLastError()); + return NULL; + } + + file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); + CloseHandle(map); + if(!file_map) { + trace("MapViewOfFile failed: %u\n", GetLastError()); + return NULL; + } + + len = MultiByteToWideChar(CP_ACP, 0, file_map, size, NULL, 0); + ret = SysAllocStringLen(NULL, len); + MultiByteToWideChar(CP_ACP, 0, file_map, size, ret, len); + + UnmapViewOfFile(file_map); + + return ret; +} + +static void run_from_file(const char *filename) +{ + BSTR script_str = get_script_from_file(filename); + + strict_dispid_check = FALSE; + + if(script_str) + parse_script(SCRIPTITEM_GLOBALMEMBERS, script_str); + + SysFreeString(script_str); +} + +static void run_from_res(const char *name) +{ + const char *data; + DWORD size, len; + BSTR str; + HRSRC src; + + strict_dispid_check = FALSE; + test_name = name; + + src = FindResourceA(NULL, name, (LPCSTR)40); + ok(src != NULL, "Could not find resource %s\n", name); + + size = SizeofResource(NULL, src); + data = LoadResource(NULL, src); + + len = MultiByteToWideChar(CP_ACP, 0, data, size, NULL, 0); + str = SysAllocStringLen(NULL, len); + len = MultiByteToWideChar(CP_ACP, 0, data, size, str, len); + + SET_EXPECT(global_success_d); + SET_EXPECT(global_success_i); + parse_script(SCRIPTITEM_GLOBALMEMBERS, str); + CHECK_CALLED(global_success_d); + CHECK_CALLED(global_success_i); + + SysFreeString(str); +} + +static void test_isvisible(BOOL global_members) +{ + IActiveScriptParse *parser; + IActiveScript *engine; + HRESULT hres; + + static const WCHAR script_textW[] = + {'v','a','r',' ','v',' ','=',' ','t','e','s','t','V','a','l',';',0}; + + engine = create_script(); + if(!engine) + return; + + hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres); + if (FAILED(hres)) + { + IActiveScript_Release(engine); + return; + } + + hres = IActiveScriptParse64_InitNew(parser); + ok(hres == S_OK, "InitNew failed: %08x\n", hres); + + hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite); + ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres); + + if(global_members) + SET_EXPECT(GetItemInfo_testVal); + hres = IActiveScript_AddNamedItem(engine, test_valW, + SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE| + (global_members ? SCRIPTITEM_GLOBALMEMBERS : 0)); + ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres); + if(global_members) + CHECK_CALLED(GetItemInfo_testVal); + + hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres); + + if(!global_members) + SET_EXPECT(GetItemInfo_testVal); + hres = IActiveScriptParse64_ParseScriptText(parser, script_textW, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + if(!global_members) + CHECK_CALLED(GetItemInfo_testVal); + + hres = IActiveScriptParse64_ParseScriptText(parser, script_textW, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + + IActiveScript_Release(engine); + IUnknown_Release(parser); +} + +static void run_tests(void) +{ + HRESULT hres; + + strict_dispid_check = TRUE; + + parse_script_a(""); + parse_script_a("/* empty */ ;"); + + SET_EXPECT(global_propget_d); + SET_EXPECT(global_propget_i); + parse_script_a("testPropGet;"); + CHECK_CALLED(global_propget_d); + CHECK_CALLED(global_propget_i); + + SET_EXPECT(global_propput_d); + SET_EXPECT(global_propput_i); + parse_script_a("testPropPut = 1;"); + CHECK_CALLED(global_propput_d); + CHECK_CALLED(global_propput_i); + + SET_EXPECT(global_success_d); + SET_EXPECT(global_success_i); + parse_script_a("reportSuccess();"); + CHECK_CALLED(global_success_d); + CHECK_CALLED(global_success_i); + + SET_EXPECT(testobj_delete); + parse_script_a("delete testObj.deleteTest;"); + CHECK_CALLED(testobj_delete); + + parse_script_a("ok(typeof(test) === 'object', \"typeof(test) != 'object'\");"); + + parse_script_a("function reportSuccess() {}; reportSuccess();"); + + SET_EXPECT(global_propget_d); + parse_script_a("var testPropGet"); + CHECK_CALLED(global_propget_d); + + SET_EXPECT(global_notexists_d); + parse_script_a("var notExists; notExists = 1;"); + CHECK_CALLED(global_notexists_d); + + parse_script_a("function f() { var testPropGet; }"); + + parse_script_a("ok((testObj instanceof Object) === false, 'testObj is instance of Object');"); + + SET_EXPECT(testobj_prop_d); + parse_script_a("ok(('prop' in testObj) === true, 'prop is not in testObj');"); + CHECK_CALLED(testobj_prop_d); + + SET_EXPECT(testobj_noprop_d); + parse_script_a("ok(('noprop' in testObj) === false, 'noprop is in testObj');"); + CHECK_CALLED(testobj_noprop_d); + + SET_EXPECT(testobj_value); + parse_script_a("ok(String(testObj) === '1', 'wrong testObj value');"); + CHECK_CALLED(testobj_value); + + SET_EXPECT(testobj_value); + parse_script_a("ok(String.prototype.concat.call(testObj, ' OK') === '1 OK', 'wrong concat result');"); + CHECK_CALLED(testobj_value); + + SET_EXPECT(global_propget_d); + SET_EXPECT(global_propget_i); + parse_script_a("this.testPropGet;"); + CHECK_CALLED(global_propget_d); + CHECK_CALLED(global_propget_i); + + SET_EXPECT(global_propget_d); + SET_EXPECT(global_propget_i); + parse_script_a("(function () { this.testPropGet; })();"); + CHECK_CALLED(global_propget_d); + CHECK_CALLED(global_propget_i); + + parse_script_a("testThis(this);"); + parse_script_a("(function () { testThis(this); })();"); + + run_from_res("lang.js"); + run_from_res("api.js"); + run_from_res("regexp.js"); + + test_isvisible(FALSE); + test_isvisible(TRUE); + + parse_script_af(0, "test.testThis2(this);"); + parse_script_af(0, "(function () { test.testThis2(this); })();"); + + hres = parse_htmlscript_a(""); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + hres = parse_htmlscript_a("\n"); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + hres = parse_htmlscript_a("\n"); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + hres = parse_htmlscript_a("var a=1;\nif(a-->0) a=5;\n"); + ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres); + hres = parse_htmlscript_a("var a=1;\nif(a\n-->0) a=5;\n"); + ok(hres != S_OK, "ParseScriptText have not failed\n"); +} + +START_TEST(run) +{ + int argc; + char **argv; + + argc = winetest_get_mainargs(&argv); + + CoInitialize(NULL); + + if(argc > 2) + run_from_file(argv[2]); + else + run_tests(); + + CoUninitialize(); +} diff --git a/rostests/winetests/jscript/testlist.c b/rostests/winetests/jscript/testlist.c new file mode 100644 index 00000000000..fd13233a49b --- /dev/null +++ b/rostests/winetests/jscript/testlist.c @@ -0,0 +1,17 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_jscript(void); +extern void func_run(void); + +const struct test winetest_testlist[] = +{ + { "jscript", func_jscript }, + { "run", func_run }, + { 0, 0 } +}; diff --git a/rostests/winetests/kernel32/actctx.c b/rostests/winetests/kernel32/actctx.c index 4bc6135931f..8a8d03e224e 100644 --- a/rostests/winetests/kernel32/actctx.c +++ b/rostests/winetests/kernel32/actctx.c @@ -17,7 +17,7 @@ */ #include "wine/test.h" -#include +#include #include #include #include @@ -43,6 +43,14 @@ static const char* strw(LPCWSTR x) return buffer; } +#ifdef __i386__ +#define ARCH "x86" +#elif defined __x86_64__ +#define ARCH "amd64" +#else +#define ARCH "none" +#endif + static const char manifest1[] = "" "" @@ -54,7 +62,7 @@ static const char manifest2[] = "" "" "" -"" +"" "" "" "" @@ -76,7 +84,7 @@ static const char manifest4[] = "" "" "" + "version=\"6.0.1.0\" processorArchitecture=\"" ARCH "\" publicKeyToken=\"6595b64144ccf1df\">" "" "" "" @@ -84,19 +92,19 @@ static const char manifest4[] = static const char testdep_manifest1[] = "" -"" +"" ""; static const char testdep_manifest2[] = "" -"" +"" "" "" ""; static const char testdep_manifest3[] = " " -"" +"" "" "" "wndClass" @@ -138,7 +146,7 @@ static const char wrong_manifest6[] = static const char wrong_manifest7[] = "" -"" +"" "" ""; @@ -150,7 +158,7 @@ static const char wrong_manifest8[] = static const char wrong_depmanifest1[] = "" -"" +"" ""; static const WCHAR testlib_dll[] = @@ -223,7 +231,7 @@ static BOOL create_wide_manifest(const char *filename, const char *manifest, BOO BOOL ret; int offset = (fBOM ? 0 : 1); - MultiByteToWideChar(CP_ACP, 0, manifest, -1, &wmanifest[1], (strlen(manifest)+1) * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, manifest, -1, &wmanifest[1], (strlen(manifest)+1)); wmanifest[0] = 0xfeff; if (fReverse) { @@ -238,7 +246,8 @@ static BOOL create_wide_manifest(const char *filename, const char *manifest, BOO typedef struct { ULONG format_version; - ULONG assembly_cnt; + ULONG assembly_cnt_min; + ULONG assembly_cnt_max; ULONG root_manifest_type; LPWSTR root_manifest_path; ULONG root_config_type; @@ -247,23 +256,24 @@ typedef struct { } detailed_info_t; static const detailed_info_t detailed_info0 = { - 0, 0, 0, NULL, 0, 0, NULL + 0, 0, 0, 0, NULL, 0, 0, NULL }; static const detailed_info_t detailed_info1 = { - 1, 1, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, manifest_path, + 1, 1, 1, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, manifest_path, ACTIVATION_CONTEXT_PATH_TYPE_NONE, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, work_dir, }; static const detailed_info_t detailed_info1_child = { - 1, 1, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, app_manifest_path, + 1, 1, 1, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, app_manifest_path, ACTIVATION_CONTEXT_PATH_TYPE_NONE, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, app_dir, }; +/* On Vista+, there's an extra assembly for Microsoft.Windows.Common-Controls.Resources */ static const detailed_info_t detailed_info2 = { - 1, 2, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, manifest_path, + 1, 2, 3, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, manifest_path, ACTIVATION_CONTEXT_PATH_TYPE_NONE, ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE, work_dir, }; @@ -302,9 +312,10 @@ static void test_detailed_info(HANDLE handle, const detailed_info_t *exinfo) ok(detailed_info->ulFormatVersion == exinfo->format_version, "detailed_info->ulFormatVersion=%u, expected %u\n", detailed_info->ulFormatVersion, exinfo->format_version); - ok(detailed_info->ulAssemblyCount == exinfo->assembly_cnt, - "detailed_info->ulAssemblyCount=%u, expected %u\n", detailed_info->ulAssemblyCount, - exinfo->assembly_cnt); + ok(exinfo->assembly_cnt_min <= detailed_info->ulAssemblyCount && + detailed_info->ulAssemblyCount <= exinfo->assembly_cnt_max, + "detailed_info->ulAssemblyCount=%u, expected between %u and %u\n", detailed_info->ulAssemblyCount, + exinfo->assembly_cnt_min, exinfo->assembly_cnt_max); ok(detailed_info->ulRootManifestPathType == exinfo->root_manifest_type, "detailed_info->ulRootManifestPathType=%u, expected %u\n", detailed_info->ulRootManifestPathType, exinfo->root_manifest_type); @@ -386,21 +397,21 @@ static const info_in_assembly manifest4_info = { static const info_in_assembly depmanifest1_info = { 0x10, depmanifest_path, - "testdep,processorArchitecture=\"x86\"," + "testdep,processorArchitecture=\"" ARCH "\"," "type=\"win32\",version=\"6.5.4.3\"", TRUE }; static const info_in_assembly depmanifest2_info = { 0x10, depmanifest_path, - "testdep,processorArchitecture=\"x86\"," + "testdep,processorArchitecture=\"" ARCH "\"," "type=\"win32\",version=\"6.5.4.3\"", TRUE }; static const info_in_assembly depmanifest3_info = { 0x10, depmanifest_path, - "testdep,processorArchitecture=\"x86\",type=\"win32\",version=\"6.5.4.3\"", + "testdep,processorArchitecture=\"" ARCH "\",type=\"win32\",version=\"6.5.4.3\"", TRUE }; @@ -851,6 +862,42 @@ static void test_find_string_fail(void) ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%u\n", GetLastError()); } + +static void test_basic_info(HANDLE handle) +{ + ACTIVATION_CONTEXT_BASIC_INFORMATION basic; + SIZE_T size; + BOOL b; + + b = pQueryActCtxW(0, handle, NULL, + ActivationContextBasicInformation, &basic, + sizeof(basic), &size); + + ok (b,"ActivationContextBasicInformation failed\n"); + ok (size == sizeof(ACTIVATION_CONTEXT_BASIC_INFORMATION),"size mismatch\n"); + ok (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok (basic.hActCtx == handle, "unexpected handle\n"); + + b = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, NULL, + ActivationContextBasicInformation, &basic, + sizeof(basic), &size); + if (handle) + { + ok (!b,"ActivationContextBasicInformation succeeded\n"); + ok (size == 0,"size mismatch\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, "Wrong last error\n"); + ok (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok (basic.hActCtx == handle, "unexpected handle\n"); + } + else + { + ok (b,"ActivationContextBasicInformation failed\n"); + ok (size == sizeof(ACTIVATION_CONTEXT_BASIC_INFORMATION),"size mismatch\n"); + ok (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok (basic.hActCtx == handle, "unexpected handle\n"); + } +} + static void test_actctx(void) { ULONG_PTR cookie; @@ -865,6 +912,7 @@ static void test_actctx(void) ok(handle == NULL, "handle = %p, expected NULL\n", handle); ok(b, "GetCurrentActCtx failed: %u\n", GetLastError()); if(b) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info0); pReleaseActCtx(handle); } @@ -879,6 +927,7 @@ static void test_actctx(void) handle = test_create("test1.manifest", manifest1); DeleteFileA("test1.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest1_info); @@ -904,6 +953,7 @@ static void test_actctx(void) DeleteFileA("test2.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info2); test_info_in_assembly(handle, 1, &manifest2_info); test_info_in_assembly(handle, 2, &depmanifest1_info); @@ -921,6 +971,7 @@ static void test_actctx(void) DeleteFileA("test3.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info2); test_info_in_assembly(handle, 1, &manifest2_info); test_info_in_assembly(handle, 2, &depmanifest2_info); @@ -948,6 +999,7 @@ static void test_actctx(void) DeleteFileA("test2-3.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info2); test_info_in_assembly(handle, 1, &manifest2_info); test_info_in_assembly(handle, 2, &depmanifest3_info); @@ -976,6 +1028,7 @@ static void test_actctx(void) handle = test_create("test3.manifest", manifest3); DeleteFileA("test3.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest3_info); test_file_info(handle, 0, 0, testlib_dll); @@ -1002,6 +1055,7 @@ static void test_actctx(void) DeleteFileA("test4.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info2); test_info_in_assembly(handle, 1, &manifest4_info); test_info_in_assembly(handle, 2, &manifest_comctrl_info); @@ -1020,6 +1074,7 @@ static void test_actctx(void) handle = test_create("..\\test1.manifest", manifest1); DeleteFileA("..\\test1.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest1_info); pReleaseActCtx(handle); @@ -1039,6 +1094,7 @@ static void test_actctx(void) handle = test_create("test1.manifest", manifest1); DeleteFileA("test1.manifest"); if (handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest1_info); pReleaseActCtx(handle); @@ -1053,6 +1109,7 @@ static void test_actctx(void) handle = test_create("test1.manifest", manifest1); DeleteFileA("test1.manifest"); if (handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest1_info); pReleaseActCtx(handle); @@ -1071,6 +1128,7 @@ static void test_app_manifest(void) ok(handle == NULL, "handle != NULL\n"); ok(b, "GetCurrentActCtx failed: %u\n", GetLastError()); if(b) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1_child); test_info_in_assembly(handle, 1, &manifest1_child_info); pReleaseActCtx(handle); @@ -1084,6 +1142,8 @@ static void run_child_process(void) char **argv; PROCESS_INFORMATION pi; STARTUPINFO si = { 0 }; + HANDLE file; + FILETIME now; GetModuleFileNameA(NULL, path, MAX_PATH); strcat(path, ".manifest"); @@ -1094,6 +1154,15 @@ static void run_child_process(void) si.cb = sizeof(si); winetest_get_mainargs( &argv ); + /* Vista+ seems to cache presence of .manifest files. Change last modified + date to defeat the cache */ + file = CreateFileA(argv[0], FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (file != INVALID_HANDLE_VALUE) { + GetSystemTimeAsFileTime(&now); + SetFileTime(file, NULL, NULL, &now); + CloseHandle(file); + } sprintf(cmdline, "\"%s\" %s manifest1", argv[0], argv[1]); ok(CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) != 0, "Could not create process: %u\n", GetLastError()); @@ -1155,7 +1224,7 @@ START_TEST(actctx) if (!init_funcs()) { - skip("Needed functions are not available\n"); + win_skip("Needed functions are not available\n"); return; } init_paths(); diff --git a/rostests/winetests/kernel32/atom.c b/rostests/winetests/kernel32/atom.c index fcf60e2765d..84013b94af3 100755 --- a/rostests/winetests/kernel32/atom.c +++ b/rostests/winetests/kernel32/atom.c @@ -77,7 +77,7 @@ static BOOL unicode_OS; static void test_add_atom(void) { ATOM atom, w_atom; - int i; + INT_PTR i; SetLastError( 0xdeadbeef ); atom = GlobalAddAtomA( "foobar" ); @@ -129,20 +129,20 @@ static void test_add_atom(void) { SetLastError( 0xdeadbeef ); ok( GlobalAddAtomA((LPCSTR)i) == i && GetLastError() == 0xdeadbeef, - "failed to add atom %x\n", i ); + "failed to add atom %lx\n", i ); if (unicode_OS) { SetLastError( 0xdeadbeef ); ok( GlobalAddAtomW((LPCWSTR)i) == i && GetLastError() == 0xdeadbeef, - "failed to add atom %x\n", i ); + "failed to add atom %lx\n", i ); } } for (i = 0xc000; i <= 0xffff; i++) { - ok( !GlobalAddAtomA((LPCSTR)i), "succeeded adding %x\n", i ); + ok( !GlobalAddAtomA((LPCSTR)i), "succeeded adding %lx\n", i ); if (unicode_OS) - ok( !GlobalAddAtomW((LPCWSTR)i), "succeeded adding %x\n", i ); + ok( !GlobalAddAtomW((LPCWSTR)i), "succeeded adding %lx\n", i ); } } @@ -201,6 +201,7 @@ static void test_get_atom_name(void) sprintf( res, "#%d", i ); memset( res + strlen(res) + 1, 'a', 10 ); ok( !memcmp( res, buf, 10 ), "bad buffer contents %s\n", buf ); + if (len <= 1 || len >= 7) break; /* don't bother testing all of them */ } else ok( !len, "bad length %d\n", len ); @@ -283,6 +284,7 @@ static void test_get_atom_name(void) print_integral( res, i ); memset( res + lstrlenW(res) + 1, 'a', 10 * sizeof(WCHAR)); ok( !memcmp( res, outW, 10 * sizeof(WCHAR) ), "bad buffer contents for %d\n", i ); + if (len <= 1 || len >= 7) break; /* don't bother testing all of them */ } else ok( !len, "bad length %d\n", len ); @@ -304,7 +306,7 @@ static void test_get_atom_name(void) do_initW(inW, "abcdefghij", 255); atom = GlobalAddAtomW(inW); ok(atom, "couldn't add atom for %s\n", in); - len = GlobalGetAtomNameW(atom, outW, sizeof(outW)); + len = GlobalGetAtomNameW(atom, outW, sizeof(outW)/sizeof(outW[0])); ok(len == 255, "length mismatch (%u instead of 255)\n", len); for (i = 0; i < 255; i++) { @@ -349,7 +351,7 @@ static void test_error_handling(void) static void test_local_add_atom(void) { ATOM atom, w_atom; - int i; + INT_PTR i; SetLastError( 0xdeadbeef ); atom = AddAtomA( "foobar" ); @@ -401,20 +403,20 @@ static void test_local_add_atom(void) { SetLastError( 0xdeadbeef ); ok( AddAtomA((LPCSTR)i) == i && GetLastError() == 0xdeadbeef, - "failed to add atom %x\n", i ); + "failed to add atom %lx\n", i ); if (unicode_OS) { SetLastError( 0xdeadbeef ); ok( AddAtomW((LPCWSTR)i) == i && GetLastError() == 0xdeadbeef, - "failed to add atom %x\n", i ); + "failed to add atom %lx\n", i ); } } for (i = 0xc000; i <= 0xffff; i++) { - ok( !AddAtomA((LPCSTR)i), "succeeded adding %x\n", i ); + ok( !AddAtomA((LPCSTR)i), "succeeded adding %lx\n", i ); if (unicode_OS) - ok( !AddAtomW((LPCWSTR)i), "succeeded adding %x\n", i ); + ok( !AddAtomW((LPCWSTR)i), "succeeded adding %lx\n", i ); } } @@ -617,6 +619,10 @@ static void test_local_error_handling(void) START_TEST(atom) { + /* Global atom table seems to be available to GUI apps only in + Win7, so let's turn this app into a GUI app */ + GetDesktopWindow(); + test_add_atom(); test_get_atom_name(); test_error_handling(); diff --git a/rostests/winetests/kernel32/change.c b/rostests/winetests/kernel32/change.c index cdba120e95d..50d899a424f 100755 --- a/rostests/winetests/kernel32/change.c +++ b/rostests/winetests/kernel32/change.c @@ -38,7 +38,7 @@ static DWORD CALLBACK NotificationThread(LPVOID arg) { - HANDLE change = (HANDLE) arg; + HANDLE change = arg; BOOL notified = FALSE; BOOL ret = FALSE; DWORD status; @@ -65,8 +65,7 @@ static HANDLE StartNotificationThread(LPCSTR path, BOOL subtree, DWORD flags) change = FindFirstChangeNotificationA(path, subtree, flags); ok(change != INVALID_HANDLE_VALUE, "FindFirstChangeNotification error: %d\n", GetLastError()); - thread = CreateThread(NULL, 0, NotificationThread, (LPVOID)change, - 0, &threadId); + thread = CreateThread(NULL, 0, NotificationThread, change, 0, &threadId); ok(thread != NULL, "CreateThread error: %d\n", GetLastError()); return thread; @@ -223,6 +222,7 @@ static void test_FindFirstChangeNotification(void) file = CreateFileA(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %d\n", GetLastError()); + memset(buffer, 0, sizeof(buffer)); ret = WriteFile(file, buffer, sizeof(buffer), &count, NULL); ok(ret && count == sizeof(buffer), "WriteFile error: %d\n", GetLastError()); ret = CloseHandle(file); @@ -263,7 +263,7 @@ static void test_ffcn(void) r = GetTempPathW( MAX_PATH, path ); if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("GetTempPathW is not implemented\n"); + win_skip("GetTempPathW is not implemented\n"); return; } ok( r != 0, "temp path failed\n"); @@ -355,8 +355,8 @@ static void test_ffcnMultipleThreads(void) * directory object with an empty wine user APC queue for this thread (bug #7286) */ /* Create our notification thread */ - handles[1] = CreateThread(NULL, 0, NotificationThread, (LPVOID)handles[0], - 0, &threadId); + handles[1] = CreateThread(NULL, 0, NotificationThread, handles[0], 0, + &threadId); ok(handles[1] != NULL, "CreateThread error: %d\n", GetLastError()); status = WaitForMultipleObjects(2, handles, FALSE, 5000); @@ -386,7 +386,7 @@ static void test_readdirectorychanges(void) if (!pReadDirectoryChangesW) { - skip("ReadDirectoryChangesW is not available\n"); + win_skip("ReadDirectoryChangesW is not available\n"); return; } @@ -394,7 +394,7 @@ static void test_readdirectorychanges(void) r = GetTempPathW( MAX_PATH, path ); if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("GetTempPathW is not implemented\n"); + win_skip("GetTempPathW is not implemented\n"); return; } ok( r != 0, "temp path failed\n"); @@ -559,8 +559,8 @@ static void test_readdirectorychanges(void) pfni = (PFILE_NOTIFY_INFORMATION) buffer; ok( pfni->NextEntryOffset == 0, "offset wrong\n" ); ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" ); - ok( pfni->FileNameLength == 0x0c, "len wrong\n" ); - ok( !memcmp(pfni->FileName,&szGa[1],6), "name wrong\n" ); + ok( pfni->FileNameLength == 6*sizeof(WCHAR), "len wrong\n" ); + ok( !memcmp(pfni->FileName,&szGa[1],6*sizeof(WCHAR)), "name wrong\n" ); r = RemoveDirectoryW( subsubdir ); ok( r == TRUE, "failed to remove directory\n"); @@ -577,13 +577,21 @@ static void test_readdirectorychanges(void) ok( r == WAIT_OBJECT_0, "should be ready\n" ); pfni = (PFILE_NOTIFY_INFORMATION) buffer; - ok( pfni->NextEntryOffset == 0, "offset wrong\n" ); - ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong\n" ); - ok( pfni->FileNameLength == 0x0c, "len wrong\n" ); - ok( !memcmp(pfni->FileName,&szGa[1],6), "name wrong\n" ); + /* we may get a notification for the parent dir too */ + if (pfni->Action == FILE_ACTION_MODIFIED && pfni->NextEntryOffset) + { + ok( pfni->FileNameLength == 3*sizeof(WCHAR), "len wrong %u\n", pfni->FileNameLength ); + ok( !memcmp(pfni->FileName,&szGa[1],3*sizeof(WCHAR)), "name wrong\n" ); + pfni = (PFILE_NOTIFY_INFORMATION)((char *)pfni + pfni->NextEntryOffset); + } + ok( pfni->NextEntryOffset == 0, "offset wrong %u\n", pfni->NextEntryOffset ); + ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong %u\n", pfni->Action ); + ok( pfni->FileNameLength == 6*sizeof(WCHAR), "len wrong %u\n", pfni->FileNameLength ); + ok( !memcmp(pfni->FileName,&szGa[1],6*sizeof(WCHAR)), "name wrong\n" ); ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n"); - ok( ov.InternalHigh == 0x18, "ov.InternalHigh wrong\n"); + dwCount = (char *)&pfni->FileName[pfni->FileNameLength/sizeof(WCHAR)] - buffer; + ok( ov.InternalHigh == dwCount, "ov.InternalHigh wrong %lu/%u\n",ov.InternalHigh, dwCount ); CloseHandle(hdir); @@ -606,14 +614,14 @@ static void test_readdirectorychanges_null(void) if (!pReadDirectoryChangesW) { - skip("ReadDirectoryChangesW is not available\n"); + win_skip("ReadDirectoryChangesW is not available\n"); return; } SetLastError(0xdeadbeef); r = GetTempPathW( MAX_PATH, path ); if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("GetTempPathW is not implemented\n"); + win_skip("GetTempPathW is not implemented\n"); return; } ok( r != 0, "temp path failed\n"); @@ -708,7 +716,7 @@ static void test_readdirectorychanges_filedir(void) r = GetTempPathW( MAX_PATH, path ); if (!r && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("GetTempPathW is not implemented\n"); + win_skip("GetTempPathW is not implemented\n"); return; } ok( r != 0, "temp path failed\n"); @@ -839,8 +847,8 @@ static void test_ffcn_directory_overlap(void) ret = FindCloseChangeNotification(parent_watch); ok(ret, "FindCloseChangeNotification error: %d\n", GetLastError()); - child_thread = CreateThread(NULL, 0, NotificationThread, - (LPVOID)child_watch, 0, &threadId); + child_thread = CreateThread(NULL, 0, NotificationThread, child_watch, 0, + &threadId); ok(child_thread != NULL, "CreateThread error: %d\n", GetLastError()); /* Create a file in child */ diff --git a/rostests/winetests/kernel32/codepage.c b/rostests/winetests/kernel32/codepage.c index e8908f75c45..402e4bfdd35 100755 --- a/rostests/winetests/kernel32/codepage.c +++ b/rostests/winetests/kernel32/codepage.c @@ -2,6 +2,7 @@ * Unit tests for code page to/from unicode translations * * Copyright (c) 2002 Dmitry Timoshkov + * Copyright (c) 2008 Colin Finck * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -130,8 +131,10 @@ static void test_negative_source_length(void) SetLastError( 0xdeadbeef ); memset(buf,'x',sizeof(buf)); len = WideCharToMultiByte(CP_ACP, 0, foobarW, -2002, buf, 10, NULL, NULL); - ok(len == 7 && !lstrcmpA(buf, "foobar") && GetLastError() == 0xdeadbeef, + ok(len == 7 && GetLastError() == 0xdeadbeef, "WideCharToMultiByte(-2002): len=%d error=%u\n", len, GetLastError()); + ok(!lstrcmpA(buf, "foobar"), + "WideCharToMultiByte(-2002): expected \"foobar\" got \"%s\"\n", buf); SetLastError( 0xdeadbeef ); memset(bufW,'x',sizeof(bufW)); @@ -203,17 +206,165 @@ static void test_overlapped_buffers(void) char buf[256]; int ret; - memcpy((WCHAR *)(buf + 1), strW, sizeof(strW)); + SetLastError(0xdeadbeef); + memcpy(buf + 1, strW, sizeof(strW)); ret = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)(buf + 1), -1, buf, sizeof(buf), NULL, NULL); ok(ret == sizeof(strA), "unexpected ret %d\n", ret); ok(!memcmp(buf, strA, sizeof(strA)), "conversion failed: %s\n", buf); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); +} + +static void test_string_conversion(LPBOOL bUsedDefaultChar) +{ + char mbc; + char mbs[5]; + int ret; + WCHAR wc1 = 228; /* Western Windows-1252 character */ + WCHAR wc2 = 1088; /* Russian Windows-1251 character not displayable for Windows-1252 */ + WCHAR wcs[5] = {'T', 'h', 1088, 'i', 0}; /* String with ASCII characters and a Russian character */ + WCHAR dbwcs[3] = {28953, 25152, 0}; /* String with Chinese (codepage 950) characters */ + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + ok(mbc == -28, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, &wc2, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + ok(mbc == 63, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + if (IsValidCodePage(1251)) + { + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1251, 0, &wc2, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + ok(mbc == -16, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef || + broken(GetLastError() == 0), /* win95 */ + "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1251, 0, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + ok(mbc == 97, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + } + else + skip("Codepage 1251 not available\n"); + + /* This call triggers the last Win32 error */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, -1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 0, "ret is %d\n", ret); + ok(mbc == 84, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 5, "ret is %d\n", ret); + ok(!strcmp(mbs, "Th?i"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + mbs[0] = 0; + + /* WideCharToMultiByte mustn't add any null character automatically. + So in this case, we should get the same string again, even if we only copied the first three bytes. */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 3, "ret is %d\n", ret); + ok(!strcmp(mbs, "Th?i"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + ZeroMemory(mbs, 5); + + /* Now this shouldn't be the case like above as we zeroed the complete string buffer. */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 3, "ret is %d\n", ret); + ok(!strcmp(mbs, "Th?"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + /* Double-byte tests */ + ret = WideCharToMultiByte(1252, 0, dbwcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 3, "ret is %d\n", ret); + ok(!strcmp(mbs, "??"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + + /* Length-only tests */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, &wc2, 1, NULL, 0, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, -1, NULL, 0, NULL, bUsedDefaultChar); + ok(ret == 5, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + if (!IsValidCodePage(950)) + { + skip("Codepage 950 not available\n"); + return; + } + + /* Double-byte tests */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 5, "ret is %d\n", ret); + ok(!strcmp(mbs, "\xb5H\xa9\xd2"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 0, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %u\n", GetLastError()); + ZeroMemory(mbs, 5); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, 1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 2, "ret is %d\n", ret); + ok(!strcmp(mbs, "\xb5H"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + /* Length-only tests */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, 1, NULL, 0, NULL, bUsedDefaultChar); + ok(ret == 2, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, -1, NULL, 0, NULL, bUsedDefaultChar); + ok(ret == 5, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); } START_TEST(codepage) { + BOOL bUsedDefaultChar; + test_destination_buffer(); test_null_source(); test_negative_source_length(); test_negative_dest_length(); test_overlapped_buffers(); + + /* WideCharToMultiByte has two code paths, test both here */ + test_string_conversion(NULL); + test_string_conversion(&bUsedDefaultChar); } diff --git a/rostests/winetests/kernel32/comm.c b/rostests/winetests/kernel32/comm.c index 36e46ad5c60..e7b515e9e2a 100755 --- a/rostests/winetests/kernel32/comm.c +++ b/rostests/winetests/kernel32/comm.c @@ -27,7 +27,7 @@ #define TIMEOUT 1000 /* one second for Timeouts*/ #define SLOWBAUD 150 #define FASTBAUD 115200 -#define TIMEDELTA 100 /* 100 ms uncertainty allowed */ +#define TIMEDELTA 150 /* 150 ms uncertainty allowed */ /* Define the appropriate LOOPBACK(s) TRUE if you have a Loopback cable with * the mentioned shorts connected to your Serial port @@ -561,6 +561,7 @@ static void test_BuildCommDCBW(TEST *ptest, int initial_value, DCB *pexpected_dc BOOL result; DCB dcb; WCHAR wide_string[sizeof(ptest->string)]; + static int reportedDCBW = 0; MultiByteToWideChar(CP_ACP, 0, ptest->string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR)); @@ -571,7 +572,11 @@ static void test_BuildCommDCBW(TEST *ptest, int initial_value, DCB *pexpected_dc result = BuildCommDCBW(wide_string, &dcb); if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + if(!reportedDCBW++) + win_skip("BuildCommDCBW is not implemented\n"); return; + } /* check results */ check_result("BuildCommDCBW", ptest, initial_value, result); @@ -584,6 +589,7 @@ static void test_BuildCommDCBAndTimeoutsW(TEST *ptest, int initial_value, DCB *p DCB dcb; COMMTIMEOUTS timeouts; WCHAR wide_string[sizeof(ptest->string)]; + static int reportedDCBAndTW = 0; MultiByteToWideChar(CP_ACP, 0, ptest->string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR)); @@ -595,12 +601,16 @@ static void test_BuildCommDCBAndTimeoutsW(TEST *ptest, int initial_value, DCB *p result = BuildCommDCBAndTimeoutsW(wide_string, &dcb, &timeouts); if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + if(!reportedDCBAndTW++) + win_skip("BuildCommDCBAndTimeoutsW is not implemented\n"); return; + } /* check results */ - check_result("BuildCommDCBAndTimeoutsA", ptest, initial_value, result); - check_dcb("BuildCommDCBAndTimeoutsA", ptest, initial_value, &dcb, pexpected_dcb); - check_timeouts("BuildCommDCBAndTimeoutsA", ptest, initial_value, &timeouts, pexpected_timeouts); + check_result("BuildCommDCBAndTimeoutsW", ptest, initial_value, result); + check_dcb("BuildCommDCBAndTimeoutsW", ptest, initial_value, &dcb, pexpected_dcb); + check_timeouts("BuildCommDCBAndTimeoutsW", ptest, initial_value, &timeouts, pexpected_timeouts); } static void test_BuildCommDCB(void) @@ -674,7 +684,7 @@ static HANDLE test_OpenComm(BOOL doOverlap) if (hcom == INVALID_HANDLE_VALUE) trace("Could not find a valid COM port. Skipping test_ReadTimeOut\n"); else - trace("Found Com port %s. Connected devices may disturbe results\n", port_name); + trace("Found Com port %s. Connected devices may disturb results\n", port_name); /*shown = TRUE; */ } if (hcom != INVALID_HANDLE_VALUE) @@ -682,9 +692,12 @@ static HANDLE test_OpenComm(BOOL doOverlap) BOOL ret; ret = ClearCommError(hcom, &errors, &comstat); - if (!ret && GetLastError() == ERROR_NOT_READY) + if (!ret && (GetLastError() == ERROR_NOT_READY || GetLastError() == ERROR_INVALID_HANDLE)) { + if (GetLastError() == ERROR_NOT_READY) trace("%s doesn't respond, skipping the test\n", port_name); + else + trace("%s is not a real serial port, skipping the test\n", port_name); CloseHandle(hcom); return INVALID_HANDLE_VALUE; } @@ -1161,15 +1174,14 @@ static void test_WaitRx(HANDLE hcom) */ static DWORD CALLBACK toggle_ctlLine(LPVOID arg) { - DWORD *args = (DWORD *) arg; + DWORD_PTR *args = arg; DWORD timeout = args[0]; DWORD ctl = args[1]; HANDLE hcom = (HANDLE) args[2]; HANDLE hComPortEvent = (HANDLE) args[3]; DWORD success, err; - trace("toggle_ctlLine timeout %d clt 0x%08x handle 0x%08x\n", - args[0], args[1], args[2]); + trace("toggle_ctlLine timeout %d ctl 0x%08x handle %p\n", timeout, ctl, hcom ); Sleep(timeout); ok(EscapeCommFunction(hcom, ctl),"EscapeCommFunction 0x%08x failed\n", ctl); trace("toggle_ctline done\n"); @@ -1190,8 +1202,8 @@ static void test_WaitCts(HANDLE hcom) OVERLAPPED overlapped; HANDLE hComPortEvent; HANDLE alarmThread; - DWORD args[4], defaultStat = 0; - DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0; + DWORD_PTR args[4]; + DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0; ok(GetCommState(hcom, &dcb), "GetCommState failed\n"); dcb.fRtsControl=RTS_CONTROL_ENABLE; @@ -1208,15 +1220,15 @@ static void test_WaitCts(HANDLE hcom) args[1] = CLRRTS; else args[1] = SETRTS; - args[2]=(DWORD) hcom; + args[2]=(DWORD_PTR)hcom; - trace("test_WaitCts timeout %d clt 0x%08x handle 0x%08x\n",args[0], args[1], args[2]); + trace("test_WaitCts timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom); ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n"); hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); ok(hComPortEvent != 0, "CreateEvent failed\n"); - args[3] = (DWORD) hComPortEvent; - alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId); + args[3] = (DWORD_PTR)hComPortEvent; + alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId); /* Wait a minimum to let the thread start up */ Sleep(10); trace("Thread created\n"); @@ -1265,7 +1277,7 @@ static void test_WaitCts(HANDLE hcom) */ static DWORD CALLBACK reset_CommMask(LPVOID arg) { - DWORD *args = (DWORD *) arg; + DWORD_PTR *args = arg; DWORD timeout = args[0]; HANDLE hcom = (HANDLE) args[1]; @@ -1287,7 +1299,7 @@ static void test_AbortWaitCts(HANDLE hcom) OVERLAPPED overlapped; HANDLE hComPortEvent; HANDLE alarmThread; - DWORD args[2]; + DWORD_PTR args[2]; DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0; ok(GetCommState(hcom, &dcb), "GetCommState failed\n"); @@ -1297,14 +1309,14 @@ static void test_AbortWaitCts(HANDLE hcom) return; } args[0]= TIMEOUT >>1; - args[1]=(DWORD) hcom; + args[1]= (DWORD_PTR)hcom; - trace("test_AbortWaitCts timeout %d handle 0x%08x\n",args[0], args[1]); + trace("test_AbortWaitCts timeout %ld handle %p\n",args[0], hcom); ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n"); hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); ok(hComPortEvent != 0, "CreateEvent failed\n"); - alarmThread = CreateThread(NULL, 0, reset_CommMask, (void *) &args, 0, &alarmThreadId); + alarmThread = CreateThread(NULL, 0, reset_CommMask, args, 0, &alarmThreadId); /* Wait a minimum to let the thread start up */ Sleep(10); trace("Thread created\n"); @@ -1348,8 +1360,8 @@ static void test_WaitDsr(HANDLE hcom) OVERLAPPED overlapped; HANDLE hComPortEvent; HANDLE alarmThread; - DWORD args[3], defaultStat = 0; - DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0; + DWORD_PTR args[3]; + DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0; ok(GetCommState(hcom, &dcb), "GetCommState failed\n"); if (dcb.fDtrControl == DTR_CONTROL_DISABLE) @@ -1363,14 +1375,14 @@ static void test_WaitDsr(HANDLE hcom) args[1] = CLRDTR; else args[1] = SETDTR; - args[2]=(DWORD) hcom; + args[2]= (DWORD_PTR)hcom; - trace("test_WaitDsr timeout %d clt 0x%08x handle 0x%08x\n",args[0], args[1], args[2]); + trace("test_WaitDsr timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom); ok(SetCommMask(hcom, EV_DSR), "SetCommMask failed\n"); hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); ok(hComPortEvent != 0, "CreateEvent failed\n"); - alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId); + alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId); ok(alarmThread !=0 , "CreateThread Failed\n"); ZeroMemory( &overlapped, sizeof(overlapped)); @@ -1421,8 +1433,8 @@ static void test_WaitRing(HANDLE hcom) OVERLAPPED overlapped; HANDLE hComPortEvent; HANDLE alarmThread; - DWORD args[3], defaultStat; - DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0; + DWORD_PTR args[3]; + DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat; BOOL ret; ok(GetCommState(hcom, &dcb), "GetCommState failed\n"); @@ -1441,14 +1453,14 @@ static void test_WaitRing(HANDLE hcom) args[1] = CLRDTR; else args[1] = SETDTR; - args[2]=(DWORD) hcom; + args[2]=(DWORD_PTR) hcom; - trace("test_WaitRing timeout %d clt 0x%08x handle 0x%08x\n",args[0], args[1], args[2]); + trace("test_WaitRing timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom); ok(SetCommMask(hcom, EV_RING), "SetCommMask failed\n"); hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); ok(hComPortEvent != 0, "CreateEvent failed\n"); - alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId); + alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId); ok(alarmThread !=0 , "CreateThread Failed\n"); ZeroMemory( &overlapped, sizeof(overlapped)); @@ -1498,8 +1510,8 @@ static void test_WaitDcd(HANDLE hcom) OVERLAPPED overlapped; HANDLE hComPortEvent; HANDLE alarmThread; - DWORD args[3], defaultStat = 0; - DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0; + DWORD_PTR args[3]; + DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0; ok(GetCommState(hcom, &dcb), "GetCommState failed\n"); if (dcb.fDtrControl == DTR_CONTROL_DISABLE) @@ -1513,14 +1525,14 @@ static void test_WaitDcd(HANDLE hcom) args[1] = CLRDTR; else args[1] = SETDTR; - args[2]=(DWORD) hcom; + args[2]= (DWORD_PTR)hcom; - trace("test_WaitDcd timeout %d clt 0x%08x handle 0x%08x\n",args[0], args[1], args[2]); + trace("test_WaitDcd timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom); ok(SetCommMask(hcom, EV_RLSD), "SetCommMask failed\n"); hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); ok(hComPortEvent != 0, "CreateEvent failed\n"); - alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId); + alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId); ok(alarmThread !=0 , "CreateThread Failed\n"); ZeroMemory( &overlapped, sizeof(overlapped)); @@ -1566,7 +1578,7 @@ static void test_WaitDcd(HANDLE hcom) */ static DWORD CALLBACK set_CommBreak(LPVOID arg) { - DWORD *args = (DWORD *) arg; + DWORD_PTR *args = arg; DWORD timeout = args[0]; HANDLE hcom = (HANDLE) args[1]; @@ -1587,7 +1599,7 @@ static void test_WaitBreak(HANDLE hcom) OVERLAPPED overlapped; HANDLE hComPortEvent; HANDLE alarmThread; - DWORD args[2]; + DWORD_PTR args[2]; DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0; ok(SetCommMask(hcom, EV_BREAK), "SetCommMask failed\n"); @@ -1596,8 +1608,8 @@ static void test_WaitBreak(HANDLE hcom) trace("test_WaitBreak\n"); args[0]= TIMEOUT >>1; - args[1]=(DWORD) hcom; - alarmThread = CreateThread(NULL, 0, set_CommBreak, (void *) &args, 0, &alarmThreadId); + args[1]= (DWORD_PTR)hcom; + alarmThread = CreateThread(NULL, 0, set_CommBreak, args, 0, &alarmThreadId); /* Wait a minimum to let the thread start up */ Sleep(10); trace("Thread created\n"); @@ -1634,6 +1646,16 @@ static void test_WaitBreak(HANDLE hcom) ok(ClearCommBreak(hcom), "ClearCommBreak failed\n"); } +static void test_stdio(void) +{ + DCB dcb; + + /* cygwin tries this to determine the stdin handle type */ + ok( !GetCommState( GetStdHandle(STD_INPUT_HANDLE), &dcb ), "GetCommState succeeded on stdin\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_INVALID_FUNCTION, + "got error %u\n", GetLastError() ); +} + START_TEST(comm) { HANDLE hcom; @@ -1726,4 +1748,5 @@ START_TEST(comm) test_WaitBreak(hcom); CloseHandle(hcom); } + test_stdio(); } diff --git a/rostests/winetests/kernel32/console.c b/rostests/winetests/kernel32/console.c index aacae9cb23c..f9fcdfd9957 100755 --- a/rostests/winetests/kernel32/console.c +++ b/rostests/winetests/kernel32/console.c @@ -130,7 +130,79 @@ static void testCursor(HANDLE hCon, COORD sbSize) ERROR_INVALID_PARAMETER, GetLastError()); } -static void testWriteSimple(HANDLE hCon, COORD sbSize) +static void testCursorInfo(HANDLE hCon) +{ + BOOL ret; + CONSOLE_CURSOR_INFO info; + + SetLastError(0xdeadbeef); + ret = GetConsoleCursorInfo(NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n", + ERROR_INVALID_HANDLE, GetLastError()); + + SetLastError(0xdeadbeef); + info.dwSize = -1; + ret = GetConsoleCursorInfo(NULL, &info); + ok(!ret, "Expected failure\n"); + ok(info.dwSize == -1, "Expected no change for dwSize\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n", + ERROR_INVALID_HANDLE, GetLastError()); + + /* Test the correct call first to distinguish between win9x and the rest */ + SetLastError(0xdeadbeef); + ret = GetConsoleCursorInfo(hCon, &info); + ok(ret, "Expected success\n"); + ok(info.dwSize == 25 || + info.dwSize == 12 /* win9x */, + "Expected 12 or 25, got %d\n", info.dwSize); + ok(info.bVisible, "Expected the cursor to be visible\n"); + ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n", + 0xdeadbeef, GetLastError()); + + /* Don't test NULL CONSOLE_CURSOR_INFO, it crashes on win9x and win7 */ +} + +static void testEmptyWrite(HANDLE hCon) +{ + COORD c; + DWORD len; + const char* mytest = ""; + + c.X = c.Y = 0; + ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n"); + + len = -1; + ok(WriteConsole(hCon, NULL, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n"); + okCURSOR(hCon, c); + + /* Passing a NULL lpBuffer with sufficiently large non-zero length succeeds + * on native Windows and result in memory-like contents being written to + * the console. Calling WriteConsoleW like this will crash on Wine. */ + if (0) + { + len = -1; + ok(!WriteConsole(hCon, NULL, 16, &len, NULL) && len == -1, "WriteConsole\n"); + okCURSOR(hCon, c); + + /* Cursor advances for this call. */ + len = -1; + ok(WriteConsole(hCon, NULL, 128, &len, NULL) != 0 && len == 128, "WriteConsole\n"); + } + + len = -1; + ok(WriteConsole(hCon, mytest, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n"); + okCURSOR(hCon, c); + + /* WriteConsole does not halt on a null terminator and is happy to write + * memory contents beyond the actual size of the buffer. */ + len = -1; + ok(WriteConsole(hCon, mytest, 16, &len, NULL) != 0 && len == 16, "WriteConsole\n"); + c.X += 16; + okCURSOR(hCon, c); +} + +static void testWriteSimple(HANDLE hCon) { COORD c; DWORD len; @@ -198,6 +270,7 @@ static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize) const int mylen = strlen(mytest); const int mylen2 = strchr(mytest, '\n') - mytest; int p; + WORD attr; ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT), "clearing wrap at EOL & setting processed output\n"); @@ -212,6 +285,15 @@ static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize) { okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB); } + + ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len); + /* Win9x and WinMe change the attribs for '\n' up to 'f' */ + if (attr == TEST_ATTRIB) + { + win_skip("Win9x/WinMe don't respect ~ENABLE_WRAP_AT_EOL_OUTPUT\n"); + return; + } + okCHAR(hCon, c, ' ', DEFAULT_ATTRIB); c.X = 0; c.Y++; @@ -309,6 +391,7 @@ static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize) const char* mytest = "abcd\nf\tg"; const int mylen = strlen(mytest); int p; + WORD attr; ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)), "setting wrap at EOL & processed output\n"); @@ -324,6 +407,10 @@ static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize) okCHAR(hCon, c, mytest[p], TEST_ATTRIB); } c.X = sbSize.X - 9 + p; + ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len); + if (attr == TEST_ATTRIB) + win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n"); + else okCHAR(hCon, c, ' ', DEFAULT_ATTRIB); c.X = 0; c.Y++; okCHAR(hCon, c, mytest[5], TEST_ATTRIB); @@ -347,6 +434,10 @@ static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize) c.X = 0; c.Y++; okCHAR(hCon, c, mytest[3], TEST_ATTRIB); c.X++; + ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len); + if (attr == TEST_ATTRIB) + win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n"); + else okCHAR(hCon, c, ' ', DEFAULT_ATTRIB); c.X = 0; c.Y++; @@ -364,7 +455,9 @@ static void testWrite(HANDLE hCon, COORD sbSize) /* FIXME: should in fact insure that the sb is at least 10 character wide */ ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n"); resetContent(hCon, sbSize, FALSE); - testWriteSimple(hCon, sbSize); + testEmptyWrite(hCon); + resetContent(hCon, sbSize, FALSE); + testWriteSimple(hCon); resetContent(hCon, sbSize, FALSE); testWriteNotWrappedNotProcessed(hCon, sbSize); resetContent(hCon, sbSize, FALSE); @@ -622,7 +715,7 @@ static void testScreenBuffer(HANDLE hConOut) ret = SetConsoleOutputCP(866); if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("SetConsoleOutputCP is not implemented\n"); + win_skip("SetConsoleOutputCP is not implemented\n"); return; } ok(ret, "Cannot set output codepage to 866\n"); @@ -858,11 +951,14 @@ START_TEST(console) ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n"); ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n"); - ok(ret = GetConsoleScreenBufferInfo(hConOut, &sbi), "Getting sb info\n"); + ret = GetConsoleScreenBufferInfo(hConOut, &sbi); + ok(ret, "Getting sb info\n"); if (!ret) return; /* Non interactive tests */ testCursor(hConOut, sbi.dwSize); + /* test parameters (FIXME: test functionality) */ + testCursorInfo(hConOut); /* will test wrapped (on/off) & processed (on/off) strings output */ testWrite(hConOut, sbi.dwSize); /* will test line scrolling at the bottom of the screen */ @@ -876,7 +972,7 @@ START_TEST(console) if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA) { - skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n"); + win_skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n"); return; } else diff --git a/rostests/winetests/kernel32/debugger.c b/rostests/winetests/kernel32/debugger.c index ac7c7e1ebe2..0fb107fa8a7 100644 --- a/rostests/winetests/kernel32/debugger.c +++ b/rostests/winetests/kernel32/debugger.c @@ -20,9 +20,11 @@ #include #include -#include + +#define WIN32_NO_STATUS #include #include +#include #include "wine/test.h" #ifndef STATUS_DEBUGGER_INACTIVE @@ -32,6 +34,7 @@ static int myARGC; static char** myARGV; +static BOOL (WINAPI *pCheckRemoteDebuggerPresent)(HANDLE,PBOOL); static BOOL (WINAPI *pDebugActiveProcessStop)(DWORD); static BOOL (WINAPI *pDebugSetProcessKillOnExit)(BOOL); @@ -45,6 +48,40 @@ static void get_file_name(char* buf) GetTempFileNameA(path, "wt", 0, buf); } +typedef struct tag_reg_save_value +{ + const char *name; + DWORD type; + BYTE *data; + DWORD size; +} reg_save_value; + +static DWORD save_value(HKEY hkey, const char *value, reg_save_value *saved) +{ + DWORD ret; + saved->name=value; + saved->data=0; + saved->size=0; + ret=RegQueryValueExA(hkey, value, NULL, &saved->type, NULL, &saved->size); + if (ret == ERROR_SUCCESS) + { + saved->data=HeapAlloc(GetProcessHeap(), 0, saved->size); + RegQueryValueExA(hkey, value, NULL, &saved->type, saved->data, &saved->size); + } + return ret; +} + +static void restore_value(HKEY hkey, reg_save_value *saved) +{ + if (saved->data) + { + RegSetValueExA(hkey, saved->name, 0, saved->type, saved->data, saved->size); + HeapFree(GetProcessHeap(), 0, saved->data); + } + else + RegDeleteValueA(hkey, saved->name); +} + static void get_events(const char* name, HANDLE *start_event, HANDLE *done_event) { const char* basename; @@ -131,12 +168,13 @@ static void doDebugger(int argc, char** argv) { const char* logfile; debugger_blackbox_t blackbox; - HANDLE start_event, done_event, debug_event; + HANDLE start_event = 0, done_event = 0, debug_event; blackbox.argc=argc; logfile=(argc >= 4 ? argv[3] : NULL); blackbox.pid=(argc >= 5 ? atol(argv[4]) : 0); + blackbox.attach_err=0; if (strstr(myARGV[2], "attach")) { blackbox.attach_rc=DebugActiveProcess(blackbox.pid); @@ -146,7 +184,8 @@ static void doDebugger(int argc, char** argv) else blackbox.attach_rc=TRUE; - debug_event=(argc >= 6 ? (HANDLE)atol(argv[5]) : NULL); + debug_event=(argc >= 6 ? (HANDLE)(INT_PTR)atol(argv[5]) : NULL); + blackbox.debug_err=0; if (debug_event && strstr(myARGV[2], "event")) { blackbox.debug_rc=SetEvent(debug_event); @@ -156,13 +195,18 @@ static void doDebugger(int argc, char** argv) else blackbox.debug_rc=TRUE; + if (logfile) + { get_events(logfile, &start_event, &done_event); + } + if (strstr(myARGV[2], "order")) { trace("debugger: waiting for the start signal...\n"); WaitForSingleObject(start_event, INFINITE); } + blackbox.nokill_err=0; if (strstr(myARGV[2], "nokill")) { blackbox.nokill_rc=pDebugSetProcessKillOnExit(FALSE); @@ -172,6 +216,7 @@ static void doDebugger(int argc, char** argv) else blackbox.nokill_rc=TRUE; + blackbox.detach_err=0; if (strstr(myARGV[2], "detach")) { blackbox.detach_rc=pDebugActiveProcessStop(blackbox.pid); @@ -181,7 +226,10 @@ static void doDebugger(int argc, char** argv) else blackbox.detach_rc=TRUE; + if (logfile) + { save_blackbox(logfile, &blackbox, sizeof(blackbox)); + } trace("debugger: done debugging...\n"); SetEvent(done_event); @@ -235,13 +283,17 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks) /* If, after attaching to the debuggee, the debugger exits without * detaching, then the debuggee gets a special exit code. */ - ok(exit_code == 0xffffffff || /* Win 9x */ - exit_code == 0x80 || /* NT4 */ - exit_code == STATUS_DEBUGGER_INACTIVE, /* Win >= XP */ + ok(exit_code == STATUS_DEBUGGER_INACTIVE || + broken(exit_code == STATUS_ACCESS_VIOLATION) || /* Intermittent Vista+ */ + broken(exit_code == 0xffffffff) || /* Win9x */ + broken(exit_code == WAIT_ABANDONED), /* NT4, W2K */ "wrong exit code : %08x\n", exit_code); } else - ok(exit_code == STATUS_ACCESS_VIOLATION, "exit code = %08x instead of STATUS_ACCESS_VIOLATION\n", exit_code); + ok(exit_code == STATUS_ACCESS_VIOLATION || + broken(exit_code == WAIT_ABANDONED) || /* NT4, W2K, W2K3 */ + broken(exit_code == 0xffffffff), /* Win9x, WinME */ + "wrong exit code : %08x\n", exit_code); CloseHandle(info.hProcess); /* ...before the debugger */ @@ -298,14 +350,13 @@ static void crash_and_winedbg(HKEY hkey, const char* argv0) static void test_ExitCode(void) { static const char* AeDebug="Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"; + static const char* WineDbg="Software\\Wine\\WineDbg"; char test_exe[MAX_PATH]; DWORD ret; HKEY hkey; DWORD disposition; - LPBYTE auto_val=NULL; - DWORD auto_size, auto_type; - LPBYTE debugger_val=NULL; - DWORD debugger_size, debugger_type; + reg_save_value auto_value; + reg_save_value debugger_value; GetModuleFileNameA(GetModuleHandle(NULL), test_exe, sizeof(test_exe)); if (GetFileAttributes(test_exe) == INVALID_FILE_ATTRIBUTES) @@ -319,22 +370,10 @@ static void test_ExitCode(void) ret=RegCreateKeyExA(HKEY_LOCAL_MACHINE, AeDebug, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disposition); if (ret == ERROR_SUCCESS) { - auto_size=0; - ret=RegQueryValueExA(hkey, "auto", NULL, &auto_type, NULL, &auto_size); - if (ret == ERROR_SUCCESS) - { - auto_val=HeapAlloc(GetProcessHeap(), 0, auto_size); - RegQueryValueExA(hkey, "auto", NULL, &auto_type, auto_val, &auto_size); + save_value(hkey, "auto", &auto_value); + save_value(hkey, "debugger", &debugger_value); + trace("HKLM\\%s\\debugger is set to '%s'\n", AeDebug, debugger_value.data); } - - debugger_size=0; - ret=RegQueryValueExA(hkey, "debugger", NULL, &debugger_type, NULL, &debugger_size); - if (ret == ERROR_SUCCESS) - { - debugger_val=HeapAlloc(GetProcessHeap(), 0, debugger_size); - RegQueryValueExA(hkey, "debugger", NULL, &debugger_type, debugger_val, &debugger_size); - } - } else if (ret == ERROR_ACCESS_DENIED) { skip("not enough privileges to change the debugger\n"); @@ -346,17 +385,42 @@ static void test_ExitCode(void) return; } - if (debugger_val && debugger_type == REG_SZ && - strstr((char*)debugger_val, "winedbg --auto")) + if (debugger_value.data && debugger_value.type == REG_SZ && + strstr((char*)debugger_value.data, "winedbg --auto")) + { + HKEY hkeyWinedbg; + ret=RegCreateKeyA(HKEY_CURRENT_USER, WineDbg, &hkeyWinedbg); + if (ret == ERROR_SUCCESS) + { + static DWORD zero; + reg_save_value crash_dlg_value; + save_value(hkeyWinedbg, "ShowCrashDialog", &crash_dlg_value); + RegSetValueExA(hkeyWinedbg, "ShowCrashDialog", 0, REG_DWORD, (BYTE *)&zero, sizeof(DWORD)); crash_and_winedbg(hkey, test_exe); + restore_value(hkeyWinedbg, &crash_dlg_value); + RegCloseKey(hkeyWinedbg); + } + else + ok(0, "Couldn't access WineDbg Key - error %u\n", ret); + } + if (winetest_interactive) + /* Since the debugging process never sets the debug event, it isn't recognized + as a valid debugger and, after the debugger exits, Windows will show a dialog box + asking the user what to do */ crash_and_debug(hkey, test_exe, "dbg,none"); + else + skip("\"none\" debugger test needs user interaction\n"); crash_and_debug(hkey, test_exe, "dbg,event,order"); crash_and_debug(hkey, test_exe, "dbg,attach,event,code2"); if (pDebugSetProcessKillOnExit) crash_and_debug(hkey, test_exe, "dbg,attach,event,nokill"); + else + win_skip("DebugSetProcessKillOnExit is not available\n"); if (pDebugActiveProcessStop) crash_and_debug(hkey, test_exe, "dbg,attach,event,detach"); + else + win_skip("DebugActiveProcessStop is not available\n"); if (disposition == REG_CREATED_NEW_KEY) { @@ -365,29 +429,48 @@ static void test_ExitCode(void) } else { - if (auto_val) - { - RegSetValueExA(hkey, "auto", 0, auto_type, auto_val, auto_size); - HeapFree(GetProcessHeap(), 0, auto_val); - } - else - RegDeleteValueA(hkey, "auto"); - if (debugger_val) - { - RegSetValueExA(hkey, "debugger", 0, debugger_type, debugger_val, debugger_size); - HeapFree(GetProcessHeap(), 0, debugger_val); - } - else - RegDeleteValueA(hkey, "debugger"); + restore_value(hkey, &auto_value); + restore_value(hkey, &debugger_value); RegCloseKey(hkey); - } + } } +static void test_RemoteDebugger(void) + { + BOOL bret, present; + if(!pCheckRemoteDebuggerPresent) + { + win_skip("CheckRemoteDebuggerPresent is not available\n"); + return; + } + present = TRUE; + SetLastError(0xdeadbeef); + bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),&present); + ok(bret , "expected CheckRemoteDebuggerPresent to succeed\n"); + ok(0xdeadbeef == GetLastError(), + "expected error to be unchanged, got %d/%x\n",GetLastError(), GetLastError()); + + present = TRUE; + SetLastError(0xdeadbeef); + bret = pCheckRemoteDebuggerPresent(NULL,&present); + ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n"); + ok(present, "expected parameter to be unchanged\n"); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError()); + + SetLastError(0xdeadbeef); + bret = pCheckRemoteDebuggerPresent(GetCurrentProcess(),NULL); + ok(!bret , "expected CheckRemoteDebuggerPresent to fail\n"); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "expected error ERROR_INVALID_PARAMETER, got %d/%x\n",GetLastError(), GetLastError()); + } + START_TEST(debugger) { HMODULE hdll; hdll=GetModuleHandle("kernel32.dll"); + pCheckRemoteDebuggerPresent=(void*)GetProcAddress(hdll, "CheckRemoteDebuggerPresent"); pDebugActiveProcessStop=(void*)GetProcAddress(hdll, "DebugActiveProcessStop"); pDebugSetProcessKillOnExit=(void*)GetProcAddress(hdll, "DebugSetProcessKillOnExit"); @@ -403,5 +486,6 @@ START_TEST(debugger) else { test_ExitCode(); + test_RemoteDebugger(); } } diff --git a/rostests/winetests/kernel32/directory.c b/rostests/winetests/kernel32/directory.c index 47e77013a1d..5efa463e4e0 100755 --- a/rostests/winetests/kernel32/directory.c +++ b/rostests/winetests/kernel32/directory.c @@ -62,7 +62,10 @@ static void test_GetWindowsDirectoryW(void) len_with_null = GetWindowsDirectoryW(NULL, 0); if (len_with_null==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetWindowsDirectoryW is not implemented\n"); return; + } ok(len_with_null <= MAX_PATH, "should fit into MAX_PATH\n"); lstrcpyW(buf, fooW); @@ -125,7 +128,10 @@ static void test_GetSystemDirectoryW(void) len_with_null = GetSystemDirectoryW(NULL, 0); if (len_with_null==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetSystemDirectoryW is not available\n"); return; + } ok(len_with_null <= MAX_PATH, "should fit into MAX_PATH\n"); lstrcpyW(buf, fooW); @@ -338,28 +344,36 @@ static void test_CreateDirectoryW(void) ret = CreateDirectoryW(NULL, NULL); if (!ret && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("CreateDirectoryW is not available\n"); return; - ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, "should not create NULL path\n"); + } + ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, + "should not create NULL path ret %u err %u\n", ret, GetLastError()); ret = CreateDirectoryW(empty_strW, NULL); - ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, "should not create empty path\n"); + ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, + "should not create empty path ret %u err %u\n", ret, GetLastError()); ret = GetSystemDirectoryW(tmpdir, MAX_PATH); ok(ret < MAX_PATH, "System directory should fit into MAX_PATH\n"); ret = SetCurrentDirectoryW(tmpdir); - ok(ret == TRUE, "could not chdir to the System directory\n"); + ok(ret == TRUE, "could not chdir to the System directory ret %u err %u\n", ret, GetLastError()); ret = CreateDirectoryW(dotW, NULL); - ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, "should not create existing path\n"); + ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, + "should not create existing path ret %u err %u\n", ret, GetLastError()); ret = CreateDirectoryW(dotdotW, NULL); - ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, "should not create existing path\n"); + ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, + "should not create existing path ret %u err %u\n", ret, GetLastError()); GetTempPathW(MAX_PATH, tmpdir); tmpdir[3] = 0; /* truncate the path */ ret = CreateDirectoryW(tmpdir, NULL); - ok(ret == FALSE && GetLastError() == ERROR_ACCESS_DENIED, "should deny access to the drive root\n"); + ok(ret == FALSE && (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_ALREADY_EXISTS), + "should deny access to the drive root ret %u err %u\n", ret, GetLastError()); GetTempPathW(MAX_PATH, tmpdir); lstrcatW(tmpdir, tmp_dir_name); @@ -367,7 +381,8 @@ static void test_CreateDirectoryW(void) ok(ret == TRUE, "CreateDirectoryW should always succeed\n"); ret = CreateDirectoryW(tmpdir, NULL); - ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, "should not create existing path\n"); + ok(ret == FALSE && GetLastError() == ERROR_ALREADY_EXISTS, + "should not create existing path ret %u err %u\n", ret, GetLastError()); ret = RemoveDirectoryW(tmpdir); ok(ret == TRUE, "RemoveDirectoryW should always succeed\n"); @@ -392,7 +407,8 @@ static void test_CreateDirectoryW(void) lstrcatW(tmpdir, tmp_dir_name); ret = CreateDirectoryW(tmpdir, NULL); ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND, - "CreateDirectoryW with multiple nonexistent directories in path should fail\n"); + "CreateDirectoryW with multiple nonexistent directories in path should fail ret %u err %u\n", + ret, GetLastError()); ret = RemoveDirectoryW(tmpdir); } @@ -435,7 +451,10 @@ static void test_RemoveDirectoryW(void) lstrcatW(tmpdir, tmp_dir_name); ret = CreateDirectoryW(tmpdir, NULL); if (!ret && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("CreateDirectoryW is not available\n"); return; + } ok(ret == TRUE, "CreateDirectoryW should always succeed\n"); diff --git a/rostests/winetests/kernel32/drive.c b/rostests/winetests/kernel32/drive.c index a94cbdfea6e..30531f24044 100755 --- a/rostests/winetests/kernel32/drive.c +++ b/rostests/winetests/kernel32/drive.c @@ -39,7 +39,8 @@ static void test_GetDriveTypeA(void) for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++) { type = GetDriveTypeA(drive); - ok(type > 0 && type <= 6, "not a valid drive %c: type %u\n", drive[0], type); + ok(type > DRIVE_UNKNOWN && type <= DRIVE_RAMDISK, + "not a valid drive %c: type %u\n", drive[0], type); if (!(logical_drives & 1)) ok(type == DRIVE_NO_ROOT_DIR, @@ -64,10 +65,11 @@ static void test_GetDriveTypeW(void) type = GetDriveTypeW(drive); if (type == DRIVE_UNKNOWN && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { - /* Must be Win9x which doesn't support the Unicode functions */ + win_skip("GetDriveTypeW is not available on Win9x\n"); return; } - ok(type > 0 && type <= 6, "not a valid drive %c: type %u\n", drive[0], type); + ok(type > DRIVE_UNKNOWN && type <= DRIVE_RAMDISK, + "not a valid drive %c: type %u\n", drive[0], type); if (!(logical_drives & 1)) ok(type == DRIVE_NO_ROOT_DIR, @@ -118,7 +120,13 @@ static void test_GetDiskFreeSpaceA(void) else { ok(ret || - (!ret && (GetLastError() == ERROR_NOT_READY || GetLastError() == ERROR_INVALID_DRIVE)), + GetLastError() == ERROR_NOT_READY || + GetLastError() == ERROR_INVALID_FUNCTION || + GetLastError() == ERROR_INVALID_DRIVE || + GetLastError() == ERROR_PATH_NOT_FOUND || + GetLastError() == ERROR_REQUEST_ABORTED || + GetLastError() == ERROR_NETNAME_DELETED || + GetLastError() == ERROR_UNRECOGNIZED_VOLUME, "GetDiskFreeSpaceA(%s): ret=%d GetLastError=%d\n", drive, ret, GetLastError()); if( GetVersion() & 0x80000000) @@ -132,7 +140,13 @@ static void test_GetDiskFreeSpaceA(void) tot.QuadPart = sectors_per_cluster; tot.QuadPart = (tot.QuadPart * bytes_per_sector) * total_clusters; ret = pGetDiskFreeSpaceExA( drive, &d, &totEx, NULL); - ok( ret || (!ret && ERROR_NOT_READY == GetLastError()), + ok( ret || + GetLastError() == ERROR_NOT_READY || + GetLastError() == ERROR_INVALID_FUNCTION || + GetLastError() == ERROR_PATH_NOT_FOUND || + GetLastError() == ERROR_REQUEST_ABORTED || + GetLastError() == ERROR_NETNAME_DELETED || + GetLastError() == ERROR_UNRECOGNIZED_VOLUME, "GetDiskFreeSpaceExA( %s ) failed. GetLastError=%d\n", drive, GetLastError()); ok( bytes_per_sector == 0 || /* empty cd rom drive */ totEx.QuadPart <= tot.QuadPart, @@ -157,7 +171,7 @@ static void test_GetDiskFreeSpaceW(void) ret = GetDiskFreeSpaceW(NULL, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters); if (ret == 0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { - /* Must be Win9x which doesn't support the Unicode functions */ + win_skip("GetDiskFreeSpaceW is not available\n"); return; } ok(ret, "GetDiskFreeSpaceW error %d\n", GetLastError()); @@ -188,7 +202,12 @@ static void test_GetDiskFreeSpaceW(void) "GetDiskFreeSpaceW(%c): ret=%d GetLastError=%d\n", drive[0], ret, GetLastError()); else - ok(ret || GetLastError() == ERROR_NOT_READY, + ok( ret || + GetLastError() == ERROR_NOT_READY || + GetLastError() == ERROR_INVALID_FUNCTION || + GetLastError() == ERROR_PATH_NOT_FOUND || + GetLastError() == ERROR_REQUEST_ABORTED || + GetLastError() == ERROR_UNRECOGNIZED_VOLUME, "GetDiskFreeSpaceW(%c): ret=%d GetLastError=%d\n", drive[0], ret, GetLastError()); } diff --git a/rostests/winetests/kernel32/environ.c b/rostests/winetests/kernel32/environ.c index e6dd1fca5d3..b3526675b20 100755 --- a/rostests/winetests/kernel32/environ.c +++ b/rostests/winetests/kernel32/environ.c @@ -24,6 +24,13 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" +#include "winnls.h" + +static CHAR string[MAX_PATH]; +#define ok_w(res, format, szString) \ +\ + WideCharToMultiByte(CP_ACP, 0, szString, -1, string, MAX_PATH, NULL, NULL); \ + ok(res, format, string); static BOOL (WINAPI *pGetComputerNameExA)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD); static BOOL (WINAPI *pGetComputerNameExW)(COMPUTER_NAME_FORMAT,LPWSTR,LPDWORD); @@ -141,7 +148,7 @@ static void test_GetSetEnvironmentVariableW(void) if (ret == FALSE && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { /* Must be Win9x which doesn't support the Unicode functions */ - skip("SetEnvironmentVariableW is not implemented\n"); + win_skip("SetEnvironmentVariableW is not implemented\n"); return; } ok(ret == TRUE, @@ -156,7 +163,9 @@ static void test_GetSetEnvironmentVariableW(void) lstrcpyW(buf, fooW); ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value)); - ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n"); + ok_w(lstrcmpW(buf, fooW) == 0 || + lstrlenW(buf) == 0, /* Vista */ + "Expected untouched or empty buffer, got \"%s\"\n", buf); ok(ret_size == lstrlenW(value) + 1, "should return length with terminating 0 ret_size=%d\n", ret_size); @@ -236,13 +245,14 @@ static void test_ExpandEnvironmentStringsA(void) SetEnvironmentVariableA("EnvVar", value); ret_size = ExpandEnvironmentStringsA(NULL, buf1, sizeof(buf1)); - ok(ret_size == 1 || ret_size == 0 /* Win9x */, + ok(ret_size == 1 || ret_size == 0 /* Win9x */ || ret_size == 2 /* NT4 */, "ExpandEnvironmentStrings returned %d\n", ret_size); /* Try to get the required buffer size 'the natural way' */ strcpy(buf, "%EnvVar%"); ret_size = ExpandEnvironmentStringsA(buf, NULL, 0); ok(ret_size == strlen(value)+1 || /* win98 */ + ret_size == (strlen(value)+1)*2 || /* NT4 */ ret_size == strlen(value)+2 || /* win2k, XP, win2k3 */ ret_size == 0 /* Win95 */, "ExpandEnvironmentStrings returned %d instead of %d, %d or %d\n", @@ -251,21 +261,24 @@ static void test_ExpandEnvironmentStringsA(void) /* Again, side-stepping the Win95 bug */ ret_size = ExpandEnvironmentStringsA(buf, buf1, 0); /* v5.1.2600.2945 (XP SP2) returns len + 2 here! */ - ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2, + ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2 || + ret_size == (strlen(value)+1)*2 /* NT4 */, "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlenA(value)+1); /* Try with a buffer that's too small */ ret_size = ExpandEnvironmentStringsA(buf, buf1, 12); /* v5.1.2600.2945 (XP SP2) returns len + 2 here! */ - ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2, + ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2 || + ret_size == (strlen(value)+1)*2 /* NT4 */, "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlenA(value)+1); /* Try with a buffer of just the right size */ /* v5.1.2600.2945 (XP SP2) needs and returns len + 2 here! */ ret_size = ExpandEnvironmentStringsA(buf, buf1, ret_size); - ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2, + ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2 || + ret_size == (strlen(value)+1)*2 /* NT4 */, "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlenA(value)+1); ok(!strcmp(buf1, value), "ExpandEnvironmentStrings returned [%s]\n", buf1); @@ -273,7 +286,9 @@ static void test_ExpandEnvironmentStringsA(void) /* Try with an unset environment variable */ strcpy(buf, not_an_env_var); ret_size = ExpandEnvironmentStringsA(buf, buf1, sizeof(buf1)); - ok(ret_size == strlen(not_an_env_var)+1, "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlenA(value)+1); + ok(ret_size == strlen(not_an_env_var)+1 || + ret_size == (strlen(not_an_env_var)+1)*2 /* NT4 */, + "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlenA(not_an_env_var)+1); ok(!strcmp(buf1, not_an_env_var), "ExpandEnvironmentStrings returned [%s]\n", buf1); /* test a large destination size */ @@ -294,7 +309,9 @@ static void test_ExpandEnvironmentStringsA(void) strcpy(buf, "Indirect-%IndirectVar%-Indirect"); strcpy(buf2, "Indirect-Foo%EnvVar%Bar-Indirect"); ret_size = ExpandEnvironmentStringsA(buf, buf1, sizeof(buf1)); - ok(ret_size == strlen(buf2)+1, "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlen(buf2)+1); + ok(ret_size == strlen(buf2)+1 || + ret_size == (strlen(buf2)+1)*2 /* NT4 */, + "ExpandEnvironmentStrings returned %d instead of %d\n", ret_size, lstrlen(buf2)+1); ok(!strcmp(buf1, buf2), "ExpandEnvironmentStrings returned [%s]\n", buf1); SetEnvironmentVariableA("IndirectVar", NULL); @@ -342,7 +359,7 @@ static void test_GetComputerName(void) ret = GetComputerNameW((LPWSTR)0xdeadbeef, &size); error = GetLastError(); if (error == ERROR_CALL_NOT_IMPLEMENTED) - skip("GetComputerNameW is not implemented\n"); + win_skip("GetComputerNameW is not implemented\n"); else { todo_wine @@ -367,7 +384,7 @@ static void test_GetComputerNameExA(void) if (!pGetComputerNameExA) { - skip("GetComputerNameExA function not implemented\n"); + win_skip("GetComputerNameExA function not implemented\n"); return; } @@ -441,7 +458,7 @@ static void test_GetComputerNameExW(void) if (!pGetComputerNameExW) { - skip("GetComputerNameExW function not implemented\n"); + win_skip("GetComputerNameExW function not implemented\n"); return; } diff --git a/rostests/winetests/kernel32/file.c b/rostests/winetests/kernel32/file.c index f73f1046e49..f53e65df4b8 100755 --- a/rostests/winetests/kernel32/file.c +++ b/rostests/winetests/kernel32/file.c @@ -2,6 +2,7 @@ * Unit tests for file functions in Wine * * Copyright (c) 2002, 2004 Jakob Eriksson + * Copyright (c) 2008 Jeff Zaroyko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,12 +20,13 @@ * */ +/* ReplaceFile requires Windows 2000 or newer */ +#define _WIN32_WINNT 0x0500 + #include #include #include - -/* ReplaceFile requires Windows 2000 or newer */ -#define _WIN32_WINNT 0x0500 +#include #include "wine/test.h" #include "windef.h" @@ -34,6 +36,8 @@ static HANDLE (WINAPI *pFindFirstFileExA)(LPCSTR,FINDEX_INFO_LEVELS,LPVOID,FINDEX_SEARCH_OPS,LPVOID,DWORD); static BOOL (WINAPI *pReplaceFileA)(LPCSTR, LPCSTR, LPCSTR, DWORD, LPVOID, LPVOID); static BOOL (WINAPI *pReplaceFileW)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPVOID, LPVOID); +static UINT (WINAPI *pGetSystemWindowsDirectoryA)(LPSTR, UINT); +static BOOL (WINAPI *pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD); /* keep filename and filenameW the same */ static const char filename[] = "testfile.xxx"; @@ -50,6 +54,14 @@ static const char sillytext[] = "1234 43 4kljf lf &%%%&&&&&& 34 4 34 3############# 33 3 3 3 # 3## 3" "sdlkfjasdlkfj a dslkj adsklf \n \nasdklf askldfa sdlkf \nsadklf asdklf asdf "; +struct test_list { + const char *file; /* file string to test */ + const DWORD err; /* Win NT and further error code */ + const LONG err2; /* Win 9x & ME error code or -1 */ + const DWORD options; /* option flag to use for open */ + const BOOL todo_flag; /* todo_wine indicator */ +} ; + static void InitFunctionPointers(void) { HMODULE hkernel32 = GetModuleHandleA("kernel32"); @@ -57,15 +69,17 @@ static void InitFunctionPointers(void) pFindFirstFileExA=(void*)GetProcAddress(hkernel32, "FindFirstFileExA"); pReplaceFileA=(void*)GetProcAddress(hkernel32, "ReplaceFileA"); pReplaceFileW=(void*)GetProcAddress(hkernel32, "ReplaceFileW"); + pGetSystemWindowsDirectoryA=(void*)GetProcAddress(hkernel32, "GetSystemWindowsDirectoryA"); + pGetVolumeNameForVolumeMountPointA = (void *) GetProcAddress(hkernel32, "GetVolumeNameForVolumeMountPointA"); } static void test__hread( void ) { HFILE filehandle; char buffer[10000]; - long bytes_read; - long bytes_wanted; - long i; + LONG bytes_read; + LONG bytes_wanted; + LONG i; BOOL ret; SetFileAttributesA(filename,FILE_ATTRIBUTE_NORMAL); /* be sure to remove stale files */ @@ -110,10 +124,10 @@ static void test__hwrite( void ) { HFILE filehandle; char buffer[10000]; - long bytes_read; - long bytes_written; - long blocks; - long i; + LONG bytes_read; + LONG bytes_written; + ULONG blocks; + LONG i; char *contents; HLOCAL memory_object; char checksum[1]; @@ -145,7 +159,7 @@ static void test__hwrite( void ) srand( (unsigned)time( NULL ) ); for (blocks = 0; blocks < 100; blocks++) { - for (i = 0; i < (long)sizeof( buffer ); i++) + for (i = 0; i < (LONG)sizeof( buffer ); i++) { buffer[i] = rand( ); checksum[0] = checksum[0] + buffer[i]; @@ -341,7 +355,7 @@ static void test__llseek( void ) INT i; HFILE filehandle; char buffer[1]; - long bytes_read; + LONG bytes_read; BOOL ret; filehandle = _lcreat( filename, 0 ); @@ -353,20 +367,20 @@ static void test__llseek( void ) for (i = 0; i < 400; i++) { - ok( HFILE_ERROR != _hwrite( filehandle, sillytext, strlen( sillytext ) ), "_hwrite complains\n" ); + ok( _hwrite( filehandle, sillytext, strlen( sillytext ) ) != -1, "_hwrite complains\n" ); } - ok( HFILE_ERROR != _llseek( filehandle, 400 * strlen( sillytext ), FILE_CURRENT ), "should be able to seek\n" ); - ok( HFILE_ERROR != _llseek( filehandle, 27 + 35 * strlen( sillytext ), FILE_BEGIN ), "should be able to seek\n" ); + ok( _llseek( filehandle, 400 * strlen( sillytext ), FILE_CURRENT ) != -1, "should be able to seek\n" ); + ok( _llseek( filehandle, 27 + 35 * strlen( sillytext ), FILE_BEGIN ) != -1, "should be able to seek\n" ); bytes_read = _hread( filehandle, buffer, 1); ok( 1 == bytes_read, "file read size error\n" ); ok( buffer[0] == sillytext[27], "_llseek error, it got lost seeking\n" ); - ok( HFILE_ERROR != _llseek( filehandle, -400 * strlen( sillytext ), FILE_END ), "should be able to seek\n" ); + ok( _llseek( filehandle, -400 * (LONG)strlen( sillytext ), FILE_END ) != -1, "should be able to seek\n" ); bytes_read = _hread( filehandle, buffer, 1); ok( 1 == bytes_read, "file read size error\n" ); ok( buffer[0] == sillytext[0], "_llseek error, it got lost seeking\n" ); - ok( HFILE_ERROR != _llseek( filehandle, 1000000, FILE_END ), "should be able to seek past file; poor, poor Windows programmers\n" ); + ok( _llseek( filehandle, 1000000, FILE_END ) != -1, "should be able to seek past file; poor, poor Windows programmers\n" ); ok( HFILE_ERROR != _lclose(filehandle), "_lclose complains\n" ); ret = DeleteFileA( filename ); @@ -418,7 +432,7 @@ static void test__lread( void ) { HFILE filehandle; char buffer[10000]; - long bytes_read; + UINT bytes_read; UINT bytes_wanted; UINT i; BOOL ret; @@ -463,10 +477,10 @@ static void test__lwrite( void ) { HFILE filehandle; char buffer[10000]; - long bytes_read; - long bytes_written; - long blocks; - long i; + UINT bytes_read; + UINT bytes_written; + UINT blocks; + INT i; char *contents; HLOCAL memory_object; char checksum[1]; @@ -498,7 +512,7 @@ static void test__lwrite( void ) srand( (unsigned)time( NULL ) ); for (blocks = 0; blocks < 100; blocks++) { - for (i = 0; i < (long)sizeof( buffer ); i++) + for (i = 0; i < (INT)sizeof( buffer ); i++) { buffer[i] = rand( ); checksum[0] = checksum[0] + buffer[i]; @@ -549,6 +563,7 @@ static void test_CopyFileA(void) char source[MAX_PATH], dest[MAX_PATH]; static const char prefix[] = "pfx"; HANDLE hfile; + HANDLE hmapfile; FILETIME ft1, ft2; char buf[10]; DWORD ret; @@ -561,6 +576,9 @@ static void test_CopyFileA(void) ret = GetTempFileNameA(temp_path, prefix, 0, source); ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError()); + ret = MoveFileA(source, source); + todo_wine ok(ret, "MoveFileA: failed, error %d\n", GetLastError()); + /* make the source have not zero size */ hfile = CreateFileA(source, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0 ); ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n"); @@ -611,6 +629,34 @@ static void test_CopyFileA(void) ok( retok && ret == sizeof(prefix), "ReadFile: error %d\n", GetLastError()); ok(!memcmp(prefix, buf, sizeof(prefix)), "buffer contents mismatch\n"); + + /* check error on copying over a mapped file that was opened with FILE_SHARE_READ */ + hmapfile = CreateFileMapping(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); + ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + + ret = CopyFileA(source, dest, FALSE); + ok(!ret && GetLastError() == ERROR_SHARING_VIOLATION, + "CopyFileA with mapped dest file: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + + CloseHandle(hmapfile); + CloseHandle(hfile); + + hfile = CreateFileA(dest, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open destination file\n"); + + /* check error on copying over a mapped file that was opened with FILE_SHARE_WRITE */ + hmapfile = CreateFileMapping(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); + ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + + ret = CopyFileA(source, dest, FALSE); + todo_wine { + ok(!ret, "CopyFileA: expected failure\n"); + ok(GetLastError() == ERROR_USER_MAPPED_FILE || + broken(GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x and WinMe */ + "CopyFileA with mapped dest file: expected ERROR_USER_MAPPED_FILE, got %d\n", GetLastError()); + } + + CloseHandle(hmapfile); CloseHandle(hfile); ret = DeleteFileA(source); @@ -628,7 +674,10 @@ static void test_CopyFileW(void) ret = GetTempPathW(MAX_PATH, temp_path); if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetTempPathW is not available\n"); return; + } ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); @@ -651,13 +700,68 @@ static void test_CopyFileW(void) ok(ret, "DeleteFileW: error %d\n", GetLastError()); } + +/* + * Debugging routine to dump a buffer in a hexdump-like fashion. + */ +static void dumpmem(unsigned char* mem, int len) { + int x,y; + char buf[200]; + int ln=0; + + for (x=0; xlen) { + ln += sprintf(buf+ln, " "); + } else { + ln += sprintf(buf+ln, "%02hhx ",mem[x+y]); + } + } + ln += sprintf(buf+ln, "- "); + for (y=0; y<16; y++) { + if ((x+y)<=len) { + if (mem[x+y]<32 || mem[x+y]>127) { + ln += sprintf(buf+ln, "."); + } else { + ln += sprintf(buf+ln, "%c",mem[x+y]); + } + } + } + sprintf(buf+ln, "\n"); + trace(buf); + ln = 0; + } +} + static void test_CreateFileA(void) { HANDLE hFile; - char temp_path[MAX_PATH]; + char temp_path[MAX_PATH], dirname[MAX_PATH]; char filename[MAX_PATH]; static const char prefix[] = "pfx"; - DWORD ret; + char windowsdir[MAX_PATH]; + char Volume_1[MAX_PATH]; + unsigned char buffer[512]; + char directory[] = "removeme"; + static const char nt_drive[] = "\\\\?\\A:"; + DWORD i, ret, len; + struct test_list p[] = { + {"", ERROR_PATH_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, TRUE }, /* dir as file w \ */ + {"", ERROR_SUCCESS, ERROR_PATH_NOT_FOUND, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* dir as dir w \ */ + {"a", ERROR_FILE_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, FALSE }, /* non-exist file */ + {"a\\", ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, FALSE }, /* non-exist dir */ + {"removeme", ERROR_ACCESS_DENIED, -1, FILE_ATTRIBUTE_NORMAL, FALSE }, /* exist dir w/o \ */ + {"removeme\\", ERROR_PATH_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, TRUE }, /* exst dir w \ */ + {"c:", ERROR_ACCESS_DENIED, ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, FALSE }, /* device in file namespace */ + {"c:", ERROR_SUCCESS, ERROR_PATH_NOT_FOUND, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* device in file namespace as dir */ + {"c:\\", ERROR_PATH_NOT_FOUND, ERROR_ACCESS_DENIED, FILE_ATTRIBUTE_NORMAL, TRUE }, /* root dir w \ */ + {"c:\\", ERROR_SUCCESS, ERROR_ACCESS_DENIED, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* root dir w \ as dir */ + {"\\\\?\\c:", ERROR_SUCCESS, ERROR_BAD_NETPATH, FILE_ATTRIBUTE_NORMAL,FALSE }, /* dev namespace drive */ + {"\\\\?\\c:\\", ERROR_PATH_NOT_FOUND, ERROR_BAD_NETPATH, FILE_ATTRIBUTE_NORMAL, TRUE }, /* dev namespace drive w \ */ + {NULL, 0, -1, 0, FALSE} + }; + BY_HANDLE_FILE_INFORMATION Finfo; ret = GetTempPathA(MAX_PATH, temp_path); ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); @@ -701,6 +805,284 @@ static void test_CreateFileA(void) ret = DeleteFileA(filename); ok(ret, "DeleteFileA: error %d\n", GetLastError()); + + /* get windows drive letter */ + ret = GetWindowsDirectory(windowsdir, sizeof(windowsdir)); + ok(ret < sizeof(windowsdir), "windowsdir is abnormally long!\n"); + ok(ret != 0, "GetWindowsDirectory: error %d\n", GetLastError()); + + /* test error return codes from CreateFile for some cases */ + ret = GetTempPathA(MAX_PATH, temp_path); + ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); + strcpy(dirname, temp_path); + strcat(dirname, directory); + ret = CreateDirectory(dirname, NULL); + ok( ret, "Createdirectory failed, gle=%d\n", GetLastError() ); + /* set current drive & directory to known location */ + SetCurrentDirectoryA( temp_path ); + i = 0; + while (p[i].file) + { + filename[0] = 0; + /* update the drive id in the table entry with the current one */ + if (p[i].file[1] == ':') + { + strcpy(filename, p[i].file); + filename[0] = windowsdir[0]; +} + else if (p[i].file[0] == '\\' && p[i].file[5] == ':') + { + strcpy(filename, p[i].file); + filename[4] = windowsdir[0]; + } + else + { + /* prefix the table entry with the current temp directory */ + strcpy(filename, temp_path); + strcat(filename, p[i].file); + } + hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + p[i].options, NULL ); + /* if we get ACCESS_DENIED when we do not expect it, assume + * no access to the volume + */ + if (hFile == INVALID_HANDLE_VALUE && + GetLastError() == ERROR_ACCESS_DENIED && + p[i].err != ERROR_ACCESS_DENIED) + { + if (p[i].todo_flag) + skip("Either no authority to volume, or is todo_wine for %s err=%d should be %d\n", filename, GetLastError(), p[i].err); + else + skip("Do not have authority to access volumes. Test for %s skipped\n", filename); + } + /* otherwise validate results with expectations */ + else if (p[i].todo_flag) + todo_wine ok( + (hFile == INVALID_HANDLE_VALUE && + (p[i].err == GetLastError() || p[i].err2 == GetLastError())) || + (hFile != INVALID_HANDLE_VALUE && p[i].err == ERROR_SUCCESS), + "CreateFileA failed on %s, hFile %p, err=%u, should be %u\n", + filename, hFile, GetLastError(), p[i].err); + else + ok( + (hFile == INVALID_HANDLE_VALUE && + (p[i].err == GetLastError() || p[i].err2 == GetLastError())) || + (hFile != INVALID_HANDLE_VALUE && p[i].err == ERROR_SUCCESS), + "CreateFileA failed on %s, hFile %p, err=%u, should be %u\n", + filename, hFile, GetLastError(), p[i].err); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle( hFile ); + i++; + } + ret = RemoveDirectoryA(dirname); + ok(ret, "RemoveDirectoryA: error %d\n", GetLastError()); + + + /* test opening directory as a directory */ + hFile = CreateFileA( temp_path, GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL ); + if (hFile != INVALID_HANDLE_VALUE && GetLastError() != ERROR_PATH_NOT_FOUND) + { + ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_SUCCESS, + "CreateFileA did not work, last error %u on volume <%s>\n", + GetLastError(), temp_path ); + + if (hFile != INVALID_HANDLE_VALUE) + { + ret = GetFileInformationByHandle( hFile, &Finfo ); + if (ret) + { + ok(Finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY, + "CreateFileA probably did not open temp directory %s correctly\n file information does not include FILE_ATTRIBUTE_DIRECTORY, actual=0x%08x\n", + temp_path, Finfo.dwFileAttributes); + } + CloseHandle( hFile ); + } + } + else + skip("Probable Win9x, got ERROR_PATH_NOT_FOUND w/ FILE_FLAG_BACKUP_SEMANTICS or %s\n", temp_path); + + + /* *** Test opening volumes/devices using drive letter *** */ + + /* test using drive letter in non-rewrite format without trailing \ */ + /* this should work */ + strcpy(filename, nt_drive); + filename[4] = windowsdir[0]; + hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL ); + if (hFile != INVALID_HANDLE_VALUE || + (GetLastError() != ERROR_ACCESS_DENIED && GetLastError() != ERROR_BAD_NETPATH)) + { + /* if we have adm rights to volume, then try rest of tests */ + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n", + filename, GetLastError()); + if (hFile != INVALID_HANDLE_VALUE) + { + /* if we opened the volume/device, try to read it. Since it */ + /* opened, we should be able to read it. We don't care about*/ + /* what the data is at this time. */ + len = 512; + ret = ReadFile( hFile, buffer, len, &len, NULL ); + todo_wine ok(ret, "Failed to read volume, last error %u, %u, for %s\n", + GetLastError(), ret, filename); + if (ret) + { + trace("buffer is\n"); + dumpmem(buffer, 64); + } + CloseHandle( hFile ); + } + + /* test using drive letter with trailing \ and in non-rewrite */ + /* this should not work */ + strcpy(filename, nt_drive); + filename[4] = windowsdir[0]; + strcat( filename, "\\" ); + hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL ); + todo_wine + ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND, + "CreateFileA should have returned ERROR_PATH_NOT_FOUND on %s, but got %u\n", + filename, GetLastError()); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle( hFile ); + + /* test using temp path with trailing \ and in non-rewrite as dir */ + /* this should work */ + strcpy(filename, nt_drive); + filename[4] = 0; + strcat( filename, temp_path ); + hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL ); + ok(hFile != INVALID_HANDLE_VALUE, + "CreateFileA should have worked on %s, but got %u\n", + filename, GetLastError()); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle( hFile ); + + /* test using drive letter without trailing \ and in device ns */ + /* this should work */ + strcpy(filename, nt_drive); + filename[4] = windowsdir[0]; + filename[2] = '.'; + hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL ); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n", + filename, GetLastError()); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle( hFile ); + } + /* If we see ERROR_BAD_NETPATH then on Win9x or WinME, so skip */ + else if (GetLastError() == ERROR_BAD_NETPATH) + skip("Probable Win9x, got ERROR_BAD_NETPATH (53)\n"); + else + skip("Do not have authority to access volumes. Tests skipped\n"); + + + /* *** Test opening volumes/devices using GUID *** */ + + if (pGetVolumeNameForVolumeMountPointA) + { + strcpy(filename, "c:\\"); + filename[0] = windowsdir[0]; + ret = pGetVolumeNameForVolumeMountPointA( filename, Volume_1, MAX_PATH ); + ok(ret, "GetVolumeNameForVolumeMountPointA failed, for %s, last error=%d\n", filename, GetLastError()); + if (ret) + { + ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name <%s>\n", Volume_1); + + /* test the result of opening a unique volume name (GUID) + * with the trailing \ + * this should error out + */ + strcpy(filename, Volume_1); + hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL ); + todo_wine + ok(hFile == INVALID_HANDLE_VALUE, + "CreateFileA should not have opened %s, hFile %p\n", + filename, hFile); + todo_wine + ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND, + "CreateFileA should have returned ERROR_PATH_NOT_FOUND on %s, but got %u\n", + filename, GetLastError()); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle( hFile ); + + /* test the result of opening a unique volume name (GUID) + * with the temp path string as dir + * this should work + */ + strcpy(filename, Volume_1); + strcat(filename, temp_path+3); + hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL ); + todo_wine + ok(hFile != INVALID_HANDLE_VALUE, + "CreateFileA should have opened %s, but got %u\n", + filename, GetLastError()); + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle( hFile ); + + /* test the result of opening a unique volume name (GUID) + * without the trailing \ and in device namespace + * this should work + */ + strcpy(filename, Volume_1); + filename[2] = '.'; + filename[48] = 0; + hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL ); + if (hFile != INVALID_HANDLE_VALUE || GetLastError() != ERROR_ACCESS_DENIED) + { + /* if we have adm rights to volume, then try rest of tests */ + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n", + filename, GetLastError()); + if (hFile != INVALID_HANDLE_VALUE) + { + /* if we opened the volume/device, try to read it. Since it */ + /* opened, we should be able to read it. We don't care about*/ + /* what the data is at this time. */ + len = 512; + ret = ReadFile( hFile, buffer, len, &len, NULL ); + todo_wine ok(ret, "Failed to read volume, last error %u, %u, for %s\n", + GetLastError(), ret, filename); + if (ret) + { + trace("buffer is\n"); + dumpmem(buffer, 64); + } + CloseHandle( hFile ); + } + } + else + skip("Do not have authority to access volumes. Tests skipped\n"); + } + else + win_skip("GetVolumeNameForVolumeMountPointA not functioning\n"); + } + else + win_skip("GetVolumeNameForVolumeMountPointA not found\n"); } static void test_CreateFileW(void) @@ -715,7 +1097,10 @@ static void test_CreateFileW(void) ret = GetTempPathW(MAX_PATH, temp_path); if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetTempPathW is not available\n"); return; + } ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); @@ -777,6 +1162,16 @@ static void test_CreateFileW(void) OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND, "CreateFileW on invalid VxD name returned ret=%p error=%d\n",hFile,GetLastError()); + + ret = CreateDirectoryW(filename, NULL); + ok(ret == TRUE, "couldn't create temporary directory\n"); + hFile = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); + ok(hFile != INVALID_HANDLE_VALUE, + "expected CreateFile to succeed on existing directory, error: %d\n", GetLastError()); + CloseHandle(hFile); + ret = RemoveDirectoryW(filename); + ok(ret, "DeleteFileW: error %d\n", GetLastError()); } static void test_GetTempFileNameA(void) @@ -841,17 +1236,53 @@ static void test_DeleteFileA( void ) static void test_DeleteFileW( void ) { BOOL ret; + WCHAR pathW[MAX_PATH]; + WCHAR pathsubW[MAX_PATH]; + static const WCHAR dirW[] = {'d','e','l','e','t','e','f','i','l','e',0}; + static const WCHAR subdirW[] = {'\\','s','u','b',0}; static const WCHAR emptyW[]={'\0'}; ret = DeleteFileW(NULL); if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("DeleteFileW is not available\n"); return; + } ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND, "DeleteFileW(NULL) returned ret=%d error=%d\n",ret,GetLastError()); ret = DeleteFileW(emptyW); ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND, "DeleteFileW(\"\") returned ret=%d error=%d\n",ret,GetLastError()); + + /* test DeleteFile on empty directory */ + ret = GetTempPathW(MAX_PATH, pathW); + if (ret + sizeof(dirW)/sizeof(WCHAR)-1 + sizeof(subdirW)/sizeof(WCHAR)-1 >= MAX_PATH) + { + ok(0, "MAX_PATH exceeded in constructing paths\n"); + return; +} + lstrcatW(pathW, dirW); + lstrcpyW(pathsubW, pathW); + lstrcatW(pathsubW, subdirW); + ret = CreateDirectoryW(pathW, NULL); + ok(ret == TRUE, "couldn't create directory deletefile\n"); + ret = DeleteFileW(pathW); + ok(ret == FALSE, "DeleteFile should fail for empty directories\n"); + ret = RemoveDirectoryW(pathW); + ok(ret == TRUE, "expected to remove directory deletefile\n"); + + /* test DeleteFile on non-empty directory */ + ret = CreateDirectoryW(pathW, NULL); + ok(ret == TRUE, "couldn't create directory deletefile\n"); + ret = CreateDirectoryW(pathsubW, NULL); + ok(ret == TRUE, "couldn't create directory deletefile\\sub\n"); + ret = DeleteFileW(pathW); + ok(ret == FALSE, "DeleteFile should fail for non-empty directories\n"); + ret = RemoveDirectoryW(pathsubW); + ok(ret == TRUE, "expected to remove directory deletefile\\sub\n"); + ret = RemoveDirectoryW(pathW); + ok(ret == TRUE, "expected to remove directory deletefile\n"); } #define IsDotDir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0)))) @@ -861,7 +1292,10 @@ static void test_MoveFileA(void) char tempdir[MAX_PATH]; char source[MAX_PATH], dest[MAX_PATH]; static const char prefix[] = "pfx"; + HANDLE hfile; + HANDLE hmapfile; DWORD ret; + BOOL retok; ret = GetTempPathA(MAX_PATH, tempdir); ok(ret != 0, "GetTempPathA error %d\n", GetLastError()); @@ -880,6 +1314,50 @@ static void test_MoveFileA(void) ret = DeleteFileA(dest); ok(ret, "DeleteFileA: error %d\n", GetLastError()); + hfile = CreateFileA(source, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n"); + + retok = WriteFile(hfile, prefix, sizeof(prefix), &ret, NULL ); + ok( retok && ret == sizeof(prefix), + "WriteFile error %d\n", GetLastError()); + + hmapfile = CreateFileMapping(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); + ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + + ret = MoveFileA(source, dest); + todo_wine { + ok(!ret, "MoveFileA: expected failure\n"); + ok(GetLastError() == ERROR_SHARING_VIOLATION || + broken(GetLastError() == ERROR_ACCESS_DENIED), /* Win9x and WinMe */ + "MoveFileA: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + } + + CloseHandle(hmapfile); + CloseHandle(hfile); + + /* if MoveFile succeeded, move back to dest */ + if (ret) MoveFile(dest, source); + + hfile = CreateFileA(source, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + ok(hfile != INVALID_HANDLE_VALUE, "failed to open source file\n"); + + hmapfile = CreateFileMapping(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL); + ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); + + ret = MoveFileA(source, dest); + todo_wine { + ok(!ret, "MoveFileA: expected failure\n"); + ok(GetLastError() == ERROR_SHARING_VIOLATION || + broken(GetLastError() == ERROR_ACCESS_DENIED), /* Win9x and WinMe */ + "MoveFileA: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + } + + CloseHandle(hmapfile); + CloseHandle(hfile); + + /* if MoveFile succeeded, move back to dest */ + if (ret) MoveFile(dest, source); + ret = MoveFileA(source, dest); ok(ret, "MoveFileA: failed, error %d\n", GetLastError()); @@ -936,7 +1414,10 @@ static void test_MoveFileW(void) ret = GetTempPathW(MAX_PATH, temp_path); if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetTempPathW is not available\n"); return; + } ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); @@ -1038,6 +1519,7 @@ static void test_LockFile(void) OVERLAPPED overlapped; int limited_LockFile; int limited_UnLockFile; + BOOL ret; handle = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -1097,10 +1579,15 @@ static void test_LockFile(void) "UnlockFileEx 150,100 again succeeded\n" ); } - ok( LockFile( handle, 0, 0x10000000, 0, 0xf0000000 ), "LockFile failed\n" ); + ret = LockFile( handle, 0, 0x10000000, 0, 0xf0000000 ); + if (ret) + { ok( !LockFile( handle, ~0, ~0, 1, 0 ), "LockFile ~0,1 succeeded\n" ); ok( !LockFile( handle, 0, 0x20000000, 20, 0 ), "LockFile 0x20000000,20 succeeded\n" ); ok( UnlockFile( handle, 0, 0x10000000, 0, 0xf0000000 ), "UnlockFile failed\n" ); + } + else /* win9x */ + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong LockFile error %u\n", GetLastError() ); /* wrap-around lock should not do anything */ /* (but still succeeds on NT4 so we don't check result) */ @@ -1271,6 +1758,7 @@ static void test_FindFirstFileA(void) int err; char buffer[5] = "C:\\"; char buffer2[100]; + char nonexistent[MAX_PATH]; /* try FindFirstFileA on "C:\" */ buffer[0] = get_windows_drive(); @@ -1308,8 +1796,15 @@ static void test_FindFirstFileA(void) /* try FindFirstFileA on "C:\foo\" */ SetLastError( 0xdeadbeaf ); - strcpy(buffer2, buffer); - strcat(buffer2, "foo\\"); + if (!GetTempFileNameA( buffer, "foo", 0, nonexistent ) && GetLastError() == ERROR_ACCESS_DENIED) + { + char tmp[MAX_PATH]; + GetTempPathA( sizeof(tmp), tmp ); + GetTempFileNameA( tmp, "foo", 0, nonexistent ); + } + DeleteFileA( nonexistent ); + strcpy(buffer2, nonexistent); + strcat(buffer2, "\\"); handle = FindFirstFileA(buffer2, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); @@ -1319,8 +1814,8 @@ static void test_FindFirstFileA(void) /* try FindFirstFileA on "C:\foo\bar.txt" */ SetLastError( 0xdeadbeaf ); - strcpy(buffer2, buffer); - strcat(buffer2, "foo\\bar.txt"); + strcpy(buffer2, nonexistent); + strcat(buffer2, "\\bar.txt"); handle = FindFirstFileA(buffer2, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); @@ -1328,8 +1823,8 @@ static void test_FindFirstFileA(void) /* try FindFirstFileA on "C:\foo\*.*" */ SetLastError( 0xdeadbeaf ); - strcpy(buffer2, buffer); - strcat(buffer2, "foo\\*.*"); + strcpy(buffer2, nonexistent); + strcat(buffer2, "\\*.*"); handle = FindFirstFileA(buffer2, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); @@ -1337,7 +1832,8 @@ static void test_FindFirstFileA(void) /* try FindFirstFileA on "foo\bar.txt" */ SetLastError( 0xdeadbeaf ); - strcpy(buffer2, "foo\\bar.txt"); + strcpy(buffer2, nonexistent + 3); + strcat(buffer2, "\\bar.txt"); handle = FindFirstFileA(buffer2, &data); err = GetLastError(); ok ( handle == INVALID_HANDLE_VALUE, "FindFirstFile on %s should Fail\n", buffer2 ); @@ -1351,9 +1847,14 @@ static void test_FindFirstFileA(void) err = GetLastError(); ok( handle != INVALID_HANDLE_VALUE, "FindFirstFile on %s failed\n", buffer2 ); ok( 0 == lstrcmpiA(data.cFileName, "nul"), "wrong name %s\n", data.cFileName ); + ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes || + FILE_ATTRIBUTE_DEVICE == data.dwFileAttributes /* Win9x */, + "wrong attributes %x\n", data.dwFileAttributes ); + if (data.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) + { ok( 0 == data.nFileSizeHigh, "wrong size %d\n", data.nFileSizeHigh ); ok( 0 == data.nFileSizeLow, "wrong size %d\n", data.nFileSizeLow ); - ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes, "wrong attributes %x\n", data.dwFileAttributes ); + } SetLastError( 0xdeadbeaf ); ok( !FindNextFileA( handle, &data ), "FindNextFileA succeeded\n" ); ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %d\n", GetLastError() ); @@ -1366,9 +1867,14 @@ static void test_FindFirstFileA(void) err = GetLastError(); ok( handle != INVALID_HANDLE_VALUE, "FindFirstFile on %s failed\n", buffer2 ); ok( 0 == lstrcmpiA(data.cFileName, "lpt1"), "wrong name %s\n", data.cFileName ); + ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes || + FILE_ATTRIBUTE_DEVICE == data.dwFileAttributes /* Win9x */, + "wrong attributes %x\n", data.dwFileAttributes ); + if (data.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) + { ok( 0 == data.nFileSizeHigh, "wrong size %d\n", data.nFileSizeHigh ); ok( 0 == data.nFileSizeLow, "wrong size %d\n", data.nFileSizeLow ); - ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes, "wrong attributes %x\n", data.dwFileAttributes ); + } SetLastError( 0xdeadbeaf ); ok( !FindNextFileA( handle, &data ), "FindNextFileA succeeded\n" ); ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %d\n", GetLastError() ); @@ -1430,14 +1936,15 @@ static void test_FindNextFileA(void) ok ( err == ERROR_NO_MORE_FILES, "GetLastError should return ERROR_NO_MORE_FILES\n"); } -static void test_FindFirstFileExA(void) +static void test_FindFirstFileExA(FINDEX_SEARCH_OPS search_ops) { WIN32_FIND_DATAA search_results; HANDLE handle; + BOOL ret; if (!pFindFirstFileExA) { - skip("FindFirstFileExA() is missing\n"); + win_skip("FindFirstFileExA() is missing\n"); return; } @@ -1445,8 +1952,13 @@ static void test_FindFirstFileExA(void) _lclose(_lcreat("test-dir\\file1", 0)); _lclose(_lcreat("test-dir\\file2", 0)); CreateDirectoryA("test-dir\\dir1", NULL); - /* FindExLimitToDirectories is ignored */ - handle = pFindFirstFileExA("test-dir\\*", FindExInfoStandard, &search_results, FindExSearchLimitToDirectories, NULL, 0); + SetLastError(0xdeadbeef); + handle = pFindFirstFileExA("test-dir\\*", FindExInfoStandard, &search_results, search_ops, NULL, 0); + if (handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("FindFirstFileExA is not implemented\n"); + goto cleanup; + } ok(handle != INVALID_HANDLE_VALUE, "FindFirstFile failed (err=%u)\n", GetLastError()); ok(strcmp(search_results.cFileName, ".") == 0, "First entry should be '.', is %s\n", search_results.cFileName); @@ -1456,9 +1968,20 @@ static void test_FindFirstFileExA(void) ok(strcmp(search_results.cFileName, "..") == 0, "Second entry should be '..' is %s\n", search_results.cFileName); ok(FindNextFile(handle, &search_results), "Fetching third file failed\n"); - ok(CHECK_NAME(search_results.cFileName), "Invalid thrid entry - %s\n", search_results.cFileName); + ok(CHECK_NAME(search_results.cFileName), "Invalid third entry - %s\n", search_results.cFileName); - ok(FindNextFile(handle, &search_results), "Fetching fourth file failed\n"); + SetLastError(0xdeadbeef); + ret = FindNextFile(handle, &search_results); + if (!ret && (GetLastError() == ERROR_NO_MORE_FILES) && (search_ops == FindExSearchLimitToDirectories)) + { + skip("File system supports directory filtering\n"); + /* Results from the previous call are not cleared */ + ok(strcmp(search_results.cFileName, "dir1") == 0, "Third entry should be 'dir1' is %s\n", search_results.cFileName); + FindClose( handle ); + goto cleanup; + } + + ok(ret, "Fetching fourth file failed\n"); ok(CHECK_NAME(search_results.cFileName), "Invalid fourth entry - %s\n", search_results.cFileName); ok(FindNextFile(handle, &search_results), "Fetching fifth file failed\n"); @@ -1466,7 +1989,11 @@ static void test_FindFirstFileExA(void) #undef CHECK_NAME - ok(FindNextFile(handle, &search_results) == FALSE, "Fetching sixth file should failed\n"); + ok(FindNextFile(handle, &search_results) == FALSE, "Fetching sixth file should fail\n"); + + FindClose( handle ); + +cleanup: DeleteFileA("test-dir\\file1"); DeleteFileA("test-dir\\file2"); RemoveDirectoryA("test-dir\\dir1"); @@ -1514,12 +2041,16 @@ static void test_MapFile(void) ok( GetLastError() == ERROR_FILE_INVALID, "not ERROR_FILE_INVALID\n"); hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0x80000000, 0, NULL ); - ok( hmap == NULL, "mapping should fail\n"); + ok( hmap == NULL || broken(hmap != NULL) /* NT4 */, "mapping should fail\n"); /* GetLastError() varies between win9x and WinNT and also depends on the filesystem */ + if ( hmap ) + CloseHandle( hmap ); hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0x80000000, 0x10000, NULL ); - ok( hmap == NULL, "mapping should fail\n"); + ok( hmap == NULL || broken(hmap != NULL) /* NT4 */, "mapping should fail\n"); /* GetLastError() varies between win9x and WinNT and also depends on the filesystem */ + if ( hmap ) + CloseHandle( hmap ); /* On XP you can now map again, on Win 95 you cannot. */ @@ -1566,18 +2097,25 @@ static void test_async_file_errors(void) szFile[0] = '\0'; GetWindowsDirectoryA(szFile, sizeof(szFile)/sizeof(szFile[0])-1-strlen("\\win.ini")); strcat(szFile, "\\win.ini"); - hFile = CreateFileA(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); - ok(hFile != NULL, "CreateFileA(%s ...) failed\n", szFile); + hFile = CreateFileA(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); + if (hFile == INVALID_HANDLE_VALUE) /* win9x doesn't like FILE_SHARE_DELETE */ + hFile = CreateFileA(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA(%s ...) failed\n", szFile); while (TRUE) { BOOL res; + DWORD count; while (WaitForSingleObjectEx(hSem, INFINITE, TRUE) == WAIT_IO_COMPLETION) ; res = ReadFileEx(hFile, lpBuffer, 4096, &ovl, FileIOComplete); /*printf("Offset = %ld, result = %s\n", ovl.Offset, res ? "TRUE" : "FALSE");*/ if (!res) break; - S(U(ovl)).Offset += 4096; + if (!GetOverlappedResult(hFile, &ovl, &count, FALSE)) + break; + S(U(ovl)).Offset += count; /* i/o completion routine only called if ReadFileEx returned success. * we only care about violations of this rule so undo what should have * been done */ @@ -1585,14 +2123,16 @@ static void test_async_file_errors(void) } ok(completion_count == 0, "completion routine should only be called when ReadFileEx succeeds (this rule was violated %d times)\n", completion_count); /*printf("Error = %ld\n", GetLastError());*/ + HeapFree(GetProcessHeap(), 0, lpBuffer); } static void test_read_write(void) { - DWORD bytes, ret; + DWORD bytes, ret, old_prot; HANDLE hFile; char temp_path[MAX_PATH]; char filename[MAX_PATH]; + char *mem; static const char prefix[] = "pfx"; ret = GetTempPathA(MAX_PATH, temp_path); @@ -1642,6 +2182,95 @@ static void test_read_write(void) "ret = %d, error %d\n", ret, GetLastError()); ok(!bytes, "bytes = %d\n", bytes); + /* test passing protected memory as buffer */ + + mem = VirtualAlloc( NULL, 0x4000, MEM_COMMIT, PAGE_READWRITE ); + ok( mem != NULL, "failed to allocate virtual mem error %u\n", GetLastError() ); + + ret = WriteFile( hFile, mem, 0x4000, &bytes, NULL ); + ok( ret, "WriteFile failed error %u\n", GetLastError() ); + ok( bytes == 0x4000, "only wrote %x bytes\n", bytes ); + + ret = VirtualProtect( mem + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + + ret = WriteFile( hFile, mem, 0x4000, &bytes, NULL ); + ok( !ret, "WriteFile succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_USER_BUFFER || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "wrong error %u\n", GetLastError() ); + ok( bytes == 0, "wrote %x bytes\n", bytes ); + + ret = WriteFile( (HANDLE)0xdead, mem, 0x4000, &bytes, NULL ); + ok( !ret, "WriteFile succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_HANDLE || /* handle is checked before buffer on NT */ + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "wrong error %u\n", GetLastError() ); + ok( bytes == 0, "wrote %x bytes\n", bytes ); + + ret = VirtualProtect( mem, 0x2000, PAGE_NOACCESS, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + + ret = WriteFile( hFile, mem, 0x4000, &bytes, NULL ); + ok( !ret, "WriteFile succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_USER_BUFFER || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "wrong error %u\n", GetLastError() ); + ok( bytes == 0, "wrote %x bytes\n", bytes ); + + SetFilePointer( hFile, 0, NULL, FILE_BEGIN ); + + ret = ReadFile( hFile, mem, 0x4000, &bytes, NULL ); + ok( !ret, "ReadFile succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "wrong error %u\n", GetLastError() ); + ok( bytes == 0, "read %x bytes\n", bytes ); + + ret = VirtualProtect( mem, 0x2000, PAGE_READONLY, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + + ret = ReadFile( hFile, mem, 0x4000, &bytes, NULL ); + ok( !ret, "ReadFile succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "wrong error %u\n", GetLastError() ); + ok( bytes == 0, "read %x bytes\n", bytes ); + + ret = VirtualProtect( mem, 0x2000, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + + ret = ReadFile( hFile, mem, 0x4000, &bytes, NULL ); + ok( !ret, "ReadFile succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "wrong error %u\n", GetLastError() ); + ok( bytes == 0, "read %x bytes\n", bytes ); + + SetFilePointer( hFile, 0x1234, NULL, FILE_BEGIN ); + SetEndOfFile( hFile ); + SetFilePointer( hFile, 0, NULL, FILE_BEGIN ); + + ret = ReadFile( hFile, mem, 0x4000, &bytes, NULL ); + ok( !ret, "ReadFile succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "wrong error %u\n", GetLastError() ); + ok( bytes == 0, "read %x bytes\n", bytes ); + + ret = ReadFile( hFile, mem, 0x2000, &bytes, NULL ); + ok( ret, "ReadFile failed error %u\n", GetLastError() ); + ok( bytes == 0x1234, "read %x bytes\n", bytes ); + + ret = ReadFile( hFile, NULL, 1, &bytes, NULL ); + ok( !ret, "ReadFile succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "wrong error %u\n", GetLastError() ); + ok( bytes == 0, "read %x bytes\n", bytes ); + + VirtualFree( mem, 0, MEM_FREE ); + ret = CloseHandle(hFile); ok( ret, "CloseHandle: error %d\n", GetLastError()); ret = DeleteFileA(filename); @@ -1655,26 +2284,31 @@ static void test_OpenFile(void) BOOL ret; DWORD retval; - static const char *file = "\\regsvr32.exe"; - static const char *foo = ".\\foo-bar-foo.baz"; + static const char file[] = "regedit.exe"; + static const char foo[] = ".\\foo-bar-foo.baz"; static const char *foo_too_long = ".\\foo-bar-foo.baz+++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; - static const char *backslash = "\\"; char buff[MAX_PATH]; char buff_long[4*MAX_PATH]; char filled_0xA5[OFS_MAXPATHNAME]; + char *p; UINT length; /* Check for existing file */ - length = GetSystemDirectoryA(buff, MAX_PATH); + if (!pGetSystemWindowsDirectoryA) + length = GetWindowsDirectoryA(buff, MAX_PATH); + else + length = pGetSystemWindowsDirectoryA(buff, MAX_PATH); - if (length + lstrlen(file) < MAX_PATH) + if (length + sizeof(file) < MAX_PATH) { - lstrcatA(buff, file); + p = buff + strlen(buff); + if (p > buff && p[-1] != '\\') *p++ = '\\'; + strcpy( p, file ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1693,9 +2327,11 @@ static void test_OpenFile(void) length = GetCurrentDirectoryA(MAX_PATH, buff); /* Check for nonexistent file */ - if (length + lstrlenA(foo + 1) < MAX_PATH) + if (length + sizeof(foo) < MAX_PATH) { - lstrcatA(buff, foo + 1); /* Avoid '.' during concatenation */ + p = buff + strlen(buff); + if (p > buff && p[-1] != '\\') *p++ = '\\'; + strcpy( p, foo + 2 ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1733,17 +2369,16 @@ static void test_OpenFile(void) ofs.szPathName ); } - length = GetCurrentDirectoryA(MAX_PATH, buff); - length += lstrlenA(backslash); - length += lstrlenA(filename); + length = GetCurrentDirectoryA(MAX_PATH, buff) + sizeof(filename); if (length >= MAX_PATH) { trace("Buffer too small, requested length = %d, but MAX_PATH = %d. Skipping test.\n", length, MAX_PATH); return; } - lstrcatA(buff, backslash); - lstrcatA(buff, filename); + p = buff + strlen(buff); + if (p > buff && p[-1] != '\\') *p++ = '\\'; + strcpy( p, filename ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1753,9 +2388,10 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); - ret = CloseHandle((HANDLE)hFile); - ok( ret == TRUE, "CloseHandle() returns %d\n", ret ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ret = _lclose(hFile); + ok( !ret, "_lclose() returns %d\n", ret ); retval = GetFileAttributesA(filename); ok( retval != INVALID_FILE_ATTRIBUTES, "GetFileAttributesA: error %d\n", GetLastError() ); @@ -1768,11 +2404,12 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); - ret = CloseHandle((HANDLE)hFile); - ok( ret == TRUE, "CloseHandle() returns %d\n", ret ); + ret = _lclose(hFile); + ok( !ret, "_lclose() returns %d\n", ret ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1782,11 +2419,12 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); - ret = CloseHandle((HANDLE)hFile); - ok( ret == TRUE, "CloseHandle() returns %d\n", ret ); + ret = _lclose(hFile); + ok( !ret, "_lclose() returns %d\n", ret ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1796,11 +2434,12 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); - ret = CloseHandle((HANDLE)hFile); - ok( ret == TRUE, "CloseHandle() returns %d\n", ret ); + ret = _lclose(hFile); + ok( !ret, "_lclose() returns %d\n", ret ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1810,7 +2449,8 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); @@ -1822,7 +2462,8 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); @@ -1836,19 +2477,29 @@ static void test_overlapped(void) DWORD r, result; /* GetOverlappedResult crashes if the 2nd or 3rd param are NULL */ + if (0) /* tested: WinXP */ + { + GetOverlappedResult(0, NULL, &result, FALSE); + GetOverlappedResult(0, &ov, NULL, FALSE); + GetOverlappedResult(0, NULL, NULL, FALSE); + } memset( &ov, 0, sizeof ov ); result = 1; r = GetOverlappedResult(0, &ov, &result, 0); - ok( r == TRUE, "should return false\n"); + if (r) ok( result == 0, "wrong result %u\n", result ); + else /* win9x */ + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); result = 0; ov.Internal = 0; ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); - ok( r == TRUE, "should return false\n"); + if (r) ok( result == 0xabcd, "wrong result %u\n", result ); + else /* win9x */ + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); SetLastError( 0xb00 ); result = 0; @@ -1857,14 +2508,15 @@ static void test_overlapped(void) r = GetOverlappedResult(0, &ov, &result, 0); ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); - ok( result == 0xabcd, "wrong result %u\n", result ); + ok( result == 0xabcd || result == 0 /* win9x */, "wrong result %u\n", result ); SetLastError( 0xb00 ); result = 0; ov.Internal = STATUS_PENDING; ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); - ok( GetLastError() == ERROR_IO_INCOMPLETE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, + "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); ok( result == 0, "wrong result %u\n", result ); @@ -1873,7 +2525,8 @@ static void test_overlapped(void) ov.Internal = STATUS_PENDING; ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); - ok( GetLastError() == ERROR_IO_INCOMPLETE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, + "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); ResetEvent( ov.hEvent ); @@ -1882,7 +2535,8 @@ static void test_overlapped(void) ov.Internal = STATUS_PENDING; ov.InternalHigh = 0; r = GetOverlappedResult(0, &ov, &result, 0); - ok( GetLastError() == ERROR_IO_INCOMPLETE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, + "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); r = CloseHandle( ov.hEvent ); @@ -1901,19 +2555,23 @@ static void test_RemoveDirectory(void) ok( rc, "SetCurrentDirectory failed, gle=%d\n", GetLastError() ); rc = RemoveDirectory("."); - todo_wine { - ok( !rc, "RemoveDirectory unexpectedly worked\n" ); - } - + if (!rc) + { rc = SetCurrentDirectory(".."); ok( rc, "SetCurrentDirectory failed, gle=%d\n", GetLastError() ); rc = RemoveDirectory(directory); - todo_wine { ok( rc, "RemoveDirectory failed, gle=%d\n", GetLastError() ); } } +static BOOL check_file_time( const FILETIME *ft1, const FILETIME *ft2, UINT tolerance ) +{ + ULONGLONG t1 = ((ULONGLONG)ft1->dwHighDateTime << 32) | ft1->dwLowDateTime; + ULONGLONG t2 = ((ULONGLONG)ft2->dwHighDateTime << 32) | ft2->dwLowDateTime; + return abs(t1 - t2) <= tolerance; +} + static void test_ReplaceFileA(void) { char replaced[MAX_PATH], replacement[MAX_PATH], backup[MAX_PATH]; @@ -1925,11 +2583,11 @@ static void test_ReplaceFileA(void) static const char prefix[] = "pfx"; char temp_path[MAX_PATH]; DWORD ret; - BOOL retok; + BOOL retok, removeBackup = FALSE; if (!pReplaceFileA) { - skip("ReplaceFileA() is missing\n"); + win_skip("ReplaceFileA() is missing\n"); return; } @@ -2010,7 +2668,9 @@ static void test_ReplaceFileA(void) /* make sure that the "replaced" file has the size of the replacement file */ hReplacedFile = CreateFileA(replaced, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); ok(hReplacedFile != INVALID_HANDLE_VALUE, - "failed to open replaced file\n"); + "failed to open replaced file: %d\n", GetLastError()); + if (hReplacedFile != INVALID_HANDLE_VALUE) + { ret = GetFileSize(hReplacedFile, NULL); ok(ret == sizeof(replacementData), "replaced file has wrong size %d\n", ret); @@ -2021,15 +2681,19 @@ static void test_ReplaceFileA(void) /* make sure that the backup has the old "replaced" filetime */ ret = GetFileTime(hBackupFile, NULL, NULL, &ftBackup); ok( ret, "GetFileTime error (backup %d\n", GetLastError()); - ok(CompareFileTime(&ftBackup, &ftReplaced) == 0, - "backup file has wrong filetime\n"); + ok(check_file_time(&ftBackup, &ftReplaced, 20000000), "backup file has wrong filetime\n"); CloseHandle(hBackupFile); /* make sure that the "replaced" has the old replacement filetime */ ret = GetFileTime(hReplacedFile, NULL, NULL, &ftReplaced); ok( ret, "GetFileTime error (backup %d\n", GetLastError()); - ok(CompareFileTime(&ftReplaced, &ftReplacement) == 0, - "replaced file has wrong filetime\n"); + ok(check_file_time(&ftReplaced, &ftReplacement, 20000000), + "replaced file has wrong filetime %x%08x / %x%08x\n", + ftReplaced.dwHighDateTime, ftReplaced.dwLowDateTime, + ftReplacement.dwHighDateTime, ftReplacement.dwLowDateTime ); CloseHandle(hReplacedFile); + } + else + skip("couldn't open replacement file, skipping tests\n"); /* re-create replacement file for pass w/o backup (blank) */ ret = GetTempFileNameA(temp_path, prefix, 0, replacement); @@ -2039,7 +2703,8 @@ static void test_ReplaceFileA(void) */ SetLastError(0xdeadbeef); ret = pReplaceFileA(replaced, replacement, NULL, 0, 0, 0); - ok(ret, "ReplaceFileA: unexpected error %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "ReplaceFileA: unexpected error %d\n", GetLastError()); /* re-create replacement file for pass w/ backup (backup-file not existing) */ ret = GetTempFileNameA(temp_path, prefix, 0, replacement); @@ -2051,13 +2716,17 @@ static void test_ReplaceFileA(void) */ SetLastError(0xdeadbeef); ret = pReplaceFileA(replaced, replacement, backup, 0, 0, 0); - ok(ret, "ReplaceFileA: unexpected error %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "ReplaceFileA: unexpected error %d\n", GetLastError()); + if (ret) + removeBackup = TRUE; /* re-create replacement file for pass w/ no permissions to "replaced" */ ret = GetTempFileNameA(temp_path, prefix, 0, replacement); ok(ret != 0, "GetTempFileNameA error (replacement) %d\n", GetLastError()); ret = SetFileAttributesA(replaced, FILE_ATTRIBUTE_READONLY); - ok(ret, "SetFileAttributesA: error setting to read only %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "SetFileAttributesA: error setting to read only %d\n", GetLastError()); /* perform replacement w/ backup (no permission to "replaced") * TODO: flags are not implemented */ @@ -2066,21 +2735,25 @@ static void test_ReplaceFileA(void) ok(ret != ERROR_UNABLE_TO_REMOVE_REPLACED, "ReplaceFileA: unexpected error %d\n", GetLastError()); /* make sure that the replacement file still exists */ hReplacementFile = CreateFileA(replacement, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hReplacementFile != INVALID_HANDLE_VALUE, + ok(hReplacementFile != INVALID_HANDLE_VALUE || + broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* win2k */ "unexpected error, replacement file should still exist %d\n", GetLastError()); CloseHandle(hReplacementFile); ret = SetFileAttributesA(replaced, FILE_ATTRIBUTE_NORMAL); - ok(ret, "SetFileAttributesA: error setting to normal %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "SetFileAttributesA: error setting to normal %d\n", GetLastError()); /* replacement file still exists, make pass w/o "replaced" */ ret = DeleteFileA(replaced); - ok(ret, "DeleteFileA: error (replaced) %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "DeleteFileA: error (replaced) %d\n", GetLastError()); /* perform replacement w/ backup (no pre-existing backup or "replaced") * TODO: flags are not implemented */ SetLastError(0xdeadbeef); ret = pReplaceFileA(replaced, replacement, backup, 0, 0, 0); - ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_ACCESS_DENIED), "ReplaceFileA: unexpected error %d\n", GetLastError()); /* perform replacement w/o existing "replacement" file @@ -2088,7 +2761,8 @@ static void test_ReplaceFileA(void) */ SetLastError(0xdeadbeef); ret = pReplaceFileA(replaced, replacement, NULL, 0, 0, 0); - ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_ACCESS_DENIED), "ReplaceFileA: unexpected error %d\n", GetLastError()); /* @@ -2098,8 +2772,13 @@ static void test_ReplaceFileA(void) */ /* delete temporary files, replacement and replaced are already deleted */ + if (removeBackup) + { ret = DeleteFileA(backup); - ok(ret, "DeleteFileA: error (backup) %d\n", GetLastError()); + ok(ret || + broken(GetLastError() == ERROR_ACCESS_DENIED), /* win2k */ + "DeleteFileA: error (backup) %d\n", GetLastError()); +} } /* @@ -2112,16 +2791,20 @@ static void test_ReplaceFileW(void) static const WCHAR prefix[] = {'p','f','x',0}; WCHAR temp_path[MAX_PATH]; DWORD ret; + BOOL removeBackup = FALSE; if (!pReplaceFileW) { - skip("ReplaceFileW() is missing\n"); + win_skip("ReplaceFileW() is missing\n"); return; } ret = GetTempPathW(MAX_PATH, temp_path); if (ret==0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetTempPathW is not available\n"); return; + } ok(ret != 0, "GetTempPathW error %d\n", GetLastError()); ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n"); @@ -2140,25 +2823,31 @@ static void test_ReplaceFileW(void) ret = GetTempFileNameW(temp_path, prefix, 0, replacement); ok(ret != 0, "GetTempFileNameW error (replacement) %d\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, NULL, 0, 0, 0); - ok(ret, "ReplaceFileW: error %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "ReplaceFileW: error %d\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, replacement); ok(ret != 0, "GetTempFileNameW error (replacement) %d\n", GetLastError()); ret = DeleteFileW(backup); ok(ret, "DeleteFileW: error (backup) %d\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, backup, 0, 0, 0); - ok(ret, "ReplaceFileW: error %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "ReplaceFileW: error %d\n", GetLastError()); ret = GetTempFileNameW(temp_path, prefix, 0, replacement); ok(ret != 0, "GetTempFileNameW error (replacement) %d\n", GetLastError()); ret = SetFileAttributesW(replaced, FILE_ATTRIBUTE_READONLY); - ok(ret, "SetFileAttributesW: error setting to read only %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "SetFileAttributesW: error setting to read only %d\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, backup, 0, 0, 0); ok(ret != ERROR_UNABLE_TO_REMOVE_REPLACED, "ReplaceFileW: unexpected error %d\n", GetLastError()); ret = SetFileAttributesW(replaced, FILE_ATTRIBUTE_NORMAL); - ok(ret, "SetFileAttributesW: error setting to normal %d\n", GetLastError()); + ok(ret || GetLastError() == ERROR_ACCESS_DENIED, + "SetFileAttributesW: error setting to normal %d\n", GetLastError()); + if (ret) + removeBackup = TRUE; ret = DeleteFileW(replaced); ok(ret, "DeleteFileW: error (replaced) %d\n", GetLastError()); @@ -2166,11 +2855,17 @@ static void test_ReplaceFileW(void) ok(!ret, "ReplaceFileW: error %d\n", GetLastError()); ret = pReplaceFileW(replaced, replacement, NULL, 0, 0, 0); - ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, + ok(!ret && (GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_ACCESS_DENIED), "ReplaceFileW: unexpected error %d\n", GetLastError()); + if (removeBackup) + { ret = DeleteFileW(backup); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret || + broken(GetLastError() == ERROR_ACCESS_DENIED), /* win2k */ + "DeleteFileW: error (backup) %d\n", GetLastError()); +} } START_TEST(file) @@ -2196,7 +2891,9 @@ START_TEST(file) test_MoveFileW(); test_FindFirstFileA(); test_FindNextFileA(); - test_FindFirstFileExA(); + test_FindFirstFileExA(0); + /* FindExLimitToDirectories is ignored if the file system doesn't support directory filtering */ + test_FindFirstFileExA(FindExSearchLimitToDirectories); test_LockFile(); test_file_sharing(); test_offset_in_overlapped_structure(); diff --git a/rostests/winetests/kernel32/format_msg.c b/rostests/winetests/kernel32/format_msg.c index 1f52da9a8f5..7b249924afe 100755 --- a/rostests/winetests/kernel32/format_msg.c +++ b/rostests/winetests/kernel32/format_msg.c @@ -1,4 +1,4 @@ -/* Unit test suite for FormatMessageA +/* Unit test suite for FormatMessageA/W * * Copyright 2002 Mike McCormack for CodeWeavers * @@ -22,22 +22,365 @@ #include "wine/test.h" #include "windef.h" #include "winbase.h" +#include "winnls.h" /* #define ok(cond,failstr) if(!(cond)) {printf("line %d : %s\n",__LINE__,failstr);exit(1);} */ -static DWORD doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id, +static DWORD __cdecl doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id, LPSTR out, DWORD outsize, ... ) { - va_list list; + __ms_va_list list; DWORD r; - va_start(list, outsize); + __ms_va_start(list, outsize); r = FormatMessageA(flags, src, msg_id, lang_id, out, outsize, &list); - va_end(list); + __ms_va_end(list); return r; } +static DWORD __cdecl doitW(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id, + LPWSTR out, DWORD outsize, ... ) +{ + __ms_va_list list; + DWORD r; + + __ms_va_start(list, outsize); + r = FormatMessageW(flags, src, msg_id, + lang_id, out, outsize, &list); + __ms_va_end(list); + return r; +} + +static void test_message_from_string_wide(void) +{ + static const WCHAR test[] = {'t','e','s','t',0}; + static const WCHAR te[] = {'t','e',0}; + static const WCHAR st[] = {'s','t',0}; + static const WCHAR t[] = {'t',0}; + static const WCHAR e[] = {'e',0}; + static const WCHAR s[] = {'s',0}; + static const WCHAR fmt_1[] = {'%','1',0}; + static const WCHAR fmt_12[] = {'%','1','%','2',0}; + static const WCHAR fmt_123[] = {'%','1','%','3','%','2','%','1',0}; + static const WCHAR fmt_123c[] = {'%','1','!','c','!','%','2','!','c','!','%','3','!','c','!','%','1','!','c','!',0}; + static const WCHAR fmt_123lc[] = {'%','1','!','l','c','!','%','2','!','l','c','!','%','3','!','l','c','!','%','1','!','l','c','!',0}; + static const WCHAR fmt_123wc[] = {'%','1','!','w','c','!','%','2','!','w','c','!','%','3','!','w','c','!','%','1','!','w','c','!',0}; + static const WCHAR fmt_123C[] = {'%','1','!','C','!','%','2','!','C','!','%','3','!','C','!','%','1','!','C','!',0}; + static const WCHAR fmt_123d[] = {'%','1','!','d','!','%','2','!','d','!','%','3','!','d','!',0}; + static const WCHAR fmt_1s[] = {'%','1','!','s','!',0}; + static const WCHAR fmt_s[] = {'%','!','s','!',0}; + static const WCHAR fmt_ls[] = {'%','!','l','s','!',0}; + static const WCHAR fmt_ws[] = {'%','!','w','s','!',0}; + static const WCHAR fmt_S[] = {'%','!','S','!',0}; + static const WCHAR fmt_14d[] = {'%','1','!','4','d','!',0}; + static const WCHAR fmt_14x[] = {'%','1','!','4','x','!',0}; + static const WCHAR fmt_14X[] = {'%','1','!','4','X','!',0}; + static const WCHAR fmt_1_4X[] = {'%','1','!','-','4','X','!',0}; + static const WCHAR fmt_1_4d[] = {'%','1','!','-','4','d','!',0}; + static const WCHAR fmt_2pct[] = {' ','%','%','%','%',' ',0}; + static const WCHAR fmt_2dot1d[] = {' ', '%','.','%','.',' ',' ','%','1','!','d','!',0}; + static const WCHAR fmt_t0t[] = {'t','e','s','t','%','0','t','e','s','t',0}; + static const WCHAR fmt_yah[] = {'y','a','h','%','!','%','0',' ',' ',' ',0}; + static const WCHAR fmt_space[] = {'%',' ','%',' ',' ',' ',0}; + static const WCHAR fmt_hi_lf[] = {'h','i','\n',0}; + static const WCHAR fmt_hi_crlf[] = {'h','i','\r','\n',0}; + static const WCHAR fmt_cr[] = {'\r',0}; + static const WCHAR fmt_crcrlf[] = {'\r','\r','\n',0}; + static const WCHAR fmt_13s[] = {'%','1','!','3','s','!',0}; + static const WCHAR fmt_1os[] = {'%','1','!','*','s','!',0}; + static const WCHAR fmt_142u[] = {'%','1','!','4','.','2','u','!',0}; + static const WCHAR fmt_1oou[] = {'%','1','!','*','.','*','u','!',0}; + static const WCHAR fmt_1oou1oou[] = {'%','1','!','*','.','*','u','!',',','%','1','!','*','.','*','u','!',0}; + static const WCHAR fmt_1oou3oou[] = {'%','1','!','*','.','*','u','!',',','%','3','!','*','.','*','u','!',0}; + static const WCHAR fmt_1oou4oou[] = {'%','1','!','*','.','*','u','!',',','%','4','!','*','.','*','u','!',0}; + + static const WCHAR s_123d[] = {'1','2','3',0}; + static const WCHAR s_14d[] = {' ',' ',' ','1',0}; + static const WCHAR s_14x[] = {' ',' ',' ','b',0}; + static const WCHAR s_14X[] = {' ',' ',' ','B',0}; + static const WCHAR s_1_4X[] = {'B',' ',' ',' ',0}; + static const WCHAR s_14d2[] = {' ',' ','1','1',0}; + static const WCHAR s_1_4d[] = {'1',' ',' ',' ',0}; + static const WCHAR s_1AB[] = {' ','1','A','B',0}; + static const WCHAR s_2pct[] = {' ','%','%',' ',0}; + static const WCHAR s_2dot147[] = {' ','.','.',' ',' ','4','2','7',0}; + static const WCHAR s_yah[] = {'y','a','h','!',0}; + static const WCHAR s_space[] = {' ',' ',' ',' ',0}; + static const WCHAR s_hi_crlf[] = {'h','i','\r','\n',0}; + static const WCHAR s_crlf[] = {'\r','\n',0}; + static const WCHAR s_crlfcrlf[] = {'\r','\n','\r','\n',0}; + static const WCHAR s_hi_sp[] = {'h','i',' ',0}; + static const WCHAR s_sp[] = {' ',0}; + static const WCHAR s_2sp[] = {' ',' ',0}; + static const WCHAR s_spt[] = {' ',' ','t',0}; + static const WCHAR s_sp3t[] = {' ',' ',' ','t',0}; + static const WCHAR s_sp03[] = {' ',' ','0','3',0}; + static const WCHAR s_sp001[] = {' ',' ','0','0','1',0}; + static const WCHAR s_sp001002[] = {' ',' ','0','0','1',',',' ','0','0','0','2',0}; + static const WCHAR s_sp001sp002[] = {' ',' ','0','0','1',',',' ',' ','0','0','0','2',0}; + static const WCHAR s_sp002sp001[] = {' ',' ','0','0','0','2',',',' ',' ','0','0','1',0}; + static const WCHAR s_sp002sp003[] = {' ',' ','0','0','0','2',',',' ','0','0','0','0','3',0}; + static const WCHAR s_sp001004[] = {' ',' ','0','0','1',',','0','0','0','0','0','4',0}; + + WCHAR out[0x100] = {0}; + DWORD r, error; + + SetLastError(0xdeadbeef); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, NULL, 0, 0, NULL, 0, NULL); + error = GetLastError(); + if (!r && error == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("FormatMessageW is not implemented\n"); + return; + } + + /* the basics */ + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, + 0, out, sizeof(out)/sizeof(WCHAR), NULL); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4, "failed: r=%d\n", r); + + /* using the format feature */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1s, 0, + 0, out, sizeof(out)/sizeof(WCHAR), test); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* no format */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1, 0, + 0, out, sizeof(out)/sizeof(WCHAR), test); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* two pieces */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_12, 0, + 0, out, sizeof(out)/sizeof(WCHAR), te, st); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* three pieces */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123, 0, + 0, out, sizeof(out)/sizeof(WCHAR), t, s, e); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* s doesn't seem to work in format strings */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_s, 0, + 0, out, sizeof(out)/sizeof(WCHAR), test); + ok(!lstrcmpW(&fmt_s[1], out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3, "failed: r=%d\n", r); + + /* nor ls */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_ls, 0, + 0, out, sizeof(out)/sizeof(WCHAR), test); + ok(!lstrcmpW(&fmt_ls[1], out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4, "failed: r=%d\n", r); + + /* nor S */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_S, 0, + 0, out, sizeof(out)/sizeof(WCHAR), test); + ok(!lstrcmpW(&fmt_S[1], out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3, "failed: r=%d\n", r); + + /* nor ws */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_ws, 0, + 0, out, sizeof(out)/sizeof(WCHAR), test); + ok(!lstrcmpW(&fmt_ws[1], out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4, "failed: r=%d\n", r); + + /* as characters */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123c, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's'); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* lc is unicode */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123lc, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's'); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* wc is unicode */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123wc, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's'); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* C is unicode */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123C, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's'); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* some numbers */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123d, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 1, 2, 3); + ok(!lstrcmpW(s_123d, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3,"failed: r=%d\n", r); + + /* a single digit with some spacing */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14d, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 1); + ok(!lstrcmpW(s_14d, out), "failed out=%s\n", wine_dbgstr_w(out)); + + /* a single digit, left justified */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1_4d, 0, + 0, out, sizeof(out)/sizeof(CHAR), 1); + ok(!lstrcmpW(s_1_4d, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* two digit decimal number */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14d, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 11); + ok(!lstrcmpW(s_14d2, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* a hex number */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14x, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 11); + ok(!lstrcmpW(s_14x, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* a hex number, upper case */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14X, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 11); + ok(!lstrcmpW(s_14X, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* a hex number, upper case, left justified */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1_4X, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 11); + ok(!lstrcmpW(s_1_4X, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* a long hex number, upper case */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14X, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 0x1ab); + ok(!lstrcmpW(s_1AB, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* two percent... */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_2pct, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_2pct, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* periods are special cases */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_2dot1d, 0, + 0, out, sizeof(out)/sizeof(WCHAR), 0x1ab); + ok(!lstrcmpW(s_2dot147, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==8,"failed: r=%d\n", r); + + /* %0 ends the line */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_t0t, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(test, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* %! prints an exclamation */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_yah, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_yah, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* %space */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_space, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_space, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* line feed */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_hi_lf, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_hi_crlf, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* carriage return line feed */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_hi_crlf, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_hi_crlf, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* carriage return */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_cr, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_crlf, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==2,"failed: r=%d\n", r); + + /* double carriage return line feed */ + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_crcrlf, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_crlfcrlf, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n", r); + + /* precision and width */ + + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_13s, + 0, 0, out, sizeof(out)/sizeof(WCHAR), t ); + ok(!lstrcmpW(s_spt, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==3, "failed: r=%d\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1os, + 0, 0, out, sizeof(out)/sizeof(WCHAR), 4, t ); + ok(!lstrcmpW( s_sp3t, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_142u, + 0, 0, out, sizeof(out)/sizeof(WCHAR), 3 ); + ok(!lstrcmpW( s_sp03, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==4,"failed: r=%d\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1oou, + 0, 0, out, sizeof(out)/sizeof(WCHAR), 5, 3, 1 ); + ok(!lstrcmpW( s_sp001, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==5,"failed: r=%d\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1oou1oou, + 0, 0, out, sizeof(out)/sizeof(WCHAR), 5, 3, 1, 4, 2 ); + ok(!lstrcmpW( s_sp001002, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==11,"failed: r=%d\n",r); + r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1oou3oou, + 0, 0, out, sizeof(out)/sizeof(WCHAR), 5, 3, 1, 6, 4, 2 ); + ok(!lstrcmpW( s_sp001sp002, out) || broken(!lstrcmpW(s_sp001004, out)), + "failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==12,"failed: r=%d\n",r); + /* args are not counted the same way with an argument array */ + { + ULONG_PTR args[] = { 6, 4, 2, 5, 3, 1 }; + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, fmt_1oou1oou, + 0, 0, out, sizeof(out)/sizeof(WCHAR), (__ms_va_list *)args ); + ok(!lstrcmpW(s_sp002sp003, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==13,"failed: r=%d\n",r); + r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, fmt_1oou4oou, + 0, 0, out, sizeof(out)/sizeof(WCHAR), (__ms_va_list *)args ); + ok(!lstrcmpW(s_sp002sp001, out),"failed out=[%s]\n", wine_dbgstr_w(out)); + ok(r==12,"failed: r=%d\n",r); + } + + /* change of pace... test the low byte of dwflags */ + + /* line feed */ + r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_hi_lf, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_hi_sp, out) || !lstrcmpW(s_hi_crlf, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3 || r==4,"failed: r=%d\n", r); + + /* carriage return line feed */ + r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_hi_crlf, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_hi_sp, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==3,"failed: r=%d\n", r); + + /* carriage return */ + r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_cr, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_sp, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==1,"failed: r=%d\n", r); + + /* double carriage return line feed */ + r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_crcrlf, 0, + 0, out, sizeof(out)/sizeof(WCHAR)); + ok(!lstrcmpW(s_2sp, out), "failed out=%s\n", wine_dbgstr_w(out)); + ok(r==2,"failed: r=%d\n", r); +} + static void test_message_from_string(void) { CHAR out[0x100] = {0}; @@ -80,18 +423,48 @@ static void test_message_from_string(void) ok(!strcmp("!s!", out),"failed out=[%s]\n",out); ok(r==3,"failed: r=%d\n",r); + /* ls is unicode */ + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!ls!", 0, + 0, out, sizeof(out)/sizeof(CHAR), szwTest); + ok(!strcmp("test", out),"failed out=[%s]\n",out); + ok(r==4,"failed: r=%d\n",r); + /* S is unicode */ r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!S!", 0, 0, out, sizeof(out)/sizeof(CHAR), szwTest); ok(!strcmp("test", out),"failed out=[%s]\n",out); ok(r==4,"failed: r=%d\n",r); + /* ws is unicode */ + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!ws!", 0, + 0, out, sizeof(out)/sizeof(CHAR), szwTest); + ok(!strcmp("test", out),"failed out=[%s]\n",out); + ok(r==4,"failed: r=%d\n",r); + /* as characters */ r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!c!%2!c!%3!c!%1!c!", 0, 0, out, sizeof(out)/sizeof(CHAR), 't','e','s'); ok(!strcmp("test", out),"failed out=[%s]\n",out); ok(r==4,"failed: r=%d\n",r); + /* lc is unicode */ + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!lc!%2!lc!%3!lc!%1!lc!", 0, + 0, out, sizeof(out)/sizeof(CHAR), 't','e','s'); + ok(!strcmp("test", out),"failed out=[%s]\n",out); + ok(r==4,"failed: r=%d\n",r); + + /* wc is unicode */ + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!wc!%2!wc!%3!wc!%1!wc!", 0, + 0, out, sizeof(out)/sizeof(CHAR), 't','e','s'); + ok(!strcmp("test", out),"failed out=[%s]\n",out); + ok(r==4,"failed: r=%d\n",r); + + /* C is unicode */ + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!C!%2!C!%3!C!%1!C!", 0, + 0, out, sizeof(out)/sizeof(CHAR), 't','e','s'); + ok(!strcmp("test", out),"failed out=[%s]\n",out); + ok(r==4,"failed: r=%d\n",r); + /* some numbers */ r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!d!%2!d!%3!d!", 0, 0, out, sizeof(out)/sizeof(CHAR), 1,2,3); @@ -182,19 +555,66 @@ static void test_message_from_string(void) ok(!strcmp("hi\r\n", out),"failed out=[%s]\n",out); ok(r==4,"failed: r=%d\n",r); - /* carriage return line feed */ + /* carriage return */ r = doit(FORMAT_MESSAGE_FROM_STRING, "\r", 0, 0, out, sizeof(out)/sizeof(CHAR)); ok(!strcmp("\r\n", out),"failed out=[%s]\n",out); ok(r==2,"failed: r=%d\n",r); - /* carriage return line feed */ + /* double carriage return line feed */ r = doit(FORMAT_MESSAGE_FROM_STRING, "\r\r\n", 0, 0, out, sizeof(out)/sizeof(CHAR)); ok(!strcmp("\r\n\r\n", out),"failed out=[%s]\n",out); ok(r==4,"failed: r=%d\n",r); + /* precision and width */ + + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!3s!", + 0, 0, out, sizeof(out), "t" ); + ok(!strcmp(" t", out),"failed out=[%s]\n",out); + ok(r==3, "failed: r=%d\n",r); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*s!", + 0, 0, out, sizeof(out), 4, "t"); + if (!strcmp("*s",out)) win_skip( "width/precision not supported\n" ); + else + { + ok(!strcmp( " t", out),"failed out=[%s]\n",out); + ok(r==4,"failed: r=%d\n",r); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!4.2u!", + 0, 0, out, sizeof(out), 3 ); + ok(!strcmp( " 03", out),"failed out=[%s]\n",out); + ok(r==4,"failed: r=%d\n",r); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*.*u!", + 0, 0, out, sizeof(out), 5, 3, 1 ); + ok(!strcmp( " 001", out),"failed out=[%s]\n",out); + ok(r==5,"failed: r=%d\n",r); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*.*u!,%1!*.*u!", + 0, 0, out, sizeof(out), 5, 3, 1, 4, 2 ); + ok(!strcmp( " 001, 0002", out),"failed out=[%s]\n",out); + ok(r==11,"failed: r=%d\n",r); + r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!*.*u!,%3!*.*u!", + 0, 0, out, sizeof(out), 5, 3, 1, 6, 4, 2 ); + /* older Win versions marked as broken even though this is arguably the correct behavior */ + /* but the new (brain-damaged) behavior is specified on MSDN */ + ok(!strcmp( " 001, 0002", out) || broken(!strcmp(" 001,000004", out)), + "failed out=[%s]\n",out); + ok(r==12,"failed: r=%d\n",r); + /* args are not counted the same way with an argument array */ + { + ULONG_PTR args[] = { 6, 4, 2, 5, 3, 1 }; + r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, + "%1!*.*u!,%1!*.*u!", 0, 0, out, sizeof(out), (__ms_va_list *)args ); + ok(!strcmp(" 0002, 00003", out),"failed out=[%s]\n",out); + ok(r==13,"failed: r=%d\n",r); + r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, + "%1!*.*u!,%4!*.*u!", 0, 0, out, sizeof(out), (__ms_va_list *)args ); + ok(!strcmp(" 0002, 001", out),"failed out=[%s]\n",out); + ok(r==12,"failed: r=%d\n",r); + } + } + /* change of pace... test the low byte of dwflags */ + /* line feed */ r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\n", 0, 0, out, sizeof(out)/sizeof(CHAR)); @@ -207,13 +627,13 @@ static void test_message_from_string(void) ok(!strcmp("hi ", out),"failed out=[%s]\n",out); ok(r==3,"failed: r=%d\n",r); - /* carriage return line feed */ + /* carriage return */ r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r", 0, 0, out, sizeof(out)/sizeof(CHAR)); ok(!strcmp(" ", out),"failed out=[%s]\n",out); ok(r==1,"failed: r=%d\n",r); - /* carriage return line feed */ + /* double carriage return line feed */ r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r\r\n", 0, 0, out, sizeof(out)/sizeof(CHAR)); ok(!strcmp(" ", out),"failed out=[%s]\n",out); @@ -228,14 +648,16 @@ static void test_message_null_buffer(void) ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 0, NULL); error = GetLastError(); ok(!ret, "FormatMessageA returned %u\n", ret); - ok(error == ERROR_NOT_ENOUGH_MEMORY, "last error %u\n", error); + ok(error == ERROR_NOT_ENOUGH_MEMORY || + error == ERROR_INVALID_PARAMETER, /* win9x */ + "last error %u\n", error); SetLastError(0xdeadbeef); ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 0, NULL); error = GetLastError(); if (!ret && error == ERROR_CALL_NOT_IMPLEMENTED) { - skip("FormatMessageW is not implemented\n"); + win_skip("FormatMessageW is not implemented\n"); return; } @@ -243,8 +665,68 @@ static void test_message_null_buffer(void) ok(error == ERROR_INVALID_PARAMETER, "last error %u\n", error); } +static void test_message_from_hmodule(void) +{ + DWORD ret, error; + HMODULE h; + CHAR out[0x100] = {0}; + + h = GetModuleHandle("kernel32.dll"); + ok(h != 0, "GetModuleHandle failed\n"); + + /*Test existing messageID; as the message strings from wine's kernel32 differ from windows' kernel32 we don't compare + the strings but only test that FormatMessage doesn't return 0*/ + ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 7/*=ERROR_ARENA_TRASHED*/, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, sizeof(out)/sizeof(CHAR), NULL); + ok(ret != 0, "FormatMessageA returned 0\n"); + + /*Test nonexistent messageID with varying language ID's Note: FormatMessageW behaves the same*/ + SetLastError(0xdeadbeef); + ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), out, sizeof(out)/sizeof(CHAR), NULL); + error = GetLastError(); + ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); + ok(error == ERROR_MR_MID_NOT_FOUND || error == ERROR_MUI_FILE_NOT_FOUND, "last error %u\n", error); + + SetLastError(0xdeadbeef); + ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), out, sizeof(out)/sizeof(CHAR), NULL); + error = GetLastError(); + ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); + ok(error == ERROR_MR_MID_NOT_FOUND || error == ERROR_MUI_FILE_NOT_LOADED, "last error %u\n", error); + + SetLastError(0xdeadbeef); + ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, + MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), out, sizeof(out)/sizeof(CHAR), NULL); + error = GetLastError(); + ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); + ok(error == ERROR_MR_MID_NOT_FOUND || error == ERROR_MUI_FILE_NOT_LOADED, "last error %u\n", error); + + SetLastError(0xdeadbeef); + ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), out, sizeof(out)/sizeof(CHAR), NULL); + error = GetLastError(); + ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); + ok(error == ERROR_RESOURCE_LANG_NOT_FOUND || + error == ERROR_MR_MID_NOT_FOUND || + error == ERROR_MUI_FILE_NOT_LOADED, + "last error %u\n", error); + + SetLastError(0xdeadbeef); + ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, h, 3044, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), out, sizeof(out)/sizeof(CHAR), NULL); + error = GetLastError(); + ok(ret == 0, "FormatMessageA returned %u instead of 0\n", ret); + ok(error == ERROR_RESOURCE_LANG_NOT_FOUND || + error == ERROR_MR_MID_NOT_FOUND || + error == ERROR_MUI_FILE_NOT_FOUND, + "last error %u\n", error); +} + START_TEST(format_msg) { test_message_from_string(); + test_message_from_string_wide(); test_message_null_buffer(); + test_message_from_hmodule(); } diff --git a/rostests/winetests/kernel32/heap.c b/rostests/winetests/kernel32/heap.c index 29398622709..bddde9c590f 100755 --- a/rostests/winetests/kernel32/heap.c +++ b/rostests/winetests/kernel32/heap.c @@ -28,13 +28,38 @@ #define MAGIC_DEAD 0xdeadbeef +static BOOL (WINAPI *pHeapQueryInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); + static SIZE_T resize_9x(SIZE_T size) { DWORD dwSizeAligned = (size + 3) & ~3; return max(dwSizeAligned, 12); /* at least 12 bytes */ } -START_TEST(heap) +static void test_sized_HeapAlloc(int nbytes) +{ + int success; + char *buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nbytes); + ok(buf != NULL, "allocate failed\n"); + ok(buf[0] == 0, "buffer not zeroed\n"); + success = HeapFree(GetProcessHeap(), 0, buf); + ok(success, "free failed\n"); +} + +static void test_sized_HeapReAlloc(int nbytes1, int nbytes2) +{ + int success; + char *buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nbytes1); + ok(buf != NULL, "allocate failed\n"); + ok(buf[0] == 0, "buffer not zeroed\n"); + buf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf, nbytes2); + ok(buf != NULL, "reallocate failed\n"); + ok(buf[nbytes2-1] == 0, "buffer not zeroed\n"); + success = HeapFree(GetProcessHeap(), 0, buf); + ok(success, "free failed\n"); +} + +static void test_heap(void) { LPVOID mem; LPVOID msecond; @@ -47,6 +72,7 @@ START_TEST(heap) /* Heap*() functions */ mem = HeapAlloc(GetProcessHeap(), 0, 0); ok(mem != NULL, "memory not allocated for size 0\n"); + HeapFree(GetProcessHeap(), 0, mem); mem = HeapReAlloc(GetProcessHeap(), 0, NULL, 10); ok(mem == NULL, "memory allocated by HeapReAlloc\n"); @@ -64,13 +90,20 @@ START_TEST(heap) /* test some border cases of HeapAlloc and HeapReAlloc */ mem = HeapAlloc(GetProcessHeap(), 0, 0); ok(mem != NULL, "memory not allocated for size 0\n"); - msecond = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~0UL - 7); - ok(msecond == NULL, "HeapReAlloc(0xfffffff8) should have failed\n"); - msecond = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~0UL); - ok(msecond == NULL, "HeapReAlloc(0xffffffff) should have failed\n"); + msecond = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~(SIZE_T)0 - 7); + ok(msecond == NULL, "HeapReAlloc(~0 - 7) should have failed\n"); + msecond = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, ~(SIZE_T)0); + ok(msecond == NULL, "HeapReAlloc(~0) should have failed\n"); + HeapFree(GetProcessHeap(), 0, mem); + mem = HeapAlloc(GetProcessHeap(), 0, ~(SIZE_T)0); + ok(mem == NULL, "memory allocated for size ~0\n"); + + /* large blocks must be 16-byte aligned */ + mem = HeapAlloc(GetProcessHeap(), 0, 512 * 1024); + ok( mem != NULL, "failed for size 512K\n" ); + ok( (ULONG_PTR)mem % 16 == 0 || broken((ULONG_PTR)mem % 16) /* win9x */, + "512K block not 16-byte aligned\n" ); HeapFree(GetProcessHeap(), 0, mem); - mem = HeapAlloc(GetProcessHeap(), 0, ~0UL); - ok(mem == NULL, "memory allocated for size ~0UL\n"); /* Global*() functions */ gbl = GlobalAlloc(GMEM_MOVEABLE, 0); @@ -183,26 +216,41 @@ START_TEST(heap) ok(mem == NULL, "Expected NULL, got %p\n", mem); /* invalid free */ + if (sizeof(void *) != 8) /* crashes on 64-bit Vista */ + { SetLastError(MAGIC_DEAD); mem = GlobalFree(gbl); - ok(mem == gbl, "Expected gbl, got %p\n", mem); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(mem == gbl || broken(mem == NULL) /* nt4 */, "Expected gbl, got %p\n", mem); + if (mem == gbl) + ok(GetLastError() == ERROR_INVALID_HANDLE || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "Expected ERROR_INVALID_HANDLE or ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } gbl = GlobalAlloc(GMEM_DDESHARE, 100); res = GlobalUnlock(gbl); - ok(res == 1, "Expected 1, got %d\n", res); + ok(res == 1 || + res == 0, /* win9x */ + "Expected 1 or 0, got %d\n", res); res = GlobalUnlock(gbl); - ok(res == 1, "Expected 1, got %d\n", res); + ok(res == 1 || + res == 0, /* win9x */ + "Expected 1 or 0, got %d\n", res); /* GlobalSize on an invalid handle */ + if (sizeof(void *) != 8) /* crashes on 64-bit Vista */ + { SetLastError(MAGIC_DEAD); size = GlobalSize((HGLOBAL)0xc042); ok(size == 0, "Expected 0, got %ld\n", size); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "Expected ERROR_INVALID_HANDLE or ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + GlobalFree(gbl); /* ####################################### */ /* Local*() functions */ @@ -318,3 +366,118 @@ START_TEST(heap) GlobalFree(gbl); } + +static void test_obsolete_flags(void) +{ + static struct { + UINT flags; + UINT globalflags; + } test_global_flags[] = { + {GMEM_FIXED | GMEM_NOTIFY, 0}, + {GMEM_FIXED | GMEM_DISCARDABLE, 0}, + {GMEM_MOVEABLE | GMEM_NOTIFY, 0}, + {GMEM_MOVEABLE | GMEM_DDESHARE, GMEM_DDESHARE}, + {GMEM_MOVEABLE | GMEM_NOT_BANKED, 0}, + {GMEM_MOVEABLE | GMEM_NODISCARD, 0}, + {GMEM_MOVEABLE | GMEM_DISCARDABLE, GMEM_DISCARDABLE}, + {GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_DISCARDABLE | GMEM_LOWER | GMEM_NOCOMPACT | GMEM_NODISCARD | + GMEM_NOT_BANKED | GMEM_NOTIFY, GMEM_DDESHARE | GMEM_DISCARDABLE}, + }; + + unsigned int i; + HGLOBAL gbl; + UINT resultflags; + + UINT (WINAPI *pGlobalFlags)(HGLOBAL); + + pGlobalFlags = (void *) GetProcAddress(GetModuleHandleA("kernel32"), "GlobalFlags"); + + if (!pGlobalFlags) + { + win_skip("GlobalFlags is not available\n"); + return; + } + + for (i = 0; i < sizeof(test_global_flags)/sizeof(test_global_flags[0]); i++) + { + gbl = GlobalAlloc(test_global_flags[i].flags, 4); + ok(gbl != NULL, "GlobalAlloc failed\n"); + + SetLastError(MAGIC_DEAD); + resultflags = pGlobalFlags(gbl); + + ok( resultflags == test_global_flags[i].globalflags || + broken(resultflags == (test_global_flags[i].globalflags & ~GMEM_DDESHARE)), /* win9x */ + "%u: expected 0x%08x, but returned 0x%08x with %d\n", + i, test_global_flags[i].globalflags, resultflags, GetLastError() ); + + GlobalFree(gbl); + } +} + +static void test_HeapQueryInformation(void) +{ + ULONG info; + SIZE_T size; + BOOL ret; + + pHeapQueryInformation = (void *)GetProcAddress(GetModuleHandle("kernel32.dll"), "HeapQueryInformation"); + if (!pHeapQueryInformation) + { + win_skip("HeapQueryInformation is not available\n"); + return; + } + + if (0) /* crashes under XP */ + { + size = 0; + ret = pHeapQueryInformation(0, + HeapCompatibilityInformation, + &info, sizeof(info), &size); + size = 0; + ret = pHeapQueryInformation(GetProcessHeap(), + HeapCompatibilityInformation, + NULL, sizeof(info), &size); + } + + size = 0; + SetLastError(0xdeadbeef); + ret = pHeapQueryInformation(GetProcessHeap(), + HeapCompatibilityInformation, + NULL, 0, &size); + ok(!ret, "HeapQueryInformation should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError()); + ok(size == sizeof(ULONG), "expected 4, got %lu\n", size); + + SetLastError(0xdeadbeef); + ret = pHeapQueryInformation(GetProcessHeap(), + HeapCompatibilityInformation, + NULL, 0, NULL); + ok(!ret, "HeapQueryInformation should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError()); + + info = 0xdeadbeaf; + SetLastError(0xdeadbeef); + ret = pHeapQueryInformation(GetProcessHeap(), + HeapCompatibilityInformation, + &info, sizeof(info) + 1, NULL); + ok(ret, "HeapQueryInformation error %u\n", GetLastError()); + ok(info == 0 || info == 1 || info == 2, "expected 0, 1 or 2, got %u\n", info); +} + +START_TEST(heap) +{ + test_heap(); + test_obsolete_flags(); + + /* Test both short and very long blocks */ + test_sized_HeapAlloc(1); + test_sized_HeapAlloc(1 << 20); + test_sized_HeapReAlloc(1, 100); + test_sized_HeapReAlloc(1, (1 << 20)); + test_sized_HeapReAlloc((1 << 20), (2 << 20)); + test_sized_HeapReAlloc((1 << 20), 1); + test_HeapQueryInformation(); +} diff --git a/rostests/winetests/kernel32/interlck.c b/rostests/winetests/kernel32/interlck.c index e67fb5fc20a..2bb9d25e769 100644 --- a/rostests/winetests/kernel32/interlck.c +++ b/rostests/winetests/kernel32/interlck.c @@ -20,6 +20,7 @@ #include +#undef __ROS_LONG64__ #include "wine/test.h" #include "windef.h" #include "winbase.h" diff --git a/rostests/winetests/kernel32/kernel32.rbuild b/rostests/winetests/kernel32/kernel32.rbuild index 2b69786383a..d1ecfb413f6 100644 --- a/rostests/winetests/kernel32/kernel32.rbuild +++ b/rostests/winetests/kernel32/kernel32.rbuild @@ -1,13 +1,10 @@ - . - - 0x0600 - 0x609 + ntdll - kernel32 + user32 advapi32 actctx.c alloc.c @@ -44,4 +41,3 @@ volume.c testlist.c - diff --git a/rostests/winetests/kernel32/loader.c b/rostests/winetests/kernel32/loader.c index 363c2fdf254..9361ed58c12 100644 --- a/rostests/winetests/kernel32/loader.c +++ b/rostests/winetests/kernel32/loader.c @@ -27,6 +27,13 @@ #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1))) +static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module) +{ + if (rva == 0) + return NULL; + return ((char*) module) + rva; +} + static const struct { WORD e_magic; /* 00: MZ Header signature */ @@ -45,6 +52,8 @@ static IMAGE_NT_HEADERS nt_header = IMAGE_FILE_MACHINE_I386, /* Machine */ #elif defined __x86_64__ IMAGE_FILE_MACHINE_AMD64, /* Machine */ +#elif defined __powerpc__ + IMAGE_FILE_MACHINE_POWERPC, /* Machine */ #else # error You must specify the machine type #endif @@ -63,7 +72,9 @@ static IMAGE_NT_HEADERS nt_header = 0, /* SizeOfUninitializedData */ 0, /* AddressOfEntryPoint */ 0x10, /* BaseOfCode, also serves as e_lfanew in the truncated MZ header */ +#ifndef _WIN64 0, /* BaseOfData */ +#endif 0x10000000, /* ImageBase */ 0, /* SectionAlignment */ 0, /* FileAlignment */ @@ -103,7 +114,7 @@ static IMAGE_SECTION_HEADER section = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */ }; -START_TEST(loader) +static void test_Loader(void) { static const struct test_data { @@ -113,6 +124,7 @@ START_TEST(loader) DWORD section_alignment, file_alignment; DWORD size_of_image, size_of_headers; DWORD error; /* 0 means LoadLibrary should succeed */ + DWORD alt_error; /* alternate error */ } td[] = { { &dos_header, sizeof(dos_header), @@ -141,7 +153,7 @@ START_TEST(loader) 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200, sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x200, sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER), - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_INVALID_ADDRESS /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000, @@ -168,25 +180,25 @@ START_TEST(loader) 1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10, sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER), - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, 0xd0, /* beyond of the end of file */ 0xc0, /* beyond of the end of file */ - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, 0x1000, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, 1, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, #if 0 /* not power of 2 alignments need more test cases */ { &dos_header, sizeof(dos_header), @@ -200,13 +212,13 @@ START_TEST(loader) 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4, 1, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1, 1, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, @@ -227,7 +239,7 @@ START_TEST(loader) 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04, 1, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ } }; static const char filler[0x1000]; @@ -323,18 +335,11 @@ START_TEST(loader) SetLastError(0xdeadbeef); hlib = LoadLibrary(dll_name); - if (td[i].error == ERROR_SUCCESS) + if (hlib) { MEMORY_BASIC_INFORMATION info; - ok(hlib != 0, "%d: LoadLibrary error %d\n", i, GetLastError()); - - /* No point in crashing. Test crashes on Vista with some of the given files */ - if (hlib == 0) - { - skip("Failed to load dll number %d\n", i); - goto endloop; - } + ok( td[i].error == ERROR_SUCCESS, "%d: should have failed\n", i ); SetLastError(0xdeadbeef); ok(VirtualQuery(hlib, &info, sizeof(info)) == sizeof(info), @@ -397,7 +402,7 @@ START_TEST(loader) "%d: VirtualQuery error %d\n", i, GetLastError()); if (nt_header.OptionalHeader.SectionAlignment < si.dwPageSize) { - ok(info.BaseAddress == (char *)hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, (char *)hlib); + ok(info.BaseAddress == hlib, "%d: got %p != expected %p\n", i, info.BaseAddress, hlib); ok(info.RegionSize == ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize), "%d: got %lx != expected %x\n", i, info.RegionSize, ALIGN_SIZE(nt_header.OptionalHeader.SizeOfImage, si.dwPageSize)); ok(info.Protect == PAGE_EXECUTE_WRITECOPY, "%d: %x != PAGE_EXECUTE_WRITECOPY\n", i, info.Protect); @@ -461,8 +466,8 @@ START_TEST(loader) ok(FreeLibrary(hlib_as_data_file), "FreeLibrary error %d\n", GetLastError()); } else - { /* LoadLibrary is expected to fail */ - ok(!hlib, "%d: LoadLibrary should fail\n", i); + { + ok(td[i].error || td[i].alt_error, "%d: LoadLibrary should succeed\n", i); if (GetLastError() == ERROR_GEN_FAILURE) /* Win9x, broken behaviour */ { @@ -471,12 +476,73 @@ START_TEST(loader) return; } - ok(td[i].error == GetLastError(), "%d: expected error %d, got %d\n", - i, td[i].error, GetLastError()); + ok(td[i].error == GetLastError() || td[i].alt_error == GetLastError(), + "%d: expected error %d or %d, got %d\n", + i, td[i].error, td[i].alt_error, GetLastError()); } -endloop: SetLastError(0xdeadbeef); ok(DeleteFile(dll_name), "DeleteFile error %d\n", GetLastError()); } } + +/* Verify linking style of import descriptors */ +static void test_ImportDescriptors(void) +{ + HMODULE kernel32_module = NULL; + PIMAGE_DOS_HEADER d_header; + PIMAGE_NT_HEADERS nt_headers; + DWORD import_dir_size; + DWORD_PTR dir_offset; + PIMAGE_IMPORT_DESCRIPTOR import_chunk; + + /* Load kernel32 module */ + kernel32_module = GetModuleHandleA("kernel32.dll"); + assert( kernel32_module != NULL ); + + /* Get PE header info from module image */ + d_header = (PIMAGE_DOS_HEADER) kernel32_module; + nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) + + d_header->e_lfanew); + + /* Get size of import entry directory */ + import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; + if (!import_dir_size) + { + skip("Unable to continue testing due to missing import directory.\n"); + return; + } + + /* Get address of first import chunk */ + dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + import_chunk = RVAToAddr(dir_offset, kernel32_module); + ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk); + if (!import_chunk) return; + + /* Iterate through import descriptors and verify set name, + * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as + * kernel32.dll, don't use Borland-style linking, where the table of + * imported names is stored directly in FirstThunk and overwritten + * by the relocation, instead of being stored in OriginalFirstThunk. + * */ + for (; import_chunk->FirstThunk; import_chunk++) + { + LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module); + PIMAGE_THUNK_DATA name_table = RVAToAddr( + U(*import_chunk).OriginalFirstThunk, kernel32_module); + PIMAGE_THUNK_DATA iat = RVAToAddr( + import_chunk->FirstThunk, kernel32_module); + ok(module_name != NULL, "Imported module name should not be NULL\n"); + ok(name_table != NULL, + "Name table for imported module %s should not be NULL\n", + module_name); + ok(iat != NULL, "IAT for imported module %s should not be NULL\n", + module_name); + } +} + +START_TEST(loader) +{ + test_Loader(); + test_ImportDescriptors(); +} diff --git a/rostests/winetests/kernel32/locale.c b/rostests/winetests/kernel32/locale.c index 60e6f114a8c..a5b7173aa85 100755 --- a/rostests/winetests/kernel32/locale.c +++ b/rostests/winetests/kernel32/locale.c @@ -102,61 +102,170 @@ static void InitFunctionPointers(void) #define BUFFER_SIZE 128 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0]) -#define EXPECT_LEN(len) ok(ret == (len), "Expected Len %d, got %d\n", (int)(len), ret) -#define EXPECT_INVALID ok(GetLastError() == ERROR_INVALID_PARAMETER, \ - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()) -#define EXPECT_BUFFER ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \ - "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()) -#define EXPECT_FLAGS ok(GetLastError() == ERROR_INVALID_FLAGS, \ - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()) -#define EXPECT_INVALIDFLAGS ok(GetLastError() == ERROR_INVALID_FLAGS || \ - GetLastError() == ERROR_INVALID_PARAMETER, \ - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()) -#define EXPECT_LASTERROR_0 ok(GetLastError() == 0, \ - "Expected GetLastError() == 0, got %d\n", GetLastError()) -#define EXPECT_VALID ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()) - -#define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0); buffer[0] = '\0' -#define EXPECT_LENA EXPECT_LEN((int)strlen(Expected)+1) +#define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0' +#define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret) #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \ "Expected '%s', got '%s'\n", Expected, buffer) #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \ MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \ - SetLastError(0); buffer[0] = '\0' -#define EXPECT_LENW EXPECT_LEN((int)strlenW(Expected)+1) + SetLastError(0xdeadbeef); buffer[0] = '\0' +#define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret) #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n") -#define EXPECT_FALSE ok(FALSE == ret, "Expected return value FALSE, got TRUE\n") -#define EXPECT_TRUE ok(FALSE != ret, "Expected return value TRUE, got FALSE\n") #define NUO LOCALE_NOUSEROVERRIDE static void test_GetLocaleInfoA(void) { int ret; + int len; LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); char buffer[BUFFER_SIZE]; + char expected[BUFFER_SIZE]; ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid); + /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT + Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo + assumes SUBLANG_NEUTRAL for zh */ + memset(expected, 0, COUNTOF(expected)); + len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected)); + SetLastError(0xdeadbeef); + memset(buffer, 0, COUNTOF(buffer)); + ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer)); + ok((ret == len) && !lstrcmpA(buffer, expected), + "got %d with '%s' (expected %d with '%s')\n", + ret, buffer, len, expected); + + memset(expected, 0, COUNTOF(expected)); + len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected)); + if (len) { + SetLastError(0xdeadbeef); + memset(buffer, 0, COUNTOF(buffer)); + ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer)); + ok((ret == len) && !lstrcmpA(buffer, expected), + "got %d with '%s' (expected %d with '%s')\n", + ret, buffer, len, expected); + } + else + win_skip("LANG_ARABIC not installed\n"); + + /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */ + memset(expected, 0, COUNTOF(expected)); + len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected)); + SetLastError(0xdeadbeef); + memset(buffer, 0, COUNTOF(buffer)); + ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer)); + ok((ret == len) && !lstrcmpA(buffer, expected), + "got %d with '%s' (expected %d with '%s')\n", + ret, buffer, len, expected); + + /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to * partially fill the buffer even if it is too short. See bug 637. */ - SetLastError(0); memset(buffer, 0, COUNTOF(buffer)); + SetLastError(0xdeadbeef); + memset(buffer, 0, COUNTOF(buffer)); ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0); ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret); - SetLastError(0); memset(buffer, 0, COUNTOF(buffer)); + SetLastError(0xdeadbeef); + memset(buffer, 0, COUNTOF(buffer)); ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3); - EXPECT_BUFFER; EXPECT_LEN(0); + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer); - SetLastError(0); memset(buffer, 0, COUNTOF(buffer)); + SetLastError(0xdeadbeef); + memset(buffer, 0, COUNTOF(buffer)); ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10); - EXPECT_VALID; EXPECT_LEN(7); + ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError()); ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer); } +static void test_GetLocaleInfoW(void) +{ + LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT); + WCHAR bufferW[80], buffer2W[80]; + CHAR bufferA[80]; + DWORD ret; + INT i; + + ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW)); + if (!ret) { + win_skip("GetLocaleInfoW() isn't implemented\n"); + return; + } + ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW)); + if (!ret) { + win_skip("LANG_RUSSIAN locale data unavailable\n"); + return; + } + ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES, + bufferW, COUNTOF(bufferW)); + if (!ret) { + win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n"); + return; + } + + /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */ + bufferA[0] = 'a'; + SetLastError(0xdeadbeef); + ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES, + bufferA, COUNTOF(bufferA)); + ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n"); + ok(bufferA[0] == 'a', "Expected buffer to be untouched\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError()); + + bufferW[0] = 'a'; + SetLastError(0xdeadbeef); + ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES, + bufferW, COUNTOF(bufferW)); + ok(ret == 0, + "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret); + ok(bufferW[0] == 'a', "Expected buffer to be untouched\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError()); + + /* yes, test empty 13 month entry too */ + for (i = 0; i < 12; i++) { + bufferW[0] = 0; + ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES, + bufferW, COUNTOF(bufferW)); + ok(ret, "Expected non zero result\n"); + ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n", + ret, lstrlenW(bufferW)); + buffer2W[0] = 0; + ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i, + buffer2W, COUNTOF(buffer2W)); + ok(ret, "Expected non zero result\n"); + ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n", + ret, lstrlenW(buffer2W)); + + ok(lstrcmpW(bufferW, buffer2W) != 0, + "Expected genitive name to differ, got the same for month %d\n", i+1); + + /* for locale without genitive names nominative returned in both cases */ + bufferW[0] = 0; + ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES, + bufferW, COUNTOF(bufferW)); + ok(ret, "Expected non zero result\n"); + ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n", + ret, lstrlenW(bufferW)); + buffer2W[0] = 0; + ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i, + buffer2W, COUNTOF(buffer2W)); + ok(ret, "Expected non zero result\n"); + ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n", + ret, lstrlenW(buffer2W)); + + ok(lstrcmpW(bufferW, buffer2W) == 0, + "Expected same names, got different for month %d\n", i+1); + } +} + static void test_GetTimeFormatA(void) { int ret; @@ -168,7 +277,8 @@ static void test_GetTimeFormatA(void) STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); curtime.wHour = 8; curtime.wMinute = 56; @@ -177,83 +287,104 @@ static void test_GetTimeFormatA(void) STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2); - EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0); - EXPECT_VALID; EXPECT_LENA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */ ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */ ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */ + "Expected '', got '%s'\n", buffer ); STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */ ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */ strcpy(Expected, "8:56 AM"); ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */ ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */, + "Expected '8.@:56AM', got '%s'\n", buffer ); STRINGSA("s1s2s3", ""); /* Duplicate tokens */ ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */ + "Expected '', got '%s'\n", buffer ); STRINGSA("t/tt", "A/AM"); /* AM time marker */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 13; STRINGSA("t/tt", "P/PM"); /* PM time marker */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */ ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 14; /* change this to 14 or 2pm */ curtime.wMinute = 5; curtime.wSecond = 3; STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 0; STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* try to convert formatting strings with more than two letters * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS" @@ -268,55 +399,66 @@ static void test_GetTimeFormatA(void) STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS", "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS"); ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */ strcpy(buffer, "text"); ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0); - EXPECT_VALID; EXPECT_LEN(2); EXPECT_EQA; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + EXPECT_EQA; STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'", "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("'''", "'"); /* invalid quoted string */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* test that msdn suggested single quotation usage works as expected */ STRINGSA("''''", "'"); /* single quote mark */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("''HHHHHH", "08"); /* Normal use */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* and test for normal use of the single quotation mark */ STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */ ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 25; STRINGSA("'123'tt", ""); /* Invalid time */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); curtime.wHour = 12; curtime.wMonth = 60; /* Invalid */ STRINGSA("h:m:s", "12:56:13"); /* Invalid date */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; } static void test_GetDateFormatA(void) @@ -330,7 +472,8 @@ static void test_GetDateFormatA(void) STRINGSA("ddd',' MMM dd yy",""); SetLastError(0xdeadbeef); ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); curtime.wYear = 2002; curtime.wMonth = 5; @@ -338,48 +481,58 @@ static void test_GetDateFormatA(void) curtime.wDayOfWeek = 3; STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* Same as above but with LOCALE_NOUSEROVERRIDE */ STRINGSA("ddd',' MMM dd yy",""); /* Simple case */ SetLastError(0xdeadbeef); ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + EXPECT_EQA; STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 36; /* Invalid */ STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */ ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0); - EXPECT_VALID; EXPECT_LEN(16); EXPECT_EQA; + ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError()); + EXPECT_EQA; STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */ SetLastError(0xdeadbeef); ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2); - EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */ ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0) ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer); STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */ ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* test for expected DATE_YEARMONTH behavior with null format */ /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */ STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */ SetLastError(0xdeadbeef); ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + EXPECT_EQA; /* Test that using invalid DATE_* flags results in the correct error */ /* and return values */ @@ -387,7 +540,9 @@ static void test_GetDateFormatA(void) SetLastError(0xdeadbeef); ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + EXPECT_EQA; } static void test_GetDateFormatW(void) @@ -401,17 +556,24 @@ static void test_GetDateFormatW(void) ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL, input, buffer, COUNTOF(buffer)); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetDateFormatW is not implemented\n"); return; - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQW; + } + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + EXPECT_EQW; STRINGSW("",""); /* NULL buffer, len > 0 */ SetLastError(0xdeadbeef); ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQW; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSW("",""); /* NULL buffer, len == 0 */ ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0); - EXPECT_VALID; EXPECT_LENW; EXPECT_EQW; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENW; EXPECT_EQW; curtime.wYear = 2002; curtime.wMonth = 10; @@ -423,7 +585,8 @@ static void test_GetDateFormatW(void) curtime.wMilliseconds = 12345; STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */ ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENW; EXPECT_EQW; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENW; EXPECT_EQW; /* Limit tests */ @@ -438,7 +601,8 @@ static void test_GetDateFormatW(void) STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601"); SetLastError(0xdeadbeef); ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENW; EXPECT_EQW; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENW; EXPECT_EQW; curtime.wYear = 1600; curtime.wMonth = 12; @@ -451,7 +615,8 @@ static void test_GetDateFormatW(void) STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600"); SetLastError(0xdeadbeef); ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); } @@ -475,67 +640,82 @@ static void test_GetCurrencyFormatA(void) STRINGSA("23",""); /* NULL output, length > 0 --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("23,53",""); /* Invalid character --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("--",""); /* Double '-' --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("0-",""); /* Trailing '-' --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("0..",""); /* Double '.' --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA(" 0.1",""); /* Leading space --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("1234","$"); /* Length too small --> Write up to length chars */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2); - EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); STRINGSA("2353",""); /* Format and flags given --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer)); - EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret, "Expected ret == 0, got %d\n", ret); + ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); STRINGSA("2353",""); /* Invalid format --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("2353","$2,353.00"); /* Valid number */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("-2353","($2,353.00)"); /* Valid negative number */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.1","$2,353.10"); /* Valid real number */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NumDigits = 0; /* No decimal separator */ format.LeadingZero = 0; @@ -548,117 +728,152 @@ static void test_GetCurrencyFormatA(void) STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NumDigits = 1; /* 1 DP --> Expect decimal separator */ STRINGSA("2353","$2353.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.Grouping = 2; /* Group by 100's */ STRINGSA("2353","$23,53.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; + + STRINGSA("235","$235.0"); /* Grouping of a positive number */ + format.Grouping = 3; + ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; + + STRINGSA("-235","$-235.0"); /* Grouping of a negative number */ + format.NegativeOrder = 2; + ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.LeadingZero = 1; /* Always provide leading zero */ STRINGSA(".5","$0.5"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.PositiveOrder = CY_POS_RIGHT; STRINGSA("1","1.0$"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.PositiveOrder = CY_POS_LEFT_SPACE; STRINGSA("1","$ 1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.PositiveOrder = CY_POS_RIGHT_SPACE; STRINGSA("1","1.0 $"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 0; STRINGSA("-1","($1.0)"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 1; STRINGSA("-1","-$1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 2; STRINGSA("-1","$-1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 3; STRINGSA("-1","$1.0-"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 4; STRINGSA("-1","(1.0$)"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 5; STRINGSA("-1","-1.0$"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 6; STRINGSA("-1","1.0-$"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 7; STRINGSA("-1","1.0$-"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 8; STRINGSA("-1","-1.0 $"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 9; STRINGSA("-1","-$ 1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 10; STRINGSA("-1","1.0 $-"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 11; STRINGSA("-1","$ 1.0-"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 12; STRINGSA("-1","$ -1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 13; STRINGSA("-1","1.0- $"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 14; STRINGSA("-1","($ 1.0)"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 15; STRINGSA("-1","(1.0 $)"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; } #define NEG_PARENS 0 /* "(1.1)" */ @@ -681,71 +896,87 @@ static void test_GetNumberFormatA(void) STRINGSA("23",""); /* NULL output, length > 0 --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("23,53",""); /* Invalid character --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("--",""); /* Double '-' --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("0-",""); /* Trailing '-' --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("0..",""); /* Double '.' --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA(" 0.1",""); /* Leading space --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("1234","1"); /* Length too small --> Write up to length chars */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2); - EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); STRINGSA("2353",""); /* Format and flags given --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer)); - EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret, "Expected ret == 0, got %d\n", ret); + ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); STRINGSA("2353",""); /* Invalid format --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("2353","2,353.00"); /* Valid number */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("-2353","-2,353.00"); /* Valid negative number */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("-353","-353.00"); /* test for off by one error in grouping */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.1","2,353.10"); /* Valid real number */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NumDigits = 0; /* No decimal separator */ format.LeadingZero = 0; @@ -756,47 +987,68 @@ static void test_GetNumberFormatA(void) STRINGSA("2353","2353"); /* No decimal or grouping chars expected */ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NumDigits = 1; /* 1 DP --> Expect decimal separator */ STRINGSA("2353","2353.0"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.Grouping = 2; /* Group by 100's */ STRINGSA("2353","23,53.0"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; + + STRINGSA("235","235.0"); /* Grouping of a positive number */ + format.Grouping = 3; + ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; + + STRINGSA("-235","-235.0"); /* Grouping of a negative number */ + format.NegativeOrder = NEG_LEFT; + ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.LeadingZero = 1; /* Always provide leading zero */ STRINGSA(".5","0.5"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_PARENS; STRINGSA("-1","(1.0)"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_LEFT; STRINGSA("-1","-1.0"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_LEFT_SPACE; STRINGSA("-1","- 1.0"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_RIGHT; STRINGSA("-1","1.0-"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_RIGHT_SPACE; STRINGSA("-1","1.0 -"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT); @@ -805,7 +1057,8 @@ static void test_GetNumberFormatA(void) STRINGSA("-12345","-12 345,00"); /* Try French formatting */ Expected[3] = 160; /* Non breaking space */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; } } @@ -840,7 +1093,7 @@ static void test_CompareStringA(void) /* test for CompareStringA flags */ SetLastError(0xdeadbeef); - ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x10, "NULL", -1, "NULL", -1); + ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1); ok(GetLastError() == ERROR_INVALID_FLAGS, "unexpected error code %d\n", GetLastError()); ok(!ret, "CompareStringA must fail with invalid flag\n"); @@ -855,13 +1108,13 @@ static void test_CompareStringA(void) ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret); ret = lstrcmpA(NULL, NULL); - ok (ret == 0, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret); + ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret); ret = lstrcmpA("", NULL); - ok (ret == 1, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret); + ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret); ret = lstrcmpA(NULL, ""); - ok (ret == -1, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret); + ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret); ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1); ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret); @@ -1008,6 +1261,12 @@ static void test_CompareStringA(void) ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2); todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n"); + + ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1); + todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret); + + ret = lstrcmpi("#", "."); + todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret); } static void test_LCMapStringA(void) @@ -1119,9 +1378,11 @@ static void test_LCMapStringA(void) ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, upper_case, -1, buf, sizeof(buf)); ok(ret, "LCMapStringA must succeed\n"); + ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n"); ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, upper_case, lstrlenA(upper_case), buf2, sizeof(buf2)); - ok(ret, "LCMapStringA must succeed\n"); + ok(ret2, "LCMapStringA must succeed\n"); + ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" ); ok(ret == ret2, "lengths of sort keys must be equal\n"); ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n"); @@ -1135,15 +1396,8 @@ static void test_LCMapStringA(void) ok(ret == ret2, "lengths of sort keys must be equal\n"); ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n"); - /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */ - ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE, - lower_case, -1, buf, sizeof(buf)); - ok(ret, "LCMapStringA must succeed\n"); - ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, - lower_case, -1, buf2, sizeof(buf2)); - ok(ret2, "LCMapStringA must succeed\n"); - ok(ret == ret2, "lengths of sort keys must be equal\n"); - ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n"); + /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different + results from plain LCMAP_SORTKEY on Vista */ /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */ ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS, @@ -1193,12 +1447,17 @@ static void test_LCMapStringW(void) upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("Skipping LCMapStringW tests on Win9x\n"); + win_skip("LCMapStringW is not implemented\n"); return; } + if (broken(ret)) + ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n"); + else + { ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n"); ok(GetLastError() == ERROR_INVALID_FLAGS, "unexpected error code %d\n", GetLastError()); + } ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); @@ -1294,15 +1553,8 @@ static void test_LCMapStringW(void) ok(ret == ret2, "lengths of sort keys must be equal\n"); ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n"); - /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */ - ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE, - lower_case, -1, buf, sizeof(buf)); - ok(ret, "LCMapStringW must succeed\n"); - ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, - lower_case, -1, buf2, sizeof(buf2)); - ok(ret2, "LCMapStringW must succeed\n"); - ok(ret == ret2, "lengths of sort keys must be equal\n"); - ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n"); + /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different + results from plain LCMAP_SORTKEY on Vista */ /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */ ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS, @@ -1332,14 +1584,14 @@ static void test_LCMapStringW(void) /* test srclen = 0 */ SetLastError(0xdeadbeef); - ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)); + ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR)); ok(!ret, "LCMapStringW should fail with srclen = 0\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError()); } /* this requires collation table patch to make it MS compatible */ -const char *strings_sorted[] = +static const char * const strings_sorted[] = { "'", "-", @@ -1371,7 +1623,7 @@ const char *strings_sorted[] = "C" }; -const char *strings[] = +static const char * const strings[] = { "C", "\"", @@ -1466,7 +1718,8 @@ static void test_sorting(void) static void test_FoldStringA(void) { - int ret, i; + int ret, i, j; + BOOL is_special; char src[256], dst[256]; static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' }; static const char digits_dst[] = { '1','2','3','\0' }; @@ -1499,6 +1752,24 @@ static void test_FoldStringA(void) 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4, 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0' }; + static const char composite_dst_alt[] = + { + 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f, + 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e, + 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8, + 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8, + 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8, + 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e, + 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55, + 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61, + 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61, + 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65, + 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69, + 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f, + 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f, + 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e, + 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0' + }; static const char ligatures_src[] = { 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0' @@ -1507,6 +1778,31 @@ static void test_FoldStringA(void) { 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0' }; + static const struct special + { + char src; + char dst[4]; + } foldczone_special[] = + { + /* src dst */ + { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } }, + { 0x98, { 0x20, 0x7e, 0x00 } }, + { 0x99, { 0x54, 0x4d, 0x00 } }, + { 0xa0, { 0x20, 0x00 } }, + { 0xa8, { 0x20, 0xa8, 0x00 } }, + { 0xaa, { 0x61, 0x00 } }, + { 0xaf, { 0x20, 0xaf, 0x00 } }, + { 0xb2, { 0x32, 0x00 } }, + { 0xb3, { 0x33, 0x00 } }, + { 0xb4, { 0x20, 0xb4, 0x00 } }, + { 0xb8, { 0x20, 0xb8, 0x00 } }, + { 0xb9, { 0x31, 0x00 } }, + { 0xba, { 0x6f, 0x00 } }, + { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } }, + { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } }, + { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } }, + { 0x00 } + }; if (!pFoldStringA) return; /* FoldString is present in NT v3.1+, but not 95/98/Me */ @@ -1522,8 +1818,11 @@ static void test_FoldStringA(void) SetLastError(0); ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256); if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("FoldStringA is not implemented\n"); return; - EXPECT_LEN(4); EXPECT_VALID; + } + ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError()); ok(strcmp(dst, digits_dst) == 0, "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst); for (i = 1; i < 256; i++) @@ -1534,7 +1833,7 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == src[0], "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst); } @@ -1545,7 +1844,7 @@ static void test_FoldStringA(void) ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256); /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */ if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) { - EXPECT_LEN(sizeof(ligatures_dst)); EXPECT_VALID; + ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError()); ok(strcmp(dst, ligatures_dst) == 0, "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst); for (i = 1; i < 256; i++) @@ -1556,24 +1855,30 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + if (ret == 3) + { + /* Vista */ + ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) || + (i == 0xFC && lstrcmpA(dst, "ue") == 0), + "Got %s for %d\n", dst, i); + } + else + { + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == src[0], "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst); } } } + } /* MAP_COMPOSITE */ SetLastError(0); ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256); - EXPECT_VALID; - todo_wine - { - /* Wine gets close, but doesn't produce quite the same result as native */ - EXPECT_LEN(121); - ok(strcmp(dst, composite_dst) == 0, - "MAP_COMPOSITE: Expected '%s', got '%s'\n", composite_dst, dst); - } + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret); + ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0, + "MAP_COMPOSITE: Mismatch, got '%s'\n", dst); for (i = 1; i < 256; i++) { @@ -1583,7 +1888,7 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == src[0], "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0], (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]); @@ -1597,11 +1902,28 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + is_special = FALSE; + for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++) + { + if (foldczone_special[j].src == src[0]) + { + ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1, + "Expected ret == 2 or %d, got %d, error %d\n", + lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError()); + ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0, + "MAP_FOLDCZONE: string mismatch for 0x%02x\n", + (unsigned char)src[0]); + is_special = TRUE; + } + } + if (! is_special) + { + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(src[0] == dst[0], "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n", (unsigned char)src[0], (unsigned char)dst[0]); } + } /* MAP_PRECOMPOSED */ for (i = 1; i < 256; i++) @@ -1610,7 +1932,7 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(src[0] == dst[0], "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n", (unsigned char)src[0], (unsigned char)dst[0]); @@ -1646,6 +1968,7 @@ static void test_FoldStringW(void) 0x0D66, /* Maylayalam */ 0x0E50, /* Thai */ 0x0ED0, /* Laos */ + 0x0F29, /* Tibet - 0 is out of sequence */ 0x2070, /* Superscript - 1, 2, 3 are out of sequence */ 0x2080, /* Subscript */ 0x245F, /* Circled - 0 is out of sequence */ @@ -1654,6 +1977,7 @@ static void test_FoldStringW(void) 0x2775, /* Inverted circled - No 0 */ 0x277F, /* Patterned circled - No 0 */ 0x2789, /* Inverted Patterned circled - No 0 */ + 0x3020, /* Hangzhou */ 0xff10, /* Pliene chasse (?) */ 0xffff /* Terminator */ }; @@ -1663,125 +1987,36 @@ static void test_FoldStringW(void) 0xB9, /* Superscript 1 */ 0xB2, /* Superscript 2 */ 0xB3, /* Superscript 3 */ + 0x0F33, /* Tibetan half zero */ 0x24EA, /* Circled 0 */ + 0x3007, /* Ideographic number zero */ '\0' /* Terminator */ }; /* Digits in digitRanges for which no representation is available */ static const WCHAR noDigitAvailable[] = { 0x0BE6, /* No Tamil 0 */ + 0x0F29, /* No Tibetan half zero (out of sequence) */ 0x2473, /* No Bracketed 0 */ 0x2487, /* No 0 Full stop */ 0x2775, /* No inverted circled 0 */ 0x277F, /* No patterned circled */ 0x2789, /* No inverted Patterned circled */ + 0x3020, /* No Hangzhou 0 */ '\0' /* Terminator */ }; - /* Compatibility conversion results */ - static const WCHAR compat_F900_FA2F[256+48] = + static const WCHAR foldczone_src[] = { - 0x8c48, 0x66f4, 0x8eca, 0x8cc8, 0x6ed1, 0x4e32, 0x53e5, 0x9f9c, - 0x9f9c, 0x5951, 0x91d1, 0x5587, 0x5948, 0x61f6, 0x7669, 0x7f85, - 0x863f, 0x87ba, 0x88f8, 0x908f, 0x6a02, 0x6d1b, 0x70d9, 0x73de, - 0x843d, 0x916a, 0x99f1, 0x4e82, 0x5375, 0x6b04, 0x721b, 0x862d, - 0x9e1e, 0x5d50, 0x6feb, 0x85cd, 0x8964, 0x62c9, 0x81d8, 0x881f, - 0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x0000, 0x4f86, 0x51b7, 0x52de, - 0x64c4, 0x6ad3, 0x7210, 0x76e7, 0x8001, 0x8606, 0x865c, 0x8def, - 0x9732, 0x9b6f, 0x9dfa, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304, - 0x9e7f, 0x8ad6, 0x58df, 0x5f04, 0x7c60, 0x807e, 0x7262, 0x78ca, - 0x8cc2, 0x96f7, 0x58d8, 0x5c62, 0x6a13, 0x6dda, 0x6f0f, 0x7d2f, - 0x7e37, 0x964b, 0x52d2, 0x808b, 0x51dc, 0x51cc, 0x7a1c, 0x7dbe, - 0x83f1, 0x9675, 0x8b80, 0x62cf, 0x6a02, 0x8afe, 0x4e39, 0x5be7, - 0x6012, 0x7387, 0x7570, 0x5317, 0x78fb, 0x4fbf, 0x5fa9, 0x4e0d, - 0x6ccc, 0x6578, 0x7d22, 0x53c3, 0x585e, 0x7701, 0x8449, 0x8aaa, - 0x6bba, 0x8fb0, 0x6c88, 0x62fe, 0x82e5, 0x63a0, 0x7565, 0x4eae, - 0x5169, 0x0000, 0x6881, 0x7ce7, 0x826f, 0x8ad2, 0x91cf, 0x52f5, - 0x5442, 0x5973, 0x5eec, 0x65c5, 0x6ffe, 0x792a, 0x95ad, 0x9a6a, - 0x9e97, 0x9ece, 0x529b, 0x66c6, 0x6b77, 0x8f62, 0x5e74, 0x6190, - 0x6200, 0x649a, 0x6f23, 0x7149, 0x7489, 0x0000, 0x7df4, 0x806f, - 0x8f26, 0x84ee, 0x9023, 0x934a, 0x5217, 0x52a3, 0x54bd, 0x70c8, - 0x88c2, 0x8aaa, 0x5ec9, 0x5ff5, 0x637b, 0x6bae, 0x7c3e, 0x7375, - 0x4ee4, 0x56f9, 0x5be7, 0x5dba, 0x601c, 0x73b2, 0x7469, 0x7f9a, - 0x8046, 0x9234, 0x96f6, 0x9748, 0x9818, 0x4f8b, 0x79ae, 0x91b4, - 0x96b8, 0x60e1, 0x4e86, 0x50da, 0x5bee, 0x5c3f, 0x6599, 0x6a02, - 0x71ce, 0x7642, 0x84fc, 0x907c, 0x9f8d, 0x6688, 0x962e, 0x5289, - 0x677b, 0x67f3, 0x6d41, 0x6e9c, 0x7409, 0x7559, 0x786b, 0x7d10, - 0x985e, 0x516d, 0x622e, 0x9678, 0x502b, 0x5d19, 0x6dea, 0x8f2a, - 0x5f8b, 0x6144, 0x6817, 0x7387, 0x9686, 0x5229, 0x540f, 0x5c65, - 0x6613, 0x674e, 0x68a8, 0x6ce5, 0x7406, 0x75e2, 0x7f79, 0x0000, - 0x88e1, 0x91cc, 0x96e2, 0x533f, 0x6eba, 0x541d, 0x71d0, 0x7498, - 0x85fa, 0x0000, 0x9c57, 0x9e9f, 0x6797, 0x6dcb, 0x81e8, 0x7acb, - 0x7b20, 0x7c92, 0x72c0, 0x7099, 0x8b58, 0x4ec0, 0x8336, 0x523a, - 0x5207, 0x5ea6, 0x62d3, 0x7cd6, 0x5b85, 0x6d1e, 0x66b4, 0x8f3b, - 0x884c, 0x964d, 0x898b, 0x5ed3, 0x0000, 0x0000, 0x0000, 0x0000, - 0x585a, 0x0000, 0x6674, 0x0000, 0x0000, 0x51de, 0x8c6c, 0x76ca, - 0x0000, 0x795e, 0x7965, 0x798f, 0x9756, 0x7cbe, 0x7fbd, 0x0000, - 0x0000, 0x0000, 0x8af8, 0x0000, 0x0000, 0x9038, 0x90fd, 0x0000, - 0x0000, 0x0000, 0x98ef, 0x98fc, 0x9928, 0x9db4, 0x0000, 0x0000 + 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d, + 0xff37, 0xff49, 0xff4e, 0xff45, '\0' }; - static const WCHAR compat_FE30_FEF7[200] = + static const WCHAR foldczone_dst[] = { - 0x2025, 0x2014, 0x2013, 0x005f, 0x005f, 0x0028, 0x0029, 0x007b, - 0x007d, 0x3014, 0x3015, 0x3010, 0x3011, 0x300a, 0x300b, 0x3008, - 0x3009, 0x300c, 0x300d, 0x300e, 0x300f, 0x0000, 0x0000, 0x0000, - 0x0000, 0x203e, 0x203e, 0x203e, 0x203e, 0x005f, 0x005f, 0x005f, - 0x002c, 0x3001, 0x002e, 0x0000, 0x003b, 0x003a, 0x003f, 0x0021, - 0x2014, 0x0028, 0x0029, 0x007b, 0x007d, 0x3014, 0x3015, 0x0023, - 0x0026, 0x002a, 0x002b, 0x002d, 0x003c, 0x003e, 0x003d, 0x0000, - 0x0000, 0x0024, 0x0025, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000, - 0x064b, 0x064b, 0x064c, 0x0000, 0x064d, 0x0000, 0x064e, 0x064e, - 0x064f, 0x064f, 0x0650, 0x0650, 0x0651, 0x0651, 0x0652, 0x0652, - 0x0621, 0x0622, 0x0622, 0x0623, 0x0623, 0x0624, 0x0624, 0x0625, - 0x0625, 0x0626, 0x0626, 0x0626, 0x0626, 0x0627, 0x0627, 0x0628, - 0x0628, 0x0628, 0x0628, 0x0629, 0x0629, 0x062a, 0x062a, 0x062a, - 0x062a, 0x062b, 0x062b, 0x062b, 0x062b, 0x062c, 0x062c, 0x062c, - 0x062c, 0x062d, 0x062d, 0x062d, 0x062d, 0x062e, 0x062e, 0x062e, - 0x062e, 0x062f, 0x062f, 0x0630, 0x0630, 0x0631, 0x0631, 0x0632, - 0x0632, 0x0633, 0x0633, 0x0633, 0x0633, 0x0634, 0x0634, 0x0634, - 0x0634, 0x0635, 0x0635, 0x0635, 0x0635, 0x0636, 0x0636, 0x0636, - 0x0636, 0x0637, 0x0637, 0x0637, 0x0637, 0x0638, 0x0638, 0x0638, - 0x0638, 0x0639, 0x0639, 0x0639, 0x0639, 0x063a, 0x063a, 0x063a, - 0x063a, 0x0641, 0x0641, 0x0641, 0x0641, 0x0642, 0x0642, 0x0642, - 0x0642, 0x0643, 0x0643, 0x0643, 0x0643, 0x0644, 0x0644, 0x0644, - 0x0644, 0x0645, 0x0645, 0x0645, 0x0645, 0x0646, 0x0646, 0x0646, - 0x0646, 0x0647, 0x0647, 0x0647, 0x0647, 0x0648, 0x0648, 0x0649, - 0x0649, 0x064a, 0x064a, 0x064a, 0x064a, 0x0000, 0x0000, 0x0000 - }; - static const WCHAR compat_FF00_FFEF[240] = - { - 0x0000, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x0000, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000, - 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb, 0x30f2, 0x30a1, - 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3, - 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad, - 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd, - 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc, - 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de, - 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9, - 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c, - 0x3164, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, - 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f, - 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147, - 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x0000, - 0x0000, 0x0000, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, - 0x0000, 0x0000, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a, - 0x0000, 0x0000, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160, - 0x0000, 0x0000, 0x3161, 0x3162, 0x3163, 0x0000, 0x0000, 0x0000, - 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9, 0x0000, - 0x2502, 0x2190, 0x2191, 0x2192, 0x2193, 0x25a0, 0x25cb, 0x0000 + 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0' }; static const WCHAR ligatures_src[] = { + 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5, 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152, 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca, 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc, @@ -1790,6 +2025,7 @@ static void test_FoldStringW(void) }; static const WCHAR ligatures_dst[] = { + 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5, 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e', 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j', 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9, @@ -1799,7 +2035,7 @@ static void test_FoldStringW(void) if (!pFoldStringW) { - skip("FoldStringW is not available\n"); + win_skip("FoldStringW is not available\n"); return; /* FoldString is present in NT v3.1+, but not 95/98/Me */ } @@ -1811,31 +2047,36 @@ static void test_FoldStringW(void) ret = pFoldStringW(badFlags[i], src, 256, dst, 256); if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { - skip("FoldStringW is not implemented\n"); + win_skip("FoldStringW is not implemented\n"); return; } - EXPECT_LEN(0); EXPECT_FLAGS; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); } /* src & dst cannot be the same */ SetLastError(0); ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256); - EXPECT_LEN(0); EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* src can't be NULL */ SetLastError(0); ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256); - EXPECT_LEN(0); EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* srclen can't be 0 */ SetLastError(0); ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256); - EXPECT_LEN(0); EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* dstlen can't be < 0 */ SetLastError(0); ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1); - EXPECT_LEN(0); EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* Ret includes terminating NUL which is appended if srclen = -1 */ SetLastError(0); @@ -1843,7 +2084,7 @@ static void test_FoldStringW(void) src[1] = '\0'; dst[0] = '\0'; ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == 'A' && dst[1] == '\0', "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n", 'A', '\0', ret, dst[0], dst[1], GetLastError()); @@ -1855,7 +2096,7 @@ static void test_FoldStringW(void) dst[0] = 'X'; dst[1] = 'X'; ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256); - EXPECT_LEN(1); EXPECT_VALID; + ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == 'A' && dst[1] == 'X', "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n", 'A','X', ret, dst[0], dst[1], GetLastError()); @@ -1870,7 +2111,7 @@ static void test_FoldStringW(void) src[0] = ch; src[1] = dst[0] = '\0'; ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) || /* Wine (correctly) maps all Unicode 4.0+ digits */ @@ -1896,9 +2137,12 @@ static void test_FoldStringW(void) src[0] = c; src[1] = dst[0] = '\0'; ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') || + broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */ + (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */ + (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */ strchrW(noDigitAvailable, c), "MAP_FOLDDIGITS: ch %d Expected %d got %d\n", ch, '0' + digitRanges[j] - ch, dst[0]); @@ -1907,63 +2151,23 @@ static void test_FoldStringW(void) } /* MAP_FOLDCZONE */ - for (ch = 1; ch <0xffff; ch++) - { - WCHAR expected = 0; - - if (ch >= 0xF900 && ch <= 0xFA2F) - expected = compat_F900_FA2F[ch - 0xF900]; - else if (ch >= 0xFE30 && ch <= 0xFEF7) - expected = compat_FE30_FEF7[ch - 0xFE30]; - else if (ch >= 0xFF00 && ch <= 0xFFEF) - expected = compat_FF00_FFEF[ch - 0xFF00]; - - if (!expected) - expected = ch; - SetLastError(0); - src[0] = ch; - src[1] = dst[0] = '\0'; - ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; - ok(dst[0] == expected || - /* Wine (correctly) uses updated mappings for some Unicode 4.0 chars */ - /* FIXME: But they should be re-checked */ - ch == 0xf92c || ch == 0xf979 || ch == 0xf995 || ch == 0xf9e7 || - ch == 0xf9f1 || - (0xfa0c <= ch && ch <= 0xfa6a) || - (0xfa70 <= ch && ch <= 0xfad9) || - ch == 0xfe47 || ch == 0xfe48 || ch == 0xfe68 || - (0xfe70 <= ch && ch <= 0xfe7f) || - ch == 0xff3c || ch == 0xff5f || ch == 0xff60 || - ch == 0xff9e || ch == 0xff9f, - "MAP_FOLDCZONE: ch %d 0x%04x Expected 0x%04x got 0x%04x\n", - ch, ch, expected, dst[0]); - } + ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256); + ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]), + "Got %d, error %d\n", ret, GetLastError()); + ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)), + "MAP_FOLDCZONE: Expanded incorrectly\n"); /* MAP_EXPAND_LIGATURES */ SetLastError(0); ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256); /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */ if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) { - EXPECT_LEN(sizeof(ligatures_dst)/sizeof(ligatures_dst[0])); EXPECT_VALID; + ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]), + "Got %d, error %d\n", ret, GetLastError()); ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)), "MAP_EXPAND_LIGATURES: Expanded incorrectly\n"); - for (i = 1; i <= 0xffff; i++) - { - if (!strchrW(ligatures_src, i)) - { - src[0] = i; - src[1] = '\0'; - SetLastError(0); - ret = pFoldStringW(MAP_EXPAND_LIGATURES, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; - ok(dst[0] == src[0], - "MAP_EXPAND_LIGATURES: 0x%02x : Expected 0x%02x, got 0x%02x\n", - i, src[0], dst[0]); } - } - } /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */ } @@ -1992,13 +2196,9 @@ static void test_ConvertDefaultLocale(void) MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT)); LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT), MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT)); - LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE), - MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE)); /* Invariant language is not treated specially */ TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT); - LCID_RES(MKLCID(LANG_INVARIANT, SUBLANG_NEUTRAL, SORT_DEFAULT), - MKLCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT)); /* User/system default languages alone are not mapped */ TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE); @@ -2028,23 +2228,34 @@ static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName, static void test_EnumSystemLanguageGroupsA(void) { + BOOL ret; + if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup) + { + win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n"); return; + } /* No enumeration proc */ SetLastError(0); - pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0); - EXPECT_INVALID; + ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("EnumSystemLanguageGroupsA is not implemented\n"); + return; + } + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* Invalid flags */ SetLastError(0); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0); - EXPECT_FLAGS; + ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); /* No flags - defaults to LGRPID_INSTALLED */ - SetLastError(0); + SetLastError(0xdeadbeef); pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1); - EXPECT_LASTERROR_0; + ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError()); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0); @@ -2056,6 +2267,10 @@ static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum, { trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam); + /* invalid locale enumerated on some platforms */ + if (lcid == 0) + return TRUE; + ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE, "Enumerated grp %d not valid\n", lgrpid); ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE, @@ -2065,28 +2280,42 @@ static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum, static void test_EnumLanguageGroupLocalesA(void) { + BOOL ret; + if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup) + { + win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n"); return; + } /* No enumeration proc */ SetLastError(0); - pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0); - EXPECT_INVALID; + ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("EnumLanguageGroupLocalesA is not implemented\n"); + return; + } + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* lgrpid too small */ SetLastError(0); - pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0); - EXPECT_INVALID; + ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0); + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* lgrpid too big */ SetLastError(0); - pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0); - EXPECT_INVALID; + ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0); + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* dwFlags is reserved */ SetLastError(0); - pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0); - EXPECT_INVALID; + ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0); + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0); } @@ -2099,17 +2328,20 @@ static void test_SetLocaleInfoA(void) /* Null data */ SetLastError(0); bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0); - EXPECT_INVALID; + ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* IDATE */ SetLastError(0); bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA); - EXPECT_FLAGS; + ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); /* ILDATE */ SetLastError(0); bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA); - EXPECT_FLAGS; + ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); } static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam) @@ -2135,30 +2367,40 @@ static void test_EnumUILanguageA(void) { BOOL ret; if (!pEnumUILanguagesA) { - trace("EnumUILanguagesA is not available on Win9x\n"); + win_skip("EnumUILanguagesA is not available on Win9x or NT4\n"); return; } SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0); - EXPECT_TRUE; EXPECT_VALID; + if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("EnumUILanguagesA is not implemented\n"); + return; + } + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); enumCount = 0; SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0); - EXPECT_TRUE; EXPECT_VALID; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(NULL, 0, 0); - EXPECT_FALSE; EXPECT_INVALID; + ok(!ret, "Expected return value FALSE, got %u\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0); - EXPECT_FALSE; EXPECT_FLAGS; + ok(!ret, "Expected return value FALSE, got %u\n", ret); + ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0); - EXPECT_FALSE; EXPECT_INVALID; + ok(!ret, "Expected return value FALSE, got %u\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); } static char date_fmt_buf[1024]; @@ -2178,7 +2420,14 @@ static void test_EnumDateFormatsA(void) trace("EnumDateFormatsA 0\n"); date_fmt_buf[0] = 0; + SetLastError(0xdeadbeef); ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0); + if (!ret && (GetLastError() == ERROR_INVALID_FLAGS)) + { + win_skip("0 for dwFlags is not supported\n"); + } + else + { ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError()); trace("%s\n", date_fmt_buf); /* test the 1st enumerated format */ @@ -2186,10 +2435,18 @@ static void test_EnumDateFormatsA(void) ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf)); ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); + } trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n"); date_fmt_buf[0] = 0; + SetLastError(0xdeadbeef); ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP); + if (!ret && (GetLastError() == ERROR_INVALID_FLAGS)) + { + win_skip("LOCALE_USE_CP_ACP is not supported\n"); + } + else + { ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError()); trace("%s\n", date_fmt_buf); /* test the 1st enumerated format */ @@ -2197,6 +2454,7 @@ static void test_EnumDateFormatsA(void) ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf)); ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError()); ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); + } trace("EnumDateFormatsA DATE_SHORTDATE\n"); date_fmt_buf[0] = 0; @@ -2235,7 +2493,8 @@ static void test_EnumDateFormatsA(void) if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf)); ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError()); - ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); + ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */, + "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); } static void test_EnumTimeFormatsA(void) @@ -2280,21 +2539,36 @@ static void test_GetCPInfo(void) SetLastError(0xdeadbeef); ret = GetCPInfo(CP_UTF7, &cpinfo); + if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) + { + skip("Codepage CP_UTF7 is not installed/available\n"); + } + else + { ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError()); ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]); ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]); ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]); ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]); ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize); + } SetLastError(0xdeadbeef); ret = GetCPInfo(CP_UTF8, &cpinfo); + if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) + { + skip("Codepage CP_UTF8 is not installed/available\n"); + } + else + { ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError()); ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]); ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]); ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]); ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]); - ok(cpinfo.MaxCharSize == 4, "expected 5, got 0x%x\n", cpinfo.MaxCharSize); + ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */, + "expected 4, got %u\n", cpinfo.MaxCharSize); +} } START_TEST(locale) @@ -2304,6 +2578,7 @@ START_TEST(locale) test_EnumTimeFormatsA(); test_EnumDateFormatsA(); test_GetLocaleInfoA(); + test_GetLocaleInfoW(); test_GetTimeFormatA(); test_GetDateFormatA(); test_GetDateFormatW(); diff --git a/rostests/winetests/kernel32/mailslot.c b/rostests/winetests/kernel32/mailslot.c index 995f144b1a9..66a1c2538e1 100755 --- a/rostests/winetests/kernel32/mailslot.c +++ b/rostests/winetests/kernel32/mailslot.c @@ -34,6 +34,7 @@ static int mailslot_test(void) HANDLE hSlot, hSlot2, hWriter, hWriter2; unsigned char buffer[16]; DWORD count, dwMax, dwNext, dwMsgCount, dwTimeout; + BOOL ret; /* sanity check on GetMailslotInfo */ dwMax = dwNext = dwMsgCount = dwTimeout = 0; @@ -54,10 +55,13 @@ static int mailslot_test(void) /* open a mailslot with a null name */ hSlot = CreateMailslot( NULL, 0, 0, NULL ); - ok( hSlot == INVALID_HANDLE_VALUE, + ok( hSlot == INVALID_HANDLE_VALUE || broken(hSlot != INVALID_HANDLE_VALUE), /* win9x */ "Created mailslot with invalid name\n"); + if (hSlot == INVALID_HANDLE_VALUE) ok( GetLastError() == ERROR_PATH_NOT_FOUND, "error should be ERROR_PATH_NOT_FOUND\n"); + else /* succeeds on win9x */ + CloseHandle( hSlot ); /* valid open, but with wacky parameters ... then check them */ hSlot = CreateMailslot( szmspath, -1, -1, NULL ); @@ -80,32 +84,36 @@ static int mailslot_test(void) /* try and read/write to it */ count = 0; memset(buffer, 0, sizeof buffer); - ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), - "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "slot read\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); ok( !WriteFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot write\n"); ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); /* now try and openthe client, but with the wrong sharing mode */ - hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE, + hWriter = CreateFile(szmspath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter == INVALID_HANDLE_VALUE, "bad sharing mode\n"); - ok( GetLastError() == ERROR_SHARING_VIOLATION, - "error should be ERROR_SHARING_VIOLATION\n"); + ok( hWriter != INVALID_HANDLE_VALUE /* vista */ || GetLastError() == ERROR_SHARING_VIOLATION, + "error should be ERROR_SHARING_VIOLATION got %p / %u\n", hWriter, GetLastError()); + if (hWriter != INVALID_HANDLE_VALUE) CloseHandle( hWriter ); /* now open the client with the correct sharing mode */ hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter != INVALID_HANDLE_VALUE, "existing mailslot\n"); + if (hWriter == INVALID_HANDLE_VALUE) /* win9x doesn't like GENERIC_READ */ + hWriter = CreateFile(szmspath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + ok( hWriter != INVALID_HANDLE_VALUE, "existing mailslot err %u\n", GetLastError()); /* * opening a client should make no difference to * whether we can read or write the mailslot */ - ok( !ReadFile( hSlot, buffer, sizeof buffer/2, &count, NULL), - "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer/2, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "slot read\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); ok( !WriteFile( hSlot, buffer, sizeof buffer/2, &count, NULL), "slot write\n"); ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); @@ -116,12 +124,14 @@ static int mailslot_test(void) */ ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can read client\n"); - todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED, + "wrong error %u\n", GetLastError() ); ok( WriteFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can't write client\n"); ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can read client\n"); - todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED, + "wrong error %u\n", GetLastError() ); /* * seeing as there's something in the slot, @@ -132,24 +142,28 @@ static int mailslot_test(void) ok( count == (sizeof buffer/2), "short read\n" ); /* but not again */ - ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), - "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "slot read\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); /* now try open another writer... should fail */ hWriter2 = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter2 == INVALID_HANDLE_VALUE, "two writers\n"); + /* succeeds on vista, don't test */ + if (hWriter2 != INVALID_HANDLE_VALUE) CloseHandle( hWriter2 ); /* now try open another as a reader ... also fails */ hWriter2 = CreateFile(szmspath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter2 == INVALID_HANDLE_VALUE, "writer + reader\n"); + /* succeeds on vista, don't test */ + if (hWriter2 != INVALID_HANDLE_VALUE) CloseHandle( hWriter2 ); /* now try open another as a writer ... still fails */ hWriter2 = CreateFile(szmspath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter2 == INVALID_HANDLE_VALUE, "writer\n"); + /* succeeds on vista, don't test */ + if (hWriter2 != INVALID_HANDLE_VALUE) CloseHandle( hWriter2 ); /* now open another one */ hSlot2 = CreateMailslot( szmspath, 0, 0, NULL ); @@ -172,7 +186,8 @@ static int mailslot_test(void) */ hWriter2 = CreateFile(szmspath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter2 == INVALID_HANDLE_VALUE, "greedy writer succeeded\n"); + /* succeeds on vista, don't test */ + if (hWriter2 != INVALID_HANDLE_VALUE) CloseHandle( hWriter2 ); /* now try open another as a writer ... and share with the first */ hWriter2 = CreateFile(szmspath, GENERIC_WRITE, @@ -189,8 +204,10 @@ static int mailslot_test(void) ok( dwTimeout == 0, "dwTimeout incorrect\n"); /* check there's still no data */ - ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "slot read\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); /* write two messages */ buffer[0] = 'a'; @@ -224,9 +241,9 @@ static int mailslot_test(void) ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 1, "dwNext incorrect\n"); - todo_wine { - ok( dwMsgCount == 3, "dwMsgCount incorrect\n"); - } + todo_wine + ok( dwMsgCount == 3 || broken(dwMsgCount == 2), /* win9x */ + "dwMsgCount incorrect %u\n", dwMsgCount); buffer[0]=buffer[1]=0; @@ -245,7 +262,8 @@ static int mailslot_test(void) "getmailslotinfo failed\n"); ok( dwNext == 2, "dwNext incorrect\n"); todo_wine { - ok( dwMsgCount == 2, "dwMsgCount incorrect\n"); + ok( dwMsgCount == 2 || broken(dwMsgCount == 1), /* win9x */ + "dwMsgCount incorrect %u\n", dwMsgCount); } /* read the second message */ @@ -258,9 +276,10 @@ static int mailslot_test(void) dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); - ok( dwNext == 0, "dwNext incorrect\n"); + ok( dwNext == 0 || broken(dwNext == ~0u), /* win9x */ "dwNext incorrect %u\n", dwNext); todo_wine { - ok( dwMsgCount == 1, "dwMsgCount incorrect\n"); + ok( dwMsgCount == 1 || broken(dwMsgCount == 0), /* win9x */ + "dwMsgCount incorrect %u\n", dwMsgCount); } /* read the 3rd (zero length) message */ @@ -281,9 +300,10 @@ static int mailslot_test(void) ok( dwMsgCount == 0, "dwMsgCount incorrect\n"); /* check that reads fail */ - ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), - "3rd slot read succeeded\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "3rd slot read succeeded\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); /* finally close the mailslot and its client */ ok( CloseHandle( hWriter2 ), "closing 2nd client\n"); @@ -297,7 +317,8 @@ static int mailslot_test(void) memset(buffer, 0, sizeof buffer); dwTimeout = GetTickCount(); ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_SEM_TIMEOUT || broken(GetLastError() == ERROR_ACCESS_DENIED), /* win9x */ + "wrong error %u\n", GetLastError() ); dwTimeout = GetTickCount() - dwTimeout; ok( dwTimeout >= 990, "timeout too short %u\n", dwTimeout ); ok( CloseHandle( hSlot ), "closing the mailslot\n"); diff --git a/rostests/winetests/kernel32/module.c b/rostests/winetests/kernel32/module.c index f524be70d56..4cb30a8d89f 100755 --- a/rostests/winetests/kernel32/module.c +++ b/rostests/winetests/kernel32/module.c @@ -216,6 +216,151 @@ static void testGetProcAddress_Wrong(void) "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_HANDLE(win9x), got %d\n", GetLastError()); } +static void testLoadLibraryEx(void) +{ + CHAR path[MAX_PATH]; + HMODULE hmodule; + HANDLE hfile; + + hfile = CreateFileA("testfile.dll", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + ok(hfile != INVALID_HANDLE_VALUE, "Expected a valid file handle\n"); + + /* NULL lpFileName */ + if (is_unicode_enabled) + { + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(NULL, NULL, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + ok(GetLastError() == ERROR_MOD_NOT_FOUND || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %d\n", + GetLastError()); + } + else + win_skip("NULL filename crashes on WinMe\n"); + + /* empty lpFileName */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("", NULL, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + ok(GetLastError() == ERROR_MOD_NOT_FOUND || + GetLastError() == ERROR_DLL_NOT_FOUND, /* win9x */ + "Expected ERROR_MOD_NOT_FOUND or ERROR_DLL_NOT_FOUND, got %d\n", + GetLastError()); + + /* hFile is non-NULL */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("testfile.dll", hfile, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + todo_wine + { + ok(GetLastError() == ERROR_SHARING_VIOLATION || + GetLastError() == ERROR_INVALID_PARAMETER || /* win2k3 */ + GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */ + "Unexpected last error, got %d\n", GetLastError()); + } + + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("testfile.dll", (HANDLE)0xdeadbeef, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + todo_wine + { + ok(GetLastError() == ERROR_SHARING_VIOLATION || + GetLastError() == ERROR_INVALID_PARAMETER || /* win2k3 */ + GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */ + "Unexpected last error, got %d\n", GetLastError()); + } + + /* try to open a file that is locked */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("testfile.dll", NULL, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + todo_wine + { + ok(GetLastError() == ERROR_SHARING_VIOLATION || + GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */ + "Expected ERROR_SHARING_VIOLATION or ERROR_FILE_NOT_FOUND, got %d\n", + GetLastError()); + } + + /* lpFileName does not matter */ + if (is_unicode_enabled) + { + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(NULL, hfile, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + ok(GetLastError() == ERROR_MOD_NOT_FOUND || + GetLastError() == ERROR_INVALID_PARAMETER, /* win2k3 */ + "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %d\n", + GetLastError()); + } + + CloseHandle(hfile); + + /* load empty file */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("testfile.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + todo_wine + { + ok(GetLastError() == ERROR_FILE_INVALID || + GetLastError() == ERROR_BAD_FORMAT, /* win9x */ + "Expected ERROR_FILE_INVALID or ERROR_BAD_FORMAT, got %d\n", + GetLastError()); + } + + DeleteFileA("testfile.dll"); + + GetSystemDirectoryA(path, MAX_PATH); + if (path[lstrlenA(path) - 1] != '\\') + lstrcatA(path, "\\"); + lstrcatA(path, "kernel32.dll"); + + /* load kernel32.dll with an absolute path */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(path, NULL, LOAD_LIBRARY_AS_DATAFILE); + ok(hmodule != 0, "Expected valid module handle\n"); + ok(GetLastError() == 0xdeadbeef || + GetLastError() == ERROR_SUCCESS, /* win9x */ + "Expected 0xdeadbeef or ERROR_SUCCESS, got %d\n", GetLastError()); + + /* try invalid file handle */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(path, (HANDLE)0xdeadbeef, 0); + if (!hmodule) /* succeeds on xp and older */ + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + CloseHandle(hmodule); + + /* load kernel32.dll with no path */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("kernel32.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); + ok(hmodule != 0, "Expected valid module handle\n"); + ok(GetLastError() == 0xdeadbeef || + GetLastError() == ERROR_SUCCESS, /* win9x */ + "Expected 0xdeadbeef or ERROR_SUCCESS, got %d\n", GetLastError()); + + CloseHandle(hmodule); + + GetCurrentDirectoryA(MAX_PATH, path); + if (path[lstrlenA(path) - 1] != '\\') + lstrcatA(path, "\\"); + lstrcatA(path, "kernel32.dll"); + + /* load kernel32.dll with an absolute path that does not exist */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(path, NULL, LOAD_LIBRARY_AS_DATAFILE); + todo_wine + { + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + } + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + broken(GetLastError() == ERROR_INVALID_HANDLE), /* nt4 */ + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); +} + START_TEST(module) { WCHAR filenameW[MAX_PATH]; @@ -226,7 +371,7 @@ START_TEST(module) GetModuleFileNameW(NULL, filenameW, MAX_PATH); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("GetModuleFileNameW not existing on this platform, skipping W-calls\n"); + win_skip("GetModuleFileNameW not existing on this platform, skipping W-calls\n"); is_unicode_enabled = FALSE; } @@ -238,4 +383,5 @@ START_TEST(module) testNestedLoadLibraryA(); testLoadLibraryA_Wrong(); testGetProcAddress_Wrong(); + testLoadLibraryEx(); } diff --git a/rostests/winetests/kernel32/path.c b/rostests/winetests/kernel32/path.c index d158df1dbcc..dfe889f26c8 100755 --- a/rostests/winetests/kernel32/path.c +++ b/rostests/winetests/kernel32/path.c @@ -328,7 +328,7 @@ static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive) "GetTempPathA returned a path that did not end in '\\'\n"); lstrcpyA(tmpstr,"aaaaaaaa"); len1=GetTempPathA(len,tmpstr); - ok(len1==len+1, + ok(len1==len+1 || broken(len1 == len), /* WinME */ "GetTempPathA should return string length %d instead of %d\n",len+1,len1); /* Test GetTmpFileNameA @@ -384,14 +384,16 @@ static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive) ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n"); sprintf(tmpstr,"%s\\%s",newdir,LONGDIR); ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n"); - bRes = CreateDirectoryA("c:",NULL); + sprintf(tmpstr,"%c:", *curDrive); + bRes = CreateDirectoryA(tmpstr,NULL); ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_ALREADY_EXISTS), - "CreateDirectoryA(\"c:\" should have failed (%d)\n", GetLastError()); - bRes = CreateDirectoryA("c:\\",NULL); + "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError()); + sprintf(tmpstr,"%c:\\", *curDrive); + bRes = CreateDirectoryA(tmpstr,NULL); ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_ALREADY_EXISTS), - "CreateDirectoryA(\"c:\\\" should have failed (%d)\n", GetLastError()); + "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError()); sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE); hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL, CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); @@ -465,6 +467,14 @@ static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir) /* starting with a '.' */ sprintf(tmpstr,".\\%s",LONGDIR); test_setdir(newdir,tmpstr,tmpstr1,1,"check 9"); +/* change to root without a trailing backslash. The function call succeeds + but the directory is not changed. +*/ + sprintf(tmpstr, "%c:", newdir[0]); + test_setdir(newdir,tmpstr,newdir,1,"check 10"); +/* works however with a trailing backslash */ + sprintf(tmpstr, "%c:\\", newdir[0]); + test_setdir(newdir,tmpstr,NULL,1,"check 11"); } /* Cleanup the mess we made while executing these tests */ @@ -869,7 +879,10 @@ static void test_GetTempPathW(char* tmp_dir) lstrcpyW(buf, fooW); len = GetTempPathW(MAX_PATH, buf); if (len==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetTempPathW is not available\n"); return; + } ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n"); ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n"); @@ -893,15 +906,18 @@ static void test_GetTempPath(void) char windir[MAX_PATH]; char buf[MAX_PATH]; - GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP)); + if (!GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP))) save_TMP[0] = 0; /* test default configuration */ trace("TMP=%s\n", save_TMP); + if (save_TMP[0]) + { strcpy(buf,save_TMP); if (buf[strlen(buf)-1]!='\\') strcat(buf,"\\"); test_GetTempPathA(buf); test_GetTempPathW(buf); + } /* TMP=C:\WINDOWS */ GetWindowsDirectoryA(windir, sizeof(windir)); @@ -948,7 +964,7 @@ static void test_GetLongPathNameW(void) length = pGetLongPathNameW(NULL,NULL,0); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("GetLongPathNameW is not implemented\n"); + win_skip("GetLongPathNameW is not implemented\n"); return; } ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length); @@ -977,7 +993,7 @@ static void test_GetShortPathNameW(void) GetTempPathW( MAX_PATH, path ); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("GetTempPathW is not implemented\n"); + win_skip("GetTempPathW is not implemented\n"); return; } @@ -1208,8 +1224,11 @@ static void test_drive_letter_case(void) ret = GetTempPath(sizeof(buf), buf); ok(ret, "GetTempPath error %u\n", GetLastError()); ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret); + if (buf[0]) + { ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]); ok(buf[strlen(buf)-1] == '\\', "Temporary path (%s) doesn't end in a slash\n", buf); + } memset(buf, 0, sizeof(buf)); SetLastError(0xdeadbeef); diff --git a/rostests/winetests/kernel32/pipe.c b/rostests/winetests/kernel32/pipe.c index ce0f5b691a7..c5df6ef19ba 100755 --- a/rostests/winetests/kernel32/pipe.c +++ b/rostests/winetests/kernel32/pipe.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -63,13 +62,6 @@ static void test_CreateNamedPipe(int pipemode) /* nInBufSize */ 1024, /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, /* lpSecurityAttrib */ NULL); - - if (hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - /* Is this the right way to notify user of skipped tests? */ - ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, - "CreateNamedPipe not supported on this platform, skipping tests.\n"); - return; - } ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME, "CreateNamedPipe should fail if name doesn't start with \\\\.\\pipe\n"); @@ -390,7 +382,7 @@ static void test_CreateNamedPipe_instances_must_match(void) /** implementation of alarm() */ static DWORD CALLBACK alarmThreadMain(LPVOID arg) { - DWORD timeout = (DWORD) arg; + DWORD_PTR timeout = (DWORD_PTR) arg; trace("alarmThreadMain\n"); if (WaitForSingleObject( alarm_event, timeout ) == WAIT_TIMEOUT) { @@ -558,51 +550,74 @@ static DWORD CALLBACK serverThreadMain3(LPVOID arg) trace("Server calling overlapped ConnectNamedPipe...\n"); success = ConnectNamedPipe(hnp, &oOverlap); err = GetLastError(); - ok(success || err == ERROR_IO_PENDING - || err == ERROR_PIPE_CONNECTED, "overlapped ConnectNamedPipe\n"); + ok(!success && (err == ERROR_IO_PENDING || err == ERROR_PIPE_CONNECTED), "overlapped ConnectNamedPipe\n"); trace("overlapped ConnectNamedPipe returned.\n"); - if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait) - ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ConnectNamedPipe\n"); + if (!success && (err == ERROR_IO_PENDING)) { + if (letWFSOEwait) + { + DWORD ret; + do { + ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); + } while (ret == WAIT_IO_COMPLETION); + ok(ret == 0, "wait ConnectNamedPipe returned %x\n", ret); + } success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait); if (!letGORwait && !letWFSOEwait && !success) { ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n"); success = GetOverlappedResult(hnp, &oOverlap, &dummy, TRUE); } - ok(success, "GetOverlappedResult ConnectNamedPipe\n"); + } + ok(success || (err == ERROR_PIPE_CONNECTED), "GetOverlappedResult ConnectNamedPipe\n"); trace("overlapped ConnectNamedPipe operation complete.\n"); /* Echo bytes once */ memset(buf, 0, sizeof(buf)); trace("Server reading...\n"); - success = ReadFile(hnp, buf, sizeof(buf), NULL, &oOverlap); + success = ReadFile(hnp, buf, sizeof(buf), &readden, &oOverlap); trace("Server ReadFile returned...\n"); err = GetLastError(); ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile\n"); trace("overlapped ReadFile returned.\n"); - if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait) - ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ReadFile\n"); + if (!success && (err == ERROR_IO_PENDING)) { + if (letWFSOEwait) + { + DWORD ret; + do { + ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); + } while (ret == WAIT_IO_COMPLETION); + ok(ret == 0, "wait ReadFile returned %x\n", ret); + } success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait); if (!letGORwait && !letWFSOEwait && !success) { ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n"); success = GetOverlappedResult(hnp, &oOverlap, &readden, TRUE); } + } trace("Server done reading.\n"); ok(success, "overlapped ReadFile\n"); trace("Server writing...\n"); - success = WriteFile(hnp, buf, readden, NULL, &oOverlap); + success = WriteFile(hnp, buf, readden, &written, &oOverlap); trace("Server WriteFile returned...\n"); err = GetLastError(); ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile\n"); trace("overlapped WriteFile returned.\n"); - if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait) - ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait WriteFile\n"); + if (!success && (err == ERROR_IO_PENDING)) { + if (letWFSOEwait) + { + DWORD ret; + do { + ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); + } while (ret == WAIT_IO_COMPLETION); + ok(ret == 0, "wait WriteFile returned %x\n", ret); + } success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait); if (!letGORwait && !letWFSOEwait && !success) { ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n"); success = GetOverlappedResult(hnp, &oOverlap, &written, TRUE); } + } trace("Server done writing.\n"); ok(success, "overlapped WriteFile\n"); ok(written == readden, "write file len\n"); @@ -614,6 +629,113 @@ static DWORD CALLBACK serverThreadMain3(LPVOID arg) return 0; } +/** Trivial byte echo server - uses i/o completion ports */ +static DWORD CALLBACK serverThreadMain4(LPVOID arg) +{ + int i; + HANDLE hcompletion; + + trace("serverThreadMain4\n"); + /* Set up a simple echo server */ + hnp = CreateNamedPipe(PIPENAME "serverThreadMain4", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_WAIT, + /* nMaxInstances */ 1, + /* nOutBufSize */ 1024, + /* nInBufSize */ 1024, + /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, + /* lpSecurityAttrib */ NULL); + ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + + hcompletion = CreateIoCompletionPort(hnp, NULL, 12345, 1); + ok(hcompletion != NULL, "CreateIoCompletionPort failed, error=%i\n", GetLastError()); + + for (i = 0; i < NB_SERVER_LOOPS; i++) { + char buf[512]; + DWORD written; + DWORD readden; + DWORD dummy; + DWORD success; + OVERLAPPED oConnect; + OVERLAPPED oRead; + OVERLAPPED oWrite; + OVERLAPPED *oResult; + DWORD err; + ULONG_PTR compkey; + + memset(&oConnect, 0, sizeof(oConnect)); + memset(&oRead, 0, sizeof(oRead)); + memset(&oWrite, 0, sizeof(oWrite)); + + /* Wait for client to connect */ + trace("Server calling overlapped ConnectNamedPipe...\n"); + success = ConnectNamedPipe(hnp, &oConnect); + err = GetLastError(); + ok(!success && (err == ERROR_IO_PENDING || err == ERROR_PIPE_CONNECTED), + "overlapped ConnectNamedPipe got %u err %u\n", success, err ); + if (!success && err == ERROR_IO_PENDING) { + trace("ConnectNamedPipe GetQueuedCompletionStatus\n"); + success = GetQueuedCompletionStatus(hcompletion, &dummy, &compkey, &oResult, 0); + if (!success) + { + ok( GetLastError() == WAIT_TIMEOUT, + "ConnectNamedPipe GetQueuedCompletionStatus wrong error %u\n", GetLastError()); + success = GetQueuedCompletionStatus(hcompletion, &dummy, &compkey, &oResult, 10000); + } + ok(success, "ConnectNamedPipe GetQueuedCompletionStatus failed, errno=%i\n", GetLastError()); + if (success) + { + ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey); + ok(oResult == &oConnect, "got overlapped pointer %p instead of %p\n", oResult, &oConnect); + } + } + trace("overlapped ConnectNamedPipe operation complete.\n"); + + /* Echo bytes once */ + memset(buf, 0, sizeof(buf)); + + trace("Server reading...\n"); + success = ReadFile(hnp, buf, sizeof(buf), &readden, &oRead); + trace("Server ReadFile returned...\n"); + err = GetLastError(); + ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile, err=%i\n", err); + success = GetQueuedCompletionStatus(hcompletion, &readden, &compkey, + &oResult, 10000); + ok(success, "ReadFile GetQueuedCompletionStatus failed, errno=%i\n", GetLastError()); + if (success) + { + ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey); + ok(oResult == &oRead, "got overlapped pointer %p instead of %p\n", oResult, &oRead); + } + trace("Server done reading.\n"); + + trace("Server writing...\n"); + success = WriteFile(hnp, buf, readden, &written, &oWrite); + trace("Server WriteFile returned...\n"); + err = GetLastError(); + ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile failed, err=%u\n", err); + success = GetQueuedCompletionStatus(hcompletion, &written, &compkey, + &oResult, 10000); + ok(success, "WriteFile GetQueuedCompletionStatus failed, errno=%i\n", GetLastError()); + if (success) + { + ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey); + ok(oResult == &oWrite, "got overlapped pointer %p instead of %p\n", oResult, &oWrite); + ok(written == readden, "write file len\n"); + } + trace("Server done writing.\n"); + + /* finish this connection, wait for next one */ + ok(FlushFileBuffers(hnp), "FlushFileBuffers\n"); + success = DisconnectNamedPipe(hnp); + ok(success, "DisconnectNamedPipe failed, err %u\n", GetLastError()); + } + + ok(CloseHandle(hnp), "CloseHandle named pipe failed, err=%i\n", GetLastError()); + ok(CloseHandle(hcompletion), "CloseHandle completion failed, err=%i\n", GetLastError()); + + return 0; +} + static void exercizeServer(const char *pipename, HANDLE serverThread) { int i; @@ -691,13 +813,15 @@ static void test_NamedPipe_2(void) ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n"); exercizeServer(PIPENAME "serverThreadMain2", serverThread); - if( 0 ) /* overlapped pipe server doesn't work yet - it randomly fails */ - { /* Try server #3 */ serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId); ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n"); exercizeServer(PIPENAME "serverThreadMain3", serverThread); - } + + /* Try server #4 */ + serverThread = CreateThread(NULL, 0, serverThreadMain4, 0, 0, &serverThreadId); + ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread\n"); + exercizeServer(PIPENAME "serverThreadMain4", serverThread); ok(SetEvent( alarm_event ), "SetEvent\n"); CloseHandle( alarm_event ); @@ -712,15 +836,19 @@ static int test_DisconnectNamedPipe(void) char ibuf[32]; DWORD written; DWORD readden; + DWORD ret; + SetLastError(0xdeadbeef); hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, /* nMaxInstances */ 1, /* nOutBufSize */ 1024, /* nInBufSize */ 1024, /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, /* lpSecurityAttrib */ NULL); - if (INVALID_HANDLE_VALUE == hnp) { - trace ("Seems we have no named pipes.\n"); + if ((hnp == INVALID_HANDLE_VALUE /* Win98 */ || !hnp /* Win95 */) + && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + + win_skip("Named pipes are not implemented\n"); return 1; } @@ -749,6 +877,8 @@ static int test_DisconnectNamedPipe(void) "ReadFile from disconnected pipe with bytes waiting\n"); ok(!DisconnectNamedPipe(hnp) && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "DisconnectNamedPipe worked twice\n"); + ret = WaitForSingleObject(hFile, 0); + ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %X\n", ret); ok(CloseHandle(hFile), "CloseHandle\n"); } @@ -793,7 +923,7 @@ static void test_CreatePipe(void) size = 32768; buffer = HeapAlloc( GetProcessHeap(), 0, size ); for (i = 0; i < size; i++) buffer[i] = i; - ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, size) != 0, "CreatePipe failed\n"); + ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, (size + 24)) != 0, "CreatePipe failed\n"); ok(WriteFile(pipewrite, buffer, size, &written, NULL), "Write to anonymous pipe failed\n"); ok(written == size, "Write to anonymous pipe wrote %d bytes\n", written); /* and close the write end, read should still succeed*/ @@ -819,7 +949,7 @@ struct named_pipe_client_params static DWORD CALLBACK named_pipe_client_func(LPVOID p) { - struct named_pipe_client_params *params = (struct named_pipe_client_params *)p; + struct named_pipe_client_params *params = p; HANDLE pipe; BOOL ret; const char message[] = "Test"; @@ -952,8 +1082,8 @@ static void test_ImpersonateNamedPipeClient(HANDLE hClientToken, DWORD security_ SetLastError(0xdeadbeef); ret = ImpersonateNamedPipeClient(hPipeServer); error = GetLastError(); - todo_wine - ok(!ret && (error == ERROR_CANNOT_IMPERSONATE), "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d\n", GetLastError()); + ok(ret /* win2k3 */ || (error == ERROR_CANNOT_IMPERSONATE), + "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d\n", GetLastError()); ret = ConnectNamedPipe(hPipeServer, NULL); ok(ret || (GetLastError() == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed with error %d\n", GetLastError()); @@ -1264,7 +1394,7 @@ static DWORD CALLBACK overlapped_server(LPVOID arg) OVERLAPPED ol; HANDLE pipe; int ret, err; - struct overlapped_server_args *a = (struct overlapped_server_args*)arg; + struct overlapped_server_args *a = arg; DWORD num; char buf[100]; @@ -1321,6 +1451,117 @@ static void test_overlapped(void) CloseHandle(thread); } +static void test_NamedPipeHandleState(void) +{ + HANDLE server, client; + BOOL ret; + DWORD state, instances, maxCollectionCount, collectDataTimeout; + char userName[MAX_PATH]; + + server = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, + /* dwOpenMode */ PIPE_TYPE_BYTE | PIPE_WAIT, + /* nMaxInstances */ 1, + /* nOutBufSize */ 1024, + /* nInBufSize */ 1024, + /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, + /* lpSecurityAttrib */ NULL); + ok(server != INVALID_HANDLE_VALUE, "cf failed\n"); + ret = GetNamedPipeHandleState(server, NULL, NULL, NULL, NULL, NULL, 0); + todo_wine + ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError()); + ret = GetNamedPipeHandleState(server, &state, &instances, NULL, NULL, NULL, + 0); + todo_wine + ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError()); + if (ret) + { + ok(state == 0, "unexpected state %08x\n", state); + ok(instances == 1, "expected 1 instances, got %d\n", instances); + } + /* Some parameters have no meaning, and therefore can't be retrieved, + * on a local pipe. + */ + SetLastError(0xdeadbeef); + ret = GetNamedPipeHandleState(server, &state, &instances, + &maxCollectionCount, &collectDataTimeout, userName, + sizeof(userName) / sizeof(userName[0])); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* A byte-mode pipe server can't be changed to message mode. */ + state = PIPE_READMODE_MESSAGE; + SetLastError(0xdeadbeef); + ret = SetNamedPipeHandleState(server, &state, NULL, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + ok(client != INVALID_HANDLE_VALUE, "cf failed\n"); + + state = PIPE_READMODE_BYTE; + ret = SetNamedPipeHandleState(client, &state, NULL, NULL); + todo_wine + ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError()); + /* A byte-mode pipe client can't be changed to message mode, either. */ + state = PIPE_READMODE_MESSAGE; + SetLastError(0xdeadbeef); + ret = SetNamedPipeHandleState(server, &state, NULL, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + CloseHandle(client); + CloseHandle(server); + + server = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, + /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_WAIT, + /* nMaxInstances */ 1, + /* nOutBufSize */ 1024, + /* nInBufSize */ 1024, + /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, + /* lpSecurityAttrib */ NULL); + ok(server != INVALID_HANDLE_VALUE, "cf failed\n"); + ret = GetNamedPipeHandleState(server, NULL, NULL, NULL, NULL, NULL, 0); + todo_wine + ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError()); + ret = GetNamedPipeHandleState(server, &state, &instances, NULL, NULL, NULL, + 0); + todo_wine + ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError()); + if (ret) + { + ok(state == 0, "unexpected state %08x\n", state); + ok(instances == 1, "expected 1 instances, got %d\n", instances); + } + /* In contrast to byte-mode pipes, a message-mode pipe server can be + * changed to byte mode. + */ + state = PIPE_READMODE_BYTE; + ret = SetNamedPipeHandleState(server, &state, NULL, NULL); + todo_wine + ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError()); + + client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + ok(client != INVALID_HANDLE_VALUE, "cf failed\n"); + + state = PIPE_READMODE_MESSAGE; + ret = SetNamedPipeHandleState(client, &state, NULL, NULL); + todo_wine + ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError()); + /* A message-mode pipe client can also be changed to byte mode. + */ + state = PIPE_READMODE_BYTE; + ret = SetNamedPipeHandleState(client, &state, NULL, NULL); + todo_wine + ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError()); + + CloseHandle(client); + CloseHandle(server); +} + START_TEST(pipe) { HMODULE hmod; @@ -1337,4 +1578,5 @@ START_TEST(pipe) test_CreatePipe(); test_impersonation(); test_overlapped(); + test_NamedPipeHandleState(); } diff --git a/rostests/winetests/kernel32/process.c b/rostests/winetests/kernel32/process.c index 3a3743a5c10..dadb53cd318 100755 --- a/rostests/winetests/kernel32/process.c +++ b/rostests/winetests/kernel32/process.c @@ -24,16 +24,41 @@ #include #include -#include "wine/test.h" +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winuser.h" #include "wincon.h" #include "winnls.h" +#include "winternl.h" + +#include "wine/test.h" + +#define expect_eq_d(expected, actual) \ + do { \ + int value = (actual); \ + ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \ + (expected), value); \ + } while (0) +#define expect_eq_s(expected, actual) \ + do { \ + LPCSTR value = (actual); \ + ok(lstrcmpA((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \ + expected, value); \ + } while (0) +#define expect_eq_ws_i(expected, actual) \ + do { \ + LPCWSTR value = (actual); \ + ok(lstrcmpiW((expected), value) == 0, "Expected " #actual " to be L\"%s\" (" #expected ") is L\"%s\"\n", \ + wine_dbgstr_w(expected), wine_dbgstr_w(value)); \ + } while (0) static HINSTANCE hkernel32; static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD); static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD); +static BOOL (WINAPI *pQueryFullProcessImageNameA)(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize); +static BOOL (WINAPI *pQueryFullProcessImageNameW)(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD lpdwSize); /* ############################### */ static char base[MAX_PATH]; @@ -124,7 +149,6 @@ static char* decodeA(const char* str) return ptr; } -#if 0 /* This will be needed to decode Unicode strings saved by the child process * when we test Unicode functions. */ @@ -145,7 +169,6 @@ static WCHAR* decodeW(const char* str) ptr[len] = '\0'; return ptr; } -#endif /****************************************************************** * init @@ -173,6 +196,8 @@ static int init(void) hkernel32 = GetModuleHandleA("kernel32"); pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx"); pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx"); + pQueryFullProcessImageNameA = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameA"); + pQueryFullProcessImageNameW = (void *) GetProcAddress(hkernel32, "QueryFullProcessImageNameW"); return 1; } @@ -239,7 +264,7 @@ static void doChild(const char* file, const char* option) siA.dwX, siA.dwY, siA.dwXSize, siA.dwYSize, siA.dwXCountChars, siA.dwYCountChars, siA.dwFillAttribute, siA.dwFlags, siA.wShowWindow, - (DWORD)siA.hStdInput, (DWORD)siA.hStdOutput, (DWORD)siA.hStdError); + (DWORD_PTR)siA.hStdInput, (DWORD_PTR)siA.hStdOutput, (DWORD_PTR)siA.hStdError); /* since GetStartupInfoW is only implemented in win2k, * zero out before calling so we can notice the difference @@ -256,7 +281,7 @@ static void doChild(const char* file, const char* option) siW.dwX, siW.dwY, siW.dwXSize, siW.dwYSize, siW.dwXCountChars, siW.dwYCountChars, siW.dwFillAttribute, siW.dwFlags, siW.wShowWindow, - (DWORD)siW.hStdInput, (DWORD)siW.hStdOutput, (DWORD)siW.hStdError); + (DWORD_PTR)siW.hStdInput, (DWORD_PTR)siW.hStdOutput, (DWORD_PTR)siW.hStdError); /* Arguments */ childPrintf(hFile, "[Arguments]\nargcA=%d\n", myARGC); @@ -348,8 +373,18 @@ static void doChild(const char* file, const char* option) childPrintf(hFile, "OutputMode=%ld\n", modeOut); /* now that we have written all relevant information, let's change it */ - ok(SetConsoleCP(1252), "Setting CP\n"); + SetLastError(0xdeadbeef); + ret = SetConsoleCP(1252); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Setting the codepage is not implemented\n"); + } + else + { + ok(ret, "Setting CP\n"); ok(SetConsoleOutputCP(1252), "Setting SB CP\n"); + } + ret = SetConsoleMode(hConIn, modeIn ^ 1); ok( ret, "Setting mode (%d)\n", GetLastError()); ret = SetConsoleMode(hConOut, modeOut ^ 1); @@ -397,6 +432,18 @@ static char* getChildString(const char* sect, const char* key) return ret; } +static WCHAR* getChildStringW(const char* sect, const char* key) +{ + char buf[1024+4*MAX_LISTED_ENV_VAR]; + WCHAR* ret; + + GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile); + if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL; + assert(!(strlen(buf) & 1)); + ret = decodeW(buf); + return ret; +} + /* FIXME: this may be moved to the wtmain.c file, because it may be needed by * others... (windows uses stricmp while Un*x uses strcasecmp...) */ @@ -432,8 +479,35 @@ static void ok_child_string( int line, const char *sect, const char *key, sect, key, expect ? expect : "(null)", result ); } +static void ok_child_stringWA( int line, const char *sect, const char *key, + const char *expect, int sensitive ) +{ + WCHAR* expectW; + CHAR* resultA; + DWORD len; + WCHAR* result = getChildStringW( sect, key ); + + len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0); + expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len); + + len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL); + resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR)); + WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL); + + if (sensitive) + ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n", + sect, key, expect ? expect : "(null)", resultA ); + else + ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n", + sect, key, expect ? expect : "(null)", resultA ); + HeapFree(GetProcessHeap(),0,expectW); + HeapFree(GetProcessHeap(),0,resultA); +} + #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 ) #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 ) +#define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 ) /* using !expect ensures that the test will fail if the sect/key isn't present * in result file @@ -441,7 +515,7 @@ static void ok_child_string( int line, const char *sect, const char *key, #define okChildInt(sect, key, expect) \ do { \ UINT result = GetPrivateProfileIntA((sect), (key), !(expect), resfile); \ - ok(result == expect, "%s:%s expected %d, but got %d\n", (sect), (key), (int)(expect), result); \ + ok(result == expect, "%s:%s expected %u, but got %u\n", (sect), (key), (UINT)(expect), result); \ } while (0) static void test_Startup(void) @@ -450,7 +524,7 @@ static void test_Startup(void) PROCESS_INFORMATION info; STARTUPINFOA startup,si; static CHAR title[] = "I'm the title string", - desktop[] = "I'm the desktop string", + desktop[] = "winsta0\\default", empty[] = ""; /* let's start simplistic */ @@ -470,8 +544,6 @@ static void test_Startup(void) GetStartupInfoA(&si); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", si.lpDesktop); - ok (si.lpTitle == NULL || !strncmp(si.lpTitle, selfname, strlen(selfname)), - "StartupInfoA:lpTitle expected something starting with '%s' or null, got '%s'\n", selfname, si.lpTitle); okChildInt("StartupInfoA", "dwX", startup.dwX); okChildInt("StartupInfoA", "dwY", startup.dwY); okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); @@ -719,6 +791,7 @@ static void test_Startup(void) static void test_CommandLine(void) { char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p; + char buffer2[MAX_PATH]; PROCESS_INFORMATION info; STARTUPINFOA startup; DWORD len; @@ -804,9 +877,9 @@ static void test_CommandLine(void) assert ( lpFilePart != 0); *(lpFilePart -1 ) = 0; p = strrchr(fullpath, '\\'); - assert (p); /* Use exename to avoid buffer containing things like 'C:' */ - sprintf(buffer, "..%s/%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", p, exename, resfile); + if (p) sprintf(buffer, "..%s/%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", p, exename, resfile); + else sprintf(buffer, "./%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", exename, resfile); SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); @@ -814,11 +887,102 @@ static void test_CommandLine(void) ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); /* child process has changed result file, so let profile functions know about it */ WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - sprintf(buffer, "..%s/%s", p, exename); + if (p) sprintf(buffer, "..%s/%s", p, exename); + else sprintf(buffer, "./%s", exename); okChildString("Arguments", "argvA0", buffer); release_memory(); assert(DeleteFileA(resfile) != 0); + /* Using AppName */ + get_file_name(resfile); + len = GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart); + assert ( lpFilePart != 0); + *(lpFilePart -1 ) = 0; + p = strrchr(fullpath, '\\'); + /* Use exename to avoid buffer containing things like 'C:' */ + if (p) sprintf(buffer, "..%s/%s", p, exename); + else sprintf(buffer, "./%s", exename); + sprintf(buffer2, "dummy tests/process.c %s \"a\\\"b\\\\\" c\\\" d", resfile); + SetLastError(0xdeadbeef); + ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); + /* wait for child to terminate */ + ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + /* child process has changed result file, so let profile functions know about it */ + WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + sprintf(buffer, "tests/process.c %s", resfile); + okChildString("Arguments", "argvA0", "dummy"); + okChildString("Arguments", "CommandLineA", buffer2); + okChildStringWA("Arguments", "CommandLineW", buffer2); + release_memory(); + assert(DeleteFileA(resfile) != 0); + + if (0) /* Test crashes on NT-based Windows. */ + { + /* Test NULL application name and command line parameters. */ + SetLastError(0xdeadbeef); + ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(!ret, "CreateProcessA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); +} + + buffer[0] = '\0'; + + /* Test empty application name parameter. */ + SetLastError(0xdeadbeef); + ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(!ret, "CreateProcessA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_PATH_NOT_FOUND || + broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ || + broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */, + "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); + + buffer2[0] = '\0'; + + /* Test empty application name and command line parameters. */ + SetLastError(0xdeadbeef); + ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(!ret, "CreateProcessA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_PATH_NOT_FOUND || + broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ || + broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */, + "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError()); + + /* Test empty command line parameter. */ + SetLastError(0xdeadbeef); + ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(!ret, "CreateProcessA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ || + GetLastError() == ERROR_BAD_PATHNAME /* Win98 */ || + GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */, + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + strcpy(buffer, "doesnotexist.exe"); + strcpy(buffer2, "does not exist.exe"); + + /* Test nonexistent application name. */ + SetLastError(0xdeadbeef); + ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(!ret, "CreateProcessA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(!ret, "CreateProcessA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + /* Test nonexistent command line parameter. */ + SetLastError(0xdeadbeef); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(!ret, "CreateProcessA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(!ret, "CreateProcessA unexpectedly succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); } static void test_Directory(void) @@ -1061,6 +1225,7 @@ static void test_SuspendFlag(void) static void test_DebuggingFlag(void) { char buffer[MAX_PATH]; + void *processbase = NULL; PROCESS_INFORMATION info; STARTUPINFOA startup, us; DEBUG_EVENT de; @@ -1081,7 +1246,15 @@ static void test_DebuggingFlag(void) { ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); + if (!dbg) + { + ok(de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT, + "first event: %d\n", de.dwDebugEventCode); + processbase = de.u.CreateProcessInfo.lpBaseOfImage; + } if (de.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) dbg++; + ok(de.dwDebugEventCode != LOAD_DLL_DEBUG_EVENT || + de.u.LoadDll.lpBaseOfDll != processbase, "got LOAD_DLL for main module\n"); } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT); ok(dbg, "I have seen a debug event\n"); @@ -1127,6 +1300,7 @@ static void test_Console(void) HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut; const char* msg = "This is a std-handle inheritance test."; unsigned msg_len; + BOOL run_tests = TRUE; memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); @@ -1182,13 +1356,18 @@ static void test_Console(void) /* Try to set invalid CP */ SetLastError(0xdeadbeef); ok(!SetConsoleCP(0), "Shouldn't succeed\n"); - ok(GetLastError()==ERROR_INVALID_PARAMETER, + ok(GetLastError()==ERROR_INVALID_PARAMETER || + broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ "GetLastError: expecting %u got %u\n", ERROR_INVALID_PARAMETER, GetLastError()); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + run_tests = FALSE; + SetLastError(0xdeadbeef); ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n"); - ok(GetLastError()==ERROR_INVALID_PARAMETER, + ok(GetLastError()==ERROR_INVALID_PARAMETER || + broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ "GetLastError: expecting %u got %u\n", ERROR_INVALID_PARAMETER, GetLastError()); @@ -1212,9 +1391,9 @@ static void test_Console(void) okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow); /* check child correctly inherited the console */ - okChildInt("StartupInfoA", "hStdInput", (DWORD)startup.hStdInput); - okChildInt("StartupInfoA", "hStdOutput", (DWORD)startup.hStdOutput); - okChildInt("StartupInfoA", "hStdError", (DWORD)startup.hStdError); + okChildInt("StartupInfoA", "hStdInput", (DWORD_PTR)startup.hStdInput); + okChildInt("StartupInfoA", "hStdOutput", (DWORD_PTR)startup.hStdOutput); + okChildInt("StartupInfoA", "hStdError", (DWORD_PTR)startup.hStdError); okChildInt("Console", "SizeX", (DWORD)sbi.dwSize.X); okChildInt("Console", "SizeY", (DWORD)sbi.dwSize.Y); okChildInt("Console", "CursorX", (DWORD)sbi.dwCursorPosition.X); @@ -1231,8 +1410,14 @@ static void test_Console(void) okChildInt("Console", "InputMode", modeIn); okChildInt("Console", "OutputMode", modeOut); + if (run_tests) + { ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn); ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut); + } + else + win_skip("Setting the codepage is not implemented\n"); + ok(modeInC == (modeIn ^ 1), "Wrong console mode\n"); ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n"); trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X); @@ -1323,7 +1508,7 @@ static void test_OpenProcess(void) /* not exported in all windows versions */ if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) { - skip("VirtualAllocEx not found\n"); + win_skip("VirtualAllocEx not found\n"); return; } @@ -1337,7 +1522,7 @@ static void test_OpenProcess(void) if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { /* Win9x */ CloseHandle(hproc); - skip("VirtualAllocEx not implemented\n"); + win_skip("VirtualAllocEx not implemented\n"); return; } ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError()); @@ -1399,6 +1584,190 @@ static void test_OpenProcess(void) ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); } +static void test_GetProcessVersion(void) +{ + static char cmdline[] = "winver.exe"; + PROCESS_INFORMATION pi; + STARTUPINFOA si; + DWORD ret; + + SetLastError(0xdeadbeef); + ret = GetProcessVersion(0); + ok(ret, "GetProcessVersion error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = GetProcessVersion(GetCurrentProcessId()); + ok(ret, "GetProcessVersion error %u\n", GetLastError()); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + SetLastError(0xdeadbeef); + ok(ret, "CreateProcess error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = GetProcessVersion(pi.dwProcessId); + ok(ret, "GetProcessVersion error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = TerminateProcess(pi.hProcess, 0); + ok(ret, "TerminateProcess error %u\n", GetLastError()); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} + +static void test_ProcessNameA(void) +{ +#define INIT_STR "Just some words" + DWORD length, size; + CHAR buf[1024]; + + if (!pQueryFullProcessImageNameA) + { + win_skip("QueryFullProcessImageNameA unavailable (added in Windows Vista)\n"); + return; + } + /* get the buffer length without \0 terminator */ + length = 1024; + expect_eq_d(TRUE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &length)); + expect_eq_d(length, lstrlenA(buf)); + + /* when the buffer is too small + * - function fail with error ERROR_INSUFFICIENT_BUFFER + * - the size variable is not modified + * tested with the biggest too small size + */ + size = length; + sprintf(buf,INIT_STR); + expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size)); + expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); + expect_eq_d(length, size); + expect_eq_s(INIT_STR, buf); + + /* retest with smaller buffer size + */ + size = 4; + sprintf(buf,INIT_STR); + expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, buf, &size)); + expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); + expect_eq_d(4, size); + expect_eq_s(INIT_STR, buf); + + /* this is a difference between the ascii and the unicode version + * the unicode version crashes when the size is big enough to hold the result + * ascii version throughs an error + */ + size = 1024; + expect_eq_d(FALSE, pQueryFullProcessImageNameA(GetCurrentProcess(), 0, NULL, &size)); + expect_eq_d(1024, size); + expect_eq_d(ERROR_INVALID_PARAMETER, GetLastError()); +} + +static void test_ProcessName(void) +{ + HANDLE hSelf; + WCHAR module_name[1024]; + WCHAR deviceW[] = {'\\','D', 'e','v','i','c','e',0}; + WCHAR buf[1024]; + DWORD size; + + if (!pQueryFullProcessImageNameW) + { + win_skip("QueryFullProcessImageNameW unavailable (added in Windows Vista)\n"); + return; + } + + ok(GetModuleFileNameW(NULL, module_name, 1024), "GetModuleFileNameW(NULL, ...) failed\n"); + + /* GetCurrentProcess pseudo-handle */ + size = sizeof(buf) / sizeof(buf[0]); + expect_eq_d(TRUE, pQueryFullProcessImageNameW(GetCurrentProcess(), 0, buf, &size)); + expect_eq_d(lstrlenW(buf), size); + expect_eq_ws_i(buf, module_name); + + hSelf = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); + /* Real handle */ + size = sizeof(buf) / sizeof(buf[0]); + expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); + expect_eq_d(lstrlenW(buf), size); + expect_eq_ws_i(buf, module_name); + + /* Buffer too small */ + size = lstrlenW(module_name)/2; + lstrcpyW(buf, deviceW); + SetLastError(0xdeadbeef); + expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); + expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */ + expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); + expect_eq_ws_i(deviceW, buf); /* buffer not changed */ + + /* Too small - not space for NUL terminator */ + size = lstrlenW(module_name); + SetLastError(0xdeadbeef); + expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); + expect_eq_d(lstrlenW(module_name), size); /* size not changed(!) */ + expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); + + /* NULL buffer */ + size = 0; + expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, NULL, &size)); + expect_eq_d(0, size); + expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); + + /* native path */ + size = sizeof(buf) / sizeof(buf[0]); + expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, PROCESS_NAME_NATIVE, buf, &size)); + expect_eq_d(lstrlenW(buf), size); + ok(buf[0] == '\\', "NT path should begin with '\\'\n"); + todo_wine ok(memcmp(buf, deviceW, sizeof(WCHAR)*lstrlenW(deviceW)) == 0, "NT path should begin with \\Device\n"); + + /* Buffer too small */ + size = lstrlenW(module_name)/2; + SetLastError(0xdeadbeef); + lstrcpyW(buf, module_name); + expect_eq_d(FALSE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size)); + expect_eq_d(lstrlenW(module_name)/2, size); /* size not changed(!) */ + expect_eq_d(ERROR_INSUFFICIENT_BUFFER, GetLastError()); + expect_eq_ws_i(module_name, buf); /* buffer not changed */ + + CloseHandle(hSelf); +} + +static void test_Handles(void) +{ + HANDLE handle = GetCurrentProcess(); + BOOL ret; + DWORD code; + + ok( handle == (HANDLE)~(ULONG_PTR)0 || + handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */, + "invalid current process handle %p\n", handle ); + ret = GetExitCodeProcess( handle, &code ); + ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() ); +#ifdef _WIN64 + /* truncated handle */ + SetLastError( 0xdeadbeef ); + handle = (HANDLE)((ULONG_PTR)handle & ~0u); + ret = GetExitCodeProcess( handle, &code ); + ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); + /* sign-extended handle */ + SetLastError( 0xdeadbeef ); + handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle); + ret = GetExitCodeProcess( handle, &code ); + ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() ); + /* invalid high-word */ + SetLastError( 0xdeadbeef ); + handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32)); + ret = GetExitCodeProcess( handle, &code ); + ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); +#endif +} + START_TEST(process) { int b = init(); @@ -1419,6 +1788,10 @@ START_TEST(process) test_Console(); test_ExitCode(); test_OpenProcess(); + test_GetProcessVersion(); + test_ProcessNameA(); + test_ProcessName(); + test_Handles(); /* things that can be tested: * lookup: check the way program to be executed is searched * handles: check the handle inheritance stuff (+sec options) diff --git a/rostests/winetests/kernel32/profile.c b/rostests/winetests/kernel32/profile.c index 8611c114594..232027067f7 100755 --- a/rostests/winetests/kernel32/profile.c +++ b/rostests/winetests/kernel32/profile.c @@ -19,6 +19,7 @@ */ #include +#include #include "wine/test.h" #include "windef.h" @@ -91,14 +92,23 @@ static void test_profile_int(void) static void test_profile_string(void) { + static WCHAR emptyW[] = { 0 }; + static WCHAR keyW[] = { 'k','e','y',0 }; + static WCHAR sW[] = { 's',0 }; + static WCHAR TESTFILE2W[] = {'.','\\','t','e','s','t','w','i','n','e','2','.','i','n','i',0}; + static WCHAR valsectionW[] = {'v','a','l','_','e','_','s','e','c','t','i','o','n',0 }; + static WCHAR valnokeyW[] = {'v','a','l','_','n','o','_','k','e','y',0}; HANDLE h; int ret; DWORD count; char buf[100]; + WCHAR bufW[100]; char *p; /* test that lines without an '=' will not be enumerated */ /* in the case below, name2 is a key while name3 is not. */ char content[]="[s]\r\nname1=val1\r\nname2=\r\nname3\r\nname4=val4\r\n"; + char content2[]="\r\nkey=val_no_section\r\n[]\r\nkey=val_e_section\r\n" + "[s]\r\n=val_no_key\r\n[t]\r\n"; DeleteFileA( TESTFILE2); h = CreateFileA( TESTFILE2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); @@ -125,6 +135,27 @@ static void test_profile_string(void) ok( ret == 24 && !strcmp( buf, "name1,name2,name4,name5"), "wrong keys returned(%d): %s\n", ret, buf); + h = CreateFileA( TESTFILE2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", TESTFILE2); + if( h == INVALID_HANDLE_VALUE) return; + WriteFile( h, content2, sizeof(content2), &count, NULL); + CloseHandle( h); + + /* works only in unicode, ascii crashes */ + ret=GetPrivateProfileStringW(emptyW, keyW, emptyW, bufW, + sizeof(bufW)/sizeof(bufW[0]), TESTFILE2W); + todo_wine + ok(!lstrcmpW(valsectionW,bufW), "expected %s, got %s\n", + wine_dbgstr_w(valsectionW), wine_dbgstr_w(bufW) ); + + /* works only in unicode, ascii crashes */ + ret=GetPrivateProfileStringW(sW, emptyW, emptyW, bufW, + sizeof(bufW)/sizeof(bufW[0]), TESTFILE2W); + todo_wine + ok(!lstrcmpW(valnokeyW,bufW), "expected %s, got %s\n", + wine_dbgstr_w(valnokeyW), wine_dbgstr_w(bufW) ); + DeleteFileA( TESTFILE2); } @@ -173,22 +204,45 @@ static void test_profile_sections(void) SetLastError(0xdeadbeef); ret = GetPrivateProfileSectionA( NULL, buf, sizeof(buf), testfile4 ); ok( ret == 0, "expected return size 0, got %d\n", ret ); - ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_INVALID_PARAMETER || + broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); SetLastError(0xdeadbeef); ret = GetPrivateProfileSectionA( "section1", buf, sizeof(buf), NULL ); ok( ret == 0, "expected return size 0, got %d\n", ret ); todo_wine - ok( GetLastError() == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || + broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ + "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); - /* And a real one */ + /* Existing empty section with no keys */ + SetLastError(0xdeadbeef); + ret=GetPrivateProfileSectionA("section2", buf, sizeof(buf), testfile4); + ok( ret == 0, "expected return size 0, got %d\n", ret ); + ok( GetLastError() == ERROR_SUCCESS || + broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ + "expected ERROR_SUCCESS, got %d\n", GetLastError()); + + /* Existing section with keys and values*/ + SetLastError(0xdeadbeef); ret=GetPrivateProfileSectionA("section1", buf, sizeof(buf), testfile4); for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1) p[-1] = ','; ok( ret == 35 && !strcmp( buf, "name1=val1,name2=,name3,name4=val4"), "wrong section returned(%d): %s\n", ret, buf); ok( buf[ret-1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" ); - ok( GetLastError() == S_OK, "expected S_OK, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_SUCCESS || + broken(GetLastError() == 0xdeadbeef), /* Win9x, WinME */ + "expected ERROR_SUCCESS, got %d\n", GetLastError()); + + /* Overflow*/ + ret=GetPrivateProfileSectionA("section1", buf, 24, testfile4); + for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1) + p[-1] = ','; + ok( ret == 22 && !strcmp( buf, "name1=val1,name2=,name"), "wrong section returned(%d): %s\n", + ret, buf); + ok( buf[ret] == 0 && buf[ret+1] == 0, "returned buffer not terminated with double-null\n" ); DeleteFileA( testfile4 ); } @@ -213,33 +267,54 @@ static void test_profile_sections_names(void) CloseHandle( h); /* Test with sufficiently large buffer */ + memset(buf, 0xc, sizeof(buf)); ret = GetPrivateProfileSectionNamesA( buf, 29, testfile3 ); - ok( ret == 27, "expected return size 27, got %d\n", ret ); - ok( buf[ret-1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" ); + ok( ret == 27 || + broken(ret == 28), /* Win9x, WinME */ + "expected return size 27, got %d\n", ret ); + ok( (buf[ret-1] == 0 && buf[ret] == 0) || + broken(buf[ret-1] == 0 && buf[ret-2] == 0), /* Win9x, WinME */ + "returned buffer not terminated with double-null\n" ); /* Test with exactly fitting buffer */ + memset(buf, 0xc, sizeof(buf)); ret = GetPrivateProfileSectionNamesA( buf, 28, testfile3 ); - ok( ret == 26, "expected return size 26, got %d\n", ret ); - ok( buf[ret+1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" ); + ok( ret == 26 || + broken(ret == 28), /* Win9x, WinME */ + "expected return size 26, got %d\n", ret ); + todo_wine + ok( (buf[ret+1] == 0 && buf[ret] == 0) || /* W2K3 and higher */ + broken(buf[ret+1] == 0xc && buf[ret] == 0) || /* NT4, W2K, WinXP */ + broken(buf[ret-1] == 0 && buf[ret-2] == 0), /* Win9x, WinME */ + "returned buffer not terminated with double-null\n" ); /* Test with a buffer too small */ + memset(buf, 0xc, sizeof(buf)); ret = GetPrivateProfileSectionNamesA( buf, 27, testfile3 ); ok( ret == 25, "expected return size 25, got %d\n", ret ); - ok( buf[ret+1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" ); + /* Win9x and WinME only fills the buffer with complete section names (double-null terminated) */ + count = strlen("section1") + sizeof(CHAR) + strlen("section2"); + todo_wine + ok( (buf[ret+1] == 0 && buf[ret] == 0) || + broken(buf[count] == 0 && buf[count+1] == 0), /* Win9x, WinME */ + "returned buffer not terminated with double-null\n" ); /* Tests on nonexistent file */ - memset(buf, 0xcc, sizeof(buf)); + memset(buf, 0xc, sizeof(buf)); ret = GetPrivateProfileSectionNamesA( buf, 10, ".\\not_here.ini" ); - ok( ret == 0, "expected return size 0, got %d\n", ret ); + ok( ret == 0 || + broken(ret == 1), /* Win9x, WinME */ + "expected return size 0, got %d\n", ret ); ok( buf[0] == 0, "returned buffer not terminated with null\n" ); ok( buf[1] != 0, "returned buffer terminated with double-null\n" ); /* Test with sufficiently large buffer */ SetLastError(0xdeadbeef); + memset(bufW, 0xcc, sizeof(bufW)); ret = GetPrivateProfileSectionNamesW( bufW, 29, testfile3W ); if (ret == 0 && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("GetPrivateProfileSectionNamesW is not implemented\n"); + win_skip("GetPrivateProfileSectionNamesW is not implemented\n"); DeleteFileA( testfile3 ); return; } @@ -247,11 +322,15 @@ static void test_profile_sections_names(void) ok( bufW[ret-1] == 0 && bufW[ret] == 0, "returned buffer not terminated with double-null\n" ); /* Test with exactly fitting buffer */ + memset(bufW, 0xcc, sizeof(bufW)); ret = GetPrivateProfileSectionNamesW( bufW, 28, testfile3W ); ok( ret == 26, "expected return size 26, got %d\n", ret ); - ok( bufW[ret+1] == 0 && bufW[ret] == 0, "returned buffer not terminated with double-null\n" ); + ok( (bufW[ret+1] == 0 && bufW[ret] == 0) || /* W2K3 and higher */ + broken(bufW[ret+1] == 0xcccc && bufW[ret] == 0), /* NT4, W2K, WinXP */ + "returned buffer not terminated with double-null\n" ); /* Test with a buffer too small */ + memset(bufW, 0xcc, sizeof(bufW)); ret = GetPrivateProfileSectionNamesW( bufW, 27, testfile3W ); ok( ret == 25, "expected return size 25, got %d\n", ret ); ok( bufW[ret+1] == 0 && bufW[ret] == 0, "returned buffer not terminated with double-null\n" ); @@ -266,10 +345,793 @@ static void test_profile_sections_names(void) ok( bufW[1] != 0, "returned buffer terminated with double-null\n" ); } +/* If the ini-file has already been opened with CreateFile, WritePrivateProfileString failed in wine with an error ERROR_SHARING_VIOLATION, some testing here */ +static void test_profile_existing(void) +{ + static const char *testfile1 = ".\\winesharing1.ini"; + static const char *testfile2 = ".\\winesharing2.ini"; + + static const struct { + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD write_error; + BOOL read_error; + DWORD broken_error; + } pe[] = { + {GENERIC_READ, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, + {GENERIC_READ, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, + {GENERIC_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, + {GENERIC_WRITE, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, + {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, + {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, + {GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */}, + {GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */}, + /*Thief demo (bug 5024) opens .ini file like this*/ + {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */} + }; + + int i; + BOOL ret; + DWORD size; + HANDLE h = 0; + char buffer[MAX_PATH]; + + for (i=0; i < sizeof(pe)/sizeof(pe[0]); i++) + { + h = CreateFile(testfile1, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(INVALID_HANDLE_VALUE != h, "%d: CreateFile failed\n",i); + SetLastError(0xdeadbeef); + + ret = WritePrivateProfileString(SECTION, KEY, "12345", testfile1); + if (!pe[i].write_error) + { + if (!ret) + ok( broken(GetLastError() == pe[i].broken_error), + "%d: WritePrivateProfileString failed with error %u\n", i, GetLastError() ); + CloseHandle(h); + size = GetPrivateProfileString(SECTION, KEY, 0, buffer, MAX_PATH, testfile1); + if (ret) + ok( size == 5, "%d: test failed, number of characters copied: %d instead of 5\n", i, size ); + else + ok( !size, "%d: test failed, number of characters copied: %d instead of 0\n", i, size ); + } + else + { + DWORD err = GetLastError(); + ok( !ret, "%d: WritePrivateProfileString succeeded\n", i ); + if (!ret) + ok( err == pe[i].write_error, "%d: WritePrivateProfileString failed with error %u/%u\n", + i, err, pe[i].write_error ); + CloseHandle(h); + size = GetPrivateProfileString(SECTION, KEY, 0, buffer, MAX_PATH, testfile1); + ok( !size, "%d: test failed, number of characters copied: %d instead of 0\n", i, size ); + } + + ok( DeleteFile(testfile1), "delete failed\n" ); + } + + h = CreateFile(testfile2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + sprintf( buffer, "[%s]\r\n%s=123\r\n", SECTION, KEY ); + ok( WriteFile( h, buffer, strlen(buffer), &size, NULL ), "failed to write\n" ); + CloseHandle( h ); + + for (i=0; i < sizeof(pe)/sizeof(pe[0]); i++) + { + h = CreateFile(testfile2, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ok(INVALID_HANDLE_VALUE != h, "%d: CreateFile failed\n",i); + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStringA(SECTION, KEY, NULL, buffer, MAX_PATH, testfile2); + /* Win9x and WinME returns 0 for all cases except the first one */ + if (!pe[i].read_error) + ok( ret || + broken(!ret && GetLastError() == 0xdeadbeef), /* Win9x, WinME */ + "%d: GetPrivateProfileString failed with error %u\n", i, GetLastError() ); + else + ok( !ret, "%d: GetPrivateProfileString succeeded\n", i ); + CloseHandle(h); + } + ok( DeleteFile(testfile2), "delete failed\n" ); +} + +static void test_profile_delete_on_close(void) +{ + static CHAR testfile[] = ".\\testwine5.ini"; + HANDLE h; + DWORD size, res; + static const char contents[] = "[" SECTION "]\n" KEY "=123\n"; + + h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok( WriteFile( h, contents, sizeof contents - 1, &size, NULL ), + "Cannot write test file: %x\n", GetLastError() ); + ok( size == sizeof contents - 1, "Test file: partial write\n"); + + SetLastError(0xdeadbeef); + res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); + ok( res == 123 || + broken(res == 0 && GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x, WinME */ + "Got %d instead of 123\n", res); + + /* This also deletes the file */ + CloseHandle(h); +} + +static void test_profile_refresh(void) +{ + static CHAR testfile[] = ".\\winetest4.ini"; + HANDLE h; + DWORD size, res; + static const char contents1[] = "[" SECTION "]\n" KEY "=123\n"; + static const char contents2[] = "[" SECTION "]\n" KEY "=124\n"; + + h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok( WriteFile( h, contents1, sizeof contents1 - 1, &size, NULL ), + "Cannot write test file: %x\n", GetLastError() ); + ok( size == sizeof contents1 - 1, "Test file: partial write\n"); + + SetLastError(0xdeadbeef); + res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); + ok( res == 123 || + broken(res == 0 && GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x, WinME */ + "Got %d instead of 123\n", res); + + CloseHandle(h); + + /* Test proper invalidation of wine's profile file cache */ + + h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok( WriteFile( h, contents2, sizeof contents2 - 1, &size, NULL ), + "Cannot write test file: %x\n", GetLastError() ); + ok( size == sizeof contents2 - 1, "Test file: partial write\n"); + + SetLastError(0xdeadbeef); + res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); + ok( res == 124 || + broken(res == 0 && GetLastError() == 0xdeadbeef), /* Win9x, WinME */ + "Got %d instead of 124\n", res); + + /* This also deletes the file */ + CloseHandle(h); +} + +static void create_test_file(LPCSTR name, LPCSTR data, DWORD size) +{ + HANDLE hfile; + DWORD count; + + hfile = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hfile != INVALID_HANDLE_VALUE, "cannot create %s\n", name); + WriteFile(hfile, data, size, &count, NULL); + CloseHandle(hfile); +} + +static BOOL emptystr_ok(CHAR emptystr[MAX_PATH]) +{ + int i; + + for(i = 0;i < MAX_PATH;++i) + if(emptystr[i] != 0) + { + trace("emptystr[%d] = %d\n",i,emptystr[i]); + return FALSE; + } + + return TRUE; +} + +static void test_GetPrivateProfileString(const char *content, const char *descript) +{ + DWORD ret, len; + CHAR buf[MAX_PATH]; + CHAR def_val[MAX_PATH]; + CHAR path[MAX_PATH]; + CHAR windir[MAX_PATH]; + /* NT series crashes on r/o empty strings, so pass an r/w + empty string and check for modification */ + CHAR emptystr[MAX_PATH] = ""; + LPSTR tempfile; + + static const char filename[] = ".\\winetest.ini"; + + trace("test_GetPrivateProfileStringA: %s\n", descript); + + if(!lstrcmpA(descript, "CR only")) + { + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStringW(NULL, NULL, NULL, + NULL, 0, NULL); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Win9x and WinME don't handle 'CR only' correctly\n"); + return; + } + } + + create_test_file(filename, content, lstrlenA(content)); + + /* Run this test series with caching. Wine won't cache profile + files younger than 2.1 seconds. */ + Sleep(2500); + + /* lpAppName is NULL */ + memset(buf, 0xc, sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(NULL, "name1", "default", + buf, MAX_PATH, filename); + ok(ret == 18 || + broken(ret == 19), /* Win9x and WinME */ + "Expected 18, got %d\n", ret); + len = lstrlenA("section1") + sizeof(CHAR) + lstrlenA("section2") + 2 * sizeof(CHAR); + ok(!memcmp(buf, "section1\0section2\0\0", len), + "Expected \"section1\\0section2\\0\\0\", got \"%s\"\n", buf); + + /* lpAppName is empty */ + memset(buf, 0xc, sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(emptystr, "name1", "default", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is missing */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("notasection", "name1", "default", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* lpAppName is empty, lpDefault is NULL */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(emptystr, "name1", NULL, + buf, MAX_PATH, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, "") || + broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ + "Expected \"\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is empty, lpDefault is empty */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(emptystr, "name1", "", + buf, MAX_PATH, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is empty, lpDefault has trailing blank characters */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ + lstrcpyA(def_val, "default "); + ret = GetPrivateProfileStringA(emptystr, "name1", def_val, + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is empty, many blank characters in lpDefault */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ + lstrcpyA(def_val, "one two "); + ret = GetPrivateProfileStringA(emptystr, "name1", def_val, + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is empty, blank character but not trailing in lpDefault */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(emptystr, "name1", "one two", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpKeyName is NULL */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", NULL, "default", + buf, MAX_PATH, filename); + ok(ret == 18, "Expected 18, got %d\n", ret); + ok(!memcmp(buf, "name1\0name2\0name4\0", ret + 1), + "Expected \"name1\\0name2\\0name4\\0\", got \"%s\"\n", buf); + + /* lpKeyName is empty */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", emptystr, "default", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "KeyName modified\n"); + + /* lpKeyName is missing */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "notakey", "default", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* lpKeyName is empty, lpDefault is NULL */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", emptystr, NULL, + buf, MAX_PATH, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, "") || + broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ + "Expected \"\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "KeyName modified\n"); + + /* lpKeyName is empty, lpDefault is empty */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", emptystr, "", + buf, MAX_PATH, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "KeyName modified\n"); + + /* lpKeyName is empty, lpDefault has trailing blank characters */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ + lstrcpyA(def_val, "default "); + ret = GetPrivateProfileStringA("section1", emptystr, def_val, + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "KeyName modified\n"); + + if (0) /* crashes */ + { + /* lpReturnedString is NULL */ + ret = GetPrivateProfileStringA("section1", "name1", "default", + NULL, MAX_PATH, filename); + } + + /* lpFileName is NULL */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, MAX_PATH, NULL); + ok(ret == 7 || + broken(ret == 0), /* Win9x, WinME */ + "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default") || + broken(!lstrcmpA(buf, "kumquat")), /* Win9x, WinME */ + "Expected \"default\", got \"%s\"\n", buf); + + /* lpFileName is empty */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, MAX_PATH, ""); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* lpFileName is nonexistent */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, MAX_PATH, "nonexistent"); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* nSize is 0 */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, 0, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, "kumquat"), "Expected buf to be unchanged, got \"%s\"\n", buf); + + /* nSize is exact size of output */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, 4, filename); + ok(ret == 3, "Expected 3, got %d\n", ret); + ok(!lstrcmpA(buf, "val"), "Expected \"val\", got \"%s\"\n", buf); + + /* nSize has room for NULL terminator */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, 5, filename); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); + + /* output is 1 character */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name4", "default", + buf, MAX_PATH, filename); + ok(ret == 1, "Expected 1, got %d\n", ret); + ok(!lstrcmpA(buf, "a"), "Expected \"a\", got \"%s\"\n", buf); + + /* output is 1 character, no room for NULL terminator */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name4", "default", + buf, 1, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + + /* lpAppName is NULL, not enough room for final section name */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(NULL, "name1", "default", + buf, 16, filename); + ok(ret == 14, "Expected 14, got %d\n", ret); + len = lstrlenA("section1") + 2 * sizeof(CHAR); + todo_wine + ok(!memcmp(buf, "section1\0secti\0\0", ret + 2) || + broken(!memcmp(buf, "section1\0\0", len)), /* Win9x, WinME */ + "Expected \"section1\\0secti\\0\\0\", got \"%s\"\n", buf); + + /* lpKeyName is NULL, not enough room for final key name */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", NULL, "default", + buf, 16, filename); + ok(ret == 14, "Expected 14, got %d\n", ret); + todo_wine + ok(!memcmp(buf, "name1\0name2\0na\0\0", ret + 2) || + broken(!memcmp(buf, "name1\0name2\0n\0\0", ret + 1)), /* Win9x, WinME */ + "Expected \"name1\\0name2\\0na\\0\\0\", got \"%s\"\n", buf); + + /* key value has quotation marks which are stripped */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name2", "default", + buf, MAX_PATH, filename); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val2"), "Expected \"val2\", got \"%s\"\n", buf); + + /* case does not match */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "NaMe1", "default", + buf, MAX_PATH, filename); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); + + /* only filename is used */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "NaMe1", "default", + buf, MAX_PATH, "winetest.ini"); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + GetWindowsDirectoryA(windir, MAX_PATH); + SetLastError(0xdeadbeef); + ret = GetTempFileNameA(windir, "pre", 0, path); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + skip("Not allowed to create a file in the Windows directory\n"); + DeleteFileA(filename); + return; + } + tempfile = strrchr(path, '\\') + 1; + create_test_file(path, content, lstrlenA(content)); + + /* only filename is used, file exists in windows directory */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "NaMe1", "default", + buf, MAX_PATH, tempfile); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); + + /* successful case */ + memset(buf, 0xc,sizeof(buf)); + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, MAX_PATH, filename); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); + + /* Existing section with no keys in an existing file */ + memset(buf, 0xc,sizeof(buf)); + SetLastError(0xdeadbeef); + ret=GetPrivateProfileStringA("section2", "DoesntExist", "", + buf, MAX_PATH, filename); + ok( ret == 0, "expected return size 0, got %d\n", ret ); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + todo_wine + ok( GetLastError() == 0xdeadbeef || + GetLastError() == ERROR_FILE_NOT_FOUND /* Win 7 */, + "expected 0xdeadbeef or ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + + DeleteFileA(path); + DeleteFileA(filename); +} + +static BOOL check_binary_file_data(LPCSTR path, const VOID *data, DWORD size) +{ + HANDLE file; + CHAR buf[MAX_PATH]; + BOOL ret; + + file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (file == INVALID_HANDLE_VALUE) + return FALSE; + + if(size != GetFileSize(file, NULL) ) + { + CloseHandle(file); + return FALSE; + } + + ret = ReadFile(file, buf, size, &size, NULL); + CloseHandle(file); + if (!ret) + return FALSE; + + return !memcmp(buf, data, size); +} + +static BOOL check_file_data(LPCSTR path, LPCSTR data) +{ + return check_binary_file_data(path, data, lstrlenA(data)); +} + +static void test_WritePrivateProfileString(void) +{ + BOOL ret; + LPCSTR data; + CHAR path[MAX_PATH]; + CHAR temp[MAX_PATH]; + + SetLastError(0xdeadbeef); + ret = WritePrivateProfileStringW(NULL, NULL, NULL, NULL); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + /* Win9x/WinME needs (variable) timeouts between tests and even long timeouts don't + * guarantee a correct result. + * Win9x/WinMe also produces different ini files where there is always a newline before + * a section start (except for the first one). + */ + win_skip("WritePrivateProfileString on Win9x/WinME is hard to test reliably\n"); + return; + } + + GetTempPathA(MAX_PATH, temp); + GetTempFileNameA(temp, "wine", 0, path); + DeleteFileA(path); + + /* path is not created yet */ + + /* NULL lpAppName */ + SetLastError(0xdeadbeef); + ret = WritePrivateProfileStringA(NULL, "key", "string", path); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + broken(GetLastError() == ERROR_INVALID_PARAMETER) || /* NT4 */ + broken(GetLastError() == 0xdeadbeef), /* Win9x and WinME */ + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES, + "Expected path to not exist\n"); + + GetTempFileNameA(temp, "wine", 0, path); + + /* NULL lpAppName, path exists */ + data = ""; + SetLastError(0xdeadbeef); + ret = WritePrivateProfileStringA(NULL, "key", "string", path); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + broken(GetLastError() == ERROR_INVALID_PARAMETER) || /* NT4 */ + broken(GetLastError() == 0xdeadbeef), /* Win9x and WinME */ + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(check_file_data(path, data), "File doesn't match\n"); + DeleteFileA(path); + + if (0) + { + /* empty lpAppName, crashes on NT4 and higher */ + data = "[]\r\n" + "key=string\r\n"; + ret = WritePrivateProfileStringA("", "key", "string", path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); + DeleteFileA(path); + } + + /* NULL lpKeyName */ + data = ""; + ret = WritePrivateProfileStringA("App", NULL, "string", path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + todo_wine + { + ok(check_file_data(path, data), "File doesn't match\n"); + } + DeleteFileA(path); + + if (0) + { + /* empty lpKeyName, crashes on NT4 and higher */ + data = "[App]\r\n" + "=string\r\n"; + ret = WritePrivateProfileStringA("App", "", "string", path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + todo_wine + { + ok(check_file_data(path, data), "File doesn't match\n"); + } + DeleteFileA(path); + } + + /* NULL lpString */ + data = ""; + ret = WritePrivateProfileStringA("App", "key", NULL, path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + todo_wine + { + ok(check_file_data(path, data) || + (broken(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES)), /* Win9x and WinME */ + "File doesn't match\n"); + } + DeleteFileA(path); + + /* empty lpString */ + data = "[App]\r\n" + "key=\r\n"; + ret = WritePrivateProfileStringA("App", "key", "", path); + ok(ret == TRUE || + broken(!ret), /* Win9x and WinME */ + "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data) || + (broken(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES)), /* Win9x and WinME */ + "File doesn't match\n"); + DeleteFileA(path); + + /* empty lpFileName */ + SetLastError(0xdeadbeef); + ret = WritePrivateProfileStringA("App", "key", "string", ""); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + ok(GetLastError() == ERROR_ACCESS_DENIED || + broken(GetLastError() == ERROR_PATH_NOT_FOUND), /* Win9x and WinME */ + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* The resulting file will be X:\\%WINDIR%\\win1.tmp */ + GetWindowsDirectoryA(temp, MAX_PATH); + GetTempFileNameA(temp, "win", 1, path); + DeleteFileA(path); + + /* relative path in lpFileName */ + data = "[App]\r\n" + "key=string\r\n"; + ret = WritePrivateProfileStringA("App", "key", "string", "win1.tmp"); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); + DeleteFileA(path); + + GetTempPathA(MAX_PATH, temp); + GetTempFileNameA(temp, "wine", 0, path); + + /* build up an INI file */ + WritePrivateProfileStringA("App1", "key1", "string1", path); + WritePrivateProfileStringA("App1", "key2", "string2", path); + WritePrivateProfileStringA("App1", "key3", "string3", path); + WritePrivateProfileStringA("App2", "key4", "string4", path); + + /* make an addition and verify the INI */ + data = "[App1]\r\n" + "key1=string1\r\n" + "key2=string2\r\n" + "key3=string3\r\n" + "[App2]\r\n" + "key4=string4\r\n" + "[App3]\r\n" + "key5=string5\r\n"; + ret = WritePrivateProfileStringA("App3", "key5", "string5", path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); + + /* lpString is NULL, key2 key is deleted */ + data = "[App1]\r\n" + "key1=string1\r\n" + "key3=string3\r\n" + "[App2]\r\n" + "key4=string4\r\n" + "[App3]\r\n" + "key5=string5\r\n"; + ret = WritePrivateProfileStringA("App1", "key2", NULL, path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); + + /* try to delete key2 again */ + data = "[App1]\r\n" + "key1=string1\r\n" + "key3=string3\r\n" + "[App2]\r\n" + "key4=string4\r\n" + "[App3]\r\n" + "key5=string5\r\n"; + ret = WritePrivateProfileStringA("App1", "key2", NULL, path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); + + /* lpKeyName is NULL, App1 section is deleted */ + data = "[App2]\r\n" + "key4=string4\r\n" + "[App3]\r\n" + "key5=string5\r\n"; + ret = WritePrivateProfileStringA("App1", NULL, "string1", path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); + + /* lpString is not needed to delete a section */ + data = "[App3]\r\n" + "key5=string5\r\n"; + ret = WritePrivateProfileStringA("App2", NULL, NULL, path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); + + /* leave just the section */ + data = "[App3]\r\n"; + ret = WritePrivateProfileStringA("App3", "key5", NULL, path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + ok(check_file_data(path, data), "File doesn't match\n"); + DeleteFileA(path); + + /* NULLs in file before first section. Should be preserved in output */ + data = "Data \0 before \0 first \0 section" /* 31 bytes */ + "\r\n[section1]\r\n" /* 14 bytes */ + "key1=string1\r\n"; /* 14 bytes */ + GetTempFileNameA(temp, "wine", 0, path); + create_test_file(path, data, 31); + ret = WritePrivateProfileStringA("section1", "key1", "string1", path); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + todo_wine + ok( check_binary_file_data(path, data, 59) || + broken( check_binary_file_data(path, /* Windows 9x */ + "Data \0 before \0 first \0 section" /* 31 bytes */ + "\r\n\r\n[section1]\r\n" /* 14 bytes */ + "key1=string1" /* 14 bytes */ + , 59)), "File doesn't match\n"); + DeleteFileA(path); +} + START_TEST(profile) { test_profile_int(); test_profile_string(); test_profile_sections(); test_profile_sections_names(); + test_profile_existing(); + test_profile_delete_on_close(); + test_profile_refresh(); + test_GetPrivateProfileString( + "[section1]\r\n" + "name1=val1\r\n" + "name2=\"val2\"\r\n" + "name3\r\n" + "name4=a\r\n" + "[section2]\r\n", + "CR+LF"); + test_GetPrivateProfileString( + "[section1]\r" + "name1=val1\r" + "name2=\"val2\"\r" + "name3\r" + "name4=a\r" + "[section2]\r", + "CR only"); + test_WritePrivateProfileString(); } diff --git a/rostests/winetests/kernel32/resource.c b/rostests/winetests/kernel32/resource.c index 79d17f13fae..219be582568 100644 --- a/rostests/winetests/kernel32/resource.c +++ b/rostests/winetests/kernel32/resource.c @@ -125,6 +125,8 @@ static void update_empty_exe( void ) CloseHandle( file ); res = BeginUpdateResource( filename, TRUE ); + if ( res != NULL || GetLastError() != ERROR_FILE_INVALID ) + { ok( res != NULL, "BeginUpdateResource failed\n"); /* check if it's possible to open the file now */ @@ -135,6 +137,9 @@ static void update_empty_exe( void ) r = EndUpdateResource( res, FALSE ); ok( r == FALSE, "EndUpdateResource failed\n"); + } + else + skip( "Can't update resource in empty file\n" ); res = BeginUpdateResource( filename, FALSE ); ok( res == NULL, "BeginUpdateResource failed\n"); @@ -173,22 +178,25 @@ static void update_resources_version(void) res = BeginUpdateResource( filename, TRUE ); ok( res != NULL, "BeginUpdateResource failed\n"); + if (0) /* this causes subsequent tests to fail on Vista */ + { r = UpdateResource( res, MAKEINTRESOURCE(0x1230), MAKEINTRESOURCE(0x4567), 0xabcd, NULL, 0 ); ok( r == FALSE, "UpdateResource failed\n"); + } r = UpdateResource( res, MAKEINTRESOURCE(0x1230), MAKEINTRESOURCE(0x4567), 0xabcd, foo, sizeof foo ); - ok( r == TRUE, "UpdateResource failed\n"); + ok( r == TRUE, "UpdateResource failed: %d\n", GetLastError()); r = EndUpdateResource( res, FALSE ); - ok( r, "EndUpdateResource failed\n"); + ok( r, "EndUpdateResource failed: %d\n", GetLastError()); } @@ -249,7 +257,8 @@ static void check_exe( res_check_func fn ) dir = (void*) ((BYTE*) dos + sec[1].VirtualAddress); ok( dir->Characteristics == 0, "Characteristics wrong\n"); - ok( dir->TimeDateStamp == 0, "TimeDateStamp wrong\n"); + ok( dir->TimeDateStamp == 0 || abs( dir->TimeDateStamp - GetTickCount() ) < 1000 /* nt4 */, + "TimeDateStamp wrong %u\n", dir->TimeDateStamp); ok( dir->MajorVersion == 4, "MajorVersion wrong\n"); ok( dir->MinorVersion == 0, "MinorVersion wrong\n"); @@ -306,7 +315,7 @@ START_TEST(resource) if (GLE == ERROR_CALL_NOT_IMPLEMENTED) { - skip("Resource calls are not implemented\n"); + win_skip("Resource calls are not implemented\n"); return; } diff --git a/rostests/winetests/kernel32/sync.c b/rostests/winetests/kernel32/sync.c index b5778fccd99..ea36fc60847 100755 --- a/rostests/winetests/kernel32/sync.c +++ b/rostests/winetests/kernel32/sync.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define _WIN32_WINNT 0x500 #include #include #include @@ -26,6 +27,15 @@ #include "wine/test.h" +static BOOL (WINAPI *pChangeTimerQueueTimer)(HANDLE, HANDLE, ULONG, ULONG); +static HANDLE (WINAPI *pCreateTimerQueue)(void); +static BOOL (WINAPI *pCreateTimerQueueTimer)(PHANDLE, HANDLE, WAITORTIMERCALLBACK, + PVOID, DWORD, DWORD, ULONG); +static HANDLE (WINAPI *pCreateWaitableTimerA)(SECURITY_ATTRIBUTES*,BOOL,LPCSTR); +static BOOL (WINAPI *pDeleteTimerQueueEx)(HANDLE, HANDLE); +static BOOL (WINAPI *pDeleteTimerQueueTimer)(HANDLE, HANDLE, HANDLE); +static HANDLE (WINAPI *pOpenWaitableTimerA)(DWORD,BOOL,LPCSTR); + static void test_signalandwait(void) { DWORD (WINAPI *pSignalObjectAndWait)(HANDLE, HANDLE, DWORD, BOOL); @@ -44,7 +54,7 @@ static void test_signalandwait(void) r = pSignalObjectAndWait(NULL, NULL, 0, 0); if (r == ERROR_INVALID_FUNCTION) { - trace("SignalObjectAndWait not implemented, skipping tests\n"); + win_skip("SignalObjectAndWait is not implemented\n"); return; /* Win98/ME */ } ok( r == WAIT_FAILED, "should fail\n"); @@ -148,7 +158,34 @@ static void test_mutex(void) todo_wine ok(!ret && (GetLastError() == ERROR_NOT_OWNER), "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %d\n", GetLastError()); + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + hOpened = OpenMutex(READ_CONTROL, FALSE, "WINETESTMUTEX"); + ok(!hOpened, "OpenMutex succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win9x */ + "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + hOpened = OpenMutex(READ_CONTROL, FALSE, "winetestmutex"); + ok(!hOpened, "OpenMutex succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win9x */ + "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + hOpened = CreateMutex(NULL, FALSE, "WineTestMutex"); + ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError()); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); CloseHandle(hOpened); + + SetLastError(0xdeadbeef); + hOpened = CreateMutex(NULL, FALSE, "WINETESTMUTEX"); + ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle(hOpened); + CloseHandle(hCreated); } @@ -160,7 +197,7 @@ static void test_slist(void) int value; } item1, item2, item3, *pitem; - SLIST_HEADER slist_header, test_header; + SLIST_HEADER slist_header; PSLIST_ENTRY entry; USHORT size; @@ -183,15 +220,12 @@ static void test_slist(void) pInterlockedPopEntrySList == NULL || pInterlockedPushEntrySList == NULL) { - skip("some required slist entrypoints were not found, skipping tests\n"); + win_skip("some required slist entrypoints were not found, skipping tests\n"); return; } - memset(&test_header, 0, sizeof(test_header)); memset(&slist_header, 0xFF, sizeof(slist_header)); pInitializeSListHead(&slist_header); - ok(memcmp(&test_header, &slist_header, sizeof(SLIST_HEADER)) == 0, - "InitializeSListHead didn't zero-fill list header\n"); size = pQueryDepthSList(&slist_header); ok(size == 0, "initially created slist has size %d, expected 0\n", size); @@ -245,9 +279,9 @@ static void test_slist(void) ok(((struct item*)entry->Next)->value == 1, "item 1 not at the back of list\n"); } -static void test_event_security(void) +static void test_event(void) { - HANDLE handle; + HANDLE handle, handle2; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; ACL acl; @@ -280,6 +314,121 @@ static void test_event_security(void) handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event"); ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError()); CloseHandle(handle); + + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event"); + ok( handle != NULL, "CreateEvent failed with error %u\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event"); + ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": TEST EVENT"); + ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": Test Event"); + ok( handle2 != NULL, "OpenEvent failed with error %d\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": TEST EVENT"); + ok( !handle2, "OpenEvent succeeded\n"); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win9x */ + "wrong error %u\n", GetLastError()); + + CloseHandle( handle ); +} + +static void test_semaphore(void) +{ + HANDLE handle, handle2; + + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + handle = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore"); + ok(handle != NULL, "CreateSemaphore failed with error %u\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore"); + ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": TEST SEMAPHORE"); + ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": Test Semaphore"); + ok( handle2 != NULL, "OpenSemaphore failed with error %d\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": TEST SEMAPHORE"); + ok( !handle2, "OpenSemaphore succeeded\n"); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win9x */ + "wrong error %u\n", GetLastError()); + + CloseHandle( handle ); +} + +static void test_waitable_timer(void) +{ + HANDLE handle, handle2; + + if (!pCreateWaitableTimerA || !pOpenWaitableTimerA) + { + win_skip("{Create,Open}WaitableTimerA() is not available\n"); + return; + } + + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + handle = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer"); + ok(handle != NULL, "CreateWaitableTimer failed with error %u\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer"); + ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": TEST WAITABLETIMER"); + ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": Test WaitableTimer"); + ok( handle2 != NULL, "OpenWaitableTimer failed with error %d\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": TEST WAITABLETIMER"); + ok( !handle2, "OpenWaitableTimer succeeded\n"); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win98 */ + "wrong error %u\n", GetLastError()); + + CloseHandle( handle ); } static HANDLE sem = 0; @@ -289,7 +438,7 @@ static void CALLBACK iocp_callback(DWORD dwErrorCode, DWORD dwNumberOfBytesTrans ReleaseSemaphore(sem, 1, NULL); } -static BOOL WINAPI (*p_BindIoCompletionCallback)( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) = NULL; +static BOOL (WINAPI *p_BindIoCompletionCallback)( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) = NULL; static void test_iocp_callback(void) { @@ -306,7 +455,7 @@ static void test_iocp_callback(void) p_BindIoCompletionCallback = (void*)GetProcAddress(hmod, "BindIoCompletionCallback"); if(!p_BindIoCompletionCallback) { - skip("BindIoCompletionCallback not found in this DLL\n"); + win_skip("BindIoCompletionCallback not found in this DLL\n"); return; } @@ -341,7 +490,7 @@ static void test_iocp_callback(void) ok(retb == TRUE, "BindIoCompletionCallback failed\n"); memset(&overlapped, 0, sizeof(overlapped)); - retb = WriteFile(hFile, (const void *) buffer, 4, &bytesWritten, &overlapped); + retb = WriteFile(hFile, buffer, 4, &bytesWritten, &overlapped); ok(retb == TRUE || GetLastError() == ERROR_IO_PENDING, "WriteFile failed, lastError = %d\n", GetLastError()); ret = WaitForSingleObject(sem, 5000); @@ -360,16 +509,6 @@ static void test_iocp_callback(void) ret = DeleteFileA(filename); ok( ret, "DeleteFileA: error %d\n", GetLastError()); - hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError()); - retb = p_BindIoCompletionCallback(hFile, NULL, 0); - ok(retb == TRUE, "BindIoCompletionCallback failed with a NULL callback(first time set)\n"); - ret = CloseHandle(hFile); - ok( ret, "CloseHandle: error %d\n", GetLastError()); - ret = DeleteFileA(filename); - ok( ret, "DeleteFileA: error %d\n", GetLastError()); - /* win2k3 requires the Flags parameter to be zero */ SetLastError(0xdeadbeef); hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, @@ -388,14 +527,435 @@ static void test_iocp_callback(void) retb = p_BindIoCompletionCallback(NULL, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded on a NULL file\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "Last error is %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE || + GetLastError() == ERROR_INVALID_PARAMETER, /* vista */ + "Last error is %d\n", GetLastError()); +} + +static void CALLBACK timer_queue_cb1(PVOID p, BOOLEAN timedOut) +{ + int *pn = p; + ok(timedOut, "Timer callbacks should always time out\n"); + ++*pn; +} + +struct timer_queue_data1 +{ + int num_calls; + int max_calls; + HANDLE q, t; +}; + +static void CALLBACK timer_queue_cb2(PVOID p, BOOLEAN timedOut) +{ + struct timer_queue_data1 *d = p; + ok(timedOut, "Timer callbacks should always time out\n"); + if (d->t && ++d->num_calls == d->max_calls) + { + BOOL ret; + SetLastError(0xdeadbeef); + /* Note, XP SP2 does *not* do any deadlock checking, so passing + INVALID_HANDLE_VALUE here will just hang. */ + ret = pDeleteTimerQueueTimer(d->q, d->t, NULL); + ok(!ret, "DeleteTimerQueueTimer\n"); + ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n"); + } +} + +static void CALLBACK timer_queue_cb3(PVOID p, BOOLEAN timedOut) +{ + struct timer_queue_data1 *d = p; + ok(timedOut, "Timer callbacks should always time out\n"); + if (d->t && ++d->num_calls == d->max_calls) + { + /* Basically kill the timer since it won't have time to run + again. */ + BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 10000, 0); + ok(ret, "ChangeTimerQueueTimer\n"); + } +} + +static void CALLBACK timer_queue_cb4(PVOID p, BOOLEAN timedOut) +{ + struct timer_queue_data1 *d = p; + ok(timedOut, "Timer callbacks should always time out\n"); + if (d->t) + { + /* This tests whether a timer gets flagged for deletion before + or after the callback runs. If we start this timer with a + period of zero (run once), then ChangeTimerQueueTimer will + fail if the timer is already flagged. Hence we really run + only once. Otherwise we will run multiple times. */ + BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 50, 50); + ok(ret, "ChangeTimerQueueTimer\n"); + ++d->num_calls; + } +} + +static void CALLBACK timer_queue_cb5(PVOID p, BOOLEAN timedOut) +{ + DWORD_PTR delay = (DWORD_PTR) p; + ok(timedOut, "Timer callbacks should always time out\n"); + if (delay) + Sleep(delay); +} + +static void CALLBACK timer_queue_cb6(PVOID p, BOOLEAN timedOut) +{ + struct timer_queue_data1 *d = p; + ok(timedOut, "Timer callbacks should always time out\n"); + /* This tests an original implementation bug where a deleted timer may get + to run, but it is tricky to set up. */ + if (d->q && d->num_calls++ == 0) + { + /* First run: delete ourselves, then insert and remove a timer + that goes in front of us in the sorted timeout list. Once + removed, we will still timeout at the faster timer's due time, + but this should be a no-op if we are bug-free. There should + not be a second run. We can test the value of num_calls later. */ + BOOL ret; + HANDLE t; + + /* The delete will pend while we are in this callback. */ + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(d->q, d->t, NULL); + ok(!ret, "DeleteTimerQueueTimer\n"); + ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n"); + + ret = pCreateTimerQueueTimer(&t, d->q, timer_queue_cb1, NULL, 100, 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t != NULL, "CreateTimerQueueTimer\n"); + + ret = pDeleteTimerQueueTimer(d->q, t, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + /* Now we stay alive by hanging around in the callback. */ + Sleep(500); + } +} + +static void test_timer_queue(void) +{ + HANDLE q, t1, t2, t3, t4, t5; + int n1, n2, n3, n4, n5; + struct timer_queue_data1 d1, d2, d3, d4; + HANDLE e, et1, et2; + BOOL ret; + + if (!pChangeTimerQueueTimer || !pCreateTimerQueue || !pCreateTimerQueueTimer + || !pDeleteTimerQueueEx || !pDeleteTimerQueueTimer) + { + win_skip("TimerQueue API not present\n"); + return; + } + + /* Test asynchronous deletion of the queue. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(q, NULL); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + + /* Test synchronous deletion of the queue and running timers. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + /* Called once. */ + t1 = NULL; + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 0, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + + /* A slow one. */ + t2 = NULL; + n2 = 0; + ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb1, &n2, 0, + 100, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t2 != NULL, "CreateTimerQueueTimer\n"); + + /* A fast one. */ + t3 = NULL; + n3 = 0; + ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb1, &n3, 0, + 10, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t3 != NULL, "CreateTimerQueueTimer\n"); + + /* Start really late (it won't start). */ + t4 = NULL; + n4 = 0; + ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb1, &n4, 10000, + 10, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t4 != NULL, "CreateTimerQueueTimer\n"); + + /* Start soon, but delay so long it won't run again. */ + t5 = NULL; + n5 = 0; + ret = pCreateTimerQueueTimer(&t5, q, timer_queue_cb1, &n5, 0, + 10000, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t5 != NULL, "CreateTimerQueueTimer\n"); + + /* Give them a chance to do some work. */ + Sleep(500); + + /* Test deleting a once-only timer. */ + ret = pDeleteTimerQueueTimer(q, t1, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + /* A periodic timer. */ + ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueEx\n"); + ok(n1 == 1, "Timer callback 1\n"); + ok(n2 < n3, "Timer callback 2 should be much slower than 3\n"); + ok(n4 == 0, "Timer callback 4\n"); + ok(n5 == 1, "Timer callback 5\n"); + + /* Test synchronous deletion of the timer/queue with event trigger. */ + e = CreateEvent(NULL, TRUE, FALSE, NULL); + et1 = CreateEvent(NULL, TRUE, FALSE, NULL); + et2 = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!e || !et1 || !et2) + { + skip("Failed to create timer queue descruction event\n"); + return; + } + + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + /* Run once and finish quickly (should be done when we delete it). */ + t1 = NULL; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb5, NULL, 0, 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + + /* Run once and finish slowly (shouldn't be done when we delete it). */ + t2 = NULL; + ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb5, (PVOID) 1000, 0, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t2 != NULL, "CreateTimerQueueTimer\n"); + + /* Run once and finish quickly (should be done when we delete it). */ + t3 = NULL; + ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb5, NULL, 0, 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t3 != NULL, "CreateTimerQueueTimer\n"); + + /* Run once and finish slowly (shouldn't be done when we delete it). */ + t4 = NULL; + ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb5, (PVOID) 1000, 0, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t4 != NULL, "CreateTimerQueueTimer\n"); + + /* Give them a chance to start. */ + Sleep(400); + + /* DeleteTimerQueueTimer always returns PENDING with a NULL event, + even if the timer is finished. */ + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(q, t1, NULL); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(q, t2, NULL); + ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n"); + ok(GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(q, t3, et1); + ok(ret, "DeleteTimerQueueTimer call was expected to fail\n"); + ok(GetLastError() == 0xdeadbeef, + "DeleteTimerQueueTimer, GetLastError: expected 0xdeadbeef, got %d\n", + GetLastError()); + ok(WaitForSingleObject(et1, 250) == WAIT_OBJECT_0, + "Timer destruction event not triggered\n"); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(q, t4, et2); + ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n"); + ok(GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + ok(WaitForSingleObject(et2, 1000) == WAIT_OBJECT_0, + "Timer destruction event not triggered\n"); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(q, e); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + ok(WaitForSingleObject(e, 250) == WAIT_OBJECT_0, + "Queue destruction event not triggered\n"); + CloseHandle(e); + + /* Test deleting/changing a timer in execution. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + /* Test changing a once-only timer before it fires (this is allowed, + whereas after it fires you cannot). */ + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 10000, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + ret = pChangeTimerQueueTimer(q, t1, 0, 0); + ok(ret, "ChangeTimerQueueTimer\n"); + + d2.t = t2 = NULL; + d2.num_calls = 0; + d2.max_calls = 3; + d2.q = q; + ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb2, &d2, 10, + 10, 0); + d2.t = t2; + ok(ret, "CreateTimerQueueTimer\n"); + ok(t2 != NULL, "CreateTimerQueueTimer\n"); + + d3.t = t3 = NULL; + d3.num_calls = 0; + d3.max_calls = 4; + d3.q = q; + ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb3, &d3, 10, + 10, 0); + d3.t = t3; + ok(ret, "CreateTimerQueueTimer\n"); + ok(t3 != NULL, "CreateTimerQueueTimer\n"); + + d4.t = t4 = NULL; + d4.num_calls = 0; + d4.q = q; + ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb4, &d4, 10, + 0, 0); + d4.t = t4; + ok(ret, "CreateTimerQueueTimer\n"); + ok(t4 != NULL, "CreateTimerQueueTimer\n"); + + Sleep(500); + + ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueEx\n"); + ok(n1 == 1, "ChangeTimerQueueTimer\n"); + ok(d2.num_calls == d2.max_calls, "DeleteTimerQueueTimer\n"); + ok(d3.num_calls == d3.max_calls, "ChangeTimerQueueTimer\n"); + ok(d4.num_calls == 1, "Timer flagged for deletion incorrectly\n"); + + /* Test an obscure bug that was in the original implementation. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + /* All the work is done in the callback. */ + d1.t = t1 = NULL; + d1.num_calls = 0; + d1.q = q; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb6, &d1, 100, + 100, WT_EXECUTELONGFUNCTION); + d1.t = t1; + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + + Sleep(750); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(q, NULL); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + ok(d1.num_calls == 1, "DeleteTimerQueueTimer\n"); + + /* Test functions on the default timer queue. */ + t1 = NULL; + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, NULL, timer_queue_cb1, &n1, 1000, + 1000, 0); + ok(ret, "CreateTimerQueueTimer, default queue\n"); + ok(t1 != NULL, "CreateTimerQueueTimer, default queue\n"); + + ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000); + ok(ret, "ChangeTimerQueueTimer, default queue\n"); + + ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer, default queue\n"); + + /* Try mixing default and non-default queues. Apparently this works. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + t1 = NULL; + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 1000, + 1000, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + + t2 = NULL; + n2 = 0; + ret = pCreateTimerQueueTimer(&t2, NULL, timer_queue_cb1, &n2, 1000, + 1000, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t2 != NULL, "CreateTimerQueueTimer\n"); + + ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000); + ok(ret, "ChangeTimerQueueTimer\n"); + + ret = pChangeTimerQueueTimer(q, t2, 2000, 2000); + ok(ret, "ChangeTimerQueueTimer\n"); + + ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + /* Try to delete the default queue? In any case: not allowed. */ + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(NULL, NULL); + ok(!ret, "DeleteTimerQueueEx call was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "DeleteTimerQueueEx, GetLastError: expected ERROR_INVALID_HANDLE, got %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(q, NULL); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); } START_TEST(sync) { + HMODULE hdll = GetModuleHandle("kernel32"); + pChangeTimerQueueTimer = (void*)GetProcAddress(hdll, "ChangeTimerQueueTimer"); + pCreateTimerQueue = (void*)GetProcAddress(hdll, "CreateTimerQueue"); + pCreateTimerQueueTimer = (void*)GetProcAddress(hdll, "CreateTimerQueueTimer"); + pCreateWaitableTimerA = (void*)GetProcAddress(hdll, "CreateWaitableTimerA"); + pDeleteTimerQueueEx = (void*)GetProcAddress(hdll, "DeleteTimerQueueEx"); + pDeleteTimerQueueTimer = (void*)GetProcAddress(hdll, "DeleteTimerQueueTimer"); + pOpenWaitableTimerA = (void*)GetProcAddress(hdll, "OpenWaitableTimerA"); + test_signalandwait(); test_mutex(); test_slist(); - test_event_security(); + test_event(); + test_semaphore(); + test_waitable_timer(); test_iocp_callback(); + test_timer_queue(); } diff --git a/rostests/winetests/kernel32/thread.c b/rostests/winetests/kernel32/thread.c index 7d83b255a4d..5f98b8c49c8 100755 --- a/rostests/winetests/kernel32/thread.c +++ b/rostests/winetests/kernel32/thread.c @@ -21,6 +21,7 @@ /* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */ #define _WIN32_WINNT 0x0500 +#include #include #include @@ -99,6 +100,61 @@ In addition there are no checks that the inheritance works properly in CreateThread */ +/* Functions to ensure that from a group of threads, only one executes + certain chunks of code at a time, and we know which one is executing + it. It basically makes multithreaded execution linear, which defeats + the purpose of multiple threads, but makes testing easy. */ +static HANDLE start_event, stop_event; +static LONG num_synced; + +static void init_thread_sync_helpers(void) +{ + start_event = CreateEvent(NULL, TRUE, FALSE, NULL); + ok(start_event != NULL, "CreateEvent failed\n"); + stop_event = CreateEvent(NULL, TRUE, FALSE, NULL); + ok(stop_event != NULL, "CreateEvent failed\n"); + num_synced = -1; +} + +static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id) +{ + LONG num = InterlockedIncrement(&num_synced); + assert(-1 <= num && num <= 1); + if (num == 1) + { + ResetEvent( stop_event ); + SetEvent( start_event ); + } + else + { + DWORD ret = WaitForSingleObject(start_event, 10000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %x\n",ret); + } + return sync_id == my_id; +} + +static void resync_after_run(void) +{ + LONG num = InterlockedDecrement(&num_synced); + assert(-1 <= num && num <= 1); + if (num == -1) + { + ResetEvent( start_event ); + SetEvent( stop_event ); + } + else + { + DWORD ret = WaitForSingleObject(stop_event, 10000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + } +} + +static void cleanup_thread_sync_helpers(void) +{ + CloseHandle(start_event); + CloseHandle(stop_event); +} + DWORD tlsIndex; typedef struct { @@ -127,11 +183,11 @@ INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */ */ static DWORD WINAPI threadFunc1(LPVOID p) { - t1Struct *tstruct = (t1Struct *)p; + t1Struct *tstruct = p; int i; /* write our thread # into shared memory */ tstruct->threadmem[tstruct->threadnum]=GetCurrentThreadId(); - ok(TlsSetValue(tlsIndex,(LPVOID)(tstruct->threadnum+1))!=0, + ok(TlsSetValue(tlsIndex,(LPVOID)(INT_PTR)(tstruct->threadnum+1))!=0, "TlsSetValue failed\n"); /* The threads synchronize before terminating. This is done by Signaling an event, and waiting for all events to occur @@ -149,7 +205,7 @@ static DWORD WINAPI threadFunc1(LPVOID p) ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" ); /* Check that no one changed our tls memory */ - ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum, + ok((INT_PTR)TlsGetValue(tlsIndex)-1==tstruct->threadnum, "TlsGetValue failed\n"); return NUM_THREADS+tstruct->threadnum; } @@ -169,7 +225,7 @@ static DWORD WINAPI threadFunc3(LPVOID p) static DWORD WINAPI threadFunc4(LPVOID p) { - HANDLE event = (HANDLE)p; + HANDLE event = p; if(event != NULL) { SetEvent(event); } @@ -180,7 +236,7 @@ static DWORD WINAPI threadFunc4(LPVOID p) #if CHECK_STACK static DWORD WINAPI threadFunc5(LPVOID p) { - DWORD *exitCode = (DWORD *)p; + DWORD *exitCode = p; SYSTEM_INFO sysInfo; sysInfo.dwPageSize=0; GetSystemInfo(&sysInfo); @@ -199,13 +255,13 @@ static DWORD WINAPI threadFunc5(LPVOID p) static DWORD WINAPI threadFunc_SetEvent(LPVOID p) { - SetEvent((HANDLE) p); + SetEvent(p); return 0; } static DWORD WINAPI threadFunc_CloseHandle(LPVOID p) { - CloseHandle((HANDLE) p); + CloseHandle(p); return 0; } @@ -252,7 +308,7 @@ static VOID test_CreateRemoteThread(void) hRemoteEvent, CREATE_SUSPENDED, &tid); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("CreateRemoteThread is not implemented\n"); + win_skip("CreateRemoteThread is not implemented\n"); goto cleanup; } ok(hThread != NULL, "CreateRemoteThread failed, err=%u\n", GetLastError()); @@ -320,6 +376,7 @@ static VOID test_CreateThread_basic(void) int error; DWORD i,j; DWORD GLE, ret; + DWORD tid; /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */ ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" ); @@ -377,7 +434,7 @@ static VOID test_CreateThread_basic(void) /* Test how passing NULL as a pointer to threadid works */ SetLastError(0xFACEaBAD); - thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,NULL); + thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid); GLE = GetLastError(); if (thread[0]) { /* NT */ ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE); @@ -398,6 +455,7 @@ static VOID test_CreateThread_suspended(void) { HANDLE thread; DWORD threadId; + DWORD suspend_count; int error; thread = CreateThread(NULL,0,threadFunc2,NULL, @@ -419,6 +477,15 @@ static VOID test_CreateThread_suspended(void) if(error!=WAIT_OBJECT_0) { TerminateThread(thread,1); } + + suspend_count = SuspendThread(thread); + ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count); + + suspend_count = ResumeThread(thread); + ok(suspend_count == 0 || + broken(suspend_count == -1), /* win9x */ + "ResumeThread returned %d, expected 0\n", suspend_count); + ok(CloseHandle(thread)!=0,"CloseHandle failed\n"); } @@ -483,8 +550,7 @@ static VOID test_TerminateThread(void) HANDLE thread,access_thread,event; DWORD threadId,exitCode; event=CreateEventA(NULL,TRUE,FALSE,NULL); - thread = CreateThread(NULL,0,threadFunc4, - (LPVOID)event, 0,&threadId); + thread = CreateThread(NULL,0,threadFunc4,event,0,&threadId); ok(thread!=NULL,"Create Thread failed\n"); /* TerminateThread has a race condition in Wine. If the thread is terminated before it starts, it leaves a process behind. Therefore, we wait for the @@ -627,9 +693,11 @@ static VOID test_thread_priority(void) SetLastError(0xdeadbeef); rc=pGetThreadPriorityBoost(curthread,&disabled); if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) - return; /* WinME */ + { + win_skip("GetThreadPriorityBoost is not implemented on WinME\n"); + return; + } - todo_wine ok(rc!=0,"error=%d\n",GetLastError()); if (pOpenThread) { @@ -640,7 +708,7 @@ static VOID test_thread_priority(void) ok(access_thread!=NULL,"OpenThread returned an invalid handle\n"); if (access_thread!=NULL) { obey_ar(pSetThreadPriorityBoost(access_thread,1)==0); - obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0); + todo_wine obey_ar(pGetThreadPriorityBoost(access_thread,&disabled)==0); ok(CloseHandle(access_thread),"Error Closing thread handle\n"); } } @@ -654,11 +722,11 @@ static VOID test_thread_priority(void) rc = pSetThreadPriorityBoost(curthread,0); ok( rc != 0, "error=%d\n",GetLastError()); + } rc=pGetThreadPriorityBoost(curthread,&disabled); ok(rc!=0 && disabled==0, "rc=%d error=%d disabled=%d\n",rc,GetLastError(),disabled); } -} /* check the GetThreadTimes function */ static VOID test_GetThreadTimes(void) @@ -689,7 +757,10 @@ static VOID test_GetThreadTimes(void) /* GetThreadTimes should set all of the parameters passed to it */ error=GetThreadTimes(thread,&creationTime,&exitTime, &kernelTime,&userTime); - if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) { + + if (error == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + win_skip("GetThreadTimes is not implemented\n"); + else { ok(error!=0,"GetThreadTimes failed\n"); ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99, "creationTime was invalid\n"); @@ -740,24 +811,26 @@ static VOID test_thread_processor(void) "SetThreadAffinityMask passed for an illegal processor\n"); /* NOTE: This only works on WinNT/2000/XP) */ if (pSetThreadIdealProcessor) { - todo_wine { - SetLastError(0); + SetLastError(0xdeadbeef); error=pSetThreadIdealProcessor(curthread,0); - if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) { - ok(error!=-1, "SetThreadIdealProcessor failed\n"); - } + if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("SetThreadIdealProcessor is not implemented\n"); + return; } - if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) { + ok(error!=-1, "SetThreadIdealProcessor failed\n"); + + SetLastError(0xdeadbeef); error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1); ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n"); - todo_wine { + ok(GetLastError()==ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS); ok(error==0, "SetThreadIdealProcessor returned an incorrect value\n"); } } - } -} static VOID test_GetThreadExitCode(void) { @@ -862,7 +935,7 @@ static DWORD CALLBACK work_function(void *p) static void test_QueueUserWorkItem(void) { - int i; + INT_PTR i; DWORD wait_result; DWORD before, after; @@ -911,7 +984,7 @@ static void test_RegisterWaitForSingleObject(void) if (!pRegisterWaitForSingleObject || !pUnregisterWait) { - skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n"); + win_skip("RegisterWaitForSingleObject or UnregisterWait not implemented\n"); return; } @@ -953,6 +1026,183 @@ static void test_RegisterWaitForSingleObject(void) ok(ret, "UnregisterWait failed with error %d\n", GetLastError()); } +static DWORD TLS_main; +static DWORD TLS_index0, TLS_index1; + +static DWORD WINAPI TLS_InheritanceProc(LPVOID p) +{ + /* We should NOT inherit the TLS values from our parent or from the + main thread. */ + LPVOID val; + + val = TlsGetValue(TLS_main); + ok(val == NULL, "TLS inheritance failed\n"); + + val = TlsGetValue(TLS_index0); + ok(val == NULL, "TLS inheritance failed\n"); + + val = TlsGetValue(TLS_index1); + ok(val == NULL, "TLS inheritance failed\n"); + + return 0; +} + +/* Basic TLS usage test. Make sure we can create slots and the values we + store in them are separate among threads. Also test TLS value + inheritance with TLS_InheritanceProc. */ +static DWORD WINAPI TLS_ThreadProc(LPVOID p) +{ + LONG_PTR id = (LONG_PTR) p; + LPVOID val; + BOOL ret; + + if (sync_threads_and_run_one(0, id)) + { + TLS_index0 = TlsAlloc(); + ok(TLS_index0 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(1, id)) + { + TLS_index1 = TlsAlloc(); + ok(TLS_index1 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); + + /* Slot indices should be different even if created in different + threads. */ + ok(TLS_index0 != TLS_index1, "TlsAlloc failed\n"); + + /* Both slots should be initialized to NULL */ + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(0, id)) + { + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + ret = TlsSetValue(TLS_index0, (LPVOID) 1); + ok(ret, "TlsSetValue failed\n"); + + ret = TlsSetValue(TLS_index1, (LPVOID) 2); + ok(ret, "TlsSetValue failed\n"); + + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(1, id)) + { + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + ret = TlsSetValue(TLS_index0, (LPVOID) 3); + ok(ret, "TlsSetValue failed\n"); + + ret = TlsSetValue(TLS_index1, (LPVOID) 4); + ok(ret, "TlsSetValue failed\n"); + + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 3, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 4, "TLS slot not initialized correctly\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(0, id)) + { + HANDLE thread; + DWORD waitret, tid; + + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n"); + + thread = CreateThread(NULL, 0, TLS_InheritanceProc, 0, 0, &tid); + ok(thread != NULL, "CreateThread failed\n"); + waitret = WaitForSingleObject(thread, 60000); + ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(thread); + + ret = TlsFree(TLS_index0); + ok(ret, "TlsFree failed\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(1, id)) + { + ret = TlsFree(TLS_index1); + ok(ret, "TlsFree failed\n"); + } + resync_after_run(); + + return 0; +} + +static void test_TLS(void) +{ + HANDLE threads[2]; + LONG_PTR i; + DWORD ret; + BOOL suc; + + init_thread_sync_helpers(); + + /* Allocate a TLS slot in the main thread to test for inheritance. */ + TLS_main = TlsAlloc(); + ok(TLS_main != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); + suc = TlsSetValue(TLS_main, (LPVOID) 4114); + ok(suc, "TlsSetValue failed\n"); + + for (i = 0; i < 2; ++i) + { + DWORD tid; + + threads[i] = CreateThread(NULL, 0, TLS_ThreadProc, (LPVOID) i, 0, &tid); + ok(threads[i] != NULL, "CreateThread failed\n"); + } + + ret = WaitForMultipleObjects(2, threads, TRUE, 60000); + ok(ret == WAIT_OBJECT_0 || ret == WAIT_OBJECT_0+1 /* nt4 */, "WaitForMultipleObjects failed %u\n",ret); + + for (i = 0; i < 2; ++i) + CloseHandle(threads[i]); + + suc = TlsFree(TLS_main); + ok(suc, "TlsFree failed\n"); + cleanup_thread_sync_helpers(); +} + START_TEST(thread) { HINSTANCE lib; @@ -986,7 +1236,8 @@ START_TEST(thread) while (1) { HANDLE hThread; - hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, NULL); + DWORD tid; + hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid); ok(hThread != NULL, "CreateThread failed, error %u\n", GetLastError()); ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0, @@ -1012,4 +1263,5 @@ START_TEST(thread) #endif test_QueueUserWorkItem(); test_RegisterWaitForSingleObject(); + test_TLS(); } diff --git a/rostests/winetests/kernel32/time.c b/rostests/winetests/kernel32/time.c index 21a8232b917..0b3959a56e5 100755 --- a/rostests/winetests/kernel32/time.c +++ b/rostests/winetests/kernel32/time.c @@ -294,7 +294,7 @@ static void test_GetTimeZoneInformation(void) if (!pSystemTimeToTzSpecificLocalTime) { - skip("SystemTimeToTzSpecificLocalTime not present\n"); + win_skip("SystemTimeToTzSpecificLocalTime not available\n"); return; } @@ -305,7 +305,7 @@ static void test_GetTimeZoneInformation(void) res = pSystemTimeToTzSpecificLocalTime(&tzinfo, &utc, ¤t); if (!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("SystemTimeToTzSpecificLocalTime is not implemented\n"); + win_skip("SystemTimeToTzSpecificLocalTime is not implemented\n"); return; } @@ -425,7 +425,7 @@ static void test_TzSpecificLocalTimeToSystemTime(void) if (!pTzSpecificLocalTimeToSystemTime || !pSystemTimeToTzSpecificLocalTime) { - skip("TzSpecificLocalTimeToSystemTime or SystemTimeToTzSpecificLocalTime not present\n"); + win_skip("TzSpecificLocalTimeToSystemTime or SystemTimeToTzSpecificLocalTime not available\n"); return; } diff --git a/rostests/winetests/kernel32/timer.c b/rostests/winetests/kernel32/timer.c index 34418908705..3c3fde76f11 100755 --- a/rostests/winetests/kernel32/timer.c +++ b/rostests/winetests/kernel32/timer.c @@ -38,11 +38,17 @@ static void test_timer(void) pCreateWaitableTimerA = (fnCreateWaitableTimerA) GetProcAddress( hker, "CreateWaitableTimerA"); if( !pCreateWaitableTimerA ) + { + win_skip("CreateWaitableTimerA is not available\n"); return; + } pSetWaitableTimer = (fnSetWaitableTimer) GetProcAddress( hker, "SetWaitableTimer"); if( !pSetWaitableTimer ) + { + win_skip("SetWaitableTimer is not available\n"); return; + } /* try once with a positive number */ handle = pCreateWaitableTimerA( NULL, 0, NULL ); diff --git a/rostests/winetests/kernel32/toolhelp.c b/rostests/winetests/kernel32/toolhelp.c index 48b6a6b790f..21ce2720920 100644 --- a/rostests/winetests/kernel32/toolhelp.c +++ b/rostests/winetests/kernel32/toolhelp.c @@ -44,7 +44,7 @@ static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32); static DWORD WINAPI sub_thread(void* pmt) { - DWORD w = WaitForSingleObject((HANDLE)pmt, WAIT_TIME); + DWORD w = WaitForSingleObject(pmt, WAIT_TIME); return w; } @@ -73,8 +73,8 @@ static int init(void) case 2: /* the test program */ return 0; case 4: /* the sub-process */ - ev1 = (HANDLE)atoi(argv[2]); - ev2 = (HANDLE)atoi(argv[3]); + ev1 = (HANDLE)(INT_PTR)atoi(argv[2]); + ev2 = (HANDLE)(INT_PTR)atoi(argv[3]); ev3 = CreateEvent(NULL, FALSE, FALSE, NULL); if (ev3 == NULL) ExitProcess(WAIT_ABANDONED); @@ -102,7 +102,6 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) { HANDLE hSnapshot; PROCESSENTRY32 pe; - THREADENTRY32 te; MODULEENTRY32 me; unsigned found = 0; int num = 0; @@ -144,9 +143,6 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) * interesting to be there, especially not the just forked off child */ ok (childpos !=0, "child is not expected to be at position 0.\n"); - te.dwSize = sizeof(te); - ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n"); - me.dwSize = sizeof(me); ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n"); @@ -157,7 +153,6 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) { HANDLE hSnapshot; - PROCESSENTRY32 pe; THREADENTRY32 te; MODULEENTRY32 me; int num = 0; @@ -175,6 +170,7 @@ static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) { if (te.th32OwnerProcessID == curr_pid) curr_found++; if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++; + if (winetest_debug > 1) trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); num++; } while (pThread32Next( hSnapshot, &te )); @@ -191,6 +187,7 @@ static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) { if (te.th32OwnerProcessID == curr_pid) curr_found++; if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++; + if (winetest_debug > 1) trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); num--; } while (pThread32Next( hSnapshot, &te )); @@ -198,9 +195,6 @@ static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) ok(curr_found == 1, "couldn't find self in thread list\n"); ok(sub_found == 2, "couldn't find sub-process thread's in thread list\n"); - pe.dwSize = sizeof(pe); - ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n"); - me.dwSize = sizeof(me); ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n"); @@ -210,14 +204,14 @@ static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) static const char* curr_expected_modules[] = { - "kernel32.dll", "kernel32_test.exe" + "kernel32.dll", /* FIXME: could test for ntdll on NT and Wine */ }; static const char* sub_expected_modules[] = { - "kernel32.dll", "kernel32_test.exe", + "kernel32.dll", "shell32.dll" /* FIXME: could test for ntdll on NT and Wine */ }; @@ -278,7 +272,7 @@ static void test_module(DWORD pid, const char* expected[], unsigned num_expected pe.dwSize = sizeof(pe); ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n"); - me.dwSize = sizeof(me); + te.dwSize = sizeof(te); ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n"); CloseHandle(hSnapshot); @@ -289,6 +283,7 @@ START_TEST(toolhelp) { DWORD pid = GetCurrentProcessId(); int r; + char *p, module[MAX_PATH]; char buffer[MAX_PATH]; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION info; @@ -310,7 +305,7 @@ START_TEST(toolhelp) !pProcess32First || !pProcess32Next || !pThread32First || !pThread32Next) { - skip("Needed functions are not available, most likely running on Windows NT\n"); + win_skip("Needed functions are not available, most likely running on Windows NT\n"); return; } @@ -330,12 +325,18 @@ START_TEST(toolhelp) startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; - sprintf(buffer, "%s tests/toolhelp.c %u %u", selfname, (DWORD)ev1, (DWORD)ev2); + sprintf(buffer, "%s tests/toolhelp.c %lu %lu", selfname, (DWORD_PTR)ev1, (DWORD_PTR)ev2); ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &info), "CreateProcess\n"); /* wait for child to be initialized */ w = WaitForSingleObject(ev1, WAIT_TIME); ok(w == WAIT_OBJECT_0, "Failed to wait on sub-process startup\n"); + GetModuleFileNameA( 0, module, sizeof(module) ); + if (!(p = strrchr( module, '\\' ))) p = module; + else p++; + curr_expected_modules[0] = p; + sub_expected_modules[0] = p; + test_process(pid, info.dwProcessId); test_thread(pid, info.dwProcessId); test_module(pid, curr_expected_modules, NUM_OF(curr_expected_modules)); diff --git a/rostests/winetests/kernel32/version.c b/rostests/winetests/kernel32/version.c index 5371795ba6b..5805e32f6e2 100644 --- a/rostests/winetests/kernel32/version.c +++ b/rostests/winetests/kernel32/version.c @@ -92,7 +92,9 @@ static void test_GetVersionEx(void) SetLastError(0xdeadbeef); infoExA.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA); ret = GetVersionExA((OSVERSIONINFOA *)&infoExA); - ok(ret, "Expected GetVersionExA to succeed\n"); + ok(ret || + broken(ret == 0), /* win95 */ + "Expected GetVersionExA to succeed\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); } @@ -105,7 +107,7 @@ static void test_VerifyVersionInfo(void) if(!pVerifyVersionInfoA || !pVerSetConditionMask) { - skip("Needed functions not available\n"); + win_skip("Needed functions not available\n"); return; } @@ -162,8 +164,12 @@ static void test_VerifyVersionInfo(void) pVerSetConditionMask(pVerSetConditionMask(0, VER_MINORVERSION, VER_GREATER_EQUAL), VER_MAJORVERSION, VER_GREATER_EQUAL)); if (servicepack == 0) - ok(!ret && (GetLastError() == ERROR_OLD_WIN_VERSION), - "VerifyVersionInfoA should have failed with ERROR_OLD_WIN_VERSION instead of %d\n", GetLastError()); + { + ok(!ret || broken(ret), /* win2k3 */ + "VerifyVersionInfoA should have failed\n"); + ok(GetLastError() == ERROR_OLD_WIN_VERSION, + "Expected ERROR_OLD_WIN_VERSION instead of %d\n", GetLastError()); + } else ok(ret, "VerifyVersionInfoA failed with error %d\n", GetLastError()); diff --git a/rostests/winetests/kernel32/virtual.c b/rostests/winetests/kernel32/virtual.c index dad82f6612a..aeb4f38e216 100755 --- a/rostests/winetests/kernel32/virtual.c +++ b/rostests/winetests/kernel32/virtual.c @@ -32,6 +32,8 @@ static HINSTANCE hkernel32; static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD); static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD); +static UINT (WINAPI *pGetWriteWatch)(DWORD,LPVOID,SIZE_T,LPVOID*,ULONG_PTR*,ULONG*); +static UINT (WINAPI *pResetWriteWatch)(LPVOID,SIZE_T); /* ############################### */ @@ -55,7 +57,7 @@ static void test_VirtualAllocEx(void) { const unsigned int alloc_size = 1<<15; char *src, *dst; - unsigned long bytes_written = 0, bytes_read = 0, i; + SIZE_T bytes_written = 0, bytes_read = 0, i; void *addr1, *addr2; BOOL b; DWORD old_prot; @@ -64,7 +66,7 @@ static void test_VirtualAllocEx(void) /* not exported in all windows-versions */ if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) { - skip("VirtualAllocEx not found\n"); + win_skip("Virtual{Alloc,Free}Ex not available\n"); return; } @@ -76,14 +78,14 @@ static void test_VirtualAllocEx(void) PAGE_EXECUTE_READWRITE); if (!addr1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { /* Win9x */ - skip("VirtualAllocEx not implemented\n"); + win_skip("VirtualAllocEx not implemented\n"); TerminateProcess(hProcess, 0); CloseHandle(hProcess); return; } - src = HeapAlloc( GetProcessHeap(), 0, alloc_size ); - dst = HeapAlloc( GetProcessHeap(), 0, alloc_size ); + src = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE ); + dst = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE ); for (i = 0; i < alloc_size; i++) src[i] = i & 0xff; @@ -94,11 +96,40 @@ static void test_VirtualAllocEx(void) b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read); ok(b && (bytes_read == alloc_size), "%lu bytes read\n", bytes_read); ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n"); + + /* test invalid source buffers */ + + b = VirtualProtect( src + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot ); + ok( b, "VirtualProtect failed error %u\n", GetLastError() ); + b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); + ok( !b, "WriteProcessMemory succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_PARTIAL_COPY, /* vista */ + "wrong error %u\n", GetLastError() ); + ok( bytes_written == 0, "%lu bytes written\n", bytes_written ); + b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read); + ok( !b, "ReadProcessMemory succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + ok( bytes_read == 0, "%lu bytes written\n", bytes_read ); + + b = VirtualProtect( src, 0x2000, PAGE_NOACCESS, &old_prot ); + ok( b, "VirtualProtect failed error %u\n", GetLastError() ); + b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written); + ok( !b, "WriteProcessMemory succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS || + GetLastError() == ERROR_PARTIAL_COPY, /* vista */ + "wrong error %u\n", GetLastError() ); + ok( bytes_written == 0, "%lu bytes written\n", bytes_written ); + b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read); + ok( !b, "ReadProcessMemory succeeded\n" ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + ok( bytes_read == 0, "%lu bytes written\n", bytes_read ); + b = pVirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE); ok(b != 0, "VirtualFreeEx, error %u\n", GetLastError()); - HeapFree( GetProcessHeap(), 0, src ); - HeapFree( GetProcessHeap(), 0, dst ); + VirtualFree( src, 0, MEM_FREE ); + VirtualFree( dst, 0, MEM_FREE ); /* * The following tests parallel those in test_VirtualAlloc() @@ -253,6 +284,66 @@ static void test_VirtualAlloc(void) ok(old_prot == PAGE_READONLY, "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot); + ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), + "VirtualQuery failed\n"); + ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State); + ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect); + memset( addr1, 0x55, 20 ); + ok( *(DWORD *)addr1 == 0x55555555, "wrong data %x\n", *(DWORD *)addr1 ); + + addr2 = VirtualAlloc( addr1, 0x1000, MEM_RESET, PAGE_NOACCESS ); + ok( addr2 == addr1 || broken( !addr2 && GetLastError() == ERROR_INVALID_PARAMETER), /* win9x */ + "VirtualAlloc failed err %u\n", GetLastError() ); + ok( *(DWORD *)addr1 == 0x55555555 || *(DWORD *)addr1 == 0, "wrong data %x\n", *(DWORD *)addr1 ); + if (addr2) + { + ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info), + "VirtualQuery failed\n"); + ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize); + ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State); + ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect); + + addr2 = VirtualAlloc( (char *)addr1 + 0x1000, 0x1000, MEM_RESET, PAGE_NOACCESS ); + ok( (char *)addr2 == (char *)addr1 + 0x1000, "VirtualAlloc failed\n" ); + + ok(VirtualQuery(addr2, &info, sizeof(info)) == sizeof(info), + "VirtualQuery failed\n"); + ok(info.RegionSize == 0xf000, "%lx != 0xf000\n", info.RegionSize); + ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State); + ok(info.Protect == 0, "%x != 0\n", info.Protect); + + addr2 = VirtualAlloc( (char *)addr1 + 0xf000, 0x2000, MEM_RESET, PAGE_NOACCESS ); + ok( !addr2, "VirtualAlloc failed\n" ); + ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %u\n", GetLastError() ); + } + + /* invalid protection values */ + SetLastError(0xdeadbeef); + addr2 = VirtualAlloc(NULL, 0x1000, MEM_RESERVE, 0); + ok(!addr2, "VirtualAlloc succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + addr2 = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, 0); + ok(!addr2, "VirtualAlloc succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_READONLY | PAGE_EXECUTE); + ok(!addr2, "VirtualAlloc succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ok(!VirtualProtect(addr1, 0x1000, PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY, &old_prot), + "VirtualProtect succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ok(!VirtualProtect(addr1, 0x1000, 0, &old_prot), "VirtualProtect succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); ok(!VirtualFree(addr1, 0x10000, 0), "VirtualFree should fail with type 0\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError()); @@ -270,8 +361,9 @@ static void test_VirtualAlloc(void) static void test_MapViewOfFile(void) { static const char testfile[] = "testfile.xxx"; - HANDLE file, mapping; - void *ptr, *ptr2; + const char *name; + HANDLE file, mapping, map2; + void *ptr, *ptr2, *addr; MEMORY_BASIC_INFORMATION info; BOOL ret; @@ -307,6 +399,39 @@ static void test_MapViewOfFile(void) ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 ); ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() ); UnmapViewOfFile( ptr ); + + ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, + FILE_MAP_READ|FILE_MAP_WRITE, FALSE, 0 ); + ok( ret, "DuplicateHandle failed error %u\n", GetLastError()); + ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() ); + UnmapViewOfFile( ptr ); + CloseHandle( map2 ); + + ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, + FILE_MAP_READ, FALSE, 0 ); + ok( ret, "DuplicateHandle failed error %u\n", GetLastError()); + ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 ); + if (!ptr) + { + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + CloseHandle( map2 ); + ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, 0, FALSE, 0 ); + ok( ret, "DuplicateHandle failed error %u\n", GetLastError()); + ptr = MapViewOfFile( map2, 0, 0, 0, 4096 ); + ok( !ptr, "MapViewOfFile succeeded\n" ); + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + CloseHandle( map2 ); + ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, + FILE_MAP_READ, FALSE, 0 ); + ok( ret, "DuplicateHandle failed error %u\n", GetLastError()); + ptr = MapViewOfFile( map2, 0, 0, 0, 4096 ); + ok( ptr != NULL, "MapViewOfFile NO_ACCESS error %u\n", GetLastError() ); + } + else win_skip( "no access checks on win9x\n" ); + + UnmapViewOfFile( ptr ); + CloseHandle( map2 ); CloseHandle( mapping ); /* read-only mapping */ @@ -450,16 +575,24 @@ static void test_MapViewOfFile(void) DeleteFileA( testfile ); SetLastError(0xdeadbeef); - file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "Global\\Foo"); + name = "Local\\Foo"; + file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, name ); + /* nt4 doesn't have Local\\ */ + if (!file && GetLastError() == ERROR_PATH_NOT_FOUND) + { + name = "Foo"; + file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, name ); + } ok( file != 0, "CreateFileMapping PAGE_READWRITE error %u\n", GetLastError() ); SetLastError(0xdeadbeef); - mapping = OpenFileMapping( FILE_MAP_READ, FALSE, "Global\\Foo" ); + mapping = OpenFileMapping( FILE_MAP_READ, FALSE, name ); ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %u\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); -todo_wine ok( !ptr, "MapViewOfFile FILE_MAP_WRITE should fail\n" ); -todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + if (!ptr) + { + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); @@ -468,20 +601,23 @@ todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLast "VirtualQuery error %u\n", GetLastError() ); ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr ); ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr ); -todo_wine ok( info.AllocationProtect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.AllocationProtect ); + ok( info.AllocationProtect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.AllocationProtect ); ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize ); ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State ); -todo_wine ok( info.Protect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.Protect ); + ok( info.Protect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.Protect ); + } + else win_skip( "no access checks on win9x\n" ); UnmapViewOfFile( ptr ); CloseHandle( mapping ); SetLastError(0xdeadbeef); - mapping = OpenFileMapping( FILE_MAP_WRITE, FALSE, "Global\\Foo" ); + mapping = OpenFileMapping( FILE_MAP_WRITE, FALSE, name ); ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %u\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); -todo_wine ok( !ptr, "MapViewOfFile FILE_MAP_READ should fail\n" ); -todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + if (!ptr) + { + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() ); @@ -494,6 +630,8 @@ todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLast ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize ); ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State ); ok( info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect ); + } + else win_skip( "no access checks on win9x\n" ); UnmapViewOfFile( ptr ); CloseHandle( mapping ); @@ -506,56 +644,128 @@ todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLast ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); ok(ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError()); + ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); + /* on NT ptr != ptr2 but on Win9x ptr == ptr2 */ + ok(ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError()); + trace("mapping same section resulted in views %p and %p\n", ptr, ptr2); + ret = VirtualQuery(ptr, &info, sizeof(info)); ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress); ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase); - ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); ok(info.RegionSize == MAPPING_SIZE, "RegionSize should have been 0x%x but was 0x%x\n", MAPPING_SIZE, (unsigned int)info.RegionSize); -todo_wine ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%x\n", info.State); -todo_wine + if (info.Type == MEM_PRIVATE) /* win9x is different for uncommitted mappings */ + { + ok(info.AllocationProtect == PAGE_NOACCESS, + "AllocationProtect should have been PAGE_NOACCESS but was 0x%x\n", info.AllocationProtect); + ok(info.Protect == PAGE_NOACCESS, + "Protect should have been PAGE_NOACCESS instead of 0x%x\n", info.Protect); + } + else + { + ok(info.AllocationProtect == PAGE_READWRITE, + "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); ok(info.Protect == 0, "Protect should have been 0 instead of 0x%x\n", info.Protect); ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + } - ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READWRITE); + if (ptr != ptr2) + { + ret = VirtualQuery(ptr2, &info, sizeof(info)); + ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); + ok(info.BaseAddress == ptr2, + "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress); + ok(info.AllocationBase == ptr2, + "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, + "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); + ok(info.RegionSize == MAPPING_SIZE, + "RegionSize should have been 0x%x but was 0x%x\n", MAPPING_SIZE, (unsigned int)info.RegionSize); + ok(info.State == MEM_RESERVE, + "State should have been MEM_RESERVE instead of 0x%x\n", info.State); + ok(info.Protect == 0, + "Protect should have been 0 instead of 0x%x\n", info.Protect); + ok(info.Type == MEM_MAPPED, + "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + } + + ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READONLY); ok(ptr != NULL, "VirtualAlloc failed with error %d\n", GetLastError()); ret = VirtualQuery(ptr, &info, sizeof(info)); ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress); ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase); - ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); -todo_wine ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize); ok(info.State == MEM_COMMIT, "State should have been MEM_RESERVE instead of 0x%x\n", info.State); - ok(info.Protect == PAGE_READWRITE, "Protect should have been 0 instead of 0x%x\n", info.Protect); + ok(info.Protect == PAGE_READONLY, "Protect should have been 0 instead of 0x%x\n", info.Protect); + if (info.Type == MEM_PRIVATE) /* win9x is different for uncommitted mappings */ + { + ok(info.AllocationProtect == PAGE_NOACCESS, + "AllocationProtect should have been PAGE_NOACCESS but was 0x%x\n", info.AllocationProtect); + } + else + { + ok(info.AllocationProtect == PAGE_READWRITE, + "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); - - ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); - /* on NT ptr != ptr2 but on Win9x ptr == ptr2 */ - ok(ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError()); - trace("mapping same section resulted in views %p and %p\n", ptr, ptr2); + } /* shows that the VirtualAlloc above affects the mapping, not just the * virtual memory in this process - it also affects all other processes * with a view of the mapping, but that isn't tested here */ + if (ptr != ptr2) + { ret = VirtualQuery(ptr2, &info, sizeof(info)); ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); - ok(info.BaseAddress == ptr2, "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress); - ok(info.AllocationBase == ptr2, "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase); - ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); -todo_wine - ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize); - ok(info.State == MEM_COMMIT, "State should have been MEM_RESERVE instead of 0x%x\n", info.State); - ok(info.Protect == PAGE_READWRITE, "Protect should have been 0 instead of 0x%x\n", info.Protect); + ok(info.BaseAddress == ptr2, + "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress); + ok(info.AllocationBase == ptr2, + "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, + "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); + ok(info.RegionSize == 0x10000, + "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize); + ok(info.State == MEM_COMMIT, + "State should have been MEM_RESERVE instead of 0x%x\n", info.State); + ok(info.Protect == PAGE_READWRITE, + "Protect should have been 0 instead of 0x%x\n", info.Protect); ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + } + + addr = VirtualAlloc( ptr, MAPPING_SIZE, MEM_RESET, PAGE_READONLY ); + ok( addr == ptr || broken(!addr && GetLastError() == ERROR_INVALID_PARAMETER), /* win9x */ + "VirtualAlloc failed with error %u\n", GetLastError() ); + + ret = VirtualFree( ptr, 0x10000, MEM_DECOMMIT ); + ok( !ret || broken(ret) /* win9x */, "VirtualFree succeeded\n" ); + if (!ret) + ok( GetLastError() == ERROR_INVALID_PARAMETER, "VirtualFree failed with %u\n", GetLastError() ); ret = UnmapViewOfFile(ptr2); ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError()); ret = UnmapViewOfFile(ptr); ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError()); CloseHandle(mapping); + + addr = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READONLY ); + ok( addr != NULL, "VirtualAlloc failed with error %u\n", GetLastError() ); + + SetLastError(0xdeadbeef); + ok( !UnmapViewOfFile(addr), "UnmapViewOfFile should fail on VirtualAlloc mem\n" ); + ok( GetLastError() == ERROR_INVALID_ADDRESS, + "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + SetLastError(0xdeadbeef); + ok( !UnmapViewOfFile((char *)addr + 0x3000), "UnmapViewOfFile should fail on VirtualAlloc mem\n" ); + ok( GetLastError() == ERROR_INVALID_ADDRESS, + "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + SetLastError(0xdeadbeef); + ok( !UnmapViewOfFile((void *)0xdeadbeef), "UnmapViewOfFile should fail on VirtualAlloc mem\n" ); + ok( GetLastError() == ERROR_INVALID_ADDRESS, + "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError()); + + ok( VirtualFree(addr, 0, MEM_RELEASE), "VirtualFree failed\n" ); } static DWORD (WINAPI *pNtMapViewOfSection)( HANDLE handle, HANDLE process, PVOID *addr_ptr, @@ -582,7 +792,7 @@ static void test_NtMapViewOfSection(void) pNtUnmapViewOfSection = (void *)GetProcAddress( GetModuleHandle("ntdll.dll"), "NtUnmapViewOfSection" ); if (!pNtMapViewOfSection || !pNtUnmapViewOfSection) { - skip( "NtMapViewOfSection not found\n" ); + win_skip( "NtMapViewOfSection not available\n" ); return; } @@ -622,6 +832,46 @@ static void test_NtMapViewOfSection(void) CloseHandle(hProcess); } +static void test_CreateFileMapping(void) +{ + HANDLE handle, handle2; + + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + handle = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000, + "Wine Test Mapping"); + ok( handle != NULL, "CreateFileMapping failed with error %u\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000, + "Wine Test Mapping"); + ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000, + "WINE TEST MAPPING"); + ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "Wine Test Mapping"); + ok( handle2 != NULL, "OpenFileMapping failed with error %d\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "WINE TEST MAPPING"); + ok( !handle2, "OpenFileMapping succeeded\n"); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_NAME /* win9x */, + "wrong error %u\n", GetLastError()); + + CloseHandle( handle ); +} + static void test_BadPtr(void) { void *ptr = (void*)1; @@ -631,6 +881,306 @@ static void test_BadPtr(void) ok(IsBadCodePtr(ptr),"IsBadCodePtr(1) failed.\n"); } +static void test_write_watch(void) +{ + char *base; + DWORD ret, size, old_prot; + MEMORY_BASIC_INFORMATION info; + void *results[64]; + ULONG_PTR count; + ULONG pagesize; + + if (!pGetWriteWatch || !pResetWriteWatch) + { + win_skip( "GetWriteWatch not supported\n" ); + return; + } + + size = 0x10000; + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE ); + if (!base && + (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED)) + { + win_skip( "MEM_WRITE_WATCH not supported\n" ); + return; + } + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ret = VirtualQuery( base, &info, sizeof(info) ); + ok(ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.AllocationProtect == PAGE_READWRITE, "wrong AllocationProtect %x\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); + + count = 64; + SetLastError( 0xdeadbeef ); + ret = pGetWriteWatch( 0, NULL, size, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || + broken( GetLastError() == 0xdeadbeef ), /* win98 */ + "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pGetWriteWatch( 0, GetModuleHandle(0), size, results, &count, &pagesize ); + if (ret) + { + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + } + else /* win98 */ + { + ok( count == 0, "wrong count %lu\n", count ); + } + + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 0, "wrong count %lu\n", count ); + + base[pagesize + 1] = 0x44; + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 0, "wrong count %lu\n", count ); + + base[2*pagesize + 3] = 0x11; + base[4*pagesize + 8] = 0x11; + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 2, "wrong count %lu\n", count ); + ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] ); + ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] ); + + count = 64; + ret = pGetWriteWatch( 0, base + 3*pagesize, 2*pagesize, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] ); + + ret = pResetWriteWatch( base, 3*pagesize ); + ok( !ret, "pResetWriteWatch failed %u\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] ); + + *(DWORD *)(base + 2*pagesize - 2) = 0xdeadbeef; + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 3, "wrong count %lu\n", count ); + ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); + ok( results[1] == base + 2*pagesize, "wrong result %p\n", results[1] ); + ok( results[2] == base + 4*pagesize, "wrong result %p\n", results[2] ); + + count = 1; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 2, "wrong count %lu\n", count ); + ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] ); + ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] ); + + /* changing protections doesn't affect watches */ + + ret = VirtualProtect( base, 3*pagesize, PAGE_READONLY, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + + ret = VirtualQuery( base, &info, sizeof(info) ); + ok(ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.RegionSize == 3*pagesize, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + ok( info.Protect == PAGE_READONLY, "wrong Protect 0x%x\n", info.Protect ); + + ret = VirtualProtect( base, 3*pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_READONLY, "wrong old prot %x\n", old_prot ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 2, "wrong count %lu\n", count ); + ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] ); + ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] ); + + ret = VirtualQuery( base, &info, sizeof(info) ); + ok(ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); + + /* some invalid parameter tests */ + + SetLastError( 0xdeadbeef ); + count = 0; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + if (ret) + { + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pGetWriteWatch( 0, base, size, results, NULL, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, NULL ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 0; + ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, size * 2, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base + size - pagesize, pagesize + 1, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pResetWriteWatch( base, 0 ); + ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pResetWriteWatch( GetModuleHandle(0), size ); + ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + } + else /* win98 is completely different */ + { + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); + ok( ret == ERROR_INVALID_PARAMETER, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == 0xdeadbeef, "wrong error %u\n", GetLastError() ); + + count = 0; + ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", ret ); + + count = 64; + ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", ret ); + + count = 64; + ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", ret ); + + ret = pResetWriteWatch( base, 0 ); + ok( !ret, "ResetWriteWatch failed %u\n", ret ); + + ret = pResetWriteWatch( GetModuleHandle(0), size ); + ok( !ret, "ResetWriteWatch failed %u\n", ret ); + } + + VirtualFree( base, 0, MEM_FREE ); + + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE ); + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + VirtualFree( base, 0, MEM_FREE ); + + base = VirtualAlloc( 0, size, MEM_WRITE_WATCH, PAGE_READWRITE ); + ok( !base, "VirtualAlloc succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + /* initial protect doesn't matter */ + + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_NOACCESS ); + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_NOACCESS ); + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 0, "wrong count %lu\n", count ); + + ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot ); + + base[5*pagesize + 200] = 3; + + ret = VirtualProtect( base, 6*pagesize, PAGE_NOACCESS, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); + + ret = VirtualFree( base, size, MEM_DECOMMIT ); + ok( ret, "VirtualFree failed %u\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1 || broken(count == 0), /* win98 */ + "wrong count %lu\n", count ); + if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); + + VirtualFree( base, 0, MEM_FREE ); +} + START_TEST(virtual) { int argc; @@ -662,10 +1212,14 @@ START_TEST(virtual) hkernel32 = GetModuleHandleA("kernel32.dll"); pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx"); pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx"); + pGetWriteWatch = (void *) GetProcAddress(hkernel32, "GetWriteWatch"); + pResetWriteWatch = (void *) GetProcAddress(hkernel32, "ResetWriteWatch"); test_VirtualAllocEx(); test_VirtualAlloc(); test_MapViewOfFile(); test_NtMapViewOfSection(); + test_CreateFileMapping(); test_BadPtr(); + test_write_watch(); } diff --git a/rostests/winetests/kernel32/volume.c b/rostests/winetests/kernel32/volume.c index 9a21db1badc..42142e82707 100644 --- a/rostests/winetests/kernel32/volume.c +++ b/rostests/winetests/kernel32/volume.c @@ -20,6 +20,7 @@ #include "wine/test.h" #include "winbase.h" +#include static HINSTANCE hdll; static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD); @@ -27,24 +28,54 @@ static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointW)(LPCWSTR, LPWSTR, DWORD static HANDLE (WINAPI *pFindFirstVolumeA)(LPSTR,DWORD); static BOOL (WINAPI *pFindNextVolumeA)(HANDLE,LPSTR,DWORD); static BOOL (WINAPI *pFindVolumeClose)(HANDLE); +static UINT (WINAPI *pGetLogicalDriveStringsA)(UINT,LPSTR); +static UINT (WINAPI *pGetLogicalDriveStringsW)(UINT,LPWSTR); +static BOOL (WINAPI *pGetVolumeInformationA)(LPCSTR, LPSTR, DWORD, LPDWORD, LPDWORD, LPDWORD, LPSTR, DWORD); /* ############################### */ static void test_query_dos_deviceA(void) { char drivestr[] = "a:"; - char *p, buffer[2000]; - DWORD ret; + char *p, *buffer, buffer2[2000]; + DWORD ret, ret2, buflen=32768; BOOL found = FALSE; + if (!pFindFirstVolumeA) { + win_skip("On win9x, HARDDISK and RAMDISK not present\n"); + return; + } + + buffer = HeapAlloc( GetProcessHeap(), 0, buflen ); + ret = QueryDosDeviceA( NULL, buffer, buflen ); + ok(ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER, + "QueryDosDevice buffer too small\n"); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + HeapFree( GetProcessHeap(), 0, buffer ); + return; + } + ok(ret, "QueryDosDeviceA failed to return list, last error %u\n", GetLastError()); + if (ret) { + p = buffer; + for (;;) { + if (!strlen(p)) break; + ret2 = QueryDosDeviceA( p, buffer2, sizeof(buffer2) ); + ok(ret2, "QueryDosDeviceA failed to return current mapping for %s, last error %u\n", p, GetLastError()); + p += strlen(p) + 1; + if (ret <= (p-buffer)) break; + } + } + for (;drivestr[0] <= 'z'; drivestr[0]++) { - ret = QueryDosDeviceA( drivestr, buffer, sizeof(buffer)); + /* Older W2K fails with ERROR_INSUFFICIENT_BUFFER when buflen is > 32767 */ + ret = QueryDosDeviceA( drivestr, buffer, buflen - 1); if(ret) { for (p = buffer; *p; p++) *p = toupper(*p); if (strstr(buffer, "HARDDISK") || strstr(buffer, "RAMDISK")) found = TRUE; } } - todo_wine ok(found, "expected at least one devicename to contain HARDDISK or RAMDISK\n"); + ok(found, "expected at least one devicename to contain HARDDISK or RAMDISK\n"); + HeapFree( GetProcessHeap(), 0, buffer ); } static void test_FindFirstVolume(void) @@ -84,7 +115,8 @@ static void test_GetVolumeNameForVolumeMountPointA(void) { BOOL ret; char volume[MAX_PATH], path[] = "c:\\"; - DWORD len = sizeof(volume); + DWORD len = sizeof(volume), reti; + char temp_path[MAX_PATH]; /* not present before w2k */ if (!pGetVolumeNameForVolumeMountPointA) { @@ -92,8 +124,15 @@ static void test_GetVolumeNameForVolumeMountPointA(void) return; } + reti = GetTempPathA(MAX_PATH, temp_path); + ok(reti != 0, "GetTempPathA error %d\n", GetLastError()); + ok(reti < MAX_PATH, "temp path should fit into MAX_PATH\n"); + ret = pGetVolumeNameForVolumeMountPointA(path, volume, 0); ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n"); + ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE || + GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */ + "wrong error, last=%d\n", GetLastError()); if (0) { /* these crash on XP */ ret = pGetVolumeNameForVolumeMountPointA(path, NULL, len); @@ -105,6 +144,43 @@ static void test_GetVolumeNameForVolumeMountPointA(void) ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); + ok(!strncmp( volume, "\\\\?\\Volume{", 11), + "GetVolumeNameForVolumeMountPointA failed to return valid string <%s>\n", + volume); + + /* test with too small buffer */ + ret = pGetVolumeNameForVolumeMountPointA(path, volume, 10); + ok(ret == FALSE && GetLastError() == ERROR_FILENAME_EXCED_RANGE, + "GetVolumeNameForVolumeMountPointA failed, wrong error returned, was %d, should be ERROR_FILENAME_EXCED_RANGE\n", + GetLastError()); + + /* Try on a arbitrary directory */ + ret = pGetVolumeNameForVolumeMountPointA(temp_path, volume, len); + ok(ret == FALSE && GetLastError() == ERROR_NOT_A_REPARSE_POINT, + "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", + temp_path, GetLastError()); + + /* Try on a nonexistent dos drive */ + path[2] = 0; + for (;path[0] <= 'z'; path[0]++) { + ret = QueryDosDeviceA( path, volume, len); + if(!ret) break; +} + if (path[0] <= 'z') + { + path[2] = '\\'; + ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); + ok(ret == FALSE && GetLastError() == ERROR_FILE_NOT_FOUND, + "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", + path, GetLastError()); + + /* Try without trailing \ and on a nonexistent dos drive */ + path[2] = 0; + ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); + ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME, + "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", + path, GetLastError()); + } } static void test_GetVolumeNameForVolumeMountPointW(void) @@ -121,6 +197,9 @@ static void test_GetVolumeNameForVolumeMountPointW(void) ret = pGetVolumeNameForVolumeMountPointW(path, volume, 0); ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n"); + ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE || + GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */ + "wrong error, last=%d\n", GetLastError()); if (0) { /* these crash on XP */ ret = pGetVolumeNameForVolumeMountPointW(path, NULL, len); @@ -134,6 +213,232 @@ static void test_GetVolumeNameForVolumeMountPointW(void) ok(ret == TRUE, "GetVolumeNameForVolumeMountPointW failed\n"); } +static void test_GetLogicalDriveStringsA(void) +{ + UINT size, size2; + char *buf, *ptr; + + if(!pGetLogicalDriveStringsA) { + win_skip("GetLogicalDriveStringsA not available\n"); + return; + } + + size = pGetLogicalDriveStringsA(0, NULL); + ok(size%4 == 1, "size = %d\n", size); + + buf = HeapAlloc(GetProcessHeap(), 0, size); + + *buf = 0; + size2 = pGetLogicalDriveStringsA(2, buf); + ok(size2 == size, "size2 = %d\n", size2); + ok(!*buf, "buf changed\n"); + + size2 = pGetLogicalDriveStringsA(size, buf); + ok(size2 == size-1, "size2 = %d\n", size2); + + for(ptr = buf; ptr < buf+size2; ptr += 4) { + ok(('A' <= *ptr && *ptr <= 'Z') || + (broken('a' <= *ptr && *ptr <= 'z')), /* Win9x and WinMe */ + "device name '%c' is not uppercase\n", *ptr); + ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]); + ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]); + ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]); + } + ok(!*ptr, "buf[size2] is not nullbyte\n"); + + HeapFree(GetProcessHeap(), 0, buf); +} + +static void test_GetLogicalDriveStringsW(void) +{ + UINT size, size2; + WCHAR *buf, *ptr; + + if(!pGetLogicalDriveStringsW) { + win_skip("GetLogicalDriveStringsW not available\n"); + return; + } + + SetLastError(0xdeadbeef); + size = pGetLogicalDriveStringsW(0, NULL); + if (size == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + win_skip("GetLogicalDriveStringsW not implemented\n"); + return; + } + ok(size%4 == 1, "size = %d\n", size); + + buf = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); + + *buf = 0; + size2 = pGetLogicalDriveStringsW(2, buf); + ok(size2 == size, "size2 = %d\n", size2); + ok(!*buf, "buf changed\n"); + + size2 = pGetLogicalDriveStringsW(size, buf); + ok(size2 == size-1, "size2 = %d\n", size2); + + for(ptr = buf; ptr < buf+size2; ptr += 4) { + ok('A' <= *ptr && *ptr <= 'Z', "device name '%c' is not uppercase\n", *ptr); + ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]); + ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]); + ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]); + } + ok(!*ptr, "buf[size2] is not nullbyte\n"); + + HeapFree(GetProcessHeap(), 0, buf); +} + +static void test_GetVolumeInformationA(void) +{ + BOOL ret; + UINT result; + char Root_Dir0[]="C:"; + char Root_Dir1[]="C:\\"; + char Root_Dir2[]="\\\\?\\C:\\"; + char volume[MAX_PATH+1]; + DWORD vol_name_size=MAX_PATH+1, vol_serial_num=-1, max_comp_len=0, fs_flags=0, fs_name_len=MAX_PATH+1; + char vol_name_buf[MAX_PATH+1], fs_name_buf[MAX_PATH+1]; + char windowsdir[MAX_PATH+10]; + char currentdir[MAX_PATH+1]; + + if (!pGetVolumeInformationA) { + win_skip("GetVolumeInformationA not found\n"); + return; + } + if (!pGetVolumeNameForVolumeMountPointA) { + win_skip("GetVolumeNameForVolumeMountPointA not found\n"); + return; + } + + /* get windows drive letter and update strings for testing */ + result = GetWindowsDirectory(windowsdir, sizeof(windowsdir)); + ok(result < sizeof(windowsdir), "windowsdir is abnormally long!\n"); + ok(result != 0, "GetWindowsDirectory: error %d\n", GetLastError()); + Root_Dir0[0] = windowsdir[0]; + Root_Dir1[0] = windowsdir[0]; + Root_Dir2[4] = windowsdir[0]; + + /* get the unique volume name for the windows drive */ + ret = pGetVolumeNameForVolumeMountPointA(Root_Dir1, volume, MAX_PATH); + ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); + + result = GetCurrentDirectory(MAX_PATH, currentdir); + ok(result, "GetCurrentDirectory: error %d\n", GetLastError()); + + /* **** now start the tests **** */ + /* check for error on no trailing \ */ + if (result > 3) + { + ret = pGetVolumeInformationA(Root_Dir0, vol_name_buf, vol_name_size, NULL, + NULL, NULL, fs_name_buf, fs_name_len); + ok(!ret && GetLastError() == ERROR_INVALID_NAME, + "GetVolumeInformationA w/o '\\' did not fail, last error %u\n", GetLastError()); + } + else + skip("Running on a root directory\n"); + + /* check for error on no trailing \ when current dir is root dir */ + ret = SetCurrentDirectory(Root_Dir1); + ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ret = pGetVolumeInformationA(Root_Dir0, vol_name_buf, vol_name_size, NULL, + NULL, NULL, fs_name_buf, fs_name_len); + todo_wine + ok(ret, "GetVolumeInformationA failed, last error %u\n", GetLastError()); + + /* check for error on no trailing \ when current dir is windows dir */ + ret = SetCurrentDirectory(windowsdir); + ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + ret = pGetVolumeInformationA(Root_Dir0, vol_name_buf, vol_name_size, NULL, + NULL, NULL, fs_name_buf, fs_name_len); + ok(!ret && GetLastError() == ERROR_INVALID_NAME, + "GetVolumeInformationA did not fail, last error %u\n", GetLastError()); + + /* reset current directory */ + ret = SetCurrentDirectory(currentdir); + ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); + + /* try null root directory to return "root of the current directory" */ + ret = pGetVolumeInformationA(NULL, vol_name_buf, vol_name_size, NULL, + NULL, NULL, fs_name_buf, fs_name_len); + ok(ret, "GetVolumeInformationA failed on null root dir, last error %u\n", GetLastError()); + + /* Try normal drive letter with trailing \ */ + ret = pGetVolumeInformationA(Root_Dir1, vol_name_buf, vol_name_size, + &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); + ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Dir1, GetLastError()); + + /* try again with dirve letter and the "disable parsing" prefix */ + ret = pGetVolumeInformationA(Root_Dir2, vol_name_buf, vol_name_size, + &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); + todo_wine ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Dir2, GetLastError()); + + /* try again with unique voluem name */ + ret = pGetVolumeInformationA(volume, vol_name_buf, vol_name_size, + &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); + todo_wine ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", volume, GetLastError()); + + /* try again with device name space */ + Root_Dir2[2] = '.'; + ret = pGetVolumeInformationA(Root_Dir2, vol_name_buf, vol_name_size, + &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); + todo_wine ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Dir2, GetLastError()); + + /* try again with a directory off the root - should generate error */ + if (windowsdir[strlen(windowsdir)-1] != '\\') strcat(windowsdir, "\\"); + ret = pGetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size, + &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); + todo_wine ok(!ret && GetLastError()==ERROR_DIR_NOT_ROOT, + "GetVolumeInformationA failed, root=%s, last error=%u\n", windowsdir, GetLastError()); +} + +/* Test to check that unique volume name from windows dir mount point */ +/* matches at least one of the unique volume names returned from the */ +/* FindFirstVolumeA/FindNextVolumeA list. */ +static void test_enum_vols(void) +{ + DWORD ret; + HANDLE hFind = INVALID_HANDLE_VALUE; + char Volume_1[MAX_PATH] = {0}; + char Volume_2[MAX_PATH] = {0}; + char path[] = "c:\\"; + BOOL found = FALSE; + char windowsdir[MAX_PATH]; + + if (!pGetVolumeNameForVolumeMountPointA) { + win_skip("GetVolumeNameForVolumeMountPointA not found\n"); + return; + } + + /*get windows drive letter and update strings for testing */ + ret = GetWindowsDirectory( windowsdir, sizeof(windowsdir) ); + ok(ret < sizeof(windowsdir), "windowsdir is abnormally long!\n"); + ok(ret != 0, "GetWindowsDirecory: error %d\n", GetLastError()); + path[0] = windowsdir[0]; + + /* get the unique volume name for the windows drive */ + ret = pGetVolumeNameForVolumeMountPointA( path, Volume_1, MAX_PATH ); + ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); + ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name %s\n", Volume_1); + + /* get first unique volume name of list */ + hFind = pFindFirstVolumeA( Volume_2, MAX_PATH ); + ok(hFind != INVALID_HANDLE_VALUE, "FindFirstVolume failed, err=%u\n", + GetLastError()); + + do + { + /* validate correct length of unique volume name */ + ok(strlen(Volume_2) == 49, "Find[First/Next]Volume returned wrong length name %s\n", Volume_1); + if (memcmp(Volume_1, Volume_2, 49) == 0) + { + found = TRUE; + break; + } + } while (pFindNextVolumeA( hFind, Volume_2, MAX_PATH )); + ok(found, "volume name %s not found by Find[First/Next]Volume\n", Volume_1); + pFindVolumeClose( hFind ); +} + START_TEST(volume) { hdll = GetModuleHandleA("kernel32.dll"); @@ -142,9 +447,16 @@ START_TEST(volume) pFindFirstVolumeA = (void *) GetProcAddress(hdll, "FindFirstVolumeA"); pFindNextVolumeA = (void *) GetProcAddress(hdll, "FindNextVolumeA"); pFindVolumeClose = (void *) GetProcAddress(hdll, "FindVolumeClose"); + pGetLogicalDriveStringsA = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsA"); + pGetLogicalDriveStringsW = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsW"); + pGetVolumeInformationA = (void *) GetProcAddress(hdll, "GetVolumeInformationA"); test_query_dos_deviceA(); test_FindFirstVolume(); test_GetVolumeNameForVolumeMountPointA(); test_GetVolumeNameForVolumeMountPointW(); + test_GetLogicalDriveStringsA(); + test_GetLogicalDriveStringsW(); + test_GetVolumeInformationA(); + test_enum_vols(); } diff --git a/rostests/winetests/localspl/localmon.c b/rostests/winetests/localspl/localmon.c new file mode 100644 index 00000000000..23a3608d649 --- /dev/null +++ b/rostests/winetests/localspl/localmon.c @@ -0,0 +1,1457 @@ +/* + * Unit test suite for localspl API functions: local print monitor + * + * Copyright 2006-2007 Detlef Riekenberg + * + * 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 + * + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wingdi.h" +#include "winreg.h" + +#include "winspool.h" +#include "ddk/winsplp.h" + +#include "wine/test.h" + + +/* ##### */ + +static HMODULE hdll; +static HMODULE hlocalmon; +static LPMONITOREX (WINAPI *pInitializePrintMonitor)(LPWSTR); + +static LPMONITOREX pm; +static BOOL (WINAPI *pEnumPorts)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD); +static BOOL (WINAPI *pOpenPort)(LPWSTR, PHANDLE); +static BOOL (WINAPI *pOpenPortEx)(LPWSTR, LPWSTR, PHANDLE, struct _MONITOR *); +static BOOL (WINAPI *pStartDocPort)(HANDLE, LPWSTR, DWORD, DWORD, LPBYTE); +static BOOL (WINAPI *pWritePort)(HANDLE hPort, LPBYTE, DWORD, LPDWORD); +static BOOL (WINAPI *pReadPort)(HANDLE hPort, LPBYTE, DWORD, LPDWORD); +static BOOL (WINAPI *pEndDocPort)(HANDLE); +static BOOL (WINAPI *pClosePort)(HANDLE); +static BOOL (WINAPI *pAddPort)(LPWSTR, HWND, LPWSTR); +static BOOL (WINAPI *pAddPortEx)(LPWSTR, DWORD, LPBYTE, LPWSTR); +static BOOL (WINAPI *pConfigurePort)(LPWSTR, HWND, LPWSTR); +static BOOL (WINAPI *pDeletePort)(LPWSTR, HWND, LPWSTR); +static BOOL (WINAPI *pGetPrinterDataFromPort)(HANDLE, DWORD, LPWSTR, LPWSTR, DWORD, LPWSTR, DWORD, LPDWORD); +static BOOL (WINAPI *pSetPortTimeOuts)(HANDLE, LPCOMMTIMEOUTS, DWORD); +static BOOL (WINAPI *pXcvOpenPort)(LPCWSTR, ACCESS_MASK, PHANDLE phXcv); +static DWORD (WINAPI *pXcvDataPort)(HANDLE, LPCWSTR, PBYTE, DWORD, PBYTE, DWORD, PDWORD); +static BOOL (WINAPI *pXcvClosePort)(HANDLE); + +static HANDLE hXcv; +static HANDLE hXcv_noaccess; + +/* ########################### */ + +static const WCHAR cmd_AddPortW[] = {'A','d','d','P','o','r','t',0}; +static const WCHAR cmd_ConfigureLPTPortCommandOKW[] = {'C','o','n','f','i','g','u','r','e', + 'L','P','T','P','o','r','t', + 'C','o','m','m','a','n','d','O','K',0}; +static WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0}; +static WCHAR cmd_GetTransmissionRetryTimeoutW[] = {'G','e','t', + 'T','r','a','n','s','m','i','s','s','i','o','n', + 'R','e','t','r','y','T','i','m','e','o','u','t',0}; + +static WCHAR cmd_MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0}; +static WCHAR cmd_MonitorUI_lcaseW[] = {'m','o','n','i','t','o','r','u','i',0}; +static WCHAR cmd_PortIsValidW[] = {'P','o','r','t','I','s','V','a','l','i','d',0}; +static WCHAR does_not_existW[] = {'d','o','e','s','_','n','o','t','_','e','x','i','s','t',0}; +static CHAR emptyA[] = ""; +static WCHAR emptyW[] = {0}; +static WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0}; +static WCHAR Monitors_LocalPortW[] = { + 'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\', + 'P','r','i','n','t','\\', + 'M','o','n','i','t','o','r','s','\\', + 'L','o','c','a','l',' ','P','o','r','t',0}; + +static CHAR num_0A[] = "0"; +static WCHAR num_0W[] = {'0',0}; +static CHAR num_1A[] = "1"; +static WCHAR num_1W[] = {'1',0}; +static CHAR num_999999A[] = "999999"; +static WCHAR num_999999W[] = {'9','9','9','9','9','9',0}; +static CHAR num_1000000A[] = "1000000"; +static WCHAR num_1000000W[] = {'1','0','0','0','0','0','0',0}; + +static WCHAR portname_comW[] = {'C','O','M',0}; +static WCHAR portname_com1W[] = {'C','O','M','1',':',0}; +static WCHAR portname_com2W[] = {'C','O','M','2',':',0}; +static WCHAR portname_fileW[] = {'F','I','L','E',':',0}; +static WCHAR portname_lptW[] = {'L','P','T',0}; +static WCHAR portname_lpt1W[] = {'L','P','T','1',':',0}; +static WCHAR portname_lpt2W[] = {'L','P','T','2',':',0}; +static WCHAR server_does_not_existW[] = {'\\','\\','d','o','e','s','_','n','o','t','_','e','x','i','s','t',0}; + +static CHAR TransmissionRetryTimeoutA[] = {'T','r','a','n','s','m','i','s','s','i','o','n', + 'R','e','t','r','y','T','i','m','e','o','u','t',0}; + +static CHAR WinNT_CV_WindowsA[] = {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s',' ','N','T','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'W','i','n','d','o','w','s',0}; +static WCHAR wineW[] = {'W','i','n','e',0}; + +static WCHAR tempdirW[MAX_PATH]; +static WCHAR tempfileW[MAX_PATH]; + +#define PORTNAME_PREFIX 3 +#define PORTNAME_MINSIZE 5 +#define PORTNAME_MAXSIZE 10 +static WCHAR have_com[PORTNAME_MAXSIZE]; +static WCHAR have_lpt[PORTNAME_MAXSIZE]; +static WCHAR have_file[PORTNAME_MAXSIZE]; + +/* ########################### */ + +static DWORD delete_port(LPWSTR portname) +{ + DWORD res; + + if (pDeletePort) { + res = pDeletePort(NULL, 0, portname); + } + else + { + res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) portname, (lstrlenW(portname) + 1) * sizeof(WCHAR), NULL, 0, NULL); + } + return res; +} + +/* ########################### */ + +static void find_installed_ports(void) +{ + PORT_INFO_1W * pi = NULL; + WCHAR nameW[PORTNAME_MAXSIZE]; + DWORD needed; + DWORD returned; + DWORD res; + DWORD id; + + have_com[0] = '\0'; + have_lpt[0] = '\0'; + have_file[0] = '\0'; + + if (!pEnumPorts) return; + + res = pEnumPorts(NULL, 1, NULL, 0, &needed, &returned); + if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { + pi = HeapAlloc(GetProcessHeap(), 0, needed); + } + res = pEnumPorts(NULL, 1, (LPBYTE) pi, needed, &needed, &returned); + + if (!res) { + skip("no ports found\n"); + HeapFree(GetProcessHeap(), 0, pi); + return; + } + + id = 0; + while (id < returned) { + res = lstrlenW(pi[id].pName); + if ((res >= PORTNAME_MINSIZE) && (res < PORTNAME_MAXSIZE) && + (pi[id].pName[res-1] == ':')) { + /* copy only the prefix ("LPT" or "COM") */ + memcpy(&nameW, pi[id].pName, PORTNAME_PREFIX * sizeof(WCHAR)); + nameW[PORTNAME_PREFIX] = '\0'; + + if (!have_com[0] && (lstrcmpiW(nameW, portname_comW) == 0)) { + memcpy(&have_com, pi[id].pName, (res+1) * sizeof(WCHAR)); + } + + if (!have_lpt[0] && (lstrcmpiW(nameW, portname_lptW) == 0)) { + memcpy(&have_lpt, pi[id].pName, (res+1) * sizeof(WCHAR)); + } + + if (!have_file[0] && (lstrcmpiW(pi[id].pName, portname_fileW) == 0)) { + memcpy(&have_file, pi[id].pName, (res+1) * sizeof(WCHAR)); + } + } + id++; + } + + HeapFree(GetProcessHeap(), 0, pi); +} + +/* ########################### */ + +static void test_AddPort(void) +{ + DWORD res; + + /* moved to localui.dll since w2k */ + if (!pAddPort) return; + + if (0) + { + /* NT4 crash on this test */ + res = pAddPort(NULL, 0, NULL); + } + + /* Testing-Results (localmon.dll from NT4.0): + - The Servername is ignored + - Case of MonitorName is ignored + */ + + SetLastError(0xdeadbeef); + res = pAddPort(NULL, 0, emptyW); + ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pAddPort(NULL, 0, does_not_existW); + ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError()); + +} + +/* ########################### */ + +static void test_AddPortEx(void) +{ + PORT_INFO_2W pi; + DWORD res; + + if (!pAddPortEx) { + skip("AddPortEx\n"); + return; + } + if ((!pDeletePort) && (!hXcv)) { + skip("No API to delete a Port\n"); + return; + } + + /* start test with clean ports */ + delete_port(tempfileW); + + pi.pPortName = tempfileW; + if (0) { + /* tests crash with native localspl.dll in w2k, + but works with native localspl.dll in wine */ + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW); + trace("returned %u with %u\n", res, GetLastError() ); + ok( res, "got %u with %u (expected '!= 0')\n", res, GetLastError()); + + /* port already exists: */ + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW); + trace("returned %u with %u\n", res, GetLastError() ); + ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER), + "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); + delete_port(tempfileW); + + + /* NULL for pMonitorName is documented for Printmonitors, but + localspl.dll fails always with ERROR_INVALID_PARAMETER */ + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 1, (LPBYTE) &pi, NULL); + trace("returned %u with %u\n", res, GetLastError() ); + ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER), + "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); + if (res) delete_port(tempfileW); + + + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 1, (LPBYTE) &pi, emptyW); + trace("returned %u with %u\n", res, GetLastError() ); + ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER), + "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); + if (res) delete_port(tempfileW); + + + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 1, (LPBYTE) &pi, does_not_existW); + trace("returned %u with %u\n", res, GetLastError() ); + ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER), + "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); + if (res) delete_port(tempfileW); + } + + pi.pPortName = NULL; + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW); + ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER), + "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); + + /* level 2 is documented as supported for Printmonitors, + but localspl.dll fails always with ERROR_INVALID_LEVEL */ + + pi.pPortName = tempfileW; + pi.pMonitorName = LocalPortW; + pi.pDescription = wineW; + pi.fPortType = PORT_TYPE_WRITE; + + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 2, (LPBYTE) &pi, LocalPortW); + ok( !res && (GetLastError() == ERROR_INVALID_LEVEL), + "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n", + res, GetLastError()); + if (res) delete_port(tempfileW); + + + /* invalid levels */ + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 0, (LPBYTE) &pi, LocalPortW); + ok( !res && (GetLastError() == ERROR_INVALID_LEVEL), + "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n", + res, GetLastError()); + if (res) delete_port(tempfileW); + + + SetLastError(0xdeadbeef); + res = pAddPortEx(NULL, 3, (LPBYTE) &pi, LocalPortW); + ok( !res && (GetLastError() == ERROR_INVALID_LEVEL), + "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n", + res, GetLastError()); + if (res) delete_port(tempfileW); + + /* cleanup */ + delete_port(tempfileW); +} + +/* ########################### */ + +static void test_ClosePort(void) +{ + HANDLE hPort; + HANDLE hPort2; + LPWSTR nameW = NULL; + DWORD res; + DWORD res2; + + + if (!pOpenPort || !pClosePort) return; + + if (have_com[0]) { + nameW = have_com; + + hPort = (HANDLE) 0xdeadbeef; + res = pOpenPort(nameW, &hPort); + hPort2 = (HANDLE) 0xdeadbeef; + res2 = pOpenPort(nameW, &hPort2); + + if (res2 && (hPort2 != hPort)) { + SetLastError(0xdeadbeef); + res2 = pClosePort(hPort2); + ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError()); + } + + if (res) { + SetLastError(0xdeadbeef); + res = pClosePort(hPort); + ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError()); + } + } + + + if (have_lpt[0]) { + nameW = have_lpt; + + hPort = (HANDLE) 0xdeadbeef; + res = pOpenPort(nameW, &hPort); + hPort2 = (HANDLE) 0xdeadbeef; + res2 = pOpenPort(nameW, &hPort2); + + if (res2 && (hPort2 != hPort)) { + SetLastError(0xdeadbeef); + res2 = pClosePort(hPort2); + ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError()); + } + + if (res) { + SetLastError(0xdeadbeef); + res = pClosePort(hPort); + ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError()); + } + } + + + if (have_file[0]) { + nameW = have_file; + + hPort = (HANDLE) 0xdeadbeef; + res = pOpenPort(nameW, &hPort); + hPort2 = (HANDLE) 0xdeadbeef; + res2 = pOpenPort(nameW, &hPort2); + + if (res2 && (hPort2 != hPort)) { + SetLastError(0xdeadbeef); + res2 = pClosePort(hPort2); + ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError()); + } + + if (res) { + SetLastError(0xdeadbeef); + res = pClosePort(hPort); + ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError()); + } + + } + + if (0) { + /* an invalid HANDLE crash native localspl.dll */ + + SetLastError(0xdeadbeef); + res = pClosePort(NULL); + trace("got %u with %u\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pClosePort( (HANDLE) 0xdeadbeef); + trace("got %u with %u\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pClosePort(INVALID_HANDLE_VALUE); + trace("got %u with %u\n", res, GetLastError()); + } + +} + +/* ########################### */ + +static void test_ConfigurePort(void) +{ + DWORD res; + + /* moved to localui.dll since w2k */ + if (!pConfigurePort) return; + + if (0) + { + /* NT4 crash on this test */ + res = pConfigurePort(NULL, 0, NULL); + } + + /* Testing-Results (localmon.dll from NT4.0): + - Case of Portname is ignored + - "COM1:" and "COM01:" are the same (Compared by value) + - Portname without ":" => Dialog "Nothing to configure" comes up; Success + - "LPT1:", "LPT0:" and "LPT:" are the same (Numbers in "LPT:" are ignored) + - Empty Servername (LPT1:) => Dialog comes up (Servername is ignored) + - "FILE:" => Dialog "Nothing to configure" comes up; Success + - Empty Portname => => Dialog "Nothing to configure" comes up; Success + - Port "does_not_exist" => Dialog "Nothing to configure" comes up; Success + */ + if (winetest_interactive > 0) { + + SetLastError(0xdeadbeef); + res = pConfigurePort(NULL, 0, portname_com1W); + trace("returned %d with %u\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pConfigurePort(NULL, 0, portname_lpt1W); + trace("returned %d with %u\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pConfigurePort(NULL, 0, portname_fileW); + trace("returned %d with %u\n", res, GetLastError()); + } +} + +/* ########################### */ + +static void test_DeletePort(void) +{ + DWORD res; + + /* moved to localui.dll since w2k */ + if (!pDeletePort) return; + + if (0) + { + /* NT4 crash on this test */ + res = pDeletePort(NULL, 0, NULL); + } + + /* Testing-Results (localmon.dll from NT4.0): + - Case of Portname is ignored (returned '1' on Success) + - "COM1:" and "COM01:" are different (Compared as string) + - server_does_not_exist (LPT1:) => Port deleted, Success (Servername is ignored) + - Empty Portname => => FALSE (LastError not changed) + - Port "does_not_exist" => FALSE (LastError not changed) + */ + + SetLastError(0xdeadbeef); + res = pDeletePort(NULL, 0, emptyW); + ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pDeletePort(NULL, 0, does_not_existW); + ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError()); + +} + +/* ########################### */ + +static void test_EnumPorts(void) +{ + DWORD res; + DWORD level; + LPBYTE buffer; + DWORD cbBuf; + DWORD pcbNeeded; + DWORD pcReturned; + + if (!pEnumPorts) return; + + /* valid levels are 1 and 2 */ + for(level = 0; level < 4; level++) { + + cbBuf = 0xdeadbeef; + pcReturned = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pEnumPorts(NULL, level, NULL, 0, &cbBuf, &pcReturned); + + /* use only a short test, when we test with an invalid level */ + if(!level || (level > 2)) { + /* NT4 fails with ERROR_INVALID_LEVEL (as expected) + XP succeeds with ERROR_SUCCESS () */ + ok( (cbBuf == 0) && (pcReturned == 0), + "(%d) returned %d with %u and %d, %d (expected 0, 0)\n", + level, res, GetLastError(), cbBuf, pcReturned); + continue; + } + + ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), + "(%d) returned %d with %u and %d, %d (expected '0' with " + "ERROR_INSUFFICIENT_BUFFER)\n", + level, res, GetLastError(), cbBuf, pcReturned); + + buffer = HeapAlloc(GetProcessHeap(), 0, cbBuf * 2); + if (buffer == NULL) continue; + + pcbNeeded = 0xdeadbeef; + pcReturned = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pEnumPorts(NULL, level, buffer, cbBuf, &pcbNeeded, &pcReturned); + ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n", + level, res, GetLastError(), pcbNeeded, pcReturned); + /* We can compare the returned Data with the Registry / "win.ini",[Ports] here */ + + pcbNeeded = 0xdeadbeef; + pcReturned = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pEnumPorts(NULL, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned); + ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n", + level, res, GetLastError(), pcbNeeded, pcReturned); + + pcbNeeded = 0xdeadbeef; + pcReturned = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pEnumPorts(NULL, level, buffer, cbBuf-1, &pcbNeeded, &pcReturned); + ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), + "(%d) returned %d with %u and %d, %d (expected '0' with " + "ERROR_INSUFFICIENT_BUFFER)\n", + level, res, GetLastError(), pcbNeeded, pcReturned); + + if (0) + { + /* The following tests crash this app with native localmon/localspl */ + res = pEnumPorts(NULL, level, NULL, cbBuf, &pcbNeeded, &pcReturned); + res = pEnumPorts(NULL, level, buffer, cbBuf, NULL, &pcReturned); + res = pEnumPorts(NULL, level, buffer, cbBuf, &pcbNeeded, NULL); + } + + /* The Servername is ignored */ + pcbNeeded = 0xdeadbeef; + pcReturned = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pEnumPorts(emptyW, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned); + ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n", + level, res, GetLastError(), pcbNeeded, pcReturned); + + pcbNeeded = 0xdeadbeef; + pcReturned = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pEnumPorts(server_does_not_existW, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned); + ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n", + level, res, GetLastError(), pcbNeeded, pcReturned); + + HeapFree(GetProcessHeap(), 0, buffer); + } +} + +/* ########################### */ + + +static void test_InitializePrintMonitor(void) +{ + LPMONITOREX res; + + SetLastError(0xdeadbeef); + res = pInitializePrintMonitor(NULL); + /* The Parameter was unchecked before w2k */ + ok( res || (GetLastError() == ERROR_INVALID_PARAMETER), + "returned %p with %u\n (expected '!= NULL' or: NULL with " + "ERROR_INVALID_PARAMETER)\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pInitializePrintMonitor(emptyW); + ok( res || (GetLastError() == ERROR_INVALID_PARAMETER), + "returned %p with %u\n (expected '!= NULL' or: NULL with " + "ERROR_INVALID_PARAMETER)\n", res, GetLastError()); + + + /* Every call with a non-empty string returns the same Pointer */ + SetLastError(0xdeadbeef); + res = pInitializePrintMonitor(Monitors_LocalPortW); + ok( res == pm, + "returned %p with %u (expected %p)\n", res, GetLastError(), pm); +} + + +/* ########################### */ + +static void test_OpenPort(void) +{ + HANDLE hPort; + HANDLE hPort2; + LPWSTR nameW = NULL; + DWORD res; + DWORD res2; + + if (!pOpenPort || !pClosePort) return; + + if (have_com[0]) { + nameW = have_com; + + hPort = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pOpenPort(nameW, &hPort); + ok( res, "got %u with %u and %p (expected '!= 0')\n", + res, GetLastError(), hPort); + + /* the same HANDLE is returned for a second OpenPort in native localspl */ + hPort2 = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res2 = pOpenPort(nameW, &hPort2); + ok( res2, "got %u with %u and %p (expected '!= 0')\n", + res2, GetLastError(), hPort2); + + if (res) pClosePort(hPort); + if (res2 && (hPort2 != hPort)) pClosePort(hPort2); + } + + if (have_lpt[0]) { + nameW = have_lpt; + + hPort = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pOpenPort(nameW, &hPort); + ok( res || (GetLastError() == ERROR_ACCESS_DENIED), + "got %u with %u and %p (expected '!= 0' or '0' with ERROR_ACCESS_DENIED)\n", + res, GetLastError(), hPort); + + /* the same HANDLE is returned for a second OpenPort in native localspl */ + hPort2 = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res2 = pOpenPort(nameW, &hPort2); + ok( res2 || (GetLastError() == ERROR_ACCESS_DENIED), + "got %u with %u and %p (expected '!= 0' or '0' with ERROR_ACCESS_DENIED)\n", + res2, GetLastError(), hPort2); + + if (res) pClosePort(hPort); + if (res2 && (hPort2 != hPort)) pClosePort(hPort2); + } + + if (have_file[0]) { + nameW = have_file; + + hPort = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pOpenPort(nameW, &hPort); + ok( res, "got %u with %u and %p (expected '!= 0')\n", + res, GetLastError(), hPort); + + /* a different HANDLE is returned for a second OpenPort */ + hPort2 = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res2 = pOpenPort(nameW, &hPort2); + ok( res2 && (hPort2 != hPort), + "got %u with %u and %p (expected '!= 0' and '!= %p')\n", + res2, GetLastError(), hPort2, hPort); + + if (res) pClosePort(hPort); + if (res2 && (hPort2 != hPort)) pClosePort(hPort2); + } + + if (0) { + /* this test crash native localspl (w2k+xp) */ + if (nameW) { + hPort = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pOpenPort(nameW, NULL); + trace("got %u with %u and %p\n", res, GetLastError(), hPort); + } + } + + hPort = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pOpenPort(does_not_existW, &hPort); + ok (!res && (hPort == (HANDLE) 0xdeadbeef), + "got %u with 0x%x and %p (expected '0' and 0xdeadbeef)\n", res, GetLastError(), hPort); + if (res) pClosePort(hPort); + + hPort = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pOpenPort(emptyW, &hPort); + ok (!res && (hPort == (HANDLE) 0xdeadbeef), + "got %u with 0x%x and %p (expected '0' and 0xdeadbeef)\n", res, GetLastError(), hPort); + if (res) pClosePort(hPort); + + + /* NULL as name crash native localspl (w2k+xp) */ + if (0) { + hPort = (HANDLE) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pOpenPort(NULL, &hPort); + trace("got %u with %u and %p\n", res, GetLastError(), hPort); + } + +} + +/* ########################### */ + +static void test_XcvClosePort(void) +{ + DWORD res; + HANDLE hXcv2; + + + if (0) + { + /* crash with native localspl.dll (w2k+xp) */ + res = pXcvClosePort(NULL); + res = pXcvClosePort(INVALID_HANDLE_VALUE); + } + + + SetLastError(0xdeadbeef); + hXcv2 = (HANDLE) 0xdeadbeef; + res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv2); + ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2); + + if (res) { + SetLastError(0xdeadbeef); + res = pXcvClosePort(hXcv2); + ok( res, "returned %d with %u (expected '!= 0')\n", res, GetLastError()); + + if (0) + { + /* test for "Double Free": crash with native localspl.dll (w2k+xp) */ + res = pXcvClosePort(hXcv2); + } + } +} + +/* ########################### */ + +static void test_XcvDataPort_AddPort(void) +{ + DWORD res; + + + /* + * The following tests crash with native localspl.dll on w2k and xp, + * but it works, when the native dll (w2k and xp) is used in wine. + * also tested (same crash): replacing emptyW with portname_lpt1W + * and replacing "NULL, 0, NULL" with "buffer, MAX_PATH, &needed" + * + * We need to use a different API (AddPortEx) instead + */ + if (0) + { + /* create a Port for a normal, writable file */ + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL); + + /* add our testport again */ + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL); + + /* create a well-known Port */ + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_lpt1W, (lstrlenW(portname_lpt1W) + 1) * sizeof(WCHAR), NULL, 0, NULL); + + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_lpt1W, (lstrlenW(portname_lpt1W) + 1) * sizeof(WCHAR), NULL, 0, NULL); + /* native localspl.dll on wine: ERROR_ALREADY_EXISTS */ + + /* ERROR_ALREADY_EXISTS is also returned from native localspl.dll on wine, + when "RPT1:" was already installed for redmonnt.dll: + res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_rpt1W, ... + */ + + /* cleanup */ + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL); + } + +} + +/* ########################### */ + +static void test_XcvDataPort_ConfigureLPTPortCommandOK(void) +{ + CHAR org_value[16]; + CHAR buffer[16]; + HKEY hroot = NULL; + DWORD res; + DWORD needed; + + + /* Read the original value from the registry */ + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsA, 0, KEY_ALL_ACCESS, &hroot); + if (res == ERROR_ACCESS_DENIED) { + skip("ACCESS_DENIED\n"); + return; + } + + if (res != ERROR_SUCCESS) { + /* unable to open the registry: skip the test */ + skip("got %d\n", res); + return; + } + org_value[0] = '\0'; + needed = sizeof(org_value)-1 ; + res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) org_value, &needed); + ok( (res == ERROR_SUCCESS) || (res == ERROR_FILE_NOT_FOUND), + "returned %u and %u for \"%s\" (expected ERROR_SUCCESS or " + "ERROR_FILE_NOT_FOUND)\n", res, needed, org_value); + + RegDeleteValueA(hroot, TransmissionRetryTimeoutA); + + /* set to "0" */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_0W, sizeof(num_0W), NULL, 0, &needed); + if (res == ERROR_INVALID_PARAMETER) { + skip("'ConfigureLPTPortCommandOK' not supported\n"); + return; + } + ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError()); + needed = sizeof(buffer)-1 ; + res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed); + ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_0A) == 0), + "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n", + res, buffer, num_0A); + + + /* set to "1" */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_1W, sizeof(num_1W), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError()); + needed = sizeof(buffer)-1 ; + res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed); + ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_1A) == 0), + "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n", + res, buffer, num_1A); + + /* set to "999999" */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_999999W, sizeof(num_999999W), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError()); + needed = sizeof(buffer)-1 ; + res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed); + ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_999999A) == 0), + "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n", + res, buffer, num_999999A); + + /* set to "1000000" */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_1000000W, sizeof(num_1000000W), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError()); + needed = sizeof(buffer)-1 ; + res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed); + ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_1000000A) == 0), + "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n", + res, buffer, num_1000000A); + + /* using cmd_ConfigureLPTPortCommandOKW with does_not_existW: + the string "does_not_exist" is written to the registry */ + + + /* restore the original value */ + RegDeleteValueA(hroot, TransmissionRetryTimeoutA); + if (org_value[0]) { + res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)org_value, lstrlenA(org_value)+1); + ok(res == ERROR_SUCCESS, "unable to restore original value (got %u): %s\n", res, org_value); + } + + RegCloseKey(hroot); + +} + +/* ########################### */ + +static void test_XcvDataPort_DeletePort(void) +{ + DWORD res; + DWORD needed; + + + /* cleanup: just to make sure */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed); + ok( !res || (res == ERROR_FILE_NOT_FOUND), + "returned %d with %u (expected ERROR_SUCCESS or ERROR_FILE_NOT_FOUND)\n", + res, GetLastError()); + + + /* ToDo: cmd_AddPortW for tempfileW, then cmd_DeletePortW for the existing Port */ + + + /* try to delete a nonexistent Port */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed); + ok( res == ERROR_FILE_NOT_FOUND, + "returned %d with %u (expected ERROR_FILE_NOT_FOUND)\n", res, GetLastError()); + + /* emptyW as Portname: ERROR_FILE_NOT_FOUND is returned */ + /* NULL as Portname: Native localspl.dll crashed */ + +} + +/* ########################### */ + +static void test_XcvDataPort_GetTransmissionRetryTimeout(void) +{ + CHAR org_value[16]; + HKEY hroot = NULL; + DWORD buffer[2]; + DWORD res; + DWORD needed; + DWORD len; + + + /* ask for needed size */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, NULL, 0, &needed); + if (res == ERROR_INVALID_PARAMETER) { + skip("'GetTransmissionRetryTimeout' not supported\n"); + return; + } + len = sizeof(DWORD); + ok( (res == ERROR_INSUFFICIENT_BUFFER) && (needed == len), + "returned %d with %u and %u (expected ERROR_INSUFFICIENT_BUFFER " + "and '%u')\n", res, GetLastError(), needed, len); + len = needed; + + /* Read the original value from the registry */ + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsA, 0, KEY_ALL_ACCESS, &hroot); + if (res == ERROR_ACCESS_DENIED) { + skip("ACCESS_DENIED\n"); + return; + } + + if (res != ERROR_SUCCESS) { + /* unable to open the registry: skip the test */ + skip("got %d\n", res); + return; + } + + org_value[0] = '\0'; + needed = sizeof(org_value)-1 ; + res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) org_value, &needed); + ok( (res == ERROR_SUCCESS) || (res == ERROR_FILE_NOT_FOUND), + "returned %u and %u for \"%s\" (expected ERROR_SUCCESS or " + "ERROR_FILE_NOT_FOUND)\n", res, needed, org_value); + + /* Get default value (documented as 90 in the w2k reskit, but that is wrong) */ + RegDeleteValueA(hroot, TransmissionRetryTimeoutA); + needed = (DWORD) 0xdeadbeef; + buffer[0] = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed); + ok( (res == ERROR_SUCCESS) && (buffer[0] == 45), + "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS " + "for '45')\n", res, GetLastError(), needed, buffer[0]); + + /* the default timeout is returned, when the value is empty */ + res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)emptyA, 1); + needed = (DWORD) 0xdeadbeef; + buffer[0] = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed); + ok( (res == ERROR_SUCCESS) && (buffer[0] == 45), + "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS " + "for '45')\n", res, GetLastError(), needed, buffer[0]); + + /* the dialog is limited (1 - 999999), but that is done somewhere else */ + res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_0A, lstrlenA(num_0A)+1); + needed = (DWORD) 0xdeadbeef; + buffer[0] = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed); + ok( (res == ERROR_SUCCESS) && (buffer[0] == 0), + "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS " + "for '0')\n", res, GetLastError(), needed, buffer[0]); + + + res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_1A, lstrlenA(num_1A)+1); + needed = (DWORD) 0xdeadbeef; + buffer[0] = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed); + ok( (res == ERROR_SUCCESS) && (buffer[0] == 1), + "returned %d with %u and %u for %d\n (expected 'ERROR_SUCCESS' " + "for '1')\n", res, GetLastError(), needed, buffer[0]); + + res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_999999A, lstrlenA(num_999999A)+1); + needed = (DWORD) 0xdeadbeef; + buffer[0] = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed); + ok( (res == ERROR_SUCCESS) && (buffer[0] == 999999), + "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS " + "for '999999')\n", res, GetLastError(), needed, buffer[0]); + + + res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_1000000A, lstrlenA(num_1000000A)+1); + needed = (DWORD) 0xdeadbeef; + buffer[0] = 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed); + ok( (res == ERROR_SUCCESS) && (buffer[0] == 1000000), + "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS " + "for '1000000')\n", res, GetLastError(), needed, buffer[0]); + + /* restore the original value */ + RegDeleteValueA(hroot, TransmissionRetryTimeoutA); + if (org_value[0]) { + res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)org_value, lstrlenA(org_value)+1); + ok(res == ERROR_SUCCESS, "unable to restore original value (got %u): %s\n", res, org_value); + } + + RegCloseKey(hroot); +} + +/* ########################### */ + +static void test_XcvDataPort_MonitorUI(void) +{ + DWORD res; + BYTE buffer[MAX_PATH + 2]; + DWORD needed; + DWORD len; + + + /* ask for needed size */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, NULL, 0, &needed); + if (res == ERROR_INVALID_PARAMETER) { + skip("'MonitorUI' nor supported\n"); + return; + } + ok( (res == ERROR_INSUFFICIENT_BUFFER) && (needed <= MAX_PATH), + "returned %d with %u and 0x%x (expected 'ERROR_INSUFFICIENT_BUFFER' " + " and '<= MAX_PATH')\n", res, GetLastError(), needed); + + if (needed > MAX_PATH) { + skip("buffer overflow (%u)\n", needed); + return; + } + len = needed; + + /* the command is required */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, emptyW, NULL, 0, NULL, 0, &needed); + ok( res == ERROR_INVALID_PARAMETER, "returned %d with %u and 0x%x " + "(expected 'ERROR_INVALID_PARAMETER')\n", res, GetLastError(), needed); + + if (0) { + /* crash with native localspl.dll (w2k+xp) */ + res = pXcvDataPort(hXcv, NULL, NULL, 0, buffer, MAX_PATH, &needed); + res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, NULL, len, &needed); + res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len, NULL); + } + + + /* hXcv is ignored for the command "MonitorUI" */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(NULL, cmd_MonitorUIW, NULL, 0, buffer, len, &needed); + ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x " + "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed); + + + /* pszDataName is case-sensitive */ + memset(buffer, 0, len); + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_MonitorUI_lcaseW, NULL, 0, buffer, len, &needed); + ok( res == ERROR_INVALID_PARAMETER, "returned %d with %u and 0x%x " + "(expected 'ERROR_INVALID_PARAMETER')\n", res, GetLastError(), needed); + + /* off by one: larger */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len+1, &needed); + ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x " + "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed); + + + /* off by one: smaller */ + /* the buffer is not modified for NT4, w2k, XP */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len-1, &needed); + ok( res == ERROR_INSUFFICIENT_BUFFER, "returned %d with %u and 0x%x " + "(expected 'ERROR_INSUFFICIENT_BUFFER')\n", res, GetLastError(), needed); + + /* Normal use. The DLL-Name without a Path is returned */ + memset(buffer, 0, len); + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len, &needed); + ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x " + "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed); + + + /* small check without access-rights: */ + if (!hXcv_noaccess) return; + + /* The ACCESS_MASK is ignored for "MonitorUI" */ + memset(buffer, 0, len); + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv_noaccess, cmd_MonitorUIW, NULL, 0, buffer, sizeof(buffer), &needed); + ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x " + "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed); +} + +/* ########################### */ + +static void test_XcvDataPort_PortIsValid(void) +{ + DWORD res; + DWORD needed; + + /* normal use: "LPT1:" */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, &needed); + if (res == ERROR_INVALID_PARAMETER) { + skip("'PostIsValid' not supported\n"); + return; + } + ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError()); + + + if (0) { + /* crash with native localspl.dll (w2k+xp) */ + res = pXcvDataPort(hXcv, cmd_PortIsValidW, NULL, 0, NULL, 0, &needed); + } + + + /* hXcv is ignored for the command "PortIsValid" */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(NULL, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, NULL); + ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError()); + + /* needed is ignored */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, NULL); + ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError()); + + + /* cbInputData is ignored */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, 0, NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, 1, NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W) -1, NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W) -2, NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + + /* an empty name is not allowed */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) emptyW, sizeof(emptyW), NULL, 0, &needed); + ok( res == ERROR_PATH_NOT_FOUND, + "returned %d with %u and 0x%x (expected ERROR_PATH_NOT_FOUND)\n", + res, GetLastError(), needed); + + + /* a directory is not allowed */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) tempdirW, (lstrlenW(tempdirW) + 1) * sizeof(WCHAR), NULL, 0, &needed); + /* XP(admin): ERROR_INVALID_NAME, XP(user): ERROR_PATH_NOT_FOUND, w2k ERROR_ACCESS_DENIED */ + ok( (res == ERROR_INVALID_NAME) || (res == ERROR_PATH_NOT_FOUND) || + (res == ERROR_ACCESS_DENIED), "returned %d with %u and 0x%x " + "(expected ERROR_INVALID_NAME, ERROR_PATH_NOT_FOUND or ERROR_ACCESS_DENIED)\n", + res, GetLastError(), needed); + + + /* test more valid well known Ports: */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt2W, sizeof(portname_lpt2W), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_com1W, sizeof(portname_com1W), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_com2W, sizeof(portname_com2W), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_fileW, sizeof(portname_fileW), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + + /* a normal, writable file is allowed */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, + "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n", + res, GetLastError(), needed); + + + /* small check without access-rights: */ + if (!hXcv_noaccess) return; + + /* The ACCESS_MASK from XcvOpenPort is ignored in "PortIsValid" */ + needed = (DWORD) 0xdeadbeef; + SetLastError(0xdeadbeef); + res = pXcvDataPort(hXcv_noaccess, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, &needed); + ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError()); + +} + +/* ########################### */ + +static void test_XcvOpenPort(void) +{ + DWORD res; + HANDLE hXcv2; + + + if (0) + { + /* crash with native localspl.dll (w2k+xp) */ + res = pXcvOpenPort(NULL, SERVER_ACCESS_ADMINISTER, &hXcv2); + res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, NULL); + } + + + /* The returned handle is the result from a previous "spoolss.dll,DllAllocSplMem" */ + SetLastError(0xdeadbeef); + hXcv2 = (HANDLE) 0xdeadbeef; + res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv2); + ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2); + if (res) pXcvClosePort(hXcv2); + + + /* The ACCESS_MASK is not checked in XcvOpenPort */ + SetLastError(0xdeadbeef); + hXcv2 = (HANDLE) 0xdeadbeef; + res = pXcvOpenPort(emptyW, 0, &hXcv2); + ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2); + if (res) pXcvClosePort(hXcv2); + + + /* A copy of pszObject is saved in the Memory-Block */ + SetLastError(0xdeadbeef); + hXcv2 = (HANDLE) 0xdeadbeef; + res = pXcvOpenPort(portname_lpt1W, SERVER_ALL_ACCESS, &hXcv2); + ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2); + if (res) pXcvClosePort(hXcv2); + + SetLastError(0xdeadbeef); + hXcv2 = (HANDLE) 0xdeadbeef; + res = pXcvOpenPort(portname_fileW, SERVER_ALL_ACCESS, &hXcv2); + ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2); + if (res) pXcvClosePort(hXcv2); + +} + +/* ########################### */ + +#define GET_MONITOR_FUNC(name) \ + if(numentries > 0) { \ + numentries--; \ + p##name = pm->Monitor.pfn##name ; \ + } + + +START_TEST(localmon) +{ + DWORD numentries; + DWORD res; + + LoadLibraryA("winspool.drv"); + /* This DLL does not exist on Win9x */ + hdll = LoadLibraryA("localspl.dll"); + if (!hdll) { + skip("localspl.dll cannot be loaded, most likely running on Win9x\n"); + return; + } + + tempdirW[0] = '\0'; + tempfileW[0] = '\0'; + res = GetTempPathW(MAX_PATH, tempdirW); + ok(res != 0, "with %u\n", GetLastError()); + res = GetTempFileNameW(tempdirW, wineW, 0, tempfileW); + ok(res != 0, "with %u\n", GetLastError()); + + pInitializePrintMonitor = (void *) GetProcAddress(hdll, "InitializePrintMonitor"); + + if (!pInitializePrintMonitor) { + /* The Monitor for "Local Ports" was in a separate dll before w2k */ + hlocalmon = LoadLibraryA("localmon.dll"); + if (hlocalmon) { + pInitializePrintMonitor = (void *) GetProcAddress(hlocalmon, "InitializePrintMonitor"); + } + } + if (!pInitializePrintMonitor) return; + + /* Native localmon.dll / localspl.dll need a valid Port-Entry in: + a) since xp: HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports + b) up to w2k: Section "Ports" in win.ini + or InitializePrintMonitor fails. */ + pm = pInitializePrintMonitor(Monitors_LocalPortW); + if (pm) { + numentries = (pm->dwMonitorSize ) / sizeof(VOID *); + /* NT4: 14, since w2k: 17 */ + ok( numentries == 14 || numentries == 17, + "dwMonitorSize (%d) => %d Functions\n", pm->dwMonitorSize, numentries); + + GET_MONITOR_FUNC(EnumPorts); + GET_MONITOR_FUNC(OpenPort); + GET_MONITOR_FUNC(OpenPortEx); + GET_MONITOR_FUNC(StartDocPort); + GET_MONITOR_FUNC(WritePort); + GET_MONITOR_FUNC(ReadPort); + GET_MONITOR_FUNC(EndDocPort); + GET_MONITOR_FUNC(ClosePort); + GET_MONITOR_FUNC(AddPort); + GET_MONITOR_FUNC(AddPortEx); + GET_MONITOR_FUNC(ConfigurePort); + GET_MONITOR_FUNC(DeletePort); + GET_MONITOR_FUNC(GetPrinterDataFromPort); + GET_MONITOR_FUNC(SetPortTimeOuts); + GET_MONITOR_FUNC(XcvOpenPort); + GET_MONITOR_FUNC(XcvDataPort); + GET_MONITOR_FUNC(XcvClosePort); + + if ((pXcvOpenPort) && (pXcvDataPort) && (pXcvClosePort)) { + SetLastError(0xdeadbeef); + res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv); + ok(res, "hXcv: %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv); + + SetLastError(0xdeadbeef); + res = pXcvOpenPort(emptyW, 0, &hXcv_noaccess); + ok(res, "hXcv_noaccess: %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv_noaccess); + } + } + + test_InitializePrintMonitor(); + + find_installed_ports(); + + test_AddPort(); + test_AddPortEx(); + test_ClosePort(); + test_ConfigurePort(); + test_DeletePort(); + test_EnumPorts(); + test_OpenPort(); + + if ( !hXcv ) { + skip("Xcv not supported\n"); + } + else + { + test_XcvClosePort(); + test_XcvDataPort_AddPort(); + test_XcvDataPort_ConfigureLPTPortCommandOK(); + test_XcvDataPort_DeletePort(); + test_XcvDataPort_GetTransmissionRetryTimeout(); + test_XcvDataPort_MonitorUI(); + test_XcvDataPort_PortIsValid(); + test_XcvOpenPort(); + + pXcvClosePort(hXcv); + } + if (hXcv_noaccess) pXcvClosePort(hXcv_noaccess); + + /* Cleanup our temporary file */ + DeleteFileW(tempfileW); +} diff --git a/rostests/winetests/localspl/localspl.rbuild b/rostests/winetests/localspl/localspl.rbuild new file mode 100644 index 00000000000..5e8ca464e6d --- /dev/null +++ b/rostests/winetests/localspl/localspl.rbuild @@ -0,0 +1,9 @@ + + . + + localmon.c + testlist.c + wine + advapi32 + ntdll + diff --git a/rostests/winetests/localspl/testlist.c b/rostests/winetests/localspl/testlist.c new file mode 100644 index 00000000000..5e1945fded4 --- /dev/null +++ b/rostests/winetests/localspl/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_localmon(void); + +const struct test winetest_testlist[] = +{ + { "localmon", func_localmon }, + { 0, 0 } +}; diff --git a/rostests/winetests/localui/localui.c b/rostests/winetests/localui/localui.c new file mode 100644 index 00000000000..cb7a1cff248 --- /dev/null +++ b/rostests/winetests/localui/localui.c @@ -0,0 +1,329 @@ +/* + * Unit test suite for the Local Printmonitor User Interface + * + * Copyright 2007 Detlef Riekenberg + * + * 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 + * + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wingdi.h" +#include "winnls.h" +#include "winreg.h" + +#include "winspool.h" +#include "ddk/winsplp.h" + +#include "wine/test.h" + + +/* ##### */ + +static HMODULE hdll; +static PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID); +static PMONITORUI pui; +static BOOL (WINAPI *pAddPortUI)(PCWSTR, HWND, PCWSTR, PWSTR *); +static BOOL (WINAPI *pConfigurePortUI)(PCWSTR, HWND, PCWSTR); +static BOOL (WINAPI *pDeletePortUI)(PCWSTR, HWND, PCWSTR); + +static WCHAR does_not_existW[] = {'d','o','e','s','_','n','o','t','_','e','x','i','s','t',0}; +static WCHAR emptyW[] = {0}; +static CHAR fmt_comA[] = {'C','O','M','%','u',':',0}; +static CHAR fmt_lptA[] = {'L','P','T','%','u',':',0}; +static WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0}; +static WCHAR portname_fileW[] = {'F','I','L','E',':',0}; + +static LPBYTE pi_buffer; +static DWORD pi_numports; +static DWORD pi_needed; + +static PORT_INFO_2W * lpt_present; +static PORT_INFO_2W * com_present; +static PORT_INFO_2W * file_present; + +static LPWSTR lpt_absent; +static LPWSTR com_absent; + +/* ########################### */ + +static PORT_INFO_2W * find_portinfo2(LPWSTR pPort) +{ + PORT_INFO_2W * pi; + DWORD res; + + if (!pi_buffer) { + res = EnumPortsW(NULL, 2, NULL, 0, &pi_needed, &pi_numports); + pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed); + SetLastError(0xdeadbeef); + res = EnumPortsW(NULL, 2, pi_buffer, pi_needed, &pi_needed, &pi_numports); + } + if (pi_buffer) { + pi = (PORT_INFO_2W *) pi_buffer; + res = 0; + while (pi_numports > res) { + if (lstrcmpiW(pi->pPortName, pPort) == 0) { + return pi; + } + pi++; + res++; + } + } + return NULL; +} + + +/* ########################### */ + +static LPCSTR load_functions(void) +{ + LPCSTR ptr; + + ptr = "localui.dll"; + hdll = LoadLibraryA(ptr); + if (!hdll) return ptr; + + ptr = "InitializePrintMonitorUI"; + pInitializePrintMonitorUI = (VOID *) GetProcAddress(hdll, ptr); + if (!pInitializePrintMonitorUI) return ptr; + + return NULL; +} + +/* ########################### + * strdupW [internal] + */ + +static LPWSTR strdupW(LPCWSTR strW) +{ + LPWSTR ptr; + + ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(strW) + 1) * sizeof(WCHAR)); + if (ptr) { + lstrcpyW(ptr, strW); + } + return ptr; +} + +/* ########################### */ + +static void test_AddPortUI(void) +{ + DWORD res; + LPWSTR new_portname; + + /* not present before w2k */ + if (!pAddPortUI) { + skip("AddPortUI not found\n"); + return; + } + + SetLastError(0xdeadbeef); + res = pAddPortUI(NULL, NULL, NULL, NULL); + ok( !res && + ((GetLastError() == ERROR_UNKNOWN_PORT) || (GetLastError() == ERROR_INVALID_PRINTER_NAME)), + "got %d with %u (expected '0' with: ERROR_UNKNOWN_PORT or " + "ERROR_INVALID_PRINTER_NAME)\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pAddPortUI(NULL, NULL, emptyW, NULL); + ok( !res && + ((GetLastError() == ERROR_UNKNOWN_PORT) || (GetLastError() == ERROR_INVALID_PRINTER_NAME)), + "got %d with %u (expected '0' with: ERROR_UNKNOWN_PORT or " + "ERROR_INVALID_PRINTER_NAME)\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pAddPortUI(NULL, NULL, does_not_existW, NULL); + ok( !res && + ((GetLastError() == ERROR_UNKNOWN_PORT) || (GetLastError() == ERROR_INVALID_PRINTER_NAME)), + "got %d with %u (expected '0' with: ERROR_UNKNOWN_PORT or " + "ERROR_INVALID_PRINTER_NAME)\n", res, GetLastError()); + + if (winetest_interactive) { + SetLastError(0xdeadbeef); + new_portname = NULL; + /* + * - On MSDN, you can read, that no dialogs should be displayed, when hWnd + * is NULL, but native localui does not care + * - when the new port already exist, + * TRUE is returned, but new_portname is NULL + * - when the new port starts with "COM" or "LPT", + * FALSE is returned with ERROR_NOT_SUPPORTED in windows + */ + res = pAddPortUI(NULL, NULL, localportW, &new_portname); + ok( res || + (GetLastError() == ERROR_CANCELLED) || + (GetLastError() == ERROR_ACCESS_DENIED) || + (GetLastError() == ERROR_NOT_SUPPORTED), + "got %d with %u and %p (expected '!= 0' or '0' with: " + "ERROR_CANCELLED, ERROR_ACCESS_DENIED or ERROR_NOT_SUPPORTED)\n", + res, GetLastError(), new_portname); + + GlobalFree(new_portname); + } +} + +/* ########################### */ + +static void test_ConfigurePortUI(void) +{ + DWORD res; + + /* not present before w2k */ + if (!pConfigurePortUI) { + skip("ConfigurePortUI not found\n"); + return; + } + + SetLastError(0xdeadbeef); + res = pConfigurePortUI(NULL, NULL, NULL); + ok( !res && + ((GetLastError() == ERROR_UNKNOWN_PORT) || (GetLastError() == ERROR_INVALID_PRINTER_NAME)), + "got %d with %u (expected '0' with: ERROR_UNKNOWN_PORT or " + "ERROR_INVALID_PRINTER_NAME)\n", res, GetLastError()); + + SetLastError(0xdeadbeef); + res = pConfigurePortUI(NULL, NULL, emptyW); + ok( !res && + ((GetLastError() == ERROR_UNKNOWN_PORT) || (GetLastError() == ERROR_INVALID_PRINTER_NAME)), + "got %d with %u (expected '0' with: ERROR_UNKNOWN_PORT or " + "ERROR_INVALID_PRINTER_NAME)\n", res, GetLastError()); + + + SetLastError(0xdeadbeef); + res = pConfigurePortUI(NULL, NULL, does_not_existW); + ok( !res && + ((GetLastError() == ERROR_UNKNOWN_PORT) || (GetLastError() == ERROR_INVALID_PRINTER_NAME)), + "got %d with %u (expected '0' with: ERROR_UNKNOWN_PORT or " + "ERROR_INVALID_PRINTER_NAME)\n", res, GetLastError()); + + if (winetest_interactive && lpt_present) { + SetLastError(0xdeadbeef); + res = pConfigurePortUI(NULL, NULL, lpt_present->pPortName); + ok( res || + (GetLastError() == ERROR_CANCELLED) || (GetLastError() == ERROR_ACCESS_DENIED), + "got %d with %u (expected '!= 0' or '0' with: ERROR_CANCELLED or " + "ERROR_ACCESS_DENIED)\n", res, GetLastError()); + } + + if (lpt_absent) { + SetLastError(0xdeadbeef); + res = pConfigurePortUI(NULL, NULL, lpt_absent); + ok( !res && + ((GetLastError() == ERROR_UNKNOWN_PORT) || (GetLastError() == ERROR_INVALID_PRINTER_NAME)), + "got %d with %u (expected '0' with: ERROR_UNKNOWN_PORT or " + "ERROR_INVALID_PRINTER_NAME)\n", res, GetLastError()); + } + + if (winetest_interactive && com_present) { + SetLastError(0xdeadbeef); + res = pConfigurePortUI(NULL, NULL, com_present->pPortName); + ok( res || + (GetLastError() == ERROR_CANCELLED) || (GetLastError() == ERROR_ACCESS_DENIED), + "got %d with %u (expected '!= 0' or '0' with: ERROR_CANCELLED or " + "ERROR_ACCESS_DENIED)\n", res, GetLastError()); + } + + if (com_absent) { + SetLastError(0xdeadbeef); + res = pConfigurePortUI(NULL, NULL, com_absent); + ok( !res && + ((GetLastError() == ERROR_UNKNOWN_PORT) || (GetLastError() == ERROR_INVALID_PRINTER_NAME)), + "got %d with %u (expected '0' with: ERROR_UNKNOWN_PORT or " + "ERROR_INVALID_PRINTER_NAME)\n", res, GetLastError()); + + } + + if (winetest_interactive && file_present) { + SetLastError(0xdeadbeef); + res = pConfigurePortUI(NULL, NULL, portname_fileW); + ok( !res && + ((GetLastError() == ERROR_CANCELLED) || (GetLastError() == ERROR_ACCESS_DENIED)), + "got %d with %u (expected '0' with: ERROR_CANCELLED or " + "ERROR_ACCESS_DENIED)\n", res, GetLastError()); + } +} + +/* ########################### */ + +START_TEST(localui) +{ + LPCSTR ptr; + DWORD numentries; + PORT_INFO_2W * pi2; + WCHAR bufferW[16]; + CHAR bufferA[16]; + DWORD id; + + /* localui.dll does not exist before w2k */ + ptr = load_functions(); + if (ptr) { + skip("%s not found\n", ptr); + return; + } + + pui = pInitializePrintMonitorUI(); + if (pui) { + numentries = (pui->dwMonitorUISize - sizeof(DWORD)) / sizeof(VOID *); + ok( numentries == 3, + "dwMonitorUISize (%d) => %d Functions\n", pui->dwMonitorUISize, numentries); + + if (numentries > 2) { + pAddPortUI = pui->pfnAddPortUI; + pConfigurePortUI = pui->pfnConfigurePortUI; + pDeletePortUI = pui->pfnDeletePortUI; + } + } + + /* find installed Ports */ + + id = 0; + /* "LPT1:" - "LPT9:" */ + while (((lpt_present == NULL) || (lpt_absent == NULL)) && id < 9) { + id++; + sprintf(bufferA, fmt_lptA, id); + MultiByteToWideChar( CP_ACP, 0, bufferA, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ); + pi2 = find_portinfo2(bufferW); + if (pi2 && (lpt_present == NULL)) lpt_present = pi2; + if (!pi2 && (lpt_absent == NULL)) lpt_absent = strdupW(bufferW); + } + + id = 0; + /* "COM1:" - "COM9:" */ + while (((com_present == NULL) || (com_absent == NULL)) && id < 9) { + id++; + sprintf(bufferA, fmt_comA, id); + MultiByteToWideChar( CP_ACP, 0, bufferA, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ); + pi2 = find_portinfo2(bufferW); + if (pi2 && (com_present == NULL)) com_present = pi2; + if (!pi2 && (com_absent == NULL)) com_absent = strdupW(bufferW); + } + + /* "FILE:" */ + file_present = find_portinfo2(portname_fileW); + + test_AddPortUI(); + test_ConfigurePortUI(); + + /* cleanup */ + HeapFree(GetProcessHeap(), 0, lpt_absent); + HeapFree(GetProcessHeap(), 0, com_absent); + HeapFree(GetProcessHeap(), 0, pi_buffer); +} diff --git a/rostests/winetests/localui/localui.rbuild b/rostests/winetests/localui/localui.rbuild new file mode 100644 index 00000000000..a219470a038 --- /dev/null +++ b/rostests/winetests/localui/localui.rbuild @@ -0,0 +1,9 @@ + + . + + localui.c + testlist.c + wine + winspool + ntdll + diff --git a/rostests/winetests/localui/testlist.c b/rostests/winetests/localui/testlist.c new file mode 100644 index 00000000000..241a4dd483b --- /dev/null +++ b/rostests/winetests/localui/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_localui(void); + +const struct test winetest_testlist[] = +{ + { "localui", func_localui }, + { 0, 0 } +}; diff --git a/rostests/winetests/lz32/lz32.rbuild b/rostests/winetests/lz32/lz32.rbuild index 207bb004fc1..205c347d865 100644 --- a/rostests/winetests/lz32/lz32.rbuild +++ b/rostests/winetests/lz32/lz32.rbuild @@ -3,13 +3,11 @@ . - 0x600 - 0x600 + lzexpand_main.c testlist.c wine lz32 - kernel32 ntdll diff --git a/rostests/winetests/lz32/lzexpand_main.c b/rostests/winetests/lz32/lzexpand_main.c index a296b28e630..91fd6873e3f 100644 --- a/rostests/winetests/lz32/lzexpand_main.c +++ b/rostests/winetests/lz32/lzexpand_main.c @@ -230,7 +230,8 @@ static void test_LZOpenFileA_existing_compressed(void) /* d, using underscore-terminated file name. */ file = LZOpenFileA(_terminated, &test, OF_EXIST); ok(file >= 0, "LZOpenFileA failed on switching to a compressed file name\n"); - ok(test.cBytes == sizeof(OFSTRUCT), + ok(test.cBytes == sizeof(OFSTRUCT) || + broken(test.cBytes == FIELD_OFFSET(OFSTRUCT, szPathName) + lstrlenA(test.szPathName)), /* win9x */ "LZOpenFileA set test.cBytes to %d\n", test.cBytes); ok(test.nErrCode == 0, "LZOpenFileA set test.nErrCode to %d\n", test.nErrCode); @@ -370,7 +371,7 @@ static void test_LZOpenFileA(void) ok(test.cBytes == sizeof(OFSTRUCT), "LZOpenFileA set test.cBytes to %d\n", test.cBytes); ok(test.nErrCode == ERROR_SUCCESS || - test.nErrCode == ERROR_FILE_NOT_FOUND, /* win9x */ + broken(test.nErrCode != ERROR_SUCCESS), /* win9x */ "LZOpenFileA set test.nErrCode to %d\n", test.nErrCode); ok(lstrcmpA(test.szPathName, expected) == 0, "LZOpenFileA returned '%s', but was expected to return '%s'\n", @@ -388,8 +389,9 @@ static void test_LZOpenFileA(void) /* a, for reading. */ file = LZOpenFileA(filename_, &test, OF_READ); ok(file >= 0, "LZOpenFileA failed on read\n"); - ok(test.cBytes == sizeof(OFSTRUCT), - "LZOpenFileA set test.cBytes to %d\n", test.cBytes); + ok(test.cBytes == sizeof(OFSTRUCT) || + broken(test.cBytes == FIELD_OFFSET(OFSTRUCT, szPathName) + lstrlenA(test.szPathName)), /* win9x */ + "LZOpenFileA set test.cBytes to %d '%s'('%s')\n", test.cBytes, expected, short_expected); ok(test.nErrCode == ERROR_SUCCESS, "LZOpenFileA set test.nErrCode to %d\n", test.nErrCode); ok(lstrcmpA(test.szPathName, expected) == 0 || @@ -403,7 +405,8 @@ static void test_LZOpenFileA(void) /* b, for writing. */ file = LZOpenFileA(filename_, &test, OF_WRITE); ok(file >= 0, "LZOpenFileA failed on write\n"); - ok(test.cBytes == sizeof(OFSTRUCT), + ok(test.cBytes == sizeof(OFSTRUCT) || + broken(test.cBytes == FIELD_OFFSET(OFSTRUCT, szPathName) + lstrlenA(test.szPathName)), /* win9x */ "LZOpenFileA set test.cBytes to %d\n", test.cBytes); ok(test.nErrCode == ERROR_SUCCESS, "LZOpenFileA set test.nErrCode to %d\n", test.nErrCode); @@ -418,7 +421,8 @@ static void test_LZOpenFileA(void) /* c, for reading and writing. */ file = LZOpenFileA(filename_, &test, OF_READWRITE); ok(file >= 0, "LZOpenFileA failed on read/write\n"); - ok(test.cBytes == sizeof(OFSTRUCT), + ok(test.cBytes == sizeof(OFSTRUCT) || + broken(test.cBytes == FIELD_OFFSET(OFSTRUCT, szPathName) + lstrlenA(test.szPathName)), /* win9x */ "LZOpenFileA set test.cBytes to %d\n", test.cBytes); ok(test.nErrCode == ERROR_SUCCESS, "LZOpenFileA set test.nErrCode to %d\n", test.nErrCode); @@ -433,7 +437,8 @@ static void test_LZOpenFileA(void) /* d, for checking file existence. */ file = LZOpenFileA(filename_, &test, OF_EXIST); ok(file >= 0, "LZOpenFileA failed on read/write\n"); - ok(test.cBytes == sizeof(OFSTRUCT), + ok(test.cBytes == sizeof(OFSTRUCT) || + broken(test.cBytes == FIELD_OFFSET(OFSTRUCT, szPathName) + lstrlenA(test.szPathName)), /* win9x */ "LZOpenFileA set test.cBytes to %d\n", test.cBytes); ok(test.nErrCode == ERROR_SUCCESS, "LZOpenFileA set test.nErrCode to %d\n", test.nErrCode); @@ -448,7 +453,8 @@ static void test_LZOpenFileA(void) /* Delete the file then make sure it doesn't exist anymore. */ file = LZOpenFileA(filename_, &test, OF_DELETE); ok(file >= 0, "LZOpenFileA failed on delete\n"); - ok(test.cBytes == sizeof(OFSTRUCT), + ok(test.cBytes == sizeof(OFSTRUCT) || + broken(test.cBytes == FIELD_OFFSET(OFSTRUCT, szPathName) + lstrlenA(test.szPathName)), /* win9x */ "LZOpenFileA set test.cBytes to %d\n", test.cBytes); ok(test.nErrCode == ERROR_SUCCESS, "LZOpenFileA set test.nErrCode to %d\n", test.nErrCode); @@ -764,13 +770,13 @@ static void test_LZOpenFileW(void) SetLastError(0xfaceabee); /* Check for nonexistent file. */ file = LZOpenFileW(badfilenameW, &test, OF_READ); - ok(GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, - "GetLastError() returns %d\n", GetLastError()); if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("LZOpenFileW call not implemented, skipping rest of the test\n"); + win_skip("LZOpenFileW call is not implemented\n"); return; } + ok(GetLastError() == ERROR_FILE_NOT_FOUND, + "GetLastError() returns %d\n", GetLastError()); ok(file == LZERROR_BADINHANDLE, "LZOpenFileW succeeded on nonexistent file\n"); LZClose(file); diff --git a/rostests/winetests/mapi32/imalloc.c b/rostests/winetests/mapi32/imalloc.c index 63c66f27747..485180c0e45 100644 --- a/rostests/winetests/mapi32/imalloc.c +++ b/rostests/winetests/mapi32/imalloc.c @@ -26,6 +26,7 @@ #include "winerror.h" #include "winnt.h" #include "mapiutil.h" +#include "mapi32_test.h" static HMODULE hMapi32 = 0; @@ -64,8 +65,7 @@ static void test_IMalloc(void) /* Prove that native mapi uses LocalAlloc/LocalFree */ lpMem = IMalloc_Alloc(lpMalloc, 61); - ok (lpMem && IMalloc_GetSize(lpMalloc, lpMem) == - LocalSize((HANDLE)lpMem), + ok (lpMem && IMalloc_GetSize(lpMalloc, lpMem) == LocalSize(lpMem), "Expected non-null, same size, got %p, %s size\n", lpMem, lpMem ? "different" : "same"); @@ -89,12 +89,18 @@ START_TEST(imalloc) { SCODE ret; + if (!HaveDefaultMailClient()) + { + win_skip("No default mail client installed\n"); + return; + } + hMapi32 = LoadLibraryA("mapi32.dll"); pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4"); if (!pScInitMapiUtil) { - skip("ScInitMapiUtil is not available\n"); + win_skip("ScInitMapiUtil is not available\n"); FreeLibrary(hMapi32); return; } @@ -103,7 +109,13 @@ START_TEST(imalloc) ret = pScInitMapiUtil(0); if ((ret != S_OK) && (GetLastError() == ERROR_PROC_NOT_FOUND)) { - skip("ScInitMapiUtil is not implemented\n"); + win_skip("ScInitMapiUtil is not implemented\n"); + FreeLibrary(hMapi32); + return; + } + else if ((ret == E_FAIL) && (GetLastError() == ERROR_INVALID_HANDLE)) + { + win_skip("ScInitMapiUtil doesn't work on some Win98 and WinME systems\n"); FreeLibrary(hMapi32); return; } diff --git a/rostests/winetests/mapi32/mapi32.rbuild b/rostests/winetests/mapi32/mapi32.rbuild index 4b46ee995b5..4d27118fbd8 100644 --- a/rostests/winetests/mapi32/mapi32.rbuild +++ b/rostests/winetests/mapi32/mapi32.rbuild @@ -3,14 +3,13 @@ . - 0x600 - 0x600 + imalloc.c prop.c util.c testlist.c wine - kernel32 + advapi32 uuid ntdll diff --git a/rostests/winetests/mapi32/mapi32_test.h b/rostests/winetests/mapi32/mapi32_test.h new file mode 100644 index 00000000000..5002dbc99b3 --- /dev/null +++ b/rostests/winetests/mapi32/mapi32_test.h @@ -0,0 +1,62 @@ +/* + * 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 + */ + +/* + * Return FALSE if no default mail client is installed. + */ +static BOOL HaveDefaultMailClient(void) +{ + HKEY Key; + DWORD Type, Size; + BYTE Buffer[64]; + BOOL HasHKCUKey; + + /* We check the default value of both HKCU\Software\Clients\Mail and + * HKLM\Software\Clients\Mail, if one of them is present there is a default + * mail client. If neither of these keys is present, we might be running + * on an old Windows version (W95, NT4) and we assume a default mail client + * might be available. Only if one of the keys is present, but there is + * no default value do we assume there is no default client. */ + if (RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Clients\\Mail", 0, KEY_QUERY_VALUE, &Key) == ERROR_SUCCESS) + { + Size = sizeof(Buffer); + /* Any return value besides ERROR_FILE_NOT_FOUND (including success, + ERROR_MORE_DATA) indicates the value is present */ + if (RegQueryValueExA(Key, NULL, NULL, &Type, Buffer, &Size) != ERROR_FILE_NOT_FOUND) + { + RegCloseKey(Key); + return TRUE; + } + RegCloseKey(Key); + HasHKCUKey = TRUE; + } + else + HasHKCUKey = FALSE; + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Clients\\Mail", 0, KEY_QUERY_VALUE, &Key) == ERROR_SUCCESS) + { + Size = sizeof(Buffer); + if (RegQueryValueExA(Key, NULL, NULL, &Type, Buffer, &Size) != ERROR_FILE_NOT_FOUND) + { + RegCloseKey(Key); + return TRUE; + } + RegCloseKey(Key); + return FALSE; + } + + return ! HasHKCUKey; +} diff --git a/rostests/winetests/mapi32/prop.c b/rostests/winetests/mapi32/prop.c index a2b92891934..237134b07c5 100644 --- a/rostests/winetests/mapi32/prop.c +++ b/rostests/winetests/mapi32/prop.c @@ -27,6 +27,7 @@ #include "initguid.h" #include "mapiutil.h" #include "mapitags.h" +#include "mapi32_test.h" static HMODULE hMapi32 = 0; @@ -93,11 +94,11 @@ static void test_PropCopyMore(void) if (!pPropCopyMore) return; - scode = pMAPIAllocateBuffer(sizeof(LPSPropValue), (LPVOID *)lpDest); + scode = pMAPIAllocateBuffer(sizeof(LPSPropValue), lpDest); if (FAILED(scode)) return; - scode = pMAPIAllocateMore(sizeof(LPSPropValue), lpDest, (LPVOID *)lpSrc); + scode = pMAPIAllocateMore(sizeof(LPSPropValue), lpDest, lpSrc); if (FAILED(scode)) return; @@ -239,7 +240,8 @@ static void test_UlPropSize(void) } res = pUlPropSize(&pv); - ok(res == exp, "pt= %d: Expected %d, got %d\n", pt, exp, res); + ok(res == exp, + "pt= %d: Expected %d, got %d\n", pt, exp, res); } } @@ -502,7 +504,8 @@ static void test_FPropCompareProp(void) } bRet = pFPropCompareProp(&pvLeft, FPCProp_Results[j].relOp, &pvRight); - ok(bRet == bExp, "pt %d (%d,%d,%s): expected %d, got %d\n", ptTypes[i], + ok(bRet == bExp, + "pt %d (%d,%d,%s): expected %d, got %d\n", ptTypes[i], FPCProp_Results[j].lVal, FPCProp_Results[j].rVal, relops[FPCProp_Results[j].relOp], bExp, bRet); } @@ -625,7 +628,8 @@ static void test_LPropCompareProp(void) } iRet = pLPropCompareProp(&pvLeft, &pvRight); - ok(iRet == iExp, "pt %d (%d,%d): expected %d, got %d\n", ptTypes[i], + ok(iRet == iExp, + "pt %d (%d,%d): expected %d, got %d\n", ptTypes[i], LPCProp_Results[j].lVal, LPCProp_Results[j].rVal, iExp, iRet); } } @@ -646,7 +650,8 @@ static void test_PpropFindProp(void) pvProp.ulPropTag = ptTypes[i]; pRet = pPpropFindProp(&pvProp, 1u, ptTypes[i]); - ok(pRet == &pvProp, "PpropFindProp[%d]: Didn't find existing propery\n", + ok(pRet == &pvProp, + "PpropFindProp[%d]: Didn't find existing propery\n", ptTypes[i]); pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]); @@ -882,7 +887,8 @@ static void test_LpValFindProp(void) pvProp.ulPropTag = PROP_TAG(ptTypes[i], 1u); pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 1u), 1u, &pvProp); - ok(pRet == &pvProp, "LpValFindProp[%d]: Didn't find existing propery id/type\n", + ok(pRet == &pvProp, + "LpValFindProp[%d]: Didn't find existing propery id/type\n", ptTypes[i]); pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp); @@ -894,7 +900,8 @@ static void test_LpValFindProp(void) ptTypes[i]); pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp); - ok(pRet == &pvProp, "LpValFindProp[%d]: Didn't find existing propery id\n", + ok(pRet == &pvProp, + "LpValFindProp[%d]: Didn't find existing propery id\n", ptTypes[i]); } } @@ -990,7 +997,8 @@ static void test_FBadPropTag(void) if (bBad) ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt); else - ok(res == 0, "pt= %d: Expected zero, got %d\n", pt, res); + ok(res == 0, + "pt= %d: Expected zero, got %d\n", pt, res); } } @@ -1079,7 +1087,8 @@ static void test_FBadProp(void) if (bBad) ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt); else - ok(res == 0, "pt= %d: Expected zero, got %d\n", pt, res); + ok(res == 0, + "pt= %d: Expected zero, got %d\n", pt, res); } } @@ -1130,7 +1139,8 @@ static void test_FBadColumnSet(void) if (bBad) ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt); else - ok(res == 0, "pt= %d: Expected zero, got %d\n", pt, res); + ok(res == 0, + "pt= %d: Expected zero, got %d\n", pt, res); } } @@ -1351,9 +1361,15 @@ START_TEST(prop) { SCODE ret; + if (!HaveDefaultMailClient()) + { + win_skip("No default mail client installed\n"); + return; + } + if(!InitFuncPtrs()) { - skip("Needed functions are not available\n"); + win_skip("Needed functions are not available\n"); return; } @@ -1361,7 +1377,13 @@ START_TEST(prop) ret = pScInitMapiUtil(0); if ((ret != S_OK) && (GetLastError() == ERROR_PROC_NOT_FOUND)) { - skip("ScInitMapiUtil is not implemented\n"); + win_skip("ScInitMapiUtil is not implemented\n"); + FreeLibrary(hMapi32); + return; + } + else if ((ret == E_FAIL) && (GetLastError() == ERROR_INVALID_HANDLE)) + { + win_skip("ScInitMapiUtil doesn't work on some Win98 and WinME systems\n"); FreeLibrary(hMapi32); return; } diff --git a/rostests/winetests/mapi32/util.c b/rostests/winetests/mapi32/util.c index 2ae42f1c814..feb2c6daa0b 100644 --- a/rostests/winetests/mapi32/util.c +++ b/rostests/winetests/mapi32/util.c @@ -26,6 +26,7 @@ #include "winnt.h" #include "mapiutil.h" #include "mapitags.h" +#include "mapi32_test.h" static HMODULE hMapi32 = 0; @@ -51,7 +52,7 @@ static void test_SwapPword(void) shorts[1] = 0x10ff; shorts[2] = 0x2001; pSwapPword(shorts, 2); - ok(shorts[0] == 0x01ff && shorts[1] == 0xff10 && shorts[2] == 0x2001, + ok((shorts[0] == 0x01ff && shorts[1] == 0xff10 && shorts[2] == 0x2001), "Expected {0x01ff,0xff10,0x2001}, got {0x%04x,0x%04x,0x%04x}\n", shorts[0], shorts[1], shorts[2]); } @@ -68,7 +69,7 @@ static void test_SwapPlong(void) longs[1] = 0x1000ffff; longs[2] = 0x20000001; pSwapPlong(longs, 2); - ok(longs[0] == 0x0100ffff && longs[1] == 0xffff0010 && longs[2] == 0x20000001, + ok((longs[0] == 0x0100ffff && longs[1] == 0xffff0010 && longs[2] == 0x20000001), "Expected {0x0100ffff,0xffff0010,0x20000001}, got {0x%08x,0x%08x,0x%08x}\n", longs[0], longs[1], longs[2]); } @@ -151,7 +152,8 @@ static void test_CbOfEncoded(void) memset(buff, '\0', sizeof(buff)); memset(buff, '?', i); ulRet = pCbOfEncoded(buff); - ok(ulRet == ulExpected, "CbOfEncoded(length %d): expected %d, got %d\n", + ok(ulRet == ulExpected, + "CbOfEncoded(length %d): expected %d, got %d\n", i, ulExpected, ulRet); } } @@ -171,13 +173,19 @@ START_TEST(util) { SCODE ret; + if (!HaveDefaultMailClient()) + { + win_skip("No default mail client installed\n"); + return; + } + hMapi32 = LoadLibraryA("mapi32.dll"); pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4"); if (!pScInitMapiUtil) { - skip("ScInitMapiUtil is not available\n"); + win_skip("ScInitMapiUtil is not available\n"); FreeLibrary(hMapi32); return; } @@ -186,7 +194,13 @@ START_TEST(util) ret = pScInitMapiUtil(0); if ((ret != S_OK) && (GetLastError() == ERROR_PROC_NOT_FOUND)) { - skip("ScInitMapiUtil is not implemented\n"); + win_skip("ScInitMapiUtil is not implemented\n"); + FreeLibrary(hMapi32); + return; + } + else if ((ret == E_FAIL) && (GetLastError() == ERROR_INVALID_HANDLE)) + { + win_skip("ScInitMapiUtil doesn't work on some Win98 and WinME systems\n"); FreeLibrary(hMapi32); return; } diff --git a/rostests/winetests/mlang/mlang.c b/rostests/winetests/mlang/mlang.c index 115080eb692..ac881857990 100644 --- a/rostests/winetests/mlang/mlang.c +++ b/rostests/winetests/mlang/mlang.c @@ -2,6 +2,7 @@ * Unit test suite for MLANG APIs. * * Copyright 2004 Dmitry Timoshkov + * Copyright 2009 Detlef Riekenberg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,10 +22,12 @@ #define COBJMACROS #include +#include #include "windef.h" #include "winbase.h" #include "winerror.h" +#include "initguid.h" #include "mlang.h" #include "wine/test.h" @@ -42,20 +45,242 @@ #endif #endif /* 0 */ -#define TRACE_2 OutputDebugStringA +static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA); +static HRESULT (WINAPI *pConvertINetMultiByteToUnicode)(LPDWORD, DWORD, LPCSTR, + LPINT, LPWSTR, LPINT); +static HRESULT (WINAPI *pConvertINetUnicodeToMultiByte)(LPDWORD, DWORD, LPCWSTR, + LPINT, LPSTR, LPINT); +static HRESULT (WINAPI *pRfc1766ToLcidA)(LCID *, LPCSTR); +static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT); -static CHAR string1[MAX_PATH], string2[MAX_PATH]; +typedef struct lcid_tag_table { + LPCSTR rfc1766; + LCID lcid; + HRESULT hr; + LCID broken_lcid; + LPCSTR broken_rfc; +} lcid_table_entry; + +/* en, ar and zh use SUBLANG_NEUTRAL for the rfc1766 name without the country + all others suppress the country with SUBLANG_DEFAULT. + For 3 letter language codes, the rfc1766 is too small for the country */ + +static const lcid_table_entry lcid_table[] = { + {"e", -1, E_FAIL}, + {"", -1, E_FAIL}, + {"-", -1, E_FAIL}, + {"e-", -1, E_FAIL}, + + {"ar", 1, S_OK}, + {"zh", 4, S_OK}, + + {"de", 0x0407, S_OK}, + {"de-ch", 0x0807, S_OK}, + {"de-at", 0x0c07, S_OK}, + {"de-lu", 0x1007, S_OK}, + {"de-li", 0x1407, S_OK}, + + {"en", 9, S_OK}, + {"en-gb", 0x809, S_OK}, + {"en-GB", 0x809, S_OK}, + {"EN-GB", 0x809, S_OK}, + {"en-US", 0x409, S_OK}, + {"en-us", 0x409, S_OK}, + + {"fr", 0x040c, S_OK}, + {"fr-be", 0x080c, S_OK}, + {"fr-ca", 0x0c0c, S_OK}, + {"fr-ch", 0x100c, S_OK}, + {"fr-lu", 0x140c, S_OK}, + {"fr-mc", 0x180c, S_OK, 0x040c, "fr"}, + + {"it", 0x0410, S_OK}, + {"it-ch", 0x0810, S_OK}, + + {"nl", 0x0413, S_OK}, + {"nl-be", 0x0813, S_OK}, + {"pl", 0x0415, S_OK}, + {"ru", 0x0419, S_OK}, + + {"kok", 0x0457, S_OK, 0x0412, "x-kok"} + +}; + +#define TODO_NAME 1 + +typedef struct info_table_tag { + LCID lcid; + LANGID lang; + DWORD todo; + LPCSTR rfc1766; + LPCWSTR localename; + LPCWSTR broken_name; +} info_table_entry; + +static const WCHAR de_en[] = {'E','n','g','l','i','s','c','h',0}; +static const WCHAR de_enca[] = {'E','n','g','l','i','s','c','h',' ', + '(','K','a','n','a','d','a',')',0}; +static const WCHAR de_engb[] = {'E','n','g','l','i','s','c','h',' ', + '(','G','r','o',0xDF,'b','r','i','t','a','n','n','i','e','n',')',0}; +static const WCHAR de_engb2[] ={'E','n','g','l','i','s','c','h',' ', + '(','V','e','r','e','i','n','i','g','t','e','s',' ', + 'K',0xF6,'n','i','g','r','e','i','c',0}; +static const WCHAR de_enus[] = {'E','n','g','l','i','s','c','h',' ', + '(','U','S','A',')',0}; +static const WCHAR de_de[] = {'D','e','u','t','s','c','h',' ', + '(','D','e','u','t','s','c','h','l','a','n','d',')',0}; +static const WCHAR de_deat[] = {'D','e','u','t','s','c','h',' ', + '(',0xD6,'s','t','e','r','r','e','i','c','h',')',0}; +static const WCHAR de_dech[] = {'D','e','u','t','s','c','h',' ', + '(','S','c','h','w','e','i','z',')',0}; + +static const WCHAR en_en[] = {'E','n','g','l','i','s','h',0}; +static const WCHAR en_enca[] = {'E','n','g','l','i','s','h',' ', + '(','C','a','n','a','d','a',')',0}; +static const WCHAR en_engb[] = {'E','n','g','l','i','s','h',' ', + '(','U','n','i','t','e','d',' ','K','i','n','g','d','o','m',')',0}; +static const WCHAR en_enus[] = {'E','n','g','l','i','s','h',' ', + '(','U','n','i','t','e','d',' ','S','t','a','t','e','s',')',0}; +static const WCHAR en_de[] = {'G','e','r','m','a','n',' ', + '(','G','e','r','m','a','n','y',')',0}; +static const WCHAR en_deat[] = {'G','e','r','m','a','n',' ', + '(','A','u','s','t','r','i','a',')',0}; +static const WCHAR en_dech[] = {'G','e','r','m','a','n',' ', + '(','S','w','i','t','z','e','r','l','a','n','d',')',0}; + +static const WCHAR fr_en[] = {'A','n','g','l','a','i','s',0}; +static const WCHAR fr_enca[] = {'A','n','g','l','a','i','s',' ', + '(','C','a','n','a','d','a',')',0}; +static const WCHAR fr_engb[] = {'A','n','g','l','a','i','s',' ', + '(','R','o','y','a','u','m','e','-','U','n','i',')',0}; +static const WCHAR fr_enus[] = {'A','n','g','l','a','i','s',' ', + '(',0xC9, 't','a','t','s','-','U','n','i','s',')',0}; +static const WCHAR fr_enus2[] ={'A','n','g','l','a','i','s',' ', + '(','U','.','S','.',')',0}; +static const WCHAR fr_de[] = {'A','l','l','e','m','a','n','d',' ', + '(','A','l','l','e','m','a','g','n','e',')',0}; +static const WCHAR fr_de2[] = {'A','l','l','e','m','a','n','d',' ', + '(','S','t','a','n','d','a','r','d',')',0}; +static const WCHAR fr_deat[] = {'A','l','l','e','m','a','n','d',' ', + '(','A','u','t','r','i','c','h','e',')',0}; +static const WCHAR fr_dech[] = {'A','l','l','e','m','a','n','d',' ', + '(','S','u','i','s','s','e',')',0}; + +static const info_table_entry info_table[] = { + {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "en", en_en}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "en-us", en_enus}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "en-gb", en_engb}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "en-us", en_enus}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "en-ca", en_enca}, + + {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "de", en_de}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "de", en_de}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "de-ch", en_dech}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), + 0, "de-at", en_deat}, + + {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "en", de_en}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "en-us", de_enus}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "en-gb", de_engb, de_engb2}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "en-us", de_enus}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "en-ca", de_enca}, + + {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "de", de_de}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "de",de_de}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "de-ch", de_dech}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + TODO_NAME, "de-at", de_deat}, + + {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "en", fr_en}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "en-us", fr_enus, fr_enus2}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "en-gb", fr_engb}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "en-us", fr_enus, fr_enus2}, + {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "en-ca", fr_enca}, + + {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "de", fr_de, fr_de2}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "de", fr_de, fr_de2}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "de-ch", fr_dech}, + {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + TODO_NAME, "de-at", fr_deat} + +}; + +static BOOL init_function_ptrs(void) +{ + HMODULE hMlang; + + hMlang = LoadLibraryA("mlang.dll"); + if (!hMlang) + { + skip("mlang not available\n"); + return FALSE; + } + + pConvertINetMultiByteToUnicode = (void *)GetProcAddress(hMlang, "ConvertINetMultiByteToUnicode"); + pConvertINetUnicodeToMultiByte = (void *)GetProcAddress(hMlang, "ConvertINetUnicodeToMultiByte"); + pRfc1766ToLcidA = (void *)GetProcAddress(hMlang, "Rfc1766ToLcidA"); + pLcidToRfc1766A = (void *)GetProcAddress(hMlang, "LcidToRfc1766A"); + + pGetCPInfoExA = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCPInfoExA"); + + return TRUE; +} #define ok_w2(format, szString1, szString2) \ \ - if (lstrcmpW(szString1, szString2) != 0) \ + if (lstrcmpW((szString1), (szString2)) != 0) \ { \ - WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ - WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ - ok(0, format, string1, string2); \ + CHAR string1[256], string2[256]; \ + WideCharToMultiByte(CP_ACP, 0, (szString1), -1, string1, 256, NULL, NULL); \ + WideCharToMultiByte(CP_ACP, 0, (szString2), -1, string2, 256, NULL, NULL); \ + ok(0, (format), string1, string2); \ } -static BOOL (WINAPI *pGetCPInfoExA)(UINT,DWORD,LPCPINFOEXA); +/* lstrcmpW is not supported on Win9x! */ +static int mylstrcmpW(const WCHAR* str1, const WCHAR* str2) +{ + if (!str2) return 1; + while (*str1 && *str1==*str2) { + str1++; + str2++; + } + return *str1-*str2; +} + +/* lstrcpyW is not supported on Win95 */ +static void mylstrcpyW(WCHAR* str1, const WCHAR* str2) +{ + while (str2 && *str2) { + *str1 = *str2; + str1++; + str2++; + } + *str1 = '\0'; +} static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) { @@ -66,24 +291,12 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) WCHAR bufW[256]; UINT lenA, lenW, expected_len; HRESULT ret; - HMODULE hMlang; - FARPROC pConvertINetMultiByteToUnicode; - FARPROC pConvertINetUnicodeToMultiByte; - - hMlang = LoadLibraryA("mlang.dll"); - ok(hMlang != 0, "couldn't load mlang.dll\n"); - - pConvertINetMultiByteToUnicode = GetProcAddress(hMlang, "ConvertINetMultiByteToUnicode"); - ok(pConvertINetMultiByteToUnicode != NULL, "couldn't resolve ConvertINetMultiByteToUnicode\n"); - pConvertINetUnicodeToMultiByte = GetProcAddress(hMlang, "ConvertINetUnicodeToMultiByte"); - ok(pConvertINetUnicodeToMultiByte != NULL, "couldn't resolve ConvertINetUnicodeToMultiByte\n"); /* IMultiLanguage2_ConvertStringToUnicode tests */ memset(bufW, 'x', sizeof(bufW)); lenA = 0; lenW = sizeof(bufW)/sizeof(bufW[0]); - TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n"); ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW); ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret); ok(lenA == 0, "expected lenA 0, got %u\n", lenA); @@ -92,7 +305,6 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufW, 'x', sizeof(bufW)); lenA = -1; lenW = sizeof(bufW)/sizeof(bufW[0]); - TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n"); ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW); ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret); ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); @@ -107,7 +319,6 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufW, 'x', sizeof(bufW)); lenA = -1; lenW = 5; - TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n"); ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW); ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringToUnicode should fail: %08x\n", ret); ok(lenW == 0, "expected lenW 0, got %u\n", lenW); @@ -117,7 +328,6 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufW, 'x', sizeof(bufW)); lenA = -1; lenW = sizeof(bufW)/sizeof(bufW[0]); - TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n"); ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, CP_UNICODE, stringA, &lenA, bufW, &lenW); ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret); ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); @@ -138,7 +348,7 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufW, 'x', sizeof(bufW)); lenA = lstrlenA(stringA); lenW = sizeof(bufW)/sizeof(bufW[0]); - ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, &lenA, NULL, &lenW); + ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW); ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret); ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0); @@ -147,7 +357,7 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufW, 'x', sizeof(bufW)); lenA = lstrlenA(stringA); lenW = 0; - ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, &lenA, NULL, &lenW); + ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW); ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret); ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0); @@ -158,7 +368,6 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufA, 'x', sizeof(bufA)); lenW = 0; lenA = sizeof(bufA); - TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n"); ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA); ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret); ok(lenA == 0, "expected lenA 0, got %u\n", lenA); @@ -167,7 +376,6 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufA, 'x', sizeof(bufA)); lenW = -1; lenA = sizeof(bufA); - TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n"); ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA); ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret); ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA); @@ -179,7 +387,6 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufA, 'x', sizeof(bufA)); lenW = -1; lenA = 5; - TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n"); ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA); ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringFromUnicode should fail: %08x\n", ret); ok(lenA == 0, "expected lenA 0, got %u\n", lenA); @@ -189,7 +396,6 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) memset(bufA, 'x', sizeof(bufA)); lenW = -1; lenA = sizeof(bufA); - TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n"); ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, CP_UNICODE, stringW, &lenW, bufA, &lenA); ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret); ok(lenA == lstrlenA(stringA) * (int)sizeof(WCHAR), "wrong lenA %u\n", lenA); @@ -207,27 +413,9 @@ static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW); expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL); ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA); - - memset(bufA, 'x', sizeof(bufA)); - lenW = lstrlenW(stringW); - lenA = sizeof(bufA); - ret = pConvertINetUnicodeToMultiByte(NULL, 1252, stringW, &lenW, NULL, &lenA); - ok(ret == S_OK, "ConvertINetUnicodeToMultiByte failed: %08x\n", ret); - ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW); - expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL); - ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA); - - memset(bufA, 'x', sizeof(bufA)); - lenW = lstrlenW(stringW); - lenA = 0; - ret = pConvertINetUnicodeToMultiByte(NULL, 1252, stringW, &lenW, NULL, &lenA); - ok(ret == S_OK, "ConvertINetUnicodeToMultiByte failed: %08x\n", ret); - ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW); - expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL); - ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA); } -static inline void cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2) +static void cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2) { ok(cpinfo1->dwFlags == cpinfo2->dwFlags, "dwFlags mismatch: %08x != %08x\n", cpinfo1->dwFlags, cpinfo2->dwFlags); ok(cpinfo1->uiCodePage == cpinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", cpinfo1->uiCodePage, cpinfo2->uiCodePage); @@ -266,7 +454,7 @@ static const char *dump_mime_flags(DWORD flags) } #endif -static BOOL check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to) +static HRESULT check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to) { CHAR convert[MAX_PATH]; BYTE dest[MAX_PATH]; @@ -275,21 +463,37 @@ static BOOL check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to) static WCHAR strW[] = {'a','b','c',0}; - srcsz = -1; + /* Check to see if the target codepage has these characters or not */ + if (from != CP_UTF8) + { + BOOL fDefaultChar; + char ch[10]; + int cb; + cb = WideCharToMultiByte( from, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR, + strW, 3, ch, sizeof(ch), NULL, &fDefaultChar); + + if(cb == 0 || fDefaultChar) + { + trace("target codepage %i does not contain 'abc'\n",from); + return E_FAIL; + } + } + + srcsz = lstrlenW(strW) + 1; destsz = MAX_PATH; hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, from, strW, &srcsz, convert, &destsz); if (hr != S_OK) - return FALSE; + return S_FALSE; srcsz = -1; destsz = MAX_PATH; hr = IMultiLanguage2_ConvertString(iML2, NULL, from, to, (BYTE *)convert, &srcsz, dest, &destsz); if (hr != S_OK) - return FALSE; + return S_FALSE; - return TRUE; + return S_OK; } static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) @@ -302,38 +506,35 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) UINT total; total = 0; - TRACE_2("Call IMultiLanguage2_GetNumberOfCodePageInfo\n"); ret = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &total); ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfCodePageInfo: expected S_OK/!0, got %08x/%u\n", ret, total); trace("total mlang supported codepages %u\n", total); - TRACE_2("Call IMultiLanguage2_EnumCodePages\n"); ret = IMultiLanguage2_EnumCodePages(iML2, flags, LANG_NEUTRAL, &iEnumCP); - trace("IMultiLanguage2_EnumCodePages = %08x, iEnumCP = %p\n", ret, iEnumCP); ok(ret == S_OK && iEnumCP, "IMultiLanguage2_EnumCodePages: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumCP); - TRACE_2("Call IEnumCodePage_Reset\n"); ret = IEnumCodePage_Reset(iEnumCP); ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret); n = 65536; - TRACE_2("Call IEnumCodePage_Next\n"); ret = IEnumCodePage_Next(iEnumCP, 0, NULL, &n); + if (ret == S_FALSE) ok(n == 0 && ret == S_FALSE, "IEnumCodePage_Next: expected 0/S_FALSE, got %u/%08x\n", n, ret); - TRACE_2("Call IEnumCodePage_Next\n"); + else if (ret == E_FAIL) + ok(n == 65536 && ret == E_FAIL, "IEnumCodePage_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret); ret = IEnumCodePage_Next(iEnumCP, 0, NULL, NULL); + if (ret == S_FALSE) ok(ret == S_FALSE, "IEnumCodePage_Next: expected S_FALSE, got %08x\n", ret); + else if (ret == E_FAIL) + ok(n == 65536 && ret == E_FAIL, "IEnumCodePage_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret); cpinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo) * total * 2); n = total * 2; - TRACE_2("Call IEnumCodePage_Next\n"); ret = IEnumCodePage_Next(iEnumCP, 0, cpinfo, &n); - trace("IEnumCodePage_Next = %08x, n = %u\n", ret, n); ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n); n = total * 2; - TRACE_2("Call IEnumCodePage_Next\n"); ret = IEnumCodePage_Next(iEnumCP, n, cpinfo, &n); ok(ret == S_OK && n != 0, "IEnumCodePage_Next: expected S_OK/!0, got %08x/%u\n", ret, n); @@ -352,9 +553,9 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) { CHARSETINFO csi; MIMECSETINFO mcsi; - BOOL convertible; - HRESULT check = S_OK; + HRESULT convertible = S_OK; static const WCHAR autoW[] = {'_','a','u','t','o',0}; + static const WCHAR feffW[] = {'u','n','i','c','o','d','e','F','E','F','F',0}; #ifdef DUMP_CP_INFO trace("MIMECPINFO #%u:\n" @@ -382,13 +583,15 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) #endif ok(cpinfo[i].dwFlags & flags, "enumerated flags %08x do not include requested %08x\n", cpinfo[i].dwFlags, flags); - if (TranslateCharsetInfo((DWORD *)cpinfo[i].uiFamilyCodePage, &csi, TCI_SRCCODEPAGE)) + if (TranslateCharsetInfo((DWORD *)(INT_PTR)cpinfo[i].uiFamilyCodePage, &csi, TCI_SRCCODEPAGE)) ok(cpinfo[i].bGDICharset == csi.ciCharset, "%d != %d\n", cpinfo[i].bGDICharset, csi.ciCharset); else + if (winetest_debug > 1) trace("TranslateCharsetInfo failed for cp %u\n", cpinfo[i].uiFamilyCodePage); +#ifdef DUMP_CP_INFO trace("%u: codepage %u family %u\n", i, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); - +#endif /* Win95 does not support UTF-7 */ if (cpinfo[i].uiCodePage == CP_UTF7) continue; @@ -397,27 +600,28 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) */ if (IsValidCodePage(cpinfo[i].uiCodePage)) { - TRACE_2("Call IMultiLanguage2_IsConvertible\n"); ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UNICODE); ok(ret == S_OK, "IMultiLanguage2_IsConvertible(%u -> CP_UNICODE) = %08x\n", cpinfo[i].uiCodePage, ret); - TRACE_2("Call IMultiLanguage2_IsConvertible\n"); ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, cpinfo[i].uiCodePage); ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08x\n", cpinfo[i].uiCodePage, ret); convertible = check_convertible(iML2, cpinfo[i].uiCodePage, CP_UTF8); - if (!convertible) - check = S_FALSE; - - TRACE_2("Call IMultiLanguage2_IsConvertible\n"); + if (convertible != E_FAIL) + { ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UTF8); - ok(ret == check, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo[i].uiCodePage, ret); - TRACE_2("Call IMultiLanguage2_IsConvertible\n"); + ok(ret == convertible, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo[i].uiCodePage, ret); ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, cpinfo[i].uiCodePage); - ok(ret == check, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo[i].uiCodePage, ret); + ok(ret == convertible, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo[i].uiCodePage, ret); + } } else + if (winetest_debug > 1) trace("IsValidCodePage failed for cp %u\n", cpinfo[i].uiCodePage); + if (memcmp(cpinfo[i].wszWebCharset,feffW,sizeof(WCHAR)*11)==0) + skip("Legacy windows bug returning invalid charset of unicodeFEFF\n"); + else + { ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszWebCharset, &mcsi); /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */ if (memcmp(cpinfo[i].wszWebCharset, autoW, 5 * sizeof(WCHAR))) @@ -443,7 +647,12 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); } } + } + if (memcmp(cpinfo[i].wszHeaderCharset,feffW,sizeof(WCHAR)*11)==0) + skip("Legacy windows bug returning invalid charset of unicodeFEFF\n"); + else + { ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszHeaderCharset, &mcsi); /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */ if (memcmp(cpinfo[i].wszHeaderCharset, autoW, 5 * sizeof(WCHAR))) @@ -469,7 +678,12 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); } } + } + if (memcmp(cpinfo[i].wszBodyCharset,feffW,sizeof(WCHAR)*11)==0) + skip("Legacy windows bug returning invalid charset of unicodeFEFF\n"); + else + { ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszBodyCharset, &mcsi); /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */ if (memcmp(cpinfo[i].wszBodyCharset, autoW, 5 * sizeof(WCHAR))) @@ -496,6 +710,7 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) } } } + } /* now IEnumCodePage_Next should fail, since pointer is at the end */ n = 1; @@ -529,7 +744,7 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) IEnumCodePage_Release(iEnumCP); } -static inline void scriptinfo_cmp(SCRIPTINFO *sinfo1, SCRIPTINFO *sinfo2) +static void scriptinfo_cmp(SCRIPTINFO *sinfo1, SCRIPTINFO *sinfo2) { ok(sinfo1->ScriptId == sinfo2->ScriptId, "ScriptId mismatch: %d != %d\n", sinfo1->ScriptId, sinfo2->ScriptId); ok(sinfo1->uiCodePage == sinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", sinfo1->uiCodePage, sinfo2->uiCodePage); @@ -548,37 +763,29 @@ static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags) UINT total; total = 0; - TRACE_2("Call IMultiLanguage2_GetNumberOfScripts\n"); ret = IMultiLanguage2_GetNumberOfScripts(iML2, &total); ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfScripts: expected S_OK/!0, got %08x/%u\n", ret, total); trace("total mlang supported scripts %u\n", total); - TRACE_2("Call IMultiLanguage2_EnumScripts\n"); ret = IMultiLanguage2_EnumScripts(iML2, flags, LANG_NEUTRAL, &iEnumScript); - trace("IMultiLanguage2_EnumScripts = %08x, iEnumScript = %p\n", ret, iEnumScript); ok(ret == S_OK && iEnumScript, "IMultiLanguage2_EnumScripts: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumScript); - TRACE_2("Call IEnumScript_Reset\n"); ret = IEnumScript_Reset(iEnumScript); ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret); n = 65536; - TRACE_2("Call IEnumScript_Next\n"); ret = IEnumScript_Next(iEnumScript, 0, NULL, &n); ok(n == 65536 && ret == E_FAIL, "IEnumScript_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret); - TRACE_2("Call IEnumScript_Next\n"); ret = IEnumScript_Next(iEnumScript, 0, NULL, NULL); ok(ret == E_FAIL, "IEnumScript_Next: expected E_FAIL, got %08x\n", ret); sinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*sinfo) * total * 2); n = total * 2; - TRACE_2("Call IEnumScript_Next\n"); ret = IEnumScript_Next(iEnumScript, 0, sinfo, &n); ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n); n = total * 2; - TRACE_2("Call IEnumScript_Next\n"); ret = IEnumScript_Next(iEnumScript, n, sinfo, &n); ok(ret == S_OK && n != 0, "IEnumScript_Next: expected S_OK, got %08x/%u\n", ret, n); @@ -607,8 +814,8 @@ static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags) wine_dbgstr_w(sinfo[i].wszDescription), wine_dbgstr_w(sinfo[i].wszFixedWidthFont), wine_dbgstr_w(sinfo[i].wszProportionalFont)); -#endif trace("%u codepage %u\n", i, sinfo[i].uiCodePage); +#endif } /* now IEnumScript_Next should fail, since pointer is at the end */ @@ -645,41 +852,142 @@ static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags) static void IMLangFontLink_Test(IMLangFontLink* iMLFL) { - DWORD dwCodePages = 0; - DWORD dwManyCodePages = 0; - UINT CodePage = 0; + DWORD dwCodePages, dwManyCodePages; + DWORD dwCmpCodePages; + UINT CodePage; + static const WCHAR str[3] = { 'd', 0x0436, 0xff90 }; + LONG processed; + HRESULT ret; - ok(IMLangFontLink_CodePageToCodePages(iMLFL, 932, &dwCodePages)==S_OK, - "IMLangFontLink_CodePageToCodePages failed\n"); - ok (dwCodePages != 0, "No CodePages returned\n"); - ok(IMLangFontLink_CodePagesToCodePage(iMLFL, dwCodePages, 1035, - &CodePage)==S_OK, - "IMLangFontLink_CodePagesToCodePage failed\n"); + dwCodePages = ~0u; + ret = IMLangFontLink_CodePageToCodePages(iMLFL, -1, &dwCodePages); + ok(ret == E_FAIL, "IMLangFontLink_CodePageToCodePages should fail: %x\n", ret); + ok(dwCodePages == 0, "expected 0, got %u\n", dwCodePages); + + dwCodePages = 0; + ret = IMLangFontLink_CodePageToCodePages(iMLFL, 932, &dwCodePages); + ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret); + ok(dwCodePages == FS_JISJAPAN, "expected FS_JISJAPAN, got %08x\n", dwCodePages); + CodePage = 0; + ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwCodePages, 1035, &CodePage); + ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret); ok(CodePage == 932, "Incorrect CodePage Returned (%i)\n",CodePage); - ok(IMLangFontLink_CodePageToCodePages(iMLFL, 1252, &dwCodePages)==S_OK, - "IMLangFontLink_CodePageToCodePages failed\n"); - dwManyCodePages = dwManyCodePages | dwCodePages; - ok(IMLangFontLink_CodePageToCodePages(iMLFL, 1256, &dwCodePages)==S_OK, - "IMLangFontLink_CodePageToCodePages failed\n"); - dwManyCodePages = dwManyCodePages | dwCodePages; - ok(IMLangFontLink_CodePageToCodePages(iMLFL, 874, &dwCodePages)==S_OK, - "IMLangFontLink_CodePageToCodePages failed\n"); - dwManyCodePages = dwManyCodePages | dwCodePages; + dwManyCodePages = 0; + ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1252, &dwManyCodePages); + ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret); + ok(dwManyCodePages == FS_LATIN1, "expected FS_LATIN1, got %08x\n", dwManyCodePages); + dwCodePages = 0; + ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1256, &dwCodePages); + ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret); + ok(dwCodePages == FS_ARABIC, "expected FS_ARABIC, got %08x\n", dwCodePages); + dwManyCodePages |= dwCodePages; + ret = IMLangFontLink_CodePageToCodePages(iMLFL, 874, &dwCodePages); + ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret); + ok(dwCodePages == FS_THAI, "expected FS_THAI, got %08x\n", dwCodePages); + dwManyCodePages |= dwCodePages; - ok(IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 1256, - &CodePage)==S_OK, - "IMLangFontLink_CodePagesToCodePage failed\n"); + ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 1256, &CodePage); + ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret); ok(CodePage == 1256, "Incorrect CodePage Returned (%i)\n",CodePage); - ok(IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 936, - &CodePage)==S_OK, - "IMLangFontLink_CodePagesToCodePage failed\n"); + ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 936, &CodePage); + ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret); ok(CodePage == 1252, "Incorrect CodePage Returned (%i)\n",CodePage); + + /* Tests for GetCharCodePages */ + + /* Latin 1 */ + dwCmpCodePages = FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC | FS_GREEK | FS_TURKISH + | FS_HEBREW | FS_ARABIC | FS_BALTIC | FS_VIETNAMESE | FS_THAI + | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG | FS_CHINESETRAD; + ret = IMLangFontLink_GetCharCodePages(iMLFL, 'd', &dwCodePages); + ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + + dwCodePages = 0; + processed = 0; + ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[0], 1, 0, &dwCodePages, &processed); + ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 1, "expected 1, got %d\n", processed); + + /* Cyrillic */ + dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG; + ret = IMLangFontLink_GetCharCodePages(iMLFL, 0x0436, &dwCodePages); + ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + + dwCodePages = 0; + processed = 0; + ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[1], 1, 0, &dwCodePages, &processed); + ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 1, "expected 1, got %d\n", processed); + + /* Japanese */ + dwCmpCodePages = FS_JISJAPAN; + ret = IMLangFontLink_GetCharCodePages(iMLFL, 0xff90, &dwCodePages); + ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + + dwCodePages = 0; + processed = 0; + ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed); + ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 1, "expected 1, got %d\n", processed); + + dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG; + dwCodePages = 0; + processed = 0; + ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 2, 0, &dwCodePages, &processed); + ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 2, "expected 2, got %d\n", processed); + + dwCmpCodePages = FS_JISJAPAN; + dwCodePages = 0; + processed = 0; + ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 3, 0, &dwCodePages, &processed); + ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 3, "expected 3, got %d\n", processed); + + dwCodePages = 0xffff; + processed = -1; + ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed); + ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); + ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 1, "expected 0, got %d\n", processed); + + ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, NULL, NULL); + ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret); + + dwCodePages = 0xffff; + processed = -1; + ret = IMLangFontLink_GetStrCodePages(iMLFL, str, -1, 0, &dwCodePages, &processed); + ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret); + ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 0, "expected 0, got %d\n", processed); + + dwCodePages = 0xffff; + processed = -1; + ret = IMLangFontLink_GetStrCodePages(iMLFL, NULL, 1, 0, &dwCodePages, &processed); + ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret); + ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 0, "expected 0, got %d\n", processed); + + dwCodePages = 0xffff; + processed = -1; + ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 0, 0, &dwCodePages, &processed); + ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret); + ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages); + ok(processed == 0, "expected 0, got %d\n", processed); } /* copied from libs/wine/string.c */ -WCHAR *strstrW(const WCHAR *str, const WCHAR *sub) +static WCHAR *strstrW(const WCHAR *str, const WCHAR *sub) { while (*str) { @@ -730,95 +1038,957 @@ static void test_rfc1766(IMultiLanguage2 *iML2) static void test_GetLcidFromRfc1766(IMultiLanguage2 *iML2) { + WCHAR rfc1766W[MAX_RFC1766_NAME + 1]; LCID lcid; HRESULT ret; + DWORD i; - static WCHAR e[] = { 'e',0 }; static WCHAR en[] = { 'e','n',0 }; - static WCHAR empty[] = { 0 }; - static WCHAR dash[] = { '-',0 }; - static WCHAR e_dash[] = { 'e','-',0 }; - static WCHAR en_gb[] = { 'e','n','-','g','b',0 }; - static WCHAR en_us[] = { 'e','n','-','u','s',0 }; static WCHAR en_them[] = { 'e','n','-','t','h','e','m',0 }; static WCHAR english[] = { 'e','n','g','l','i','s','h',0 }; + + for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) { + lcid = -1; + MultiByteToWideChar(CP_ACP, 0, lcid_table[i].rfc1766, -1, rfc1766W, MAX_RFC1766_NAME); + ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, rfc1766W); + + /* IE <6.0 guess 0x412 (ko) from "kok" */ + ok((ret == lcid_table[i].hr) || + broken(lcid_table[i].broken_lcid && (ret == S_FALSE)), + "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr); + + ok((lcid == lcid_table[i].lcid) || + broken(lcid == lcid_table[i].broken_lcid), /* IE <6.0 */ + "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid); + } + + ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, NULL, en); ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret); ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, NULL); ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret); - ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, e); - ok(ret == E_FAIL, "GetLcidFromRfc1766 returned: %08x\n", ret); - - ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, empty); - ok(ret == E_FAIL, "GetLcidFromRfc1766 returned: %08x\n", ret); - - ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, dash); - ok(ret == E_FAIL, "GetLcidFromRfc1766 returned: %08x\n", ret); - - ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, e_dash); - ok(ret == E_FAIL, "GetLcidFromRfc1766 returned: %08x\n", ret); - ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, en_them); - ok(ret == E_FAIL, "GetLcidFromRfc1766 returned: %08x\n", ret); + ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret); + if (ret == S_FALSE) + { + BSTR rfcstr; + static WCHAR en[] = {'e','n',0}; + + ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + ok_w2("Expected \"%s\", got \"%s\"n", en, rfcstr); + } ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, english); - ok(ret == E_FAIL, "GetLcidFromRfc1766 returned: %08x\n", ret); + ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret); + if (ret == S_FALSE) + { + BSTR rfcstr; + static WCHAR en[] = {'e','n',0}; - lcid = 0; + ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + ok_w2("Expected \"%s\", got \"%s\"n", en, rfcstr); + } - ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, en); - ok(ret == S_OK, "GetLcidFromRfc1766 returned: %08x\n", ret); - ok(lcid == 9, "got wrong lcid: %04x\n", lcid); +} - ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, en_gb); - ok(ret == S_OK, "GetLcidFromRfc1766 returned: %08x\n", ret); - ok(lcid == 0x809, "got wrong lcid: %04x\n", lcid); +static void test_Rfc1766ToLcid(void) +{ + LCID lcid; + HRESULT ret; + DWORD i; + + for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) { + lcid = -1; + ret = pRfc1766ToLcidA(&lcid, lcid_table[i].rfc1766); + + /* IE <6.0 guess 0x412 (ko) from "kok" */ + ok( (ret == lcid_table[i].hr) || + broken(lcid_table[i].broken_lcid && (ret == S_FALSE)), + "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr); + + ok( (lcid == lcid_table[i].lcid) || + broken(lcid == lcid_table[i].broken_lcid), /* IE <6.0 */ + "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid); + } + + ret = pRfc1766ToLcidA(&lcid, NULL); + ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret); + + ret = pRfc1766ToLcidA(NULL, "en"); + ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret); +} + +static void test_GetNumberOfCodePageInfo(IMultiLanguage2 *iML2) +{ + HRESULT hr; + UINT value; + + value = 0xdeadbeef; + hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &value); + ok( (hr == S_OK) && value, + "got 0x%x with %d (expected S_OK with '!= 0')\n", hr, value); + + hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, NULL); + ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr); - ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, en_us); - ok(ret == S_OK, "GetLcidFromRfc1766 returned: %08x\n", ret); - ok(lcid == 0x409, "got wrong lcid: %04x\n", lcid); } static void test_GetRfc1766FromLcid(IMultiLanguage2 *iML2) { + CHAR expected[MAX_RFC1766_NAME]; + CHAR buffer[MAX_RFC1766_NAME + 1]; + DWORD i; HRESULT hr; BSTR rfcstr; - LCID lcid; - static WCHAR kok[] = {'k','o','k',0}; + for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) { + buffer[0] = '\0'; - hr = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, kok); + rfcstr = NULL; + hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid_table[i].lcid, &rfcstr); + ok(hr == lcid_table[i].hr, + "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr); + + if (hr != S_OK) + continue; /* no result-string created */ + + WideCharToMultiByte(CP_ACP, 0, rfcstr, -1, buffer, sizeof(buffer), NULL, NULL); + LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, lcid_table[i].rfc1766, + lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME); + + /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */ + ok( (!lstrcmpA(buffer, expected)) || + broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)), + "#%02d: got '%s' (expected '%s')\n", i, buffer, expected); + + SysFreeString(rfcstr); + } + + hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL); + ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr); +} + +static void test_LcidToRfc1766(void) +{ + CHAR expected[MAX_RFC1766_NAME]; + CHAR buffer[MAX_RFC1766_NAME * 2]; + HRESULT hr; + DWORD i; + + for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) { + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + + hr = pLcidToRfc1766A(lcid_table[i].lcid, buffer, MAX_RFC1766_NAME); + + /* IE <5.0 does not recognize 0x180c (fr-mc) and 0x457 (kok) */ + ok( (hr == lcid_table[i].hr) || + broken(lcid_table[i].broken_lcid && (hr == E_FAIL)), + "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr); + + if (hr != S_OK) + continue; + + LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, lcid_table[i].rfc1766, + lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME); + + /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */ + /* IE <5.0 return "fr" for LCID 0x180c ("fr-mc") */ + ok( (!lstrcmpA(buffer, expected)) || + broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)), + "#%02d: got '%s' (expected '%s')\n", i, buffer, expected); + + } + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pLcidToRfc1766A(-1, buffer, MAX_RFC1766_NAME); + ok(hr == E_FAIL, "got 0x%08x and '%s' (expected E_FAIL)\n", hr, buffer); + + hr = pLcidToRfc1766A(LANG_ENGLISH, NULL, MAX_RFC1766_NAME); + ok(hr == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", hr); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pLcidToRfc1766A(LANG_ENGLISH, buffer, -1); + ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pLcidToRfc1766A(LANG_ENGLISH, buffer, 0); + ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer); +} + +static void test_GetRfc1766Info(IMultiLanguage2 *iML2) +{ + WCHAR short_broken_name[MAX_LOCALE_NAME]; + CHAR rfc1766A[MAX_RFC1766_NAME + 1]; + BYTE buffer[sizeof(RFC1766INFO) + 4]; + PRFC1766INFO prfc = (RFC1766INFO *) buffer; + HRESULT ret; + DWORD i; + + for(i = 0; i < sizeof(info_table) / sizeof(info_table[0]); i++) { + memset(buffer, 'x', sizeof(RFC1766INFO) + 2); + buffer[sizeof(buffer) -1] = 0; + buffer[sizeof(buffer) -2] = 0; + + ret = IMultiLanguage2_GetRfc1766Info(iML2, info_table[i].lcid, info_table[i].lang, prfc); + WideCharToMultiByte(CP_ACP, 0, prfc->wszRfc1766, -1, rfc1766A, MAX_RFC1766_NAME, NULL, NULL); + ok(ret == S_OK, "#%02d: got 0x%x (expected S_OK)\n", i, ret); + ok(prfc->lcid == info_table[i].lcid, + "#%02d: got 0x%04x (expected 0x%04x)\n", i, prfc->lcid, info_table[i].lcid); + + ok(!lstrcmpA(rfc1766A, info_table[i].rfc1766), + "#%02d: got '%s' (expected '%s')\n", i, rfc1766A, info_table[i].rfc1766); + + /* Some IE versions truncate an oversized name one character to short */ + mylstrcpyW(short_broken_name, info_table[i].broken_name); + short_broken_name[MAX_LOCALE_NAME - 2] = '\0'; + + if (info_table[i].todo & TODO_NAME) { + todo_wine + ok( (!mylstrcmpW(prfc->wszLocaleName, info_table[i].localename)) || + broken(!mylstrcmpW(prfc->wszLocaleName, info_table[i].broken_name)) || /* IE < 6.0 */ + broken(!mylstrcmpW(prfc->wszLocaleName, short_broken_name)), + "#%02d: got %s (expected %s)\n", i, + wine_dbgstr_w(prfc->wszLocaleName), wine_dbgstr_w(info_table[i].localename)); + } + else + ok( (!mylstrcmpW(prfc->wszLocaleName, info_table[i].localename)) || + broken(!mylstrcmpW(prfc->wszLocaleName, info_table[i].broken_name)) || /* IE < 6.0 */ + broken(!mylstrcmpW(prfc->wszLocaleName, short_broken_name)), + "#%02d: got %s (expected %s)\n", i, + wine_dbgstr_w(prfc->wszLocaleName), wine_dbgstr_w(info_table[i].localename)); + + } + + /* SUBLANG_NEUTRAL only allowed for english, arabic, chinese */ + ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_GERMAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc); + ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret); + + ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_ITALIAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc); + ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret); + + /* NULL not allowed */ + ret = IMultiLanguage2_GetRfc1766Info(iML2, 0, LANG_ENGLISH, prfc); + ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret); + + ret = IMultiLanguage2_GetRfc1766Info(iML2, LANG_ENGLISH, LANG_ENGLISH, NULL); + ok(ret == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", ret); +} + +static void test_IMultiLanguage2_ConvertStringFromUnicode(IMultiLanguage2 *iML2) +{ + CHAR dest[MAX_PATH]; + CHAR invariate[MAX_PATH]; + UINT srcsz, destsz; + HRESULT hr; + + static WCHAR src[] = {'a','b','c',0}; + + memset(invariate, 'x', sizeof(invariate)); + + /* pSrcStr NULL */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = sizeof(dest); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL, + &srcsz, dest, &destsz); + ok(hr == S_OK || hr == E_FAIL,"expected S_OK or E_FAIL, got %08x\n",hr); + if (hr == S_OK) + { + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + } + else if (hr == E_FAIL) + { + ok(srcsz == 0, + "Expected %u, got %u\n", 0, srcsz); + } + + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + ok(destsz == 0, "Expected 0, got %u\n", destsz); + + /* pcSrcSize NULL */ + memset(dest, 'x', sizeof(dest)); + destsz = sizeof(dest); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + NULL, dest, &destsz); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!strncmp(dest, "abc", 3), + "Expected first three chars to be \"abc\"\n"); + ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), + "Expected rest of dest to be unchanged, got %s\n", dest); + ok(destsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), destsz); - hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr); + /* both pSrcStr and pcSrcSize NULL */ + memset(dest, 'x', sizeof(dest)); + destsz = sizeof(dest); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL, + NULL, dest, &destsz); + ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + ok(destsz == 0, "Expected 0, got %u\n", destsz); + + /* pDstStr NULL */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = sizeof(dest); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, NULL, &destsz); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); - ok_w2("Expected \"%s\", got \"%s\"n", kok, rfcstr); + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + ok(destsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); - SysFreeString(rfcstr); + /* pcDstSize NULL */ + memset(dest, 'x', sizeof(dest)); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, dest, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + + /* pcSrcSize is 0 */ + memset(dest, 'x', sizeof(dest)); + srcsz = 0; + destsz = sizeof(dest); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == 0, "Expected 0, got %u\n", srcsz); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + ok(destsz == 0, "Expected 0, got %u\n", destsz); + + /* pcSrcSize does not include NULL terminator */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src); + destsz = sizeof(dest); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), srcsz); + ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); + ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), + "Expected rest of dest to be unchanged, got %s\n", dest); + ok(destsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), destsz); + + /* pcSrcSize includes NULL terminator */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = sizeof(dest); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz); + ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest); + ok(destsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); + + /* pcSrcSize is -1 */ + memset(dest, 'x', sizeof(dest)); + srcsz = -1; + destsz = sizeof(dest); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), srcsz); + ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); + ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), + "Expected rest of dest to be unchanged, got %s\n", dest); + ok(destsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), destsz); + + /* pcDstSize is 0 */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = 0; + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + ok(destsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); + + /* pcDstSize is not large enough */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = lstrlenW(src); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, dest, &destsz); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + ok(srcsz == 0, "Expected 0, got %u\n", srcsz); + ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); + ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), + "Expected rest of dest to be unchanged, got %s\n", dest); + ok(destsz == 0, "Expected 0, got %u\n", srcsz); + + /* pcDstSize (bytes) does not leave room for NULL terminator */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = lstrlenW(src) * sizeof(WCHAR); + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src, + &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest); + ok(destsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); +} + +static void test_ConvertINetUnicodeToMultiByte(void) +{ + CHAR dest[MAX_PATH]; + CHAR invariate[MAX_PATH]; + INT srcsz, destsz; + HRESULT hr; + + static WCHAR src[] = {'a','b','c',0}; + + memset(invariate, 'x', sizeof(invariate)); + + /* lpSrcStr NULL */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = sizeof(dest); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, &srcsz, dest, &destsz); + ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr); + if (hr == S_OK) + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + else if (hr == E_FAIL) + ok(srcsz == 0, + "Expected %u, got %u\n", 0, srcsz); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + ok(destsz == 0, "Expected 0, got %u\n", destsz); + + /* lpnWideCharCount NULL */ + memset(dest, 'x', sizeof(dest)); + destsz = sizeof(dest); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, NULL, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!strncmp(dest, "abc", 3), + "Expected first three chars to be \"abc\"\n"); + ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), + "Expected rest of dest to be unchanged, got %s\n", dest); + ok(destsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), destsz); + + /* both lpSrcStr and lpnWideCharCount NULL */ + memset(dest, 'x', sizeof(dest)); + destsz = sizeof(dest); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, NULL, dest, &destsz); + ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + ok(destsz == 0, "Expected 0, got %u\n", destsz); + + /* lpDstStr NULL */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = sizeof(dest); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, NULL, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + ok(destsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + + /* lpnMultiCharCount NULL */ + memset(dest, 'x', sizeof(dest)); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + + /* lpnWideCharCount is 0 */ + memset(dest, 'x', sizeof(dest)); + srcsz = 0; + destsz = sizeof(dest); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == 0, "Expected 0, got %u\n", srcsz); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + ok(destsz == 0, "Expected 0, got %u\n", destsz); + + /* lpnWideCharCount does not include NULL terminator */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src); + destsz = sizeof(dest); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), srcsz); + ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); + ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), + "Expected rest of dest to be unchanged, got %s\n", dest); + ok(destsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), destsz); + + /* lpnWideCharCount includes NULL terminator */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = sizeof(dest); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz); + ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest); + ok(destsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); + + /* lpnWideCharCount is -1 */ + memset(dest, 'x', sizeof(dest)); + srcsz = -1; + destsz = sizeof(dest); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), srcsz); + ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); + ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), + "Expected rest of dest to be unchanged, got %s\n", dest); + ok(destsz == lstrlenW(src), + "Expected %u, got %u\n", lstrlenW(src), destsz); + + /* lpnMultiCharCount is 0 */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = 0; + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + ok(!memcmp(dest, invariate, sizeof(dest)), + "Expected dest to be unchanged, got %s\n", dest); + ok(destsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); + + /* lpnMultiCharCount is not large enough */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = lstrlenW(src); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + ok(srcsz == 0, "Expected 0, got %u\n", srcsz); + ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n"); + ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3), + "Expected rest of dest to be unchanged, got %s\n", dest); + ok(destsz == 0, "Expected 0, got %u\n", srcsz); + + /* lpnMultiCharCount (bytes) does not leave room for NULL terminator */ + memset(dest, 'x', sizeof(dest)); + srcsz = lstrlenW(src) + 1; + destsz = lstrlenW(src) * sizeof(WCHAR); + hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(srcsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz); + ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest); + ok(destsz == lstrlenW(src) + 1, + "Expected %u, got %u\n", lstrlenW(src) + 1, destsz); +} + +static void test_JapaneseConversion(void) +{ + /* Data */ + static WCHAR unc_jp[9][12] = { + {9,0x31,0x20,0x3042,0x3044,0x3046,0x3048,0x304a,0x000d,0x000a}, + {9,0x31,0x20,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x000d,0x000a}, + {9,0x31,0x20,0xff71,0xff72,0xff73,0xff74,0xff75,0x000d,0x000a}, + {9,0x31,0x20,0x3041,0x3043,0x3045,0x3047,0x3049,0x000d,0x000a}, + {9,0x31,0x20,0x30a1,0x30a3,0x30a5,0x30a7,0x30a9,0x000d,0x000a}, + {9,0x31,0x20,0xff67,0xff68,0xff69,0xff6a,0xff6b,0x000d,0x000a}, + {9,0x31,0x20,0x300c,0x65e5,0x672c,0x8a9e,0x300d,0x000d,0x000a}, + {7,0x31,0x20,0x25c7,0x25c7,0x3012,0x000d,0x000a}, + {11,0x31,0x20,0x203b,0x3010,0x0074,0x0065,0x0073,0x0074,0x3011,0x000d,0x000a} + }; + static CHAR jis_jp[9][27] = { + {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x22,0x24,0x24,0x24,0x26,0x24,0x28, + 0x24,0x2a,0x1b,0x28,0x42,0x0d,0x0a}, + {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28, + 0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a}, + {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28, + 0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a}, + {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x21,0x24,0x23,0x24,0x25,0x24,0x27, + 0x24,0x29,0x1b,0x28,0x42,0x0d,0x0a}, + {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27, + 0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a}, + {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27, + 0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a}, + {20,0x31,0x20,0x1b,0x24,0x42,0x21,0x56,0x46,0x7c,0x4b,0x5c,0x38,0x6c, + 0x21,0x57,0x1b,0x28,0x42,0x0d,0x0a}, + {16,0x31,0x20,0x1b,0x24,0x42,0x21,0x7e,0x21,0x7e,0x22,0x29,0x1b,0x28, + 0x42,0x0d,0x0a}, + {26,0x31,0x20,0x1b,0x24,0x42,0x22,0x28,0x21,0x5a,0x1b,0x28,0x42,0x74, + 0x65,0x73,0x74,0x1b,0x24,0x42,0x21,0x5b,0x1b,0x28,0x42,0x0d,0x0a} + }; + static CHAR sjis_jp[9][15] = { + {14,0x31,0x20,0x82,0xa0,0x82,0xa2,0x82,0xa4,0x82,0xa6,0x82,0xa8,0x0d,0x0a}, + {14,0x31,0x20,0x83,0x41,0x83,0x43,0x83,0x45,0x83,0x47,0x83,0x49,0x0d,0x0a}, + {9,0x31,0x20,0xb1,0xb2,0xb3,0xb4,0xb5,0x0d,0x0a}, + {14,0x31,0x20,0x82,0x9f,0x82,0xa1,0x82,0xa3,0x82,0xa5,0x82,0xa7,0x0d,0x0a}, + {14,0x31,0x20,0x83,0x40,0x83,0x42,0x83,0x44,0x83,0x46,0x83,0x48,0x0d,0x0a}, + {9,0x31,0x20,0xa7,0xa8,0xa9,0xaa,0xab,0x0d,0x0a}, + {14,0x31,0x20,0x81,0x75,0x93,0xfa,0x96,0x7b,0x8c,0xea,0x81,0x76,0x0d,0x0a}, + {10,0x31,0x20,0x81,0x9e,0x81,0x9e,0x81,0xa7,0x0d,0x0a}, + {14,0x31,0x20,0x81,0xa6,0x81,0x79,0x74,0x65,0x73,0x74,0x81,0x7a,0x0d,0x0a} + }; + static CHAR euc_jp[9][15] = { + {14,0x31,0x20,0xa4,0xa2,0xa4,0xa4,0xa4,0xa6,0xa4,0xa8,0xa4,0xaa,0x0d,0x0a}, + {14,0x31,0x20,0xa5,0xa2,0xa5,0xa4,0xa5,0xa6,0xa5,0xa8,0xa5,0xaa,0x0d,0x0a}, + {14,0x31,0x20,0x8e,0xb1,0x8e,0xb2,0x8e,0xb3,0x8e,0xb4,0x8e,0xb5,0x0d,0x0a}, + {14,0x31,0x20,0xa4,0xa1,0xa4,0xa3,0xa4,0xa5,0xa4,0xa7,0xa4,0xa9,0x0d,0x0a}, + {14,0x31,0x20,0xa5,0xa1,0xa5,0xa3,0xa5,0xa5,0xa5,0xa7,0xa5,0xa9,0x0d,0x0a}, + {14,0x31,0x20,0x8e,0xa7,0x8e,0xa8,0x8e,0xa9,0x8e,0xaa,0x8e,0xab,0x0d,0x0a}, + {14,0x31,0x20,0xa1,0xd6,0xc6,0xfc,0xcb,0xdc,0xb8,0xec,0xa1,0xd7,0x0d,0x0a}, + {10,0x31,0x20,0xa1,0xfe,0xa1,0xfe,0xa2,0xa9,0x0d,0x0a}, + {14,0x31,0x20,0xa2,0xa8,0xa1,0xda,0x74,0x65,0x73,0x74,0xa1,0xdb,0x0d,0x0a} + }; + + INT srcsz, destsz; + INT i; + HRESULT hr; + CHAR output[30]; + WCHAR outputW[30]; + int outlen; + + /* test unc->jis */ + for (i = 0; i < 9; i++) + { + int j; + destsz = 30; + outlen = jis_jp[i][0]; + srcsz = unc_jp[i][0]; + hr = pConvertINetUnicodeToMultiByte(NULL, 50220, &unc_jp[i][1], &srcsz, output, &destsz); + if (hr == S_FALSE) + { + skip("Code page identifier 50220 is not supported\n"); + break; + } + ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr); + ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz); + ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz); + ok(memcmp(output,&jis_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); + + /* and back */ + srcsz = outlen; + destsz = 30; + hr = pConvertINetMultiByteToUnicode(NULL, 50220, output, &srcsz, outputW,&destsz); + + /* + * JIS does not have hankata so it get automatically converted to + * zenkata. this means that strings 1 and 2 are identical as well as + * strings 4 and 5. + */ + j = i; + if (i == 2) j = 1; + if (i == 5) j = 4; + + ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i, hr); + ok(destsz == unc_jp[j][0],"(%i) Expected %i, got %i\n",i,unc_jp[j][0],destsz); + ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz); + ok(memcmp(outputW,&unc_jp[j][1],destsz)==0,"(%i) Strings do not match\n",i); + } + + /* test unc->sjis */ + for (i = 0; i < 9; i++) + { + destsz = 30; + outlen = sjis_jp[i][0]; + srcsz = unc_jp[i][0]; + + hr = pConvertINetUnicodeToMultiByte(NULL, 932, &unc_jp[i][1], &srcsz, output, &destsz); + if (hr == S_FALSE) + { + skip("Code page identifier 932 is not supported\n"); + break; + } + ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr); + ok(destsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,destsz); + ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz); + ok(memcmp(output,&sjis_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i); + + srcsz = outlen; + destsz = 30; + hr = pConvertINetMultiByteToUnicode(NULL, 932, output, &srcsz, outputW,&destsz); + + ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr); + ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); + ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz); + ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); + } + + /* test unc->euc */ + for (i = 0; i < 9; i++) + { + destsz = 30; + outlen = euc_jp[i][0]; + srcsz = unc_jp[i][0]; + + hr = pConvertINetUnicodeToMultiByte(NULL, 51932, &unc_jp[i][1], &srcsz, output, &destsz); + if (hr == S_FALSE) + { + skip("Code page identifier 51932 is not supported\n"); + break; + } + ok(hr == S_OK, "(%i) Expected S_OK, got %08x\n",i,hr); + ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz); + ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); + ok(memcmp(output,&euc_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i); + + srcsz = outlen; + destsz = 30; + hr = pConvertINetMultiByteToUnicode(NULL, 51932, output, &srcsz, outputW,&destsz); + + ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr); + ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); + ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz); + ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); + } + + /* Japanese autodetect */ + i = 0; + destsz = 30; + srcsz = jis_jp[i][0]; + hr = pConvertINetMultiByteToUnicode(NULL, 50932, &jis_jp[i][1], &srcsz, outputW, &destsz); + if (hr == S_FALSE) + { + skip("Code page identifier 50932 is not supported\n"); + return; + } + ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr); + ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); + ok(srcsz == jis_jp[i][0],"(%i) Expected %i, got %i\n",i,jis_jp[i][0],srcsz); + ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); + + i = 1; + destsz = 30; + srcsz = sjis_jp[i][0]; + hr = pConvertINetMultiByteToUnicode(NULL, 50932, &sjis_jp[i][1], &srcsz, outputW, &destsz); + ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr); + ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz); + ok(srcsz == sjis_jp[i][0],"(%i) Expected %i, got %i\n",i,sjis_jp[i][0],srcsz); + ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i); +} + +static void test_GetScriptFontInfo(IMLangFontLink2 *font_link) +{ + HRESULT hr; + UINT nfonts; + SCRIPTFONTINFO sfi[1]; + + nfonts = 0; + hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, 0, &nfonts, NULL); + ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); + ok(nfonts, "unexpected result\n"); + + nfonts = 0; + hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, NULL); + ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); + ok(nfonts, "unexpected result\n"); + + nfonts = 0; + hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, NULL); + ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); + ok(nfonts, "unexpected result\n"); + + nfonts = 1; + memset(sfi, 0, sizeof(sfi)); + hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, sfi); + ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); + ok(nfonts == 1, "got %u, expected 1\n", nfonts); + ok(sfi[0].scripts != 0, "unexpected result\n"); + ok(sfi[0].wszFont[0], "unexpected result\n"); + + nfonts = 1; + memset(sfi, 0, sizeof(sfi)); + hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, sfi); + ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError()); + ok(nfonts == 1, "got %u, expected 1\n", nfonts); + ok(sfi[0].scripts != 0, "unexpected result\n"); + ok(sfi[0].wszFont[0], "unexpected result\n"); +} + +static void test_CodePageToScriptID(IMLangFontLink2 *font_link) +{ + HRESULT hr; + UINT i; + SCRIPT_ID sid; + static const struct + { + UINT cp; + SCRIPT_ID sid; + HRESULT hr; + } + cp_sid[] = + { + {874, sidThai}, + {932, sidKana}, + {936, sidHan}, + {949, sidHangul}, + {950, sidBopomofo}, + {1250, sidAsciiLatin}, + {1251, sidCyrillic}, + {1252, sidAsciiLatin}, + {1253, sidGreek}, + {1254, sidAsciiLatin}, + {1255, sidHebrew}, + {1256, sidArabic}, + {1257, sidAsciiLatin}, + {1258, sidAsciiLatin}, + {CP_UNICODE, 0, E_FAIL} + }; + + for (i = 0; i < sizeof(cp_sid)/sizeof(cp_sid[0]); i++) + { + hr = IMLangFontLink2_CodePageToScriptID(font_link, cp_sid[i].cp, &sid); + ok(hr == cp_sid[i].hr, "%u CodePageToScriptID failed 0x%08x %u\n", i, hr, GetLastError()); + if (SUCCEEDED(hr)) + { + ok(sid == cp_sid[i].sid, + "%u got sid %u for codepage %u, expected %u\n", i, sid, cp_sid[i].cp, cp_sid[i].sid); + } + } +} + +static void test_GetFontUnicodeRanges(IMLangFontLink2 *font_link) +{ + HRESULT hr; + UINT count; + HFONT hfont, old_hfont; + LOGFONTA lf; + HDC hdc; + UNICODERANGE *ur; + + hdc = CreateCompatibleDC(0); + memset(&lf, 0, sizeof(lf)); + lstrcpyA(lf.lfFaceName, "Arial"); + hfont = CreateFontIndirectA(&lf); + old_hfont = SelectObject(hdc, hfont); + + count = 0; + hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, NULL, &count, NULL); + ok(hr == E_FAIL, "expected E_FAIL, got 0x%08x\n", hr); + + hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, NULL, NULL); + ok(hr == E_INVALIDARG, "expected E_FAIL, got 0x%08x\n", hr); + + count = 0; + hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, NULL); + ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); + ok(count, "expected count > 0\n"); + + ur = HeapAlloc(GetProcessHeap(), 0, sizeof(*ur) * count); + + hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, ur); + ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); + + count--; + hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, ur); + ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); + + HeapFree(GetProcessHeap(), 0, ur); + + SelectObject(hdc, old_hfont); + DeleteObject(hfont); + DeleteDC(hdc); +} + +static void test_IsCodePageInstallable(IMultiLanguage2 *ml2) +{ + UINT i; + HRESULT hr; + + SetLastError(0xdeadbeef); + lstrcmpW(NULL, NULL); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + /* This corruption leads (sometimes) to test failures in oleaut32 but also + * to the inability to use the Regional Settings. + * This only seems to be an issue with Win98 and IE6 (mlang version 6.0.2800.1106). + * + * A reboot restores the codepages again. + */ + win_skip("IsCodePageInstallable could mess up the codepages on Win98\n"); + return; + } + + for (i = 0; i < 0xffff; i++) + { + hr = IMultiLanguage2_IsCodePageInstallable(ml2, i); + + /* it would be better to use IMultiLanguage2_ValidateCodePageEx here but that brings + * up an installation dialog on some platforms, even when specifying CPIOD_PEEK. + */ + if (IsValidCodePage(i)) + ok(hr == S_OK, "code page %u is valid but not installable 0x%08x\n", i, hr); + } } START_TEST(mlang) { + IMultiLanguage *iML = NULL; IMultiLanguage2 *iML2 = NULL; IMLangFontLink *iMLFL = NULL; + IMLangFontLink2 *iMLFL2 = NULL; HRESULT ret; - pGetCPInfoExA = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCPInfoExA"); + if (!init_function_ptrs()) + return; CoInitialize(NULL); - TRACE_2("Call CoCreateInstance\n"); + test_Rfc1766ToLcid(); + test_LcidToRfc1766(); + + test_ConvertINetUnicodeToMultiByte(); + test_JapaneseConversion(); + + + trace("IMultiLanguage\n"); + ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, + &IID_IMultiLanguage, (void **)&iML); + if (ret != S_OK || !iML) return; + + test_GetNumberOfCodePageInfo((IMultiLanguage2 *)iML); + IMultiLanguage_Release(iML); + + + /* IMultiLanguage2 (IE5.0 and above) */ + trace("IMultiLanguage2\n"); ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, &IID_IMultiLanguage2, (void **)&iML2); - - trace("ret = %08x, MultiLanguage2 iML2 = %p\n", ret, iML2); if (ret != S_OK || !iML2) return; test_rfc1766(iML2); test_GetLcidFromRfc1766(iML2); test_GetRfc1766FromLcid(iML2); + test_GetRfc1766Info(iML2); + test_GetNumberOfCodePageInfo(iML2); test_EnumCodePages(iML2, 0); test_EnumCodePages(iML2, MIMECONTF_MIME_LATEST); @@ -832,25 +2002,36 @@ START_TEST(mlang) test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER); test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM); - TRACE_2("Call IMultiLanguage2_IsConvertible\n"); ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, CP_UNICODE); ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08x\n", ret); - TRACE_2("Call IMultiLanguage2_IsConvertible\n"); ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, CP_UTF8); ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> CP_UTF8) = %08x\n", ret); test_multibyte_to_unicode_translations(iML2); + test_IMultiLanguage2_ConvertStringFromUnicode(iML2); + + test_IsCodePageInstallable(iML2); IMultiLanguage2_Release(iML2); + + /* IMLangFontLink */ ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, &IID_IMLangFontLink, (void **)&iMLFL); - - trace("ret = %08x, IMLangFontLink iMLFL = %p\n", ret, iMLFL); - if (ret != S_OK || !iML2) return; + if (ret != S_OK || !iMLFL) return; IMLangFontLink_Test(iMLFL); IMLangFontLink_Release(iMLFL); + /* IMLangFontLink2 */ + ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, + &IID_IMLangFontLink2, (void **)&iMLFL2); + if (ret != S_OK || !iMLFL2) return; + + test_GetScriptFontInfo(iMLFL2); + test_GetFontUnicodeRanges(iMLFL2); + test_CodePageToScriptID(iMLFL2); + IMLangFontLink2_Release(iMLFL2); + CoUninitialize(); } diff --git a/rostests/winetests/mlang/mlang.rbuild b/rostests/winetests/mlang/mlang.rbuild index 8cf5aebcc43..05d515cedbe 100644 --- a/rostests/winetests/mlang/mlang.rbuild +++ b/rostests/winetests/mlang/mlang.rbuild @@ -3,8 +3,7 @@ . - 0x600 - 0x600 + mlang.c testlist.c wine @@ -12,7 +11,6 @@ oleaut32 ole32 gdi32 - kernel32 ntdll diff --git a/rostests/winetests/msacm32/msacm.c b/rostests/winetests/msacm32/msacm.c index cfa6aea004c..26eeb478b63 100644 --- a/rostests/winetests/msacm32/msacm.c +++ b/rostests/winetests/msacm32/msacm.c @@ -29,12 +29,12 @@ #include "winnls.h" #include "mmsystem.h" #define NOBITMAP -#include "wine/mmreg.h" -#include "wine/msacm.h" +#include "mmreg.h" +#include "msacm.h" static BOOL CALLBACK FormatTagEnumProc(HACMDRIVERID hadid, PACMFORMATTAGDETAILS paftd, - DWORD dwInstance, + DWORD_PTR dwInstance, DWORD fdwSupport) { if (winetest_interactive) @@ -45,7 +45,7 @@ static BOOL CALLBACK FormatTagEnumProc(HACMDRIVERID hadid, static BOOL CALLBACK FormatEnumProc(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, - DWORD dwInstance, + DWORD_PTR dwInstance, DWORD fd) { if (winetest_interactive) @@ -55,11 +55,11 @@ static BOOL CALLBACK FormatEnumProc(HACMDRIVERID hadid, } static BOOL CALLBACK DriverEnumProc(HACMDRIVERID hadid, - DWORD dwInstance, + DWORD_PTR dwInstance, DWORD fdwSupport) { MMRESULT rc; - ACMDRIVERDETAILSA dd; + ACMDRIVERDETAILS dd; HACMDRIVER had; DWORD dwDriverPriority; @@ -275,9 +275,9 @@ static BOOL CALLBACK DriverEnumProc(HACMDRIVERID hadid, "acmMetrics(): rc = %08x, should be %08x\n", rc, MMSYSERR_NOERROR); if (rc == MMSYSERR_NOERROR) { - ACMFORMATDETAILSA fd; + ACMFORMATDETAILS fd; WAVEFORMATEX * pwfx; - ACMFORMATTAGDETAILSA aftd; + ACMFORMATTAGDETAILS aftd; /* try bad pointer */ rc = acmFormatEnum(had, 0, FormatEnumProc, 0, 0); diff --git a/rostests/winetests/msacm32/msacm32.rbuild b/rostests/winetests/msacm32/msacm32.rbuild index 40b1c9b73e5..477d64fdc50 100644 --- a/rostests/winetests/msacm32/msacm32.rbuild +++ b/rostests/winetests/msacm32/msacm32.rbuild @@ -3,10 +3,8 @@ . - 0x600 - 0x600 + wine - kernel32 msacm32 msacm.c testlist.c diff --git a/rostests/winetests/mscms/mscms.rbuild b/rostests/winetests/mscms/mscms.rbuild new file mode 100644 index 00000000000..8da6ea1ea1d --- /dev/null +++ b/rostests/winetests/mscms/mscms.rbuild @@ -0,0 +1,9 @@ + + . + + profile.c + testlist.c + wine + advapi32 + ntdll + diff --git a/rostests/winetests/mscms/profile.c b/rostests/winetests/mscms/profile.c new file mode 100644 index 00000000000..100c15c4f1f --- /dev/null +++ b/rostests/winetests/mscms/profile.c @@ -0,0 +1,1574 @@ +/* + * Tests for color profile functions + * + * Copyright 2004, 2005, 2006 Hans Leidekker + * + * 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 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winnls.h" +#include "wingdi.h" +#include "winuser.h" +#include "icm.h" + +#include "wine/test.h" + +HMODULE hmscms; +HMODULE huser32; + +static BOOL (WINAPI *pAssociateColorProfileWithDeviceA)(PCSTR,PCSTR,PCSTR); +static BOOL (WINAPI *pCloseColorProfile)(HPROFILE); +static BOOL (WINAPI *pDisassociateColorProfileFromDeviceA)(PCSTR,PCSTR,PCSTR); +static BOOL (WINAPI *pGetColorDirectoryA)(PCHAR,PCHAR,PDWORD); +static BOOL (WINAPI *pGetColorDirectoryW)(PWCHAR,PWCHAR,PDWORD); +static BOOL (WINAPI *pGetColorProfileElement)(HPROFILE,TAGTYPE,DWORD,PDWORD,PVOID,PBOOL); +static BOOL (WINAPI *pGetColorProfileElementTag)(HPROFILE,DWORD,PTAGTYPE); +static BOOL (WINAPI *pGetColorProfileFromHandle)(HPROFILE,PBYTE,PDWORD); +static BOOL (WINAPI *pGetColorProfileHeader)(HPROFILE,PPROFILEHEADER); +static BOOL (WINAPI *pGetCountColorProfileElements)(HPROFILE,PDWORD); +static BOOL (WINAPI *pGetStandardColorSpaceProfileA)(PCSTR,DWORD,PSTR,PDWORD); +static BOOL (WINAPI *pGetStandardColorSpaceProfileW)(PCWSTR,DWORD,PWSTR,PDWORD); +static BOOL (WINAPI *pEnumColorProfilesA)(PCSTR,PENUMTYPEA,PBYTE,PDWORD,PDWORD); +static BOOL (WINAPI *pEnumColorProfilesW)(PCWSTR,PENUMTYPEW,PBYTE,PDWORD,PDWORD); +static BOOL (WINAPI *pInstallColorProfileA)(PCSTR,PCSTR); +static BOOL (WINAPI *pInstallColorProfileW)(PCWSTR,PCWSTR); +static BOOL (WINAPI *pIsColorProfileTagPresent)(HPROFILE,TAGTYPE,PBOOL); +static HPROFILE (WINAPI *pOpenColorProfileA)(PPROFILE,DWORD,DWORD,DWORD); +static HPROFILE (WINAPI *pOpenColorProfileW)(PPROFILE,DWORD,DWORD,DWORD); +static BOOL (WINAPI *pSetColorProfileElement)(HPROFILE,TAGTYPE,DWORD,PDWORD,PVOID); +static BOOL (WINAPI *pSetColorProfileHeader)(HPROFILE,PPROFILEHEADER); +static BOOL (WINAPI *pSetStandardColorSpaceProfileA)(PCSTR,DWORD,PSTR); +static BOOL (WINAPI *pSetStandardColorSpaceProfileW)(PCWSTR,DWORD,PWSTR); +static BOOL (WINAPI *pUninstallColorProfileA)(PCSTR,PCSTR,BOOL); +static BOOL (WINAPI *pUninstallColorProfileW)(PCWSTR,PCWSTR,BOOL); + +static BOOL (WINAPI *pEnumDisplayDevicesA)(LPCSTR,DWORD,PDISPLAY_DEVICE,DWORD); + +#define GETFUNCPTR(func) p##func = (void *)GetProcAddress( hmscms, #func ); \ + if (!p##func) return FALSE; + +static BOOL init_function_ptrs( void ) +{ + GETFUNCPTR( AssociateColorProfileWithDeviceA ) + GETFUNCPTR( CloseColorProfile ) + GETFUNCPTR( DisassociateColorProfileFromDeviceA ) + GETFUNCPTR( GetColorDirectoryA ) + GETFUNCPTR( GetColorDirectoryW ) + GETFUNCPTR( GetColorProfileElement ) + GETFUNCPTR( GetColorProfileElementTag ) + GETFUNCPTR( GetColorProfileFromHandle ) + GETFUNCPTR( GetColorProfileHeader ) + GETFUNCPTR( GetCountColorProfileElements ) + GETFUNCPTR( GetStandardColorSpaceProfileA ) + GETFUNCPTR( GetStandardColorSpaceProfileW ) + GETFUNCPTR( EnumColorProfilesA ) + GETFUNCPTR( EnumColorProfilesW ) + GETFUNCPTR( InstallColorProfileA ) + GETFUNCPTR( InstallColorProfileW ) + GETFUNCPTR( IsColorProfileTagPresent ) + GETFUNCPTR( OpenColorProfileA ) + GETFUNCPTR( OpenColorProfileW ) + GETFUNCPTR( SetColorProfileElement ) + GETFUNCPTR( SetColorProfileHeader ) + GETFUNCPTR( SetStandardColorSpaceProfileA ) + GETFUNCPTR( SetStandardColorSpaceProfileW ) + GETFUNCPTR( UninstallColorProfileA ) + GETFUNCPTR( UninstallColorProfileW ) + + pEnumDisplayDevicesA = (void *)GetProcAddress( huser32, "EnumDisplayDevicesA" ); + + return TRUE; +} + +static const char machine[] = "dummy"; +static const WCHAR machineW[] = { 'd','u','m','m','y',0 }; + +/* To do any real functionality testing with this suite you need a copy of + * the freely distributable standard RGB color space profile. It comes + * standard with Windows, but on Wine you probably need to install it yourself + * in one of the locations mentioned below. + */ + +/* Two common places to find the standard color space profile, relative + * to the system directory. + */ +static const char profile1[] = +"\\color\\srgb color space profile.icm"; +static const char profile2[] = +"\\spool\\drivers\\color\\srgb color space profile.icm"; + +static const WCHAR profile1W[] = +{ '\\','c','o','l','o','r','\\','s','r','g','b',' ','c','o','l','o','r',' ', + 's','p','a','c','e',' ','p','r','o','f','i','l','e','.','i','c','m',0 }; +static const WCHAR profile2W[] = +{ '\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\', + 'c','o','l','o','r','\\','s','r','g','b',' ','c','o','l','o','r',' ', + 's','p','a','c','e',' ','p','r','o','f','i','l','e','.','i','c','m',0 }; + +static const unsigned char rgbheader[] = +{ 0x48, 0x0c, 0x00, 0x00, 0x6f, 0x6e, 0x69, 0x4c, 0x00, 0x00, 0x10, 0x02, + 0x72, 0x74, 0x6e, 0x6d, 0x20, 0x42, 0x47, 0x52, 0x20, 0x5a, 0x59, 0x58, + 0x02, 0x00, 0xce, 0x07, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x31, 0x00, + 0x70, 0x73, 0x63, 0x61, 0x54, 0x46, 0x53, 0x4d, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x43, 0x45, 0x49, 0x42, 0x47, 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf6, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x2d, 0xd3, 0x00, 0x00, 0x20, 0x20, 0x50, 0x48 }; + +static LPSTR standardprofile; +static LPWSTR standardprofileW; + +static LPSTR testprofile; +static LPWSTR testprofileW; + +#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/') + +static void MSCMS_basenameA( LPCSTR path, LPSTR name ) +{ + INT i = strlen( path ); + + while (i > 0 && !IS_SEPARATOR(path[i - 1])) i--; + strcpy( name, &path[i] ); +} + +static void MSCMS_basenameW( LPCWSTR path, LPWSTR name ) +{ + INT i = lstrlenW( path ); + + while (i > 0 && !IS_SEPARATOR(path[i - 1])) i--; + lstrcpyW( name, &path[i] ); +} + +static void test_GetColorDirectoryA(void) +{ + BOOL ret; + DWORD size; + char buffer[MAX_PATH]; + + /* Parameter checks */ + + ret = pGetColorDirectoryA( NULL, NULL, NULL ); + ok( !ret, "GetColorDirectoryA() succeeded (%d)\n", GetLastError() ); + + size = 0; + + ret = pGetColorDirectoryA( NULL, NULL, &size ); + ok( !ret && size > 0, "GetColorDirectoryA() succeeded (%d)\n", GetLastError() ); + + size = 0; + + ret = pGetColorDirectoryA( NULL, buffer, &size ); + ok( !ret && size > 0, "GetColorDirectoryA() succeeded (%d)\n", GetLastError() ); + + size = 1; + + ret = pGetColorDirectoryA( NULL, buffer, &size ); + ok( !ret && size > 0, "GetColorDirectoryA() succeeded (%d)\n", GetLastError() ); + + /* Functional checks */ + + size = sizeof(buffer); + + ret = pGetColorDirectoryA( NULL, buffer, &size ); + ok( ret && size > 0, "GetColorDirectoryA() failed (%d)\n", GetLastError() ); +} + +static void test_GetColorDirectoryW(void) +{ + BOOL ret; + DWORD size; + WCHAR buffer[MAX_PATH]; + + /* Parameter checks */ + + /* This one crashes win2k + + ret = pGetColorDirectoryW( NULL, NULL, NULL ); + ok( !ret, "GetColorDirectoryW() succeeded (%d)\n", GetLastError() ); + + */ + + size = 0; + + ret = pGetColorDirectoryW( NULL, NULL, &size ); + ok( !ret && size > 0, "GetColorDirectoryW() succeeded (%d)\n", GetLastError() ); + + size = 0; + + ret = pGetColorDirectoryW( NULL, buffer, &size ); + ok( !ret && size > 0, "GetColorDirectoryW() succeeded (%d)\n", GetLastError() ); + + size = 1; + + ret = pGetColorDirectoryW( NULL, buffer, &size ); + ok( !ret && size > 0, "GetColorDirectoryW() succeeded (%d)\n", GetLastError() ); + + /* Functional checks */ + + size = sizeof(buffer); + + ret = pGetColorDirectoryW( NULL, buffer, &size ); + ok( ret && size > 0, "GetColorDirectoryW() failed (%d)\n", GetLastError() ); +} + +static void test_GetColorProfileElement(void) +{ + if (standardprofile) + { + PROFILE profile; + HPROFILE handle; + BOOL ret, ref; + DWORD size; + TAGTYPE tag = 0x63707274; /* 'cprt' */ + static char buffer[51]; + static const char expect[] = + { 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x70, + 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, + 0x31, 0x39, 0x39, 0x38, 0x20, 0x48, 0x65, 0x77, 0x6c, 0x65, 0x74, + 0x74, 0x2d, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x72, 0x64, 0x20, 0x43, + 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x00 }; + + profile.dwType = PROFILE_FILENAME; + profile.pProfileData = standardprofile; + profile.cbDataSize = strlen(standardprofile); + + handle = pOpenColorProfileA( &profile, PROFILE_READ, 0, OPEN_EXISTING ); + ok( handle != NULL, "OpenColorProfileA() failed (%d)\n", GetLastError() ); + + /* Parameter checks */ + + ret = pGetColorProfileElement( handle, tag, 0, NULL, NULL, &ref ); + ok( !ret, "GetColorProfileElement() succeeded (%d)\n", GetLastError() ); + + ret = pGetColorProfileElement( handle, tag, 0, &size, NULL, NULL ); + ok( !ret, "GetColorProfileElement() succeeded (%d)\n", GetLastError() ); + + size = 0; + + ret = pGetColorProfileElement( handle, tag, 0, &size, NULL, &ref ); + ok( !ret && size > 0, "GetColorProfileElement() succeeded (%d)\n", GetLastError() ); + + size = sizeof(buffer); + + /* Functional checks */ + + ret = pGetColorProfileElement( handle, tag, 0, &size, buffer, &ref ); + ok( ret && size > 0, "GetColorProfileElement() failed (%d)\n", GetLastError() ); + + ok( !memcmp( buffer, expect, sizeof(expect) ), "Unexpected tag data\n" ); + + pCloseColorProfile( handle ); + } +} + +static void test_GetColorProfileElementTag(void) +{ + if (standardprofile) + { + PROFILE profile; + HPROFILE handle; + BOOL ret; + DWORD index = 1; + TAGTYPE tag, expect = 0x63707274; /* 'cprt' */ + + profile.dwType = PROFILE_FILENAME; + profile.pProfileData = standardprofile; + profile.cbDataSize = strlen(standardprofile); + + handle = pOpenColorProfileA( &profile, PROFILE_READ, 0, OPEN_EXISTING ); + ok( handle != NULL, "OpenColorProfileA() failed (%d)\n", GetLastError() ); + + /* Parameter checks */ + + ret = pGetColorProfileElementTag( NULL, index, &tag ); + ok( !ret, "GetColorProfileElementTag() succeeded (%d)\n", GetLastError() ); + + ret = pGetColorProfileElementTag( handle, 0, &tag ); + ok( !ret, "GetColorProfileElementTag() succeeded (%d)\n", GetLastError() ); + + ret = pGetColorProfileElementTag( handle, index, NULL ); + ok( !ret, "GetColorProfileElementTag() succeeded (%d)\n", GetLastError() ); + + ret = pGetColorProfileElementTag( handle, 18, NULL ); + ok( !ret, "GetColorProfileElementTag() succeeded (%d)\n", GetLastError() ); + + /* Functional checks */ + + ret = pGetColorProfileElementTag( handle, index, &tag ); + ok( ret && tag == expect, "GetColorProfileElementTag() failed (%d)\n", + GetLastError() ); + + pCloseColorProfile( handle ); + } +} + +static void test_GetColorProfileFromHandle(void) +{ + if (testprofile) + { + PROFILE profile; + HPROFILE handle; + DWORD size; + BOOL ret; + static const unsigned char expect[] = + { 0x00, 0x00, 0x0c, 0x48, 0x4c, 0x69, 0x6e, 0x6f, 0x02, 0x10, 0x00, + 0x00, 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, + 0x5a, 0x20, 0x07, 0xce, 0x00, 0x02, 0x00, 0x09, 0x00, 0x06, 0x00, + 0x31, 0x00, 0x00, 0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47, + 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xd3, 0x2d, 0x48, 0x50, 0x20, 0x20 }; + + unsigned char *buffer; + + profile.dwType = PROFILE_FILENAME; + profile.pProfileData = testprofile; + profile.cbDataSize = strlen(testprofile); + + handle = pOpenColorProfileA( &profile, PROFILE_READ, 0, OPEN_EXISTING ); + ok( handle != NULL, "OpenColorProfileA() failed (%d)\n", GetLastError() ); + + /* Parameter checks */ + + size = 0; + + ret = pGetColorProfileFromHandle( handle, NULL, &size ); + ok( !ret && size > 0, "GetColorProfileFromHandle() failed (%d)\n", GetLastError() ); + + buffer = HeapAlloc( GetProcessHeap(), 0, size ); + + if (buffer) + { + ret = pGetColorProfileFromHandle( NULL, buffer, &size ); + ok( !ret, "GetColorProfileFromHandle() succeeded (%d)\n", GetLastError() ); + + ret = pGetColorProfileFromHandle( handle, buffer, NULL ); + ok( !ret, "GetColorProfileFromHandle() succeeded (%d)\n", GetLastError() ); + + /* Functional checks */ + + ret = pGetColorProfileFromHandle( handle, buffer, &size ); + ok( ret && size > 0, "GetColorProfileFromHandle() failed (%d)\n", GetLastError() ); + + ok( !memcmp( buffer, expect, sizeof(expect) ), "Unexpected header data\n" ); + + HeapFree( GetProcessHeap(), 0, buffer ); + } + + pCloseColorProfile( handle ); + } +} + +static void test_GetColorProfileHeader(void) +{ + if (testprofile) + { + PROFILE profile; + HPROFILE handle; + BOOL ret; + PROFILEHEADER header; + + profile.dwType = PROFILE_FILENAME; + profile.pProfileData = testprofile; + profile.cbDataSize = strlen(testprofile); + + handle = pOpenColorProfileA( &profile, PROFILE_READ, 0, OPEN_EXISTING ); + ok( handle != NULL, "OpenColorProfileA() failed (%d)\n", GetLastError() ); + + /* Parameter checks */ + + ret = pGetColorProfileHeader( NULL, NULL ); + ok( !ret, "GetColorProfileHeader() succeeded (%d)\n", GetLastError() ); + + ret = pGetColorProfileHeader( NULL, &header ); + ok( !ret, "GetColorProfileHeader() succeeded (%d)\n", GetLastError() ); + + if (0) /* Crashes on Vista */ + { + ret = pGetColorProfileHeader( handle, NULL ); + ok( !ret, "GetColorProfileHeader() succeeded (%d)\n", GetLastError() ); + } + + /* Functional checks */ + + ret = pGetColorProfileHeader( handle, &header ); + ok( ret, "GetColorProfileHeader() failed (%d)\n", GetLastError() ); + + ok( !memcmp( &header, rgbheader, sizeof(rgbheader) ), "Unexpected header data\n" ); + + pCloseColorProfile( handle ); + } +} + +static void test_GetCountColorProfileElements(void) +{ + if (standardprofile) + { + PROFILE profile; + HPROFILE handle; + BOOL ret; + DWORD count, expect = 17; + + profile.dwType = PROFILE_FILENAME; + profile.pProfileData = standardprofile; + profile.cbDataSize = strlen(standardprofile); + + handle = pOpenColorProfileA( &profile, PROFILE_READ, 0, OPEN_EXISTING ); + ok( handle != NULL, "OpenColorProfileA() failed (%d)\n", GetLastError() ); + + /* Parameter checks */ + + ret = pGetCountColorProfileElements( NULL, &count ); + ok( !ret, "GetCountColorProfileElements() succeeded (%d)\n", + GetLastError() ); + + ret = pGetCountColorProfileElements( handle, NULL ); + ok( !ret, "GetCountColorProfileElements() succeeded (%d)\n", + GetLastError() ); + + /* Functional checks */ + + ret = pGetCountColorProfileElements( handle, &count ); + ok( ret && count == expect, + "GetCountColorProfileElements() failed (%d)\n", GetLastError() ); + + pCloseColorProfile( handle ); + } +} + +typedef struct colorspace_description_struct { + DWORD dwID; + const char *szName; + BOOL registered; + char filename[MAX_PATH]; +} colorspace_descr; + +#define describe_colorspace(id) {id, #id, FALSE, ""} + +colorspace_descr known_colorspaces[] = { + describe_colorspace(SPACE_XYZ), + describe_colorspace(SPACE_Lab), + describe_colorspace(SPACE_Luv), + describe_colorspace(SPACE_YCbCr), + describe_colorspace(SPACE_Yxy), + describe_colorspace(SPACE_RGB), + describe_colorspace(SPACE_GRAY), + describe_colorspace(SPACE_HSV), + describe_colorspace(SPACE_HLS), + describe_colorspace(SPACE_CMYK), + describe_colorspace(SPACE_CMY), + describe_colorspace(SPACE_2_CHANNEL), + describe_colorspace(SPACE_3_CHANNEL), + describe_colorspace(SPACE_4_CHANNEL), + describe_colorspace(SPACE_5_CHANNEL), + describe_colorspace(SPACE_6_CHANNEL), + describe_colorspace(SPACE_7_CHANNEL), + describe_colorspace(SPACE_8_CHANNEL) +}; + +static void enum_registered_color_profiles(void) +{ + BOOL ret; + DWORD size, count, i, present; + CHAR profile[MAX_PATH]; + + size = sizeof(profile); + count = sizeof(known_colorspaces)/sizeof(known_colorspaces[0]); + + present = 0; + trace("\n"); + trace("Querying registered standard colorspace profiles via GetStandardColorSpaceProfileA():\n"); + for (i=0; i 0, "GetColorProfileElement() failed (%d)\n", GetLastError() ); + + ok( !memcmp( data, buffer, sizeof(data) ), + "Unexpected tag data, expected %s, got %s (%d)\n", + data, buffer, GetLastError() ); + + pCloseColorProfile( handle ); + } +} + +static void test_SetColorProfileHeader(void) +{ + if (testprofile) + { + PROFILE profile; + HPROFILE handle; + BOOL ret; + PROFILEHEADER header; + + profile.dwType = PROFILE_FILENAME; + profile.pProfileData = testprofile; + profile.cbDataSize = strlen(testprofile); + + header.phSize = 0x00000c48; + header.phCMMType = 0x4c696e6f; + header.phVersion = 0x02100000; + header.phClass = 0x6d6e7472; + header.phDataColorSpace = 0x52474220; + header.phConnectionSpace = 0x58595a20; + header.phDateTime[0] = 0x07ce0002; + header.phDateTime[1] = 0x00090006; + header.phDateTime[2] = 0x00310000; + header.phSignature = 0x61637370; + header.phPlatform = 0x4d534654; + header.phProfileFlags = 0x00000000; + header.phManufacturer = 0x49454320; + header.phModel = 0x73524742; + header.phAttributes[0] = 0x00000000; + header.phAttributes[1] = 0x00000000; + header.phRenderingIntent = 0x00000000; + header.phIlluminant.ciexyzX = 0x0000f6d6; + header.phIlluminant.ciexyzY = 0x00010000; + header.phIlluminant.ciexyzZ = 0x0000d32d; + header.phCreator = 0x48502020; + + /* Parameter checks */ + + handle = pOpenColorProfileA( &profile, PROFILE_READ, 0, OPEN_EXISTING ); + ok( handle != NULL, "OpenColorProfileA() failed (%d)\n", GetLastError() ); + + ret = pSetColorProfileHeader( handle, &header ); + ok( !ret, "SetColorProfileHeader() succeeded (%d)\n", GetLastError() ); + + pCloseColorProfile( handle ); + + handle = pOpenColorProfileA( &profile, PROFILE_READWRITE, 0, OPEN_EXISTING ); + ok( handle != NULL, "OpenColorProfileA() failed (%d)\n", GetLastError() ); + + ret = pSetColorProfileHeader( NULL, NULL ); + ok( !ret, "SetColorProfileHeader() succeeded (%d)\n", GetLastError() ); + + ret = pSetColorProfileHeader( handle, NULL ); + ok( !ret, "SetColorProfileHeader() succeeded (%d)\n", GetLastError() ); + + ret = pSetColorProfileHeader( NULL, &header ); + ok( !ret, "SetColorProfileHeader() succeeded (%d)\n", GetLastError() ); + + /* Functional checks */ + + ret = pSetColorProfileHeader( handle, &header ); + ok( ret, "SetColorProfileHeader() failed (%d)\n", GetLastError() ); + + ret = pGetColorProfileHeader( handle, &header ); + ok( ret, "GetColorProfileHeader() failed (%d)\n", GetLastError() ); + + ok( !memcmp( &header, rgbheader, sizeof(rgbheader) ), "Unexpected header data\n" ); + + pCloseColorProfile( handle ); + } +} + +static void test_UninstallColorProfileA(void) +{ + BOOL ret; + + /* Parameter checks */ + + ret = pUninstallColorProfileA( NULL, NULL, FALSE ); + ok( !ret, "UninstallColorProfileA() succeeded (%d)\n", GetLastError() ); + + ret = pUninstallColorProfileA( machine, NULL, FALSE ); + ok( !ret, "UninstallColorProfileA() succeeded (%d)\n", GetLastError() ); + + /* Functional checks */ + + if (testprofile) + { + CHAR dest[MAX_PATH], base[MAX_PATH]; + DWORD size = sizeof(dest); + CHAR slash[] = "\\"; + HANDLE handle; + + SetLastError(0xdeadbeef); + ret = pInstallColorProfileA( NULL, testprofile ); + if (!ret && (GetLastError() == ERROR_ACCESS_DENIED)) + { + skip("Not enough rights for InstallColorProfileA\n"); + return; + } + ok( ret, "InstallColorProfileA() failed (%d)\n", GetLastError() ); + + ret = pGetColorDirectoryA( NULL, dest, &size ); + ok( ret, "GetColorDirectoryA() failed (%d)\n", GetLastError() ); + + MSCMS_basenameA( testprofile, base ); + + lstrcatA( dest, slash ); + lstrcatA( dest, base ); + + ret = pUninstallColorProfileA( NULL, dest, TRUE ); + ok( ret, "UninstallColorProfileA() failed (%d)\n", GetLastError() ); + + /* Check if the profile is really gone */ + handle = CreateFileA( dest, 0 , 0, NULL, OPEN_EXISTING, 0, NULL ); + ok( handle == INVALID_HANDLE_VALUE, "Found the profile (%d)\n", GetLastError() ); + CloseHandle( handle ); + } +} + +static void test_UninstallColorProfileW(void) +{ + BOOL ret; + + /* Parameter checks */ + + ret = pUninstallColorProfileW( NULL, NULL, FALSE ); + ok( !ret, "UninstallColorProfileW() succeeded (%d)\n", GetLastError() ); + + ret = pUninstallColorProfileW( machineW, NULL, FALSE ); + ok( !ret, "UninstallColorProfileW() succeeded (%d)\n", GetLastError() ); + + /* Functional checks */ + + if (testprofileW) + { + WCHAR dest[MAX_PATH], base[MAX_PATH]; + char destA[MAX_PATH]; + DWORD size = sizeof(dest); + WCHAR slash[] = { '\\', 0 }; + HANDLE handle; + int bytes_copied; + + SetLastError(0xdeadbeef); + ret = pInstallColorProfileW( NULL, testprofileW ); + if (!ret && (GetLastError() == ERROR_ACCESS_DENIED)) + { + skip("Not enough rights for InstallColorProfileW\n"); + return; + } + ok( ret, "InstallColorProfileW() failed (%d)\n", GetLastError() ); + + ret = pGetColorDirectoryW( NULL, dest, &size ); + ok( ret, "GetColorDirectoryW() failed (%d)\n", GetLastError() ); + + MSCMS_basenameW( testprofileW, base ); + + lstrcatW( dest, slash ); + lstrcatW( dest, base ); + + ret = pUninstallColorProfileW( NULL, dest, TRUE ); + ok( ret, "UninstallColorProfileW() failed (%d)\n", GetLastError() ); + + bytes_copied = WideCharToMultiByte(CP_ACP, 0, dest, -1, destA, MAX_PATH, NULL, NULL); + ok( bytes_copied > 0 , "WideCharToMultiByte() returns %d\n", bytes_copied); + /* Check if the profile is really gone */ + handle = CreateFileA( destA, 0 , 0, NULL, OPEN_EXISTING, 0, NULL ); + ok( handle == INVALID_HANDLE_VALUE, "Found the profile (%d)\n", GetLastError() ); + CloseHandle( handle ); + } +} + +static void test_AssociateColorProfileWithDeviceA(void) +{ + BOOL ret; + char profile[MAX_PATH], basename[MAX_PATH]; + DWORD error, size = sizeof(profile); + DISPLAY_DEVICE display; + BOOL res; + DISPLAY_DEVICE monitor; + + if (testprofile && pEnumDisplayDevicesA) + { + display.cb = sizeof( DISPLAY_DEVICE ); + res = pEnumDisplayDevicesA( NULL, 0, &display, 0 ); + ok( res, "Can't get display info\n" ); + + monitor.cb = sizeof( DISPLAY_DEVICE ); + res = pEnumDisplayDevicesA( display.DeviceName, 0, &monitor, 0 ); + if (res) + { + SetLastError(0xdeadbeef); + ret = pAssociateColorProfileWithDeviceA( "machine", testprofile, NULL ); + error = GetLastError(); + ok( !ret, "AssociateColorProfileWithDevice() succeeded\n" ); + ok( error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error ); + + SetLastError(0xdeadbeef); + ret = pAssociateColorProfileWithDeviceA( "machine", NULL, monitor.DeviceID ); + error = GetLastError(); + ok( !ret, "AssociateColorProfileWithDevice() succeeded\n" ); + ok( error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error ); + + SetLastError(0xdeadbeef); + ret = pAssociateColorProfileWithDeviceA( "machine", testprofile, monitor.DeviceID ); + error = GetLastError(); + ok( !ret, "AssociateColorProfileWithDevice() succeeded\n" ); + ok( error == ERROR_NOT_SUPPORTED, "expected ERROR_NOT_SUPPORTED, got %u\n", error ); + + ret = pInstallColorProfileA( NULL, testprofile ); + ok( ret, "InstallColorProfileA() failed (%u)\n", GetLastError() ); + + ret = pGetColorDirectoryA( NULL, profile, &size ); + ok( ret, "GetColorDirectoryA() failed (%d)\n", GetLastError() ); + + MSCMS_basenameA( testprofile, basename ); + lstrcatA( profile, "\\" ); + lstrcatA( profile, basename ); + + ret = pAssociateColorProfileWithDeviceA( NULL, profile, monitor.DeviceID ); + ok( ret, "AssociateColorProfileWithDevice() failed (%u)\n", GetLastError() ); + + SetLastError(0xdeadbeef); + ret = pDisassociateColorProfileFromDeviceA( "machine", profile, NULL ); + error = GetLastError(); + ok( !ret, "DisassociateColorProfileFromDeviceA() succeeded\n" ); + ok( error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error ); + + SetLastError(0xdeadbeef); + ret = pDisassociateColorProfileFromDeviceA( "machine", NULL, monitor.DeviceID ); + error = GetLastError(); + ok( !ret, "DisassociateColorProfileFromDeviceA() succeeded\n" ); + ok( error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error ); + + SetLastError(0xdeadbeef); + ret = pDisassociateColorProfileFromDeviceA( "machine", profile, monitor.DeviceID ); + error = GetLastError(); + ok( !ret, "DisassociateColorProfileFromDeviceA() succeeded\n" ); + ok( error == ERROR_NOT_SUPPORTED, "expected ERROR_NOT_SUPPORTED, got %u\n", error ); + + ret = pDisassociateColorProfileFromDeviceA( NULL, profile, monitor.DeviceID ); + ok( ret, "DisassociateColorProfileFromDeviceA() failed (%u)\n", GetLastError() ); + + ret = pUninstallColorProfileA( NULL, profile, TRUE ); + ok( ret, "UninstallColorProfileA() failed (%d)\n", GetLastError() ); + } + else + skip("Unable to obtain monitor name\n"); + } +} + +START_TEST(profile) +{ + UINT len; + HANDLE handle; + char path[MAX_PATH], file[MAX_PATH]; + char profilefile1[MAX_PATH], profilefile2[MAX_PATH]; + WCHAR profilefile1W[MAX_PATH], profilefile2W[MAX_PATH]; + BOOL has_space_rgb; + WCHAR fileW[MAX_PATH]; + UINT ret; + + hmscms = LoadLibraryA( "mscms.dll" ); + if (!hmscms) return; + + huser32 = LoadLibraryA( "user32.dll" ); + if (!huser32) + { + FreeLibrary( hmscms ); + return; + } + + if (!init_function_ptrs()) + { + FreeLibrary( huser32 ); + FreeLibrary( hmscms ); + return; + } + + /* See if we can find the standard color profile */ + ret = GetSystemDirectoryA( profilefile1, sizeof(profilefile1) ); + ok( ret > 0, "GetSystemDirectoryA() returns %d, LastError = %d\n", ret, GetLastError()); + ok( lstrlenA(profilefile1) > 0 && lstrlenA(profilefile1) < MAX_PATH, + "GetSystemDirectoryA() returns %d, LastError = %d\n", ret, GetLastError()); + MultiByteToWideChar(CP_ACP, 0, profilefile1, -1, profilefile1W, MAX_PATH); + ok( lstrlenW(profilefile1W) > 0 && lstrlenW(profilefile1W) < MAX_PATH, + "GetSystemDirectoryA() returns %d, LastError = %d\n", ret, GetLastError()); + lstrcpyA(profilefile2, profilefile1); + lstrcpyW(profilefile2W, profilefile1W); + + lstrcatA( profilefile1, profile1 ); + lstrcatW( profilefile1W, profile1W ); + handle = CreateFileA( profilefile1, 0 , 0, NULL, OPEN_EXISTING, 0, NULL ); + + if (handle != INVALID_HANDLE_VALUE) + { + standardprofile = profilefile1; + standardprofileW = profilefile1W; + CloseHandle( handle ); + } + + lstrcatA( profilefile2, profile2 ); + lstrcatW( profilefile2W, profile2W ); + handle = CreateFileA( profilefile2, 0 , 0, NULL, OPEN_EXISTING, 0, NULL ); + + if (handle != INVALID_HANDLE_VALUE) + { + standardprofile = profilefile2; + standardprofileW = profilefile2W; + CloseHandle( handle ); + } + + /* If found, create a temporary copy for testing purposes */ + if (standardprofile && GetTempPath( sizeof(path), path )) + { + if (GetTempFileName( path, "rgb", 0, file )) + { + if (CopyFileA( standardprofile, file, FALSE )) + { + testprofile = (LPSTR)&file; + + len = MultiByteToWideChar( CP_ACP, 0, testprofile, -1, NULL, 0 ); + MultiByteToWideChar( CP_ACP, 0, testprofile, -1, fileW, len ); + + testprofileW = (LPWSTR)&fileW; + } + } + } + + test_GetColorDirectoryA(); + test_GetColorDirectoryW(); + + test_GetColorProfileElement(); + test_GetColorProfileElementTag(); + + test_GetColorProfileFromHandle(); + test_GetColorProfileHeader(); + + test_GetCountColorProfileElements(); + + enum_registered_color_profiles(); + check_registry(&has_space_rgb); + + test_GetStandardColorSpaceProfileA(has_space_rgb); + test_GetStandardColorSpaceProfileW(has_space_rgb); + + test_EnumColorProfilesA(); + test_EnumColorProfilesW(); + + test_InstallColorProfileA(); + test_InstallColorProfileW(); + + test_IsColorProfileTagPresent(); + + test_OpenColorProfileA(); + test_OpenColorProfileW(); + + test_SetColorProfileElement(); + test_SetColorProfileHeader(); + + test_UninstallColorProfileA(); + test_UninstallColorProfileW(); + + test_AssociateColorProfileWithDeviceA(); + + /* Clean up */ + if (testprofile) + DeleteFileA( testprofile ); + + FreeLibrary( huser32 ); + FreeLibrary( hmscms ); +} diff --git a/rostests/winetests/mscms/testlist.c b/rostests/winetests/mscms/testlist.c new file mode 100644 index 00000000000..ef2de04f9c7 --- /dev/null +++ b/rostests/winetests/mscms/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_profile(void); + +const struct test winetest_testlist[] = +{ + { "profile", func_profile }, + { 0, 0 } +}; diff --git a/rostests/winetests/msctf/inputprocessor.c b/rostests/winetests/msctf/inputprocessor.c new file mode 100644 index 00000000000..7ba9140573a --- /dev/null +++ b/rostests/winetests/msctf/inputprocessor.c @@ -0,0 +1,1311 @@ +/* + * Unit tests for ITfInputProcessor + * + * Copyright 2009 Aric Stewart, CodeWeavers + * + * 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 + */ + +#include + +#define COBJMACROS +#include "wine/test.h" +#include "winuser.h" +#include "initguid.h" +#include "shlwapi.h" +#include "shlguid.h" +#include "comcat.h" +#include "msctf.h" +#include "olectl.h" + +static ITfInputProcessorProfiles* g_ipp; +static LANGID gLangid; +static ITfCategoryMgr * g_cm = NULL; +static ITfThreadMgr* g_tm = NULL; +static ITfDocumentMgr *g_dm = NULL; +static TfClientId cid = 0; +static TfClientId tid = 0; + +#define SINK_UNEXPECTED 0 +#define SINK_EXPECTED 1 +#define SINK_FIRED 2 + +static BOOL test_ShouldActivate = FALSE; +static BOOL test_ShouldDeactivate = FALSE; + +static DWORD tmSinkCookie; +static DWORD tmSinkRefCount; +static ITfDocumentMgr *test_CurrentFocus = NULL; +static ITfDocumentMgr *test_PrevFocus = NULL; +static INT test_OnSetFocus = SINK_UNEXPECTED; +static INT test_OnInitDocumentMgr = SINK_UNEXPECTED; +static INT test_OnPushContext = SINK_UNEXPECTED; +static INT test_OnPopContext = SINK_UNEXPECTED; +static INT test_KEV_OnSetFocus = SINK_UNEXPECTED; + +HRESULT RegisterTextService(REFCLSID rclsid); +HRESULT UnregisterTextService(); +HRESULT ThreadMgrEventSink_Constructor(IUnknown **ppOut); +HRESULT TextStoreACP_Constructor(IUnknown **ppOut); + +DEFINE_GUID(CLSID_FakeService, 0xEDE1A7AD,0x66DE,0x47E0,0xB6,0x20,0x3E,0x92,0xF8,0x24,0x6B,0xF3); +DEFINE_GUID(CLSID_TF_InputProcessorProfiles, 0x33c53a50,0xf456,0x4884,0xb0,0x49,0x85,0xfd,0x64,0x3e,0xcf,0xed); +DEFINE_GUID(CLSID_TF_CategoryMgr, 0xA4B544A1,0x438D,0x4B41,0x93,0x25,0x86,0x95,0x23,0xE2,0xD6,0xC7); +DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745c63,0xb2f0,0x4784,0x8b,0x67,0x5e,0x12,0xc8,0x70,0x1a,0x31); +DEFINE_GUID(GUID_TFCAT_TIP_SPEECH, 0xB5A73CD1,0x8355,0x426B,0xA1,0x61,0x25,0x98,0x08,0xF2,0x6B,0x14); +DEFINE_GUID(GUID_TFCAT_TIP_HANDWRITING, 0x246ecb87,0xc2f2,0x4abe,0x90,0x5b,0xc8,0xb3,0x8a,0xdd,0x2c,0x43); +DEFINE_GUID (GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, 0x046B8C80,0x1647,0x40F7,0x9B,0x21,0xB9,0x3B,0x81,0xAA,0xBC,0x1B); +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +DEFINE_GUID(CLSID_TF_ThreadMgr, 0x529a9e6b,0x6587,0x4f23,0xab,0x9e,0x9c,0x7d,0x68,0x3e,0x3c,0x50); +DEFINE_GUID(CLSID_PreservedKey, 0xA0ED8E55,0xCD3B,0x4274,0xB2,0x95,0xF6,0xC9,0xBA,0x2B,0x84,0x72); + + +static HRESULT initialize(void) +{ + HRESULT hr; + CoInitialize(NULL); + hr = CoCreateInstance (&CLSID_TF_InputProcessorProfiles, NULL, + CLSCTX_INPROC_SERVER, &IID_ITfInputProcessorProfiles, (void**)&g_ipp); + if (SUCCEEDED(hr)) + hr = CoCreateInstance (&CLSID_TF_CategoryMgr, NULL, + CLSCTX_INPROC_SERVER, &IID_ITfCategoryMgr, (void**)&g_cm); + if (SUCCEEDED(hr)) + hr = CoCreateInstance (&CLSID_TF_ThreadMgr, NULL, + CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (void**)&g_tm); + return hr; +} + +static void cleanup(void) +{ + if (g_ipp) + ITfInputProcessorProfiles_Release(g_ipp); + if (g_cm) + ITfCategoryMgr_Release(g_cm); + if (g_tm) + ITfThreadMgr_Release(g_tm); + CoUninitialize(); +} + +static void test_Register(void) +{ + HRESULT hr; + + static const WCHAR szDesc[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',0}; + static const WCHAR szFile[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',' ','F','i','l','e',0}; + + hr = ITfInputProcessorProfiles_GetCurrentLanguage(g_ipp,&gLangid); + ok(SUCCEEDED(hr),"Unable to get current language id\n"); + trace("Current Language %x\n",gLangid); + + hr = RegisterTextService(&CLSID_FakeService); + ok(SUCCEEDED(hr),"Unable to register COM for TextService\n"); + hr = ITfInputProcessorProfiles_Register(g_ipp, &CLSID_FakeService); + ok(SUCCEEDED(hr),"Unable to register text service(%x)\n",hr); + hr = ITfInputProcessorProfiles_AddLanguageProfile(g_ipp, &CLSID_FakeService, gLangid, &CLSID_FakeService, szDesc, sizeof(szDesc)/sizeof(WCHAR), szFile, sizeof(szFile)/sizeof(WCHAR), 1); + ok(SUCCEEDED(hr),"Unable to add Language Profile (%x)\n",hr); +} + +static void test_Unregister(void) +{ + HRESULT hr; + hr = ITfInputProcessorProfiles_Unregister(g_ipp, &CLSID_FakeService); + ok(SUCCEEDED(hr),"Unable to unregister text service(%x)\n",hr); + UnregisterTextService(); +} + +static void test_EnumInputProcessorInfo(void) +{ + IEnumGUID *ppEnum; + BOOL found = FALSE; + + if (SUCCEEDED(ITfInputProcessorProfiles_EnumInputProcessorInfo(g_ipp, &ppEnum))) + { + ULONG fetched; + GUID g; + while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK) + { + if(IsEqualGUID(&g,&CLSID_FakeService)) + found = TRUE; + } + } + ok(found,"Did not find registered text service\n"); +} + +static void test_EnumLanguageProfiles(void) +{ + BOOL found = FALSE; + IEnumTfLanguageProfiles *ppEnum; + if (SUCCEEDED(ITfInputProcessorProfiles_EnumLanguageProfiles(g_ipp,gLangid,&ppEnum))) + { + TF_LANGUAGEPROFILE profile; + while (IEnumTfLanguageProfiles_Next(ppEnum,1,&profile,NULL)==S_OK) + { + if (IsEqualGUID(&profile.clsid,&CLSID_FakeService)) + { + found = TRUE; + ok(profile.langid == gLangid, "LangId Incorrect\n"); + ok(IsEqualGUID(&profile.catid,&GUID_TFCAT_TIP_KEYBOARD), "CatId Incorrect\n"); + ok(IsEqualGUID(&profile.guidProfile,&CLSID_FakeService), "guidProfile Incorrect\n"); + } + } + } + ok(found,"Registered text service not found\n"); +} + +static void test_RegisterCategory(void) +{ + HRESULT hr; + hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService); + ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n"); + hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService); + ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n"); +} + +static void test_UnregisterCategory(void) +{ + HRESULT hr; + hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService); + ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n"); + hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService); + ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n"); +} + +static void test_FindClosestCategory(void) +{ + GUID output; + HRESULT hr; + const GUID *list[3] = {&GUID_TFCAT_TIP_SPEECH, &GUID_TFCAT_TIP_KEYBOARD, &GUID_TFCAT_TIP_HANDWRITING}; + + hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, NULL, 0); + ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); + ok(IsEqualGUID(&output,&GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER),"Wrong GUID\n"); + + hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 1); + ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); + ok(IsEqualGUID(&output,&GUID_NULL),"Wrong GUID\n"); + + hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 3); + ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); + ok(IsEqualGUID(&output,&GUID_TFCAT_TIP_KEYBOARD),"Wrong GUID\n"); +} + +static void test_Enable(void) +{ + HRESULT hr; + BOOL enabled = FALSE; + + hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, TRUE); + ok(SUCCEEDED(hr),"Failed to enable text service\n"); + hr = ITfInputProcessorProfiles_IsEnabledLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, &enabled); + ok(SUCCEEDED(hr),"Failed to get enabled state\n"); + ok(enabled == TRUE,"enabled state incorrect\n"); +} + +static void test_Disable(void) +{ + HRESULT hr; + + trace("Disabling\n"); + hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, FALSE); + ok(SUCCEEDED(hr),"Failed to disable text service\n"); +} + +static void test_ThreadMgrAdviseSinks(void) +{ + ITfSource *source = NULL; + HRESULT hr; + IUnknown *sink; + + hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source); + ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n"); + if (!source) + return; + + ThreadMgrEventSink_Constructor(&sink); + + tmSinkRefCount = 1; + tmSinkCookie = 0; + hr = ITfSource_AdviseSink(source,&IID_ITfThreadMgrEventSink, sink, &tmSinkCookie); + ok(SUCCEEDED(hr),"Failed to Advise Sink\n"); + ok(tmSinkCookie!=0,"Failed to get sink cookie\n"); + + /* Advising the sink adds a ref, Relesing here lets the object be deleted + when unadvised */ + tmSinkRefCount = 2; + IUnknown_Release(sink); + ITfSource_Release(source); +} + +static void test_ThreadMgrUnadviseSinks(void) +{ + ITfSource *source = NULL; + HRESULT hr; + + hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source); + ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n"); + if (!source) + return; + + tmSinkRefCount = 1; + hr = ITfSource_UnadviseSink(source, tmSinkCookie); + ok(SUCCEEDED(hr),"Failed to unadvise Sink\n"); + ITfSource_Release(source); +} + +/********************************************************************** + * ITfKeyEventSink + **********************************************************************/ +typedef struct tagKeyEventSink +{ + const ITfKeyEventSinkVtbl *KeyEventSinkVtbl; + LONG refCount; +} KeyEventSink; + +static void KeyEventSink_Destructor(KeyEventSink *This) +{ + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI KeyEventSink_QueryInterface(ITfKeyEventSink *iface, REFIID iid, LPVOID *ppvOut) +{ + KeyEventSink *This = (KeyEventSink *)iface; + *ppvOut = NULL; + + if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfKeyEventSink)) + { + *ppvOut = This; + } + + if (*ppvOut) + { + IUnknown_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI KeyEventSink_AddRef(ITfKeyEventSink *iface) +{ + KeyEventSink *This = (KeyEventSink *)iface; + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI KeyEventSink_Release(ITfKeyEventSink *iface) +{ + KeyEventSink *This = (KeyEventSink *)iface; + ULONG ret; + + ret = InterlockedDecrement(&This->refCount); + if (ret == 0) + KeyEventSink_Destructor(This); + return ret; +} + +static HRESULT WINAPI KeyEventSink_OnSetFocus(ITfKeyEventSink *iface, + BOOL fForeground) +{ + ok(test_KEV_OnSetFocus == SINK_EXPECTED,"Unexpected KeyEventSink_OnSetFocus\n"); + test_KEV_OnSetFocus = SINK_FIRED; + return S_OK; +} + +static HRESULT WINAPI KeyEventSink_OnTestKeyDown(ITfKeyEventSink *iface, + ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) +{ + trace("\n"); + return S_OK; +} + +static HRESULT WINAPI KeyEventSink_OnTestKeyUp(ITfKeyEventSink *iface, + ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) +{ + trace("\n"); + return S_OK; +} + +static HRESULT WINAPI KeyEventSink_OnKeyDown(ITfKeyEventSink *iface, + ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) +{ + trace("\n"); + return S_OK; +} + +static HRESULT WINAPI KeyEventSink_OnKeyUp(ITfKeyEventSink *iface, + ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) +{ + trace("\n"); + return S_OK; +} + +static HRESULT WINAPI KeyEventSink_OnPreservedKey(ITfKeyEventSink *iface, + ITfContext *pic, REFGUID rguid, BOOL *pfEaten) +{ + trace("\n"); + return S_OK; +} + +static const ITfKeyEventSinkVtbl KeyEventSink_KeyEventSinkVtbl = +{ + KeyEventSink_QueryInterface, + KeyEventSink_AddRef, + KeyEventSink_Release, + + KeyEventSink_OnSetFocus, + KeyEventSink_OnTestKeyDown, + KeyEventSink_OnTestKeyUp, + KeyEventSink_OnKeyDown, + KeyEventSink_OnKeyUp, + KeyEventSink_OnPreservedKey +}; + +HRESULT KeyEventSink_Constructor(ITfKeyEventSink **ppOut) +{ + KeyEventSink *This; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(KeyEventSink)); + if (This == NULL) + return E_OUTOFMEMORY; + + This->KeyEventSinkVtbl = &KeyEventSink_KeyEventSinkVtbl; + This->refCount = 1; + + *ppOut = (ITfKeyEventSink*)This; + return S_OK; +} + + +static void test_KeystrokeMgr(void) +{ + ITfKeystrokeMgr *keymgr= NULL; + HRESULT hr; + TF_PRESERVEDKEY tfpk; + BOOL preserved; + ITfKeyEventSink *sink; + + KeyEventSink_Constructor(&sink); + + hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfKeystrokeMgr, (LPVOID*)&keymgr); + ok(SUCCEEDED(hr),"Failed to get IID_ITfKeystrokeMgr for ThreadMgr\n"); + + tfpk.uVKey = 'A'; + tfpk.uModifiers = TF_MOD_SHIFT; + + test_KEV_OnSetFocus = SINK_EXPECTED; + hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,tid,sink,TRUE); + todo_wine ok(SUCCEEDED(hr),"ITfKeystrokeMgr_AdviseKeyEventSink failed\n"); + todo_wine ok(test_KEV_OnSetFocus == SINK_FIRED, "KeyEventSink_OnSetFocus not fired as expected\n"); + + hr =ITfKeystrokeMgr_PreserveKey(keymgr, 0, &CLSID_PreservedKey, &tfpk, NULL, 0); + ok(hr==E_INVALIDARG,"ITfKeystrokeMgr_PreserveKey inproperly succeeded\n"); + + hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0); + ok(SUCCEEDED(hr),"ITfKeystrokeMgr_PreserveKey failed\n"); + + hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0); + ok(hr == TF_E_ALREADY_EXISTS,"ITfKeystrokeMgr_PreserveKey inproperly succeeded\n"); + + preserved = FALSE; + hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved); + ok(hr == S_OK, "ITfKeystrokeMgr_IsPreservedKey failed\n"); + if (hr == S_OK) ok(preserved == TRUE,"misreporting preserved key\n"); + + hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk); + ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnpreserveKey failed\n"); + + hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved); + ok(hr == S_FALSE, "ITfKeystrokeMgr_IsPreservedKey failed\n"); + if (hr == S_FALSE) ok(preserved == FALSE,"misreporting preserved key\n"); + + hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk); + ok(hr==CONNECT_E_NOCONNECTION,"ITfKeystrokeMgr_UnpreserveKey inproperly succeeded\n"); + + hr = ITfKeystrokeMgr_UnadviseKeyEventSink(keymgr,tid); + todo_wine ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnadviseKeyEventSink failed\n"); + + ITfKeystrokeMgr_Release(keymgr); + ITfKeyEventSink_Release(sink); +} + +static void test_Activate(void) +{ + HRESULT hr; + + hr = ITfInputProcessorProfiles_ActivateLanguageProfile(g_ipp,&CLSID_FakeService,gLangid,&CLSID_FakeService); + ok(SUCCEEDED(hr),"Failed to Activate text service\n"); +} + +static inline int check_context_refcount(ITfContext *iface) +{ + IUnknown_AddRef(iface); + return IUnknown_Release(iface); +} + +static void test_startSession(void) +{ + HRESULT hr; + DWORD cnt; + DWORD editCookie; + ITfDocumentMgr *dmtest; + ITfContext *cxt,*cxt2,*cxt3,*cxtTest; + ITextStoreACP *ts; + TfClientId cid2 = 0; + + hr = ITfThreadMgr_Deactivate(g_tm); + ok(hr == E_UNEXPECTED,"Deactivate should have failed with E_UNEXPECTED\n"); + + test_ShouldActivate = TRUE; + hr = ITfThreadMgr_Activate(g_tm,&cid); + ok(SUCCEEDED(hr),"Failed to Activate\n"); + ok(cid != tid,"TextService id mistakenly matches Client id\n"); + + test_ShouldActivate = FALSE; + hr = ITfThreadMgr_Activate(g_tm,&cid2); + ok(SUCCEEDED(hr),"Failed to Activate\n"); + ok (cid == cid2, "Second activate client ID does not match\n"); + + hr = ITfThreadMgr_Deactivate(g_tm); + ok(SUCCEEDED(hr),"Failed to Deactivate\n"); + + hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&g_dm); + ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); + + hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); + ok(SUCCEEDED(hr),"GetFocus Failed\n"); + ok(dmtest == NULL,"Initial focus not null\n"); + + test_CurrentFocus = g_dm; + test_PrevFocus = NULL; + test_OnSetFocus = SINK_EXPECTED; + hr = ITfThreadMgr_SetFocus(g_tm,g_dm); + ok(SUCCEEDED(hr),"SetFocus Failed\n"); + ok(test_OnSetFocus == SINK_FIRED, "OnSetFocus sink not called\n"); + test_OnSetFocus = SINK_UNEXPECTED; + + hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); + ok(SUCCEEDED(hr),"GetFocus Failed\n"); + ok(g_dm == dmtest,"Expected DocumentMgr not focused\n"); + + cnt = ITfDocumentMgr_Release(g_dm); + ok(cnt == 2,"DocumentMgr refcount not expected (2 vs %i)\n",cnt); + + hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); + ok(SUCCEEDED(hr),"GetFocus Failed\n"); + ok(g_dm == dmtest,"Expected DocumentMgr not focused\n"); + + TextStoreACP_Constructor((IUnknown**)&ts); + + hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, (IUnknown*)ts, &cxt, &editCookie); + ok(SUCCEEDED(hr),"CreateContext Failed\n"); + + hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt2, &editCookie); + ok(SUCCEEDED(hr),"CreateContext Failed\n"); + + hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt3, &editCookie); + ok(SUCCEEDED(hr),"CreateContext Failed\n"); + + cnt = check_context_refcount(cxt); + test_OnPushContext = SINK_EXPECTED; + test_OnInitDocumentMgr = SINK_EXPECTED; + hr = ITfDocumentMgr_Push(g_dm, cxt); + ok(SUCCEEDED(hr),"Push Failed\n"); + ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); + ok(test_OnPushContext == SINK_FIRED, "OnPushContext sink not fired\n"); + ok(test_OnInitDocumentMgr == SINK_FIRED, "OnInitDocumentMgr sink not fired\n"); + + hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetTop Failed\n"); + ok(cxtTest == cxt, "Wrong context on top\n"); + ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); + cnt = ITfContext_Release(cxtTest); + + hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetBase Failed\n"); + ok(cxtTest == cxt, "Wrong context on Base\n"); + ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); + ITfContext_Release(cxtTest); + + check_context_refcount(cxt2); + test_OnPushContext = SINK_EXPECTED; + hr = ITfDocumentMgr_Push(g_dm, cxt2); + ok(SUCCEEDED(hr),"Push Failed\n"); + ok(test_OnPushContext == SINK_FIRED, "OnPushContext sink not fired\n"); + + cnt = check_context_refcount(cxt2); + hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetTop Failed\n"); + ok(cxtTest == cxt2, "Wrong context on top\n"); + ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n"); + ITfContext_Release(cxtTest); + + cnt = check_context_refcount(cxt); + hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetBase Failed\n"); + ok(cxtTest == cxt, "Wrong context on Base\n"); + ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); + ITfContext_Release(cxtTest); + + cnt = check_context_refcount(cxt3); + hr = ITfDocumentMgr_Push(g_dm, cxt3); + ok(!SUCCEEDED(hr),"Push Succeeded\n"); + ok(check_context_refcount(cxt3) == cnt, "Ref changed\n"); + + cnt = check_context_refcount(cxt2); + hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetTop Failed\n"); + ok(cxtTest == cxt2, "Wrong context on top\n"); + ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n"); + ITfContext_Release(cxtTest); + + cnt = check_context_refcount(cxt); + hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetBase Failed\n"); + ok(cxtTest == cxt, "Wrong context on Base\n"); + ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); + ITfContext_Release(cxtTest); + + cnt = check_context_refcount(cxt2); + test_OnPopContext = SINK_EXPECTED; + hr = ITfDocumentMgr_Pop(g_dm, 0); + ok(SUCCEEDED(hr),"Pop Failed\n"); + ok(check_context_refcount(cxt2) < cnt, "Ref count did not decrease\n"); + ok(test_OnPopContext == SINK_FIRED, "OnPopContext sink not fired\n"); + + hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetTop Failed\n"); + ok(cxtTest == cxt, "Wrong context on top\n"); + ITfContext_Release(cxtTest); + + hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetBase Failed\n"); + ok(cxtTest == cxt, "Wrong context on base\n"); + ITfContext_Release(cxtTest); + + hr = ITfDocumentMgr_Pop(g_dm, 0); + ok(!SUCCEEDED(hr),"Pop Succeeded\n"); + + hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetTop Failed\n"); + ok(cxtTest == cxt, "Wrong context on top\n"); + ITfContext_Release(cxtTest); + + hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); + ok(SUCCEEDED(hr),"GetBase Failed\n"); + ok(cxtTest == cxt, "Wrong context on base\n"); + ITfContext_Release(cxtTest); + + ITfContext_Release(cxt); + ITfContext_Release(cxt2); + ITfContext_Release(cxt3); +} + +static void test_endSession(void) +{ + HRESULT hr; + test_ShouldDeactivate = TRUE; + test_CurrentFocus = NULL; + test_PrevFocus = g_dm; + test_OnSetFocus = SINK_EXPECTED; + hr = ITfThreadMgr_Deactivate(g_tm); + ok(SUCCEEDED(hr),"Failed to Deactivate\n"); + ok(test_OnSetFocus == SINK_FIRED, "OnSetFocus sink not called\n"); + test_OnSetFocus = SINK_UNEXPECTED; +} + +static void test_TfGuidAtom(void) +{ + GUID gtest,g1; + HRESULT hr; + TfGuidAtom atom1,atom2; + BOOL equal; + + CoCreateGuid(>est); + + /* msdn reports this should return E_INVALIDARG. However my test show it crashing (winxp)*/ + /* + hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,NULL); + ok(hr==E_INVALIDARG,"ITfCategoryMgr_RegisterGUID should have failed\n"); + */ + hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,&atom1); + ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n"); + hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,&atom2); + ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n"); + ok(atom1 == atom2,"atoms do not match\n"); + hr = ITfCategoryMgr_GetGUID(g_cm,atom2,NULL); + ok(hr==E_INVALIDARG,"ITfCategoryMgr_GetGUID should have failed\n"); + hr = ITfCategoryMgr_GetGUID(g_cm,atom2,&g1); + ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n"); + ok(IsEqualGUID(&g1,>est),"guids do not match\n"); + hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,>est,NULL); + ok(hr==E_INVALIDARG,"ITfCategoryMgr_IsEqualTfGuidAtom should have failed\n"); + hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,>est,&equal); + ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n"); + ok(equal == TRUE,"Equal value invalid\n"); + + /* show that cid and tid TfClientIds are also TfGuidAtoms */ + hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,tid,&CLSID_FakeService,&equal); + ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n"); + ok(equal == TRUE,"Equal value invalid\n"); + hr = ITfCategoryMgr_GetGUID(g_cm,cid,&g1); + ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n"); + ok(!IsEqualGUID(&g1,&GUID_NULL),"guid should not be NULL\n"); +} + +static void test_ClientId(void) +{ + ITfClientId *pcid; + TfClientId id1,id2; + HRESULT hr; + GUID g2; + + hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfClientId, (LPVOID*)&pcid); + ok(SUCCEEDED(hr),"Unable to aquire ITfClientId interface\n"); + + CoCreateGuid(&g2); + + hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id1); + ok(SUCCEEDED(hr),"GetClientId failed\n"); + hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id2); + ok(SUCCEEDED(hr),"GetClientId failed\n"); + ok(id1==id2,"Id's for GUID_NULL do not match\n"); + hr = ITfClientId_GetClientId(pcid,&CLSID_FakeService,&id2); + ok(SUCCEEDED(hr),"GetClientId failed\n"); + ok(id2!=id1,"Id matches GUID_NULL\n"); + ok(id2==tid,"Id for CLSID_FakeService not matching tid\n"); + ok(id2!=cid,"Id for CLSID_FakeService matching cid\n"); + hr = ITfClientId_GetClientId(pcid,&g2,&id2); + ok(SUCCEEDED(hr),"GetClientId failed\n"); + ok(id2!=id1,"Id matches GUID_NULL\n"); + ok(id2!=tid,"Id for random guid matching tid\n"); + ok(id2!=cid,"Id for random guid matching cid\n"); + ITfClientId_Release(pcid); +} + +START_TEST(inputprocessor) +{ + if (SUCCEEDED(initialize())) + { + test_Register(); + test_RegisterCategory(); + test_EnumInputProcessorInfo(); + test_Enable(); + test_ThreadMgrAdviseSinks(); + test_Activate(); + test_startSession(); + test_TfGuidAtom(); + test_ClientId(); + test_KeystrokeMgr(); + test_endSession(); + test_EnumLanguageProfiles(); + test_FindClosestCategory(); + test_Disable(); + test_ThreadMgrUnadviseSinks(); + test_UnregisterCategory(); + test_Unregister(); + } + else + skip("Unable to create InputProcessor\n"); + cleanup(); +} + +/********************************************************************** + * ITextStoreACP + **********************************************************************/ +typedef struct tagTextStoreACP +{ + const ITextStoreACPVtbl *TextStoreACPVtbl; + LONG refCount; +} TextStoreACP; + +static void TextStoreACP_Destructor(TextStoreACP *This) +{ + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI TextStoreACP_QueryInterface(ITextStoreACP *iface, REFIID iid, LPVOID *ppvOut) +{ + TextStoreACP *This = (TextStoreACP *)iface; + *ppvOut = NULL; + + if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACP)) + { + *ppvOut = This; + } + + if (*ppvOut) + { + IUnknown_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI TextStoreACP_AddRef(ITextStoreACP *iface) +{ + TextStoreACP *This = (TextStoreACP *)iface; + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI TextStoreACP_Release(ITextStoreACP *iface) +{ + TextStoreACP *This = (TextStoreACP *)iface; + ULONG ret; + + ret = InterlockedDecrement(&This->refCount); + if (ret == 0) + TextStoreACP_Destructor(This); + return ret; +} + +static HRESULT WINAPI TextStoreACP_AdviseSink(ITextStoreACP *iface, + REFIID riid, IUnknown *punk, DWORD dwMask) +{ + trace("\n"); + return S_OK; +} + +static HRESULT WINAPI TextStoreACP_UnadviseSink(ITextStoreACP *iface, + IUnknown *punk) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_RequestLock(ITextStoreACP *iface, + DWORD dwLockFlags, HRESULT *phrSession) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetStatus(ITextStoreACP *iface, + TS_STATUS *pdcs) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_QueryInsert(ITextStoreACP *iface, + LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, + LONG *pacpResultEnd) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetSelection(ITextStoreACP *iface, + ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_SetSelection(ITextStoreACP *iface, + ULONG ulCount, const TS_SELECTION_ACP *pSelection) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetText(ITextStoreACP *iface, + LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq, + ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq, + ULONG *pcRunInfoRet, LONG *pacpNext) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_SetText(ITextStoreACP *iface, + DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, + ULONG cch, TS_TEXTCHANGE *pChange) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetFormattedText(ITextStoreACP *iface, + LONG acpStart, LONG acpEnd, IDataObject **ppDataObject) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetEmbedded(ITextStoreACP *iface, + LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_QueryInsertEmbedded(ITextStoreACP *iface, + const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_InsertEmbedded(ITextStoreACP *iface, + DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, + TS_TEXTCHANGE *pChange) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_InsertTextAtSelection(ITextStoreACP *iface, + DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart, + LONG *pacpEnd, TS_TEXTCHANGE *pChange) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_InsertEmbeddedAtSelection(ITextStoreACP *iface, + DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd, + TS_TEXTCHANGE *pChange) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_RequestSupportedAttrs(ITextStoreACP *iface, + DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_RequestAttrsAtPosition(ITextStoreACP *iface, + LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, + DWORD dwFlags) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_RequestAttrsTransitioningAtPosition(ITextStoreACP *iface, + LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, + DWORD dwFlags) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_FindNextAttrTransition(ITextStoreACP *iface, + LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, + DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_RetrieveRequestedAttrs(ITextStoreACP *iface, + ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetEndACP(ITextStoreACP *iface, + LONG *pacp) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetActiveView(ITextStoreACP *iface, + TsViewCookie *pvcView) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetACPFromPoint(ITextStoreACP *iface, + TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags, + LONG *pacp) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetTextExt(ITextStoreACP *iface, + TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, + BOOL *pfClipped) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetScreenExt(ITextStoreACP *iface, + TsViewCookie vcView, RECT *prc) +{ + trace("\n"); + return S_OK; +} +static HRESULT WINAPI TextStoreACP_GetWnd(ITextStoreACP *iface, + TsViewCookie vcView, HWND *phwnd) +{ + trace("\n"); + return S_OK; +} + +static const ITextStoreACPVtbl TextStoreACP_TextStoreACPVtbl = +{ + TextStoreACP_QueryInterface, + TextStoreACP_AddRef, + TextStoreACP_Release, + + TextStoreACP_AdviseSink, + TextStoreACP_UnadviseSink, + TextStoreACP_RequestLock, + TextStoreACP_GetStatus, + TextStoreACP_QueryInsert, + TextStoreACP_GetSelection, + TextStoreACP_SetSelection, + TextStoreACP_GetText, + TextStoreACP_SetText, + TextStoreACP_GetFormattedText, + TextStoreACP_GetEmbedded, + TextStoreACP_QueryInsertEmbedded, + TextStoreACP_InsertEmbedded, + TextStoreACP_InsertTextAtSelection, + TextStoreACP_InsertEmbeddedAtSelection, + TextStoreACP_RequestSupportedAttrs, + TextStoreACP_RequestAttrsAtPosition, + TextStoreACP_RequestAttrsTransitioningAtPosition, + TextStoreACP_FindNextAttrTransition, + TextStoreACP_RetrieveRequestedAttrs, + TextStoreACP_GetEndACP, + TextStoreACP_GetActiveView, + TextStoreACP_GetACPFromPoint, + TextStoreACP_GetTextExt, + TextStoreACP_GetScreenExt, + TextStoreACP_GetWnd +}; + +HRESULT TextStoreACP_Constructor(IUnknown **ppOut) +{ + TextStoreACP *This; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACP)); + if (This == NULL) + return E_OUTOFMEMORY; + + This->TextStoreACPVtbl = &TextStoreACP_TextStoreACPVtbl; + This->refCount = 1; + + *ppOut = (IUnknown *)This; + return S_OK; +} + +/********************************************************************** + * ITfThreadMgrEventSink + **********************************************************************/ +typedef struct tagThreadMgrEventSink +{ + const ITfThreadMgrEventSinkVtbl *ThreadMgrEventSinkVtbl; + LONG refCount; +} ThreadMgrEventSink; + +static void ThreadMgrEventSink_Destructor(ThreadMgrEventSink *This) +{ + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut) +{ + ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface; + *ppvOut = NULL; + + if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgrEventSink)) + { + *ppvOut = This; + } + + if (*ppvOut) + { + IUnknown_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface) +{ + ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface; + ok (tmSinkRefCount == This->refCount,"ThreadMgrEventSink refcount off %i vs %i\n",This->refCount,tmSinkRefCount); + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface) +{ + ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface; + ULONG ret; + + ok (tmSinkRefCount == This->refCount,"ThreadMgrEventSink refcount off %i vs %i\n",This->refCount,tmSinkRefCount); + ret = InterlockedDecrement(&This->refCount); + if (ret == 0) + ThreadMgrEventSink_Destructor(This); + return ret; +} + +static HRESULT WINAPI ThreadMgrEventSink_OnInitDocumentMgr(ITfThreadMgrEventSink *iface, +ITfDocumentMgr *pdim) +{ + ok(test_OnInitDocumentMgr == SINK_EXPECTED, "Unexpected OnInitDocumentMgr sink\n"); + test_OnInitDocumentMgr = SINK_FIRED; + return S_OK; +} + +static HRESULT WINAPI ThreadMgrEventSink_OnUninitDocumentMgr(ITfThreadMgrEventSink *iface, +ITfDocumentMgr *pdim) +{ + trace("\n"); + return S_OK; +} + +static HRESULT WINAPI ThreadMgrEventSink_OnSetFocus(ITfThreadMgrEventSink *iface, +ITfDocumentMgr *pdimFocus, ITfDocumentMgr *pdimPrevFocus) +{ + ok(test_OnSetFocus == SINK_EXPECTED, "Unexpected OnSetFocus sink\n"); + ok(pdimFocus == test_CurrentFocus,"Sink reports wrong focus\n"); + ok(pdimPrevFocus == test_PrevFocus,"Sink reports wrong previous focus\n"); + test_OnSetFocus = SINK_FIRED; + return S_OK; +} + +static HRESULT WINAPI ThreadMgrEventSink_OnPushContext(ITfThreadMgrEventSink *iface, +ITfContext *pic) +{ + ok(test_OnPushContext == SINK_EXPECTED, "Unexpected OnPushContext sink\n"); + test_OnPushContext = SINK_FIRED; + return S_OK; +} + +static HRESULT WINAPI ThreadMgrEventSink_OnPopContext(ITfThreadMgrEventSink *iface, +ITfContext *pic) +{ + ok(test_OnPopContext == SINK_EXPECTED, "Unexpected OnPopContext sink\n"); + test_OnPopContext = SINK_FIRED; + return S_OK; +} + +static const ITfThreadMgrEventSinkVtbl ThreadMgrEventSink_ThreadMgrEventSinkVtbl = +{ + ThreadMgrEventSink_QueryInterface, + ThreadMgrEventSink_AddRef, + ThreadMgrEventSink_Release, + + ThreadMgrEventSink_OnInitDocumentMgr, + ThreadMgrEventSink_OnUninitDocumentMgr, + ThreadMgrEventSink_OnSetFocus, + ThreadMgrEventSink_OnPushContext, + ThreadMgrEventSink_OnPopContext +}; + +HRESULT ThreadMgrEventSink_Constructor(IUnknown **ppOut) +{ + ThreadMgrEventSink *This; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgrEventSink)); + if (This == NULL) + return E_OUTOFMEMORY; + + This->ThreadMgrEventSinkVtbl = &ThreadMgrEventSink_ThreadMgrEventSinkVtbl; + This->refCount = 1; + + *ppOut = (IUnknown *)This; + return S_OK; +} + + +/******************************************************************************************** + * Stub text service for testing + ********************************************************************************************/ + +static LONG TS_refCount; +static IClassFactory *cf; +static DWORD regid; + +typedef HRESULT (*LPFNCONSTRUCTOR)(IUnknown *pUnkOuter, IUnknown **ppvOut); + +typedef struct tagClassFactory +{ + const IClassFactoryVtbl *vtbl; + LONG ref; + LPFNCONSTRUCTOR ctor; +} ClassFactory; + +typedef struct tagTextService +{ + const ITfTextInputProcessorVtbl *TextInputProcessorVtbl; + LONG refCount; +} TextService; + +static void ClassFactory_Destructor(ClassFactory *This) +{ + HeapFree(GetProcessHeap(),0,This); + TS_refCount--; +} + +static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppvOut) +{ + *ppvOut = NULL; + if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) + { + IClassFactory_AddRef(iface); + *ppvOut = iface; + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) +{ + ClassFactory *This = (ClassFactory *)iface; + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) +{ + ClassFactory *This = (ClassFactory *)iface; + ULONG ret = InterlockedDecrement(&This->ref); + + if (ret == 0) + ClassFactory_Destructor(This); + return ret; +} + +static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *punkOuter, REFIID iid, LPVOID *ppvOut) +{ + ClassFactory *This = (ClassFactory *)iface; + HRESULT ret; + IUnknown *obj; + + ret = This->ctor(punkOuter, &obj); + if (FAILED(ret)) + return ret; + ret = IUnknown_QueryInterface(obj, iid, ppvOut); + IUnknown_Release(obj); + return ret; +} + +static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) +{ + if(fLock) + InterlockedIncrement(&TS_refCount); + else + InterlockedDecrement(&TS_refCount); + + return S_OK; +} + +static const IClassFactoryVtbl ClassFactoryVtbl = { + /* IUnknown */ + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + + /* IClassFactory*/ + ClassFactory_CreateInstance, + ClassFactory_LockServer +}; + +static HRESULT ClassFactory_Constructor(LPFNCONSTRUCTOR ctor, LPVOID *ppvOut) +{ + ClassFactory *This = HeapAlloc(GetProcessHeap(),0,sizeof(ClassFactory)); + This->vtbl = &ClassFactoryVtbl; + This->ref = 1; + This->ctor = ctor; + *ppvOut = (LPVOID)This; + TS_refCount++; + return S_OK; +} + +static void TextService_Destructor(TextService *This) +{ + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI TextService_QueryInterface(ITfTextInputProcessor *iface, REFIID iid, LPVOID *ppvOut) +{ + TextService *This = (TextService *)iface; + *ppvOut = NULL; + + if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfTextInputProcessor)) + { + *ppvOut = This; + } + + if (*ppvOut) + { + IUnknown_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI TextService_AddRef(ITfTextInputProcessor *iface) +{ + TextService *This = (TextService *)iface; + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI TextService_Release(ITfTextInputProcessor *iface) +{ + TextService *This = (TextService *)iface; + ULONG ret; + + ret = InterlockedDecrement(&This->refCount); + if (ret == 0) + TextService_Destructor(This); + return ret; +} + +static HRESULT WINAPI TextService_Activate(ITfTextInputProcessor *iface, + ITfThreadMgr *ptim, TfClientId id) +{ + trace("TextService_Activate\n"); + ok(test_ShouldActivate,"Activation came unexpectedly\n"); + tid = id; + return S_OK; +} + +static HRESULT WINAPI TextService_Deactivate(ITfTextInputProcessor *iface) +{ + trace("TextService_Deactivate\n"); + ok(test_ShouldDeactivate,"Deactivation came unexpectedly\n"); + return S_OK; +} + +static const ITfTextInputProcessorVtbl TextService_TextInputProcessorVtbl= +{ + TextService_QueryInterface, + TextService_AddRef, + TextService_Release, + + TextService_Activate, + TextService_Deactivate +}; + +HRESULT TextService_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) +{ + TextService *This; + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextService)); + if (This == NULL) + return E_OUTOFMEMORY; + + This->TextInputProcessorVtbl= &TextService_TextInputProcessorVtbl; + This->refCount = 1; + + *ppOut = (IUnknown *)This; + return S_OK; +} + +HRESULT RegisterTextService(REFCLSID rclsid) +{ + ClassFactory_Constructor( TextService_Constructor ,(LPVOID*)&cf); + return CoRegisterClassObject(rclsid, (IUnknown*) cf, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id); +} + +HRESULT UnregisterTextService() +{ + return CoRevokeClassObject(regid); +} diff --git a/rostests/winetests/msctf/msctf.rbuild b/rostests/winetests/msctf/msctf.rbuild new file mode 100644 index 00000000000..537242ad582 --- /dev/null +++ b/rostests/winetests/msctf/msctf.rbuild @@ -0,0 +1,10 @@ + + . + + inputprocessor.c + testlist.c + wine + ole32 + user32 + ntdll + diff --git a/rostests/winetests/msctf/testlist.c b/rostests/winetests/msctf/testlist.c new file mode 100644 index 00000000000..8338fa7b8ce --- /dev/null +++ b/rostests/winetests/msctf/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_inputprocessor(void); + +const struct test winetest_testlist[] = +{ + { "inputprocessor", func_inputprocessor }, + { 0, 0 } +}; diff --git a/rostests/winetests/mshtml/dom.c b/rostests/winetests/mshtml/dom.c index 4540ed405b8..25ee0300a8d 100644 --- a/rostests/winetests/mshtml/dom.c +++ b/rostests/winetests/mshtml/dom.c @@ -1,5 +1,5 @@ /* - * Copyright 2007 Jacek Caban for CodeWeavers + * Copyright 2007-2008 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,6 +31,7 @@ #include "mshtmhst.h" #include "docobj.h" #include "dispex.h" +#include "mshtml_test.h" static const char doc_blank[] = ""; static const char doc_str1[] = "test"; @@ -40,29 +41,28 @@ static const char range_test2_str[] = "abc
123

def"; static const char elem_test_str[] = "test" - "text test" - "link" + "text test" + "link" "" "" "" - "
" - "" + "
td1 texttd2 text
" + "" "" "" + "" ""; static const char indent_test_str[] = "testabc
123"; - -static const WCHAR noneW[] = {'N','o','n','e',0}; +static const char cond_comment_str[] = + "test" + "" + ""; static WCHAR characterW[] = {'c','h','a','r','a','c','t','e','r',0}; static WCHAR texteditW[] = {'t','e','x','t','e','d','i','t',0}; static WCHAR wordW[] = {'w','o','r','d',0}; -static const WCHAR text_javascriptW[] = {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0}; - -static const WCHAR idW[] = {'i','d',0}; - typedef enum { ET_NONE, ET_HTML, @@ -84,29 +84,60 @@ typedef enum { ET_TEST, ET_TESTG, ET_COMMENT, - ET_IMG + ET_IMG, + ET_TR, + ET_TD, + ET_IFRAME } elem_type_t; -static REFIID const none_iids[] = { +static const IID * const none_iids[] = { &IID_IUnknown, NULL }; -static REFIID const elem_iids[] = { +static const IID * const doc_node_iids[] = { + &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, + &IID_IHTMLDocument, + &IID_IHTMLDocument2, + &IID_IHTMLDocument3, + &IID_IHTMLDocument4, + &IID_IHTMLDocument5, + &IID_IDispatchEx, + &IID_IConnectionPointContainer, + &IID_IInternetHostSecurityManager, + NULL +}; + +static const IID * const doc_obj_iids[] = { + &IID_IHTMLDocument, + &IID_IHTMLDocument2, + &IID_IHTMLDocument3, + &IID_IHTMLDocument4, + &IID_IHTMLDocument5, + &IID_IDispatchEx, + &IID_IConnectionPointContainer, + &IID_ICustomDoc, + NULL +}; + +static const IID * const elem_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const body_iids[] = { +static const IID * const body_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLTextContainer, &IID_IHTMLBodyElement, &IID_IDispatchEx, @@ -114,22 +145,24 @@ static REFIID const body_iids[] = { NULL }; -static REFIID const anchor_iids[] = { +static const IID * const anchor_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLAnchorElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const input_iids[] = { +static const IID * const input_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLInputElement, &IID_IHTMLInputTextElement, &IID_IDispatchEx, @@ -137,75 +170,80 @@ static REFIID const input_iids[] = { NULL }; -static REFIID const select_iids[] = { +static const IID * const select_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLSelectElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const textarea_iids[] = { +static const IID * const textarea_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLTextAreaElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const option_iids[] = { +static const IID * const option_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLOptionElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const table_iids[] = { +static const IID * const table_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLTable, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const script_iids[] = { +static const IID * const script_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLScriptElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const text_iids[] = { +static const IID * const text_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLDOMTextNode, NULL }; -static REFIID const location_iids[] = { +static const IID * const location_iids[] = { &IID_IDispatch, &IID_IHTMLLocation, NULL }; -static REFIID const window_iids[] = { +static const IID * const window_iids[] = { &IID_IDispatch, &IID_IHTMLWindow2, &IID_IHTMLWindow3, @@ -213,39 +251,96 @@ static REFIID const window_iids[] = { NULL }; -static REFIID const comment_iids[] = { +static const IID * const comment_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLCommentElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const img_iids[] = { +static const IID * const img_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IDispatchEx, &IID_IHTMLImgElement, &IID_IConnectionPointContainer, NULL }; -static REFIID const generic_iids[] = { +static const IID * const tr_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, + &IID_IDispatchEx, + &IID_IHTMLTableRow, + &IID_IConnectionPointContainer, + NULL +}; + +static const IID * const td_iids[] = { + &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, + &IID_IHTMLElement, + &IID_IHTMLElement2, + &IID_IHTMLElement3, + &IID_IDispatchEx, + &IID_IConnectionPointContainer, + NULL +}; + +static const IID * const iframe_iids[] = { + &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, + &IID_IHTMLElement, + &IID_IHTMLElement2, + &IID_IHTMLElement3, + &IID_IHTMLFrameBase2, + &IID_IDispatchEx, + &IID_IConnectionPointContainer, + NULL +}; + +static const IID * const generic_iids[] = { + &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, + &IID_IHTMLElement, + &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLGenericElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; +static const IID * const style_iids[] = { + &IID_IUnknown, + &IID_IDispatch, + &IID_IDispatchEx, + &IID_IHTMLStyle, + &IID_IHTMLStyle2, + &IID_IHTMLStyle3, + &IID_IHTMLStyle4, + NULL +}; + +static const IID * const cstyle_iids[] = { + &IID_IUnknown, + &IID_IDispatch, + &IID_IDispatchEx, + &IID_IHTMLCurrentStyle, + NULL +}; + typedef struct { const char *tag; REFIID *iids; @@ -257,8 +352,8 @@ static const elem_type_info_t elem_type_infos[] = { {"HTML", elem_iids, NULL}, {"HEAD", elem_iids, NULL}, {"TITLE", elem_iids, NULL}, - {"BODY", body_iids, NULL}, - {"A", anchor_iids, NULL}, + {"BODY", body_iids, &DIID_DispHTMLBody}, + {"A", anchor_iids, &DIID_DispHTMLAnchorElement}, {"INPUT", input_iids, &DIID_DispHTMLInputElement}, {"SELECT", select_iids, &DIID_DispHTMLSelectElement}, {"TEXTAREA", textarea_iids, NULL}, @@ -267,24 +362,18 @@ static const elem_type_info_t elem_type_infos[] = { {"BLOCKQUOTE",elem_iids, NULL}, {"P", elem_iids, NULL}, {"BR", elem_iids, NULL}, - {"TABLE", table_iids, NULL}, + {"TABLE", table_iids, &DIID_DispHTMLTable}, {"TBODY", elem_iids, NULL}, {"SCRIPT", script_iids, NULL}, {"TEST", elem_iids, &DIID_DispHTMLUnknownElement}, {"TEST", generic_iids, &DIID_DispHTMLGenericElement}, {"!", comment_iids, &DIID_DispHTMLCommentElement}, - {"IMG", img_iids, &DIID_DispHTMLImg} + {"IMG", img_iids, &DIID_DispHTMLImg}, + {"TR", tr_iids, &DIID_DispHTMLTableRow}, + {"TD", td_iids, NULL}, + {"IFRAME", iframe_iids, &DIID_DispHTMLIFrame} }; -static const char *dbgstr_w(LPCWSTR str) -{ - static char buf[512]; - if(!str) - return "(null)"; - WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); - return buf; -} - static const char *dbgstr_guid(REFIID riid) { static char buf[50]; @@ -299,9 +388,9 @@ static const char *dbgstr_guid(REFIID riid) static int strcmp_wa(LPCWSTR strw, const char *stra) { - WCHAR buf[512]; - MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR)); - return lstrcmpW(strw, buf); + CHAR buf[512]; + WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); + return lstrcmpA(stra, buf); } static BSTR a2bstr(const char *str) @@ -316,15 +405,39 @@ static BSTR a2bstr(const char *str) return ret; } +static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2) +{ + IUnknown *unk1, *unk2; + + if(iface1 == iface2) + return TRUE; + + IUnknown_QueryInterface(iface1, &IID_IUnknown, (void**)&unk1); + IUnknown_Release(unk1); + IUnknown_QueryInterface(iface2, &IID_IUnknown, (void**)&unk2); + IUnknown_Release(unk2); + + return unk1 == unk2; +} + static IHTMLDocument2 *create_document(void) { IHTMLDocument2 *doc; + IHTMLDocument5 *doc5; HRESULT hres; hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, &IID_IHTMLDocument2, (void**)&doc); ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument5, (void**)&doc5); + if(FAILED(hres)) { + win_skip("Could not get IHTMLDocument5, probably too old IE\n"); + IHTMLDocument2_Release(doc); + return NULL; + } + + IHTMLDocument5_Release(doc5); return doc; } @@ -343,18 +456,19 @@ static void _test_ifaces(unsigned line, IUnknown *iface, REFIID *iids) } } -#define test_disp(u,id) _test_disp(__LINE__,u,id) -static void _test_disp(unsigned line, IUnknown *unk, const IID *diid) +#define test_get_dispid(u,id) _test_disp(__LINE__,u,id) +static BOOL _test_get_dispid(unsigned line, IUnknown *unk, IID *iid) { IDispatchEx *dispex; ITypeInfo *typeinfo; + BOOL ret = FALSE; UINT ticnt; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); ok_(__FILE__,line) (hres == S_OK, "Could not get IDispatch: %08x\n", hres); if(FAILED(hres)) - return; + return FALSE; ticnt = 0xdeadbeef; hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); @@ -369,13 +483,65 @@ static void _test_disp(unsigned line, IUnknown *unk, const IID *diid) hres = ITypeInfo_GetTypeAttr(typeinfo, &type_attr); ok_(__FILE__,line) (hres == S_OK, "GetTypeAttr failed: %08x\n", hres); - ok_(__FILE__,line) (IsEqualGUID(&type_attr->guid, diid), "unexpected guid %s\n", dbgstr_guid(&type_attr->guid)); + if(hres == S_OK) { + *iid = type_attr->guid; + ret = TRUE; + } ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr); ITypeInfo_Release(typeinfo); } IDispatchEx_Release(dispex); + return ret; +} + +#define test_disp_value(u) _test_disp_value(__LINE__,u,v) +static void _test_disp_value(unsigned line, IUnknown *unk, const char *val) +{ + DISPPARAMS dp = {NULL,NULL,0,0}; + IDispatchEx *dispex; + EXCEPINFO ei; + VARIANT var; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); + ok_(__FILE__,line)(hres == S_OK, "Could not get IDispatchEx interface: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, 0, DISPATCH_PROPERTYGET, &dp, &var, &ei, NULL); + IDispatchEx_Release(dispex); + ok_(__FILE__,line)(hres == S_OK, "InvokeEx(DISPID_VALUE) returned: %08x\n", hres); + + ok_(__FILE__,line)(V_VT(&var) == VT_BSTR, "V_VT(value) = %d\n", V_VT(&var)); + ok_(__FILE__,line)(!strcmp_wa(V_BSTR(&var), val), "value = %s, expected %s\n", wine_dbgstr_w(V_BSTR(&var)), val); + VariantClear(&var); +} + +#define test_disp(u,id,v) _test_disp(__LINE__,u,id,v) +static void _test_disp(unsigned line, IUnknown *unk, const IID *diid, const char *val) +{ + IID iid; + + if(_test_get_dispid(line, unk, &iid)) + ok_(__FILE__,line) (IsEqualGUID(&iid, diid), "unexpected guid %s\n", dbgstr_guid(&iid)); + + if(val) + _test_disp_value(line, unk, val); +} + +#define test_disp2(u,id,id2,v) _test_disp2(__LINE__,u,id,id2,v) +static void _test_disp2(unsigned line, IUnknown *unk, const IID *diid, const IID *diid2, const char *val) +{ + IID iid; + + if(_test_get_dispid(line, unk, &iid)) + ok_(__FILE__,line) (IsEqualGUID(&iid, diid) || broken(IsEqualGUID(&iid, diid2)), + "unexpected guid %s\n", dbgstr_guid(&iid)); + + if(val) + _test_disp_value(line, unk, val); } #define get_elem_iface(u) _get_elem_iface(__LINE__,u) @@ -385,7 +551,7 @@ static IHTMLElement *_get_elem_iface(unsigned line, IUnknown *unk) HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement, (void**)&elem); - ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLElement: %08x\n", hres); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement: %08x\n", hres); return elem; } @@ -396,7 +562,18 @@ static IHTMLElement2 *_get_elem2_iface(unsigned line, IUnknown *unk) HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement2, (void**)&elem); - ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLElement2: %08x\n", hres); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement2: %08x\n", hres); + return elem; +} + +#define get_elem3_iface(u) _get_elem3_iface(__LINE__,u) +static IHTMLElement3 *_get_elem3_iface(unsigned line, IUnknown *unk) +{ + IHTMLElement3 *elem; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement3, (void**)&elem); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement3: %08x\n", hres); return elem; } @@ -407,7 +584,18 @@ static IHTMLDOMNode *_get_node_iface(unsigned line, IUnknown *unk) HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode, (void**)&node); - ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLDOMNode: %08x\n", hres); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDOMNode: %08x\n", hres); + return node; +} + +#define get_node2_iface(u) _get_node2_iface(__LINE__,u) +static IHTMLDOMNode2 *_get_node2_iface(unsigned line, IUnknown *unk) +{ + IHTMLDOMNode2 *node; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode2, (void**)&node); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDOMNode2: %08x\n", hres); return node; } @@ -422,6 +610,17 @@ static IHTMLImgElement *_get_img_iface(unsigned line, IUnknown *unk) return img; } +#define get_anchor_iface(u) _get_anchor_iface(__LINE__,u) +static IHTMLAnchorElement *_get_anchor_iface(unsigned line, IUnknown *unk) +{ + IHTMLAnchorElement *anchor; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLAnchorElement, (void**)&anchor); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLAnchorElement: %08x\n", hres); + return anchor; +} + #define test_node_name(u,n) _test_node_name(__LINE__,u,n) static void _test_node_name(unsigned line, IUnknown *unk, const char *exname) { @@ -432,11 +631,47 @@ static void _test_node_name(unsigned line, IUnknown *unk, const char *exname) hres = IHTMLDOMNode_get_nodeName(node, &name); IHTMLDOMNode_Release(node); ok_(__FILE__, line) (hres == S_OK, "get_nodeName failed: %08x\n", hres); - ok_(__FILE__, line) (!strcmp_wa(name, exname), "got name: %s, expected %s\n", dbgstr_w(name), exname); + ok_(__FILE__, line) (!strcmp_wa(name, exname), "got name: %s, expected %s\n", wine_dbgstr_w(name), exname); SysFreeString(name); } +#define get_owner_doc(u) _get_owner_doc(__LINE__,u) +static IHTMLDocument2 *_get_owner_doc(unsigned line, IUnknown *unk) +{ + IHTMLDOMNode2 *node = _get_node2_iface(line, unk); + IDispatch *disp = (void*)0xdeadbeef; + IHTMLDocument2 *doc; + HRESULT hres; + + hres = IHTMLDOMNode2_get_ownerDocument(node, &disp); + IHTMLDOMNode2_Release(node); + ok_(__FILE__,line)(hres == S_OK, "get_ownerDocument failed: %08x\n", hres); + ok_(__FILE__,line)(disp != NULL, "disp = NULL\n"); + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLDocument2, (void**)&doc); + IDispatch_Release(disp); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLDocument2 iface: %08x\n", hres); + + return doc; +} + +#define clone_node(n,d) _clone_node(__LINE__,n,d) +static IHTMLDOMNode *_clone_node(unsigned line, IUnknown *unk, VARIANT_BOOL deep) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + IHTMLDOMNode *ret = NULL; + HRESULT hres; + + hres = IHTMLDOMNode_cloneNode(node, deep, &ret); + IHTMLDOMNode_Release(node); + ok_(__FILE__,line)(hres == S_OK, "cloneNode failed: %08x\n", hres); + ok_(__FILE__,line)(ret != NULL, "ret == NULL\n"); + + return ret; + +} + #define test_elem_tag(u,n) _test_elem_tag(__LINE__,u,n) static void _test_elem_tag(unsigned line, IUnknown *unk, const char *extag) { @@ -447,7 +682,7 @@ static void _test_elem_tag(unsigned line, IUnknown *unk, const char *extag) hres = IHTMLElement_get_tagName(elem, &tag); IHTMLElement_Release(elem); ok_(__FILE__, line) (hres == S_OK, "get_tagName failed: %08x\n", hres); - ok_(__FILE__, line) (!strcmp_wa(tag, extag), "got tag: %s, expected %s\n", dbgstr_w(tag), extag); + ok_(__FILE__, line) (!strcmp_wa(tag, extag), "got tag: %s, expected %s\n", wine_dbgstr_w(tag), extag); SysFreeString(tag); } @@ -458,12 +693,64 @@ static void _test_elem_type(unsigned line, IUnknown *unk, elem_type_t type) _test_elem_tag(line, unk, elem_type_infos[type].tag); _test_ifaces(line, unk, elem_type_infos[type].iids); - if(elem_type_infos[type].dispiid) - _test_disp(line, unk, elem_type_infos[type].dispiid); + if(elem_type_infos[type].dispiid && type != ET_A) + _test_disp(line, unk, elem_type_infos[type].dispiid, "[object]"); +} + +#define get_node_type(n) _get_node_type(__LINE__,n) +static LONG _get_node_type(unsigned line, IUnknown *unk) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + LONG type = -1; + HRESULT hres; + + hres = IHTMLDOMNode_get_nodeType(node, &type); + ok(hres == S_OK, "get_nodeType failed: %08x\n", hres); + + IHTMLDOMNode_Release(node); + + return type; +} + +#define get_child_nodes(u) _get_child_nodes(__LINE__,u) +static IHTMLDOMChildrenCollection *_get_child_nodes(unsigned line, IUnknown *unk) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + IHTMLDOMChildrenCollection *col = NULL; + IDispatch *disp; + HRESULT hres; + + hres = IHTMLDOMNode_get_childNodes(node, &disp); + IHTMLDOMNode_Release(node); + ok_(__FILE__,line) (hres == S_OK, "get_childNodes failed: %08x\n", hres); + if(FAILED(hres)) + return NULL; + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLDOMChildrenCollection, (void**)&col); + IDispatch_Release(disp); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDOMChildrenCollection: %08x\n", hres); + + return col; +} + +#define get_child_item(c,i) _get_child_item(__LINE__,c,i) +static IHTMLDOMNode *_get_child_item(unsigned line, IHTMLDOMChildrenCollection *col, LONG idx) +{ + IHTMLDOMNode *node = NULL; + IDispatch *disp; + HRESULT hres; + + hres = IHTMLDOMChildrenCollection_item(col, idx, &disp); + ok(hres == S_OK, "item failed: %08x\n", hres); + + node = _get_node_iface(line, (IUnknown*)disp); + IDispatch_Release(disp); + + return node; } #define test_elem_attr(e,n,v) _test_elem_attr(__LINE__,e,n,v) -static void _test_elem_attr(unsigned line, IHTMLElement *elem, LPCWSTR name, LPCWSTR exval) +static void _test_elem_attr(unsigned line, IHTMLElement *elem, const char *name, const char *exval) { VARIANT value; BSTR tmp; @@ -471,14 +758,14 @@ static void _test_elem_attr(unsigned line, IHTMLElement *elem, LPCWSTR name, LPC VariantInit(&value); - tmp = SysAllocString(name); + tmp = a2bstr(name); hres = IHTMLElement_getAttribute(elem, tmp, 0, &value); SysFreeString(tmp); ok_(__FILE__,line) (hres == S_OK, "getAttribute failed: %08x\n", hres); if(exval) { ok_(__FILE__,line) (V_VT(&value) == VT_BSTR, "vt=%d\n", V_VT(&value)); - ok_(__FILE__,line) (!lstrcmpW(exval, V_BSTR(&value)), "unexpected value %s\n", dbgstr_w(V_BSTR(&value))); + ok_(__FILE__,line) (!strcmp_wa(V_BSTR(&value), exval), "unexpected value %s\n", wine_dbgstr_w(V_BSTR(&value))); }else { ok_(__FILE__,line) (V_VT(&value) == VT_NULL, "vt=%d\n", V_VT(&value)); } @@ -490,21 +777,47 @@ static void _test_elem_attr(unsigned line, IHTMLElement *elem, LPCWSTR name, LPC static void _test_elem_offset(unsigned line, IUnknown *unk) { IHTMLElement *elem = _get_elem_iface(line, unk); - long l; + LONG l; HRESULT hres; hres = IHTMLElement_get_offsetTop(elem, &l); ok_(__FILE__,line) (hres == S_OK, "get_offsetTop failed: %08x\n", hres); + hres = IHTMLElement_get_offsetHeight(elem, &l); + ok_(__FILE__,line) (hres == S_OK, "get_offsetHeight failed: %08x\n", hres); + + hres = IHTMLElement_get_offsetWidth(elem, &l); + ok_(__FILE__,line) (hres == S_OK, "get_offsetWidth failed: %08x\n", hres); + IHTMLElement_Release(elem); } -static void test_doc_elem(IHTMLDocument2 *doc) +#define get_doc_node(d) _get_doc_node(__LINE__,d) +static IHTMLDocument2 *_get_doc_node(unsigned line, IHTMLDocument2 *doc) +{ + IHTMLWindow2 *window; + IHTMLDocument2 *ret; + HRESULT hres; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok_(__FILE__,line)(hres == S_OK, "get_parentWindow failed: %08x\n", hres); + + hres = IHTMLWindow2_get_document(window, &ret); + ok_(__FILE__,line)(hres == S_OK, "get_document failed: %08x\n", hres); + ok_(__FILE__,line)(ret != NULL, "document = NULL\n"); + + return ret; +} + +static void test_get_set_attr(IHTMLDocument2 *doc) { IHTMLElement *elem; IHTMLDocument3 *doc3; HRESULT hres; + BSTR bstr; + VARIANT val; + /* grab an element to test with */ hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3); ok(hres == S_OK, "QueryInterface(IID_IHTMLDocument3) failed: %08x\n", hres); @@ -512,8 +825,60 @@ static void test_doc_elem(IHTMLDocument2 *doc) IHTMLDocument3_Release(doc3); ok(hres == S_OK, "get_documentElement failed: %08x\n", hres); - test_node_name((IUnknown*)elem, "HTML"); - test_elem_tag((IUnknown*)elem, "HTML"); + /* get a non-present attribute */ + bstr = a2bstr("notAnAttribute"); + hres = IHTMLElement_getAttribute(elem, bstr, 0, &val); + ok(hres == S_OK, "getAttribute failed: %08x\n", hres); + ok(V_VT(&val) == VT_NULL, "variant type should have been VT_NULL (0x%x), was: 0x%x\n", VT_NULL, V_VT(&val)); + VariantClear(&val); + SysFreeString(bstr); + + /* get a present attribute */ + bstr = a2bstr("scrollHeight"); + hres = IHTMLElement_getAttribute(elem, bstr, 0, &val); + ok(hres == S_OK, "getAttribute failed: %08x\n", hres); + ok(V_VT(&val) == VT_I4, "variant type should have been VT_I4 (0x%x), was: 0x%x\n", VT_I4, V_VT(&val)); + VariantClear(&val); + SysFreeString(bstr); + + /* create a new BSTR attribute */ + bstr = a2bstr("newAttribute"); + + V_VT(&val) = VT_BSTR; + V_BSTR(&val) = a2bstr("the value"); + hres = IHTMLElement_setAttribute(elem, bstr, val, 0); + ok(hres == S_OK, "setAttribute failed: %08x\n", hres); + VariantClear(&val); + + hres = IHTMLElement_getAttribute(elem, bstr, 0, &val); + ok(hres == S_OK, "getAttribute failed: %08x\n", hres); + ok(V_VT(&val) == VT_BSTR, "variant type should have been VT_BSTR (0x%x), was: 0x%x\n", VT_BSTR, V_VT(&val)); + ok(strcmp_wa(V_BSTR(&val), "the value") == 0, "variant value should have been L\"the value\", was %s\n", wine_dbgstr_w(V_BSTR(&val))); + VariantClear(&val); + + /* overwrite the attribute with a BOOL */ + V_VT(&val) = VT_BOOL; + V_BOOL(&val) = VARIANT_TRUE; + hres = IHTMLElement_setAttribute(elem, bstr, val, 0); + ok(hres == S_OK, "setAttribute failed: %08x\n", hres); + VariantClear(&val); + + hres = IHTMLElement_getAttribute(elem, bstr, 0, &val); + ok(hres == S_OK, "getAttribute failed: %08x\n", hres); + ok(V_VT(&val) == VT_BOOL, "variant type should have been VT_BOOL (0x%x), was: 0x%x\n", VT_BOOL, V_VT(&val)); + ok(V_BOOL(&val) == VARIANT_TRUE, "variant value should have been VARIANT_TRUE (0x%x), was %d\n", VARIANT_TRUE, V_BOOL(&val)); + VariantClear(&val); + + SysFreeString(bstr); + + /* case-insensitive */ + bstr = a2bstr("newattribute"); + hres = IHTMLElement_getAttribute(elem, bstr, 0, &val); + ok(hres == S_OK, "getAttribute failed: %08x\n", hres); + todo_wine ok(V_VT(&val) == VT_BOOL, "variant type should have been VT_BOOL (0x%x), was: 0x%x\n", VT_BOOL, V_VT(&val)); + todo_wine ok(V_BOOL(&val) == VARIANT_TRUE, "variant value should have been VARIANT_TRUE (0x%x), was %d\n", VARIANT_TRUE, V_BOOL(&val)); + VariantClear(&val); + SysFreeString(bstr); IHTMLElement_Release(elem); } @@ -534,6 +899,21 @@ static IHTMLElement *_get_doc_elem(unsigned line, IHTMLDocument2 *doc) return elem; } +#define test_anchor_href(a,h) _test_anchor_href(__LINE__,a,h) +static void _test_anchor_href(unsigned line, IUnknown *unk, const char *exhref) +{ + IHTMLAnchorElement *anchor = _get_anchor_iface(line, unk); + BSTR str; + HRESULT hres; + + hres = IHTMLAnchorElement_get_href(anchor, &str); + ok_(__FILE__,line)(hres == S_OK, "get_href failed: %08x\n", hres); + ok_(__FILE__,line)(!strcmp_wa(str, exhref), "href = %s, expected %s\n", wine_dbgstr_w(str), exhref); + SysFreeString(str); + + _test_disp_value(line, unk, exhref); +} + #define test_option_text(o,t) _test_option_text(__LINE__,o,t) static void _test_option_text(unsigned line, IHTMLOptionElement *option, const char *text) { @@ -542,7 +922,7 @@ static void _test_option_text(unsigned line, IHTMLOptionElement *option, const c hres = IHTMLOptionElement_get_text(option, &bstr); ok_(__FILE__,line) (hres == S_OK, "get_text failed: %08x\n", hres); - ok_(__FILE__,line) (!strcmp_wa(bstr, text), "text=%s\n", dbgstr_w(bstr)); + ok_(__FILE__,line) (!strcmp_wa(bstr, text), "text=%s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); } @@ -568,7 +948,7 @@ static void _test_option_value(unsigned line, IHTMLOptionElement *option, const hres = IHTMLOptionElement_get_value(option, &bstr); ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres); - ok_(__FILE__,line) (!strcmp_wa(bstr, value), "value=%s\n", dbgstr_w(bstr)); + ok_(__FILE__,line) (!strcmp_wa(bstr, value), "value=%s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); } @@ -623,29 +1003,29 @@ static IHTMLOptionElement *_create_option_elem(unsigned line, IHTMLDocument2 *do } #define test_select_length(s,l) _test_select_length(__LINE__,s,l) -static void _test_select_length(unsigned line, IHTMLSelectElement *select, long length) +static void _test_select_length(unsigned line, IHTMLSelectElement *select, LONG length) { - long len = 0xdeadbeef; + LONG len = 0xdeadbeef; HRESULT hres; hres = IHTMLSelectElement_get_length(select, &len); ok_(__FILE__,line) (hres == S_OK, "get_length failed: %08x\n", hres); - ok_(__FILE__,line) (len == length, "len=%ld, expected %ld\n", len, length); + ok_(__FILE__,line) (len == length, "len=%d, expected %d\n", len, length); } #define test_select_selidx(s,i) _test_select_selidx(__LINE__,s,i) -static void _test_select_selidx(unsigned line, IHTMLSelectElement *select, long index) +static void _test_select_selidx(unsigned line, IHTMLSelectElement *select, LONG index) { - long idx = 0xdeadbeef; + LONG idx = 0xdeadbeef; HRESULT hres; hres = IHTMLSelectElement_get_selectedIndex(select, &idx); ok_(__FILE__,line) (hres == S_OK, "get_selectedIndex failed: %08x\n", hres); - ok_(__FILE__,line) (idx == index, "idx=%ld, expected %ld\n", idx, index); + ok_(__FILE__,line) (idx == index, "idx=%d, expected %d\n", idx, index); } #define test_select_put_selidx(s,i) _test_select_put_selidx(__LINE__,s,i) -static void _test_select_put_selidx(unsigned line, IHTMLSelectElement *select, long index) +static void _test_select_put_selidx(unsigned line, IHTMLSelectElement *select, LONG index) { HRESULT hres; @@ -663,9 +1043,9 @@ static void _test_select_value(unsigned line, IHTMLSelectElement *select, const hres = IHTMLSelectElement_get_value(select, &val); ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres); if(exval) - ok_(__FILE__,line) (!strcmp_wa(val, exval), "unexpected value %s\n", dbgstr_w(val)); + ok_(__FILE__,line) (!strcmp_wa(val, exval), "unexpected value %s\n", wine_dbgstr_w(val)); else - ok_(__FILE__,line) (val == NULL, "val=%s, expected NULL\n", dbgstr_w(val)); + ok_(__FILE__,line) (val == NULL, "val=%s, expected NULL\n", wine_dbgstr_w(val)); } #define test_select_set_value(s,v) _test_select_set_value(__LINE__,s,v) @@ -688,7 +1068,7 @@ static void _test_select_type(unsigned line, IHTMLSelectElement *select, const c hres = IHTMLSelectElement_get_type(select, &type); ok_(__FILE__,line) (hres == S_OK, "get_type failed: %08x\n", hres); - ok_(__FILE__,line) (!strcmp_wa(type, extype), "type=%s, expected %s\n", dbgstr_w(type), extype); + ok_(__FILE__,line) (!strcmp_wa(type, extype), "type=%s, expected %s\n", wine_dbgstr_w(type), extype); } #define test_range_text(r,t) _test_range_text(__LINE__,r,t) @@ -702,9 +1082,9 @@ static void _test_range_text(unsigned line, IHTMLTxtRange *range, const char *ex if(extext) { ok_(__FILE__, line) (text != NULL, "text == NULL\n"); - ok_(__FILE__, line) (!strcmp_wa(text, extext), "text=\"%s\", expected \"%s\"\n", dbgstr_w(text), extext); + ok_(__FILE__, line) (!strcmp_wa(text, extext), "text=%s, expected %s\n", wine_dbgstr_w(text), extext); }else { - ok_(__FILE__, line) (text == NULL, "text=\"%s\", expected NULL\n", dbgstr_w(text)); + ok_(__FILE__, line) (text == NULL, "text=%s, expected NULL\n", wine_dbgstr_w(text)); } SysFreeString(text); @@ -735,38 +1115,38 @@ static void _test_range_expand(unsigned line, IHTMLTxtRange *range, LPWSTR unit, } #define test_range_move(r,u,c,e) _test_range_move(__LINE__,r,u,c,e) -static void _test_range_move(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt) +static void _test_range_move(unsigned line, IHTMLTxtRange *range, LPWSTR unit, LONG cnt, LONG excnt) { - long c = 0xdeadbeef; + LONG c = 0xdeadbeef; HRESULT hres; hres = IHTMLTxtRange_move(range, unit, cnt, &c); ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres); - ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt); + ok_(__FILE__,line) (c == excnt, "count=%d, expected %d\n", c, excnt); _test_range_text(line, range, NULL); } #define test_range_movestart(r,u,c,e) _test_range_movestart(__LINE__,r,u,c,e) static void _test_range_movestart(unsigned line, IHTMLTxtRange *range, - LPWSTR unit, long cnt, long excnt) + LPWSTR unit, LONG cnt, LONG excnt) { - long c = 0xdeadbeef; + LONG c = 0xdeadbeef; HRESULT hres; hres = IHTMLTxtRange_moveStart(range, unit, cnt, &c); ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres); - ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt); + ok_(__FILE__,line) (c == excnt, "count=%d, expected %d\n", c, excnt); } #define test_range_moveend(r,u,c,e) _test_range_moveend(__LINE__,r,u,c,e) -static void _test_range_moveend(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt) +static void _test_range_moveend(unsigned line, IHTMLTxtRange *range, LPWSTR unit, LONG cnt, LONG excnt) { - long c = 0xdeadbeef; + LONG c = 0xdeadbeef; HRESULT hres; hres = IHTMLTxtRange_moveEnd(range, unit, cnt, &c); ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres); - ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt); + ok_(__FILE__,line) (c == excnt, "count=%d, expected %d\n", c, excnt); } #define test_range_put_text(r,t) _test_range_put_text(__LINE__,r,t) @@ -831,31 +1211,31 @@ static void _test_range_parent(unsigned line, IHTMLTxtRange *range, elem_type_t #define test_elem_collection(c,t,l) _test_elem_collection(__LINE__,c,t,l) static void _test_elem_collection(unsigned line, IUnknown *unk, - const elem_type_t *elem_types, long exlen) + const elem_type_t *elem_types, LONG exlen) { IHTMLElementCollection *col; - long len; + LONG len; DWORD i; VARIANT name, index; - IDispatch *disp; + IDispatch *disp, *disp2; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLElementCollection, (void**)&col); - ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); - test_disp((IUnknown*)col, &DIID_DispHTMLElementCollection); + test_disp((IUnknown*)col, &DIID_DispHTMLElementCollection, "[object]"); hres = IHTMLElementCollection_get_length(col, &len); ok_(__FILE__,line) (hres == S_OK, "get_length failed: %08x\n", hres); - ok_(__FILE__,line) (len == exlen, "len=%ld, expected %ld\n", len, exlen); + ok_(__FILE__,line) (len == exlen, "len=%d, expected %d\n", len, exlen); if(len > exlen) len = exlen; V_VT(&index) = VT_EMPTY; - V_VT(&name) = VT_I4; for(i=0; itest
"); + doc_write(content_doc, TRUE, ""); + + hres = IHTMLDocument2_get_all(content_doc, &col); + ok(hres == S_OK, "get_all failed: %08x\n", hres); + test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); + IHTMLElementCollection_Release(col); + + hres = IHTMLDocument2_close(content_doc); + ok(hres == S_OK, "close failed: %08x\n", hres); + + IHTMLDocument2_Release(content_doc); } static void test_stylesheet(IDispatch *disp) @@ -1973,7 +4653,7 @@ static void test_stylesheets(IHTMLDocument2 *doc) { IHTMLStyleSheetsCollection *col = NULL; VARIANT idx, res; - long len = 0; + LONG len = 0; HRESULT hres; hres = IHTMLDocument2_get_styleSheets(doc, &col); @@ -1982,7 +4662,7 @@ static void test_stylesheets(IHTMLDocument2 *doc) hres = IHTMLStyleSheetsCollection_get_length(col, &len); ok(hres == S_OK, "get_length failed: %08x\n", hres); - ok(len == 1, "len=%ld\n", len); + ok(len == 1, "len=%d\n", len); VariantInit(&res); V_VT(&idx) = VT_I4; @@ -2015,7 +4695,7 @@ static void test_child_col_disp(IHTMLDOMChildrenCollection *col) DISPPARAMS dp = {NULL, NULL, 0, 0}; VARIANT var; EXCEPINFO ei; - long type; + LONG type; DISPID id; BSTR bstr; HRESULT hres; @@ -2038,7 +4718,7 @@ static void test_child_col_disp(IHTMLDOMChildrenCollection *col) ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n"); node = get_node_iface((IUnknown*)V_DISPATCH(&var)); type = get_node_type((IUnknown*)node); - ok(type == 3, "type=%ld\n", type); + ok(type == 3, "type=%d\n", type); IHTMLDOMNode_Release(node); VariantClear(&var); @@ -2056,18 +4736,14 @@ static void test_elems(IHTMLDocument2 *doc) { IHTMLElementCollection *col; IHTMLDOMChildrenCollection *child_col; - IHTMLElement *elem; + IHTMLElement *elem, *elem2, *elem3; IHTMLDOMNode *node, *node2; IDispatch *disp; - long type; + LONG type; HRESULT hres; - - static const WCHAR imgidW[] = {'i','m','g','i','d',0}; - static const WCHAR inW[] = {'i','n',0}; - static const WCHAR xW[] = {'x',0}; - static const WCHAR sW[] = {'s',0}; - static const WCHAR scW[] = {'s','c',0}; - static const WCHAR xxxW[] = {'x','x','x',0}; + IHTMLElementCollection *collection; + IHTMLDocument3 *doc3; + BSTR str; static const elem_type_t all_types[] = { ET_HTML, @@ -2084,9 +4760,14 @@ static void test_elems(IHTMLDocument2 *doc) ET_TEXTAREA, ET_TABLE, ET_TBODY, + ET_TR, + ET_TR, + ET_TD, + ET_TD, ET_SCRIPT, ET_TEST, - ET_IMG + ET_IMG, + ET_IFRAME }; static const elem_type_t item_types[] = { @@ -2098,31 +4779,53 @@ static void test_elems(IHTMLDocument2 *doc) hres = IHTMLDocument2_get_all(doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); - test_elem_col_item(col, xW, item_types, sizeof(item_types)/sizeof(item_types[0])); + test_elem_col_item(col, "x", item_types, sizeof(item_types)/sizeof(item_types[0])); IHTMLElementCollection_Release(col); + hres = IHTMLDocument2_get_images(doc, &collection); + ok(hres == S_OK, "get_images failed: %08x\n", hres); + if(hres == S_OK) + { + static const elem_type_t images_types[] = {ET_IMG}; + test_elem_collection((IUnknown*)collection, images_types, 1); + + IHTMLElementCollection_Release(collection); + } + + hres = IHTMLDocument2_get_links(doc, &collection); + ok(hres == S_OK, "get_links failed: %08x\n", hres); + if(hres == S_OK) + { + static const elem_type_t images_types[] = {ET_A}; + test_elem_collection((IUnknown*)collection, images_types, 1); + + IHTMLElementCollection_Release(collection); + } + + hres = IHTMLDocument2_get_anchors(doc, &collection); + ok(hres == S_OK, "get_anchors failed: %08x\n", hres); + if(hres == S_OK) + { + static const elem_type_t anchor_types[] = {ET_A}; + test_elem_collection((IUnknown*)collection, anchor_types, 1); + + IHTMLElementCollection_Release(collection); + } + elem = get_doc_elem(doc); - ok(hres == S_OK, "get_documentElement failed: %08x\n", hres); - hres = IHTMLElement_get_all(elem, &disp); + test_elem_all((IUnknown*)elem, all_types+1, sizeof(all_types)/sizeof(all_types[0])-1); IHTMLElement_Release(elem); - ok(hres == S_OK, "get_all failed: %08x\n", hres); - hres = IDispatch_QueryInterface(disp, &IID_IHTMLElementCollection, (void**)&col); - IDispatch_Release(disp); - ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); - test_elem_collection((IUnknown*)col, all_types+1, sizeof(all_types)/sizeof(all_types[0])-1); - IHTMLElementCollection_Release(col); - - get_elem_by_id(doc, xxxW, FALSE); - elem = get_doc_elem_by_id(doc, xxxW); + get_elem_by_id(doc, "xxx", FALSE); + elem = get_doc_elem_by_id(doc, "xxx"); ok(!elem, "elem != NULL\n"); - elem = get_doc_elem_by_id(doc, sW); + elem = get_doc_elem_by_id(doc, "s"); ok(elem != NULL, "elem == NULL\n"); if(elem) { test_elem_type((IUnknown*)elem, ET_SELECT); - test_elem_attr(elem, xxxW, NULL); - test_elem_attr(elem, idW, sW); + test_elem_attr(elem, "xxx", NULL); + test_elem_attr(elem, "id", "s"); test_elem_class((IUnknown*)elem, NULL); test_elem_set_class((IUnknown*)elem, "cl"); test_elem_set_class((IUnknown*)elem, NULL); @@ -2139,19 +4842,40 @@ static void test_elems(IHTMLDocument2 *doc) node = test_node_get_parent((IUnknown*)node2); IHTMLDOMNode_Release(node2); ok(node != NULL, "node == NULL\n"); + if (node) + { test_node_name((IUnknown*)node, "#document"); type = get_node_type((IUnknown*)node); - ok(type == 9, "type=%ld, expected 9\n", type); + ok(type == 9, "type=%d, expected 9\n", type); node2 = test_node_get_parent((IUnknown*)node); IHTMLDOMNode_Release(node); ok(node2 == NULL, "node != NULL\n"); + } + + elem2 = test_elem_get_parent((IUnknown*)elem); + ok(elem2 != NULL, "elem2 == NULL\n"); + test_node_name((IUnknown*)elem2, "BODY"); + elem3 = test_elem_get_parent((IUnknown*)elem2); + IHTMLElement_Release(elem2); + ok(elem3 != NULL, "elem3 == NULL\n"); + test_node_name((IUnknown*)elem3, "HTML"); + elem2 = test_elem_get_parent((IUnknown*)elem3); + IHTMLElement_Release(elem3); + ok(elem2 == NULL, "elem2 != NULL\n"); + + test_elem_getelembytag((IUnknown*)elem, ET_OPTION, 2); + test_elem_getelembytag((IUnknown*)elem, ET_SELECT, 0); + test_elem_getelembytag((IUnknown*)elem, ET_HTML, 0); + + test_elem_innertext(elem, "opt1opt2"); IHTMLElement_Release(elem); } - elem = get_elem_by_id(doc, sW, TRUE); + elem = get_elem_by_id(doc, "s", TRUE); if(elem) { IHTMLSelectElement *select; + IHTMLDocument2 *doc_node; hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLSelectElement, (void**)&select); ok(hres == S_OK, "Could not get IHTMLSelectElement interface: %08x\n", hres); @@ -2171,13 +4895,21 @@ static void test_elems(IHTMLDocument2 *doc) } type = get_node_type((IUnknown*)select); - ok(type == 1, "type=%ld\n", type); + ok(type == 1, "type=%d\n", type); IHTMLSelectElement_Release(select); + + hres = IHTMLElement_get_document(elem, &disp); + ok(hres == S_OK, "get_document failed: %08x\n", hres); + + doc_node = get_doc_node(doc); + ok(iface_cmp((IUnknown*)disp, (IUnknown*)doc_node), "disp != doc\n"); + IHTMLDocument2_Release(doc_node); + IHTMLElement_Release(elem); } - elem = get_elem_by_id(doc, scW, TRUE); + elem = get_elem_by_id(doc, "sc", TRUE); if(elem) { IHTMLScriptElement *script; BSTR type; @@ -2185,15 +4917,31 @@ static void test_elems(IHTMLDocument2 *doc) hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLScriptElement, (void**)&script); ok(hres == S_OK, "Could not get IHTMLScriptElement interface: %08x\n", hres); + if(hres == S_OK) + { + VARIANT_BOOL vb; + hres = IHTMLScriptElement_get_type(script, &type); ok(hres == S_OK, "get_type failed: %08x\n", hres); - ok(!lstrcmpW(type, text_javascriptW), "Unexpected type %s\n", dbgstr_w(type)); + ok(!strcmp_wa(type, "text/javascript"), "Unexpected type %s\n", wine_dbgstr_w(type)); SysFreeString(type); + /* test defer */ + hres = IHTMLScriptElement_put_defer(script, VARIANT_TRUE); + ok(hres == S_OK, "put_defer failed: %08x\n", hres); + + hres = IHTMLScriptElement_get_defer(script, &vb); + ok(hres == S_OK, "get_defer failed: %08x\n", hres); + ok(vb == VARIANT_TRUE, "get_defer result is %08x\n", hres); + + hres = IHTMLScriptElement_put_defer(script, VARIANT_FALSE); + ok(hres == S_OK, "put_defer failed: %08x\n", hres); + } + IHTMLScriptElement_Release(script); } - elem = get_elem_by_id(doc, inW, TRUE); + elem = get_elem_by_id(doc, "in", TRUE); if(elem) { IHTMLInputElement *input; @@ -2205,6 +4953,10 @@ static void test_elems(IHTMLDocument2 *doc) test_input_get_disabled(input, VARIANT_FALSE); test_input_set_disabled(input, VARIANT_TRUE); test_input_set_disabled(input, VARIANT_FALSE); + test_elem3_set_disabled((IUnknown*)input, VARIANT_TRUE); + test_input_get_disabled(input, VARIANT_TRUE); + test_elem3_set_disabled((IUnknown*)input, VARIANT_FALSE); + test_input_get_disabled(input, VARIANT_FALSE); test_elem_client_size((IUnknown*)elem); test_node_get_value_str((IUnknown*)elem, NULL); @@ -2218,18 +4970,57 @@ static void test_elems(IHTMLDocument2 *doc) test_elem_set_tabindex((IUnknown*)elem, 3); test_elem_title((IUnknown*)elem, "test title"); + test_input_get_defaultchecked(input, VARIANT_FALSE); + test_input_set_defaultchecked(input, VARIANT_TRUE); + test_input_set_defaultchecked(input, VARIANT_FALSE); + + test_input_get_checked(input, VARIANT_FALSE); + test_input_set_checked(input, VARIANT_TRUE); + test_input_set_checked(input, VARIANT_FALSE); + + test_input_src(input, NULL); + test_input_set_src(input, "about:blank"); + IHTMLInputElement_Release(input); IHTMLElement_Release(elem); } - elem = get_elem_by_id(doc, imgidW, TRUE); + elem = get_elem_by_id(doc, "imgid", TRUE); if(elem) { + test_img_src((IUnknown*)elem, ""); test_img_set_src((IUnknown*)elem, "about:blank"); test_img_alt((IUnknown*)elem, NULL); test_img_set_alt((IUnknown*)elem, "alt test"); IHTMLElement_Release(elem); } + elem = get_doc_elem_by_id(doc, "tbl"); + ok(elem != NULL, "elem == NULL\n"); + if(elem) { + test_table_elem(elem); + IHTMLElement_Release(elem); + } + + elem = get_doc_elem_by_id(doc, "row2"); + ok(elem != NULL, "elem == NULL\n"); + if(elem) { + test_tr_elem(elem); + IHTMLElement_Release(elem); + } + + elem = get_doc_elem_by_id(doc, "ifr"); + ok(elem != NULL, "elem == NULL\n"); + if(elem) { + test_iframe_elem(elem); + IHTMLElement_Release(elem); + } + + elem = get_elem_by_id(doc, "a", TRUE); + if(elem) { + test_anchor_href((IUnknown*)elem, "http://test/"); + IHTMLElement_Release(elem); + } + hres = IHTMLDocument2_get_body(doc, &elem); ok(hres == S_OK, "get_body failed: %08x\n", hres); @@ -2237,13 +5028,13 @@ static void test_elems(IHTMLDocument2 *doc) ok(node != NULL, "node == NULL\n"); if(node) { test_ifaces((IUnknown*)node, text_iids); - test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode); + test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode, "[object]"); node2 = get_first_child((IUnknown*)node); ok(!node2, "node2 != NULL\n"); type = get_node_type((IUnknown*)node); - ok(type == 3, "type=%ld\n", type); + ok(type == 3, "type=%d\n", type); test_node_get_value_str((IUnknown*)node, "text test"); test_node_put_value_str((IUnknown*)elem, "test text"); @@ -2255,9 +5046,9 @@ static void test_elems(IHTMLDocument2 *doc) child_col = get_child_nodes((IUnknown*)elem); ok(child_col != NULL, "child_coll == NULL\n"); if(child_col) { - long length = 0; + LONG length = 0; - test_disp((IUnknown*)child_col, &DIID_DispDOMChildrenCollection); + test_disp((IUnknown*)child_col, &DIID_DispDOMChildrenCollection, "[object]"); hres = IHTMLDOMChildrenCollection_get_length(child_col, &length); ok(hres == S_OK, "get_length failed: %08x\n", hres); @@ -2267,7 +5058,7 @@ static void test_elems(IHTMLDocument2 *doc) ok(node != NULL, "node == NULL\n"); if(node) { type = get_node_type((IUnknown*)node); - ok(type == 3, "type=%ld\n", type); + ok(type == 3, "type=%d\n", type); IHTMLDOMNode_Release(node); } @@ -2275,49 +5066,112 @@ static void test_elems(IHTMLDocument2 *doc) ok(node != NULL, "node == NULL\n"); if(node) { type = get_node_type((IUnknown*)node); - ok(type == 8, "type=%ld\n", type); + ok(type == 8, "type=%d\n", type); test_elem_id((IUnknown*)node, NULL); IHTMLDOMNode_Release(node); } - disp = (void*)0xdeadbeef; + hres = IHTMLDOMChildrenCollection_item(child_col, length - 1, NULL); + ok(hres == E_POINTER, "item failed: %08x, expected E_POINTER\n", hres); + + hres = IHTMLDOMChildrenCollection_item(child_col, length, NULL); + ok(hres == E_POINTER, "item failed: %08x, expected E_POINTER\n", hres); + hres = IHTMLDOMChildrenCollection_item(child_col, 6000, &disp); ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); - ok(disp == (void*)0xdeadbeef, "disp=%p\n", disp); - disp = (void*)0xdeadbeef; hres = IHTMLDOMChildrenCollection_item(child_col, length, &disp); ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); - ok(disp == (void*)0xdeadbeef, "disp=%p\n", disp); test_child_col_disp(child_col); IHTMLDOMChildrenCollection_Release(child_col); } + test_elem3_get_disabled((IUnknown*)elem, VARIANT_FALSE); + test_elem3_set_disabled((IUnknown*)elem, VARIANT_TRUE); + test_elem3_set_disabled((IUnknown*)elem, VARIANT_FALSE); + IHTMLElement_Release(elem); test_stylesheets(doc); test_create_option_elem(doc); + + elem = get_doc_elem_by_id(doc, "tbl"); + ok(elem != NULL, "elem = NULL\n"); + test_elem_set_innertext(elem, "inner text"); + IHTMLElement_Release(elem); + + test_doc_title(doc, "test"); + test_doc_set_title(doc, "test title"); + test_doc_title(doc, "test title"); + + disp = NULL; + hres = IHTMLDocument2_get_Script(doc, &disp); + ok(hres == S_OK, "get_Script failed: %08x\n", hres); + if(hres == S_OK) + { + IDispatchEx *dispex; + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "IDispatch_QueryInterface failed: %08x\n", hres); + if(hres == S_OK) + { + DISPID pid = -1; + BSTR str = a2bstr("Testing"); + hres = IDispatchEx_GetDispID(dispex, str, 1, &pid); + ok(hres == S_OK, "GetDispID failed: %08x\n", hres); + ok(pid != -1, "pid == -1\n"); + SysFreeString(str); + IDispatchEx_Release(dispex); +} + } + IDispatch_Release(disp); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3); + ok(hres == S_OK, "Could not get IHTMLDocument3 iface: %08x\n", hres); + + str = a2bstr("img"); + hres = IHTMLDocument3_getElementsByTagName(doc3, str, &col); + ok(hres == S_OK, "getElementsByTagName(%s) failed: %08x\n", wine_dbgstr_w(str), hres); + SysFreeString(str); + if(hres == S_OK) + { + static const elem_type_t img_types[] = { ET_IMG }; + + test_elem_collection((IUnknown*)col, img_types, sizeof(img_types)/sizeof(img_types[0])); + IHTMLElementCollection_Release(col); + } + + elem = get_doc_elem_by_id(doc, "y"); + test_elem_set_innerhtml((IUnknown*)elem, "inner html"); + test_elem_innerhtml((IUnknown*)elem, "inner html"); + test_elem_set_innerhtml((IUnknown*)elem, ""); + test_elem_innerhtml((IUnknown*)elem, NULL); + IHTMLElement_Release(elem); + + IHTMLDocument3_Release(doc3); } static void test_create_elems(IHTMLDocument2 *doc) { IHTMLElement *elem, *body, *elem2; - IHTMLDOMNode *node; + IHTMLDOMNode *node, *node2, *node3, *comment; + IHTMLDocument5 *doc5; IDispatch *disp; - long type; + VARIANT var; + LONG type; HRESULT hres; + BSTR str; static const elem_type_t types1[] = { ET_TESTG }; elem = test_create_elem(doc, "TEST"); test_elem_tag((IUnknown*)elem, "TEST"); type = get_node_type((IUnknown*)elem); - ok(type == 1, "type=%ld\n", type); + ok(type == 1, "type=%d\n", type); test_ifaces((IUnknown*)elem, elem_iids); - test_disp((IUnknown*)elem, &DIID_DispHTMLGenericElement); + test_disp((IUnknown*)elem, &DIID_DispHTMLGenericElement, "[object]"); hres = IHTMLDocument2_get_body(doc, &body); ok(hres == S_OK, "get_body failed: %08x\n", hres); @@ -2341,14 +5195,50 @@ static void test_create_elems(IHTMLDocument2 *doc) IDispatch_Release(disp); test_node_has_child((IUnknown*)body, VARIANT_FALSE); - IHTMLElement_Release(body); IHTMLElement_Release(elem); IHTMLDOMNode_Release(node); node = test_create_text(doc, "test"); test_ifaces((IUnknown*)node, text_iids); - test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode); + test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode, "[object]"); + + V_VT(&var) = VT_NULL; + node2 = test_node_insertbefore((IUnknown*)body, node, &var); IHTMLDOMNode_Release(node); + + node = test_create_text(doc, "insert "); + + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = (IDispatch*)node2; + node3 = test_node_insertbefore((IUnknown*)body, node, &var); + IHTMLDOMNode_Release(node); + IHTMLDOMNode_Release(node2); + IHTMLDOMNode_Release(node3); + + test_elem_innertext(body, "insert test"); + test_elem_innerhtml((IUnknown*)body, "insert test"); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument5, (void**)&doc5); + if(hres == S_OK) + { + str = a2bstr("testing"); + hres = IHTMLDocument5_createComment(doc5, str, &comment); + SysFreeString(str); + ok(hres == S_OK, "createComment failed: %08x\n", hres); + if(hres == S_OK) + { + type = get_node_type((IUnknown*)comment); + ok(type == 8, "type=%d, expected 8\n", type); + + test_node_get_value_str((IUnknown*)comment, "testing"); + + IHTMLDOMNode_Release(comment); +} + + IHTMLDocument5_Release(doc5); + } + + IHTMLElement_Release(body); } static void test_exec(IUnknown *unk, const GUID *grpid, DWORD cmdid, VARIANT *in, VARIANT *out) @@ -2406,6 +5296,25 @@ static void test_indent(IHTMLDocument2 *doc) IHTMLElementCollection_Release(col); } +static void test_cond_comment(IHTMLDocument2 *doc) +{ + IHTMLElementCollection *col; + HRESULT hres; + + static const elem_type_t all_types[] = { + ET_HTML, + ET_HEAD, + ET_TITLE, + ET_BODY, + ET_BR + }; + + hres = IHTMLDocument2_get_all(doc, &col); + ok(hres == S_OK, "get_all failed: %08x\n", hres); + test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); + IHTMLElementCollection_Release(col); +} + static IHTMLDocument2 *notif_doc; static BOOL doc_complete; @@ -2437,12 +5346,10 @@ static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, D BSTR state; HRESULT hres; - static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0}; - hres = IHTMLDocument2_get_readyState(notif_doc, &state); ok(hres == S_OK, "get_readyState failed: %08x\n", hres); - if(!lstrcmpW(state, completeW)) + if(!strcmp_wa(state, "complete")) doc_complete = TRUE; SysFreeString(state); @@ -2524,6 +5431,9 @@ static void run_domtest(const char *str, domtest_t test) HRESULT hres; doc = create_doc_with_string(str); + if(!doc) + return; + do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink); while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) { @@ -2542,7 +5452,9 @@ static void run_domtest(const char *str, domtest_t test) } ref = IHTMLDocument2_Release(doc); - ok(!ref, "ref = %d\n", ref); + ok(!ref || + ref == 1, /* Vista */ + "ref = %d\n", ref); } static void gecko_installer_workaround(BOOL disable) @@ -2581,12 +5493,18 @@ START_TEST(dom) CoInitialize(NULL); run_domtest(doc_str1, test_doc_elem); + run_domtest(doc_str1, test_get_set_attr); run_domtest(range_test_str, test_txtrange); run_domtest(range_test2_str, test_txtrange2); + if (winetest_interactive || ! is_ie_hardened()) { run_domtest(elem_test_str, test_elems); + }else { + skip("IE running in Enhanced Security Configuration\n"); + } run_domtest(doc_blank, test_create_elems); run_domtest(doc_blank, test_defaults); run_domtest(indent_test_str, test_indent); + run_domtest(cond_comment_str, test_cond_comment); CoUninitialize(); gecko_installer_workaround(FALSE); diff --git a/rostests/winetests/mshtml/events.c b/rostests/winetests/mshtml/events.c new file mode 100644 index 00000000000..d0ddadb44da --- /dev/null +++ b/rostests/winetests/mshtml/events.c @@ -0,0 +1,1554 @@ +/* + * Copyright 2008-2009 Jacek Caban for CodeWeavers + * + * 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 + */ + +#define COBJMACROS +#define CONST_VTABLE + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "ole2.h" +#include "mshtml.h" +#include "docobj.h" +#include "hlink.h" +#include "dispex.h" + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) + +#define CHECK_EXPECT2(func) \ + do { \ + trace(#func "\n"); \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(document_onclick); +DEFINE_EXPECT(body_onclick); +DEFINE_EXPECT(div_onclick); +DEFINE_EXPECT(div_onclick_attached); +DEFINE_EXPECT(timeout); + +static HWND container_hwnd = NULL; +static IHTMLWindow2 *window; +static IOleDocumentView *view; + +typedef struct { + LONG x; + LONG y; + LONG offset_x; + LONG offset_y; +} xy_test_t; + +static const xy_test_t no_xy = {-10,-10,-10,-10}; +static const xy_test_t zero_xy = {0,0,0,0}; + +static const char empty_doc_str[] = + ""; + +static const char click_doc_str[] = + "" + "
click here
" + ""; + +static const char *debugstr_w(LPCWSTR str) +{ + static char buf[1024]; + WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); + return buf; +} + +static const char *debugstr_guid(REFIID riid) +{ + static char buf[50]; + + sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], + riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4], + riid->Data4[5], riid->Data4[6], riid->Data4[7]); + + return buf; +} + +static int strcmp_wa(LPCWSTR strw, const char *stra) +{ + CHAR buf[512]; + WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); + return lstrcmpA(stra, buf); +} + +static BSTR a2bstr(const char *str) +{ + BSTR ret; + int len; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = SysAllocStringLen(NULL, len-1); + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + + return ret; +} + +static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2) +{ + IUnknown *unk1, *unk2; + + if(iface1 == iface2) + return TRUE; + + IUnknown_QueryInterface(iface1, &IID_IUnknown, (void**)&unk1); + IUnknown_Release(unk1); + IUnknown_QueryInterface(iface1, &IID_IUnknown, (void**)&unk2); + IUnknown_Release(unk2); + + return unk1 == unk2; +} + +#define test_disp(u,id) _test_disp(__LINE__,u,id) +static void _test_disp(unsigned line, IUnknown *unk, const IID *diid) +{ + IDispatchEx *dispex; + ITypeInfo *typeinfo; + UINT ticnt; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); + ok_(__FILE__,line) (hres == S_OK, "Could not get IDispatch: %08x\n", hres); + if(FAILED(hres)) + return; + + ticnt = 0xdeadbeef; + hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); + ok_(__FILE__,line) (hres == S_OK, "GetTypeInfoCount failed: %08x\n", hres); + ok_(__FILE__,line) (ticnt == 1, "ticnt=%u\n", ticnt); + + hres = IDispatchEx_GetTypeInfo(dispex, 0, 0, &typeinfo); + ok_(__FILE__,line) (hres == S_OK, "GetTypeInfo failed: %08x\n", hres); + + if(SUCCEEDED(hres)) { + TYPEATTR *type_attr; + + hres = ITypeInfo_GetTypeAttr(typeinfo, &type_attr); + ok_(__FILE__,line) (hres == S_OK, "GetTypeAttr failed: %08x\n", hres); + ok_(__FILE__,line) (IsEqualGUID(&type_attr->guid, diid), "unexpected guid %s\n", + debugstr_guid(&type_attr->guid)); + + ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr); + ITypeInfo_Release(typeinfo); + } + + IDispatchEx_Release(dispex); +} + +#define get_doc3_iface(u) _get_doc3_iface(__LINE__,u) +static IHTMLDocument3 *_get_doc3_iface(unsigned line, IUnknown *unk) +{ + IHTMLDocument3 *doc3; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLDocument3, (void**)&doc3); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDocument3 iface: %08x\n", hres); + + return doc3; +} + +#define get_elem_iface(u) _get_elem_iface(__LINE__,u) +static IHTMLElement *_get_elem_iface(unsigned line, IUnknown *unk) +{ + IHTMLElement *elem; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement, (void**)&elem); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement iface: %08x\n", hres); + + return elem; +} + +#define get_elem2_iface(u) _get_elem2_iface(__LINE__,u) +static IHTMLElement2 *_get_elem2_iface(unsigned line, IUnknown *unk) +{ + IHTMLElement2 *elem2; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement2, (void**)&elem2); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement2 iface: %08x\n", hres); + + return elem2; +} + +#define doc_get_body(d) _doc_get_body(__LINE__,d) +static IHTMLElement *_doc_get_body(unsigned line, IHTMLDocument2 *doc) +{ + IHTMLElement *body = NULL; + HRESULT hres; + + hres = IHTMLDocument2_get_body(doc, &body); + ok_(__FILE__,line) (hres == S_OK, "get_body failed: %08x\n", hres); + ok_(__FILE__,line) (body != NULL, "body == NULL\n"); + + return body; +} + +#define get_elem_id(d,i) _get_elem_id(__LINE__,d,i) +static IHTMLElement *_get_elem_id(unsigned line, IHTMLDocument2 *doc, const char *id) +{ + IHTMLDocument3 *doc3 = _get_doc3_iface(line, (IUnknown*)doc); + IHTMLElement *elem; + BSTR str; + HRESULT hres; + + str = a2bstr(id); + hres = IHTMLDocument3_getElementById(doc3, str, &elem); + SysFreeString(str); + IHTMLDocument3_Release(doc3); + ok_(__FILE__,line) (hres == S_OK, "getElementById failed: %08x\n", hres); + + return elem; +} + +#define test_elem_tag(u,n) _test_elem_tag(__LINE__,u,n) +static void _test_elem_tag(unsigned line, IUnknown *unk, const char *extag) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + BSTR tag; + HRESULT hres; + + hres = IHTMLElement_get_tagName(elem, &tag); + IHTMLElement_Release(elem); + ok_(__FILE__, line) (hres == S_OK, "get_tagName failed: %08x\n", hres); + ok_(__FILE__, line) (!strcmp_wa(tag, extag), "got tag: %s, expected %s\n", debugstr_w(tag), extag); + + SysFreeString(tag); +} + +#define get_event_obj() _get_event_obj(__LINE__) +static IHTMLEventObj *_get_event_obj(unsigned line) +{ + IHTMLEventObj *event = NULL; + HRESULT hres; + + hres = IHTMLWindow2_get_event(window, &event); + ok_(__FILE__,line) (hres == S_OK, "get_event failed: %08x\n", hres); + ok_(__FILE__,line) (event != NULL, "event = NULL\n"); + _test_disp(line, (IUnknown*)event, &DIID_DispCEventObj); + + return event; +} + +#define test_event_args(a,b,c,d,e,f,g) _test_event_args(__LINE__,a,b,c,d,e,f,g) +static void _test_event_args(unsigned line, const IID *dispiid, DISPID id, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok_(__FILE__,line) (id == DISPID_VALUE, "id = %d\n", id); + ok_(__FILE__,line) (wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok_(__FILE__,line) (pdp != NULL, "pdp == NULL\n"); + ok_(__FILE__,line) (pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs); + ok_(__FILE__,line) (pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); + ok_(__FILE__,line) (pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %d\n", + pdp->rgdispidNamedArgs[0]); + ok_(__FILE__,line) (V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok_(__FILE__,line) (pvarRes != NULL, "pvarRes == NULL\n"); + ok_(__FILE__,line) (pei != NULL, "pei == NULL"); + ok_(__FILE__,line) (!pspCaller, "pspCaller != NULL\n"); + + if(dispiid) + _test_disp(line, (IUnknown*)V_DISPATCH(pdp->rgvarg), dispiid); +} + +#define test_attached_event_args(a,b,c,d,e) _test_attached_event_args(__LINE__,a,b,c,d,e) +static void _test_attached_event_args(unsigned line, DISPID id, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei) +{ + IHTMLEventObj *event; + + ok(id == DISPID_VALUE, "id = %d\n", id); + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pDispParams == NULL\n"); + ok(pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs); + ok(!pdp->cNamedArgs, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); + ok(!pdp->rgdispidNamedArgs, "pdp->rgdispidNamedArgs = %p\n", pdp->rgdispidNamedArgs); + ok(pdp->rgvarg != NULL, "rgvarg = NULL\n"); + ok(pvarRes != NULL, "pvarRes = NULL\n"); + ok(pei != NULL, "pei = NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pVarRes) = %d\n", V_VT(pvarRes)); + ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(pdp->rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_DISPATCH(pdp->rgvarg) != NULL, "V_DISPATCH(pdp->rgvarg) = %p\n", V_DISPATCH(pdp->rgvarg)); + + event = _get_event_obj(line); + ok(iface_cmp((IUnknown*)event, (IUnknown*)V_DISPATCH(pdp->rgvarg)), "event != arg0\n"); + IHTMLEventObj_Release(event); +} + +#define test_event_src(t) _test_event_src(__LINE__,t) +static void _test_event_src(unsigned line, const char *src_tag) +{ + IHTMLEventObj *event = _get_event_obj(line); + IHTMLElement *src_elem = NULL; + HRESULT hres; + + hres = IHTMLEventObj_get_srcElement(event, &src_elem); + IHTMLEventObj_Release(event); + ok_(__FILE__,line) (hres == S_OK, "get_srcElement failed: %08x\n", hres); + + if(src_tag) { + ok_(__FILE__,line) (src_elem != NULL, "src_elem = NULL\n"); + _test_elem_tag(line, (IUnknown*)src_elem, src_tag); + IHTMLElement_Release(src_elem); + }else { + ok_(__FILE__,line) (!src_elem, "src_elem != NULL\n"); + } +} + +static void _test_event_altkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval) +{ + VARIANT_BOOL b; + HRESULT hres; + + hres = IHTMLEventObj_get_altKey(event, &b); + ok_(__FILE__,line)(hres == S_OK, "get_altKey failed: %08x\n", hres); + ok_(__FILE__,line)(b == exval, "altKey = %x, expected %x\n", b, exval); +} + +static void _test_event_ctrlkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval) +{ + VARIANT_BOOL b; + HRESULT hres; + + hres = IHTMLEventObj_get_ctrlKey(event, &b); + ok_(__FILE__,line)(hres == S_OK, "get_ctrlKey failed: %08x\n", hres); + ok_(__FILE__,line)(b == exval, "ctrlKey = %x, expected %x\n", b, exval); +} + +static void _test_event_shiftkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval) +{ + VARIANT_BOOL b; + HRESULT hres; + + hres = IHTMLEventObj_get_shiftKey(event, &b); + ok_(__FILE__,line)(hres == S_OK, "get_shiftKey failed: %08x\n", hres); + ok_(__FILE__,line)(b == exval, "shiftKey = %x, expected %x\n", b, exval); +} + +static void _test_event_cancelbubble(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval) +{ + VARIANT_BOOL b; + HRESULT hres; + + hres = IHTMLEventObj_get_cancelBubble(event, &b); + ok_(__FILE__,line)(hres == S_OK, "get_cancelBubble failed: %08x\n", hres); + ok_(__FILE__,line)(b == exval, "cancelBubble = %x, expected %x\n", b, exval); +} + +static void _test_event_fromelem(unsigned line, IHTMLEventObj *event, const char *from_tag) +{ + IHTMLElement *elem; + HRESULT hres; + + hres = IHTMLEventObj_get_fromElement(event, &elem); + ok_(__FILE__,line)(hres == S_OK, "get_fromElement failed: %08x\n", hres); + if(from_tag) + _test_elem_tag(line, (IUnknown*)elem, from_tag); + else + ok_(__FILE__,line)(elem == NULL, "fromElement != NULL\n"); + if(elem) + IHTMLElement_Release(elem); +} + +static void _test_event_toelem(unsigned line, IHTMLEventObj *event, const char *to_tag) +{ + IHTMLElement *elem; + HRESULT hres; + + hres = IHTMLEventObj_get_toElement(event, &elem); + ok_(__FILE__,line)(hres == S_OK, "get_toElement failed: %08x\n", hres); + if(to_tag) + _test_elem_tag(line, (IUnknown*)elem, to_tag); + else + ok_(__FILE__,line)(elem == NULL, "toElement != NULL\n"); + if(elem) + IHTMLElement_Release(elem); +} + +static void _test_event_keycode(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_keyCode(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_keyCode failed: %08x\n", hres); + ok_(__FILE__,line)(l == exl, "keyCode = %x, expected %x\n", l, exl); +} + +static void _test_event_button(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_button(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_button failed: %08x\n", hres); + ok_(__FILE__,line)(l == exl, "button = %x, expected %x\n", l, exl); +} + +static void _test_event_reason(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_reason(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_reason failed: %08x\n", hres); + ok_(__FILE__,line)(l == exl, "reason = %x, expected %x\n", l, exl); +} + +static void _test_event_x(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_x(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_x failed: %08x\n", hres); + if(exl == -10) /* don't test the exact value */ + todo_wine ok_(__FILE__,line)(l > 0, "x = %d\n", l); + else + ok_(__FILE__,line)(l == exl, "x = %d, expected %d\n", l, exl); +} + +static void _test_event_y(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_y(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_y failed: %08x\n", hres); + if(exl == -10) /* don't test the exact value */ + todo_wine ok_(__FILE__,line)(l > 0, "y = %d\n", l); + else + ok_(__FILE__,line)(l == exl, "y = %d, expected %d\n", l, exl); +} + +static void _test_event_clientx(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_clientX(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_clientX failed: %08x\n", hres); + if(exl == -10) /* don't test the exact value */ + ok_(__FILE__,line)(l > 0, "clientX = %d\n", l); + else + ok_(__FILE__,line)(l == exl, "clientX = %d, expected %d\n", l, exl); +} + +static void _test_event_clienty(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_clientY(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_clientY failed: %08x\n", hres); + if(exl == -10) /* don't test the exact value */ + ok_(__FILE__,line)(l > 0, "clientY = %d\n", l); + else + ok_(__FILE__,line)(l == exl, "clientY = %d, expected %d\n", l, exl); +} + +static void _test_event_offsetx(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_offsetX(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_offsetX failed: %08x\n", hres); + if(exl == -10) /* don't test the exact value */ + todo_wine ok_(__FILE__,line)(l > 0, "offsetX = %d\n", l); + else + ok_(__FILE__,line)(l == exl, "offsetX = %d, expected %d\n", l, exl); +} + +static void _test_event_offsety(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_offsetY(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_offsetY failed: %08x\n", hres); + if(exl == -10) /* don't test the exact value */ + todo_wine ok_(__FILE__,line)(l > 0, "offsetY = %d\n", l); + else + ok_(__FILE__,line)(l == exl, "offsetY = %d, expected %d\n", l, exl); +} + +static void _test_event_screenx(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_screenX(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_screenX failed: %08x\n", hres); + if(exl == -10) /* don't test the exact value */ + ok_(__FILE__,line)(l > 0, "screenX = %d\n", l); + else + ok_(__FILE__,line)(l == exl, "screenX = %d, expected %d\n", l, exl); +} + +static void _test_event_screeny(unsigned line, IHTMLEventObj *event, LONG exl) +{ + LONG l; + HRESULT hres; + + hres = IHTMLEventObj_get_screenY(event, &l); + ok_(__FILE__,line)(hres == S_OK, "get_screenY failed: %08x\n", hres); + if(exl == -10) /* don't test the exact value */ + ok_(__FILE__,line)(l > 0, "screenY = %d\n", l); + else + ok_(__FILE__,line)(l == exl, "screenY = %d, expected %d\n", l, exl); +} + +static void _test_event_type(unsigned line, IHTMLEventObj *event, const char *exstr) +{ + BSTR str; + HRESULT hres; + + hres = IHTMLEventObj_get_type(event, &str); + ok_(__FILE__,line)(hres == S_OK, "get_type failed: %08x\n", hres); + ok_(__FILE__,line)(!strcmp_wa(str, exstr), "type = %s, expected %s\n", wine_dbgstr_w(str), exstr); +} + +static void _test_event_qualifier(unsigned line, IHTMLEventObj *event, const char *exstr) +{ + BSTR str; + HRESULT hres; + + hres = IHTMLEventObj_get_qualifier(event, &str); + ok_(__FILE__,line)(hres == S_OK, "get_qualifier failed: %08x\n", hres); + if(exstr) + ok_(__FILE__,line)(!strcmp_wa(str, exstr), "qualifier = %s, expected %s\n", wine_dbgstr_w(str), exstr); + else + ok_(__FILE__,line)(!str, "qualifier != NULL\n"); +} + +static void _test_event_srcfilter(unsigned line, IHTMLEventObj *event) +{ + IDispatch *disp; + HRESULT hres; + + hres = IHTMLEventObj_get_srcFilter(event, &disp); + ok_(__FILE__,line)(hres == S_OK, "get_srcFilter failed: %08x\n", hres); + ok_(__FILE__,line)(!disp, "srcFilter != NULL\n"); +} + +#define test_event_obj(t,x) _test_event_obj(__LINE__,t,x) +static void _test_event_obj(unsigned line, const char *type, const xy_test_t *xy) +{ + IHTMLEventObj *event = _get_event_obj(line); + VARIANT v; + HRESULT hres; + + _test_event_altkey(line, event, VARIANT_FALSE); + _test_event_ctrlkey(line, event, VARIANT_FALSE); + _test_event_shiftkey(line, event, VARIANT_FALSE); + _test_event_cancelbubble(line, event, VARIANT_FALSE); + _test_event_fromelem(line, event, NULL); + _test_event_toelem(line, event, NULL); + _test_event_keycode(line, event, 0); + _test_event_button(line, event, 0); + _test_event_type(line, event, type); + _test_event_qualifier(line, event, NULL); + _test_event_reason(line, event, 0); + _test_event_srcfilter(line, event); + _test_event_x(line, event, xy->x); + _test_event_y(line, event, xy->y); + _test_event_clientx(line, event, -10); + _test_event_clienty(line, event, -10); + _test_event_offsetx(line, event, xy->offset_x); + _test_event_offsety(line, event, xy->offset_y); + _test_event_screenx(line, event, -10); + _test_event_screeny(line, event, -10); + + hres = IHTMLEventObj_get_returnValue(event, &v); + ok_(__FILE__,line)(hres == S_OK, "get_returnValue failed: %08x\n", hres); + ok_(__FILE__,line)(V_VT(&v) == VT_EMPTY, "V_VT(returnValue) = %d\n", V_VT(&v)); + + IHTMLEventObj_Release(event); +} + +#define elem_attach_event(a,b,c) _elem_attach_event(__LINE__,a,b,c) +static void _elem_attach_event(unsigned line, IUnknown *unk, const char *namea, IDispatch *disp) +{ + IHTMLElement2 *elem = _get_elem2_iface(line, unk); + VARIANT_BOOL res; + BSTR name; + HRESULT hres; + + name = a2bstr(namea); + hres = IHTMLElement2_attachEvent(elem, name, disp, &res); + IHTMLElement2_Release(elem); + SysFreeString(name); + ok_(__FILE__,line)(hres == S_OK, "attachEvent failed: %08x\n", hres); + ok_(__FILE__,line)(res == VARIANT_TRUE, "attachEvent returned %x\n", res); +} + +static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDispatch) + || IsEqualGUID(riid, &IID_IDispatchEx)) + *ppv = iface; + else { + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + return S_OK; +} + +static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) +{ + return 2; +} + +static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) +{ + return 1; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) +{ + ok(0, "unexpected call %s %x\n", debugstr_w(bstrName), grfdex); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +#define EVENT_HANDLER_FUNC_OBJ(event) \ + static IDispatchExVtbl event ## FuncVtbl = { \ + DispatchEx_QueryInterface, \ + DispatchEx_AddRef, \ + DispatchEx_Release, \ + DispatchEx_GetTypeInfoCount, \ + DispatchEx_GetTypeInfo, \ + DispatchEx_GetIDsOfNames, \ + DispatchEx_Invoke, \ + DispatchEx_GetDispID, \ + event, \ + DispatchEx_DeleteMemberByName, \ + DispatchEx_DeleteMemberByDispID, \ + DispatchEx_GetMemberProperties, \ + DispatchEx_GetMemberName, \ + DispatchEx_GetNextDispID, \ + DispatchEx_GetNameSpaceParent \ + }; \ + static IDispatchEx event ## _obj = { &event ## FuncVtbl }; + +static HRESULT WINAPI document_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + IHTMLDocument3 *doc3; + CHECK_EXPECT(document_onclick); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + doc3 = get_doc3_iface((IUnknown*)V_DISPATCH(pdp->rgvarg)); + IHTMLDocument3_Release(doc3); + test_event_src("DIV"); + test_event_obj("click", &no_xy); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(document_onclick); + +static HRESULT WINAPI div_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(div_onclick); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + test_event_src("DIV"); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(div_onclick); + +static HRESULT WINAPI div_onclick_attached(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(div_onclick_attached); + + test_attached_event_args(id, wFlags, pdp, pvarRes, pei); + test_event_src("DIV"); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(div_onclick_attached); + +static HRESULT WINAPI body_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(body_onclick); + test_event_args(&DIID_DispHTMLBody, id, wFlags, pdp, pvarRes, pei, pspCaller); + test_event_src("DIV"); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(body_onclick); + +static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(nocall); + +static HRESULT WINAPI timeoutFunc_Invoke(IDispatchEx *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + CHECK_EXPECT(timeout); + + ok(dispIdMember == DISPID_VALUE, "dispIdMember = %d\n", dispIdMember); + ok(IsEqualGUID(&IID_NULL, riid), "riid = %s\n", debugstr_guid(riid)); + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(!lcid, "lcid = %x\n", lcid); + ok(pDispParams != NULL, "pDispParams == NULL\n"); + ok(!pDispParams->cArgs, "pdp->cArgs = %d\n", pDispParams->cArgs); + ok(!pDispParams->cNamedArgs, "pdp->cNamedArgs = %d\n", pDispParams->cNamedArgs); + ok(!pDispParams->rgdispidNamedArgs, "pdp->rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs); + ok(!pDispParams->rgvarg, "rgvarg = %p\n", pDispParams->rgvarg); + ok(pVarResult != NULL, "pVarResult = NULL\n"); + ok(pExcepInfo != NULL, "pExcepInfo = NULL\n"); + ok(!puArgErr, "puArgErr = %p\n", puArgErr); + ok(V_VT(pVarResult) == VT_EMPTY, "V_VT(pVarResult) = %d\n", V_VT(pVarResult)); + + return S_OK; +} + +static IDispatchExVtbl timeoutFuncVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + timeoutFunc_Invoke, + DispatchEx_GetDispID, + DispatchEx_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx timeoutFunc = { &timeoutFuncVtbl }; + +static void pump_msgs(BOOL *b) +{ + MSG msg; + while(!*b && GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +static void test_onclick(IHTMLDocument2 *doc) +{ + IHTMLElement *div, *body; + VARIANT v; + HRESULT hres; + + div = get_elem_id(doc, "clickdiv"); + + elem_attach_event((IUnknown*)div, "abcde", (IDispatch*)&nocall_obj); + elem_attach_event((IUnknown*)div, "onclick", (IDispatch*)&div_onclick_attached_obj); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLElement_get_onclick(div, &v); + ok(hres == S_OK, "get_onclick failed: %08x\n", hres); + ok(V_VT(&v) == VT_NULL, "V_VT(onclick) = %d\n", V_VT(&v)); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&div_onclick_obj; + hres = IHTMLElement_put_onclick(div, v); + ok(hres == S_OK, "put_onclick failed: %08x\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLElement_get_onclick(div, &v); + ok(hres == S_OK, "get_onclick failed: %08x\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onclick) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&div_onclick_obj, "V_DISPATCH(onclick) != onclickFunc\n"); + VariantClear(&v); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLDocument2_get_onclick(doc, &v); + ok(hres == S_OK, "get_onclick failed: %08x\n", hres); + ok(V_VT(&v) == VT_NULL, "V_VT(onclick) = %d\n", V_VT(&v)); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&document_onclick_obj; + hres = IHTMLDocument2_put_onclick(doc, v); + ok(hres == S_OK, "put_onclick failed: %08x\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLDocument2_get_onclick(doc, &v); + ok(hres == S_OK, "get_onclick failed: %08x\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onclick) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&document_onclick_obj, "V_DISPATCH(onclick) != onclickFunc\n"); + VariantClear(&v); + + body = doc_get_body(doc); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&body_onclick_obj; + hres = IHTMLElement_put_onclick(body, v); + ok(hres == S_OK, "put_onclick failed: %08x\n", hres); + + if(winetest_interactive) { + SET_EXPECT(div_onclick); + SET_EXPECT(div_onclick_attached); + SET_EXPECT(body_onclick); + SET_EXPECT(document_onclick); + pump_msgs(&called_document_onclick); + CHECK_CALLED(div_onclick); + CHECK_CALLED(div_onclick_attached); + CHECK_CALLED(body_onclick); + CHECK_CALLED(document_onclick); + } + + IHTMLElement_Release(div); + IHTMLElement_Release(body); +} + +static void test_timeout(IHTMLDocument2 *doc) +{ + IHTMLWindow3 *win3; + VARIANT expr, var; + LONG id; + HRESULT hres; + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow3, (void**)&win3); + ok(hres == S_OK, "Could not get IHTMLWindow3 iface: %08x\n", hres); + + V_VT(&expr) = VT_DISPATCH; + V_DISPATCH(&expr) = (IDispatch*)&timeoutFunc; + V_VT(&var) = VT_EMPTY; + id = 0; + hres = IHTMLWindow3_setTimeout(win3, &expr, 0, &var, &id); + ok(hres == S_OK, "setTimeout failed: %08x\n", hres); + ok(id, "id = 0\n"); + + SET_EXPECT(timeout); + pump_msgs(&called_timeout); + CHECK_CALLED(timeout); + + V_VT(&expr) = VT_DISPATCH; + V_DISPATCH(&expr) = (IDispatch*)&timeoutFunc; + V_VT(&var) = VT_EMPTY; + id = 0; + hres = IHTMLWindow3_setTimeout(win3, &expr, 0, &var, &id); + ok(hres == S_OK, "setTimeout failed: %08x\n", hres); + ok(id, "id = 0\n"); + + hres = IHTMLWindow2_clearTimeout(window, id); + ok(hres == S_OK, "clearTimeout failed: %08x\n", hres); + + IHTMLWindow3_Release(win3); +} + +static HRESULT QueryInterface(REFIID,void**); + +static HRESULT WINAPI InPlaceFrame_QueryInterface(IOleInPlaceFrame *iface, REFIID riid, void **ppv) +{ + return E_NOINTERFACE; +} + +static ULONG WINAPI InPlaceFrame_AddRef(IOleInPlaceFrame *iface) +{ + return 2; +} + +static ULONG WINAPI InPlaceFrame_Release(IOleInPlaceFrame *iface) +{ + return 1; +} + +static HRESULT WINAPI InPlaceFrame_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_ContextSensitiveHelp(IOleInPlaceFrame *iface, BOOL fEnterMode) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_GetBorder(IOleInPlaceFrame *iface, LPRECT lprectBorder) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_RequestBorderSpace(IOleInPlaceFrame *iface, + LPCBORDERWIDTHS pborderwidths) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_SetBorderSpace(IOleInPlaceFrame *iface, + LPCBORDERWIDTHS pborderwidths) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceUIWindow_SetActiveObject(IOleInPlaceFrame *iface, + IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_SetActiveObject(IOleInPlaceFrame *iface, + IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_InsertMenus(IOleInPlaceFrame *iface, HMENU hmenuShared, + LPOLEMENUGROUPWIDTHS lpMenuWidths) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_SetMenu(IOleInPlaceFrame *iface, HMENU hmenuShared, + HOLEMENU holemenu, HWND hwndActiveObject) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_RemoveMenus(IOleInPlaceFrame *iface, HMENU hmenuShared) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_SetStatusText(IOleInPlaceFrame *iface, LPCOLESTR pszStatusText) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_EnableModeless(IOleInPlaceFrame *iface, BOOL fEnable) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_TranslateAccelerator(IOleInPlaceFrame *iface, LPMSG lpmsg, WORD wID) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IOleInPlaceFrameVtbl InPlaceFrameVtbl = { + InPlaceFrame_QueryInterface, + InPlaceFrame_AddRef, + InPlaceFrame_Release, + InPlaceFrame_GetWindow, + InPlaceFrame_ContextSensitiveHelp, + InPlaceFrame_GetBorder, + InPlaceFrame_RequestBorderSpace, + InPlaceFrame_SetBorderSpace, + InPlaceFrame_SetActiveObject, + InPlaceFrame_InsertMenus, + InPlaceFrame_SetMenu, + InPlaceFrame_RemoveMenus, + InPlaceFrame_SetStatusText, + InPlaceFrame_EnableModeless, + InPlaceFrame_TranslateAccelerator +}; + +static IOleInPlaceFrame InPlaceFrame = { &InPlaceFrameVtbl }; + +static const IOleInPlaceFrameVtbl InPlaceUIWindowVtbl = { + InPlaceFrame_QueryInterface, + InPlaceFrame_AddRef, + InPlaceFrame_Release, + InPlaceFrame_GetWindow, + InPlaceFrame_ContextSensitiveHelp, + InPlaceFrame_GetBorder, + InPlaceFrame_RequestBorderSpace, + InPlaceFrame_SetBorderSpace, + InPlaceUIWindow_SetActiveObject, +}; + +static IOleInPlaceFrame InPlaceUIWindow = { &InPlaceUIWindowVtbl }; + +static HRESULT WINAPI InPlaceSite_QueryInterface(IOleInPlaceSite *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI InPlaceSite_AddRef(IOleInPlaceSite *iface) +{ + return 2; +} + +static ULONG WINAPI InPlaceSite_Release(IOleInPlaceSite *iface) +{ + return 1; +} + +static HRESULT WINAPI InPlaceSite_GetWindow(IOleInPlaceSite *iface, HWND *phwnd) +{ + *phwnd = container_hwnd; + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_ContextSensitiveHelp(IOleInPlaceSite *iface, BOOL fEnterMode) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_CanInPlaceActivate(IOleInPlaceSite *iface) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceActivate(IOleInPlaceSite *iface) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_OnUIActivate(IOleInPlaceSite *iface) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_GetWindowContext(IOleInPlaceSite *iface, + IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, + LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) +{ + static const RECT rect = {0,0,300,300}; + + *ppFrame = &InPlaceFrame; + *ppDoc = (IOleInPlaceUIWindow*)&InPlaceUIWindow; + *lprcPosRect = rect; + *lprcClipRect = rect; + + lpFrameInfo->cb = sizeof(*lpFrameInfo); + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->hwndFrame = container_hwnd; + lpFrameInfo->haccel = NULL; + lpFrameInfo->cAccelEntries = 0; + + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_Scroll(IOleInPlaceSite *iface, SIZE scrollExtant) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnUIDeactivate(IOleInPlaceSite *iface, BOOL fUndoable) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceDeactivate(IOleInPlaceSite *iface) +{ + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_DiscardUndoState(IOleInPlaceSite *iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_DeactivateAndUndo(IOleInPlaceSite *iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnPosRectChange(IOleInPlaceSite *iface, LPCRECT lprcPosRect) +{ + return E_NOTIMPL; +} + +static const IOleInPlaceSiteVtbl InPlaceSiteVtbl = { + InPlaceSite_QueryInterface, + InPlaceSite_AddRef, + InPlaceSite_Release, + InPlaceSite_GetWindow, + InPlaceSite_ContextSensitiveHelp, + InPlaceSite_CanInPlaceActivate, + InPlaceSite_OnInPlaceActivate, + InPlaceSite_OnUIActivate, + InPlaceSite_GetWindowContext, + InPlaceSite_Scroll, + InPlaceSite_OnUIDeactivate, + InPlaceSite_OnInPlaceDeactivate, + InPlaceSite_DiscardUndoState, + InPlaceSite_DeactivateAndUndo, + InPlaceSite_OnPosRectChange, +}; + +static IOleInPlaceSite InPlaceSite = { &InPlaceSiteVtbl }; + +static HRESULT WINAPI ClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI ClientSite_AddRef(IOleClientSite *iface) +{ + return 2; +} + +static ULONG WINAPI ClientSite_Release(IOleClientSite *iface) +{ + return 1; +} + +static HRESULT WINAPI ClientSite_SaveObject(IOleClientSite *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ClientSite_GetMoniker(IOleClientSite *iface, DWORD dwAssign, DWORD dwWhichMoniker, + IMoniker **ppmon) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ClientSite_GetContainer(IOleClientSite *iface, IOleContainer **ppContainer) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ClientSite_ShowObject(IOleClientSite *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ClientSite_OnShowWindow(IOleClientSite *iface, BOOL fShow) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ClientSite_RequestNewObjectLayout(IOleClientSite *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IOleClientSiteVtbl ClientSiteVtbl = { + ClientSite_QueryInterface, + ClientSite_AddRef, + ClientSite_Release, + ClientSite_SaveObject, + ClientSite_GetMoniker, + ClientSite_GetContainer, + ClientSite_ShowObject, + ClientSite_OnShowWindow, + ClientSite_RequestNewObjectLayout +}; + +static IOleClientSite ClientSite = { &ClientSiteVtbl }; + +static HRESULT WINAPI DocumentSite_QueryInterface(IOleDocumentSite *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI DocumentSite_AddRef(IOleDocumentSite *iface) +{ + return 2; +} + +static ULONG WINAPI DocumentSite_Release(IOleDocumentSite *iface) +{ + return 1; +} + +static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocumentView *pViewToActivate) +{ + RECT rect = {0,0,300,300}; + IOleDocument *document; + HRESULT hres; + + hres = IOleDocumentView_QueryInterface(pViewToActivate, &IID_IOleDocument, (void**)&document); + ok(hres == S_OK, "could not get IOleDocument: %08x\n", hres); + + hres = IOleDocument_CreateView(document, &InPlaceSite, NULL, 0, &view); + IOleDocument_Release(document); + ok(hres == S_OK, "CreateView failed: %08x\n", hres); + + hres = IOleDocumentView_SetInPlaceSite(view, &InPlaceSite); + ok(hres == S_OK, "SetInPlaceSite failed: %08x\n", hres); + + hres = IOleDocumentView_UIActivate(view, TRUE); + ok(hres == S_OK, "UIActivate failed: %08x\n", hres); + + hres = IOleDocumentView_SetRect(view, &rect); + ok(hres == S_OK, "SetRect failed: %08x\n", hres); + + hres = IOleDocumentView_Show(view, TRUE); + ok(hres == S_OK, "Show failed: %08x\n", hres); + + return S_OK; +} + +static const IOleDocumentSiteVtbl DocumentSiteVtbl = { + DocumentSite_QueryInterface, + DocumentSite_AddRef, + DocumentSite_Release, + DocumentSite_ActivateMe +}; + +static IOleDocumentSite DocumentSite = { &DocumentSiteVtbl }; + +static HRESULT QueryInterface(REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IOleClientSite, riid)) + *ppv = &ClientSite; + else if(IsEqualGUID(&IID_IOleDocumentSite, riid)) + *ppv = &DocumentSite; + else if(IsEqualGUID(&IID_IOleWindow, riid) || IsEqualGUID(&IID_IOleInPlaceSite, riid)) + *ppv = &InPlaceSite; + + return *ppv ? S_OK : E_NOINTERFACE; +} + +static IHTMLDocument2 *notif_doc; +static BOOL doc_complete; + +static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface, + REFIID riid, void**ppv) +{ + if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) { + *ppv = iface; + return S_OK; + } + + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface) +{ + return 2; +} + +static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface) +{ + return 1; +} + +static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID) +{ + if(dispID == DISPID_READYSTATE){ + BSTR state; + HRESULT hres; + + hres = IHTMLDocument2_get_readyState(notif_doc, &state); + ok(hres == S_OK, "get_readyState failed: %08x\n", hres); + + if(!strcmp_wa(state, "complete")) + doc_complete = TRUE; + + SysFreeString(state); + } + + return S_OK; +} + +static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = { + PropertyNotifySink_QueryInterface, + PropertyNotifySink_AddRef, + PropertyNotifySink_Release, + PropertyNotifySink_OnChanged, + PropertyNotifySink_OnRequestEdit +}; + +static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl }; + +static void doc_load_string(IHTMLDocument2 *doc, const char *str) +{ + IPersistStreamInit *init; + IStream *stream; + HGLOBAL mem; + SIZE_T len; + + notif_doc = doc; + + doc_complete = FALSE; + len = strlen(str); + mem = GlobalAlloc(0, len); + memcpy(mem, str, len); + CreateStreamOnHGlobal(mem, TRUE, &stream); + + IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init); + + IPersistStreamInit_Load(init, stream); + IPersistStreamInit_Release(init); + IStream_Release(stream); +} + +static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise) +{ + IConnectionPointContainer *container; + IConnectionPoint *cp; + DWORD cookie; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container); + ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres); + + hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp); + IConnectionPointContainer_Release(container); + ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres); + + hres = IConnectionPoint_Advise(cp, unk_advise, &cookie); + IConnectionPoint_Release(cp); + ok(hres == S_OK, "Advise failed: %08x\n", hres); +} + +static void set_client_site(IHTMLDocument2 *doc, BOOL set) +{ + IOleObject *oleobj; + HRESULT hres; + + if(!set && view) { + IOleDocumentView_Show(view, FALSE); + IOleDocumentView_CloseView(view, 0); + IOleDocumentView_SetInPlaceSite(view, NULL); + IOleDocumentView_Release(view); + view = NULL; + } + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IOleObject, (void**)&oleobj); + ok(hres == S_OK, "Could not et IOleObject: %08x\n", hres); + + hres = IOleObject_SetClientSite(oleobj, set ? &ClientSite : NULL); + ok(hres == S_OK, "SetClientSite failed: %08x\n", hres); + + if(set) { + IHlinkTarget *hlink; + + hres = IOleObject_QueryInterface(oleobj, &IID_IHlinkTarget, (void**)&hlink); + ok(hres == S_OK, "Could not get IHlinkTarget iface: %08x\n", hres); + + hres = IHlinkTarget_Navigate(hlink, 0, NULL); + ok(hres == S_OK, "Navgate failed: %08x\n", hres); + + IHlinkTarget_Release(hlink); + } + + IOleObject_Release(oleobj); +} +static IHTMLDocument2 *create_document(void) +{ + IHTMLDocument2 *doc; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IHTMLDocument2, (void**)&doc); + ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); + + return doc; +} + + +typedef void (*testfunc_t)(IHTMLDocument2*); + +static void run_test(const char *str, testfunc_t test) +{ + IHTMLDocument2 *doc; + IHTMLElement *body = NULL; + ULONG ref; + MSG msg; + HRESULT hres; + + doc = create_document(); + set_client_site(doc, TRUE); + doc_load_string(doc, str); + do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink); + + while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + hres = IHTMLDocument2_get_body(doc, &body); + ok(hres == S_OK, "get_body failed: %08x\n", hres); + + if(body) { + IHTMLElement_Release(body); + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08x\n", hres); + ok(window != NULL, "window == NULL\n"); + + test(doc); + + IHTMLWindow2_Release(window); + window = NULL; + }else { + skip("Could not get document body. Assuming no Gecko installed.\n"); + } + + set_client_site(doc, FALSE); + ref = IHTMLDocument2_Release(doc); + ok(!ref, "ref = %d\n", ref); +} + +static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +static HWND create_container_window(void) +{ + static const CHAR szHTMLDocumentTest[] = "HTMLDocumentTest"; + static WNDCLASSEXA wndclass = { + sizeof(WNDCLASSEXA), + 0, + wnd_proc, + 0, 0, NULL, NULL, NULL, NULL, NULL, + szHTMLDocumentTest, + NULL + }; + + RegisterClassExA(&wndclass); + return CreateWindowA(szHTMLDocumentTest, szHTMLDocumentTest, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, + 300, 300, NULL, NULL, NULL, NULL); +} + +START_TEST(events) +{ + CoInitialize(NULL); + container_hwnd = create_container_window(); + + if(winetest_interactive) + ShowWindow(container_hwnd, SW_SHOW); + + run_test(empty_doc_str, test_timeout); + run_test(click_doc_str, test_onclick); + + DestroyWindow(container_hwnd); + CoUninitialize(); +} diff --git a/rostests/winetests/mshtml/htmldoc.c b/rostests/winetests/mshtml/htmldoc.c index 4de528676cd..f8cfc7f078a 100644 --- a/rostests/winetests/mshtml/htmldoc.c +++ b/rostests/winetests/mshtml/htmldoc.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Jacek Caban for CodeWeavers + * Copyright 2005-2009 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,7 @@ #include "windef.h" #include "winbase.h" +#include "initguid.h" #include "ole2.h" #include "mshtml.h" #include "docobj.h" @@ -35,8 +36,11 @@ #include "dispex.h" #include "idispids.h" #include "shlguid.h" +#include "perhist.h" +#include "mshtml_test.h" -#include "initguid.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +DEFINE_GUID(IID_IProxyManager,0x00000008,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); DEFINE_OLEGUID(CGID_DocHostCmdPriv, 0x000214D4L, 0, 0); #define DEFINE_EXPECT(func) \ @@ -100,6 +104,8 @@ DEFINE_EXPECT(Exec_SETDOWNLOADSTATE_1); DEFINE_EXPECT(Exec_ShellDocView_37); DEFINE_EXPECT(Exec_ShellDocView_84); DEFINE_EXPECT(Exec_ShellDocView_103); +DEFINE_EXPECT(Exec_ShellDocView_105); +DEFINE_EXPECT(Exec_ShellDocView_140); DEFINE_EXPECT(Exec_UPDATECOMMANDS); DEFINE_EXPECT(Exec_SETTITLE); DEFINE_EXPECT(Exec_HTTPEQUIV); @@ -117,6 +123,7 @@ DEFINE_EXPECT(Navigate); DEFINE_EXPECT(OnFrameWindowActivate); DEFINE_EXPECT(OnChanged_READYSTATE); DEFINE_EXPECT(OnChanged_1005); +DEFINE_EXPECT(OnChanged_1012); DEFINE_EXPECT(GetDisplayName); DEFINE_EXPECT(BindToStorage); DEFINE_EXPECT(IsSystemMoniker); @@ -136,14 +143,20 @@ DEFINE_EXPECT(RequestUIActivate); DEFINE_EXPECT(InPlaceFrame_SetBorderSpace); DEFINE_EXPECT(InPlaceUIWindow_SetActiveObject); DEFINE_EXPECT(GetExternal); +DEFINE_EXPECT(EnableModeless_TRUE); +DEFINE_EXPECT(EnableModeless_FALSE); +DEFINE_EXPECT(Frame_EnableModeless_TRUE); +DEFINE_EXPECT(Frame_EnableModeless_FALSE); +DEFINE_EXPECT(Frame_GetWindow); static IUnknown *doc_unk; +static IMoniker *doc_mon; static BOOL expect_LockContainer_fLock; static BOOL expect_InPlaceUIWindow_SetActiveObject_active = TRUE; static BOOL ipsex; static BOOL set_clientsite = FALSE, container_locked = FALSE; -static BOOL readystate_set_loading = FALSE, load_from_stream; -static BOOL editmode = FALSE; +static BOOL readystate_set_loading = FALSE, readystate_set_interactive = FALSE, load_from_stream; +static BOOL editmode = FALSE, show_failed; static int stream_read, protocol_read; static enum load_state_t { LD_DOLOAD, @@ -174,8 +187,6 @@ static BOOL nogecko = FALSE; #define test_readyState(u) _test_readyState(__LINE__,u) static void _test_readyState(unsigned,IUnknown*); -static void test_GetCurMoniker(IUnknown*,IMoniker*,LPCWSTR); - static const WCHAR wszTimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0}; static const WCHAR wszArial[] = @@ -193,15 +204,17 @@ static const char *debugstr_guid(REFIID riid) return buf; } -static const char *debugstr_w(LPCWSTR str) +static int strcmp_wa(LPCWSTR strw, const char *stra) { - static char buf[1024]; + CHAR buf[512]; + WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); + return lstrcmpA(stra, buf); +} - if(!str) - return "(null)"; - - WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); - return buf; +static BOOL is_english(void) +{ + return PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH + && PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH; } #define EXPECT_UPDATEUI 1 @@ -233,6 +246,75 @@ static void test_timer(DWORD flags) CHECK_CALLED(Exec_SETTITLE); } +static IMoniker Moniker; + +#define test_GetCurMoniker(u,m,v) _test_GetCurMoniker(__LINE__,u,m,v) +static void _test_GetCurMoniker(unsigned line, IUnknown *unk, IMoniker *exmon, LPCWSTR exurl) +{ + IHTMLDocument2 *doc; + IPersistMoniker *permon; + IMoniker *mon = (void*)0xdeadbeef; + BSTR doc_url = (void*)0xdeadbeef; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IPersistMoniker, (void**)&permon); + ok(hres == S_OK, "QueryInterface(IID_IPersistMoniker) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLDocument2, (void**)&doc); + ok(hres == S_OK, "QueryInterface(IID_IHTMLDocument2) failed: %08x\n", hres); + + hres = IHTMLDocument2_get_URL(doc, &doc_url); + ok(hres == S_OK, "get_URL failed: %08x\n", hres); + + hres = IPersistMoniker_GetCurMoniker(permon, &mon); + IPersistMoniker_Release(permon); + + if(exmon) { + LPOLESTR url; + BOOL exb = expect_GetDisplayName; + BOOL clb = called_GetDisplayName; + + ok_(__FILE__,line)(hres == S_OK, "GetCurrentMoniker failed: %08x\n", hres); + ok_(__FILE__,line)(mon == exmon, "mon(%p) != exmon(%p)\n", mon, exmon); + + if(mon == &Moniker) + SET_EXPECT(GetDisplayName); + hres = IMoniker_GetDisplayName(mon, NULL, NULL, &url); + ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres); + if(mon == &Moniker) + CHECK_CALLED(GetDisplayName); + expect_GetDisplayName = exb; + called_GetDisplayName = clb; + + ok(!lstrcmpW(url, doc_url), "url != doc_url\n"); + CoTaskMemFree(url); + }else if(exurl) { + LPOLESTR url; + + ok(hres == S_OK, "GetCurrentMoniker failed: %08x\n", hres); + + hres = IMoniker_GetDisplayName(mon, NULL, NULL, &url); + ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres); + + ok(!lstrcmpW(url, exurl), "unexpected url\n"); + ok(!lstrcmpW(url, doc_url), "url != doc_url\n"); + + CoTaskMemFree(url); + }else { + ok(hres == E_UNEXPECTED, + "GetCurrentMoniker failed: %08x, expected E_UNEXPECTED\n", hres); + ok(mon == (IMoniker*)0xdeadbeef, "mon=%p\n", mon); + ok(!lstrcmpW(doc_url, about_blank_url), "doc_url is not about:blank\n"); + } + + SysFreeString(doc_url); + IHTMLDocument_Release(doc); + if(mon && mon != (void*)0xdeadbeef) + IMoniker_Release(mon); +} + DEFINE_GUID(IID_External_unk,0x30510406,0x98B5,0x11CF,0xBB,0x82,0x00,0xAA,0x00,0xBD,0xCE,0x0B); static HRESULT WINAPI External_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) @@ -328,7 +410,7 @@ static ULONG WINAPI Protocol_Release(IInternetProtocol *iface) static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, - DWORD grfPI, DWORD dwReserved) + DWORD grfPI, HANDLE_PTR dwReserved) { BINDINFO bindinfo; DWORD bindf = 0; @@ -342,7 +424,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, ok(pOIProtSink != NULL, "pOIProtSink == NULL\n"); ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n"); ok(!grfPI, "grfPI = %x\n", grfPI); - ok(!dwReserved, "dwReserved = %d\n", dwReserved); + ok(!dwReserved, "dwReserved = %lx\n", dwReserved); memset(&bindinfo, 0, sizeof(bindinfo)); bindinfo.cbSize = sizeof(bindinfo); @@ -641,6 +723,12 @@ static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, D switch(dispID) { case DISPID_READYSTATE: CHECK_EXPECT2(OnChanged_READYSTATE); + + if(readystate_set_interactive) { + readystate_set_interactive = FALSE; + load_state = LD_INTERACTIVE; + } + else test_MSHTML_QueryStatus(NULL, OLECMDF_SUPPORTED | (editmode && (load_state == LD_INTERACTIVE || load_state == LD_COMPLETE) ? OLECMDF_ENABLED : 0)); @@ -649,12 +737,21 @@ static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, D readystate_set_loading = FALSE; load_state = LD_LOADING; } + if(!editmode || load_state != LD_LOADING || !called_Exec_Explorer_69) test_readyState(NULL); return S_OK; case 1005: CHECK_EXPECT(OnChanged_1005); + if(!editmode) test_readyState(NULL); - load_state = LD_INTERACTIVE; + readystate_set_interactive = (load_state != LD_INTERACTIVE); + return S_OK; + case 1012: + CHECK_EXPECT(OnChanged_1012); + return S_OK; + case 3000029: + case 3000030: + /* TODO */ return S_OK; } @@ -1007,8 +1104,10 @@ static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMon BINDSTATUS_ENDDOWNLOADDATA, NULL); ok(hres == S_OK, "OnProgress(BINDSTATUS_ENDDOWNLOADDATA) failed: %08x\n", hres); + SET_EXPECT(GetBindResult); hres = IBindStatusCallback_OnStopBinding(callback, S_OK, NULL); ok(hres == S_OK, "OnStopBinding failed: %08x\n", hres); + SET_CALLED(GetBindResult); /* IE7 */ IBindStatusCallback_Release(callback); @@ -1186,7 +1285,12 @@ static IOleContainer OleContainer = { &OleContainerVtbl }; static HRESULT WINAPI InPlaceFrame_QueryInterface(IOleInPlaceFrame *iface, REFIID riid, void **ppv) { - ok(0, "unexpected call\n"); + static const GUID undocumented_frame_iid = {0xfbece6c9,0x48d7,0x4a37,{0x8f,0xe3,0x6a,0xd4,0x27,0x2f,0xdd,0xac}}; + + if(!IsEqualGUID(&undocumented_frame_iid, riid)) + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); + + *ppv = NULL; return E_NOINTERFACE; } @@ -1202,7 +1306,7 @@ static ULONG WINAPI InPlaceFrame_Release(IOleInPlaceFrame *iface) static HRESULT WINAPI InPlaceFrame_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd) { - ok(0, "unexpected call\n"); + CHECK_EXPECT(Frame_GetWindow); return E_NOTIMPL; } @@ -1242,7 +1346,7 @@ static HRESULT WINAPI InPlaceUIWindow_SetActiveObject(IOleInPlaceFrame *iface, if(expect_InPlaceUIWindow_SetActiveObject_active) { ok(pActiveObject != NULL, "pActiveObject = NULL\n"); - if(pActiveObject && PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) + if(pActiveObject && is_english()) ok(!lstrcmpW(wszHTML_Document, pszObjName), "pszObjName != \"HTML Document\"\n"); } else { @@ -1262,7 +1366,7 @@ static HRESULT WINAPI InPlaceFrame_SetActiveObject(IOleInPlaceFrame *iface, if(pActiveObject) { CHECK_EXPECT2(SetActiveObject); - if(pActiveObject && PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH) + if(pActiveObject && is_english()) ok(!lstrcmpW(wszHTML_Document, pszObjName), "pszObjName != \"HTML Document\"\n"); }else { CHECK_EXPECT(SetActiveObject_null); @@ -1304,7 +1408,10 @@ static HRESULT WINAPI InPlaceFrame_SetStatusText(IOleInPlaceFrame *iface, LPCOLE static HRESULT WINAPI InPlaceFrame_EnableModeless(IOleInPlaceFrame *iface, BOOL fEnable) { - ok(0, "unexpected call\n"); + if(fEnable) + CHECK_EXPECT2(Frame_EnableModeless_TRUE); + else + CHECK_EXPECT2(Frame_EnableModeless_FALSE); return E_NOTIMPL; } @@ -1365,7 +1472,7 @@ static ULONG WINAPI InPlaceSite_Release(IOleInPlaceSiteEx *iface) static HRESULT WINAPI InPlaceSite_GetWindow(IOleInPlaceSiteEx *iface, HWND *phwnd) { - CHECK_EXPECT(GetWindow); + CHECK_EXPECT2(GetWindow); ok(phwnd != NULL, "phwnd = NULL\n"); *phwnd = container_hwnd; return S_OK; @@ -1664,11 +1771,6 @@ static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocum expect_status_text = NULL; hres = IOleDocumentView_UIActivate(view, TRUE); - - if(FAILED(hres)) { - skip("UIActivate failed: %08x\n", hres); - return hres; - } ok(hres == S_OK, "UIActivate failed: %08x\n", hres); CHECK_CALLED(CanInPlaceActivate); @@ -1724,6 +1826,14 @@ static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocum expect_status_text = (load_state == LD_COMPLETE ? (LPCOLESTR)0xdeadbeef : NULL); hres = IOleDocumentView_Show(view, TRUE); + if(FAILED(hres)) { + win_skip("Show failed\n"); + if(activeobj) + IOleInPlaceActiveObject_Release(activeobj); + IOleDocument_Release(document); + show_failed = TRUE; + return S_OK; + } ok(hres == S_OK, "Show failed: %08x\n", hres); CHECK_CALLED(CanInPlaceActivate); @@ -1918,7 +2028,10 @@ static HRESULT WINAPI DocHostUIHandler_UpdateUI(IDocHostUIHandler2 *iface) static HRESULT WINAPI DocHostUIHandler_EnableModeless(IDocHostUIHandler2 *iface, BOOL fEnable) { - ok(0, "unexpected call\n"); + if(fEnable) + CHECK_EXPECT2(EnableModeless_TRUE); + else + CHECK_EXPECT2(EnableModeless_FALSE); return E_NOTIMPL; } @@ -2118,6 +2231,7 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID break; case 1: CHECK_EXPECT(Exec_SETDOWNLOADSTATE_1); + readystate_set_interactive = (load_state != LD_INTERACTIVE); break; default: ok(0, "unexpevted V_I4(pvaIn)=%d\n", V_I4(pvaIn)); @@ -2140,8 +2254,12 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID return S_OK; case OLECMDID_HTTPEQUIV: CHECK_EXPECT2(Exec_HTTPEQUIV); - ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER, "nCmdexecopts=%08x\n", nCmdexecopt); - /* TODO */ + ok(!nCmdexecopt, "nCmdexecopts=%08x\n", nCmdexecopt); + ok(pvaIn != NULL, "pvaIn == NULL\n"); + ok(pvaOut == NULL, "pvaOut=%p\n", pvaOut); + ok(V_VT(pvaIn) == VT_BSTR, "V_VT(pvaIn)=%d\n", V_VT(pvaIn)); + ok(V_BSTR(pvaIn) != NULL, "V_BSTR(pvaIn) = NULL\n"); + test_readyState(NULL); return S_OK; default: ok(0, "unexpected command %d\n", nCmdID); @@ -2159,7 +2277,7 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID if(load_from_stream) test_GetCurMoniker(doc_unk, NULL, about_blank_url); else if(!editmode) - test_GetCurMoniker(doc_unk, &Moniker, NULL); + test_GetCurMoniker(doc_unk, doc_mon, NULL); ok(pvaOut == NULL, "pvaOut=%p, expected NULL\n", pvaOut); ok(pvaIn != NULL, "pvaIn == NULL\n"); @@ -2186,6 +2304,22 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID return E_NOTIMPL; + case 105: + CHECK_EXPECT2(Exec_ShellDocView_105); + + ok(pvaIn != NULL, "pvaIn == NULL\n"); + ok(pvaOut == NULL, "pvaOut != NULL\n"); + + return E_NOTIMPL; + + case 140: + CHECK_EXPECT2(Exec_ShellDocView_140); + + ok(pvaIn == NULL, "pvaIn != NULL\n"); + ok(pvaOut == NULL, "pvaOut != NULL\n"); + + return E_NOTIMPL; + default: ok(0, "unexpected command %d\n", nCmdID); return E_FAIL; @@ -2231,6 +2365,9 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID ok(pvaIn == NULL, "pvaIn != NULL\n"); ok(pvaOut == NULL, "pvaOut != NULL\n"); return S_OK; + case OLECMDID_SHOWSCRIPTERROR: + /* TODO */ + return S_OK; default: ok(0, "unexpected command %d\n", nCmdID); return E_FAIL; @@ -2372,8 +2509,10 @@ static const IServiceProviderVtbl ServiceProviderVtbl = { static IServiceProvider ServiceProvider = { &ServiceProviderVtbl }; DEFINE_GUID(IID_unk1, 0xD48A6EC6,0x6A4A,0x11CF,0x94,0xA7,0x44,0x45,0x53,0x54,0x00,0x00); /* HTMLWindow2 ? */ -DEFINE_GUID(IID_unk2, 0x7BB0B520,0xB1A7,0x11D2,0xBB,0x23,0x00,0xC0,0x4F,0x79,0xAB,0xCD); -DEFINE_GUID(IID_unk3, 0x000670BA,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +DEFINE_GUID(IID_IThumbnailView, 0x7BB0B520,0xB1A7,0x11D2,0xBB,0x23,0x00,0xC0,0x4F,0x79,0xAB,0xCD); +DEFINE_GUID(IID_IRenMailEditor, 0x000670BA,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +DEFINE_GUID(IID_unk4, 0x305104a6,0x98b5,0x11cf,0xbb,0x82,0x00,0xaa,0x00,0xbd,0xce,0x0b); +DEFINE_GUID(IID_IDocHostUIHandlerPriv, 0xf0d241d1,0x5d0e,0x4e85,0xbc,0xb4,0xfa,0xd7,0xf7,0xc5,0x52,0x8c); static HRESULT QueryInterface(REFIID riid, void **ppv) { @@ -2405,9 +2544,13 @@ static HRESULT QueryInterface(REFIID riid, void **ppv) return E_NOINTERFACE; /* ? */ else if(IsEqualGUID(&IID_unk1, riid)) return E_NOINTERFACE; /* HTMLWindow2 ? */ - else if(IsEqualGUID(&IID_unk2, riid)) + else if(IsEqualGUID(&IID_IThumbnailView, riid)) return E_NOINTERFACE; /* ? */ - else if(IsEqualGUID(&IID_unk3, riid)) + else if(IsEqualGUID(&IID_IRenMailEditor, riid)) + return E_NOINTERFACE; /* ? */ + else if(IsEqualGUID(&IID_unk4, riid)) + return E_NOINTERFACE; /* ? */ + else if(IsEqualGUID(&IID_IDocHostUIHandlerPriv, riid)) return E_NOINTERFACE; /* ? */ else ok(0, "unexpected riid %s\n", debugstr_guid(riid)); @@ -2430,18 +2573,13 @@ static void _test_readyState(unsigned line, IUnknown *unk) VARIANT out; HRESULT hres; - static const WCHAR wszUninitialized[] = {'u','n','i','n','i','t','i','a','l','i','z','e','d',0}; - static const WCHAR wszLoading[] = {'l','o','a','d','i','n','g',0}; - static const WCHAR wszInteractive[] = {'i','n','t','e','r','a','c','t','i','v','e',0}; - static const WCHAR wszComplete[] = {'c','o','m','p','l','e','t','e',0}; - - static const LPCWSTR expected_state[] = { - wszUninitialized, - wszLoading, + static const LPCSTR expected_state[] = { + "uninitialized", + "loading", NULL, - wszInteractive, - wszComplete, - wszUninitialized + "interactive", + "complete", + "uninitialized" }; if(!unk) @@ -2457,9 +2595,13 @@ static void _test_readyState(unsigned line, IUnknown *unk) hres = IHTMLDocument2_get_readyState(htmldoc, &state); ok(hres == S_OK, "get_ReadyState failed: %08x\n", hres); + + if(!strcmp_wa(state, "interactive") && load_state == LD_LOADING) + load_state = LD_INTERACTIVE; + ok_(__FILE__, line) - (!lstrcmpW(state, expected_state[load_state]), "unexpected state \"%s\", expected %d\n", - debugstr_w(state), load_state); + (!strcmp_wa(state, expected_state[load_state]), "unexpected state %s, expected %d\n", + wine_dbgstr_w(state), load_state); SysFreeString(state); dispparams.cArgs = 0; @@ -2534,71 +2676,7 @@ static void test_ConnectionPointContainer(IUnknown *unk) IConnectionPointContainer_Release(container); } -static void test_GetCurMoniker(IUnknown *unk, IMoniker *exmon, LPCWSTR exurl) -{ - IHTMLDocument2 *doc; - IPersistMoniker *permon; - IMoniker *mon = (void*)0xdeadbeef; - BSTR doc_url = (void*)0xdeadbeef; - HRESULT hres; - - hres = IUnknown_QueryInterface(unk, &IID_IPersistMoniker, (void**)&permon); - ok(hres == S_OK, "QueryInterface(IID_IPersistMoniker) failed: %08x\n", hres); - if(FAILED(hres)) - return; - - hres = IUnknown_QueryInterface(unk, &IID_IHTMLDocument2, (void**)&doc); - ok(hres == S_OK, "QueryInterface(IID_IHTMLDocument2) failed: %08x\n", hres); - - hres = IHTMLDocument2_get_URL(doc, &doc_url); - ok(hres == S_OK, "get_URL failed: %08x\n", hres); - - hres = IPersistMoniker_GetCurMoniker(permon, &mon); - IPersistMoniker_Release(permon); - - if(exmon) { - LPOLESTR url; - BOOL exb = expect_GetDisplayName; - BOOL clb = called_GetDisplayName; - - ok(hres == S_OK, "GetCurrentMoniker failed: %08x\n", hres); - ok(mon == exmon, "mon(%p) != exmon(%p)\n", mon, exmon); - - SET_EXPECT(GetDisplayName); - hres = IMoniker_GetDisplayName(mon, NULL, NULL, &url); - ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres); - CHECK_CALLED(GetDisplayName); - expect_GetDisplayName = exb; - called_GetDisplayName = clb; - - ok(!lstrcmpW(url, doc_url), "url != doc_url\n"); - CoTaskMemFree(url); - }else if(exurl) { - LPOLESTR url; - - ok(hres == S_OK, "GetCurrentMoniker failed: %08x\n", hres); - - hres = IMoniker_GetDisplayName(mon, NULL, NULL, &url); - ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres); - - ok(!lstrcmpW(url, exurl), "unexpected url\n"); - ok(!lstrcmpW(url, doc_url), "url != doc_url\n"); - - CoTaskMemFree(url); - }else { - ok(hres == E_UNEXPECTED, - "GetCurrentMoniker failed: %08x, expected E_UNEXPECTED\n", hres); - ok(mon == (IMoniker*)0xdeadbeef, "mon=%p\n", mon); - ok(!lstrcmpW(doc_url, about_blank_url), "doc_url is not about:blank\n"); - } - - SysFreeString(doc_url); - IHTMLDocument_Release(doc); - if(mon && mon != (void*)0xdeadbeef) - IMoniker_Release(mon); -} - -static void test_Load(IPersistMoniker *persist) +static void test_Load(IPersistMoniker *persist, IMoniker *mon) { IBindCtx *bind; HRESULT hres; @@ -2608,10 +2686,13 @@ static void test_Load(IPersistMoniker *persist) test_readyState((IUnknown*)persist); + doc_mon = mon; + CreateBindCtx(0, &bind); IBindCtx_RegisterObjectParam(bind, sz_html_clientsite_objectparam, (IUnknown*)&ClientSite); + if(mon == &Moniker) SET_EXPECT(GetDisplayName); if(!set_clientsite) { SET_EXPECT(Invoke_AMBIENT_USERMODE); @@ -2635,6 +2716,8 @@ static void test_Load(IPersistMoniker *persist) } SET_EXPECT(OnChanged_READYSTATE); SET_EXPECT(Exec_ShellDocView_84); + SET_EXPECT(IsSystemMoniker); + if(mon == &Moniker) SET_EXPECT(BindToStorage); SET_EXPECT(SetActiveObject); if(set_clientsite) { @@ -2646,9 +2729,10 @@ static void test_Load(IPersistMoniker *persist) expect_LockContainer_fLock = TRUE; readystate_set_loading = TRUE; - hres = IPersistMoniker_Load(persist, FALSE, &Moniker, bind, 0x12); + hres = IPersistMoniker_Load(persist, FALSE, mon, bind, 0x12); ok(hres == S_OK, "Load failed: %08x\n", hres); + if(mon == &Moniker) CHECK_CALLED(GetDisplayName); if(!set_clientsite) { CHECK_CALLED(Invoke_AMBIENT_USERMODE); @@ -2672,7 +2756,9 @@ static void test_Load(IPersistMoniker *persist) container_locked = TRUE; } CHECK_CALLED(OnChanged_READYSTATE); + SET_CALLED(IsSystemMoniker); /* IE7 */ SET_CALLED(Exec_ShellDocView_84); + if(mon == &Moniker) CHECK_CALLED(BindToStorage); SET_CALLED(SetActiveObject); /* FIXME */ if(set_clientsite) { @@ -2683,14 +2769,19 @@ static void test_Load(IPersistMoniker *persist) set_clientsite = container_locked = TRUE; - test_GetCurMoniker((IUnknown*)persist, &Moniker, NULL); + test_GetCurMoniker((IUnknown*)persist, mon, NULL); IBindCtx_Release(bind); test_readyState((IUnknown*)persist); } -static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) +#define DWL_VERBDONE 0x0001 +#define DWL_CSS 0x0002 +#define DWL_TRYCSS 0x0004 +#define DWL_HTTP 0x0008 + +static void test_download(DWORD flags) { HWND hwnd; MSG msg; @@ -2700,17 +2791,16 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) test_readyState(NULL); - if(verb_done) { + if(flags & (DWL_VERBDONE|DWL_HTTP)) SET_EXPECT(Exec_SETPROGRESSMAX); - if(!load_from_stream) + if((flags & DWL_VERBDONE) && !load_from_stream) SET_EXPECT(GetHostInfo); - } SET_EXPECT(SetStatusText); SET_EXPECT(Exec_SETDOWNLOADSTATE_1); SET_EXPECT(GetDropTarget); - if(css_try_dwl) + if(flags & DWL_TRYCSS) SET_EXPECT(Exec_ShellDocView_84); - if(css_dwl) { + if(flags & DWL_CSS) { SET_EXPECT(CreateInstance); SET_EXPECT(Start); SET_EXPECT(LockRequest); @@ -2719,13 +2809,25 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) SET_EXPECT(UnlockRequest); } SET_EXPECT(Exec_Explorer_69); + SET_EXPECT(EnableModeless_TRUE); /* IE7 */ + SET_EXPECT(Frame_EnableModeless_TRUE); /* IE7 */ + SET_EXPECT(EnableModeless_FALSE); /* IE7 */ + SET_EXPECT(Frame_EnableModeless_FALSE); /* IE7 */ + if(doc_mon != &Moniker) { + SET_EXPECT(OnChanged_1012); + SET_EXPECT(Exec_HTTPEQUIV); + SET_EXPECT(Exec_SETTITLE); + } SET_EXPECT(OnChanged_1005); SET_EXPECT(OnChanged_READYSTATE); SET_EXPECT(Exec_SETPROGRESSPOS); SET_EXPECT(Exec_SETDOWNLOADSTATE_0); SET_EXPECT(Exec_ShellDocView_103); + SET_EXPECT(Exec_ShellDocView_105); + SET_EXPECT(Exec_ShellDocView_140); SET_EXPECT(Exec_MSHTML_PARSECOMPLETE); SET_EXPECT(Exec_HTTPEQUIV_DONE); + SET_EXPECT(SetStatusText); expect_status_text = (LPWSTR)0xdeadbeef; /* TODO */ while(!called_Exec_HTTPEQUIV_DONE && GetMessage(&msg, NULL, 0, 0)) { @@ -2733,17 +2835,18 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) DispatchMessage(&msg); } - if(verb_done) { + if(flags & DWL_VERBDONE) CHECK_CALLED(Exec_SETPROGRESSMAX); - if(!load_from_stream) + if(flags & DWL_HTTP) + SET_CALLED(Exec_SETPROGRESSMAX); + if((flags & DWL_VERBDONE) && !load_from_stream) CHECK_CALLED(GetHostInfo); - } CHECK_CALLED(SetStatusText); CHECK_CALLED(Exec_SETDOWNLOADSTATE_1); CHECK_CALLED(GetDropTarget); - if(css_try_dwl) + if(flags & DWL_TRYCSS) SET_CALLED(Exec_ShellDocView_84); - if(css_dwl) { + if(flags & DWL_CSS) { if(called_CreateInstance) { CHECK_CALLED(CreateInstance); CHECK_CALLED(Start); @@ -2766,20 +2869,32 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) } } SET_CALLED(Exec_Explorer_69); + SET_CALLED(EnableModeless_TRUE); /* IE7 */ + SET_CALLED(Frame_EnableModeless_TRUE); /* IE7 */ + SET_CALLED(EnableModeless_FALSE); /* IE7 */ + SET_CALLED(Frame_EnableModeless_FALSE); /* IE7 */ + if(doc_mon != &Moniker) todo_wine { + CHECK_CALLED(OnChanged_1012); + CHECK_CALLED(Exec_HTTPEQUIV); + CHECK_CALLED(Exec_SETTITLE); + } CHECK_CALLED(OnChanged_1005); CHECK_CALLED(OnChanged_READYSTATE); CHECK_CALLED(Exec_SETPROGRESSPOS); CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); SET_CALLED(Exec_ShellDocView_103); + SET_CALLED(Exec_ShellDocView_105); + SET_CALLED(Exec_ShellDocView_140); CHECK_CALLED(Exec_MSHTML_PARSECOMPLETE); CHECK_CALLED(Exec_HTTPEQUIV_DONE); + SET_CALLED(SetStatusText); load_state = LD_COMPLETE; test_readyState(NULL); } -static void test_Persist(IUnknown *unk) +static void test_Persist(IUnknown *unk, IMoniker *mon) { IPersistMoniker *persist_mon; IPersistFile *persist_file; @@ -2810,7 +2925,7 @@ static void test_Persist(IUnknown *unk) ok(IsEqualGUID(&CLSID_HTMLDocument, &guid), "guid != CLSID_HTMLDocument\n"); if(load_state == LD_DOLOAD) - test_Load(persist_mon); + test_Load(persist_mon, mon); test_readyState(unk); @@ -3044,6 +3159,7 @@ static void test_exec_editmode(IUnknown *unk, BOOL loaded) SET_EXPECT(Invoke_AMBIENT_SILENT); SET_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); SET_EXPECT(OnChanged_READYSTATE); + SET_EXPECT(IsSystemMoniker); SET_EXPECT(Exec_ShellDocView_84); if(loaded) SET_EXPECT(BindToStorage); @@ -3069,6 +3185,7 @@ static void test_exec_editmode(IUnknown *unk, BOOL loaded) CHECK_CALLED(Invoke_AMBIENT_SILENT); CHECK_CALLED(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); CHECK_CALLED(OnChanged_READYSTATE); + SET_CALLED(IsSystemMoniker); /* IE7 */ SET_CALLED(Exec_ShellDocView_84); if(loaded) CHECK_CALLED(BindToStorage); @@ -3121,7 +3238,7 @@ static void test_exec_fontname(IUnknown *unk, LPCWSTR name, LPCWSTR exname) if(V_VT(out) == VT_BSTR) { if(exname) ok(!lstrcmpW(V_BSTR(out), name ? name : exname), - "unexpected fontname \"%s\"\n", debugstr_w(name)); + "unexpected fontname %s\n", wine_dbgstr_w(name)); else ok(V_BSTR(out) == NULL, "V_BSTR(out) != NULL\n"); } @@ -3199,7 +3316,7 @@ static HWND create_container_window(void) 515, 530, NULL, NULL, NULL, NULL); } -static HRESULT test_DoVerb(IOleObject *oleobj) +static void test_DoVerb(IOleObject *oleobj) { RECT rect = {0,0,500,500}; HRESULT hres; @@ -3212,8 +3329,6 @@ static HRESULT test_DoVerb(IOleObject *oleobj) expect_LockContainer_fLock = TRUE; hres = IOleObject_DoVerb(oleobj, OLEIVERB_SHOW, NULL, &ClientSite, -1, container_hwnd, &rect); - if(FAILED(hres)) - return hres; ok(hres == S_OK, "DoVerb failed: %08x\n", hres); if(!container_locked) { @@ -3222,8 +3337,6 @@ static HRESULT test_DoVerb(IOleObject *oleobj) container_locked = TRUE; } CHECK_CALLED(ActivateMe); - - return hres; } #define CLIENTSITE_EXPECTPATH 0x00000001 @@ -3465,7 +3578,7 @@ static void test_InPlaceDeactivate(IUnknown *unk, BOOL expect_call) IOleInPlaceObjectWindowless_Release(windowlessobj); } -static HRESULT test_Activate(IUnknown *unk, DWORD flags) +static void test_Activate(IUnknown *unk, DWORD flags) { IOleObject *oleobj = NULL; IOleDocumentView *docview; @@ -3480,8 +3593,6 @@ static HRESULT test_Activate(IUnknown *unk, DWORD flags) hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj); ok(hres == S_OK, "QueryInterface(IID_IOleObject) failed: %08x\n", hres); - if(FAILED(hres)) - return hres; hres = IOleObject_GetUserClassID(oleobj, NULL); ok(hres == E_INVALIDARG, "GetUserClassID returned: %08x, expected E_INVALIDARG\n", hres); @@ -3494,8 +3605,7 @@ static HRESULT test_Activate(IUnknown *unk, DWORD flags) test_ClientSite(oleobj, flags); test_InPlaceDeactivate(unk, FALSE); - - hres = test_DoVerb(oleobj); + test_DoVerb(oleobj); if(call_UIActivate == CallUIActivate_AfterShow) { hres = IOleObject_QueryInterface(oleobj, &IID_IOleDocumentView, (void **)&docview); @@ -3523,8 +3633,6 @@ static HRESULT test_Activate(IUnknown *unk, DWORD flags) IOleObject_Release(oleobj); test_OnFrameWindowActivate(unk); - - return hres; } static void test_Window(IUnknown *unk, BOOL expect_success) @@ -3612,9 +3720,23 @@ static void test_Hide(void) static HRESULT create_document(IUnknown **unk) { - HRESULT hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + IHTMLDocument5 *doc5; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void**)unk); ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); + if(FAILED(hres)) + return hres; + + hres = IUnknown_QueryInterface(*unk, &IID_IHTMLDocument5, (void**)&doc5); + if(SUCCEEDED(hres)) { + IHTMLDocument5_Release(doc5); + }else { + win_skip("Could not get IHTMLDocument5, probably too old IE\n"); + IUnknown_Release(*unk); +} + return hres; } @@ -3707,27 +3829,32 @@ static void test_QueryInterface(IUnknown *unk) qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qirunnable=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qirunnable=%p, expected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode2, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IPersistPropertyBag, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_UndocumentedScriptIface, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); + + qi = (void*)0xdeadbeef; + hres = IUnknown_QueryInterface(unk, &IID_IMarshal, (void**)&qi); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); } static void init_test(enum load_state_t ls) { @@ -3764,18 +3891,14 @@ static void test_HTMLDocument(BOOL do_load) test_external(unk, FALSE); test_ConnectionPointContainer(unk); test_GetCurMoniker(unk, NULL, NULL); - test_Persist(unk); + test_Persist(unk, &Moniker); if(!do_load) test_OnAmbientPropertyChange2(unk); - hres = test_Activate(unk, CLIENTSITE_EXPECTPATH); - if(FAILED(hres)) { - IUnknown_Release(unk); - return; - } + test_Activate(unk, CLIENTSITE_EXPECTPATH); if(do_load) { - test_download(FALSE, TRUE, TRUE); + test_download(DWL_CSS|DWL_TRYCSS); test_GetCurMoniker(unk, &Moniker, NULL); } @@ -3863,10 +3986,14 @@ static void test_HTMLDocument_hlink(void) test_ConnectionPointContainer(unk); test_GetCurMoniker(unk, NULL, NULL); - test_Persist(unk); + test_Persist(unk, &Moniker); test_Navigate(unk); + if(show_failed) { + IUnknown_Release(unk); + return; + } - test_download(FALSE, TRUE, TRUE); + test_download(DWL_CSS|DWL_TRYCSS); test_IsDirty(unk, S_FALSE); test_MSHTML_QueryStatus(unk, OLECMDF_SUPPORTED); @@ -3886,6 +4013,62 @@ static void test_HTMLDocument_hlink(void) ok(ref == 0, "ref=%d, expected 0\n", ref); } +static void test_HTMLDocument_http(void) +{ + IMoniker *http_mon; + IUnknown *unk; + ULONG ref; + HRESULT hres; + + static const WCHAR http_urlW[] = + {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; + + trace("Testing HTMLDocument (http)...\n"); + + hres = CreateURLMoniker(NULL, http_urlW, &http_mon); + ok(hres == S_OK, "CreateURLMoniker failed: %08x\n", hres); + + init_test(LD_DOLOAD); + ipsex = TRUE; + + hres = create_document(&unk); + if(FAILED(hres)) + return; + doc_unk = unk; + + test_ConnectionPointContainer(unk); + test_GetCurMoniker(unk, NULL, NULL); + test_Persist(unk, http_mon); + test_Navigate(unk); + if(show_failed) { + IUnknown_Release(unk); + return; + } + + if (winetest_interactive || ! is_ie_hardened()) + test_download(DWL_HTTP); + else + win_skip("IE running in Enhanced Security Configuration\n"); + + test_IsDirty(unk, S_FALSE); + test_MSHTML_QueryStatus(unk, OLECMDF_SUPPORTED); + + test_InPlaceDeactivate(unk, TRUE); + test_Close(unk, FALSE); + test_IsDirty(unk, S_FALSE); + test_GetCurMoniker(unk, http_mon, NULL); + + if(view) + IOleDocumentView_Release(view); + view = NULL; + + ref = IUnknown_Release(unk); + ok(!ref, "ref=%d, expected 0\n", ref); + + ref = IMoniker_Release(http_mon); + ok(!ref, "ref=%d, expected 0\n", ref); +} + static void test_HTMLDocument_StreamLoad(void) { IOleObject *oleobj; @@ -3917,7 +4100,7 @@ static void test_HTMLDocument_StreamLoad(void) test_GetCurMoniker(unk, NULL, NULL); test_StreamLoad(unk); - test_download(TRUE, FALSE, TRUE); + test_download(DWL_VERBDONE|DWL_TRYCSS); test_MSHTML_QueryStatus(unk, OLECMDF_SUPPORTED); test_UIDeactivate(); @@ -3990,7 +4173,7 @@ static void test_editing_mode(BOOL do_load) test_MSHTML_QueryStatus(unk, OLECMDF_SUPPORTED); if(do_load) - test_Persist(unk); + test_Persist(unk, &Moniker); stream_read = protocol_read = 0; test_exec_editmode(unk, do_load); test_UIDeactivate(); @@ -3998,8 +4181,12 @@ static void test_editing_mode(BOOL do_load) IOleObject_Release(oleobj); test_MSHTML_QueryStatus(unk, OLECMDF_SUPPORTED); - test_download(TRUE, do_load, do_load); + test_download(DWL_VERBDONE | (do_load ? DWL_CSS|DWL_TRYCSS : 0)); + + SET_EXPECT(SetStatusText); /* ignore race in native mshtml */ test_timer(EXPECT_UPDATEUI); + SET_CALLED(SetStatusText); + test_MSHTML_QueryStatus(unk, OLECMDF_SUPPORTED|OLECMDF_ENABLED); if(!do_load) { @@ -4088,6 +4275,51 @@ static void gecko_installer_workaround(BOOL disable) RegCloseKey(hkey); } +static void test_HTMLDoc_ISupportErrorInfo(void) +{ + HRESULT hres; + IUnknown *unk; + ISupportErrorInfo *sinfo; + LONG ref; + + hres = create_document(&unk); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_ISupportErrorInfo, (void**)&sinfo); + ok(hres == S_OK, "got %x\n", hres); + ok(sinfo != NULL, "got %p\n", sinfo); + if(sinfo) + { + hres = ISupportErrorInfo_InterfaceSupportsErrorInfo(sinfo, &IID_IErrorInfo); + ok(hres == S_FALSE, "Expected S_OK, got %x\n", hres); + IUnknown_Release(sinfo); + } + + ref = IUnknown_Release(unk); + ok(ref == 0, "ref=%d, expected 0\n", ref); +} + +static void test_IPersistHistory(void) +{ + HRESULT hres; + IUnknown *unk; + LONG ref; + IPersistHistory *phist; + + hres = create_document(&unk); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IPersistHistory, (void**)&phist); + ok(hres == S_OK, "QueryInterface returned %08x, expected S_OK\n", hres); + if(hres == S_OK) + IPersistHistory_Release(phist); + + ref = IUnknown_Release(unk); + ok(ref == 0, "ref=%d, expected 0\n", ref); +} + START_TEST(htmldoc) { gecko_installer_workaround(TRUE); @@ -4096,12 +4328,17 @@ START_TEST(htmldoc) container_hwnd = create_container_window(); register_protocol(); + test_HTMLDocument_hlink(); + if(!show_failed) { test_HTMLDocument(FALSE); test_HTMLDocument(TRUE); - test_HTMLDocument_hlink(); test_HTMLDocument_StreamLoad(); test_editing_mode(FALSE); test_editing_mode(TRUE); + test_HTMLDocument_http(); + } + test_HTMLDoc_ISupportErrorInfo(); + test_IPersistHistory(); DestroyWindow(container_hwnd); CoUninitialize(); diff --git a/rostests/winetests/mshtml/misc.c b/rostests/winetests/mshtml/misc.c index 62c7e37901d..ed8de36b9a3 100644 --- a/rostests/winetests/mshtml/misc.c +++ b/rostests/winetests/mshtml/misc.c @@ -24,9 +24,8 @@ #include "windef.h" #include "winbase.h" #include "ole2.h" -#include "optary.h" - #include "initguid.h" +#include "optary.h" static void test_HTMLLoadOptions(void) { diff --git a/rostests/winetests/mshtml/mshtml.rbuild b/rostests/winetests/mshtml/mshtml.rbuild index af12a16e8c9..280dced8372 100644 --- a/rostests/winetests/mshtml/mshtml.rbuild +++ b/rostests/winetests/mshtml/mshtml.rbuild @@ -3,9 +3,9 @@ . - 0x600 - 0x600 + dom.c + events.c htmldoc.c misc.c protocol.c @@ -19,7 +19,6 @@ user32 urlmon advapi32 - kernel32 ntdll diff --git a/rostests/winetests/mshtml/mshtml_test.h b/rostests/winetests/mshtml/mshtml_test.h new file mode 100644 index 00000000000..7f2cdf2eef3 --- /dev/null +++ b/rostests/winetests/mshtml/mshtml_test.h @@ -0,0 +1,38 @@ +/* + * Copyright 2009 Ge van Geldorp for VMware, Inc. + * + * 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 + */ + +/* Check if Internet Explorer is configured to run in "Enhanced Security Configuration" (aka hardened mode) */ +/* Note: this code is duplicated in dlls/mshtml/tests/mshtml_test.h and dlls/urlmon/tests/sec_mgr.c */ +static BOOL is_ie_hardened(void) +{ + HKEY zone_map; + DWORD ie_harden, type, size; + + ie_harden = 0; + if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ZoneMap", + 0, KEY_QUERY_VALUE, &zone_map) == ERROR_SUCCESS) { + size = sizeof(DWORD); + if (RegQueryValueEx(zone_map, "IEHarden", NULL, &type, (LPBYTE) &ie_harden, &size) != ERROR_SUCCESS || + type != REG_DWORD) { + ie_harden = 0; + } + RegCloseKey(zone_map); + } + + return ie_harden != 0; +} diff --git a/rostests/winetests/mshtml/protocol.c b/rostests/winetests/mshtml/protocol.c index 4e8b3d0c79a..6902707d3df 100644 --- a/rostests/winetests/mshtml/protocol.c +++ b/rostests/winetests/mshtml/protocol.c @@ -20,6 +20,7 @@ #include #include +#include #include "windef.h" #include "winbase.h" @@ -56,6 +57,7 @@ DEFINE_GUID(CLSID_ResProtocol, 0x3050F3BC, 0x98B5, 0x11CF, 0xBB,0x82, 0x00,0xAA,0x00,0xBD,0xCE,0x0B); DEFINE_GUID(CLSID_AboutProtocol, 0x3050F406, 0x98B5, 0x11CF, 0xBB,0x82, 0x00,0xAA,0x00,0xBD,0xCE,0x0B); +DEFINE_GUID(CLSID_JSProtocol, 0x3050F3B2, 0x98B5, 0x11CF, 0xBB,0x82, 0x00,0xAA,0x00,0xBD,0xCE,0x0B); DEFINE_EXPECT(GetBindInfo); DEFINE_EXPECT(ReportProgress); @@ -69,11 +71,17 @@ static DWORD bindf; static const WCHAR about_blank_url[] = {'a','b','o','u','t',':','b','l','a','n','k',0}; static const WCHAR about_test_url[] = {'a','b','o','u','t',':','t','e','s','t',0}; static const WCHAR about_res_url[] = {'r','e','s',':','b','l','a','n','k',0}; +static const WCHAR javascript_test_url[] = {'j','a','v','a','s','c','r','i','p','t',':','t','e','s','t','(',')',0}; -static const char *debugstr_w(LPCWSTR str) +static const char *debugstr_guid(REFIID riid) { - static char buf[1024]; - WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); + static char buf[50]; + + sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], + riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4], + riid->Data4[5], riid->Data4[6], riid->Data4[7]); + return buf; } @@ -83,6 +91,9 @@ static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, *ppv = iface; return S_OK; } + + *ppv = NULL; + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } @@ -167,6 +178,9 @@ static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFIID r *ppv = iface; return S_OK; } + + *ppv = NULL; + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } @@ -266,15 +280,19 @@ static void res_sec_url_cmp(LPCWSTR url, DWORD size, LPCWSTR file) return; } + SetLastError(0xdeadbeef); len = SearchPathW(NULL, file, NULL, sizeof(buf)/sizeof(WCHAR), buf, NULL); if(!len) { + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + win_skip("SearchPathW is not implemented\n"); + else ok(0, "SearchPath failed: %u\n", GetLastError()); return; } len += sizeof(fileW)/sizeof(WCHAR)+1; ok(len == size, "wrong size %u, expected %u\n", size, len); - ok(!lstrcmpW(url + sizeof(fileW)/sizeof(WCHAR), buf), "wrong file part %s\n", debugstr_w(url)); + ok(!lstrcmpW(url + sizeof(fileW)/sizeof(WCHAR), buf), "wrong file part %s\n", wine_dbgstr_w(url)); } static void test_res_protocol(void) @@ -301,7 +319,7 @@ static void test_res_protocol(void) hres = CoGetClassObject(&CLSID_ResProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres); - if(!SUCCEEDED(hres)) + if(FAILED(hres)) return; hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); @@ -346,14 +364,18 @@ static void test_res_protocol(void) sizeof(buf)/sizeof(buf[0]), &size, 0); ok(hres == S_OK || hres == E_FAIL, "ParseUrl failed: %08x\n", hres); ok(buf[0] == '?', "buf changed\n"); - ok(size == sizeof(blank_url)/sizeof(WCHAR), "size=%d\n", size); + ok(size == sizeof(blank_url)/sizeof(WCHAR) || + size == sizeof(buf)/sizeof(buf[0]), /* IE8 */ + "size=%d\n", size); size = 0xdeadbeef; hres = IInternetProtocolInfo_ParseUrl(protocol_info, wrong_url1, PARSE_DOMAIN, 0, buf, sizeof(buf)/sizeof(buf[0]), &size, 0); ok(hres == S_OK || hres == E_FAIL, "ParseUrl failed: %08x\n", hres); ok(buf[0] == '?', "buf changed\n"); - ok(size == sizeof(wrong_url1)/sizeof(WCHAR), "size=%d\n", size); + ok(size == sizeof(wrong_url1)/sizeof(WCHAR) || + size == sizeof(buf)/sizeof(buf[0]), /* IE8 */ + "size=%d\n", size); if (0) { @@ -364,7 +386,7 @@ static void test_res_protocol(void) sizeof(buf)/sizeof(buf[0]), &size, 0); ok(hres == E_FAIL, "ParseUrl failed: %08x\n", hres); ok(buf[0] == '?', "buf changed\n"); - ok(size == 1, "size=%u, ezpected 1\n", size); + ok(size == 1, "size=%u, expected 1\n", size); buf[0] = '?'; hres = IInternetProtocolInfo_ParseUrl(protocol_info, blank_url, PARSE_DOMAIN, 0, buf, @@ -610,7 +632,7 @@ static void test_about_protocol(void) hres = CoGetClassObject(&CLSID_AboutProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres); - if(!SUCCEEDED(hres)) + if(FAILED(hres)) return; hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); @@ -649,7 +671,9 @@ static void test_about_protocol(void) sizeof(buf)/sizeof(buf[0]), &size, 0); ok(hres == S_OK || hres == E_FAIL, "ParseUrl failed: %08x\n", hres); ok(buf[0] == '?', "buf changed\n"); - ok(size == sizeof(about_blank_url)/sizeof(WCHAR), "size=%d\n", size); + ok(size == sizeof(about_blank_url)/sizeof(WCHAR) || + size == sizeof(buf)/sizeof(buf[0]), /* IE8 */ + "size=%d\n", size); if (0) { @@ -660,7 +684,7 @@ static void test_about_protocol(void) sizeof(buf)/sizeof(buf[0]), &size, 0); ok(hres == E_FAIL, "ParseUrl failed: %08x\n", hres); ok(buf[0] == '?', "buf changed\n"); - ok(size == 1, "size=%u, ezpected 1\n", size); + ok(size == 1, "size=%u, expected 1\n", size); buf[0] = '?'; hres = IInternetProtocolInfo_ParseUrl(protocol_info, about_blank_url, PARSE_DOMAIN, 0, buf, @@ -770,12 +794,108 @@ static void test_about_protocol(void) IUnknown_Release(unk); } +static void test_javascript_protocol(void) +{ + IInternetProtocolInfo *protocol_info; + IUnknown *unk; + IClassFactory *factory; + HRESULT hres; + + hres = CoGetClassObject(&CLSID_JSProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); + ok(hres == S_OK, "Could not get IInternetProtocolInfo interface: %08x\n", hres); + if(SUCCEEDED(hres)) { + WCHAR buf[128]; + DWORD size; + int i; + + for(i = PARSE_CANONICALIZE; i <= PARSE_UNESCAPE; i++) { + if(i != PARSE_SECURITY_URL && i != PARSE_DOMAIN) { + hres = IInternetProtocolInfo_ParseUrl(protocol_info, javascript_test_url, i, 0, buf, + sizeof(buf)/sizeof(buf[0]), &size, 0); + ok(hres == INET_E_DEFAULT_ACTION, + "[%d] failed: %08x, expected INET_E_DEFAULT_ACTION\n", i, hres); + } + } + + hres = IInternetProtocolInfo_ParseUrl(protocol_info, javascript_test_url, PARSE_UNESCAPE+1, 0, buf, + sizeof(buf)/sizeof(buf[0]), &size, 0); + ok(hres == INET_E_DEFAULT_ACTION, + "ParseUrl failed: %08x, expected INET_E_DEFAULT_ACTION\n", hres); + + size = 0xdeadbeef; + hres = IInternetProtocolInfo_CombineUrl(protocol_info, javascript_test_url, javascript_test_url, + 0, buf, sizeof(buf)/sizeof(buf[0]), &size, 0); + ok(hres == INET_E_USE_DEFAULT_PROTOCOLHANDLER, "CombineUrl failed: %08x\n", hres); + ok(size == 0xdeadbeef, "size=%d\n", size); + + hres = IInternetProtocolInfo_CompareUrl(protocol_info, javascript_test_url, javascript_test_url, 0); + ok(hres == E_NOTIMPL, "CompareUrl failed: %08x\n", hres); + + for(i=0; i<30; i++) { + switch(i) { + case QUERY_USES_NETWORK: + case QUERY_IS_SECURE: + break; + default: + hres = IInternetProtocolInfo_QueryInfo(protocol_info, javascript_test_url, i, 0, + buf, sizeof(buf), &size, 0); + ok(hres == INET_E_USE_DEFAULT_PROTOCOLHANDLER, + "QueryInfo(%d) returned: %08x, expected INET_E_USE_DEFAULT_PROTOCOLHANDLER\n", i, hres); + } + } + + + memset(buf, '?', sizeof(buf)); + hres = IInternetProtocolInfo_QueryInfo(protocol_info, javascript_test_url, QUERY_USES_NETWORK, 0, + buf, sizeof(buf), &size, 0); + ok(hres == S_OK, "QueryInfo(QUERY_USES_NETWORK) failed: %08x\n", hres); + ok(size == sizeof(DWORD), "size=%d\n", size); + ok(!*(DWORD*)buf, "buf=%d\n", *(DWORD*)buf); + + memset(buf, '?', sizeof(buf)); + hres = IInternetProtocolInfo_QueryInfo(protocol_info, javascript_test_url, QUERY_USES_NETWORK, 0, + buf, sizeof(buf), NULL, 0); + ok(hres == S_OK, "QueryInfo(QUERY_USES_NETWORK) failed: %08x\n", hres); + ok(!*(DWORD*)buf, "buf=%d\n", *(DWORD*)buf); + + hres = IInternetProtocolInfo_QueryInfo(protocol_info, javascript_test_url, QUERY_USES_NETWORK, 0, + buf, 3, &size, 0); + ok(hres == E_FAIL, "QueryInfo(QUERY_USES_NETWORK) failed: %08x, expected E_FAIL\n", hres); + + hres = IInternetProtocolInfo_QueryInfo(protocol_info, javascript_test_url, QUERY_USES_NETWORK, 0, + NULL, sizeof(buf), &size, 0); + ok(hres == E_FAIL, "QueryInfo(QUERY_USES_NETWORK) failed: %08x, expected E_FAIL\n", hres); + + hres = IInternetProtocolInfo_QueryInfo(protocol_info, javascript_test_url, 60, 0, + NULL, sizeof(buf), &size, 0); + ok(hres == INET_E_USE_DEFAULT_PROTOCOLHANDLER, + "QueryInfo failed: %08x, expected INET_E_USE_DEFAULT_PROTOCOLHANDLER\n", hres); + + /* FIXME: test QUERY_IS_SECURE */ + + IInternetProtocolInfo_Release(protocol_info); + } + + hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory); + ok(hres == S_OK, "Could not get IClassFactory interface\n"); + if(SUCCEEDED(hres)) + IClassFactory_Release(factory); + + IUnknown_Release(unk); +} + START_TEST(protocol) { OleInitialize(NULL); test_res_protocol(); test_about_protocol(); + test_javascript_protocol(); OleUninitialize(); } diff --git a/rostests/winetests/mshtml/script.c b/rostests/winetests/mshtml/script.c index bbd9c3cca5f..245fcff9871 100644 --- a/rostests/winetests/mshtml/script.c +++ b/rostests/winetests/mshtml/script.c @@ -1,5 +1,5 @@ /* - * Copyright 2008 Jacek Caban for CodeWeavers + * Copyright 2008-2009 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,10 +28,32 @@ #include "ole2.h" #include "dispex.h" #include "mshtml.h" +#include "initguid.h" #include "activscp.h" #include "activdbg.h" #include "objsafe.h" #include "mshtmdid.h" +#include "mshtml_test.h" + +DEFINE_GUID(CLSID_IdentityUnmarshal,0x0000001b,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); + +/* Defined as extern in urlmon.idl, but not exported by uuid.lib */ +const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY = + {0x10200490,0xfa38,0x11d0,{0xac,0x0e,0x00,0xa0,0xc9,0xf,0xff,0xc0}}; + +#ifdef _WIN64 + +#define CTXARG_T DWORDLONG +#define IActiveScriptParseVtbl IActiveScriptParse64Vtbl +#define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_64Vtbl + +#else + +#define CTXARG_T DWORD +#define IActiveScriptParseVtbl IActiveScriptParse32Vtbl +#define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_32Vtbl + +#endif #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -57,6 +79,12 @@ expect_ ## func = called_ ## func = FALSE; \ }while(0) +#define CHECK_CALLED_BROKEN(func) \ + do { \ + ok(called_ ## func || broken(!called_ ## func), "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + #define CHECK_NOT_CALLED(func) \ do { \ ok(!called_ ## func, "unexpected " #func "\n"); \ @@ -72,7 +100,9 @@ DEFINE_EXPECT(GetInterfaceSafetyOptions); DEFINE_EXPECT(SetInterfaceSafetyOptions); DEFINE_EXPECT(InitNew); DEFINE_EXPECT(Close); -DEFINE_EXPECT(SetProperty); +DEFINE_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK); +DEFINE_EXPECT(SetProperty_INVOKEVERSIONING); +DEFINE_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION); DEFINE_EXPECT(SetScriptSite); DEFINE_EXPECT(GetScriptState); DEFINE_EXPECT(SetScriptState_STARTED); @@ -81,22 +111,27 @@ DEFINE_EXPECT(SetScriptState_DISCONNECTED); DEFINE_EXPECT(AddNamedItem); DEFINE_EXPECT(ParseScriptText); DEFINE_EXPECT(GetScriptDispatch); +DEFINE_EXPECT(funcDisp); +DEFINE_EXPECT(script_testprop_d); +DEFINE_EXPECT(script_testprop_i); +DEFINE_EXPECT(AXQueryInterface_IActiveScript); +DEFINE_EXPECT(AXQueryInterface_IObjectSafety); +DEFINE_EXPECT(AXGetInterfaceSafetyOptions); +DEFINE_EXPECT(AXSetInterfaceSafetyOptions); #define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}" +#define DISPID_SCRIPT_TESTPROP 0x100000 + static const GUID CLSID_TestScript = {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}; +static const GUID CLSID_TestActiveX = + {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x06,0x46}}; static IHTMLDocument2 *notif_doc; static IDispatchEx *window_dispex; static BOOL doc_complete; - -static const char *debugstr_w(LPCWSTR str) -{ - static char buf[1024]; - WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); - return buf; -} +static IDispatch *script_disp; static const char *debugstr_guid(REFIID riid) { @@ -110,6 +145,25 @@ static const char *debugstr_guid(REFIID riid) return buf; } +static int strcmp_wa(LPCWSTR strw, const char *stra) +{ + CHAR buf[512]; + WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); + return lstrcmpA(stra, buf); +} + +static BSTR a2bstr(const char *str) +{ + BSTR ret; + int len; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret = SysAllocStringLen(NULL, len); + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + + return ret; +} + static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface, REFIID riid, void**ppv) { @@ -167,6 +221,206 @@ static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = { static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl }; +static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDispatch) + || IsEqualGUID(riid, &IID_IDispatchEx)) + *ppv = iface; + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) +{ + return 2; +} + +static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) +{ + return 1; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) +{ + ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI funcDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(funcDisp); + + ok(id == DISPID_VALUE, "id = %d\n", id); + ok(lcid == 0, "lcid = %x\n", lcid); + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->cArgs == 2, "pdp->cArgs = %d\n", pdp->cArgs); + ok(pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]); + ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_VT(pdp->rgvarg+1) == VT_BOOL, "V_VT(rgvarg[1]) = %d\n", V_VT(pdp->rgvarg)); + ok(V_BOOL(pdp->rgvarg+1) == VARIANT_TRUE, "V_BOOL(rgvarg[1]) = %x\n", V_BOOL(pdp->rgvarg)); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + ok(!pspCaller, "pspCaller != NULL\n"); + + V_VT(pvarRes) = VT_I4; + V_I4(pvarRes) = 100; + return S_OK; +} + +static IDispatchExVtbl testObjVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + funcDisp_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx funcDisp = { &testObjVtbl }; + +static HRESULT WINAPI scriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + if(!strcmp_wa(bstrName, "testProp")) { + CHECK_EXPECT(script_testprop_d); + ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex); + *pid = DISPID_SCRIPT_TESTPROP; + return S_OK; + } + + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI scriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + switch(id) { + case DISPID_SCRIPT_TESTPROP: + CHECK_EXPECT(script_testprop_i); + + ok(lcid == 0, "lcid = %x\n", lcid); + ok(wFlags == DISPATCH_PROPERTYGET, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->cArgs == 0, "pdp->cArgs = %d\n", pdp->cArgs); + ok(pdp->cNamedArgs == 0, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); + ok(!pdp->rgdispidNamedArgs, "pdp->rgdispidNamedArgs != NULL\n"); + ok(!pdp->rgvarg, "rgvarg != NULL\n"); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + ok(!pspCaller, "pspCaller != NULL\n"); + + V_VT(pvarRes) = VT_NULL; + break; + default: + ok(0, "unexpected call\n"); + return E_NOTIMPL; + } + + return S_OK; +} + +static IDispatchExVtbl scriptDispVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + scriptDisp_GetDispID, + scriptDisp_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx scriptDisp = { &scriptDispVtbl }; + static IHTMLDocument2 *create_document(void) { IHTMLDocument2 *doc; @@ -234,6 +488,10 @@ static IHTMLDocument2 *create_and_load_doc(const char *str) ULONG ref; MSG msg; HRESULT hres; + static const WCHAR ucPtr[] = {'b','a','c','k','g','r','o','u','n','d',0}; + DISPID dispID = -1; + OLECHAR *name; + doc = create_doc_with_string(str); do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink); @@ -253,6 +511,12 @@ static IHTMLDocument2 *create_and_load_doc(const char *str) return NULL; } + /* Check we can query for function on the IHTMLElementBody interface */ + name = (WCHAR*)ucPtr; + hres = IHTMLElement_GetIDsOfNames(body, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispID); + ok(hres == S_OK, "GetIDsOfNames(background) failed %08x\n", hres); + ok(dispID == DISPID_IHTMLBODYELEMENT_BACKGROUND, "Incorrect dispID got (%d)\n", dispID); + IHTMLElement_Release(body); return doc; } @@ -263,7 +527,7 @@ static SCRIPTSTATE state; static HRESULT WINAPI ObjectSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv) { *ppv = NULL; - ok(0, "unexpected call\n"); + ok(0, "unexpected call %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } @@ -317,6 +581,110 @@ static const IObjectSafetyVtbl ObjectSafetyVtbl = { static IObjectSafety ObjectSafety = { &ObjectSafetyVtbl }; +static HRESULT WINAPI AXObjectSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID_IActiveScript, riid)) { + CHECK_EXPECT(AXQueryInterface_IActiveScript); + return E_NOINTERFACE; + } + + if(IsEqualGUID(&IID_IObjectSafety, riid)) { + CHECK_EXPECT(AXQueryInterface_IObjectSafety); + *ppv = iface; + return S_OK; + } + + ok(0, "unexpected call %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static HRESULT WINAPI AXObjectSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid, + DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) +{ + CHECK_EXPECT(AXGetInterfaceSafetyOptions); + + ok(IsEqualGUID(&IID_IDispatchEx, riid), "unexpected riid %s\n", debugstr_guid(riid)); + ok(pdwSupportedOptions != NULL, "pdwSupportedOptions == NULL\n"); + ok(pdwEnabledOptions != NULL, "pdwEnabledOptions == NULL\n"); + + *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER; + *pdwEnabledOptions = INTERFACE_USES_DISPEX; + + return S_OK; +} + +static HRESULT WINAPI AXObjectSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid, + DWORD dwOptionSetMask, DWORD dwEnabledOptions) +{ + CHECK_EXPECT(AXSetInterfaceSafetyOptions); + + ok(IsEqualGUID(&IID_IDispatchEx, riid), "unexpected riid %s\n", debugstr_guid(riid)); + + ok(dwOptionSetMask == (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACE_USES_SECURITY_MANAGER), + "dwOptionSetMask=%x\n", dwOptionSetMask); + ok(dwEnabledOptions == (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACE_USES_SECURITY_MANAGER), + "dwEnabledOptions=%x\n", dwOptionSetMask); + + return S_OK; +} + +static const IObjectSafetyVtbl AXObjectSafetyVtbl = { + AXObjectSafety_QueryInterface, + ObjectSafety_AddRef, + ObjectSafety_Release, + AXObjectSafety_GetInterfaceSafetyOptions, + AXObjectSafety_SetInterfaceSafetyOptions +}; + +static IObjectSafety AXObjectSafety = { &AXObjectSafetyVtbl }; + +static void test_security(void) +{ + IInternetHostSecurityManager *sec_mgr; + IServiceProvider *sp; + DWORD policy, policy_size; + struct CONFIRMSAFETY cs; + BYTE *ppolicy; + HRESULT hres; + + hres = IActiveScriptSite_QueryInterface(site, &IID_IServiceProvider, (void**)&sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08x\n", hres); + + hres = IServiceProvider_QueryService(sp, &SID_SInternetHostSecurityManager, + &IID_IInternetHostSecurityManager, (void**)&sec_mgr); + IServiceProvider_Release(sp); + ok(hres == S_OK, "QueryService failed: %08x\n", hres); + + hres = IInternetHostSecurityManager_ProcessUrlAction(sec_mgr, URLACTION_ACTIVEX_RUN, (BYTE*)&policy, sizeof(policy), + (BYTE*)&CLSID_TestActiveX, sizeof(CLSID), 0, 0); + ok(hres == S_OK, "ProcessUrlAction failed: %08x\n", hres); + ok(policy == URLPOLICY_ALLOW, "policy = %x\n", policy); + + cs.clsid = CLSID_TestActiveX; + cs.pUnk = (IUnknown*)&AXObjectSafety; + cs.dwFlags = 0; + + SET_EXPECT(AXQueryInterface_IActiveScript); + SET_EXPECT(AXQueryInterface_IObjectSafety); + SET_EXPECT(AXGetInterfaceSafetyOptions); + SET_EXPECT(AXSetInterfaceSafetyOptions); + hres = IInternetHostSecurityManager_QueryCustomPolicy(sec_mgr, &GUID_CUSTOM_CONFIRMOBJECTSAFETY, + &ppolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0); + CHECK_CALLED(AXQueryInterface_IActiveScript); + CHECK_CALLED(AXQueryInterface_IObjectSafety); + CHECK_CALLED(AXGetInterfaceSafetyOptions); + CHECK_CALLED(AXSetInterfaceSafetyOptions); + + ok(hres == S_OK, "QueryCusromPolicy failed: %08x\n", hres); + ok(policy_size == sizeof(DWORD), "policy_size = %d\n", policy_size); + ok(*(DWORD*)ppolicy == URLPOLICY_ALLOW, "policy = %x\n", *(DWORD*)ppolicy); + CoTaskMemFree(ppolicy); + + IInternetHostSecurityManager_Release(sec_mgr); +} + static HRESULT WINAPI ActiveScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -344,15 +712,31 @@ static HRESULT WINAPI ActiveScriptProperty_GetProperty(IActiveScriptProperty *if static HRESULT WINAPI ActiveScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty, VARIANT *pvarIndex, VARIANT *pvarValue) { - CHECK_EXPECT(SetProperty); + switch(dwProperty) { + case SCRIPTPROP_HACK_TRIDENTEVENTSINK: + CHECK_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK); + ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue)=%d\n", V_VT(pvarValue)); + ok(V_BOOL(pvarValue) == VARIANT_TRUE, "V_BOOL(pvarValue)=%x\n", V_BOOL(pvarValue)); + break; + case SCRIPTPROP_INVOKEVERSIONING: + CHECK_EXPECT(SetProperty_INVOKEVERSIONING); + ok(V_VT(pvarValue) == VT_I4, "V_VT(pvarValue)=%d\n", V_VT(pvarValue)); + ok(V_I4(pvarValue) == 1, "V_I4(pvarValue)=%d\n", V_I4(pvarValue)); + break; + case SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION: + CHECK_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION); + ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue)=%d\n", V_VT(pvarValue)); + ok(V_BOOL(pvarValue) == VARIANT_TRUE, "V_BOOL(pvarValue)=%x\n", V_BOOL(pvarValue)); + break; + default: + ok(0, "unexpected property %x\n", dwProperty); + return E_NOTIMPL; + } - ok(dwProperty == SCRIPTPROP_HACK_TRIDENTEVENTSINK, "unexpected property %d\n", dwProperty); ok(!pvarIndex, "pvarIndex != NULL\n"); ok(pvarValue != NULL, "pvarValue == NULL\n"); - ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue)=%d\n", V_VT(pvarValue)); - ok(V_BOOL(pvarValue) == VARIANT_TRUE, "V_BOOL(pvarValue)=%x\n", V_BOOL(pvarValue)); - return E_NOTIMPL; + return S_OK; } static const IActiveScriptPropertyVtbl ActiveScriptPropertyVtbl = { @@ -385,7 +769,7 @@ static ULONG WINAPI ActiveScriptParseProcedure_Release(IActiveScriptParseProcedu static HRESULT WINAPI ActiveScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface, LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName, LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter, - DWORD dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp) + CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp) { ok(0, "unexpected call\n"); return E_NOTIMPL; @@ -426,29 +810,130 @@ static HRESULT WINAPI ActiveScriptParse_InitNew(IActiveScriptParse *iface) static HRESULT WINAPI ActiveScriptParse_AddScriptlet(IActiveScriptParse *iface, LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName, LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter, - DWORD dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, + CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, BSTR *pbstrName, EXCEPINFO *pexcepinfo) { ok(0, "unexpected call\n"); return E_NOTIMPL; } +static HRESULT dispex_propput(IDispatchEx *obj, DISPID id, VARIANT *var) +{ + DISPID propput_arg = DISPID_PROPERTYPUT; + DISPPARAMS dp = {var, &propput_arg, 1, 1}; + EXCEPINFO ei = {0}; + + return IDispatchEx_InvokeEx(obj, id, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dp, NULL, &ei, NULL); +} + +static void test_func(IDispatchEx *obj) +{ + DISPID id; + IDispatchEx *dispex; + IDispatch *disp; + EXCEPINFO ei; + DISPPARAMS dp; + BSTR str; + VARIANT var; + HRESULT hres; + + str = a2bstr("toString"); + hres = IDispatchEx_GetDispID(obj, str, fdexNameCaseSensitive, &id); + SysFreeString(str); + ok(hres == S_OK, "GetDispID failed: %08x\n", hres); + ok(id == DISPID_IOMNAVIGATOR_TOSTRING, "id = %x\n", id); + + memset(&dp, 0, sizeof(dp)); + memset(&ei, 0, sizeof(ei)); + VariantInit(&var); + hres = IDispatchEx_InvokeEx(obj, id, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dp, &var, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n"); + disp = V_DISPATCH(&var); + + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + IDispatch_Release(disp); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres); + + /* FIXME: Test InvokeEx(DISPATCH_METHOD) */ + + memset(&dp, 0, sizeof(dp)); + memset(&ei, 0, sizeof(ei)); + VariantInit(&var); + hres = IDispatchEx_Invoke(dispex, DISPID_VALUE, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dp, &var, &ei, NULL); + ok(hres == S_OK || broken(E_ACCESSDENIED), "InvokeEx failed: %08x\n", hres); + if(SUCCEEDED(hres)) { + ok(V_VT(&var) == VT_BSTR, "V_VT(var)=%d\n", V_VT(&var)); + ok(!strcmp_wa(V_BSTR(&var), "[object]"), "V_BSTR(var) = %s\n", wine_dbgstr_w(V_BSTR(&var))); + VariantClear(&var); + } + + V_VT(&var) = VT_I4; + V_I4(&var) = 100; + hres = dispex_propput(obj, id, &var); + ok(hres == E_NOTIMPL, "InvokeEx failed: %08x\n", hres); + + IDispatchEx_Release(dispex); +} + +static void test_nextdispid(IDispatchEx *dispex) +{ + DISPID last_id = DISPID_STARTENUM, id, dyn_id; + BSTR name; + VARIANT var; + HRESULT hres; + + name = a2bstr("dynVal"); + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive|fdexNameEnsure, &dyn_id); + ok(hres == S_OK, "GetDispID failed: %08x\n", hres); + SysFreeString(name); + + V_VT(&var) = VT_EMPTY; + hres = dispex_propput(dispex, dyn_id, &var); + + while(last_id != dyn_id) { + hres = IDispatchEx_GetNextDispID(dispex, fdexEnumAll, last_id, &id); + ok(hres == S_OK, "GetNextDispID returned: %08x\n", hres); + ok(id != DISPID_STARTENUM, "id == DISPID_STARTENUM\n"); + ok(id != DISPID_IOMNAVIGATOR_TOSTRING, "id == DISPID_IOMNAVIGATOR_TOSTRING\n"); + + hres = IDispatchEx_GetMemberName(dispex, id, &name); + ok(hres == S_OK, "GetMemberName failed: %08x\n", hres); + + if(id == dyn_id) + ok(!strcmp_wa(name, "dynVal"), "name = %s\n", wine_dbgstr_w(name)); + else if(id == DISPID_IOMNAVIGATOR_PLATFORM) + ok(!strcmp_wa(name, "platform"), "name = %s\n", wine_dbgstr_w(name)); + + SysFreeString(name); + last_id = id; + } + + hres = IDispatchEx_GetNextDispID(dispex, 0, id, &id); + ok(hres == S_FALSE, "GetNextDispID returned: %08x\n", hres); + ok(id == DISPID_STARTENUM, "id != DISPID_STARTENUM\n"); +} + static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *iface, LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext, - LPCOLESTR pstrDelimiter, DWORD dwSourceContextCookie, ULONG ulStartingLine, + LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine, DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo) { - IDispatchEx *document; + IDispatchEx *document, *dispex; + IHTMLWindow2 *window; + IOmNavigator *navigator; IUnknown *unk; - VARIANT var; + VARIANT var, arg; DISPPARAMS dp; EXCEPINFO ei; - DISPID id, named_arg = DISPID_PROPERTYPUT; + DISPID id; BSTR tmp; HRESULT hres; static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0}; static const WCHAR testW[] = {'t','e','s','t',0}; + static const WCHAR funcW[] = {'f','u','n','c',0}; CHECK_EXPECT(ParseScriptText); @@ -460,7 +945,7 @@ static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *ifac ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres); ok(id == DISPID_IHTMLWINDOW2_DOCUMENT, "id=%x\n", id); - todo_wine CHECK_CALLED(GetScriptDispatch); + CHECK_CALLED(GetScriptDispatch); VariantInit(&var); memset(&dp, 0, sizeof(dp)); @@ -489,14 +974,9 @@ static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *ifac ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres); ok(id, "id == 0\n"); - dp.cArgs = 1; - dp.rgvarg = &var; - dp.cNamedArgs = 1; - dp.rgdispidNamedArgs = &named_arg; V_VT(&var) = VT_I4; V_I4(&var) = 100; - - hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYPUT, &dp, NULL, &ei, NULL); + hres = dispex_propput(document, id, &var); ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); tmp = SysAllocString(testW); @@ -512,13 +992,90 @@ static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *ifac ok(V_VT(&var) == VT_I4, "V_VT(var)=%d\n", V_VT(&var)); ok(V_I4(&var) == 100, "V_I4(&var) == NULL\n"); - IDispatchEx_Release(document); - unk = (void*)0xdeadbeef; hres = IDispatchEx_GetNameSpaceParent(window_dispex, &unk); ok(hres == S_OK, "GetNameSpaceParent failed: %08x\n", hres); ok(!unk, "unk=%p, expected NULL\n", unk); + id = 0; + tmp = SysAllocString(funcW); + hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive|fdexNameEnsure, &id); + SysFreeString(tmp); + ok(hres == S_OK, "GetDispID(func) failed: %08x\n", hres); + ok(id, "id == 0\n"); + + dp.cArgs = 1; + dp.rgvarg = &var; + dp.cNamedArgs = 0; + dp.rgdispidNamedArgs = NULL; + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = (IDispatch*)&funcDisp; + hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYPUT, &dp, NULL, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + + VariantInit(&var); + memset(&dp, 0, sizeof(dp)); + memset(&ei, 0, sizeof(ei)); + V_VT(&arg) = VT_BOOL; + V_BOOL(&arg) = VARIANT_TRUE; + dp.cArgs = 1; + dp.rgvarg = &arg; + + SET_EXPECT(funcDisp); + hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_FUNC, &dp, &var, &ei, NULL); + CHECK_CALLED(funcDisp); + + ok(hres == S_OK, "InvokeEx(INVOKE_FUNC) failed: %08x\n", hres); + ok(V_VT(&var) == VT_I4, "V_VT(var)=%d\n", V_VT(&var)); + ok(V_I4(&var) == 100, "V_I4(&var) == NULL\n"); + + IDispatchEx_Release(document); + + hres = IDispatchEx_QueryInterface(window_dispex, &IID_IHTMLWindow2, (void**)&window); + ok(hres == S_OK, "Could not get IHTMLWindow2 iface: %08x\n", hres); + + hres = IHTMLWindow2_get_navigator(window, &navigator); + IHTMLWindow2_Release(window); + ok(hres == S_OK, "get_navigator failed: %08x\n", hres); + + hres = IOmNavigator_QueryInterface(navigator, &IID_IDispatchEx, (void**)&dispex); + IOmNavigator_Release(navigator); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres); + + test_func(dispex); + test_nextdispid(dispex); + IDispatchEx_Release(dispex); + + script_disp = (IDispatch*)&scriptDisp; + + SET_EXPECT(GetScriptDispatch); + SET_EXPECT(script_testprop_d); + tmp = a2bstr("testProp"); + hres = IDispatchEx_GetDispID(window_dispex, tmp, fdexNameCaseSensitive, &id); + ok(hres == S_OK, "GetDispID failed: %08x\n", hres); + ok(id != DISPID_SCRIPT_TESTPROP, "id == DISPID_SCRIPT_TESTPROP\n"); + CHECK_CALLED(GetScriptDispatch); + CHECK_CALLED(script_testprop_d); + SysFreeString(tmp); + + tmp = a2bstr("testProp"); + hres = IDispatchEx_GetDispID(window_dispex, tmp, fdexNameCaseSensitive, &id); + ok(hres == S_OK, "GetDispID failed: %08x\n", hres); + ok(id != DISPID_SCRIPT_TESTPROP, "id == DISPID_SCRIPT_TESTPROP\n"); + SysFreeString(tmp); + + SET_EXPECT(GetScriptDispatch); + SET_EXPECT(script_testprop_i); + memset(&ei, 0, sizeof(ei)); + memset(&dp, 0, sizeof(dp)); + hres = IDispatchEx_InvokeEx(window_dispex, id, 0, DISPATCH_PROPERTYGET, &dp, &var, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + ok(V_VT(&var) == VT_NULL, "V_VT(var) = %d\n", V_VT(&var)); + CHECK_CALLED(GetScriptDispatch); + CHECK_CALLED(script_testprop_i); + + test_security(); + return S_OK; } @@ -562,6 +1119,9 @@ static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID r return S_OK; } + if(IsEqualGUID(&IID_IActiveScriptDebug, riid)) + return E_NOINTERFACE; + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } @@ -580,6 +1140,8 @@ static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveSc { IActiveScriptSiteInterruptPoll *poll; IActiveScriptSiteDebug *debug; + IServiceProvider *service; + ICanHandleException *canexpection; LCID lcid; HRESULT hres; @@ -603,6 +1165,14 @@ static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveSc if(SUCCEEDED(hres)) IActiveScriptSiteDebug32_Release(debug); + hres = IActiveScriptSite_QueryInterface(pass, &IID_ICanHandleException, (void**)&canexpection); + ok(hres == E_NOINTERFACE, "Could not get IID_ICanHandleException interface: %08x\n", hres); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_IServiceProvider, (void**)&service); + ok(hres == S_OK, "Could not get IServiceProvider interface: %08x\n", hres); + if(SUCCEEDED(hres)) + IServiceProvider_Release(service); + site = pass; IActiveScriptSite_AddRef(site); return S_OK; @@ -665,7 +1235,7 @@ static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface, CHECK_EXPECT(AddNamedItem); - ok(!lstrcmpW(pstrName, windowW), "pstrName=%s\n", debugstr_w(pstrName)); + ok(!lstrcmpW(pstrName, windowW), "pstrName=%s\n", wine_dbgstr_w(pstrName)); ok(dwFlags == (SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS), "dwFlags=%x\n", dwFlags); hres = IActiveScriptSite_GetItemInfo(site, windowW, SCRIPTINFO_IUNKNOWN, &unk, NULL); @@ -700,7 +1270,14 @@ static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOL IDispatch **ppdisp) { CHECK_EXPECT(GetScriptDispatch); + + ok(!strcmp_wa(pstrItemName, "window"), "pstrItemName = %s\n", wine_dbgstr_w(pstrItemName)); + + if(!script_disp) return E_NOTIMPL; + + *ppdisp = script_disp; + return S_OK; } static HRESULT WINAPI ActiveScript_GetCurrentScriptThreadID(IActiveScript *iface, @@ -824,12 +1401,14 @@ static void test_simple_script(void) SET_EXPECT(CreateInstance); SET_EXPECT(GetInterfaceSafetyOptions); SET_EXPECT(SetInterfaceSafetyOptions); - SET_EXPECT(SetProperty); + SET_EXPECT(SetProperty_INVOKEVERSIONING); /* IE8 */ + SET_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK); SET_EXPECT(InitNew); SET_EXPECT(SetScriptSite); SET_EXPECT(GetScriptState); SET_EXPECT(SetScriptState_STARTED); SET_EXPECT(AddNamedItem); + SET_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION); /* IE8 */ SET_EXPECT(ParseScriptText); SET_EXPECT(SetScriptState_CONNECTED); @@ -839,12 +1418,14 @@ static void test_simple_script(void) CHECK_CALLED(CreateInstance); CHECK_CALLED(GetInterfaceSafetyOptions); CHECK_CALLED(SetInterfaceSafetyOptions); - CHECK_CALLED(SetProperty); + CHECK_CALLED_BROKEN(SetProperty_INVOKEVERSIONING); /* IE8 */ + CHECK_CALLED(SetProperty_HACK_TRIDENTEVENTSINK); CHECK_CALLED(InitNew); CHECK_CALLED(SetScriptSite); CHECK_CALLED(GetScriptState); CHECK_CALLED(SetScriptState_STARTED); CHECK_CALLED(AddNamedItem); + CHECK_CALLED_BROKEN(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION); /* IE8 */ CHECK_CALLED(ParseScriptText); CHECK_CALLED(SetScriptState_CONNECTED); @@ -945,12 +1526,16 @@ START_TEST(script) gecko_installer_workaround(TRUE); CoInitialize(NULL); + if(winetest_interactive || ! is_ie_hardened()) { if(register_script_engine()) { test_simple_script(); init_registry(FALSE); }else { skip("Could not register TestScript engine\n"); } + }else { + skip("IE running in Enhanced Security Configuration\n"); + } CoUninitialize(); gecko_installer_workaround(FALSE); diff --git a/rostests/winetests/mshtml/testlist.c b/rostests/winetests/mshtml/testlist.c index 6039fe93ed2..0905322ca97 100644 --- a/rostests/winetests/mshtml/testlist.c +++ b/rostests/winetests/mshtml/testlist.c @@ -7,6 +7,7 @@ #include "wine/test.h" extern void func_dom(void); +extern void func_events(void); extern void func_htmldoc(void); extern void func_misc(void); extern void func_protocol(void); @@ -15,6 +16,7 @@ extern void func_script(void); const struct test winetest_testlist[] = { { "dom", func_dom }, + { "events", func_events }, { "htmldoc", func_htmldoc }, { "misc", func_misc }, { "protocol", func_protocol }, diff --git a/rostests/winetests/msi/automation.c b/rostests/winetests/msi/automation.c index 68b0f75c25c..b792fa722bd 100644 --- a/rostests/winetests/msi/automation.c +++ b/rostests/winetests/msi/automation.c @@ -23,6 +23,7 @@ #include +#include #include #include #include @@ -31,6 +32,8 @@ #include "wine/test.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + static const char *msifile = "winetest.msi"; static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0}; static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 }; @@ -60,8 +63,7 @@ static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttribu "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n" "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n" "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n" - "component\t\tMSITESTDIR\t0\t1\tfile\n" - "service_comp\t\tMSITESTDIR\t0\t1\tservice_file"; + "component\t\tMSITESTDIR\t0\t1\tfile\n"; static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n" "s72\tS72\tl255\n" @@ -82,8 +84,7 @@ static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\t "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n" "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n" "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n" - "feature\t\t\t\t2\t1\tTARGETDIR\t0\n" - "service_feature\t\t\t\t2\t1\tTARGETDIR\t0"; + "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"; static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n" "s38\ts72\n" @@ -93,8 +94,7 @@ static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n" "One\tOne\n" "Three\tThree\n" "Two\tTwo\n" - "feature\tcomponent\n" - "service_feature\tservice_comp\n"; + "feature\tcomponent\n"; static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" @@ -104,8 +104,7 @@ static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tL "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n" "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n" "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n" - "file\tcomponent\tfilename\t100\t\t\t8192\t1\n" - "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1"; + "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"; static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n" "s72\tS255\tI2\n" @@ -115,7 +114,6 @@ static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n" "CostInitialize\t\t800\n" "FileCost\t\t900\n" "InstallFiles\t\t4000\n" - "InstallServices\t\t5000\n" "RegisterProduct\t\t6100\n" "PublishProduct\t\t6400\n" "InstallFinalize\t\t6600\n" @@ -155,17 +153,6 @@ static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_ "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n" "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent"; -static const CHAR service_install_dat[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t" - "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n" - "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n" - "ServiceInstall\tServiceInstall\n" - "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t"; - -static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n" - "s72\tl255\ti2\tL255\tI2\ts72\n" - "ServiceControl\tServiceControl\n" - "ServiceControl\tTestService\t8\t\t0\tservice_comp"; - typedef struct _msi_table { const CHAR *filename; @@ -185,9 +172,7 @@ static const msi_table tables[] = ADD_TABLE(install_exec_seq), ADD_TABLE(media), ADD_TABLE(property), - ADD_TABLE(registry), - ADD_TABLE(service_install), - ADD_TABLE(service_control) + ADD_TABLE(registry) }; typedef struct _msi_summary_info @@ -340,7 +325,6 @@ static void create_test_files(void) CreateDirectoryA("msitest\\cabout\\new",NULL); create_file("msitest\\cabout\\new\\five.txt", 100); create_file("msitest\\filename", 100); - create_file("msitest\\service.exe", 100); } static BOOL delete_pf(const CHAR *rel_path, BOOL is_file) @@ -365,7 +349,6 @@ static void delete_test_files(void) DeleteFileA("msitest\\second\\three.txt"); DeleteFileA("msitest\\first\\two.txt"); DeleteFileA("msitest\\one.txt"); - DeleteFileA("msitest\\service.exe"); DeleteFileA("msitest\\filename"); RemoveDirectoryA("msitest\\cabout\\new"); RemoveDirectoryA("msitest\\cabout"); @@ -374,24 +357,6 @@ static void delete_test_files(void) RemoveDirectoryA("msitest"); } -static void check_service_is_installed(void) -{ - SC_HANDLE scm, service; - BOOL res; - - scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - ok(scm != NULL, "Failed to open the SC Manager\n"); - - service = OpenService(scm, "TestService", SC_MANAGER_ALL_ACCESS); - ok(service != NULL, "Failed to open TestService\n"); - - res = DeleteService(service); - ok(res, "Failed to delete TestService\n"); - - CloseServiceHandle(service); - CloseServiceHandle(scm); -} - /* * Automation helpers and tests */ @@ -399,9 +364,29 @@ static void check_service_is_installed(void) /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */ static CHAR string1[MAX_PATH], string2[MAX_PATH]; +/* lstrcmpW is not supported on Win9x */ +static int strcmp_ww(const WCHAR* str1, const WCHAR* str2) +{ + CHAR str1A[MAX_PATH], str2A[MAX_PATH]; + + WideCharToMultiByte(CP_ACP, 0, str1, -1, str1A, MAX_PATH, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, str2, -1, str2A, MAX_PATH, NULL, NULL); + + return lstrcmpA(str1A, str2A); +} + #define ok_w2(format, szString1, szString2) \ \ - if (lstrcmpW(szString1, szString2) != 0) \ + do { \ + WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ + WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ + if (lstrcmpA(string1, string2) != 0) \ + ok(0, format, string1, string2); \ + } while(0); + +#define ok_w2n(format, szString1, szString2, len) \ +\ + if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \ { \ WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ @@ -620,7 +605,7 @@ static void test_dispatch(void) ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr); /* Test getting ID of a function name that does exist */ - name = (WCHAR *)szOpenPackage; + name = szOpenPackage; hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); @@ -664,7 +649,7 @@ static void test_dispatch(void) ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr); /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */ - name = (WCHAR *)szProductState; + name = szProductState; hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); @@ -749,7 +734,7 @@ static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VariantInit(&vararg[2]); V_VT(&vararg[2]) = VT_I4; - V_I4(&vararg[2]) = (int)hkey; + V_I4(&vararg[2]) = (INT_PTR)hkey; VariantInit(&vararg[1]); V_VT(&vararg[1]) = VT_BSTR; V_BSTR(&vararg[1]) = SysAllocString(szKey); @@ -785,7 +770,9 @@ static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValu V_BSTR(&vararg) = SysAllocString(szValue); hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR); - if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) + /* lstrcpyW is not implemented on Win95 (lstrlenW is though) */ + memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR)); VariantClear(&varresult); return hr; } @@ -801,7 +788,8 @@ static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LP V_I4(&vararg) = iValue; hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult); - if (vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult)); + if (SUCCEEDED(hr) && vtResult == VT_BSTR) + memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR)); VariantClear(&varresult); return hr; } @@ -892,7 +880,8 @@ static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPW V_BSTR(&vararg[0]) = SysAllocString(szAttribute); hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) + memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR)); VariantClear(&varresult); return hr; } @@ -931,7 +920,8 @@ static HRESULT Installer_VersionGet(LPWSTR szVersion) HRESULT hr; hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) + memcpy(szVersion, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR)); VariantClear(&varresult); return hr; } @@ -959,7 +949,8 @@ static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR s V_BSTR(&vararg[0]) = SysAllocString(szName); hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) + memcpy(szReturn, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR)); VariantClear(&varresult); return hr; } @@ -1072,7 +1063,28 @@ static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szConditio return hr; } -static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel) +static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret) +{ + VARIANT varresult; + VARIANTARG vararg[2]; + DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; + HRESULT hr; + + VariantInit(&varresult); + V_VT(vararg) = VT_DISPATCH; + V_DISPATCH(vararg) = record; + V_VT(vararg+1) = VT_I4; + V_I4(vararg+1) = kind; + + hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4); + + ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult)); + *ret = V_I4(&varresult); + + return hr; +} + +static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel) { VARIANT varresult; VARIANTARG vararg[1]; @@ -1237,7 +1249,8 @@ static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szStr V_I4(&vararg[0]) = iField; hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) + memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR)); VariantClear(&varresult); return hr; } @@ -1314,7 +1327,8 @@ static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szStri V_I4(&vararg[0]) = iIndex; hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); - if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); + if (V_BSTR(&varresult)) + memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR)); VariantClear(&varresult); return hr; } @@ -1492,8 +1506,7 @@ static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *in hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var)); ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); - /* FIXME: Off by one second */ - todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult)); + ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult)); VariantClear(&varresult); VariantClear(&var); @@ -1646,7 +1659,7 @@ static void test_Session(IDispatch *pSession) UINT len; BOOL bool; int myint; - IDispatch *pDatabase = NULL, *pInst = NULL; + IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL; HRESULT hr; /* Session::Installer */ @@ -1659,7 +1672,7 @@ static void test_Session(IDispatch *pSession) memset(stringw, 0, sizeof(stringw)); hr = Session_PropertyGet(pSession, szProductName, stringw); ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr); - if (lstrcmpW(stringw, szMSITEST) != 0) + if (strcmp_ww(stringw, szMSITEST) != 0) { len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL); ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); @@ -1672,7 +1685,7 @@ static void test_Session(IDispatch *pSession) memset(stringw, 0, sizeof(stringw)); hr = Session_PropertyGet(pSession, szProductName, stringw); ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr); - if (lstrcmpW(stringw, szProductName) != 0) + if (strcmp_ww(stringw, szProductName) != 0) { len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL); ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); @@ -1700,12 +1713,12 @@ static void test_Session(IDispatch *pSession) /* Session::Mode, put */ hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE); - todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool); ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr); ok(bool, "Reboot at end session mode is %d, expected 1\n", bool); hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */ - todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); /* Session::Database, get */ hr = Session_Database(pSession, &pDatabase); @@ -1743,6 +1756,13 @@ static void test_Session(IDispatch *pSession) ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr); ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); + /* Session::Message */ + hr = Installer_CreateRecord(0, &record); + ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr); + hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint); + ok(hr == S_OK, "Session_Message failed: %08x\n", hr); + ok(myint == 0, "Session_Message returned %x\n", myint); + /* Session::EvaluateCondition */ hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint); ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); @@ -1814,9 +1834,18 @@ static void test_Installer_RegistryValue(void) HKEY curr_user = (HKEY)1; HRESULT hr; BOOL bRet; + LONG lRet; /* Delete keys */ - if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey ); + SetLastError(0xdeadbeef); + lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey ); + if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Needed W-functions are not implemented\n"); + return; + } + if (!lRet) + delete_key( hkey ); /* Does our key exist? Shouldn't; check with all three possible value parameter types */ hr = Installer_RegistryValueE(curr_user, szKey, &bRet); @@ -1847,7 +1876,7 @@ static void test_Installer_RegistryValue(void) "RegSetValueExW failed\n"); ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8), "RegSetValueExW failed\n"); - ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0), + ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0), "RegSetValueExW failed\n"); ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)), @@ -1895,10 +1924,12 @@ static void test_Installer_RegistryValue(void) ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour); + /* Vista does not NULL-terminate this case */ memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString); ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); - ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi); + ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n", + szString, szFiveHi, lstrlenW(szFiveHi)); memset(szString, 0, sizeof(szString)); hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString); @@ -1993,7 +2024,7 @@ static void test_Installer_Products(BOOL bProductInstalled) ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED); /* Not found our product code yet? Check */ - if (!bProductFound && !lstrcmpW(szString, szProductCode)) + if (!bProductFound && !strcmp_ww(szString, szProductCode)) bProductFound = TRUE; /* IEnumVARIANT::Next */ @@ -2009,7 +2040,7 @@ static void test_Installer_Products(BOOL bProductInstalled) } } - if (bProductInstalled) todo_wine + if (bProductInstalled) { ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n", bProductInstalled ? "be" : "not be", @@ -2241,7 +2272,6 @@ static void test_Installer_InstallProduct(void) ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); - ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); ok(delete_pf("msitest", FALSE), "File not installed\n"); res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); @@ -2275,8 +2305,6 @@ static void test_Installer_InstallProduct(void) res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest"); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - check_service_is_installed(); - /* Remove registry keys written by RegisterProduct standard action */ res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}"); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); @@ -2285,12 +2313,22 @@ static void test_Installer_InstallProduct(void) ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey); - ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(res == ERROR_SUCCESS || + broken(res == ERROR_FILE_NOT_FOUND), /* win9x */ + "Expected ERROR_SUCCESS, got %d\n", res); if (res == ERROR_SUCCESS) { res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203"); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); RegCloseKey(hkey); + + res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203"); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + } + else + { + /* win9x defaults to a per-machine install. */ + RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203"); } /* Remove registry keys written by PublishProduct standard action */ @@ -2305,16 +2343,12 @@ static void test_Installer_InstallProduct(void) RegCloseKey(hkey); - res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203"); - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - /* Delete installation files we installed */ delete_test_files(); } static void test_Installer(void) { - static WCHAR szBackslash[] = { '\\',0 }; static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 }; static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 }; WCHAR szPath[MAX_PATH]; @@ -2378,8 +2412,9 @@ static void test_Installer(void) ok(len, "MultiByteToWideChar returned error %d\n", GetLastError()); if (!len) return; - lstrcatW(szPath, szBackslash); - lstrcatW(szPath, szMsifile); + /* lstrcatW does not work on win95 */ + szPath[len - 1] = '\\'; + memcpy(&szPath[len], szMsifile, sizeof(szMsifile)); /* Installer::OpenPackage */ hr = Installer_OpenPackage(szPath, 0, &pSession); @@ -2391,7 +2426,7 @@ static void test_Installer(void) } /* Installer::OpenDatabase */ - hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase); + hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase); ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr); if (hr == S_OK) { diff --git a/rostests/winetests/msi/db.c b/rostests/winetests/msi/db.c index 5d5eb08f3c8..3af113518f8 100644 --- a/rostests/winetests/msi/db.c +++ b/rostests/winetests/msi/db.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -144,6 +145,9 @@ static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec) MSIHANDLE hview = 0; UINT r, ret; + if (phrec) + *phrec = 0; + /* open a select query */ r = MsiDatabaseOpenView(hdb, query, &hview); if (r != ERROR_SUCCESS) @@ -190,6 +194,27 @@ static UINT create_component_table( MSIHANDLE hdb ) "PRIMARY KEY `Component`)" ); } +static UINT create_custom_action_table( MSIHANDLE hdb ) +{ + return run_query( hdb, 0, + "CREATE TABLE `CustomAction` ( " + "`Action` CHAR(72) NOT NULL, " + "`Type` SHORT NOT NULL, " + "`Source` CHAR(72), " + "`Target` CHAR(255) " + "PRIMARY KEY `Action`)" ); +} + +static UINT create_directory_table( MSIHANDLE hdb ) +{ + return run_query( hdb, 0, + "CREATE TABLE `Directory` ( " + "`Directory` CHAR(255) NOT NULL, " + "`Directory_Parent` CHAR(255), " + "`DefaultDir` CHAR(255) NOT NULL " + "PRIMARY KEY `Directory`)" ); +} + static UINT create_feature_components_table( MSIHANDLE hdb ) { return run_query( hdb, 0, @@ -217,69 +242,38 @@ static UINT create_binary_table( MSIHANDLE hdb ) "PRIMARY KEY `Name` )" ); } -static UINT add_component_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Component` " - "(`Component`, `ComponentId`, `Directory_`, `Attributes`, `Condition`, `KeyPath`) " - "VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, 0, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; +#define make_add_entry(type, qtext) \ + static UINT add##_##type##_##entry( MSIHANDLE hdb, const char *values ) \ + { \ + char insert[] = qtext; \ + char *query; \ + UINT sz, r; \ + sz = strlen(values) + sizeof insert; \ + query = HeapAlloc(GetProcessHeap(),0,sz); \ + sprintf(query,insert,values); \ + r = run_query( hdb, 0, query ); \ + HeapFree(GetProcessHeap(), 0, query); \ + return r; \ } -static UINT add_feature_components_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `FeatureComponents` " - "(`Feature_`, `Component_`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(component, + "INSERT INTO `Component` " + "(`Component`, `ComponentId`, `Directory_`, " + "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, 0, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(custom_action, + "INSERT INTO `CustomAction` " + "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )") -static UINT add_std_dlls_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `StdDlls` " - "(`File`, `Binary_`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(feature_components, + "INSERT INTO `FeatureComponents` " + "(`Feature_`, `Component_`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, 0, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(std_dlls, + "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )") -static UINT add_binary_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Binary` " - "(`Name`, `Data`) " - "VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, 0, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(binary, + "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )") static void test_msiinsert(void) { @@ -328,10 +322,8 @@ static void test_msiinsert(void) r = MsiRecordGetFieldCount(hrec); ok(r == 3, "record count wrong\n"); - todo_wine { r = MsiRecordIsNull(hrec, 0); ok(r == FALSE, "field 0 not null\n"); - } r = MsiRecordGetInteger(hrec, 1); ok(r == 1, "field 1 contents wrong\n"); @@ -658,7 +650,10 @@ static void test_msibadqueries(void) ok(r == ERROR_SUCCESS , "query failed\n"); r = try_query( hdb, "select * from c where b = 'x"); - todo_wine ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + + r = try_query( hdb, "select * from c where b = 'x'"); + ok(r == ERROR_SUCCESS, "query failed\n"); r = try_query( hdb, "select * from 'c'"); ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); @@ -907,10 +902,7 @@ static void test_viewmodify(void) ok(r == ERROR_SUCCESS, "failed to set string\n"); r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec); - todo_wine - { ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n"); - } r = MsiCloseHandle(hrec); ok(r == ERROR_SUCCESS, "failed to close record\n"); @@ -1079,8 +1071,8 @@ static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO ty if( r == ERROR_SUCCESS ) { MsiViewGetColumnInfo( hview, type, &rec ); - MsiViewClose(hview); } + MsiViewClose(hview); MsiCloseHandle(hview); return rec; } @@ -1110,9 +1102,8 @@ static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field) type = MsiRecordGetInteger( rec, 4 ); MsiCloseHandle( rec ); } - - MsiViewClose(hview); } + MsiViewClose(hview); MsiCloseHandle(hview); return type; } @@ -1138,7 +1129,14 @@ static void test_viewgetcolumninfo(void) r = run_query( hdb, 0, "CREATE TABLE `Properties` " - "( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" ); + "( `Property` CHAR(255), " + " `Value` CHAR(1), " + " `Intvalue` INT, " + " `Integervalue` INTEGER, " + " `Shortvalue` SHORT, " + " `Longvalue` LONG, " + " `Longcharvalue` LONGCHAR " + " PRIMARY KEY `Property`)" ); ok( r == ERROR_SUCCESS , "Failed to create table\n" ); /* check the column types */ @@ -1147,12 +1145,22 @@ static void test_viewgetcolumninfo(void) ok( check_record( rec, 1, "S255"), "wrong record type\n"); ok( check_record( rec, 2, "S1"), "wrong record type\n"); + ok( check_record( rec, 3, "I2"), "wrong record type\n"); + ok( check_record( rec, 4, "I2"), "wrong record type\n"); + ok( check_record( rec, 5, "I2"), "wrong record type\n"); + ok( check_record( rec, 6, "I4"), "wrong record type\n"); + ok( check_record( rec, 7, "S0"), "wrong record type\n"); MsiCloseHandle( rec ); /* check the type in _Columns */ ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n"); ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n"); + ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n"); + ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n"); + ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n"); + ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n"); + ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_columns table wrong\n"); /* now try the names */ rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES ); @@ -1160,6 +1168,11 @@ static void test_viewgetcolumninfo(void) ok( check_record( rec, 1, "Property"), "wrong record type\n"); ok( check_record( rec, 2, "Value"), "wrong record type\n"); + ok( check_record( rec, 3, "Intvalue"), "wrong record type\n"); + ok( check_record( rec, 4, "Integervalue"), "wrong record type\n"); + ok( check_record( rec, 5, "Shortvalue"), "wrong record type\n"); + ok( check_record( rec, 6, "Longvalue"), "wrong record type\n"); + ok( check_record( rec, 7, "Longcharvalue"), "wrong record type\n"); MsiCloseHandle( rec ); @@ -1334,6 +1347,7 @@ static void test_longstrings(void) r = MsiViewFetch(hview, &hrec); ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n"); + MsiViewClose(hview); MsiCloseHandle(hview); r = MsiRecordGetString(hrec, 2, NULL, &len); @@ -1345,18 +1359,29 @@ static void test_longstrings(void) DeleteFile(msifile); } -static void create_file(const CHAR *name) +static void create_file_data(LPCSTR name, LPCSTR data, DWORD size) { HANDLE file; DWORD written; file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name); - WriteFile(file, name, strlen(name), &written, NULL); + if (file == INVALID_HANDLE_VALUE) + return; + + WriteFile(file, data, strlen(data), &written, NULL); WriteFile(file, "\n", strlen("\n"), &written, NULL); + + if (size) + { + SetFilePointer(file, size, NULL, FILE_BEGIN); + SetEndOfFile(file); + } + CloseHandle(file); } +#define create_file(name) create_file_data(name, name, 0) + static void test_streamtable(void) { MSIHANDLE hdb = 0, rec, view; @@ -1423,6 +1448,7 @@ static void test_streamtable(void) ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r); MsiCloseHandle( rec ); + MsiViewClose( view ); MsiCloseHandle( view ); r = MsiDatabaseOpenView( hdb, @@ -1451,11 +1477,190 @@ static void test_streamtable(void) r = MsiViewFetch( view, &rec ); ok( r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + MsiViewClose( view ); MsiCloseHandle( view ); MsiCloseHandle( hdb ); DeleteFile(msifile); } +static void test_binary(void) +{ + MSIHANDLE hdb = 0, rec; + char file[MAX_PATH]; + char buf[MAX_PATH]; + DWORD size; + LPCSTR query; + UINT r; + + /* insert a file into the Binary table */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb ); + ok( r == ERROR_SUCCESS , "Failed to open database\n" ); + + query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT PRIMARY KEY `Name`, `ID`)"; + r = run_query( hdb, 0, query ); + ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r ); + + create_file( "test.txt" ); + rec = MsiCreateRecord( 1 ); + r = MsiRecordSetStream( rec, 1, "test.txt" ); + ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r); + DeleteFile( "test.txt" ); + + query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )"; + r = run_query( hdb, rec, query ); + ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r ); + + r = MsiCloseHandle( rec ); + ok( r == ERROR_SUCCESS , "Failed to close record handle\n" ); + + r = MsiDatabaseCommit( hdb ); + ok( r == ERROR_SUCCESS , "Failed to commit database\n" ); + + r = MsiCloseHandle( hdb ); + ok( r == ERROR_SUCCESS , "Failed to close database\n" ); + + /* read file from the Stream table */ + r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb ); + ok( r == ERROR_SUCCESS , "Failed to open database\n" ); + + query = "SELECT * FROM `_Streams`"; + r = do_query( hdb, query, &rec ); + ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r ); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, file, &size ); + ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r ); + ok( !lstrcmp(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file ); + + size = MAX_PATH; + memset( buf, 0, MAX_PATH ); + r = MsiRecordReadStream( rec, 2, buf, &size ); + ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r ); + ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf ); + + r = MsiCloseHandle( rec ); + ok( r == ERROR_SUCCESS , "Failed to close record handle\n" ); + + /* read file from the Binary table */ + query = "SELECT * FROM `Binary`"; + r = do_query( hdb, query, &rec ); + ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r ); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, file, &size ); + ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r ); + ok( !lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file ); + + size = MAX_PATH; + memset( buf, 0, MAX_PATH ); + r = MsiRecordReadStream( rec, 3, buf, &size ); + ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r ); + ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf ); + + r = MsiCloseHandle( rec ); + ok( r == ERROR_SUCCESS , "Failed to close record handle\n" ); + + r = MsiCloseHandle( hdb ); + ok( r == ERROR_SUCCESS , "Failed to close database\n" ); + + DeleteFile( msifile ); +} + +static void test_where_not_in_selected(void) +{ + MSIHANDLE hdb = 0, rec, view; + LPCSTR query; + UINT r; + + hdb = create_db(); + ok( hdb, "failed to create db\n"); + + r = run_query(hdb, 0, + "CREATE TABLE `IESTable` (" + "`Action` CHAR(64), " + "`Condition` CHAR(64), " + "`Sequence` LONG PRIMARY KEY `Sequence`)"); + ok( r == S_OK, "Cannot create IESTable table: %d\n", r); + + r = run_query(hdb, 0, + "CREATE TABLE `CATable` (" + "`Action` CHAR(64), " + "`Type` LONG PRIMARY KEY `Type`)"); + ok( r == S_OK, "Cannot create CATable table: %d\n", r); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'clean', 'cond4', 4)"); + ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'depends', 'cond1', 1)"); + ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'build', 'cond2', 2)"); + ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'build2', 'cond6', 6)"); + ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'build', 'cond3', 3)"); + ok(r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `CATable` " + "( `Action`, `Type` ) " + "VALUES ( 'build', 32)"); + ok(r == S_OK, "cannot add entry to CATable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `CATable` " + "( `Action`, `Type` ) " + "VALUES ( 'depends', 64)"); + ok(r == S_OK, "cannot add entry to CATable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `CATable` " + "( `Action`, `Type` ) " + "VALUES ( 'clean', 63)"); + ok(r == S_OK, "cannot add entry to CATable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `CATable` " + "( `Action`, `Type` ) " + "VALUES ( 'build2', 34)"); + ok(r == S_OK, "cannot add entry to CATable table:%d\n", r ); + query = "Select IESTable.Condition from CATable, IESTable where " + "CATable.Action = IESTable.Action and CATable.Type = 32"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r ); + + r = MsiViewExecute(view, 0); + ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r ); + + r = MsiViewFetch(view, &rec); + ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r ); + + ok( check_record( rec, 1, "cond2"), "wrong condition\n"); + + MsiCloseHandle( rec ); + r = MsiViewFetch(view, &rec); + ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r ); + + ok( check_record( rec, 1, "cond3"), "wrong condition\n"); + + MsiCloseHandle( rec ); + MsiViewClose(view); + MsiCloseHandle(view); + + MsiCloseHandle( hdb ); + DeleteFile(msifile); + +} + + static void test_where(void) { MSIHANDLE hdb = 0, rec, view; @@ -1602,6 +1807,24 @@ static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r" "a\tb\tc\td\te\tf\n" "g\th\ti\tj\tk\tl\r\n"; +static const CHAR suminfo[] = "PropertyId\tValue\n" + "i2\tl255\n" + "_SummaryInformation\tPropertyId\n" + "1\t1252\n" + "2\tInstaller Database\n" + "3\tInstaller description\n" + "4\tWineHQ\n" + "5\tInstaller\n" + "6\tInstaller comments\n" + "7\tIntel;1033\n" + "9\t{12345678-1234-1234-1234-123456789012}\n" + "12\t2009/04/12 15:46:11\n" + "13\t2009/04/12 15:46:11\n" + "14\t200\n" + "15\t2\n" + "18\tVim\n" + "19\t2\n"; + static void write_file(const CHAR *filename, const char *data, int data_size) { DWORD size; @@ -1624,6 +1847,128 @@ static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data) return r; } +static void test_suminfo_import(void) +{ + MSIHANDLE hdb, hsi, view = 0; + LPCSTR query; + UINT r, count, size, type; + char str_value[50]; + INT int_value; + FILETIME ft_value; + + GetCurrentDirectoryA(MAX_PATH, CURR_DIR); + + r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + r = add_table_to_db(hdb, suminfo); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + /* _SummaryInformation is not imported as a regular table... */ + + query = "SELECT * FROM `_SummaryInformation`"; + r = MsiDatabaseOpenViewA(hdb, query, &view); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r); + MsiCloseHandle(view); + + /* ...its data is added to the special summary information stream */ + + r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + r = MsiSummaryInfoGetPropertyCount(hsi, &count); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(count == 14, "Expected 14, got %u\n", count); + + r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_I2, "Expected VT_I2, got %u\n", type); + ok(int_value == 1252, "Expected 1252, got %d\n", int_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(size == 18, "Expected 18, got %u\n", size); + ok(!strcmp(str_value, "Installer Database"), + "Expected \"Installer Database\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Installer description"), + "Expected \"Installer description\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "WineHQ"), + "Expected \"WineHQ\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Installer"), + "Expected \"Installer\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Installer comments"), + "Expected \"Installer comments\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Intel;1033"), + "Expected \"Intel;1033\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"), + "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value); + + r = MsiSummaryInfoGetPropertyA(hsi, PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type); + + r = MsiSummaryInfoGetPropertyA(hsi, PID_LASTSAVE_DTM, &type, NULL, &ft_value, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type); + + r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_I4, "Expected VT_I4, got %u\n", type); + ok(int_value == 200, "Expected 200, got %d\n", int_value); + + r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_I4, "Expected VT_I4, got %u\n", type); + ok(int_value == 2, "Expected 2, got %d\n", int_value); + + r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_I4, "Expected VT_I4, got %u\n", type); + ok(int_value == 2, "Expected 2, got %d\n", int_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value); + + MsiCloseHandle(hsi); + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + static void test_msiimport(void) { MSIHANDLE hdb, view, rec; @@ -1712,6 +2057,7 @@ static void test_msiimport(void) ok(i == -2147483640, "Expected -2147483640, got %d\n", i); MsiCloseHandle(rec); + MsiViewClose(view); MsiCloseHandle(view); query = "SELECT * FROM `TwoPrimary`"; @@ -1829,6 +2175,63 @@ static void test_msiimport(void) DeleteFileA(msifile); } +static const CHAR bin_import_dat[] = "Name\tData\r\n" + "s72\tV0\r\n" + "Binary\tName\r\n" + "filename1\tfilename1.ibd\r\n"; + +static void test_binary_import(void) +{ + MSIHANDLE hdb = 0, rec; + char file[MAX_PATH]; + char buf[MAX_PATH]; + char path[MAX_PATH]; + DWORD size; + LPCSTR query; + UINT r; + + /* create files to import */ + write_file("bin_import.idt", bin_import_dat, + (sizeof(bin_import_dat) - 1) * sizeof(char)); + CreateDirectory("bin_import", NULL); + create_file_data("bin_import/filename1.ibd", "just some words", 15); + + /* import files into database */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok( r == ERROR_SUCCESS , "Failed to open database\n"); + + GetCurrentDirectory(MAX_PATH, path); + r = MsiDatabaseImport(hdb, path, "bin_import.idt"); + ok(r == ERROR_SUCCESS , "Failed to import Binary table\n"); + + /* read file from the Binary table */ + query = "SELECT * FROM `Binary`"; + r = do_query(hdb, query, &rec); + ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetString(rec, 1, file, &size); + ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r); + ok(!lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file); + + size = MAX_PATH; + memset(buf, 0, MAX_PATH); + r = MsiRecordReadStream(rec, 2, buf, &size); + ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r); + ok(!lstrcmp(buf, "just some words"), + "Expected 'just some words', got %s\n", buf); + + r = MsiCloseHandle(rec); + ok(r == ERROR_SUCCESS , "Failed to close record handle\n"); + + r = MsiCloseHandle(hdb); + ok(r == ERROR_SUCCESS , "Failed to close database\n"); + + DeleteFile("bin_import/filename1.ibd"); + RemoveDirectory("bin_import"); + DeleteFile("bin_import.idt"); +} + static void test_markers(void) { MSIHANDLE hdb, rec; @@ -2040,6 +2443,7 @@ static void test_handle_limit(void) for (i=0; i | D | C | A | E | B | + * --------------------- --------------------- + * + * set primary key `E` + * --------------------- --------------------- + * | D | C | A | E | B | -> | D | E | A | C | B | + * --------------------- --------------------- + */ + + query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, " + "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL " + "PRIMARY KEY `D`, `E`)"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `T`"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 4, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 5, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 4, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 5, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + MsiViewClose(view); + MsiCloseHandle(view); + + query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) " + "VALUES ( 1, 2, 'a', 3, 'bc' )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `T`"; + r = do_query(hdb, query, &rec); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 3, "Expected 3, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 4); + ok(r == 2, "Expected 2, got %d\n", r); + + r = MsiRecordGetInteger(rec, 5); + ok(r == 1, "Expected 1, got %d\n", r); + + MsiCloseHandle(rec); + + query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(view, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 1, "Expected 1, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 2, "Expected 2, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 3, "Expected 3, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 4, "Expected 4, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 5, "Expected 5, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(view); + MsiCloseHandle(view); + + query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, " + "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL " + "PRIMARY KEY `C`, `A`, `D`)"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `Z`"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 4, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 5, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 4, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 5, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + MsiViewClose(view); + MsiCloseHandle(view); + + query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) " + "VALUES ( 1, 2, 'a', 3, 'bc' )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `Z`"; + r = do_query(hdb, query, &rec); + + r = MsiRecordGetInteger(rec, 1); + ok(r == 2, "Expected 2, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 4); + ok(r == 3, "Expected 3, got %d\n", r); + + r = MsiRecordGetInteger(rec, 5); + ok(r == 1, "Expected 1, got %d\n", r); + + MsiCloseHandle(rec); + + query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(view, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 1, "Expected 1, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 2, "Expected 2, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 3, "Expected 3, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 4, "Expected 4, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 5, "Expected 5, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(view); + MsiCloseHandle(view); + + MsiCloseHandle(hdb); + DeleteFileA(msifile); } START_TEST(db) @@ -6126,8 +8618,11 @@ START_TEST(db) test_msiexport(); test_longstrings(); test_streamtable(); + test_binary(); + test_where_not_in_selected(); test_where(); test_msiimport(); + test_binary_import(); test_markers(); test_handle_limit(); test_try_transform(); @@ -6137,8 +8632,11 @@ START_TEST(db) test_integers(); test_update(); test_special_tables(); + test_tables_order(); + test_rows_order(); test_select_markers(); test_viewmodify_update(); + test_viewmodify_assign(); test_stringtable(); test_viewmodify_delete(); test_defaultdatabase(); @@ -6152,4 +8650,11 @@ START_TEST(db) test_viewmodify_refresh(); test_where_viewmodify(); test_storages_table(); + test_dbtopackage(); + test_droptable(); + test_dbmerge(); + test_select_with_tablenames(); + test_insertorder(); + test_columnorder(); + test_suminfo_import(); } diff --git a/rostests/winetests/msi/format.c b/rostests/winetests/msi/format.c index 00d3856c820..2d949e358e6 100644 --- a/rostests/winetests/msi/format.c +++ b/rostests/winetests/msi/format.c @@ -108,97 +108,46 @@ static UINT create_custom_action_table( MSIHANDLE hdb ) "PRIMARY KEY `Action`)" ); } -static UINT add_feature_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Feature` (`Feature`, `Feature_Parent`, " - "`Title`, `Description`, `Display`, `Level`, `Directory_`, `Attributes`) VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; +#define make_add_entry(type, qtext) \ + static UINT add##_##type##_##entry( MSIHANDLE hdb, const char *values ) \ + { \ + char insert[] = qtext; \ + char *query; \ + UINT sz, r; \ + sz = strlen(values) + sizeof insert; \ + query = HeapAlloc(GetProcessHeap(),0,sz); \ + sprintf(query,insert,values); \ + r = run_query( hdb, query ); \ + HeapFree(GetProcessHeap(), 0, query); \ + return r; \ } -static UINT add_component_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Component` " - "(`Component`, `ComponentId`, `Directory_`, `Attributes`, `Condition`, `KeyPath`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(feature, + "INSERT INTO `Feature` " + "(`Feature`, `Feature_Parent`, `Title`, `Description`, " + "`Display`, `Level`, `Directory_`, `Attributes`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(component, + "INSERT INTO `Component` " + "(`Component`, `ComponentId`, `Directory_`, " + "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )") -static UINT add_feature_components_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `FeatureComponents` " - "(`Feature_`, `Component_`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(feature_components, + "INSERT INTO `FeatureComponents` " + "(`Feature_`, `Component_`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(file, + "INSERT INTO `File` " + "(`File`, `Component_`, `FileName`, `FileSize`, " + "`Version`, `Language`, `Attributes`, `Sequence`) VALUES( %s )") -static UINT add_file_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `File` " - "(`File`, `Component_`, `FileName`, `FileSize`, `Version`, `Language`, `Attributes`, `Sequence`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(directory, + "INSERT INTO `Directory` " + "(`Directory`,`Directory_Parent`,`DefaultDir`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} - -static UINT add_directory_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Directory` (`Directory`,`Directory_Parent`,`DefaultDir`) VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} - -static UINT add_custom_action_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, " - "`Target`) VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(custom_action, + "INSERT INTO `CustomAction` " + "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )") static UINT set_summary_info(MSIHANDLE hdb) { @@ -279,7 +228,7 @@ static MSIHANDLE package_from_db(MSIHANDLE hdb) CHAR szPackage[10]; MSIHANDLE hPackage; - sprintf(szPackage,"#%li",hdb); + sprintf(szPackage,"#%i",hdb); res = MsiOpenPackage(szPackage,&hPackage); ok( res == ERROR_SUCCESS , "Failed to open package\n" ); @@ -354,7 +303,7 @@ static MSIHANDLE helper_createpackage( const char *szName ) res = MsiCloseHandle( suminfo); ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" ); - sprintf(szPackage,"#%li",hdb); + sprintf(szPackage,"#%i",hdb); res = MsiOpenPackage(szPackage,&hPackage); ok( res == ERROR_SUCCESS , "Failed to open package\n" ); @@ -2412,12 +2361,14 @@ static void test_formatrecord_tables(void) /* component with INSTALLSTATE_SOURCE */ lstrcpy( expected, "1: " ); lstrcat( expected, curr_dir ); + if (strlen(curr_dir) > 3) lstrcat( expected, "\\ " ); + lstrcat( expected, " " ); size = MAX_PATH; MsiRecordSetString( hrec, 1, "[$parietal]" ); r = MsiFormatRecord( hpkg, hrec, buf, &size ); ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); - ok( !lstrcmp( buf, expected ), "Expected '%s', got %s\n", expected, buf); + ok( !lstrcmp( buf, expected ), "Expected '%s', got '%s'\n", expected, buf); sprintf( buf, "%sI am a really long directory\\temporal.txt", root ); DeleteFile( buf ); diff --git a/rostests/winetests/msi/install.c b/rostests/winetests/msi/install.c index 8fa729a0833..9c5d777d13f 100644 --- a/rostests/winetests/msi/install.c +++ b/rostests/winetests/msi/install.c @@ -29,16 +29,27 @@ #include #include #include +#include #include "wine/test.h" static UINT (WINAPI *pMsiQueryComponentStateA) (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR, INSTALLSTATE*); +static UINT (WINAPI *pMsiSetExternalUIRecord) + (INSTALLUI_HANDLER_RECORD, DWORD, LPVOID, PINSTALLUI_HANDLER_RECORD); static UINT (WINAPI *pMsiSourceListEnumSourcesA) (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPSTR, LPDWORD); static UINT (WINAPI *pMsiSourceListGetInfoA) (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD); +static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*); + +static HMODULE hsrclient = 0; +static BOOL (WINAPI *pSRRemoveRestorePoint)(DWORD); +static BOOL (WINAPI *pSRSetRestorePointA)(RESTOREPOINTINFOA*, STATEMGRSTATUS*); + +static BOOL on_win9x = FALSE; + static const char *msifile = "msitest.msi"; static const char *msifile2 = "winetest2.msi"; static const char *mstfile = "winetest.mst"; @@ -53,7 +64,7 @@ static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttribu "Component\tComponent\n" "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n" "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n" - "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n" + "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\tNOT REINSTALL\tone.txt\n" "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n" "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n" "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n" @@ -115,6 +126,8 @@ static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n" "MoveFiles\t\t1700\n" "InstallFiles\t\t4000\n" "DuplicateFiles\t\t4500\n" + "WriteEnvironmentStrings\t\t4550\n" + "CreateShortcuts\t\t4600\n" "InstallServices\t\t5000\n" "InstallFinalize\t\t6600\n" "InstallInitialize\t\t1500\n" @@ -150,6 +163,98 @@ static const CHAR property_dat[] = "Property\tValue\n" "SERVNAME\tTestService\n" "SERVDISP\tTestServiceDisp\n"; +static const CHAR shortcut_dat[] = "Shortcut\tDirectory_\tName\tComponent_\tTarget\tArguments\tDescription\tHotkey\tIcon_\tIconIndex\tShowCmd\tWkDir\n" + "s72\ts72\tl128\ts72\ts72\tS255\tL255\tI2\tS72\tI2\tI2\tS72\n" + "Shortcut\tShortcut\n" + "Shortcut\tMSITESTDIR\tShortcut\tcomponent\tShortcut\t\tShortcut\t\t\t\t\t\n"; + +static const CHAR environment_dat[] = "Environment\tName\tValue\tComponent_\n" + "s72\tl255\tL255\ts72\n" + "Environment\tEnvironment\n" + "Var1\t=-MSITESTVAR1\t1\tOne\n" + "Var2\tMSITESTVAR2\t1\tOne\n" + "Var3\t=-MSITESTVAR3\t1\tOne\n" + "Var4\tMSITESTVAR4\t1\tOne\n" + "Var5\t-MSITESTVAR5\t\tOne\n" + "Var6\tMSITESTVAR6\t\tOne\n" + "Var7\t!-MSITESTVAR7\t\tOne\n" + "Var8\t!-*MSITESTVAR8\t\tOne\n" + "Var9\t=-MSITESTVAR9\t\tOne\n" + "Var10\t=MSITESTVAR10\t\tOne\n"; + +static const CHAR condition_dat[] = "Feature_\tLevel\tCondition\n" + "s38\ti2\tS255\n" + "Condition\tFeature_\tLevel\n" + "One\t4\t1\n"; + +static const CHAR up_property_dat[] = "Property\tValue\n" + "s72\tl0\n" + "Property\tProperty\n" + "DefaultUIFont\tDlgFont8\n" + "HASUIRUN\t0\n" + "INSTALLLEVEL\t3\n" + "InstallMode\tTypical\n" + "Manufacturer\tWine\n" + "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n" + "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n" + "ProductID\tnone\n" + "ProductLanguage\t1033\n" + "ProductName\tMSITEST\n" + "ProductVersion\t1.1.1\n" + "PROMPTROLLBACKCOST\tP\n" + "Setup\tSetup\n" + "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n" + "AdminProperties\tPOSTADMIN\n" + "ROOTDRIVE\tC:\\\n" + "SERVNAME\tTestService\n" + "SERVDISP\tTestServiceDisp\n" + "RemovePreviousVersions\t1\n"; + +static const CHAR up2_property_dat[] = "Property\tValue\n" + "s72\tl0\n" + "Property\tProperty\n" + "DefaultUIFont\tDlgFont8\n" + "HASUIRUN\t0\n" + "INSTALLLEVEL\t3\n" + "InstallMode\tTypical\n" + "Manufacturer\tWine\n" + "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n" + "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n" + "ProductID\tnone\n" + "ProductLanguage\t1033\n" + "ProductName\tMSITEST\n" + "ProductVersion\t1.1.2\n" + "PROMPTROLLBACKCOST\tP\n" + "Setup\tSetup\n" + "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n" + "AdminProperties\tPOSTADMIN\n" + "ROOTDRIVE\tC:\\\n" + "SERVNAME\tTestService\n" + "SERVDISP\tTestServiceDisp\n"; + +static const CHAR up3_property_dat[] = "Property\tValue\n" + "s72\tl0\n" + "Property\tProperty\n" + "DefaultUIFont\tDlgFont8\n" + "HASUIRUN\t0\n" + "INSTALLLEVEL\t3\n" + "InstallMode\tTypical\n" + "Manufacturer\tWine\n" + "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n" + "ProductCode\t{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}\n" + "ProductID\tnone\n" + "ProductLanguage\t1033\n" + "ProductName\tMSITEST\n" + "ProductVersion\t1.1.2\n" + "PROMPTROLLBACKCOST\tP\n" + "Setup\tSetup\n" + "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n" + "AdminProperties\tPOSTADMIN\n" + "ROOTDRIVE\tC:\\\n" + "SERVNAME\tTestService\n" + "SERVDISP\tTestServiceDisp\n" + "RemovePreviousVersions\t1\n"; + static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n" "s72\ti2\tl255\tL255\tL0\ts72\n" "Registry\tRegistry\n" @@ -304,6 +409,21 @@ static const CHAR rof_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\t "Media\tDiskId\n" "1\t1\t\t\tDISK1\t\n"; +static const CHAR rofc_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" + "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" + "File\tFile\n" + "maximus\tmaximus\tmaximus\t500\t\t\t16384\t1"; + +static const CHAR rofc_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n" + "i2\ti4\tL64\tS255\tS32\tS72\n" + "Media\tDiskId\n" + "1\t1\t\ttest1.cab\tDISK1\t\n"; + +static const CHAR lus2_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n" + "i2\ti4\tL64\tS255\tS32\tS72\n" + "Media\tDiskId\n" + "1\t1\t\t#test1.cab\tDISK1\t\n"; + static const CHAR sdp_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" "s72\tS255\tI2\n" "InstallExecuteSequence\tAction\n" @@ -439,6 +559,30 @@ static const CHAR pp_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" "PublishProduct\tPUBLISH_PRODUCT=1 Or FULL=1\t6400\n" "InstallFinalize\t\t6600"; +static const CHAR ppc_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" + "s72\tS38\ts72\ti2\tS255\tS72\n" + "Component\tComponent\n" + "maximus\t{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}\tMSITESTDIR\t0\tUILevel=5\tmaximus\n" + "augustus\t{5AD3C142-CEF8-490D-B569-784D80670685}\tMSITESTDIR\t1\t\taugustus\n"; + +static const CHAR ppc_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" + "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" + "File\tFile\n" + "maximus\tmaximus\tmaximus\t500\t\t\t8192\t1\n" + "augustus\taugustus\taugustus\t500\t\t\t8192\t2"; + +static const CHAR ppc_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n" + "i2\ti4\tL64\tS255\tS32\tS72\n" + "Media\tDiskId\n" + "1\t2\t\t\tDISK1\t\n"; + +static const CHAR ppc_feature_comp_dat[] = "Feature_\tComponent_\n" + "s38\ts72\n" + "FeatureComponents\tFeature_\tComponent_\n" + "feature\tmaximus\n" + "feature\taugustus\n" + "montecristo\tmaximus"; + static const CHAR tp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" "s72\tS38\ts72\ti2\tS255\tS72\n" "Component\tComponent\n" @@ -475,7 +619,7 @@ static const CHAR adm_admin_exec_seq_dat[] = "Action\tCondition\tSequence\n" static const CHAR amp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" "s72\tS38\ts72\ti2\tS255\tS72\n" "Component\tComponent\n" - "augustus\t\tMSITESTDIR\t0\tMYPROP=2718\taugustus\n"; + "augustus\t\tMSITESTDIR\t0\tMYPROP=2718 and MyProp=42\taugustus\n"; static const CHAR rem_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" "s72\tS38\ts72\ti2\tS255\tS72\n" @@ -527,7 +671,8 @@ static const CHAR rem_remove_files_dat[] = "FileKey\tComponent_\tFileName\tDirPr "attoparsec\tlithium\tattoparsec\tMSITESTDIR\t2\n" "storeys\thydrogen\tstoreys\tMSITESTDIR\t3\n" "block\thelium\tblock\tMSITESTDIR\t3\n" - "siriometer\tlithium\tsiriometer\tMSITESTDIR\t3\n"; + "siriometer\tlithium\tsiriometer\tMSITESTDIR\t3\n" + "nanoacre\thydrogen\t\tCABOUTDIR\t3\n"; static const CHAR mov_move_file_dat[] = "FileKey\tComponent_\tSourceName\tDestName\tSourceFolder\tDestFolder\tOptions\n" "s72\ts72\tS255\tS255\tS72\ts72\ti2\n" @@ -545,6 +690,7 @@ static const CHAR mov_move_file_dat[] = "FileKey\tComponent_\tSourceName\tDestNa "kazakhstan\taugustus\t\tkiribati\tFILEPATHGOOD\tMSITESTDIR\t1\n" "laos\taugustus\tlatvia\tlebanon\tSourceDir\tMSITESTDIR\t1\n" "namibia\taugustus\tnauru\tkiribati\tSourceDir\tMSITESTDIR\t1\n" + "pakistan\taugustus\tperu\tsfn|poland\tSourceDir\tMSITESTDIR\t1\n" "wildcard\taugustus\tapp*\twildcard\tSourceDir\tMSITESTDIR\t1\n" "single\taugustus\tf?o\tsingle\tSourceDir\tMSITESTDIR\t1\n" "wildcardnodest\taugustus\tbudd*\t\tSourceDir\tMSITESTDIR\t1\n" @@ -617,7 +763,9 @@ static const CHAR ca51_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" "GoodSetProperty\t\t725\n" "BadSetProperty\t\t750\n" "CostInitialize\t\t800\n" + "ResolveSource\t\t810\n" "FileCost\t\t900\n" + "SetSourceDir\tSRCDIR\t910\n" "CostFinalize\t\t1000\n" "InstallValidate\t\t1400\n" "InstallInitialize\t\t1500\n" @@ -628,7 +776,8 @@ static const CHAR ca51_custom_action_dat[] = "Action\tType\tSource\tTarget\n" "s72\ti2\tS64\tS0\n" "CustomAction\tAction\n" "GoodSetProperty\t51\tMYPROP\t42\n" - "BadSetProperty\t51\t\tMYPROP\n"; + "BadSetProperty\t51\t\tMYPROP\n" + "SetSourceDir\t51\tSourceDir\t[SRCDIR]\n"; static const CHAR is_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n" "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n" @@ -691,6 +840,112 @@ static const CHAR is_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tV "Media\tDiskId\n" "1\t12\t\t\tDISK1\t\n"; +static const CHAR sp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" + "s72\tS38\ts72\ti2\tS255\tS72\n" + "Component\tComponent\n" + "augustus\t\tTWODIR\t0\t\taugustus\n"; + +static const CHAR sp_directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n" + "s72\tS72\tl255\n" + "Directory\tDirectory\n" + "TARGETDIR\t\tSourceDir\n" + "ProgramFilesFolder\tTARGETDIR\t.\n" + "MSITESTDIR\tProgramFilesFolder\tmsitest:.\n" + "ONEDIR\tMSITESTDIR\t.:shortone|longone\n" + "TWODIR\tONEDIR\t.:shorttwo|longtwo"; + +static const CHAR mcp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" + "s72\tS38\ts72\ti2\tS255\tS72\n" + "Component\tComponent\n" + "hydrogen\t{C844BD1E-1907-4C00-8BC9-150BD70DF0A1}\tMSITESTDIR\t2\t\thydrogen\n" + "helium\t{5AD3C142-CEF8-490D-B569-784D80670685}\tMSITESTDIR\t2\t\thelium\n" + "lithium\t{4AF28FFC-71C7-4307-BDE4-B77C5338F56F}\tMSITESTDIR\t2\tPROPVAR=42\tlithium\n"; + +static const CHAR mcp_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n" + "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n" + "Feature\tFeature\n" + "hydroxyl\t\thydroxyl\thydroxyl\t2\t1\tTARGETDIR\t0\n" + "heliox\t\theliox\theliox\t2\t5\tTARGETDIR\t0\n" + "lithia\t\tlithia\tlithia\t2\t10\tTARGETDIR\t0"; + +static const CHAR mcp_feature_comp_dat[] = "Feature_\tComponent_\n" + "s38\ts72\n" + "FeatureComponents\tFeature_\tComponent_\n" + "hydroxyl\thydrogen\n" + "heliox\thelium\n" + "lithia\tlithium"; + +static const CHAR mcomp_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" + "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" + "File\tFile\n" + "hydrogen\thydrogen\thydrogen\t0\t\t\t8192\t1\n" + "helium\thelium\thelium\t0\t\t\t8192\t1\n" + "lithium\tlithium\tlithium\t0\t\t\t8192\t1\n" + "beryllium\tmissingcomp\tberyllium\t0\t\t\t8192\t1"; + +static const CHAR ai_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" + "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" + "File\tFile\n" + "five.txt\tFive\tfive.txt\t1000\t\t\t16384\t5\n" + "four.txt\tFour\tfour.txt\t1000\t\t\t16384\t4\n" + "one.txt\tOne\tone.txt\t1000\t\t\t16384\t1\n" + "three.txt\tThree\tthree.txt\t1000\t\t\t16384\t3\n" + "two.txt\tTwo\ttwo.txt\t1000\t\t\t16384\t2\n" + "file\tcomponent\tfilename\t100\t\t\t8192\t1\n" + "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1"; + +static const CHAR ip_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" + "s72\tS255\tI2\n" + "InstallExecuteSequence\tAction\n" + "CostFinalize\t\t1000\n" + "ValidateProductID\t\t700\n" + "CostInitialize\t\t800\n" + "FileCost\t\t900\n" + "RemoveFiles\t\t3500\n" + "InstallFiles\t\t4000\n" + "RegisterUser\t\t6000\n" + "RegisterProduct\t\t6100\n" + "PublishFeatures\t\t6300\n" + "PublishProduct\t\t6400\n" + "InstallFinalize\t\t6600\n" + "InstallInitialize\t\t1500\n" + "ProcessComponents\t\t1600\n" + "UnpublishFeatures\t\t1800\n" + "InstallValidate\t\t1400\n" + "LaunchConditions\t\t100\n" + "TestInstalledProp\tInstalled AND NOT REMOVE\t950\n"; + +static const CHAR ip_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n" + "s72\ti2\tS64\tS0\tS255\n" + "CustomAction\tAction\n" + "TestInstalledProp\t19\t\tTest failed\t\n"; + +static const CHAR aup_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" + "s72\tS255\tI2\n" + "InstallExecuteSequence\tAction\n" + "CostFinalize\t\t1000\n" + "ValidateProductID\t\t700\n" + "CostInitialize\t\t800\n" + "FileCost\t\t900\n" + "RemoveFiles\t\t3500\n" + "InstallFiles\t\t4000\n" + "RegisterUser\t\t6000\n" + "RegisterProduct\t\t6100\n" + "PublishFeatures\t\t6300\n" + "PublishProduct\t\t6400\n" + "InstallFinalize\t\t6600\n" + "InstallInitialize\t\t1500\n" + "ProcessComponents\t\t1600\n" + "UnpublishFeatures\t\t1800\n" + "InstallValidate\t\t1400\n" + "LaunchConditions\t\t100\n" + "TestAllUsersProp\tALLUSERS AND NOT REMOVE\t50\n"; + +static const CHAR aup_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n" + "s72\ti2\tS64\tS0\tS255\n" + "CustomAction\tAction\n" + "TestAllUsersProp\t19\t\tTest failed\t\n"; + typedef struct _msi_table { const CHAR *filename; @@ -715,6 +970,150 @@ static const msi_table tables[] = ADD_TABLE(service_control) }; +static const msi_table sc_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(property), + ADD_TABLE(shortcut) +}; + +static const msi_table ps_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(property), + ADD_TABLE(condition) +}; + +static const msi_table env_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(property), + ADD_TABLE(environment) +}; + +static const msi_table up_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(up_property), + ADD_TABLE(registry), + ADD_TABLE(service_install), + ADD_TABLE(service_control) +}; + +static const msi_table up2_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(up2_property), + ADD_TABLE(registry), + ADD_TABLE(service_install), + ADD_TABLE(service_control) +}; + +static const msi_table up3_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(up3_property), + ADD_TABLE(registry), + ADD_TABLE(service_install), + ADD_TABLE(service_control) +}; + +static const msi_table up4_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(property), + ADD_TABLE(registry), + ADD_TABLE(service_install), + ADD_TABLE(service_control) +}; + +static const msi_table up5_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(up_property), + ADD_TABLE(registry), + ADD_TABLE(service_install), + ADD_TABLE(service_control) +}; + +static const msi_table up6_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(up2_property), + ADD_TABLE(registry), + ADD_TABLE(service_install), + ADD_TABLE(service_control) +}; + +static const msi_table up7_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(up3_property), + ADD_TABLE(registry), + ADD_TABLE(service_install), + ADD_TABLE(service_control) +}; + static const msi_table cc_tables[] = { ADD_TABLE(cc_component), @@ -813,6 +1212,18 @@ static const msi_table rof_tables[] = ADD_TABLE(property), }; +static const msi_table rofc_tables[] = +{ + ADD_TABLE(rof_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(rof_feature_comp), + ADD_TABLE(rofc_file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(rofc_media), + ADD_TABLE(property), +}; + static const msi_table sdp_tables[] = { ADD_TABLE(rof_component), @@ -889,6 +1300,54 @@ static const msi_table pp_tables[] = ADD_TABLE(property), }; +static const msi_table ppc_tables[] = +{ + ADD_TABLE(ppc_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(ppc_feature_comp), + ADD_TABLE(ppc_file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(ppc_media), + ADD_TABLE(property), +}; + +static const msi_table lus0_tables[] = +{ + ADD_TABLE(ci_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(rof_feature_comp), + ADD_TABLE(rof_file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(rof_media), + ADD_TABLE(property), +}; + +static const msi_table lus1_tables[] = +{ + ADD_TABLE(ci_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(rof_feature_comp), + ADD_TABLE(rof_file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(rofc_media), + ADD_TABLE(property), +}; + +static const msi_table lus2_tables[] = +{ + ADD_TABLE(ci_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(rof_feature_comp), + ADD_TABLE(rof_file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(lus2_media), + ADD_TABLE(property), +}; + static const msi_table tp_tables[] = { ADD_TABLE(tp_component), @@ -1041,6 +1500,116 @@ static const msi_table is_tables[] = ADD_TABLE(property), }; +static const msi_table sp_tables[] = +{ + ADD_TABLE(sp_component), + ADD_TABLE(sp_directory), + ADD_TABLE(rof_feature), + ADD_TABLE(ci2_feature_comp), + ADD_TABLE(ci2_file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(rof_media), + ADD_TABLE(property), +}; + +static const msi_table mcp_tables[] = +{ + ADD_TABLE(mcp_component), + ADD_TABLE(directory), + ADD_TABLE(mcp_feature), + ADD_TABLE(mcp_feature_comp), + ADD_TABLE(rem_file), + ADD_TABLE(rem_install_exec_seq), + ADD_TABLE(rof_media), + ADD_TABLE(property), +}; + +static const msi_table mcomp_tables[] = +{ + ADD_TABLE(mcp_component), + ADD_TABLE(directory), + ADD_TABLE(mcp_feature), + ADD_TABLE(mcp_feature_comp), + ADD_TABLE(mcomp_file), + ADD_TABLE(rem_install_exec_seq), + ADD_TABLE(rof_media), + ADD_TABLE(property), +}; + +static const msi_table ai_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(ai_file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(media), + ADD_TABLE(property) +}; + +static const msi_table pc_tables[] = +{ + ADD_TABLE(ca51_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(ci2_feature_comp), + ADD_TABLE(ci2_file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(rof_media), + ADD_TABLE(property) +}; + +static const msi_table ip_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(ip_install_exec_seq), + ADD_TABLE(ip_custom_action), + ADD_TABLE(media), + ADD_TABLE(property) +}; + +static const msi_table aup_tables[] = +{ + ADD_TABLE(component), + ADD_TABLE(directory), + ADD_TABLE(feature), + ADD_TABLE(feature_comp), + ADD_TABLE(file), + ADD_TABLE(aup_install_exec_seq), + ADD_TABLE(aup_custom_action), + ADD_TABLE(media), + ADD_TABLE(property) +}; + +static const msi_table fiu_tables[] = +{ + ADD_TABLE(rof_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(rof_feature_comp), + ADD_TABLE(rof_file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(rof_media), + ADD_TABLE(property), +}; + +static const msi_table fiuc_tables[] = +{ + ADD_TABLE(rof_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(rof_feature_comp), + ADD_TABLE(rofc_file), + ADD_TABLE(pp_install_exec_seq), + ADD_TABLE(rofc_media), + ADD_TABLE(property), +}; + /* cabinet definitions */ /* make the max size large so there is only one cab file */ @@ -1049,34 +1618,34 @@ static const msi_table is_tables[] = /* the FCI callbacks */ -static void *mem_alloc(ULONG cb) +static void * CDECL mem_alloc(ULONG cb) { return HeapAlloc(GetProcessHeap(), 0, cb); } -static void mem_free(void *memory) +static void CDECL mem_free(void *memory) { HeapFree(GetProcessHeap(), 0, memory); } -static BOOL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) +static BOOL CDECL get_next_cabinet(PCCAB pccab, ULONG cbPrevCab, void *pv) { sprintf(pccab->szCab, pv, pccab->iCab); return TRUE; } -static long progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) +static LONG CDECL progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv) { return 0; } -static int file_placed(PCCAB pccab, char *pszFile, long cbFile, +static int CDECL file_placed(PCCAB pccab, char *pszFile, LONG cbFile, BOOL fContinuation, void *pv) { return 0; } -static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) +static INT_PTR CDECL fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) { HANDLE handle; DWORD dwAccess = 0; @@ -1100,7 +1669,7 @@ static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv) return (INT_PTR)handle; } -static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +static UINT CDECL fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD dwRead; @@ -1112,7 +1681,7 @@ static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) return dwRead; } -static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) +static UINT CDECL fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD dwWritten; @@ -1124,7 +1693,7 @@ static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv) return dwWritten; } -static int fci_close(INT_PTR hf, int *err, void *pv) +static int CDECL fci_close(INT_PTR hf, int *err, void *pv) { HANDLE handle = (HANDLE)hf; ok(CloseHandle(handle), "Failed to CloseHandle\n"); @@ -1132,7 +1701,7 @@ static int fci_close(INT_PTR hf, int *err, void *pv) return 0; } -static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv) +static LONG CDECL fci_seek(INT_PTR hf, LONG dist, int seektype, int *err, void *pv) { HANDLE handle = (HANDLE)hf; DWORD ret; @@ -1143,7 +1712,7 @@ static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv) return ret; } -static int fci_delete(char *pszFile, int *err, void *pv) +static int CDECL fci_delete(char *pszFile, int *err, void *pv) { BOOL ret = DeleteFileA(pszFile); ok(ret, "Failed to DeleteFile %s\n", pszFile); @@ -1154,38 +1723,62 @@ static int fci_delete(char *pszFile, int *err, void *pv) static void init_functionpointers(void) { HMODULE hmsi = GetModuleHandleA("msi.dll"); + HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); -#define GET_PROC(func) \ - p ## func = (void*)GetProcAddress(hmsi, #func); \ +#define GET_PROC(mod, func) \ + p ## func = (void*)GetProcAddress(mod, #func); \ if(!p ## func) \ trace("GetProcAddress(%s) failed\n", #func); - GET_PROC(MsiQueryComponentStateA); - GET_PROC(MsiSourceListEnumSourcesA); - GET_PROC(MsiSourceListGetInfoA); + GET_PROC(hmsi, MsiQueryComponentStateA); + GET_PROC(hmsi, MsiSetExternalUIRecord); + GET_PROC(hmsi, MsiSourceListEnumSourcesA); + GET_PROC(hmsi, MsiSourceListGetInfoA); + + GET_PROC(hadvapi32, ConvertSidToStringSidA); + + hsrclient = LoadLibraryA("srclient.dll"); + GET_PROC(hsrclient, SRRemoveRestorePoint); + GET_PROC(hsrclient, SRSetRestorePointA); #undef GET_PROC } -static void get_user_sid(LPSTR *usersid) +static BOOL check_win9x(void) +{ + SC_HANDLE scm; + + scm = OpenSCManager(NULL, NULL, GENERIC_ALL); + if (!scm && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) + return TRUE; + + CloseServiceHandle(scm); + + return FALSE; +} + +static LPSTR get_user_sid(LPSTR *usersid) { HANDLE token; BYTE buf[1024]; DWORD size; PTOKEN_USER user; - HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); - static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*); + + if (!pConvertSidToStringSidA) + { + win_skip("ConvertSidToStringSidA is not available\n"); + return NULL; + } *usersid = NULL; - pConvertSidToStringSidA = (void *)GetProcAddress(hadvapi32, "ConvertSidToStringSidA"); - if (!pConvertSidToStringSidA) - return; - OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token); size = sizeof(buf); - GetTokenInformation(token, TokenUser, (void *)buf, size, &size); + GetTokenInformation(token, TokenUser, buf, size, &size); user = (PTOKEN_USER)buf; pConvertSidToStringSidA(user->User.Sid, usersid); + ok(*usersid != NULL, "pConvertSidToStringSidA failed lre=%d\n", GetLastError()); + CloseHandle(token); + return *usersid; } static BOOL check_record(MSIHANDLE rec, UINT field, LPCSTR val) @@ -1199,7 +1792,7 @@ static BOOL check_record(MSIHANDLE rec, UINT field, LPCSTR val) return (r == ERROR_SUCCESS ) && !strcmp(val, buffer); } -static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv) +static BOOL CDECL get_temp_file(char *pszTempName, int cbTempName, void *pv) { LPSTR tempname; @@ -1218,7 +1811,7 @@ static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv) return FALSE; } -static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, +static INT_PTR CDECL get_open_info(char *pszName, USHORT *pdate, USHORT *ptime, USHORT *pattribs, int *err, void *pv) { BY_HANDLE_FILE_INFORMATION finfo; @@ -1334,7 +1927,9 @@ static void create_file_data(LPCSTR name, LPCSTR data, DWORD size) DWORD written; file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name); + if (file == INVALID_HANDLE_VALUE) + return; + WriteFile(file, data, strlen(data), &written, NULL); if (size) @@ -1421,7 +2016,7 @@ static void write_file(const CHAR *filename, const char *data, int data_size) CloseHandle(hf); } -static void write_msi_summary_info(MSIHANDLE db) +static void write_msi_summary_info(MSIHANDLE db, INT wordcount) { MSIHANDLE summary; UINT r; @@ -1439,7 +2034,7 @@ static void write_msi_summary_info(MSIHANDLE db) r = MsiSummaryInfoSetPropertyA(summary, PID_PAGECOUNT, VT_I4, 100, NULL, NULL); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); - r = MsiSummaryInfoSetPropertyA(summary, PID_WORDCOUNT, VT_I4, 0, NULL, NULL); + r = MsiSummaryInfoSetPropertyA(summary, PID_WORDCOUNT, VT_I4, wordcount, NULL, NULL); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); r = MsiSummaryInfoSetPropertyA(summary, PID_TITLE, VT_LPSTR, 0, NULL, "MSITEST"); @@ -1452,7 +2047,11 @@ static void write_msi_summary_info(MSIHANDLE db) MsiCloseHandle(summary); } -static void create_database(const CHAR *name, const msi_table *tables, int num_tables) +#define create_database(name, tables, num_tables) \ + create_database_wordcount(name, tables, num_tables, 0); + +static void create_database_wordcount(const CHAR *name, const msi_table *tables, + int num_tables, INT wordcount) { MSIHANDLE db; UINT r; @@ -1474,7 +2073,7 @@ static void create_database(const CHAR *name, const msi_table *tables, int num_t DeleteFileA(table->filename); } - write_msi_summary_info(db); + write_msi_summary_info(db, wordcount); r = MsiDatabaseCommit(db); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); @@ -1500,6 +2099,27 @@ static void check_service_is_installed(void) CloseServiceHandle(scm); } +static BOOL notify_system_change(DWORD event_type, STATEMGRSTATUS *status) +{ + RESTOREPOINTINFOA spec; + + spec.dwEventType = event_type; + spec.dwRestorePtType = APPLICATION_INSTALL; + spec.llSequenceNumber = status->llSequenceNumber; + lstrcpyA(spec.szDescription, "msitest restore point"); + + return pSRSetRestorePointA(&spec, status); +} + +static void remove_restore_point(DWORD seq_number) +{ + DWORD res; + + res = pSRRemoveRestorePoint(seq_number); + if (res != ERROR_SUCCESS) + trace("Failed to remove the restore point : %08x\n", res); +} + static void test_MsiInstallProduct(void) { UINT r; @@ -1507,19 +2127,32 @@ static void test_MsiInstallProduct(void) LONG res; HKEY hkey; DWORD num, size, type; - SC_HANDLE scm; - scm = OpenSCManager(NULL, NULL, GENERIC_ALL); - if (!scm && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) + if (on_win9x) { - skip("Services are not implemented, we are most likely on win9x\n"); + win_skip("Services are not implemented on Win9x and WinMe\n"); return; } - CloseServiceHandle(scm); + + /* szPackagePath is NULL */ + r = MsiInstallProductA(NULL, "INSTALL=ALL"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* both szPackagePath and szCommandLine are NULL */ + r = MsiInstallProductA(NULL, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* szPackagePath is empty */ + r = MsiInstallProductA("", "INSTALL=ALL"); + ok(r == ERROR_PATH_NOT_FOUND, + "Expected ERROR_PATH_NOT_FOUND, got %d\n", r); create_test_files(); create_database(msifile, tables, sizeof(tables) / sizeof(msi_table)); + /* install, don't publish */ r = MsiInstallProductA(msifile, NULL); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); @@ -1560,12 +2193,215 @@ static void test_MsiInstallProduct(void) type = REG_SZ; res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path); + ok(!lstrcmpA(path, "OrderTestValue"), "Expected OrderTestValue, got %s\n", path); check_service_is_installed(); RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest"); + /* not published, reinstall */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest"); + + create_database(msifile, up_tables, sizeof(up_tables) / sizeof(msi_table)); + + /* not published, RemovePreviousVersions set */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest"); + + create_database(msifile, up2_tables, sizeof(up2_tables) / sizeof(msi_table)); + + /* not published, version number bumped */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest"); + + create_database(msifile, up3_tables, sizeof(up3_tables) / sizeof(msi_table)); + + /* not published, RemovePreviousVersions set and version number bumped */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest"); + + create_database(msifile, up4_tables, sizeof(up4_tables) / sizeof(msi_table)); + + /* install, publish product */ + r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + create_database(msifile, up4_tables, sizeof(up4_tables) / sizeof(msi_table)); + + /* published, reinstall */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + create_database(msifile, up5_tables, sizeof(up5_tables) / sizeof(msi_table)); + + /* published product, RemovePreviousVersions set */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + create_database(msifile, up6_tables, sizeof(up6_tables) / sizeof(msi_table)); + + /* published product, version number bumped */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + create_database(msifile, up7_tables, sizeof(up7_tables) / sizeof(msi_table)); + + /* published product, RemovePreviousVersions set and version number bumped */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + delete_test_files(); } @@ -1658,6 +2494,8 @@ static void test_packagecoltypes(void) MsiCloseHandle(rec); MsiCloseHandle(view); MsiCloseHandle(hdb); + CoUninitialize(); + DeleteFile(msifile); } @@ -1958,7 +2796,7 @@ static void test_readonlyfile(void) file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_READONLY, NULL); - WriteFile(file, "readonlyfile", 20, &size, NULL); + WriteFile(file, "readonlyfile", strlen("readonlyfile"), &size, NULL); CloseHandle(file); r = MsiInstallProductA(msifile, NULL); @@ -1973,6 +2811,219 @@ static void test_readonlyfile(void) DeleteFile(msifile); } +static void test_readonlyfile_cab(void) +{ + UINT r; + DWORD size; + HANDLE file; + CHAR path[MAX_PATH]; + CHAR buf[16]; + + CreateDirectoryA("msitest", NULL); + create_file("maximus", 500); + create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0"); + DeleteFile("maximus"); + + create_database(msifile, rofc_tables, sizeof(rofc_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + lstrcpy(path, PROG_FILES_DIR); + lstrcat(path, "\\msitest"); + CreateDirectory(path, NULL); + + lstrcat(path, "\\maximus"); + file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_NEW, FILE_ATTRIBUTE_READONLY, NULL); + + WriteFile(file, "readonlyfile", strlen("readonlyfile"), &size, NULL); + CloseHandle(file); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + memset( buf, 0, sizeof(buf) ); + if ((file = CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) + { + ReadFile(file, buf, sizeof(buf) - 1, &size, NULL); + CloseHandle(file); + } + ok(!memcmp( buf, "maximus", sizeof("maximus")-1 ), "Expected file to be overwritten, got '%s'\n", buf); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + /* Delete the files in the temp (current) folder */ + delete_cab_files(); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + DeleteFile(msifile); +} + +static BOOL add_cabinet_storage(LPCSTR db, LPCSTR cabinet) +{ + WCHAR dbW[MAX_PATH], cabinetW[MAX_PATH]; + IStorage *stg; + IStream *stm; + HRESULT hr; + HANDLE handle; + + MultiByteToWideChar(CP_ACP, 0, db, -1, dbW, MAX_PATH); + hr = StgOpenStorage(dbW, NULL, STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg); + if (FAILED(hr)) + return FALSE; + + MultiByteToWideChar(CP_ACP, 0, cabinet, -1, cabinetW, MAX_PATH); + hr = IStorage_CreateStream(stg, cabinetW, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm); + if (FAILED(hr)) + { + IStorage_Release(stg); + return FALSE; + } + + handle = CreateFileW(cabinetW, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (handle != INVALID_HANDLE_VALUE) + { + DWORD count; + char buffer[1024]; + if (ReadFile(handle, buffer, sizeof(buffer), &count, NULL)) + IStream_Write(stm, buffer, count, &count); + CloseHandle(handle); + } + + IStream_Release(stm); + IStorage_Release(stg); + + return TRUE; +} + +static void test_lastusedsource(void) +{ + static char prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + + UINT r; + char value[MAX_PATH], path[MAX_PATH]; + DWORD size; + + if (!pMsiSourceListGetInfoA) + { + win_skip("MsiSourceListGetInfoA is not available\n"); + return; + } + + CreateDirectoryA("msitest", NULL); + create_file("maximus", 500); + create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0"); + DeleteFile("maximus"); + + create_database("msifile0.msi", lus0_tables, sizeof(lus0_tables) / sizeof(msi_table)); + create_database("msifile1.msi", lus1_tables, sizeof(lus1_tables) / sizeof(msi_table)); + create_database("msifile2.msi", lus2_tables, sizeof(lus2_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + /* no cabinet file */ + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); + + r = MsiInstallProductA("msifile0.msi", "PUBLISH_PRODUCT=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + lstrcpyA(path, CURR_DIR); + lstrcatA(path, "\\"); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + todo_wine + { + ok(!lstrcmpA(value, path), "Expected \"%s\", got \"%s\"\n", path, value); + ok(size == lstrlenA(path), "Expected %d, got %d\n", lstrlenA(path), size); + } + + r = MsiInstallProductA("msifile0.msi", "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + /* separate cabinet file */ + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); + + r = MsiInstallProductA("msifile1.msi", "PUBLISH_PRODUCT=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + lstrcpyA(path, CURR_DIR); + lstrcatA(path, "\\"); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + todo_wine + { + ok(!lstrcmpA(value, path), "Expected \"%s\", got \"%s\"\n", path, value); + ok(size == lstrlenA(path), "Expected %d, got %d\n", lstrlenA(path), size); + } + + r = MsiInstallProductA("msifile1.msi", "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); + + /* embedded cabinet stream */ + + add_cabinet_storage("msifile2.msi", "test1.cab"); + + r = MsiInstallProductA("msifile2.msi", "PUBLISH_PRODUCT=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + todo_wine + { + ok(!lstrcmpA(value, path), "Expected \"%s\", got \"%s\"\n", path, value); + ok(size == lstrlenA(path), "Expected %d, got %d\n", lstrlenA(path), size); + } + + r = MsiInstallProductA("msifile2.msi", "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); + + /* Delete the files in the temp (current) folder */ + delete_cab_files(); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + DeleteFile("msifile0.msi"); + DeleteFile("msifile1.msi"); + DeleteFile("msifile2.msi"); +} + static void test_setdirproperty(void) { UINT r; @@ -2074,6 +3125,7 @@ static void test_setpropertyfolder(void) { UINT r; CHAR path[MAX_PATH]; + DWORD attr; lstrcpyA(path, PROG_FILES_DIR); lstrcatA(path, "\\msitest\\added"); @@ -2087,7 +3139,8 @@ static void test_setpropertyfolder(void) r = MsiInstallProductA(msifile, NULL); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); - if (GetFileAttributesA(path) == FILE_ATTRIBUTE_DIRECTORY) + attr = GetFileAttributesA(path); + if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) { ok(delete_pf("msitest\\added\\maximus", TRUE), "File not installed\n"); ok(delete_pf("msitest\\added", FALSE), "File not installed\n"); @@ -2189,6 +3242,41 @@ static void check_reg_dword(HKEY prodkey, LPCSTR name, DWORD expected, DWORD lin ok_(__FILE__, line)(val == expected, "Expected %d, got %d\n", expected, val); } +static void check_reg_dword2(HKEY prodkey, LPCSTR name, DWORD expected1, DWORD expected2, DWORD line) +{ + DWORD val, size, type; + LONG res; + + size = sizeof(DWORD); + res = RegQueryValueExA(prodkey, name, NULL, &type, (LPBYTE)&val, &size); + + if (res != ERROR_SUCCESS || type != REG_DWORD) + { + ok_(__FILE__, line)(FALSE, "Key doesn't exist or wrong type\n"); + return; + } + + ok_(__FILE__, line)(val == expected1 || val == expected2, "Expected %d or %d, got %d\n", expected1, expected2, val); +} + +static void check_reg_dword3(HKEY prodkey, LPCSTR name, DWORD expected1, DWORD expected2, DWORD expected3, DWORD line) +{ + DWORD val, size, type; + LONG res; + + size = sizeof(DWORD); + res = RegQueryValueExA(prodkey, name, NULL, &type, (LPBYTE)&val, &size); + + if (res != ERROR_SUCCESS || type != REG_DWORD) + { + ok_(__FILE__, line)(FALSE, "Key doesn't exist or wrong type\n"); + return; + } + + ok_(__FILE__, line)(val == expected1 || val == expected2 || val == expected3, + "Expected %d, %d or %d, got %d\n", expected1, expected2, expected3, val); +} + #define CHECK_REG_STR(prodkey, name, expected) \ check_reg_str(prodkey, name, expected, TRUE, __LINE__); @@ -2210,6 +3298,20 @@ static void check_reg_dword(HKEY prodkey, LPCSTR name, DWORD expected, DWORD lin check_reg_dword(prodkey, name, expected, __LINE__); \ RegDeleteValueA(prodkey, name); +#define CHECK_REG_DWORD2(prodkey, name, expected1, expected2) \ + check_reg_dword2(prodkey, name, expected1, expected2, __LINE__); + +#define CHECK_DEL_REG_DWORD2(prodkey, name, expected1, expected2) \ + check_reg_dword2(prodkey, name, expected1, expected2, __LINE__); \ + RegDeleteValueA(prodkey, name); + +#define CHECK_REG_DWORD3(prodkey, name, expected1, expected2, expected3) \ + check_reg_dword3(prodkey, name, expected1, expected2, expected3, __LINE__); + +#define CHECK_DEL_REG_DWORD3(prodkey, name, expected1, expected2, expected3) \ + check_reg_dword3(prodkey, name, expected1, expected2, expected3, __LINE__); \ + RegDeleteValueA(prodkey, name); + static void get_date_str(LPSTR date) { SYSTEMTIME systime; @@ -2239,12 +3341,8 @@ static void test_publish_registerproduct(void) static const CHAR userugkey[] = "Software\\Microsoft\\Installer\\UpgradeCodes" "\\51AAE0C44620A5E4788506E91F249BD2"; - get_user_sid(&usersid); - if (!usersid) - { - skip("ConvertSidToStringSidA is not available\n"); + if (!get_user_sid(&usersid)) return; - } get_date_str(date); GetTempPath(MAX_PATH, temp); @@ -2292,7 +3390,7 @@ static void test_publish_registerproduct(void) CHECK_DEL_REG_DWORD(hkey, "WindowsInstaller", 1); todo_wine { - CHECK_DEL_REG_DWORD(hkey, "EstimatedSize", 12); + CHECK_DEL_REG_DWORD3(hkey, "EstimatedSize", 12, -12, 4); } RegDeleteKeyA(hkey, ""); @@ -2330,7 +3428,7 @@ static void test_publish_registerproduct(void) CHECK_DEL_REG_DWORD(props, "WindowsInstaller", 1); todo_wine { - CHECK_DEL_REG_DWORD(props, "EstimatedSize", 12); + CHECK_DEL_REG_DWORD3(props, "EstimatedSize", 12, -12, 4); } RegDeleteKeyA(props, ""); @@ -2391,7 +3489,7 @@ static void test_publish_registerproduct(void) CHECK_DEL_REG_DWORD(hkey, "WindowsInstaller", 1); todo_wine { - CHECK_DEL_REG_DWORD(hkey, "EstimatedSize", 12); + CHECK_DEL_REG_DWORD3(hkey, "EstimatedSize", 12, -12, 4); } RegDeleteKeyA(hkey, ""); @@ -2429,7 +3527,7 @@ static void test_publish_registerproduct(void) CHECK_DEL_REG_DWORD(props, "WindowsInstaller", 1); todo_wine { - CHECK_DEL_REG_DWORD(props, "EstimatedSize", 12); + CHECK_DEL_REG_DWORD3(props, "EstimatedSize", 12, -12, 4); } RegDeleteKeyA(props, ""); @@ -2484,12 +3582,8 @@ static void test_publish_publishproduct(void) static const CHAR machprod[] = "Installer\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB"; static const CHAR machup[] = "Installer\\UpgradeCodes\\51AAE0C44620A5E4788506E91F249BD2"; - get_user_sid(&usersid); - if (!usersid) - { - skip("ConvertSidToStringSidA is not available\n"); + if (!get_user_sid(&usersid)) return; - } GetTempPath(MAX_PATH, temp); @@ -2680,12 +3774,8 @@ static void test_publish_publishfeatures(void) static const CHAR classfeat[] = "Software\\Classes\\Installer\\Features" "\\84A88FD7F6998CE40A22FB59F6B9C2BB"; - get_user_sid(&usersid); - if (!usersid) - { - skip("ConvertSidToStringSidA is not available\n"); + if (!get_user_sid(&usersid)) return; - } CreateDirectoryA("msitest", NULL); create_file("msitest\\maximus", 500); @@ -2842,12 +3932,8 @@ static void test_publish_registeruser(void) "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\" "UserData\\%s\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties"; - get_user_sid(&usersid); - if (!usersid) - { - skip("ConvertSidToStringSidA is not available\n"); + if (!get_user_sid(&usersid)) return; - } get_owner_company(&owner, &company); @@ -2906,6 +3992,7 @@ static void test_publish_registeruser(void) DeleteFile(msifile); DeleteFile("msitest\\maximus"); RemoveDirectory("msitest"); + LocalFree(usersid); } static void test_publish_processcomponents(void) @@ -2917,24 +4004,21 @@ static void test_publish_processcomponents(void) LPSTR usersid; CHAR val[MAX_PATH]; CHAR keypath[MAX_PATH]; + CHAR program_files_maximus[MAX_PATH]; static const CHAR keyfmt[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\" - "UserData\\%s\\Components\\CBABC2FDCCB35E749A8944D8C1C098B5"; + "UserData\\%s\\Components\\%s"; static const CHAR compkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Components"; - get_user_sid(&usersid); - if (!usersid) - { - skip("ConvertSidToStringSidA is not available\n"); + if (!get_user_sid(&usersid)) return; - } CreateDirectoryA("msitest", NULL); create_file("msitest\\maximus", 500); - create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + create_database(msifile, ppc_tables, sizeof(ppc_tables) / sizeof(msi_table)); MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); @@ -2944,7 +4028,7 @@ static void test_publish_processcomponents(void) ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); ok(delete_pf("msitest", FALSE), "File not installed\n"); - sprintf(keypath, keyfmt, usersid); + sprintf(keypath, keyfmt, usersid, "CBABC2FDCCB35E749A8944D8C1C098B5"); res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); @@ -2953,8 +4037,31 @@ static void test_publish_processcomponents(void) res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB", NULL, NULL, (LPBYTE)val, &size); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - ok(!lstrcmpA(val, "C:\\Program Files\\msitest\\maximus"), - "Expected \"%s\", got \"%s\"\n", "C:\\Program Files\\msitest\\maximus", val); + + lstrcpyA(program_files_maximus,PROG_FILES_DIR); + lstrcatA(program_files_maximus,"\\msitest\\maximus"); + + ok(!lstrcmpiA(val, program_files_maximus), + "Expected \"%s\", got \"%s\"\n", program_files_maximus, val); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + RegDeleteValueA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB"); + RegDeleteKeyA(comp, ""); + RegCloseKey(comp); + + sprintf(keypath, keyfmt, usersid, "241C3DA58FECD0945B9687D408766058"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + size = MAX_PATH; + res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB", + NULL, NULL, (LPBYTE)val, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(!lstrcmpA(val, "01\\msitest\\augustus"), + "Expected \"01\\msitest\\augustus\", got \"%s\"\n", val); res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey); ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); @@ -2969,7 +4076,7 @@ static void test_publish_processcomponents(void) ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); ok(delete_pf("msitest", FALSE), "File not installed\n"); - sprintf(keypath, keyfmt, "S-1-5-18"); + sprintf(keypath, keyfmt, "S-1-5-18", "CBABC2FDCCB35E749A8944D8C1C098B5"); res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); @@ -2978,8 +4085,27 @@ static void test_publish_processcomponents(void) res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB", NULL, NULL, (LPBYTE)val, &size); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - ok(!lstrcmpA(val, "C:\\Program Files\\msitest\\maximus"), - "Expected \"%s\", got \"%s\"\n", "C:\\Program Files\\msitest\\maximus", val); + ok(!lstrcmpiA(val, program_files_maximus), + "Expected \"%s\", got \"%s\"\n", program_files_maximus, val); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + RegDeleteValueA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB"); + RegDeleteKeyA(comp, ""); + RegCloseKey(comp); + + sprintf(keypath, keyfmt, "S-1-5-18", "241C3DA58FECD0945B9687D408766058"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + size = MAX_PATH; + res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB", + NULL, NULL, (LPBYTE)val, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(!lstrcmpA(val, "01\\msitest\\augustus"), + "Expected \"01\\msitest\\augustus\", got \"%s\"\n", val); res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey); ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); @@ -2991,6 +4117,7 @@ static void test_publish_processcomponents(void) DeleteFile(msifile); DeleteFile("msitest\\maximus"); RemoveDirectory("msitest"); + LocalFree(usersid); } static void test_publish(void) @@ -3007,7 +4134,7 @@ static void test_publish(void) if (!pMsiQueryComponentStateA) { - skip("MsiQueryComponentStateA is not available\n"); + win_skip("MsiQueryComponentStateA is not available\n"); return; } @@ -3111,7 +4238,7 @@ static void test_publish(void) CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1); todo_wine { - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); + CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12); } RegCloseKey(prodkey); @@ -3185,7 +4312,7 @@ static void test_publish(void) CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1); todo_wine { - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); + CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12); } RegCloseKey(prodkey); @@ -3193,9 +4320,9 @@ static void test_publish(void) /* no UnpublishFeatures */ r = MsiInstallProductA(msifile, "REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!pf_exists("msitest\\maximus"), "File deleted\n"); todo_wine { - ok(!pf_exists("msitest\\maximus"), "File deleted\n"); ok(!pf_exists("msitest"), "File deleted\n"); } @@ -3263,7 +4390,7 @@ static void test_publish(void) CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1); todo_wine { - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); + CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12); } RegCloseKey(prodkey); @@ -3271,7 +4398,7 @@ static void test_publish(void) /* UnpublishFeatures, only feature removed. Only works when entire product is removed */ r = MsiInstallProductA(msifile, "UNPUBLISH_FEATURES=1 REMOVE=feature"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(pf_exists("msitest\\maximus"), "File deleted\n"); + todo_wine ok(pf_exists("msitest\\maximus"), "File deleted\n"); ok(pf_exists("msitest"), "File deleted\n"); state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); @@ -3315,7 +4442,7 @@ static void test_publish(void) CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1); todo_wine { - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); + CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12); } RegCloseKey(prodkey); @@ -3367,7 +4494,7 @@ static void test_publish(void) CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1); todo_wine { - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); + CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -20); } RegCloseKey(prodkey); @@ -3375,9 +4502,9 @@ static void test_publish(void) /* UnpublishFeatures, both features removed */ r = MsiInstallProductA(msifile, "UNPUBLISH_FEATURES=1 REMOVE=feature,montecristo"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!pf_exists("msitest\\maximus"), "File not deleted\n"); todo_wine { - ok(!pf_exists("msitest\\maximus"), "File not deleted\n"); ok(!pf_exists("msitest"), "File not deleted\n"); } @@ -3445,7 +4572,7 @@ static void test_publish(void) CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1); todo_wine { - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); + CHECK_REG_DWORD2(prodkey, "EstimatedSize", 12, -12); } RegCloseKey(prodkey); @@ -3453,9 +4580,9 @@ static void test_publish(void) /* complete uninstall */ r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!pf_exists("msitest\\maximus"), "File not deleted\n"); todo_wine { - ok(!pf_exists("msitest\\maximus"), "File not deleted\n"); ok(!pf_exists("msitest"), "File not deleted\n"); } @@ -3495,7 +4622,7 @@ static void test_publishsourcelist(void) if (!pMsiSourceListEnumSourcesA || !pMsiSourceListGetInfoA) { - skip("MsiSourceListEnumSourcesA and/or MsiSourceListGetInfoA are not available\n"); + win_skip("MsiSourceListEnumSourcesA and/or MsiSourceListGetInfoA are not available\n"); return; } @@ -3512,17 +4639,21 @@ static void test_publishsourcelist(void) ok(pf_exists("msitest"), "File not installed\n"); /* nothing published */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size); + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); @@ -3530,17 +4661,21 @@ static void test_publishsourcelist(void) ok(pf_exists("msitest"), "File not installed\n"); /* after RegisterProduct */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size); + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); r = MsiInstallProductA(msifile, "PROCESS_COMPONENTS=1"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); @@ -3548,17 +4683,21 @@ static void test_publishsourcelist(void) ok(pf_exists("msitest"), "File not installed\n"); /* after ProcessComponents */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size); + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); r = MsiInstallProductA(msifile, "PUBLISH_FEATURES=1"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); @@ -3566,17 +4705,21 @@ static void test_publishsourcelist(void) ok(pf_exists("msitest"), "File not installed\n"); /* after PublishFeatures */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size); + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); @@ -3654,9 +4797,9 @@ static void test_publishsourcelist(void) /* complete uninstall */ r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!pf_exists("msitest\\maximus"), "File not deleted\n"); todo_wine { - ok(!pf_exists("msitest\\maximus"), "File not deleted\n"); ok(!pf_exists("msitest"), "File not deleted\n"); } @@ -3691,37 +4834,22 @@ static void set_transform_summary_info(void) /* build summary info */ r = MsiGetSummaryInformation(0, mstfile, 3, &suminfo); - todo_wine - { ok(r == ERROR_SUCCESS , "Failed to open summaryinfo\n"); - } r = MsiSummaryInfoSetProperty(suminfo, PID_TITLE, VT_LPSTR, 0, NULL, "MSITEST"); - todo_wine - { ok(r == ERROR_SUCCESS, "Failed to set summary info\n"); - } r = MsiSummaryInfoSetProperty(suminfo, PID_REVNUMBER, VT_LPSTR, 0, NULL, "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}1.1.1;" "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}1.1.1;" "{4C0EAA15-0264-4E5A-8758-609EF142B92D}"); - todo_wine - { ok(r == ERROR_SUCCESS , "Failed to set summary info\n"); - } r = MsiSummaryInfoSetProperty(suminfo, PID_PAGECOUNT, VT_I4, 100, NULL, NULL); - todo_wine - { ok(r == ERROR_SUCCESS, "Failed to set summary info\n"); - } r = MsiSummaryInfoPersist(suminfo); - todo_wine - { ok(r == ERROR_SUCCESS , "Failed to make summary info persist\n"); - } r = MsiCloseHandle(suminfo); ok(r == ERROR_SUCCESS , "Failed to close suminfo\n"); @@ -3879,8 +5007,8 @@ static void test_transformprop(void) static void test_currentworkingdir(void) { UINT r; - CHAR path[MAX_PATH]; - LPSTR ptr, ptr2; + CHAR drive[MAX_PATH], path[MAX_PATH]; + LPSTR ptr; CreateDirectoryA("msitest", NULL); create_file("msitest\\augustus", 500); @@ -3907,18 +5035,17 @@ static void test_currentworkingdir(void) ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); ok(delete_pf("msitest", FALSE), "File not installed\n"); - lstrcpyA(path, CURR_DIR); + lstrcpyA(drive, CURR_DIR); + drive[2] = '\\'; + drive[3] = '\0'; + SetCurrentDirectoryA(drive); + + lstrcpy(path, CURR_DIR); if (path[lstrlenA(path) - 1] != '\\') lstrcatA(path, "\\"); - lstrcatA(path, "msitest.msi"); - - ptr2 = strrchr(path, '\\'); - *ptr2 = '\0'; - ptr = strrchr(path, '\\'); - *ptr2 = '\\'; - *(ptr++) = '\0'; - - SetCurrentDirectoryA(path); + lstrcatA(path, msifile); + ptr = strchr(path, ':'); + ptr +=2; r = MsiInstallProductA(ptr, NULL); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); @@ -4004,7 +5131,8 @@ static void set_admin_property_stream(LPCSTR file) /* AdminProperties */ static const WCHAR stmname[] = {0x41ca,0x4330,0x3e71,0x44b5,0x4233,0x45f5,0x422c,0x4836,0}; - static const WCHAR data[] = {'M','Y','P','R','O','P','=','2','7','1','8',0}; + static const WCHAR data[] = {'M','Y','P','R','O','P','=','2','7','1','8',' ', + 'M','y','P','r','o','p','=','4','2',0}; MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH); @@ -4084,13 +5212,10 @@ static void test_removefiles(void) r = MsiInstallProductA(msifile, "REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(!pf_exists("msitest\\hydrogen"), "File not deleted\n"); ok(!pf_exists("msitest\\helium"), "File not deleted\n"); ok(delete_pf("msitest\\lithium", TRUE), "File deleted\n"); - todo_wine - { - ok(!pf_exists("msitest\\hydrogen"), "File not deleted\n"); ok(delete_pf("msitest", FALSE), "File deleted\n"); - } create_pf("msitest", FALSE); create_pf("msitest\\hydrogen", TRUE); @@ -4106,13 +5231,10 @@ static void test_removefiles(void) r = MsiInstallProductA(msifile, "REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(!pf_exists("msitest\\hydrogen"), "File not deleted\n"); ok(delete_pf("msitest\\helium", TRUE), "File deleted\n"); ok(delete_pf("msitest\\lithium", TRUE), "File deleted\n"); - todo_wine - { - ok(!pf_exists("msitest\\hydrogen"), "File not deleted\n"); ok(delete_pf("msitest", FALSE), "File deleted\n"); - } create_pf("msitest", FALSE); create_pf("msitest\\furlong", TRUE); @@ -4124,25 +5246,25 @@ static void test_removefiles(void) create_pf("msitest\\storeys", TRUE); create_pf("msitest\\block", TRUE); create_pf("msitest\\siriometer", TRUE); + create_pf("msitest\\cabout", FALSE); + create_pf("msitest\\cabout\\blocker", TRUE); r = MsiInstallProductA(msifile, NULL); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); ok(!pf_exists("msitest\\helium"), "File installed\n"); ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(!pf_exists("msitest\\furlong"), "File not deleted\n"); + ok(!pf_exists("msitest\\firkin"), "File not deleted\n"); + ok(!pf_exists("msitest\\fortnight"), "File not deleted\n"); ok(pf_exists("msitest\\becquerel"), "File not installed\n"); ok(pf_exists("msitest\\dioptre"), "File not installed\n"); ok(pf_exists("msitest\\attoparsec"), "File not installed\n"); - ok(pf_exists("msitest"), "File not installed\n"); - todo_wine - { - ok(!pf_exists("msitest\\firkin"), "File not deleted\n"); - ok(!pf_exists("msitest\\fortnight"), "File not deleted\n"); - ok(!pf_exists("msitest\\furlong"), "File not deleted\n"); ok(!pf_exists("msitest\\storeys"), "File not deleted\n"); ok(!pf_exists("msitest\\block"), "File not deleted\n"); ok(!pf_exists("msitest\\siriometer"), "File not deleted\n"); - } + ok(pf_exists("msitest\\cabout"), "Directory removed\n"); + ok(pf_exists("msitest"), "File not installed\n"); create_pf("msitest\\furlong", TRUE); create_pf("msitest\\firkin", TRUE); @@ -4153,22 +5275,35 @@ static void test_removefiles(void) r = MsiInstallProductA(msifile, "REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(!delete_pf("msitest\\hydrogen", TRUE), "File not deleted\n"); ok(!delete_pf("msitest\\helium", TRUE), "File not deleted\n"); ok(delete_pf("msitest\\lithium", TRUE), "File deleted\n"); ok(delete_pf("msitest\\furlong", TRUE), "File deleted\n"); ok(delete_pf("msitest\\firkin", TRUE), "File deleted\n"); ok(delete_pf("msitest\\fortnight", TRUE), "File deleted\n"); - ok(delete_pf("msitest\\attoparsec", TRUE), "File deleted\n"); - ok(delete_pf("msitest\\siriometer", TRUE), "File deleted\n"); - todo_wine - { - ok(!delete_pf("msitest\\hydrogen", TRUE), "File not deleted\n"); ok(!delete_pf("msitest\\becquerel", TRUE), "File not deleted\n"); ok(!delete_pf("msitest\\dioptre", TRUE), "File not deleted\n"); + ok(delete_pf("msitest\\attoparsec", TRUE), "File deleted\n"); ok(!delete_pf("msitest\\storeys", TRUE), "File not deleted\n"); ok(!delete_pf("msitest\\block", TRUE), "File not deleted\n"); - } - ok(delete_pf("msitest", FALSE), "File deleted\n"); + ok(delete_pf("msitest\\siriometer", TRUE), "File deleted\n"); + ok(pf_exists("msitest\\cabout"), "Directory deleted\n"); + ok(pf_exists("msitest"), "Directory deleted\n"); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\hydrogen", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\helium", TRUE), "File installed\n"); + ok(delete_pf("msitest\\lithium", TRUE), "File not installed\n"); + ok(pf_exists("msitest\\cabout"), "Directory deleted\n"); + ok(pf_exists("msitest"), "Directory deleted\n"); + + delete_pf("msitest\\cabout\\blocker", TRUE); + + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(!delete_pf("msitest\\cabout", FALSE), "Directory not deleted\n"); + ok(delete_pf("msitest", FALSE), "Directory deleted\n"); DeleteFile(msifile); DeleteFile("msitest\\hydrogen"); @@ -4195,6 +5330,7 @@ static void test_movefiles(void) create_file("kenya", 100); CreateDirectoryA("latvia", NULL); create_file("nauru", 100); + create_file("peru", 100); create_file("apple", 100); create_file("application", 100); create_file("ape", 100); @@ -4235,6 +5371,7 @@ static void test_movefiles(void) ok(delete_pf("msitest\\kiribati", TRUE), "File not moved\n"); ok(!delete_pf("msitest\\lebanon", TRUE), "File moved\n"); ok(!delete_pf("msitest\\lebanon", FALSE), "Directory moved\n"); + ok(delete_pf("msitest\\poland", TRUE), "File not moved\n"); /* either apple or application will be moved depending on directory order */ if (!delete_pf("msitest\\apple", TRUE)) ok(delete_pf("msitest\\application", TRUE), "File not moved\n"); @@ -4267,6 +5404,7 @@ static void test_movefiles(void) ok(!DeleteFileA("kenya"), "File not moved\n"); ok(RemoveDirectoryA("latvia"), "Directory moved\n"); ok(!DeleteFileA("nauru"), "File not moved\n"); + ok(!DeleteFileA("peru"), "File not moved\n"); ok(!DeleteFileA("apple"), "File not moved\n"); ok(!DeleteFileA("application"), "File not moved\n"); ok(DeleteFileA("ape"), "File moved\n"); @@ -4303,10 +5441,15 @@ static void test_missingcab(void) create_pf_data("msitest\\caesar", "abcdefgh", TRUE); r = MsiInstallProductA(msifile, NULL); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(r == ERROR_SUCCESS || + broken(r == ERROR_INSTALL_FAILURE), /* win9x */ + "Expected ERROR_SUCCESS, got %u\n", r); + if (r == ERROR_SUCCESS) + { ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + } ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n"); - ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); ok(!delete_pf("msitest\\gaius", TRUE), "File installed\n"); ok(delete_pf("msitest", FALSE), "File not installed\n"); @@ -4411,22 +5554,22 @@ static void test_sourcefolder(void) MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_INSTALL_FAILURE, + "Expected ERROR_INSTALL_FAILURE, got %u\n", r); ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n"); todo_wine { - ok(r == ERROR_INSTALL_FAILURE, - "Expected ERROR_INSTALL_FAILURE, got %u\n", r); ok(!delete_pf("msitest", FALSE), "File installed\n"); } RemoveDirectoryA("msitest"); r = MsiInstallProductA(msifile, NULL); - todo_wine - { ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r); ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n"); + todo_wine + { ok(!delete_pf("msitest", FALSE), "File installed\n"); } @@ -4557,13 +5700,1363 @@ static void test_installstate(void) RemoveDirectory("msitest"); } +struct sourcepathmap +{ + BOOL sost; /* shortone\shorttwo */ + BOOL solt; /* shortone\longtwo */ + BOOL lost; /* longone\shorttwo */ + BOOL lolt; /* longone\longtwo */ + BOOL soste; /* shortone\shorttwo source exists */ + BOOL solte; /* shortone\longtwo source exists */ + BOOL loste; /* longone\shorttwo source exists */ + BOOL lolte; /* longone\longtwo source exists */ + UINT err; + DWORD size; +} spmap[256] = +{ + {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, ERROR_SUCCESS, 200}, + {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ERROR_INSTALL_FAILURE, 0}, + {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ERROR_INSTALL_FAILURE, 0}, +}; + +static DWORD get_pf_file_size(LPCSTR file) +{ + CHAR path[MAX_PATH]; + HANDLE hfile; + DWORD size; + + lstrcpyA(path, PROG_FILES_DIR); + lstrcatA(path, "\\"); + lstrcatA(path, file); + + hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hfile == INVALID_HANDLE_VALUE) + return 0; + + size = GetFileSize(hfile, NULL); + CloseHandle(hfile); + return size; +} + +static void test_sourcepath(void) +{ + UINT r, i; + + if (!winetest_interactive) + { + skip("Run in interactive mode to run source path tests.\n"); + return; + } + + create_database(msifile, sp_tables, sizeof(sp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + for (i = 0; i < sizeof(spmap) / sizeof(spmap[0]); i++) + { + if (spmap[i].sost) + { + CreateDirectoryA("shortone", NULL); + CreateDirectoryA("shortone\\shorttwo", NULL); + } + + if (spmap[i].solt) + { + CreateDirectoryA("shortone", NULL); + CreateDirectoryA("shortone\\longtwo", NULL); + } + + if (spmap[i].lost) + { + CreateDirectoryA("longone", NULL); + CreateDirectoryA("longone\\shorttwo", NULL); + } + + if (spmap[i].lolt) + { + CreateDirectoryA("longone", NULL); + CreateDirectoryA("longone\\longtwo", NULL); + } + + if (spmap[i].soste) + create_file("shortone\\shorttwo\\augustus", 50); + if (spmap[i].solte) + create_file("shortone\\longtwo\\augustus", 100); + if (spmap[i].loste) + create_file("longone\\shorttwo\\augustus", 150); + if (spmap[i].lolte) + create_file("longone\\longtwo\\augustus", 200); + + r = MsiInstallProductA(msifile, NULL); + ok(r == spmap[i].err, "%d: Expected %d, got %d\n", i, spmap[i].err, r); + ok(get_pf_file_size("msitest\\augustus") == spmap[i].size, + "%d: Expected %d, got %d\n", i, spmap[i].size, + get_pf_file_size("msitest\\augustus")); + + if (r == ERROR_SUCCESS) + { + ok(delete_pf("msitest\\augustus", TRUE), "%d: File not installed\n", i); + ok(delete_pf("msitest", FALSE), "%d: File not installed\n", i); + } + else + { + ok(!delete_pf("msitest\\augustus", TRUE), "%d: File installed\n", i); + todo_wine ok(!delete_pf("msitest", FALSE), "%d: File installed\n", i); + } + + DeleteFileA("shortone\\shorttwo\\augustus"); + DeleteFileA("shortone\\longtwo\\augustus"); + DeleteFileA("longone\\shorttwo\\augustus"); + DeleteFileA("longone\\longtwo\\augustus"); + RemoveDirectoryA("shortone\\shorttwo"); + RemoveDirectoryA("shortone\\longtwo"); + RemoveDirectoryA("longone\\shorttwo"); + RemoveDirectoryA("longone\\longtwo"); + RemoveDirectoryA("shortone"); + RemoveDirectoryA("longone"); + } + + DeleteFileA(msifile); +} + +static void test_MsiConfigureProductEx(void) +{ + UINT r; + LONG res; + DWORD type, size; + HKEY props, source; + CHAR keypath[MAX_PATH * 2]; + CHAR localpack[MAX_PATH]; + + if (on_win9x) + { + win_skip("Different registry keys on Win9x and WinMe\n"); + return; + } + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\hydrogen", 500); + create_file("msitest\\helium", 500); + create_file("msitest\\lithium", 500); + + create_database(msifile, mcp_tables, sizeof(mcp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + /* NULL szProduct */ + r = MsiConfigureProductExA(NULL, INSTALLLEVEL_DEFAULT, + INSTALLSTATE_DEFAULT, "PROPVAR=42"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* empty szProduct */ + r = MsiConfigureProductExA("", INSTALLLEVEL_DEFAULT, + INSTALLSTATE_DEFAULT, "PROPVAR=42"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* garbage szProduct */ + r = MsiConfigureProductExA("garbage", INSTALLLEVEL_DEFAULT, + INSTALLSTATE_DEFAULT, "PROPVAR=42"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid without brackets */ + r = MsiConfigureProductExA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, + "PROPVAR=42"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid with brackets */ + r = MsiConfigureProductExA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, + "PROPVAR=42"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* same length as guid, but random */ + r = MsiConfigureProductExA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, + "PROPVAR=42"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* product not installed yet */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, + "PROPVAR=42"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* install the product, per-user unmanaged */ + r = MsiInstallProductA(msifile, "INSTALLLEVEL=10 PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); + ok(pf_exists("msitest\\helium"), "File not installed\n"); + ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + /* product is installed per-user managed, remove it */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, + "PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n"); + todo_wine + { + ok(!delete_pf("msitest", FALSE), "File not removed\n"); + } + + /* product has been removed */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, + "PROPVAR=42"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r); + + /* install the product, machine */ + r = MsiInstallProductA(msifile, "ALLUSERS=1 INSTALLLEVEL=10 PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); + ok(pf_exists("msitest\\helium"), "File not installed\n"); + ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + /* product is installed machine, remove it */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, + "PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n"); + todo_wine + { + ok(!delete_pf("msitest", FALSE), "File not removed\n"); + } + + /* product has been removed */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, + "PROPVAR=42"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %u\n", r); + + /* install the product, machine */ + r = MsiInstallProductA(msifile, "ALLUSERS=1 INSTALLLEVEL=10 PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); + ok(pf_exists("msitest\\helium"), "File not installed\n"); + ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + DeleteFileA(msifile); + + /* local msifile is removed */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, + "PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n"); + todo_wine + { + ok(!delete_pf("msitest", FALSE), "File not removed\n"); + } + + create_database(msifile, mcp_tables, sizeof(mcp_tables) / sizeof(msi_table)); + + /* install the product, machine */ + r = MsiInstallProductA(msifile, "ALLUSERS=1 INSTALLLEVEL=10 PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); + ok(pf_exists("msitest\\helium"), "File not installed\n"); + ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + DeleteFileA(msifile); + + lstrcpyA(keypath, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\S-1-5-18\\Products\\"); + lstrcatA(keypath, "84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ, + (const BYTE *)"C:\\idontexist.msi", 18); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage is used to find the cached msi package */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, + "PROPVAR=42"); + ok(r == ERROR_INSTALL_SOURCE_ABSENT, + "Expected ERROR_INSTALL_SOURCE_ABSENT, got %d\n", r); + ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); + ok(pf_exists("msitest\\helium"), "File not installed\n"); + ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + RegCloseKey(props); + create_database(msifile, mcp_tables, sizeof(mcp_tables) / sizeof(msi_table)); + + /* LastUsedSource (local msi package) can be used as a last resort */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, + "PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n"); + todo_wine + { + ok(!delete_pf("msitest", FALSE), "File not removed\n"); + } + + /* install the product, machine */ + r = MsiInstallProductA(msifile, "ALLUSERS=1 INSTALLLEVEL=10 PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); + ok(pf_exists("msitest\\helium"), "File not installed\n"); + ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + lstrcpyA(keypath, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\S-1-5-18\\Products\\"); + lstrcatA(keypath, "84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ, + (const BYTE *)"C:\\idontexist.msi", 18); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + lstrcpyA(keypath, "SOFTWARE\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, "84A88FD7F6998CE40A22FB59F6B9C2BB\\SourceList"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + type = REG_SZ; + size = MAX_PATH; + res = RegQueryValueExA(source, "PackageName", NULL, &type, + (LPBYTE)localpack, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(source, "PackageName", 0, REG_SZ, + (const BYTE *)"idontexist.msi", 15); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList is altered */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, + "PROPVAR=42"); + ok(r == ERROR_INSTALL_SOURCE_ABSENT, + "Expected ERROR_INSTALL_SOURCE_ABSENT, got %d\n", r); + ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); + ok(pf_exists("msitest\\helium"), "File not installed\n"); + ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + /* restore the SourceList */ + res = RegSetValueExA(source, "PackageName", 0, REG_SZ, + (const BYTE *)localpack, lstrlenA(localpack) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* finally remove the product */ + r = MsiConfigureProductExA("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", + INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, + "PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n"); + todo_wine + { + ok(!delete_pf("msitest", FALSE), "File not removed\n"); + } + + DeleteFileA(msifile); + RegCloseKey(source); + RegCloseKey(props); + DeleteFileA("msitest\\hydrogen"); + DeleteFileA("msitest\\helium"); + DeleteFileA("msitest\\lithium"); + RemoveDirectoryA("msitest"); +} + +static void test_missingcomponent(void) +{ + UINT r; + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\hydrogen", 500); + create_file("msitest\\helium", 500); + create_file("msitest\\lithium", 500); + create_file("beryllium", 500); + + create_database(msifile, mcomp_tables, sizeof(mcomp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, "INSTALLLEVEL=10 PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(pf_exists("msitest\\hydrogen"), "File not installed\n"); + ok(pf_exists("msitest\\helium"), "File not installed\n"); + ok(pf_exists("msitest\\lithium"), "File not installed\n"); + ok(!pf_exists("msitest\\beryllium"), "File installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + r = MsiInstallProductA(msifile, "REMOVE=ALL INSTALLLEVEL=10 PROPVAR=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(!delete_pf("msitest\\hydrogen", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\helium", TRUE), "File not removed\n"); + ok(!delete_pf("msitest\\lithium", TRUE), "File not removed\n"); + ok(!pf_exists("msitest\\beryllium"), "File installed\n"); + todo_wine + { + ok(!delete_pf("msitest", FALSE), "File not removed\n"); + } + + DeleteFileA(msifile); + DeleteFileA("msitest\\hydrogen"); + DeleteFileA("msitest\\helium"); + DeleteFileA("msitest\\lithium"); + DeleteFileA("beryllium"); + RemoveDirectoryA("msitest"); +} + +static void test_sourcedirprop(void) +{ + UINT r; + CHAR props[MAX_PATH]; + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\augustus", 500); + + create_database(msifile, ca51_tables, sizeof(ca51_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\augustus", TRUE), "File installed\n"); + ok(delete_pf("msitest", FALSE), "File installed\n"); + + DeleteFile("msitest\\augustus"); + RemoveDirectory("msitest"); + + CreateDirectoryA("altsource", NULL); + CreateDirectoryA("altsource\\msitest", NULL); + create_file("altsource\\msitest\\augustus", 500); + + sprintf(props, "SRCDIR=%s\\altsource\\", CURR_DIR); + + r = MsiInstallProductA(msifile, props); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\augustus", TRUE), "File installed\n"); + ok(delete_pf("msitest", FALSE), "File installed\n"); + + DeleteFile(msifile); + DeleteFile("altsource\\msitest\\augustus"); + RemoveDirectory("altsource\\msitest"); + RemoveDirectory("altsource"); +} + +static void test_adminimage(void) +{ + UINT r; + + CreateDirectoryA("msitest", NULL); + CreateDirectoryA("msitest\\first", NULL); + CreateDirectoryA("msitest\\second", NULL); + CreateDirectoryA("msitest\\cabout", NULL); + CreateDirectoryA("msitest\\cabout\\new", NULL); + create_file("msitest\\one.txt", 100); + create_file("msitest\\first\\two.txt", 100); + create_file("msitest\\second\\three.txt", 100); + create_file("msitest\\cabout\\four.txt", 100); + create_file("msitest\\cabout\\new\\five.txt", 100); + create_file("msitest\\filename", 100); + create_file("msitest\\service.exe", 100); + + create_database_wordcount(msifile, ai_tables, + sizeof(ai_tables) / sizeof(msi_table), + msidbSumInfoSourceTypeAdminImage); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + DeleteFileA("msitest.msi"); + DeleteFileA("msitest\\cabout\\new\\five.txt"); + DeleteFileA("msitest\\cabout\\four.txt"); + DeleteFileA("msitest\\second\\three.txt"); + DeleteFileA("msitest\\first\\two.txt"); + DeleteFileA("msitest\\one.txt"); + DeleteFileA("msitest\\service.exe"); + DeleteFileA("msitest\\filename"); + RemoveDirectoryA("msitest\\cabout\\new"); + RemoveDirectoryA("msitest\\cabout"); + RemoveDirectoryA("msitest\\second"); + RemoveDirectoryA("msitest\\first"); + RemoveDirectoryA("msitest"); +} + +static void test_propcase(void) +{ + UINT r; + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\augustus", 500); + + create_database(msifile, pc_tables, sizeof(pc_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, "MyProp=42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + DeleteFile(msifile); + DeleteFile("msitest\\augustus"); + RemoveDirectory("msitest"); +} + +static void test_int_widths( void ) +{ + static const char int0[] = "int0\ni0\nint0\tint0\n1"; + static const char int1[] = "int1\ni1\nint1\tint1\n1"; + static const char int2[] = "int2\ni2\nint2\tint2\n1"; + static const char int3[] = "int3\ni3\nint3\tint3\n1"; + static const char int4[] = "int4\ni4\nint4\tint4\n1"; + static const char int5[] = "int5\ni5\nint5\tint5\n1"; + static const char int8[] = "int8\ni8\nint8\tint8\n1"; + + static const struct + { + const char *data; + unsigned int size; + UINT ret; + } + tests[] = + { + { int0, sizeof(int0) - 1, ERROR_SUCCESS }, + { int1, sizeof(int1) - 1, ERROR_SUCCESS }, + { int2, sizeof(int2) - 1, ERROR_SUCCESS }, + { int3, sizeof(int3) - 1, ERROR_FUNCTION_FAILED }, + { int4, sizeof(int4) - 1, ERROR_SUCCESS }, + { int5, sizeof(int5) - 1, ERROR_FUNCTION_FAILED }, + { int8, sizeof(int8) - 1, ERROR_FUNCTION_FAILED } + }; + + char tmpdir[MAX_PATH], msitable[MAX_PATH], msidb[MAX_PATH]; + MSIHANDLE db; + UINT r, i; + + GetTempPathA(MAX_PATH, tmpdir); + CreateDirectoryA(tmpdir, NULL); + + strcpy(msitable, tmpdir); + strcat(msitable, "\\msitable.idt"); + + strcpy(msidb, tmpdir); + strcat(msidb, "\\msitest.msi"); + + r = MsiOpenDatabaseA(msidb, MSIDBOPEN_CREATE, &db); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + { + write_file(msitable, tests[i].data, tests[i].size); + + r = MsiDatabaseImportA(db, tmpdir, "msitable.idt"); + ok(r == tests[i].ret, " %u expected %u, got %u\n", i, tests[i].ret, r); + + r = MsiDatabaseCommit(db); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + DeleteFileA(msitable); + } + + MsiCloseHandle(db); + DeleteFileA(msidb); + RemoveDirectoryA(tmpdir); +} + +static void test_shortcut(void) +{ + UINT r; + HRESULT hr; + + create_test_files(); + create_database(msifile, sc_tables, sizeof(sc_tables) / sizeof(msi_table)); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + ok(SUCCEEDED(hr), "CoInitialize failed 0x%08x\n", hr); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + CoUninitialize(); + + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok(SUCCEEDED(hr), "CoInitialize failed 0x%08x\n", hr); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + CoUninitialize(); + + delete_pf("msitest\\cabout\\new\\five.txt", TRUE); + delete_pf("msitest\\cabout\\new", FALSE); + delete_pf("msitest\\cabout\\four.txt", TRUE); + delete_pf("msitest\\cabout", FALSE); + delete_pf("msitest\\changed\\three.txt", TRUE); + delete_pf("msitest\\changed", FALSE); + delete_pf("msitest\\first\\two.txt", TRUE); + delete_pf("msitest\\first", FALSE); + delete_pf("msitest\\filename", TRUE); + delete_pf("msitest\\one.txt", TRUE); + delete_pf("msitest\\service.exe", TRUE); + delete_pf("msitest\\Shortcut.lnk", TRUE); + delete_pf("msitest", FALSE); + delete_test_files(); +} + +static void test_envvar(void) +{ + UINT r; + HKEY env; + LONG res; + DWORD type, size; + char buffer[16]; + + if (on_win9x) + { + win_skip("Environment variables are handled differently on Win9x and WinMe\n"); + return; + } + + create_test_files(); + create_database(msifile, env_tables, sizeof(env_tables) / sizeof(msi_table)); + + res = RegCreateKeyExA(HKEY_CURRENT_USER, "Environment", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &env, NULL); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(env, "MSITESTVAR1", 0, REG_SZ, (const BYTE *)"0", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(env, "MSITESTVAR2", 0, REG_SZ, (const BYTE *)"0", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + type = REG_NONE; + size = sizeof(buffer); + buffer[0] = 0; + res = RegQueryValueExA(env, "MSITESTVAR1", NULL, &type, (LPBYTE)buffer, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type); + ok(!lstrcmp(buffer, "1"), "Expected \"1\", got %s\n", buffer); + + res = RegDeleteValueA(env, "MSITESTVAR1"); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + type = REG_NONE; + size = sizeof(buffer); + buffer[0] = 0; + res = RegQueryValueExA(env, "MSITESTVAR2", NULL, &type, (LPBYTE)buffer, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(type == REG_SZ, "Expected REG_SZ, got %u\n", type); + ok(!lstrcmp(buffer, "1"), "Expected \"1\", got %s\n", buffer); + + res = RegDeleteValueA(env, "MSITESTVAR2"); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegDeleteValueA(env, "MSITESTVAR3"); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegDeleteValueA(env, "MSITESTVAR4"); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegDeleteValueA(env, "MSITESTVAR5"); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegDeleteValueA(env, "MSITESTVAR6"); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegDeleteValueA(env, "MSITESTVAR7"); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegDeleteValueA(env, "MSITESTVAR8"); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegDeleteValueA(env, "MSITESTVAR9"); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegDeleteValueA(env, "MSITESTVAR10"); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + RegCloseKey(env); + + delete_pf("msitest\\cabout\\new\\five.txt", TRUE); + delete_pf("msitest\\cabout\\new", FALSE); + delete_pf("msitest\\cabout\\four.txt", TRUE); + delete_pf("msitest\\cabout", FALSE); + delete_pf("msitest\\changed\\three.txt", TRUE); + delete_pf("msitest\\changed", FALSE); + delete_pf("msitest\\first\\two.txt", TRUE); + delete_pf("msitest\\first", FALSE); + delete_pf("msitest\\filename", TRUE); + delete_pf("msitest\\one.txt", TRUE); + delete_pf("msitest\\service.exe", TRUE); + delete_pf("msitest", FALSE); + delete_test_files(); +} + +static void test_preselected(void) +{ + UINT r; + + create_test_files(); + create_database(msifile, ps_tables, sizeof(ps_tables) / sizeof(msi_table)); + + r = MsiInstallProductA(msifile, "ADDLOCAL=One"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(!delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\cabout\\new", FALSE), "File installed\n"); + ok(!delete_pf("msitest\\cabout\\four.txt", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\cabout", FALSE), "File installed\n"); + ok(!delete_pf("msitest\\changed\\three.txt", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\changed", FALSE), "File installed\n"); + ok(!delete_pf("msitest\\first\\two.txt", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\first", FALSE), "File installed\n"); + ok(!delete_pf("msitest\\filename", TRUE), "File installed\n"); + todo_wine ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\service.exe", TRUE), "File installed\n"); + todo_wine ok(delete_pf("msitest", FALSE), "File not installed\n"); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\one.txt", TRUE), "File installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + delete_test_files(); +} + +static void test_installed_prop(void) +{ + static char prodcode[] = "{7df88a48-996f-4ec8-a022-bf956f9b2cbb}"; + UINT r; + + create_test_files(); + create_database(msifile, ip_tables, sizeof(ip_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, "FULL=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + r = MsiInstallProductA(msifile, "FULL=1"); + ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r); + + r = MsiConfigureProductExA(prodcode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, "FULL=1"); + ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + delete_test_files(); +} + +static void test_allusers_prop(void) +{ + UINT r; + + create_test_files(); + create_database(msifile, aup_tables, sizeof(aup_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, "FULL=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\changed", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\first", FALSE), "File not installed\n"); + ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\one.txt", TRUE), "File installed\n"); + ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + delete_test_files(); +} + +static char session_manager[] = "System\\CurrentControlSet\\Control\\Session Manager"; +static char rename_ops[] = "PendingFileRenameOperations"; + +static void process_pending_renames(HKEY hkey) +{ + char *buf, *src, *dst; + DWORD size; + LONG ret; + + ret = RegQueryValueExA(hkey, rename_ops, NULL, NULL, NULL, &size); + buf = HeapAlloc(GetProcessHeap(), 0, size); + buf[0] = 0; + + ret = RegQueryValueExA(hkey, rename_ops, NULL, NULL, (LPBYTE)buf, &size); + ok(!ret, "RegQueryValueExA failed %d (%u)\n", ret, GetLastError()); + ok(strstr(buf, "msitest\\maximus") != NULL, "Unexpected value \"%s\"\n", buf); + + for (src = buf; *src; src = dst + strlen(dst) + 1) + { + DWORD flags = MOVEFILE_COPY_ALLOWED; + + dst = src + strlen(src) + 1; + if (*dst == '!') + { + flags |= MOVEFILE_REPLACE_EXISTING; + dst++; + } + if (src[0] == '\\' && src[1] == '?' && src[2] == '?' && src[3] == '\\') src += 4; + if (*dst) + { + if (dst[0] == '\\' && dst[1] == '?' && dst[2] == '?' && dst[3] == '\\') dst += 4; + ok(MoveFileExA(src, dst, flags), "Failed to move file %s -> %s (%u)\n", src, dst, GetLastError()); + } + else + ok(DeleteFileA(src), "Failed to delete file %s (%u)\n", src, GetLastError()); + } + HeapFree(GetProcessHeap(), 0, buf); + RegDeleteValueA(hkey, rename_ops); +} + +static BOOL file_matches_data(LPCSTR file, LPCSTR data) +{ + DWORD len, data_len = strlen(data); + HANDLE handle; + char buf[128]; + + handle = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + ok(handle != INVALID_HANDLE_VALUE, "failed to open %s (%u)\n", file, GetLastError()); + + if (ReadFile(handle, buf, sizeof(buf), &len, NULL) && len >= data_len) + { + CloseHandle(handle); + return !memcmp(buf, data, data_len); + } + CloseHandle(handle); + return FALSE; +} + +static void test_file_in_use(void) +{ + UINT r; + DWORD size; + HANDLE file; + HKEY hkey; + char path[MAX_PATH]; + + if (on_win9x) + { + win_skip("Pending file renaming is implemented differently on Win9x and WinMe\n"); + return; + } + + RegOpenKeyExA(HKEY_LOCAL_MACHINE, session_manager, 0, KEY_ALL_ACCESS, &hkey); + if (!RegQueryValueExA(hkey, rename_ops, NULL, NULL, NULL, &size)) + { + skip("Pending file rename operations, skipping test\n"); + return; + } + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + create_database(msifile, fiu_tables, sizeof(fiu_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + lstrcpy(path, PROG_FILES_DIR); + lstrcat(path, "\\msitest"); + CreateDirectoryA(path, NULL); + + lstrcat(path, "\\maximus"); + file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + + r = MsiInstallProductA(msifile, "REBOOT=ReallySuppress FULL=1"); + ok(r == ERROR_SUCCESS_REBOOT_REQUIRED, "Expected ERROR_SUCCESS_REBOOT_REQUIRED got %u\n", r); + ok(!file_matches_data(path, "msitest\\maximus"), "Expected file not to match\n"); + CloseHandle(file); + ok(!file_matches_data(path, "msitest\\maximus"), "Expected file not to match\n"); + + process_pending_renames(hkey); + RegCloseKey(hkey); + + ok(file_matches_data(path, "msitest\\maximus"), "Expected file to match\n"); + ok(delete_pf("msitest\\maximus", TRUE), "File not present\n"); + ok(delete_pf("msitest", FALSE), "Directory not present or not empty\n"); + + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + delete_test_files(); +} + +static void test_file_in_use_cab(void) +{ + UINT r; + DWORD size; + HANDLE file; + HKEY hkey; + char path[MAX_PATH]; + + if (on_win9x) + { + win_skip("Pending file renaming is implemented differently on Win9x and WinMe\n"); + return; + } + + RegOpenKeyExA(HKEY_LOCAL_MACHINE, session_manager, 0, KEY_ALL_ACCESS, &hkey); + if (!RegQueryValueExA(hkey, rename_ops, NULL, NULL, NULL, &size)) + { + skip("Pending file rename operations, skipping test\n"); + return; + } + + CreateDirectoryA("msitest", NULL); + create_file("maximus", 500); + create_cab_file("test1.cab", MEDIA_SIZE, "maximus\0"); + DeleteFile("maximus"); + + create_database(msifile, fiuc_tables, sizeof(fiuc_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + lstrcpy(path, PROG_FILES_DIR); + lstrcat(path, "\\msitest"); + CreateDirectoryA(path, NULL); + + lstrcat(path, "\\maximus"); + file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + + r = MsiInstallProductA(msifile, "REBOOT=ReallySuppress FULL=1"); + ok(r == ERROR_SUCCESS_REBOOT_REQUIRED, "Expected ERROR_SUCCESS_REBOOT_REQUIRED got %u\n", r); + ok(!file_matches_data(path, "maximus"), "Expected file not to match\n"); + CloseHandle(file); + ok(!file_matches_data(path, "maximus"), "Expected file not to match\n"); + + process_pending_renames(hkey); + RegCloseKey(hkey); + + ok(file_matches_data(path, "maximus"), "Expected file to match\n"); + ok(delete_pf("msitest\\maximus", TRUE), "File not present\n"); + ok(delete_pf("msitest", FALSE), "Directory not present or not empty\n"); + + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + delete_cab_files(); + delete_test_files(); +} + +static INT CALLBACK handler_a(LPVOID context, UINT type, LPCSTR msg) +{ + return IDOK; +} + +static INT CALLBACK handler_w(LPVOID context, UINT type, LPCWSTR msg) +{ + return IDOK; +} + +static INT CALLBACK handler_record(LPVOID context, UINT type, MSIHANDLE record) +{ + return IDOK; +} + +static void test_MsiSetExternalUI(void) +{ + INSTALLUI_HANDLERA ret_a; + INSTALLUI_HANDLERW ret_w; + INSTALLUI_HANDLER_RECORD prev; + UINT error; + + ret_a = MsiSetExternalUIA(handler_a, INSTALLLOGMODE_ERROR, NULL); + ok(ret_a == NULL, "expected NULL, got %p\n", ret_a); + + ret_a = MsiSetExternalUIA(NULL, 0, NULL); + ok(ret_a == handler_a, "expected %p, got %p\n", handler_a, ret_a); + + /* Not present before Installer 3.1 */ + if (!pMsiSetExternalUIRecord) { + win_skip("MsiSetExternalUIRecord is not available\n"); + return; + } + + error = pMsiSetExternalUIRecord(handler_record, INSTALLLOGMODE_ERROR, NULL, &prev); + ok(!error, "MsiSetExternalUIRecord failed %u\n", error); + ok(prev == NULL, "expected NULL, got %p\n", prev); + + prev = (INSTALLUI_HANDLER_RECORD)0xdeadbeef; + error = pMsiSetExternalUIRecord(NULL, INSTALLLOGMODE_ERROR, NULL, &prev); + ok(!error, "MsiSetExternalUIRecord failed %u\n", error); + ok(prev == handler_record, "expected %p, got %p\n", handler_record, prev); + + ret_w = MsiSetExternalUIW(handler_w, INSTALLLOGMODE_ERROR, NULL); + ok(ret_w == NULL, "expected NULL, got %p\n", ret_w); + + ret_w = MsiSetExternalUIW(NULL, 0, NULL); + ok(ret_w == handler_w, "expected %p, got %p\n", handler_w, ret_w); + + ret_a = MsiSetExternalUIA(handler_a, INSTALLLOGMODE_ERROR, NULL); + ok(ret_a == NULL, "expected NULL, got %p\n", ret_a); + + ret_w = MsiSetExternalUIW(handler_w, INSTALLLOGMODE_ERROR, NULL); + ok(ret_w == NULL, "expected NULL, got %p\n", ret_w); + + prev = (INSTALLUI_HANDLER_RECORD)0xdeadbeef; + error = pMsiSetExternalUIRecord(handler_record, INSTALLLOGMODE_ERROR, NULL, &prev); + ok(!error, "MsiSetExternalUIRecord failed %u\n", error); + ok(prev == NULL, "expected NULL, got %p\n", prev); + + ret_a = MsiSetExternalUIA(NULL, 0, NULL); + ok(ret_a == NULL, "expected NULL, got %p\n", ret_a); + + ret_w = MsiSetExternalUIW(NULL, 0, NULL); + ok(ret_w == NULL, "expected NULL, got %p\n", ret_w); + + prev = (INSTALLUI_HANDLER_RECORD)0xdeadbeef; + error = pMsiSetExternalUIRecord(NULL, 0, NULL, &prev); + ok(!error, "MsiSetExternalUIRecord failed %u\n", error); + ok(prev == handler_record, "expected %p, got %p\n", handler_record, prev); + + error = pMsiSetExternalUIRecord(handler_record, INSTALLLOGMODE_ERROR, NULL, NULL); + ok(!error, "MsiSetExternalUIRecord failed %u\n", error); + + error = pMsiSetExternalUIRecord(NULL, 0, NULL, NULL); + ok(!error, "MsiSetExternalUIRecord failed %u\n", error); +} + START_TEST(install) { DWORD len; - char temp_path[MAX_PATH], prev_path[MAX_PATH]; + char temp_path[MAX_PATH], prev_path[MAX_PATH], log_file[MAX_PATH]; + STATEMGRSTATUS status; + BOOL ret = FALSE; init_functionpointers(); + on_win9x = check_win9x(); + GetCurrentDirectoryA(MAX_PATH, prev_path); GetTempPath(MAX_PATH, temp_path); SetCurrentDirectoryA(temp_path); @@ -4576,6 +7069,24 @@ START_TEST(install) get_program_files_dir(PROG_FILES_DIR, COMMON_FILES_DIR); + /* Create a restore point ourselves so we circumvent the multitude of restore points + * that would have been created by all the installation and removal tests. + */ + if (pSRSetRestorePointA) + { + memset(&status, 0, sizeof(status)); + ret = notify_system_change(BEGIN_NESTED_SYSTEM_CHANGE, &status); + } + + /* Create only one log file and don't append. We have to pass something + * for the log mode for this to work. The logfile needs to have an absolute + * path otherwise we still end up with some extra logfiles as some tests + * change the current directory. + */ + lstrcpyA(log_file, temp_path); + lstrcatA(log_file, "\\msitest.log"); + MsiEnableLogA(INSTALLLOGMODE_FATALEXIT, log_file, 0); + test_MsiInstallProduct(); test_MsiSetComponentState(); test_packagecoltypes(); @@ -4585,6 +7096,7 @@ START_TEST(install) test_samesequence(); test_uiLevelFlags(); test_readonlyfile(); + test_readonlyfile_cab(); test_setdirproperty(); test_cabisextracted(); test_concurrentinstall(); @@ -4608,6 +7120,32 @@ START_TEST(install) test_sourcefolder(); test_customaction51(); test_installstate(); + test_sourcepath(); + test_MsiConfigureProductEx(); + test_missingcomponent(); + test_sourcedirprop(); + test_adminimage(); + test_propcase(); + test_int_widths(); + test_shortcut(); + test_envvar(); + test_lastusedsource(); + test_preselected(); + test_installed_prop(); + test_file_in_use(); + test_file_in_use_cab(); + test_MsiSetExternalUI(); + test_allusers_prop(); + + DeleteFileA(log_file); + + if (pSRSetRestorePointA && ret) + { + ret = notify_system_change(END_NESTED_SYSTEM_CHANGE, &status); + if (ret) + remove_restore_point(status.llSequenceNumber); + } + FreeLibrary(hsrclient); SetCurrentDirectoryA(prev_path); } diff --git a/rostests/winetests/msi/msi.c b/rostests/winetests/msi/msi.c index 52cfd74564e..28ffb583dda 100644 --- a/rostests/winetests/msi/msi.c +++ b/rostests/winetests/msi/msi.c @@ -24,10 +24,13 @@ #include #include #include +#include #include #include "wine/test.h" +static const char msifile[] = "winetest.msi"; + static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*); static INSTALLSTATE (WINAPI *pMsiGetComponentPathA) @@ -40,10 +43,15 @@ static UINT (WINAPI *pMsiOpenPackageExA) (LPCSTR, DWORD, MSIHANDLE*); static UINT (WINAPI *pMsiOpenPackageExW) (LPCWSTR, DWORD, MSIHANDLE*); +static UINT (WINAPI *pMsiEnumPatchesExA) + (LPCSTR, LPCSTR, DWORD, DWORD, DWORD, LPSTR, LPSTR, + MSIINSTALLCONTEXT*, LPSTR, LPDWORD); static UINT (WINAPI *pMsiQueryComponentStateA) (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR, INSTALLSTATE*); static INSTALLSTATE (WINAPI *pMsiUseFeatureExA) (LPCSTR, LPCSTR ,DWORD, DWORD ); +static UINT (WINAPI *pMsiGetPatchInfoExA) + (LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR, LPSTR, DWORD *); static void init_functionpointers(void) { @@ -60,21 +68,129 @@ static void init_functionpointers(void) GET_PROC(hmsi, MsiGetProductInfoExA) GET_PROC(hmsi, MsiOpenPackageExA) GET_PROC(hmsi, MsiOpenPackageExW) + GET_PROC(hmsi, MsiEnumPatchesExA) GET_PROC(hmsi, MsiQueryComponentStateA) GET_PROC(hmsi, MsiUseFeatureExA) + GET_PROC(hmsi, MsiGetPatchInfoExA) GET_PROC(hadvapi32, ConvertSidToStringSidA) #undef GET_PROC } +static UINT run_query(MSIHANDLE hdb, const char *query) +{ + MSIHANDLE hview = 0; + UINT r; + + r = MsiDatabaseOpenView(hdb, query, &hview); + if (r != ERROR_SUCCESS) + return r; + + r = MsiViewExecute(hview, 0); + if (r == ERROR_SUCCESS) + r = MsiViewClose(hview); + MsiCloseHandle(hview); + return r; +} + +static UINT set_summary_info(MSIHANDLE hdb, LPSTR prodcode) +{ + UINT res; + MSIHANDLE suminfo; + + /* build summary info */ + res = MsiGetSummaryInformation(hdb, NULL, 7, &suminfo); + ok(res == ERROR_SUCCESS, "Failed to open summaryinfo\n"); + + res = MsiSummaryInfoSetProperty(suminfo, 2, VT_LPSTR, 0, NULL, + "Installation Database"); + ok(res == ERROR_SUCCESS, "Failed to set summary info\n"); + + res = MsiSummaryInfoSetProperty(suminfo, 3, VT_LPSTR, 0, NULL, + "Installation Database"); + ok(res == ERROR_SUCCESS, "Failed to set summary info\n"); + + res = MsiSummaryInfoSetProperty(suminfo, 4, VT_LPSTR, 0, NULL, + "Wine Hackers"); + ok(res == ERROR_SUCCESS, "Failed to set summary info\n"); + + res = MsiSummaryInfoSetProperty(suminfo, 7, VT_LPSTR, 0, NULL, + ";1033"); + ok(res == ERROR_SUCCESS, "Failed to set summary info\n"); + + res = MsiSummaryInfoSetProperty(suminfo, PID_REVNUMBER, VT_LPSTR, 0, NULL, + "{A2078D65-94D6-4205-8DEE-F68D6FD622AA}"); + ok(res == ERROR_SUCCESS, "Failed to set summary info\n"); + + res = MsiSummaryInfoSetProperty(suminfo, 14, VT_I4, 100, NULL, NULL); + ok(res == ERROR_SUCCESS, "Failed to set summary info\n"); + + res = MsiSummaryInfoSetProperty(suminfo, 15, VT_I4, 0, NULL, NULL); + ok(res == ERROR_SUCCESS, "Failed to set summary info\n"); + + res = MsiSummaryInfoPersist(suminfo); + ok(res == ERROR_SUCCESS, "Failed to make summary info persist\n"); + + res = MsiCloseHandle(suminfo); + ok(res == ERROR_SUCCESS, "Failed to close suminfo\n"); + + return res; +} + +static MSIHANDLE create_package_db(LPSTR prodcode) +{ + MSIHANDLE hdb = 0; + CHAR query[MAX_PATH]; + UINT res; + + DeleteFile(msifile); + + /* create an empty database */ + res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok( res == ERROR_SUCCESS , "Failed to create database\n" ); + if (res != ERROR_SUCCESS) + return hdb; + + res = MsiDatabaseCommit(hdb); + ok(res == ERROR_SUCCESS, "Failed to commit database\n"); + + set_summary_info(hdb, prodcode); + + res = run_query(hdb, + "CREATE TABLE `Directory` ( " + "`Directory` CHAR(255) NOT NULL, " + "`Directory_Parent` CHAR(255), " + "`DefaultDir` CHAR(255) NOT NULL " + "PRIMARY KEY `Directory`)"); + ok(res == ERROR_SUCCESS , "Failed to create directory table\n"); + + res = run_query(hdb, + "CREATE TABLE `Property` ( " + "`Property` CHAR(72) NOT NULL, " + "`Value` CHAR(255) " + "PRIMARY KEY `Property`)"); + ok(res == ERROR_SUCCESS , "Failed to create directory table\n"); + + sprintf(query, "INSERT INTO `Property` " + "(`Property`, `Value`) " + "VALUES( 'ProductCode', '%s' )", prodcode); + res = run_query(hdb, query); + ok(res == ERROR_SUCCESS , "Failed\n"); + + res = MsiDatabaseCommit(hdb); + ok(res == ERROR_SUCCESS, "Failed to commit database\n"); + + return hdb; +} + static void test_usefeature(void) { INSTALLSTATE r; if (!pMsiUseFeatureExA) { - skip("MsiUseFeatureExA not implemented\n"); + win_skip("MsiUseFeatureExA not implemented\n"); return; } @@ -292,7 +408,7 @@ static void test_MsiGetFileHash(void) if (!pMsiGetFileHashA) { - skip("MsiGetFileHash not implemented\n"); + win_skip("MsiGetFileHash not implemented\n"); return; } @@ -326,6 +442,8 @@ static void test_MsiGetFileHash(void) for (i = 0; i < sizeof(hash_data) / sizeof(hash_data[0]); i++) { + int ret; + create_file(name, hash_data[i].data, hash_data[i].size); memset(&hash, 0, sizeof(MSIFILEHASHINFO)); @@ -333,7 +451,11 @@ static void test_MsiGetFileHash(void) r = pMsiGetFileHashA(name, 0, &hash); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(!memcmp(&hash, &hash_data[i].hash, HASHSIZE), "Hash incorrect\n"); + + ret = memcmp(&hash, &hash_data[i].hash, HASHSIZE); + ok(ret == 0 || + broken(ret != 0), /* win95 */ + "Hash incorrect\n"); DeleteFile(name); } @@ -383,7 +505,7 @@ static void create_test_guid(LPSTR prodcode, LPSTR squashed) hr = CoCreateGuid(&guid); ok(hr == S_OK, "Expected S_OK, got %d\n", hr); - size = StringFromGUID2(&guid, (LPOLESTR)guidW, MAX_PATH); + size = StringFromGUID2(&guid, guidW, MAX_PATH); ok(size == 39, "Expected 39, got %d\n", hr); WideCharToMultiByte(CP_ACP, 0, guidW, size, prodcode, MAX_PATH, NULL, NULL); @@ -394,15 +516,20 @@ static void create_test_guid(LPSTR prodcode, LPSTR squashed) static void get_user_sid(LPSTR *usersid) { HANDLE token; - BYTE buf[1024]; DWORD size; PTOKEN_USER user; OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token); - size = sizeof(buf); - GetTokenInformation(token, TokenUser, (void *)buf, size, &size); - user = (PTOKEN_USER)buf; + + size = 0; + GetTokenInformation(token, TokenUser, NULL, size, &size); + user = HeapAlloc(GetProcessHeap(), 0, size); + + GetTokenInformation(token, TokenUser, user, size, &size); pConvertSidToStringSidA(user->User.Sid, usersid); + + HeapFree(GetProcessHeap(), 0, user); + CloseHandle(token); } static void test_MsiQueryProductState(void) @@ -634,10 +761,8 @@ static const char table_enc85[] = /* * Encodes a base85 guid given a GUID pointer * Caller should provide a 21 character buffer for the encoded string. - * - * returns TRUE if successful, FALSE if not */ -static BOOL encode_base85_guid( GUID *guid, LPWSTR str ) +static void encode_base85_guid( GUID *guid, LPWSTR str ) { unsigned int x, *p, i; @@ -656,8 +781,6 @@ static BOOL encode_base85_guid( GUID *guid, LPWSTR str ) *str++ = table_enc85[x%85]; } *str = 0; - - return TRUE; } static void compose_base85_guid(LPSTR component, LPSTR comp_base85, LPSTR squashed) @@ -672,7 +795,7 @@ static void compose_base85_guid(LPSTR component, LPSTR comp_base85, LPSTR squash hr = CoCreateGuid(&guid); ok(hr == S_OK, "Expected S_OK, got %d\n", hr); - size = StringFromGUID2(&guid, (LPOLESTR)guidW, MAX_PATH); + size = StringFromGUID2(&guid, guidW, MAX_PATH); ok(size == 39, "Expected 39, got %d\n", hr); WideCharToMultiByte(CP_ACP, 0, guidW, size, component, MAX_PATH, NULL, NULL); @@ -684,12 +807,12 @@ static void compose_base85_guid(LPSTR component, LPSTR comp_base85, LPSTR squash static void test_MsiQueryFeatureState(void) { - HKEY userkey, localkey, compkey; + HKEY userkey, localkey, compkey, compkey2; CHAR prodcode[MAX_PATH]; CHAR prod_squashed[MAX_PATH]; CHAR component[MAX_PATH]; CHAR comp_base85[MAX_PATH]; - CHAR comp_squashed[MAX_PATH]; + CHAR comp_squashed[MAX_PATH], comp_squashed2[MAX_PATH]; CHAR keypath[MAX_PATH*2]; INSTALLSTATE state; LPSTR usersid; @@ -697,6 +820,7 @@ static void test_MsiQueryFeatureState(void) create_test_guid(prodcode, prod_squashed); compose_base85_guid(component, comp_base85, comp_squashed); + compose_base85_guid(component, comp_base85 + 20, comp_squashed2); get_user_sid(&usersid); /* NULL prodcode */ @@ -785,7 +909,7 @@ static void test_MsiQueryFeatureState(void) state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); - res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 21); + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 41); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); @@ -799,6 +923,14 @@ static void test_MsiQueryFeatureState(void) res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Components\\"); + lstrcatA(keypath, comp_squashed2); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); @@ -806,20 +938,58 @@ static void test_MsiQueryFeatureState(void) ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); - ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); - res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 1); + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 6); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(compkey2, prod_squashed, 0, REG_SZ, (const BYTE *)"orange", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLSTATE_LOCAL */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"01\\", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLSTATE_SOURCE */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"01", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* bad INSTALLSTATE_SOURCE */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"01a", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLSTATE_SOURCE */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"01", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* bad INSTALLSTATE_SOURCE */ state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); RegDeleteValueA(compkey, prod_squashed); + RegDeleteValueA(compkey2, prod_squashed); RegDeleteKeyA(compkey, ""); + RegDeleteKeyA(compkey2, ""); RegDeleteValueA(localkey, "feature"); RegDeleteValueA(userkey, "feature"); RegDeleteKeyA(userkey, ""); RegCloseKey(compkey); + RegCloseKey(compkey2); RegCloseKey(localkey); RegCloseKey(userkey); @@ -837,7 +1007,7 @@ static void test_MsiQueryFeatureState(void) state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 2); + res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 1); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); /* feature value exists */ @@ -875,7 +1045,7 @@ static void test_MsiQueryFeatureState(void) state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); - res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 21); + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 41); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); @@ -889,6 +1059,14 @@ static void test_MsiQueryFeatureState(void) res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Components\\"); + lstrcatA(keypath, comp_squashed2); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); @@ -896,20 +1074,29 @@ static void test_MsiQueryFeatureState(void) ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); - ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); - res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 1); + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(compkey2, prod_squashed, 0, REG_SZ, (const BYTE *)"orange", 7); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); RegDeleteValueA(compkey, prod_squashed); + RegDeleteValueA(compkey2, prod_squashed); RegDeleteKeyA(compkey, ""); + RegDeleteKeyA(compkey2, ""); RegDeleteValueA(localkey, "feature"); RegDeleteValueA(userkey, "feature"); RegDeleteKeyA(userkey, ""); RegCloseKey(compkey); + RegCloseKey(compkey2); RegCloseKey(localkey); RegCloseKey(userkey); @@ -925,7 +1112,7 @@ static void test_MsiQueryFeatureState(void) state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 2); + res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 1); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); /* feature value exists */ @@ -962,7 +1149,7 @@ static void test_MsiQueryFeatureState(void) state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); - res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 21); + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 41); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); @@ -975,6 +1162,13 @@ static void test_MsiQueryFeatureState(void) res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, "S-1-5-18\\Components\\"); + lstrcatA(keypath, comp_squashed2); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); @@ -982,22 +1176,32 @@ static void test_MsiQueryFeatureState(void) ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); - ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); - res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 1); + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(compkey2, prod_squashed, 0, REG_SZ, (const BYTE *)"orange", 7); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); RegDeleteValueA(compkey, prod_squashed); + RegDeleteValueA(compkey2, prod_squashed); RegDeleteKeyA(compkey, ""); + RegDeleteKeyA(compkey2, ""); RegDeleteValueA(localkey, "feature"); RegDeleteValueA(userkey, "feature"); RegDeleteKeyA(userkey, ""); RegCloseKey(compkey); + RegCloseKey(compkey2); RegCloseKey(localkey); RegCloseKey(userkey); + LocalFree(usersid); } static void test_MsiQueryComponentState(void) @@ -1018,7 +1222,7 @@ static void test_MsiQueryComponentState(void) if (!pMsiQueryComponentStateA) { - skip("MsiQueryComponentStateA not implemented\n"); + win_skip("MsiQueryComponentStateA not implemented\n"); return; } @@ -1123,11 +1327,55 @@ static void test_MsiQueryComponentState(void) state = MAGIC_ERROR; r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(state == INSTALLSTATE_NOTUSED, "Expected INSTALLSTATE_NOTUSED, got %d\n", state); + ok(state == INSTALLSTATE_NOTUSED || state == INSTALLSTATE_LOCAL, + "Expected INSTALLSTATE_NOTUSED or INSTALLSTATE_LOCAL, got %d\n", state); + + /* NULL component, product exists */ + state = MAGIC_ERROR; + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, NULL, &state); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(state == MAGIC_ERROR, "Expected state not changed, got %d\n", state); res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"hi", 2); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + /* INSTALLSTATE_LOCAL */ + state = MAGIC_ERROR; + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"01\\", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLSTATE_SOURCE */ + state = MAGIC_ERROR; + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"01", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* bad INSTALLSTATE_SOURCE */ + state = MAGIC_ERROR; + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"01a", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLSTATE_SOURCE */ + state = MAGIC_ERROR; + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"01", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* bad INSTALLSTATE_SOURCE */ state = MAGIC_ERROR; r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, component, &state); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); @@ -1201,7 +1449,8 @@ static void test_MsiQueryComponentState(void) state = MAGIC_ERROR; r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, component, &state); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(state == INSTALLSTATE_NOTUSED, "Expected INSTALLSTATE_NOTUSED, got %d\n", state); + ok(state == INSTALLSTATE_NOTUSED || state == INSTALLSTATE_LOCAL, + "Expected INSTALLSTATE_NOTUSED or INSTALLSTATE_LOCAL, got %d\n", state); res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"hi", 2); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); @@ -1272,6 +1521,7 @@ static void test_MsiQueryComponentState(void) RegDeleteKeyA(compkey, ""); RegCloseKey(prodkey); RegCloseKey(compkey); + LocalFree(usersid); } static void test_MsiGetComponentPath(void) @@ -1572,7 +1822,6 @@ static void test_MsiGetComponentPath(void) RegDeleteKeyA(compkey, ""); RegCloseKey(prodkey); RegCloseKey(compkey); - RegCloseKey(installprop); DeleteFileA("C:\\imapath"); lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); @@ -1625,6 +1874,7 @@ static void test_MsiGetComponentPath(void) RegCloseKey(prodkey); RegCloseKey(compkey); DeleteFileA("C:\\imapath"); + LocalFree(usersid); } static void test_MsiGetProductCode(void) @@ -1735,9 +1985,6 @@ static void test_MsiGetProductCode(void) RegDeleteKeyA(prodkey, ""); RegCloseKey(prodkey); - RegDeleteKeyA(prodkey, ""); - RegCloseKey(prodkey); - lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); lstrcatA(keypath, prod_squashed); @@ -1884,6 +2131,7 @@ static void test_MsiGetProductCode(void) RegDeleteValueA(compkey, prod2_squashed); RegDeleteKeyA(compkey, ""); RegCloseKey(compkey); + LocalFree(usersid); } static void test_MsiEnumClients(void) @@ -2070,6 +2318,7 @@ static void test_MsiEnumClients(void) RegDeleteValueA(compkey, prod2_squashed); RegDeleteKeyA(compkey, ""); RegCloseKey(compkey); + LocalFree(usersid); } static void get_version_info(LPSTR path, LPSTR *vercheck, LPDWORD verchecksz, @@ -3456,12 +3705,31 @@ static void test_MsiGetProductInfo(void) ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); ok(sz == 2, "Expected 2, got %d\n", sz); + /* SourceList key does not exist */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGENAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), + "Expected buf to be unchanged, got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected sz to be unchanged, got %d\n", sz); + res = RegCreateKeyA(prodkey, "SourceList", &source); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + /* SourceList key exists, but PackageName val does not exist */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGENAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + res = RegSetValueExA(source, "PackageName", 0, REG_SZ, (LPBYTE)"packname", 9); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + /* PackageName val exists */ sz = MAX_PATH; lstrcpyA(buf, "apple"); r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGENAME, buf, &sz); @@ -3582,6 +3850,7 @@ static void test_MsiGetProductInfo(void) RegCloseKey(localkey); RegCloseKey(source); RegCloseKey(prodkey); + LocalFree(usersid); } static void test_MsiGetProductInfoEx(void) @@ -3601,7 +3870,7 @@ static void test_MsiGetProductInfoEx(void) if (!pMsiGetProductInfoExA) { - skip("MsiGetProductInfoExA is not available\n"); + win_skip("MsiGetProductInfoExA is not available\n"); return; } @@ -3838,7 +4107,6 @@ static void test_MsiGetProductInfoEx(void) INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); - ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); ok(sz == 10, "Expected 10, got %d\n", sz); /* szValue is NULL, pcchValue is exactly 5 */ @@ -6320,6 +6588,7 @@ static void test_MsiGetProductInfoEx(void) RegDeleteValueA(prodkey, "HelpLink"); RegDeleteKeyA(prodkey, ""); RegCloseKey(prodkey); + LocalFree(usersid); } #define INIT_USERINFO() \ @@ -6899,6 +7168,3796 @@ static void test_MsiGetUserInfo(void) RegCloseKey(userprod); RegDeleteKeyA(prodkey, ""); RegCloseKey(prodkey); + LocalFree(usersid); +} + +static void test_MsiOpenProduct(void) +{ + MSIHANDLE hprod, hdb; + CHAR val[MAX_PATH]; + CHAR path[MAX_PATH]; + CHAR keypath[MAX_PATH*2]; + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + HKEY prodkey, userkey, props; + LPSTR usersid; + DWORD size; + LONG res; + UINT r; + + GetCurrentDirectoryA(MAX_PATH, path); + lstrcatA(path, "\\"); + + create_test_guid(prodcode, prod_squashed); + get_user_sid(&usersid); + + hdb = create_package_db(prodcode); + MsiCloseHandle(hdb); + + /* NULL szProduct */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(NULL, &hprod); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + /* empty szProduct */ + hprod = 0xdeadbeef; + r = MsiOpenProductA("", &hprod); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + /* garbage szProduct */ + hprod = 0xdeadbeef; + r = MsiOpenProductA("garbage", &hprod); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + /* guid without brackets */ + hprod = 0xdeadbeef; + r = MsiOpenProductA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", &hprod); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + /* guid with brackets */ + hprod = 0xdeadbeef; + r = MsiOpenProductA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + /* same length as guid, but random */ + hprod = 0xdeadbeef; + r = MsiOpenProductA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93", &hprod); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + /* hProduct is NULL */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* managed product key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + res = RegCreateKeyA(userkey, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + lstrcpyA(val, path); + lstrcatA(val, "\\winetest.msi"); + res = RegSetValueExA(props, "ManagedLocalPackage", 0, REG_SZ, + (const BYTE *)val, lstrlenA(val) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ManagedLocalPackage value exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(hprod != 0 && hprod != 0xdeadbeef, "Expected a valid product handle\n"); + + size = MAX_PATH; + r = MsiGetPropertyA(hprod, "ProductCode", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, prodcode), "Expected \"%s\", got \"%s\"\n", prodcode, val); + ok(size == lstrlenA(prodcode), "Expected %d, got %d\n", lstrlenA(prodcode), size); + + MsiCloseHandle(hprod); + + RegDeleteValueA(props, "ManagedLocalPackage"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* unmanaged product key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + res = RegCreateKeyA(userkey, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + lstrcpyA(val, path); + lstrcatA(val, "\\winetest.msi"); + res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ, + (const BYTE *)val, lstrlenA(val) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(hprod != 0 && hprod != 0xdeadbeef, "Expected a valid product handle\n"); + + size = MAX_PATH; + r = MsiGetPropertyA(hprod, "ProductCode", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, prodcode), "Expected \"%s\", got \"%s\"\n", prodcode, val); + ok(size == lstrlenA(prodcode), "Expected %d, got %d\n", lstrlenA(prodcode), size); + + MsiCloseHandle(hprod); + + RegDeleteValueA(props, "LocalPackage"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* managed product key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\S-1-5-18\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + res = RegCreateKeyA(userkey, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + lstrcpyA(val, path); + lstrcatA(val, "\\winetest.msi"); + res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ, + (const BYTE *)val, lstrlenA(val) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(hprod != 0 && hprod != 0xdeadbeef, "Expected a valid product handle\n"); + + size = MAX_PATH; + r = MsiGetPropertyA(hprod, "ProductCode", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, prodcode), "Expected \"%s\", got \"%s\"\n", prodcode, val); + ok(size == lstrlenA(prodcode), "Expected %d, got %d\n", lstrlenA(prodcode), size); + + MsiCloseHandle(hprod); + + res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ, + (const BYTE *)"winetest.msi", 13); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage has just the package name */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_INSTALL_PACKAGE_OPEN_FAILED || r == ERROR_SUCCESS, + "Expected ERROR_INSTALL_PACKAGE_OPEN_FAILED or ERROR_SUCCESS, got %d\n", r); + if (r == ERROR_SUCCESS) + MsiCloseHandle(hprod); + else + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + lstrcpyA(val, path); + lstrcatA(val, "\\winetest.msi"); + res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ, + (const BYTE *)val, lstrlenA(val) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + DeleteFileA(msifile); + + /* local package does not exist */ + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(hprod == 0xdeadbeef, "Expected hprod to be unchanged\n"); + + RegDeleteValueA(props, "LocalPackage"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + DeleteFileA(msifile); + LocalFree(usersid); +} + +static void test_MsiEnumPatchesEx_usermanaged(LPCSTR usersid, LPCSTR expectedsid) +{ + MSIINSTALLCONTEXT context; + CHAR keypath[MAX_PATH], patch[MAX_PATH]; + CHAR patch_squashed[MAX_PATH], patchcode[MAX_PATH]; + CHAR targetsid[MAX_PATH], targetprod[MAX_PATH]; + CHAR prodcode[MAX_PATH], prod_squashed[MAX_PATH]; + HKEY prodkey, patches, udprod, udpatch, hpatch; + DWORD size, data; + LONG res; + UINT r; + + create_test_guid(prodcode, prod_squashed); + create_test_guid(patch, patch_squashed); + + /* MSIPATCHSTATE_APPLIED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, expectedsid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* managed product key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* patches key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not REG_MULTI_SZ */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)"a\0b\0c\0\0", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not a squashed guid */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + patch_squashed[lstrlenA(patch_squashed) + 1] = '\0'; + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, patch_squashed, 0, REG_SZ, + (const BYTE *)"whatever", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* patch squashed value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* increase the index */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 1, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* increase again */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 2, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* szPatchCode is NULL */ + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, NULL, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* szTargetProductCode is NULL */ + lstrcpyA(patchcode, "apple"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, NULL, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* pdwTargetProductContext is NULL */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + NULL, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* szTargetUserSid is NULL */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, NULL, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(size == lstrlenA(expectedsid) * sizeof(WCHAR), + "Expected %d*sizeof(WCHAR), got %d\n", lstrlenA(expectedsid), size); + + /* pcchTargetUserSid is exactly the length of szTargetUserSid */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = lstrlenA(expectedsid); + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(!strncmp(targetsid, expectedsid, lstrlenA(expectedsid) - 1), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid) * sizeof(WCHAR), + "Expected %d*sizeof(WCHAR), got %d\n", lstrlenA(expectedsid), size); + + /* pcchTargetUserSid has enough room for NULL terminator */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = lstrlenA(expectedsid) + 1; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* both szTargetuserSid and pcchTargetUserSid are NULL */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + + /* MSIPATCHSTATE_SUPERSEDED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, expectedsid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UserData product key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udprod, "Patches", &udpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UserData patches key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udpatch, patch_squashed, &hpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* specific UserData patch key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + data = MSIPATCHSTATE_SUPERSEDED; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* MSIPATCHSTATE_OBSOLETED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_OBSOLETED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + data = MSIPATCHSTATE_OBSOLETED; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value is obsoleted */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_OBSOLETED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* MSIPATCHSTATE_REGISTERED */ + /* FIXME */ + + /* MSIPATCHSTATE_ALL */ + + /* 1st */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERMANAGED, + "Expected MSIINSTALLCONTEXT_USERMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* same patch in multiple places, only one is enumerated */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSIPATCHSTATE_ALL, 1, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + RegDeleteValueA(hpatch, "State"); + RegDeleteKeyA(hpatch, ""); + RegCloseKey(hpatch); + RegDeleteKeyA(udpatch, ""); + RegCloseKey(udpatch); + RegDeleteKeyA(udprod, ""); + RegCloseKey(udprod); + RegDeleteValueA(patches, "Patches"); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + +static void test_MsiEnumPatchesEx_userunmanaged(LPCSTR usersid, LPCSTR expectedsid) +{ + MSIINSTALLCONTEXT context; + CHAR keypath[MAX_PATH], patch[MAX_PATH]; + CHAR patch_squashed[MAX_PATH], patchcode[MAX_PATH]; + CHAR targetsid[MAX_PATH], targetprod[MAX_PATH]; + CHAR prodcode[MAX_PATH], prod_squashed[MAX_PATH]; + HKEY prodkey, patches, udprod, udpatch; + HKEY userkey, hpatch; + DWORD size, data; + LONG res; + UINT r; + + create_test_guid(prodcode, prod_squashed); + create_test_guid(patch, patch_squashed); + + /* MSIPATCHSTATE_APPLIED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* current user product key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not REG_MULTI_SZ */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)"a\0b\0c\0\0", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not a squashed guid */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, patch_squashed, 0, REG_SZ, + (const BYTE *)"whatever", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* patch code value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, expectedsid); + lstrcatA(keypath, "\\Patches\\"); + lstrcatA(keypath, patch_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* userdata patch key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERUNMANAGED, + "Expected MSIINSTALLCONTEXT_USERUNMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* MSIPATCHSTATE_SUPERSEDED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, expectedsid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UserData product key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udprod, "Patches", &udpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UserData patches key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udpatch, patch_squashed, &hpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* specific UserData patch key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + data = MSIPATCHSTATE_SUPERSEDED; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERUNMANAGED, + "Expected MSIINSTALLCONTEXT_USERUNMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* MSIPATCHSTATE_OBSOLETED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_OBSOLETED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + data = MSIPATCHSTATE_OBSOLETED; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value is obsoleted */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_OBSOLETED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERUNMANAGED, + "Expected MSIINSTALLCONTEXT_USERUNMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* MSIPATCHSTATE_REGISTERED */ + /* FIXME */ + + /* MSIPATCHSTATE_ALL */ + + /* 1st */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_USERUNMANAGED, + "Expected MSIINSTALLCONTEXT_USERUNMANAGED, got %d\n", context); + ok(!lstrcmpA(targetsid, expectedsid), + "Expected \"%s\", got \"%s\"\n", expectedsid, targetsid); + ok(size == lstrlenA(expectedsid), + "Expected %d, got %d\n", lstrlenA(expectedsid), size); + + /* same patch in multiple places, only one is enumerated */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_ALL, 1, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + RegDeleteValueA(hpatch, "State"); + RegDeleteKeyA(hpatch, ""); + RegCloseKey(hpatch); + RegDeleteKeyA(udpatch, ""); + RegCloseKey(udpatch); + RegDeleteKeyA(udprod, ""); + RegCloseKey(udprod); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + RegDeleteValueA(patches, patch_squashed); + RegDeleteValueA(patches, "Patches"); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + +static void test_MsiEnumPatchesEx_machine(void) +{ + CHAR keypath[MAX_PATH], patch[MAX_PATH]; + CHAR patch_squashed[MAX_PATH], patchcode[MAX_PATH]; + CHAR targetsid[MAX_PATH], targetprod[MAX_PATH]; + CHAR prodcode[MAX_PATH], prod_squashed[MAX_PATH]; + HKEY prodkey, patches, udprod, udpatch; + HKEY hpatch; + MSIINSTALLCONTEXT context; + DWORD size, data; + LONG res; + UINT r; + + create_test_guid(prodcode, prod_squashed); + create_test_guid(patch, patch_squashed); + + /* MSIPATCHSTATE_APPLIED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local product key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not REG_MULTI_SZ */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)"a\0b\0c\0\0", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not a squashed guid */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + patch_squashed[lstrlenA(patch_squashed) + 1] = '\0'; + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, patch_squashed, 0, REG_SZ, + (const BYTE *)"whatever", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* patch code value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_MACHINE, + "Expected MSIINSTALLCONTEXT_MACHINE, got %d\n", context); + ok(!lstrcmpA(targetsid, ""), "Expected \"\", got \"%s\"\n", targetsid); + ok(size == 0, "Expected 0, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\S-1-5-18\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData product key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_MACHINE, + "Expected MSIINSTALLCONTEXT_MACHINE, got %d\n", context); + ok(!lstrcmpA(targetsid, ""), + "Expected \"\", got \"%s\"\n", targetsid); + ok(size == 0, "Expected 0, got %d\n", size); + + res = RegCreateKeyA(udprod, "Patches", &udpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData Patches key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_MACHINE, + "Expected MSIINSTALLCONTEXT_MACHINE, got %d\n", context); + ok(!lstrcmpA(targetsid, ""), + "Expected \"\", got \"%s\"\n", targetsid); + ok(size == 0, "Expected 0, got %d\n", size); + + res = RegCreateKeyA(udpatch, patch_squashed, &hpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData Product patch key exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + data = MSIPATCHSTATE_APPLIED; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value exists */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_APPLIED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_MACHINE, + "Expected MSIINSTALLCONTEXT_MACHINE, got %d\n", context); + ok(!lstrcmpA(targetsid, ""), + "Expected \"\", got \"%s\"\n", targetsid); + ok(size == 0, "Expected 0, got %d\n", size); + + /* MSIPATCHSTATE_SUPERSEDED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + data = MSIPATCHSTATE_SUPERSEDED; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value is MSIPATCHSTATE_SUPERSEDED */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_SUPERSEDED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_MACHINE, + "Expected MSIINSTALLCONTEXT_MACHINE, got %d\n", context); + ok(!lstrcmpA(targetsid, ""), "Expected \"\", got \"%s\"\n", targetsid); + ok(size == 0, "Expected 0, got %d\n", size); + + /* MSIPATCHSTATE_OBSOLETED */ + + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_OBSOLETED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + data = MSIPATCHSTATE_OBSOLETED; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value is obsoleted */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_OBSOLETED, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_MACHINE, + "Expected MSIINSTALLCONTEXT_MACHINE, got %d\n", context); + ok(!lstrcmpA(targetsid, ""), "Expected \"\", got \"%s\"\n", targetsid); + ok(size == 0, "Expected 0, got %d\n", size); + + /* MSIPATCHSTATE_REGISTERED */ + /* FIXME */ + + /* MSIPATCHSTATE_ALL */ + + /* 1st */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patchcode, patch), + "Expected \"%s\", got \"%s\"\n", patch, patchcode); + ok(!lstrcmpA(targetprod, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, targetprod); + ok(context == MSIINSTALLCONTEXT_MACHINE, + "Expected MSIINSTALLCONTEXT_MACHINE, got %d\n", context); + ok(!lstrcmpA(targetsid, ""), "Expected \"\", got \"%s\"\n", targetsid); + ok(size == 0, "Expected 0, got %d\n", size); + + /* same patch in multiple places, only one is enumerated */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_ALL, 1, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + RegDeleteValueA(patches, patch_squashed); + RegDeleteValueA(patches, "Patches"); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteValueA(hpatch, "State"); + RegDeleteKeyA(hpatch, ""); + RegCloseKey(hpatch); + RegDeleteKeyA(udpatch, ""); + RegCloseKey(udpatch); + RegDeleteKeyA(udprod, ""); + RegCloseKey(udprod); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + +static void test_MsiEnumPatchesEx(void) +{ + CHAR targetsid[MAX_PATH], targetprod[MAX_PATH]; + CHAR prodcode[MAX_PATH], prod_squashed[MAX_PATH]; + CHAR patchcode[MAX_PATH]; + MSIINSTALLCONTEXT context; + LPSTR usersid; + DWORD size; + UINT r; + + if (!pMsiEnumPatchesExA) + { + win_skip("MsiEnumPatchesExA not implemented\n"); + return; + } + + create_test_guid(prodcode, prod_squashed); + get_user_sid(&usersid); + + /* empty szProductCode */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, &context, + targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* garbage szProductCode */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, &context, + targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* guid without brackets */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_ALL, + 0, patchcode, targetprod, &context, + targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* guid with brackets */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA("{6700E8CF-95AB-4D9C-BC2C-15840DDA7A5D}", usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_ALL, + 0, patchcode, targetprod, &context, + targetsid, &size); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* szUserSid is S-1-5-18 */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, "S-1-5-18", + MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_ALL, + 0, patchcode, targetprod, &context, + targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* dwContext is MSIINSTALLCONTEXT_MACHINE, but szUserSid is non-NULL */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_MACHINE, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* dwContext is out of bounds */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, 0, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* dwContext is out of bounds */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_ALL + 1, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* dwFilter is out of bounds */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_INVALID, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* dwFilter is out of bounds */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + size = MAX_PATH; + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_ALL + 1, 0, patchcode, targetprod, + &context, targetsid, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* pcchTargetUserSid is NULL while szTargetUserSid is non-NULL */ + lstrcpyA(patchcode, "apple"); + lstrcpyA(targetprod, "banana"); + context = 0xdeadbeef; + lstrcpyA(targetsid, "kiwi"); + r = pMsiEnumPatchesExA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSIPATCHSTATE_ALL, 0, patchcode, targetprod, + &context, targetsid, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patchcode, "apple"), + "Expected patchcode to be unchanged, got %s\n", patchcode); + ok(!lstrcmpA(targetprod, "banana"), + "Expected targetprod to be unchanged, got %s\n", targetprod); + ok(context == 0xdeadbeef, + "Expected context to be unchanged, got %d\n", context); + ok(!lstrcmpA(targetsid, "kiwi"), + "Expected targetsid to be unchanged, got %s\n", targetsid); + + test_MsiEnumPatchesEx_usermanaged(usersid, usersid); + test_MsiEnumPatchesEx_usermanaged(NULL, usersid); + test_MsiEnumPatchesEx_usermanaged("S-1-2-34", "S-1-2-34"); + test_MsiEnumPatchesEx_userunmanaged(usersid, usersid); + test_MsiEnumPatchesEx_userunmanaged(NULL, usersid); + /* FIXME: Successfully test userunmanaged with a different user */ + test_MsiEnumPatchesEx_machine(); + LocalFree(usersid); +} + +static void test_MsiEnumPatches(void) +{ + CHAR keypath[MAX_PATH], patch[MAX_PATH]; + CHAR patchcode[MAX_PATH], patch_squashed[MAX_PATH]; + CHAR prodcode[MAX_PATH], prod_squashed[MAX_PATH]; + CHAR transforms[MAX_PATH]; + WCHAR patchW[MAX_PATH], prodcodeW[MAX_PATH], transformsW[MAX_PATH]; + HKEY prodkey, patches, udprod; + HKEY userkey, hpatch, udpatch; + DWORD size, data; + LPSTR usersid; + LONG res; + UINT r; + + create_test_guid(prodcode, prod_squashed); + create_test_guid(patchcode, patch_squashed); + get_user_sid(&usersid); + + /* NULL szProduct */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(NULL, 0, patch, transforms, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* empty szProduct */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA("", 0, patch, transforms, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* garbage szProduct */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA("garbage", 0, patch, transforms, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* guid without brackets */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", 0, patch, + transforms, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* guid with brackets */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", 0, patch, + transforms, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* same length as guid, but random */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93", 0, patch, + transforms, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* managed product key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* patches key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not REG_MULTI_SZ */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)"a\0b\0c\0\0", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not a squashed guid */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + patch_squashed[lstrlenA(patch_squashed) + 1] = '\0'; + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, patch_squashed, 0, REG_SZ, + (const BYTE *)"whatever", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* patch squashed value exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whatever"), + "Expected \"whatever\", got \"%s\"\n", transforms); + ok(size == 8 || size == MAX_PATH, "Expected 8 or MAX_PATH, got %d\n", size); + + /* lpPatchBuf is NULL */ + size = MAX_PATH; + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, NULL, transforms, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* lpTransformsBuf is NULL, pcchTransformsBuf is not */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + r = MsiEnumPatchesA(prodcode, 0, patch, NULL, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* pcchTransformsBuf is NULL, lpTransformsBuf is not */ + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + + /* pcchTransformsBuf is too small */ + size = 6; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whate"), + "Expected \"whate\", got \"%s\"\n", transforms); + ok(size == 8 || size == 16, "Expected 8 or 16, got %d\n", size); + + /* increase the index */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 1, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* increase again */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 2, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + RegDeleteValueA(patches, "Patches"); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* current user product key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not REG_MULTI_SZ */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)"a\0b\0c\0\0", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not a squashed guid */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + patch_squashed[lstrlenA(patch_squashed) + 1] = '\0'; + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, patch_squashed, 0, REG_SZ, + (const BYTE *)"whatever", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* patch code value exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Patches\\"); + lstrcatA(keypath, patch_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* userdata patch key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whatever"), + "Expected \"whatever\", got \"%s\"\n", transforms); + ok(size == 8 || size == MAX_PATH, "Expected 8 or MAX_PATH, got %d\n", size); + + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + RegDeleteValueA(patches, patch_squashed); + RegDeleteValueA(patches, "Patches"); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local product key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not REG_MULTI_SZ */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)"a\0b\0c\0\0", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists, is not a squashed guid */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + patch_squashed[lstrlenA(patch_squashed) + 1] = '\0'; + res = RegSetValueExA(patches, "Patches", 0, REG_MULTI_SZ, + (const BYTE *)patch_squashed, + lstrlenA(patch_squashed) + 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches value exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(patches, patch_squashed, 0, REG_SZ, + (const BYTE *)"whatever", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* patch code value exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whatever"), + "Expected \"whatever\", got \"%s\"\n", transforms); + ok(size == 8 || size == MAX_PATH, "Expected 8 or MAX_PATH, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\S-1-5-18\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData product key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whatever"), + "Expected \"whatever\", got \"%s\"\n", transforms); + ok(size == 8 || size == MAX_PATH, "Expected 8 or MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(udprod, "Patches", &udpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData Patches key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whatever"), + "Expected \"whatever\", got \"%s\"\n", transforms); + ok(size == 8 || size == MAX_PATH, "Expected 8 or MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(udpatch, patch_squashed, &hpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData Product patch key exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(patch, "apple"), + "Expected lpPatchBuf to be unchanged, got \"%s\"\n", patch); + ok(!lstrcmpA(transforms, "banana"), + "Expected lpTransformsBuf to be unchanged, got \"%s\"\n", transforms); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + data = MSIPATCHSTATE_APPLIED; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&data, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value exists */ + size = MAX_PATH; + lstrcpyA(patch, "apple"); + lstrcpyA(transforms, "banana"); + r = MsiEnumPatchesA(prodcode, 0, patch, transforms, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whatever"), + "Expected \"whatever\", got \"%s\"\n", transforms); + ok(size == 8 || size == MAX_PATH, "Expected 8 or MAX_PATH, got %d\n", size); + + /* now duplicate some of the tests for the W version */ + + /* pcchTransformsBuf is too small */ + size = 6; + MultiByteToWideChar( CP_ACP, 0, prodcode, -1, prodcodeW, MAX_PATH ); + MultiByteToWideChar( CP_ACP, 0, "apple", -1, patchW, MAX_PATH ); + MultiByteToWideChar( CP_ACP, 0, "banana", -1, transformsW, MAX_PATH ); + r = MsiEnumPatchesW(prodcodeW, 0, patchW, transformsW, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + WideCharToMultiByte( CP_ACP, 0, patchW, -1, patch, MAX_PATH, NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, transformsW, -1, transforms, MAX_PATH, NULL, NULL ); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whate"), + "Expected \"whate\", got \"%s\"\n", transforms); + ok(size == 8, "Expected 8, got %d\n", size); + + /* patch code value exists */ + size = MAX_PATH; + MultiByteToWideChar( CP_ACP, 0, "apple", -1, patchW, MAX_PATH ); + MultiByteToWideChar( CP_ACP, 0, "banana", -1, transformsW, MAX_PATH ); + r = MsiEnumPatchesW(prodcodeW, 0, patchW, transformsW, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + WideCharToMultiByte( CP_ACP, 0, patchW, -1, patch, MAX_PATH, NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, transformsW, -1, transforms, MAX_PATH, NULL, NULL ); + ok(!lstrcmpA(patch, patchcode), + "Expected \"%s\", got \"%s\"\n", patchcode, patch); + ok(!lstrcmpA(transforms, "whatever"), + "Expected \"whatever\", got \"%s\"\n", transforms); + ok(size == 8 || size == MAX_PATH, "Expected 8 or MAX_PATH, got %d\n", size); + + RegDeleteValueA(patches, patch_squashed); + RegDeleteValueA(patches, "Patches"); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteValueA(hpatch, "State"); + RegDeleteKeyA(hpatch, ""); + RegCloseKey(hpatch); + RegDeleteKeyA(udpatch, ""); + RegCloseKey(udpatch); + RegDeleteKeyA(udprod, ""); + RegCloseKey(udprod); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + LocalFree(usersid); +} + +static void test_MsiGetPatchInfoEx(void) +{ + CHAR keypath[MAX_PATH], val[MAX_PATH]; + CHAR patchcode[MAX_PATH], patch_squashed[MAX_PATH]; + CHAR prodcode[MAX_PATH], prod_squashed[MAX_PATH]; + HKEY prodkey, patches, udprod, props; + HKEY hpatch, udpatch, prodpatches; + LPSTR usersid; + DWORD size; + LONG res; + UINT r; + + if (!pMsiGetPatchInfoExA) + { + win_skip("MsiGetPatchInfoEx not implemented\n"); + return; + } + + create_test_guid(prodcode, prod_squashed); + create_test_guid(patchcode, patch_squashed); + get_user_sid(&usersid); + + /* NULL szPatchCode */ + lstrcpyA(val, "apple"); + size = MAX_PATH; + r = pMsiGetPatchInfoExA(NULL, prodcode, NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* empty szPatchCode */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA("", prodcode, NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* garbage szPatchCode */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA("garbage", prodcode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* guid without brackets */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", prodcode, + NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* guid with brackets */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", prodcode, + NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* same length as guid, but random */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93", prodcode, + NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* NULL szProductCode */ + lstrcpyA(val, "apple"); + size = MAX_PATH; + r = pMsiGetPatchInfoExA(patchcode, NULL, NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* empty szProductCode */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, "", NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* garbage szProductCode */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, "garbage", NULL, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* guid without brackets */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, "6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", + NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* guid with brackets */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, "{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", + NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* same length as guid, but random */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, "A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93", + NULL, MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* szUserSid cannot be S-1-5-18 for MSIINSTALLCONTEXT_USERMANAGED */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, "S-1-5-18", + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* szUserSid cannot be S-1-5-18 for MSIINSTALLCONTEXT_USERUNMANAGED */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, "S-1-5-18", + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* szUserSid cannot be S-1-5-18 for MSIINSTALLCONTEXT_MACHINE */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, "S-1-5-18", + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* szUserSid must be NULL for MSIINSTALLCONTEXT_MACHINE */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* dwContext is out of range */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_NONE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* dwContext is out of range */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_ALL, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* dwContext is invalid */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, 3, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData product key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udprod, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udprod, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(patches, patch_squashed, &hpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* managed product key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &prodpatches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(prodpatches, patch_squashed, 0, REG_SZ, + (const BYTE *)"transforms", 11); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* specific patch value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Patches\\"); + lstrcatA(keypath, patch_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UserData Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, ""), "Expected \"\", got \"%s\"\n", val); + ok(size == 0, "Expected 0, got %d\n", size); + + res = RegSetValueExA(udpatch, "ManagedLocalPackage", 0, REG_SZ, + (const BYTE *)"pack", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ManagedLocalPatch value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "pack"), "Expected \"pack\", got \"%s\"\n", val); + ok(size == 4, "Expected 4, got %d\n", size); + + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_TRANSFORMS, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "transforms"), "Expected \"transforms\", got \"%s\"\n", val); + ok(size == 10, "Expected 10, got %d\n", size); + + res = RegSetValueExA(hpatch, "Installed", 0, REG_SZ, + (const BYTE *)"mydate", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Installed value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLDATE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "mydate"), "Expected \"mydate\", got \"%s\"\n", val); + ok(size == 6, "Expected 6, got %d\n", size); + + res = RegSetValueExA(hpatch, "Uninstallable", 0, REG_SZ, + (const BYTE *)"yes", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Uninstallable value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_UNINSTALLABLE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "yes"), "Expected \"yes\", got \"%s\"\n", val); + ok(size == 3, "Expected 3, got %d\n", size); + + res = RegSetValueExA(hpatch, "State", 0, REG_SZ, + (const BYTE *)"good", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PATCHSTATE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "good"), "Expected \"good\", got \"%s\"\n", val); + ok(size == 4, "Expected 4, got %d\n", size); + + size = 1; + res = RegSetValueExA(hpatch, "State", 0, REG_DWORD, + (const BYTE *)&size, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* State value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PATCHSTATE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine ok(!lstrcmpA(val, "1"), "Expected \"1\", got \"%s\"\n", val); + ok(size == 1, "Expected 1, got %d\n", size); + + res = RegSetValueExA(hpatch, "DisplayName", 0, REG_SZ, + (const BYTE *)"display", 8); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_DISPLAYNAME, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "display"), "Expected \"display\", got \"%s\"\n", val); + ok(size == 7, "Expected 7, got %d\n", size); + + res = RegSetValueExA(hpatch, "MoreInfoURL", 0, REG_SZ, + (const BYTE *)"moreinfo", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* MoreInfoURL value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_MOREINFOURL, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "moreinfo"), "Expected \"moreinfo\", got \"%s\"\n", val); + ok(size == 8, "Expected 8, got %d\n", size); + + /* szProperty is invalid */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + "IDontExist", val, &size); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(val, "apple"), "Expected \"apple\", got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* lpValue is NULL, while pcchValue is non-NULL */ + size = MAX_PATH; + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_MOREINFOURL, NULL, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(size == 16, "Expected 16, got %d\n", size); + + /* pcchValue is NULL, while lpValue is non-NULL */ + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_MOREINFOURL, val, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), "Expected \"apple\", got \"%s\"\n", val); + + /* both lpValue and pcchValue are NULL */ + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_MOREINFOURL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* pcchValue doesn't have enough room for NULL terminator */ + size = 8; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_MOREINFOURL, val, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(val, "moreinf"), + "Expected \"moreinf\", got \"%s\"\n", val); + ok(size == 16, "Expected 16, got %d\n", size); + + /* pcchValue has exactly enough room for NULL terminator */ + size = 9; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_MOREINFOURL, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "moreinfo"), + "Expected \"moreinfo\", got \"%s\"\n", val); + ok(size == 8, "Expected 8, got %d\n", size); + + /* pcchValue is too small, lpValue is NULL */ + size = 0; + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_MOREINFOURL, NULL, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(size == 16, "Expected 16, got %d\n", size); + + RegDeleteValueA(prodpatches, patch_squashed); + RegDeleteKeyA(prodpatches, ""); + RegCloseKey(prodpatches); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* UserData is sufficient for all properties + * except INSTALLPROPERTY_TRANSFORMS + */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "pack"), "Expected \"pack\", got \"%s\"\n", val); + ok(size == 4, "Expected 4, got %d\n", size); + + /* UserData is sufficient for all properties + * except INSTALLPROPERTY_TRANSFORMS + */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_TRANSFORMS, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), "Expected \"apple\", got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + RegDeleteValueA(hpatch, "MoreInfoURL"); + RegDeleteValueA(hpatch, "Display"); + RegDeleteValueA(hpatch, "State"); + RegDeleteValueA(hpatch, "Uninstallable"); + RegDeleteValueA(hpatch, "Installed"); + RegDeleteValueA(udpatch, "ManagedLocalPackage"); + RegDeleteKeyA(udpatch, ""); + RegCloseKey(udpatch); + RegDeleteKeyA(hpatch, ""); + RegCloseKey(hpatch); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(udprod, ""); + RegCloseKey(udprod); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData product key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udprod, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udprod, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(patches, patch_squashed, &hpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* current user product key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &prodpatches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(prodpatches, patch_squashed, 0, REG_SZ, + (const BYTE *)"transforms", 11); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* specific patch value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Patches\\"); + lstrcatA(keypath, patch_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UserData Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, ""), "Expected \"\", got \"%s\"\n", val); + ok(size == 0, "Expected 0, got %d\n", size); + + res = RegSetValueExA(udpatch, "LocalPackage", 0, REG_SZ, + (const BYTE *)"pack", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPatch value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "pack"), "Expected \"pack\", got \"%s\"\n", val); + ok(size == 4, "Expected 4, got %d\n", size); + + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_TRANSFORMS, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "transforms"), "Expected \"transforms\", got \"%s\"\n", val); + ok(size == 10, "Expected 10, got %d\n", size); + + RegDeleteValueA(prodpatches, patch_squashed); + RegDeleteKeyA(prodpatches, ""); + RegCloseKey(prodpatches); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* UserData is sufficient for all properties + * except INSTALLPROPERTY_TRANSFORMS + */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "pack"), "Expected \"pack\", got \"%s\"\n", val); + ok(size == 4, "Expected 4, got %d\n", size); + + /* UserData is sufficient for all properties + * except INSTALLPROPERTY_TRANSFORMS + */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_TRANSFORMS, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), "Expected \"apple\", got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + RegDeleteValueA(udpatch, "LocalPackage"); + RegDeleteKeyA(udpatch, ""); + RegCloseKey(udpatch); + RegDeleteKeyA(hpatch, ""); + RegCloseKey(hpatch); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(udprod, ""); + RegCloseKey(udprod); + + /* MSIINSTALLCONTEXT_MACHINE */ + + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer"); + lstrcatA(keypath, "\\UserData\\S-1-5-18\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local UserData product key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udprod, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(udprod, "Patches", &patches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(patches, patch_squashed, &hpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local product key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegCreateKeyA(prodkey, "Patches", &prodpatches); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + res = RegSetValueExA(prodpatches, patch_squashed, 0, REG_SZ, + (const BYTE *)"transforms", 11); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* specific patch value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer"); + lstrcatA(keypath, "\\UserData\\S-1-5-18\\Patches\\"); + lstrcatA(keypath, patch_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &udpatch); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UserData Patches key exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, ""), "Expected \"\", got \"%s\"\n", val); + ok(size == 0, "Expected 0, got %d\n", size); + + res = RegSetValueExA(udpatch, "LocalPackage", 0, REG_SZ, + (const BYTE *)"pack", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPatch value exists */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "pack"), "Expected \"pack\", got \"%s\"\n", val); + ok(size == 4, "Expected 4, got %d\n", size); + + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_TRANSFORMS, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "transforms"), "Expected \"transforms\", got \"%s\"\n", val); + ok(size == 10, "Expected 10, got %d\n", size); + + RegDeleteValueA(prodpatches, patch_squashed); + RegDeleteKeyA(prodpatches, ""); + RegCloseKey(prodpatches); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* UserData is sufficient for all properties + * except INSTALLPROPERTY_TRANSFORMS + */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, "pack"), "Expected \"pack\", got \"%s\"\n", val); + ok(size == 4, "Expected 4, got %d\n", size); + + /* UserData is sufficient for all properties + * except INSTALLPROPERTY_TRANSFORMS + */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = pMsiGetPatchInfoExA(patchcode, prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_TRANSFORMS, val, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + ok(!lstrcmpA(val, "apple"), "Expected \"apple\", got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + RegDeleteValueA(udpatch, "LocalPackage"); + RegDeleteKeyA(udpatch, ""); + RegCloseKey(udpatch); + RegDeleteKeyA(hpatch, ""); + RegCloseKey(hpatch); + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(udprod, ""); + RegCloseKey(udprod); + LocalFree(usersid); +} + +static void test_MsiEnumProducts(void) +{ + UINT r; + int found1, found2, found3; + DWORD index; + char product1[39], product2[39], product3[39], guid[39]; + char product_squashed1[33], product_squashed2[33], product_squashed3[33]; + char keypath1[MAX_PATH], keypath2[MAX_PATH], keypath3[MAX_PATH]; + char *usersid; + HKEY key1, key2, key3; + + create_test_guid(product1, product_squashed1); + create_test_guid(product2, product_squashed2); + create_test_guid(product3, product_squashed3); + get_user_sid(&usersid); + + strcpy(keypath1, "Software\\Classes\\Installer\\Products\\"); + strcat(keypath1, product_squashed1); + + r = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath1, &key1); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + strcpy(keypath2, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + strcat(keypath2, usersid); + strcat(keypath2, "\\Installer\\Products\\"); + strcat(keypath2, product_squashed2); + + r = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath2, &key2); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + strcpy(keypath3, "Software\\Microsoft\\Installer\\Products\\"); + strcat(keypath3, product_squashed3); + + r = RegCreateKeyA(HKEY_CURRENT_USER, keypath3, &key3); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + index = 0; + r = MsiEnumProductsA(index, NULL); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r); + + index = 2; + r = MsiEnumProductsA(index, guid); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r); + + index = 0; + r = MsiEnumProductsA(index, guid); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + found1 = found2 = found3 = 0; + while ((r = MsiEnumProductsA(index, guid)) == ERROR_SUCCESS) + { + if (!strcmp(product1, guid)) found1 = 1; + if (!strcmp(product2, guid)) found2 = 1; + if (!strcmp(product3, guid)) found3 = 1; + index++; + } + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %u\n", r); + ok(found1, "product1 not found\n"); + ok(found2, "product2 not found\n"); + ok(found3, "product3 not found\n"); + + RegDeleteKeyA(key1, ""); + RegDeleteKeyA(key2, ""); + RegDeleteKeyA(key3, ""); + RegCloseKey(key1); + RegCloseKey(key2); + RegCloseKey(key3); + LocalFree(usersid); } START_TEST(msi) @@ -6911,7 +10970,7 @@ START_TEST(msi) test_MsiGetFileHash(); if (!pConvertSidToStringSidA) - skip("ConvertSidToStringSidA not implemented\n"); + win_skip("ConvertSidToStringSidA not implemented\n"); else { /* These tests rely on get_user_sid that needs ConvertSidToStringSidA */ @@ -6924,6 +10983,11 @@ START_TEST(msi) test_MsiGetProductInfo(); test_MsiGetProductInfoEx(); test_MsiGetUserInfo(); + test_MsiOpenProduct(); + test_MsiEnumPatchesEx(); + test_MsiEnumPatches(); + test_MsiGetPatchInfoEx(); + test_MsiEnumProducts(); } test_MsiGetFileVersion(); diff --git a/rostests/winetests/msi/msi.rbuild b/rostests/winetests/msi/msi.rbuild index 18f8b5e8657..2e9a6d6215e 100644 --- a/rostests/winetests/msi/msi.rbuild +++ b/rostests/winetests/msi/msi.rbuild @@ -3,8 +3,7 @@ . - 0x600 - 0x600 + automation.c db.c format.c @@ -24,7 +23,6 @@ oleaut32 user32 advapi32 - kernel32 version ntdll diff --git a/rostests/winetests/msi/package.c b/rostests/winetests/msi/package.c index 5c8741bee7b..95a2587bf3b 100644 --- a/rostests/winetests/msi/package.c +++ b/rostests/winetests/msi/package.c @@ -26,14 +26,66 @@ #include #include #include +#include #include "wine/test.h" static const char msifile[] = "winetest.msi"; char CURR_DIR[MAX_PATH]; +static UINT (WINAPI *pMsiApplyMultiplePatchesA)(LPCSTR, LPCSTR, LPCSTR); + +static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*); + +static BOOL (WINAPI *pSRRemoveRestorePoint)(DWORD); +static BOOL (WINAPI *pSRSetRestorePointA)(RESTOREPOINTINFOA*, STATEMGRSTATUS*); + +static void init_functionpointers(void) +{ + HMODULE hmsi = GetModuleHandleA("msi.dll"); + HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); + HMODULE hsrclient; + +#define GET_PROC(mod, func) \ + p ## func = (void*)GetProcAddress(mod, #func); + + GET_PROC(hmsi, MsiApplyMultiplePatchesA); + + GET_PROC(hadvapi32, ConvertSidToStringSidA); + + hsrclient = LoadLibraryA("srclient.dll"); + GET_PROC(hsrclient, SRRemoveRestorePoint); + GET_PROC(hsrclient, SRSetRestorePointA); +#undef GET_PROC +} + + +static LPSTR get_user_sid(LPSTR *usersid) +{ + HANDLE token; + BYTE buf[1024]; + DWORD size; + PTOKEN_USER user; + + if (!pConvertSidToStringSidA) + { + win_skip("ConvertSidToStringSidA is not available\n"); + return NULL; + } + + *usersid = NULL; + OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token); + size = sizeof(buf); + GetTokenInformation(token, TokenUser, buf, size, &size); + user = (PTOKEN_USER)buf; + pConvertSidToStringSidA(user->User.Sid, usersid); + ok(*usersid != NULL, "pConvertSidToStringSidA failed lre=%d\n", GetLastError()); + CloseHandle(token); + return *usersid; +} + /* RegDeleteTreeW from dlls/advapi32/registry.c */ -LSTATUS WINAPI package_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey) +static LSTATUS package_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey) { LONG ret; DWORD dwMaxSubkeyLen, dwMaxValueLen; @@ -96,6 +148,169 @@ cleanup: return ret; } +static BOOL squash_guid(LPCWSTR in, LPWSTR out) +{ + DWORD i,n=1; + GUID guid; + + if (FAILED(CLSIDFromString((LPOLESTR)in, &guid))) + return FALSE; + + for(i=0; i<8; i++) + out[7-i] = in[n++]; + n++; + for(i=0; i<4; i++) + out[11-i] = in[n++]; + n++; + for(i=0; i<4; i++) + out[15-i] = in[n++]; + n++; + for(i=0; i<2; i++) + { + out[17+i*2] = in[n++]; + out[16+i*2] = in[n++]; + } + n++; + for( ; i<8; i++) + { + out[17+i*2] = in[n++]; + out[16+i*2] = in[n++]; + } + out[32]=0; + return TRUE; +} + +static void create_test_guid(LPSTR prodcode, LPSTR squashed) +{ + WCHAR guidW[MAX_PATH]; + WCHAR squashedW[MAX_PATH]; + GUID guid; + HRESULT hr; + int size; + + hr = CoCreateGuid(&guid); + ok(hr == S_OK, "Expected S_OK, got %d\n", hr); + + size = StringFromGUID2(&guid, guidW, MAX_PATH); + ok(size == 39, "Expected 39, got %d\n", hr); + + WideCharToMultiByte(CP_ACP, 0, guidW, size, prodcode, MAX_PATH, NULL, NULL); + squash_guid(guidW, squashedW); + WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL); +} + +static void set_component_path(LPCSTR filename, MSIINSTALLCONTEXT context, + LPCSTR guid, LPSTR usersid, BOOL dir) +{ + WCHAR guidW[MAX_PATH]; + WCHAR squashedW[MAX_PATH]; + CHAR squashed[MAX_PATH]; + CHAR comppath[MAX_PATH]; + CHAR prodpath[MAX_PATH]; + CHAR path[MAX_PATH]; + LPCSTR prod = NULL; + HKEY hkey; + + MultiByteToWideChar(CP_ACP, 0, guid, -1, guidW, MAX_PATH); + squash_guid(guidW, squashedW); + WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL); + + if (context == MSIINSTALLCONTEXT_MACHINE) + { + prod = "3D0DAE300FACA1300AD792060BCDAA92"; + sprintf(comppath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\UserData\\S-1-5-18\\Components\\%s", squashed); + lstrcpyA(prodpath, + "SOFTWARE\\Classes\\Installer\\" + "Products\\3D0DAE300FACA1300AD792060BCDAA92"); + } + else if (context == MSIINSTALLCONTEXT_USERUNMANAGED) + { + prod = "7D2F387510109040002000060BECB6AB"; + sprintf(comppath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\UserData\\%s\\Components\\%s", usersid, squashed); + sprintf(prodpath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\%s\\Installer\\Products\\" + "7D2F387510109040002000060BECB6AB", usersid); + } + else if (context == MSIINSTALLCONTEXT_USERMANAGED) + { + prod = "7D2F387510109040002000060BECB6AB"; + sprintf(comppath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\UserData\\%s\\Components\\%s", usersid, squashed); + sprintf(prodpath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\Managed\\%s\\Installer\\Products\\" + "7D2F387510109040002000060BECB6AB", usersid); + } + + RegCreateKeyA(HKEY_LOCAL_MACHINE, comppath, &hkey); + + lstrcpyA(path, CURR_DIR); + lstrcatA(path, "\\"); + if (!dir) lstrcatA(path, filename); + + RegSetValueExA(hkey, prod, 0, REG_SZ, (LPBYTE)path, lstrlenA(path)); + RegCloseKey(hkey); + + RegCreateKeyA(HKEY_LOCAL_MACHINE, prodpath, &hkey); + RegCloseKey(hkey); +} + +static void delete_component_path(LPCSTR guid, MSIINSTALLCONTEXT context, LPSTR usersid) +{ + WCHAR guidW[MAX_PATH]; + WCHAR squashedW[MAX_PATH]; + WCHAR substrW[MAX_PATH]; + CHAR squashed[MAX_PATH]; + CHAR comppath[MAX_PATH]; + CHAR prodpath[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, guid, -1, guidW, MAX_PATH); + squash_guid(guidW, squashedW); + WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL); + + if (context == MSIINSTALLCONTEXT_MACHINE) + { + sprintf(comppath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\UserData\\S-1-5-18\\Components\\%s", squashed); + lstrcpyA(prodpath, + "SOFTWARE\\Classes\\Installer\\" + "Products\\3D0DAE300FACA1300AD792060BCDAA92"); + } + else if (context == MSIINSTALLCONTEXT_USERUNMANAGED) + { + sprintf(comppath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\UserData\\%s\\Components\\%s", usersid, squashed); + sprintf(prodpath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\%s\\Installer\\Products\\" + "7D2F387510109040002000060BECB6AB", usersid); + } + else if (context == MSIINSTALLCONTEXT_USERMANAGED) + { + sprintf(comppath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\UserData\\%s\\Components\\%s", usersid, squashed); + sprintf(prodpath, + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "Installer\\Managed\\%s\\Installer\\Products\\" + "7D2F387510109040002000060BECB6AB", usersid); + } + + MultiByteToWideChar(CP_ACP, 0, comppath, -1, substrW, MAX_PATH); + package_RegDeleteTreeW(HKEY_LOCAL_MACHINE, substrW); + + MultiByteToWideChar(CP_ACP, 0, prodpath, -1, substrW, MAX_PATH); + package_RegDeleteTreeW(HKEY_LOCAL_MACHINE, substrW); +} + static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec) { MSIHANDLE hview = 0; @@ -305,227 +520,101 @@ static UINT create_complocator_table( MSIHANDLE hdb ) "PRIMARY KEY `Signature_`)" ); } -static UINT add_component_entry( MSIHANDLE hdb, const char *values ) +static UINT create_inilocator_table( MSIHANDLE hdb ) { - char insert[] = "INSERT INTO `Component` " - "(`Component`, `ComponentId`, `Directory_`, `Attributes`, `Condition`, `KeyPath`) " - "VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; + return run_query( hdb, + "CREATE TABLE `IniLocator` (" + "`Signature_` CHAR(72) NOT NULL, " + "`FileName` CHAR(255) NOT NULL, " + "`Section` CHAR(96)NOT NULL, " + "`Key` CHAR(128)NOT NULL, " + "`Field` SHORT, " + "`Type` SHORT " + "PRIMARY KEY `Signature_`)" ); } -static UINT add_feature_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Feature` (`Feature`, `Feature_Parent`, " - "`Title`, `Description`, `Display`, `Level`, `Directory_`, `Attributes`) VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; +#define make_add_entry(type, qtext) \ + static UINT add##_##type##_##entry( MSIHANDLE hdb, const char *values ) \ + { \ + char insert[] = qtext; \ + char *query; \ + UINT sz, r; \ + sz = strlen(values) + sizeof insert; \ + query = HeapAlloc(GetProcessHeap(),0,sz); \ + sprintf(query,insert,values); \ + r = run_query( hdb, query ); \ + HeapFree(GetProcessHeap(), 0, query); \ + return r; \ } -static UINT add_feature_components_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `FeatureComponents` " - "(`Feature_`, `Component_`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(component, + "INSERT INTO `Component` " + "(`Component`, `ComponentId`, `Directory_`, " + "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(directory, + "INSERT INTO `Directory` " + "(`Directory`,`Directory_Parent`,`DefaultDir`) VALUES( %s )") -static UINT add_file_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `File` " - "(`File`, `Component_`, `FileName`, `FileSize`, `Version`, `Language`, `Attributes`, `Sequence`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(feature, + "INSERT INTO `Feature` " + "(`Feature`, `Feature_Parent`, `Title`, `Description`, " + "`Display`, `Level`, `Directory_`, `Attributes`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(feature_components, + "INSERT INTO `FeatureComponents` " + "(`Feature_`, `Component_`) VALUES( %s )") -static UINT add_appsearch_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `AppSearch` " - "(`Property`, `Signature_`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(file, + "INSERT INTO `File` " + "(`File`, `Component_`, `FileName`, `FileSize`, " + "`Version`, `Language`, `Attributes`, `Sequence`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(appsearch, + "INSERT INTO `AppSearch` " + "(`Property`, `Signature_`) VALUES( %s )") -static UINT add_reglocator_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `RegLocator` " - "(`Signature_`, `Root`, `Key`, `Name`, `Type`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(reglocator, + "INSERT INTO `RegLocator` " + "(`Signature_`, `Root`, `Key`, `Name`, `Type`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} - -static UINT add_signature_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Signature` " +make_add_entry(signature, + "INSERT INTO `Signature` " "(`Signature`, `FileName`, `MinVersion`, `MaxVersion`," " `MinSize`, `MaxSize`, `MinDate`, `MaxDate`, `Languages`) " - "VALUES( %s )"; - char *query; - UINT sz, r; + "VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(launchcondition, + "INSERT INTO `LaunchCondition` " + "(`Condition`, `Description`) VALUES( %s )") -static UINT add_launchcondition_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `LaunchCondition` " - "(`Condition`, `Description`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(property, + "INSERT INTO `Property` (`Property`, `Value`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(install_execute_sequence, + "INSERT INTO `InstallExecuteSequence` " + "(`Action`, `Condition`, `Sequence`) VALUES( %s )") -static UINT add_property_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Property` " - "(`Property`, `Value`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(media, + "INSERT INTO `Media` " + "(`DiskId`, `LastSequence`, `DiskPrompt`, " + "`Cabinet`, `VolumeLabel`, `Source`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(ccpsearch, + "INSERT INTO `CCPSearch` (`Signature_`) VALUES( %s )") -static UINT add_install_execute_sequence_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `InstallExecuteSequence` " - "(`Action`, `Condition`, `Sequence`) " - "VALUES( %s )"; - char *query; - UINT sz, r; +make_add_entry(drlocator, + "INSERT INTO `DrLocator` " + "(`Signature_`, `Parent`, `Path`, `Depth`) VALUES( %s )") - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(complocator, + "INSERT INTO `CompLocator` " + "(`Signature_`, `ComponentId`, `Type`) VALUES( %s )") -static UINT add_media_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Media` " - "(`DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source`) " - "VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} - -static UINT add_ccpsearch_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `CCPSearch` (`Signature_`) VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} - -static UINT add_drlocator_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `DrLocator` " - "(`Signature_`, `Parent`, `Path`, `Depth`) " - "VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} - -static UINT add_complocator_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `CompLocator` " - "(`Signature_`, `ComponentId`, `Type`) " - "VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} +make_add_entry(inilocator, + "INSERT INTO `IniLocator` " + "(`Signature_`, `FileName`, `Section`, `Key`, `Field`, `Type`) " + "VALUES( %s )") static UINT set_summary_info(MSIHANDLE hdb) { @@ -607,7 +696,7 @@ static MSIHANDLE package_from_db(MSIHANDLE hdb) CHAR szPackage[10]; MSIHANDLE hPackage; - sprintf(szPackage,"#%li",hdb); + sprintf(szPackage,"#%i",hdb); res = MsiOpenPackage(szPackage,&hPackage); if (res != ERROR_SUCCESS) return 0; @@ -631,6 +720,90 @@ static void create_test_file(const CHAR *name) CloseHandle(file); } +typedef struct _tagVS_VERSIONINFO +{ + WORD wLength; + WORD wValueLength; + WORD wType; + WCHAR szKey[1]; + WORD wPadding1[1]; + VS_FIXEDFILEINFO Value; + WORD wPadding2[1]; + WORD wChildren[1]; +} VS_VERSIONINFO; + +#define roundoffs(a, b, r) (((BYTE *)(b) - (BYTE *)(a) + ((r) - 1)) & ~((r) - 1)) +#define roundpos(a, b, r) (((BYTE *)(a)) + roundoffs(a, b, r)) + +static BOOL create_file_with_version(const CHAR *name, LONG ms, LONG ls) +{ + VS_VERSIONINFO *pVerInfo; + VS_FIXEDFILEINFO *pFixedInfo; + LPBYTE buffer, ofs; + CHAR path[MAX_PATH]; + DWORD handle, size; + HANDLE resource; + BOOL ret = FALSE; + + GetSystemDirectory(path, MAX_PATH); + /* Some dlls can't be updated on Vista/W2K8 */ + lstrcatA(path, "\\version.dll"); + + CopyFileA(path, name, FALSE); + + size = GetFileVersionInfoSize(path, &handle); + buffer = HeapAlloc(GetProcessHeap(), 0, size); + + GetFileVersionInfoA(path, 0, size, buffer); + + pVerInfo = (VS_VERSIONINFO *)buffer; + ofs = (BYTE *)&pVerInfo->szKey[lstrlenW(pVerInfo->szKey) + 1]; + pFixedInfo = (VS_FIXEDFILEINFO *)roundpos(pVerInfo, ofs, 4); + + pFixedInfo->dwFileVersionMS = ms; + pFixedInfo->dwFileVersionLS = ls; + pFixedInfo->dwProductVersionMS = ms; + pFixedInfo->dwProductVersionLS = ls; + + resource = BeginUpdateResource(name, FALSE); + if (!resource) + goto done; + + if (!UpdateResource(resource, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), buffer, size)) + goto done; + + if (!EndUpdateResource(resource, FALSE)) + goto done; + + ret = TRUE; + +done: + HeapFree(GetProcessHeap(), 0, buffer); + return ret; +} + +static BOOL notify_system_change(DWORD event_type, STATEMGRSTATUS *status) +{ + RESTOREPOINTINFOA spec; + + spec.dwEventType = event_type; + spec.dwRestorePtType = APPLICATION_INSTALL; + spec.llSequenceNumber = status->llSequenceNumber; + lstrcpyA(spec.szDescription, "msitest restore point"); + + return pSRSetRestorePointA(&spec, status); +} + +static void remove_restore_point(DWORD seq_number) +{ + DWORD res; + + res = pSRRemoveRestorePoint(seq_number); + if (res != ERROR_SUCCESS) + trace("Failed to remove the restore point : %08x\n", res); +} + static void test_createpackage(void) { MSIHANDLE hPackage = 0; @@ -644,124 +817,6 @@ static void test_createpackage(void) DeleteFile(msifile); } -static void test_getsourcepath_bad( void ) -{ - static const char str[] = { 0 }; - char buffer[0x80]; - DWORD sz; - UINT r; - - r = MsiGetSourcePath( -1, NULL, NULL, NULL ); - ok( r == ERROR_INVALID_PARAMETER, "return value wrong\n"); - - sz = 0; - r = MsiGetSourcePath( -1, NULL, buffer, &sz ); - ok( r == ERROR_INVALID_PARAMETER, "return value wrong\n"); - - sz = 0; - r = MsiGetSourcePath( -1, str, NULL, &sz ); - ok( r == ERROR_INVALID_HANDLE, "return value wrong\n"); - - sz = 0; - r = MsiGetSourcePath( -1, str, NULL, NULL ); - ok( r == ERROR_INVALID_HANDLE, "return value wrong\n"); - - sz = 0; - r = MsiGetSourcePath( -1, str, buffer, &sz ); - ok( r == ERROR_INVALID_HANDLE, "return value wrong\n"); -} - -static UINT add_directory_entry( MSIHANDLE hdb, const char *values ) -{ - char insert[] = "INSERT INTO `Directory` (`Directory`,`Directory_Parent`,`DefaultDir`) VALUES( %s )"; - char *query; - UINT sz, r; - - sz = strlen(values) + sizeof insert; - query = HeapAlloc(GetProcessHeap(),0,sz); - sprintf(query,insert,values); - r = run_query( hdb, query ); - HeapFree(GetProcessHeap(), 0, query); - return r; -} - -static void test_getsourcepath( void ) -{ - static const char str[] = { 0 }; - char buffer[0x80]; - DWORD sz; - UINT r; - MSIHANDLE hpkg, hdb; - - hpkg = package_from_db(create_package_db()); - ok( hpkg, "failed to create package\n"); - - sz = 0; - buffer[0] = 'x'; - r = MsiGetSourcePath( hpkg, str, buffer, &sz ); - ok( r == ERROR_DIRECTORY, "return value wrong\n"); - ok( buffer[0] == 'x', "buffer modified\n"); - - sz = 1; - buffer[0] = 'x'; - r = MsiGetSourcePath( hpkg, str, buffer, &sz ); - ok( r == ERROR_DIRECTORY, "return value wrong\n"); - ok( buffer[0] == 'x', "buffer modified\n"); - - MsiCloseHandle( hpkg ); - - - /* another test but try create a directory this time */ - hdb = create_package_db(); - ok( hdb, "failed to create database\n"); - - r = add_directory_entry( hdb, "'TARGETDIR', '', 'SourceDir'"); - ok( r == S_OK, "failed\n"); - - hpkg = package_from_db(hdb); - ok( hpkg, "failed to create package\n"); - - sz = sizeof buffer -1; - strcpy(buffer,"x bad"); - r = MsiGetSourcePath( hpkg, "TARGETDIR", buffer, &sz ); - ok( r == ERROR_DIRECTORY, "return value wrong\n"); - - r = MsiDoAction( hpkg, "CostInitialize"); - ok( r == ERROR_SUCCESS, "cost init failed\n"); - r = MsiDoAction( hpkg, "CostFinalize"); - ok( r == ERROR_SUCCESS, "cost finalize failed\n"); - - sz = sizeof buffer -1; - buffer[0] = 'x'; - r = MsiGetSourcePath( hpkg, "TARGETDIR", buffer, &sz ); - ok( r == ERROR_SUCCESS, "return value wrong\n"); - ok( sz == strlen(buffer), "returned length wrong\n"); - - sz = 0; - strcpy(buffer,"x bad"); - r = MsiGetSourcePath( hpkg, "TARGETDIR", buffer, &sz ); - ok( r == ERROR_MORE_DATA, "return value wrong\n"); - ok( buffer[0] == 'x', "buffer modified\n"); - - r = MsiGetSourcePath( hpkg, "TARGETDIR", NULL, NULL ); - ok( r == ERROR_SUCCESS, "return value wrong\n"); - - r = MsiGetSourcePath( hpkg, "TARGETDIR ", NULL, NULL ); - ok( r == ERROR_DIRECTORY, "return value wrong\n"); - - r = MsiGetSourcePath( hpkg, "targetdir", NULL, NULL ); - ok( r == ERROR_DIRECTORY, "return value wrong\n"); - - r = MsiGetSourcePath( hpkg, "TARGETDIR", buffer, NULL ); - ok( r == ERROR_INVALID_PARAMETER, "return value wrong\n"); - - r = MsiGetSourcePath( hpkg, "TARGETDIR", NULL, &sz ); - ok( r == ERROR_SUCCESS, "return value wrong\n"); - - MsiCloseHandle( hpkg ); - DeleteFile(msifile); -} - static void test_doaction( void ) { MSIHANDLE hpkg; @@ -788,7 +843,10 @@ static void test_doaction( void ) static void test_gettargetpath_bad(void) { + static const WCHAR boo[] = {'b','o','o',0}; + static const WCHAR empty[] = {0}; char buffer[0x80]; + WCHAR bufferW[0x80]; MSIHANDLE hpkg; DWORD sz; UINT r; @@ -814,6 +872,32 @@ static void test_gettargetpath_bad(void) r = MsiGetTargetPath( hpkg, "boo", buffer, NULL ); ok( r == ERROR_DIRECTORY, "wrong return val\n"); + sz = 0; + r = MsiGetTargetPath( hpkg, "", buffer, &sz ); + ok( r == ERROR_DIRECTORY, "wrong return val\n"); + + r = MsiGetTargetPathW( 0, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "wrong return val\n"); + + r = MsiGetTargetPathW( 0, NULL, NULL, &sz ); + ok( r == ERROR_INVALID_PARAMETER, "wrong return val\n"); + + r = MsiGetTargetPathW( 0, boo, NULL, NULL ); + ok( r == ERROR_INVALID_HANDLE, "wrong return val\n"); + + r = MsiGetTargetPathW( 0, boo, NULL, NULL ); + ok( r == ERROR_INVALID_HANDLE, "wrong return val\n"); + + r = MsiGetTargetPathW( hpkg, boo, NULL, NULL ); + ok( r == ERROR_DIRECTORY, "wrong return val\n"); + + r = MsiGetTargetPathW( hpkg, boo, bufferW, NULL ); + ok( r == ERROR_DIRECTORY, "wrong return val\n"); + + sz = 0; + r = MsiGetTargetPathW( hpkg, empty, bufferW, &sz ); + ok( r == ERROR_DIRECTORY, "wrong return val\n"); + MsiCloseHandle( hpkg ); DeleteFile(msifile); } @@ -914,6 +998,7 @@ static void test_settargetpath(void) sz = sizeof tempdir - 1; r = MsiGetTargetPath( hpkg, "TARGETDIR", tempdir, &sz ); sprintf( file, "%srootfile.txt", tempdir ); + buffer[0] = 0; query_file_path( hpkg, "[#RootFile]", buffer ); ok( r == ERROR_SUCCESS, "failed to get target path: %d\n", r); ok( !lstrcmp(buffer, file), "Expected %s, got %s\n", file, buffer ); @@ -954,13 +1039,13 @@ static void test_settargetpath(void) ok( r == ERROR_SUCCESS, "MsiSetTargetPath returned %d\n", r ); query_file_path( hpkg, "[#TestFile]", buffer ); - ok( !lstrcmp(buffer, "C:\\one\\two\\TestDir\\testfile.txt"), + ok( !lstrcmpi(buffer, "C:\\one\\two\\TestDir\\testfile.txt"), "Expected C:\\one\\two\\TestDir\\testfile.txt, got %s\n", buffer ); sz = sizeof buffer - 1; r = MsiGetTargetPath( hpkg, "TestParent", buffer, &sz ); ok( r == ERROR_SUCCESS, "failed to get target path: %d\n", r); - ok( !lstrcmp(buffer, "C:\\one\\two\\"), "Expected C:\\one\\two\\, got %s\n", buffer); + ok( !lstrcmpi(buffer, "C:\\one\\two\\"), "Expected C:\\one\\two\\, got %s\n", buffer); MsiCloseHandle( hpkg ); } @@ -1069,6 +1154,15 @@ static void test_condition(void) r = MsiEvaluateCondition(hpkg, "not LicView"); ok( r == MSICONDITION_TRUE, "wrong return val\n"); + r = MsiEvaluateCondition(hpkg, "\"Testing\" ~<< \"Testing\""); + ok (r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "LicView ~<< \"Testing\""); + ok (r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "Not LicView ~<< \"Testing\""); + ok (r == MSICONDITION_TRUE, "wrong return val\n"); + r = MsiEvaluateCondition(hpkg, "not \"A\""); ok( r == MSICONDITION_FALSE, "wrong return val\n"); @@ -2114,7 +2208,7 @@ static void test_msipackage(void) ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); /* database exists, but is emtpy */ - sprintf(name, "#%ld", hdb); + sprintf(name, "#%d", hdb); r = MsiOpenPackage(name, &hpack); ok(r == ERROR_INSTALL_PACKAGE_INVALID, "Expected ERROR_INSTALL_PACKAGE_INVALID, got %d\n", r); @@ -2132,7 +2226,7 @@ static void test_msipackage(void) ok(r == ERROR_SUCCESS, "failed to create InstallExecuteSequence table\n"); /* a few key tables exist */ - sprintf(name, "#%ld", hdb); + sprintf(name, "#%d", hdb); r = MsiOpenPackage(name, &hpack); ok(r == ERROR_INSTALL_PACKAGE_INVALID, "Expected ERROR_INSTALL_PACKAGE_INVALID, got %d\n", r); @@ -2144,7 +2238,7 @@ static void test_msipackage(void) r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - sprintf(name, "#%ld", hdb); + sprintf(name, "#%d", hdb); /* The following summary information props must exist: * - PID_REVNUMBER @@ -2240,9 +2334,6 @@ static void test_formatrecord2(void) DeleteFile(msifile); } -/* FIXME: state is INSTALLSTATE_UNKNOWN if any features are removed and the - * feature in question is not in ADD* - */ static void test_states(void) { MSIHANDLE hpkg; @@ -2250,6 +2341,10 @@ static void test_states(void) MSIHANDLE hdb; INSTALLSTATE state, action; + static const CHAR msifile2[] = "winetest2.msi"; + static const CHAR msifile3[] = "winetest3.msi"; + static const CHAR msifile4[] = "winetest4.msi"; + hdb = create_package_db(); ok ( hdb, "failed to create package database\n" ); @@ -2419,6 +2514,27 @@ static void test_states(void) r = add_component_entry( hdb, "'sigma', '{5CE9DDA8-B67B-4736-9D93-99D61C5B93E7}', 'TARGETDIR', 8, '', 'sigma_file'" ); ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r ); + /* msidbFeatureAttributesFavorLocal */ + r = add_feature_entry( hdb, "'eight', '', '', '', 2, 1, '', 0" ); + ok( r == ERROR_SUCCESS, "cannot add feature: %d\n", r ); + + r = add_component_entry( hdb, "'tau', '{07DEB510-677C-4A6F-A0A6-7CD8EFEA77ED}', 'TARGETDIR', 1, '', 'tau_file'" ); + ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r ); + + /* msidbFeatureAttributesFavorSource */ + r = add_feature_entry( hdb, "'nine', '', '', '', 2, 1, '', 1" ); + ok( r == ERROR_SUCCESS, "cannot add feature: %d\n", r ); + + r = add_component_entry( hdb, "'phi', '{9F0594C5-35AD-43EA-94DD-8DF73FAA664D}', 'TARGETDIR', 1, '', 'phi_file'" ); + ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r ); + + /* msidbFeatureAttributesFavorAdvertise */ + r = add_feature_entry( hdb, "'ten', '', '', '', 2, 1, '', 4" ); + ok( r == ERROR_SUCCESS, "cannot add feature: %d\n", r ); + + r = add_component_entry( hdb, "'chi', '{E6B539AB-5DA9-4236-A2D2-E341A50B4C38}', 'TARGETDIR', 1, '', 'chi_file'" ); + ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r ); + r = create_feature_components_table( hdb ); ok( r == ERROR_SUCCESS, "cannot create FeatureComponents table: %d\n", r ); @@ -2479,6 +2595,15 @@ static void test_states(void) r = add_feature_components_entry( hdb, "'seven', 'sigma'" ); ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r ); + r = add_feature_components_entry( hdb, "'eight', 'tau'" ); + ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r ); + + r = add_feature_components_entry( hdb, "'nine', 'phi'" ); + ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r ); + + r = add_feature_components_entry( hdb, "'ten', 'chi'" ); + ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r ); + r = create_file_table( hdb ); ok( r == ERROR_SUCCESS, "cannot create File table: %d\n", r ); @@ -2537,6 +2662,15 @@ static void test_states(void) r = add_file_entry( hdb, "'sigma_file', 'sigma', 'sigma.txt', 100, '', '1033', 8192, 1" ); ok( r == ERROR_SUCCESS, "cannot add file: %d\n", r); + r = add_file_entry( hdb, "'tau_file', 'tau', 'tau.txt', 100, '', '1033', 8192, 1" ); + ok( r == ERROR_SUCCESS, "cannot add file: %d\n", r); + + r = add_file_entry( hdb, "'phi_file', 'phi', 'phi.txt', 100, '', '1033', 8192, 1" ); + ok( r == ERROR_SUCCESS, "cannot add file: %d\n", r); + + r = add_file_entry( hdb, "'chi_file', 'chi', 'chi.txt', 100, '', '1033', 8192, 1" ); + ok( r == ERROR_SUCCESS, "cannot add file: %d\n", r); + MsiDatabaseCommit(hdb); /* these properties must not be in the saved msi file */ @@ -2549,11 +2683,21 @@ static void test_states(void) r = add_property_entry( hdb, "'REMOVE', 'six,seven'"); ok( r == ERROR_SUCCESS, "cannot add property: %d\n", r ); + r = add_property_entry( hdb, "'REINSTALL', 'eight,nine,ten'"); + ok( r == ERROR_SUCCESS, "cannot add property: %d\n", r ); + + r = add_property_entry( hdb, "'REINSTALLMODE', 'omus'"); + ok( r == ERROR_SUCCESS, "cannot add property: %d\n", r ); + hpkg = package_from_db( hdb ); ok( hpkg, "failed to create package\n"); MsiCloseHandle(hdb); + CopyFileA(msifile, msifile2, FALSE); + CopyFileA(msifile, msifile3, FALSE); + CopyFileA(msifile, msifile4, FALSE); + state = 0xdeadbee; action = 0xdeadbee; r = MsiGetFeatureState(hpkg, "one", &state, &action); @@ -2603,6 +2747,27 @@ static void test_states(void) ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "alpha", &state, &action); @@ -2729,6 +2894,27 @@ static void test_states(void) ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + r = MsiDoAction( hpkg, "CostInitialize"); ok( r == ERROR_SUCCESS, "cost init failed\n"); @@ -2781,6 +2967,27 @@ static void test_states(void) ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "alpha", &state, &action); @@ -2907,6 +3114,27 @@ static void test_states(void) ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + r = MsiDoAction( hpkg, "FileCost"); ok( r == ERROR_SUCCESS, "file cost failed\n"); @@ -2959,6 +3187,27 @@ static void test_states(void) ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "alpha", &state, &action); @@ -3085,6 +3334,27 @@ static void test_states(void) ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + r = MsiDoAction( hpkg, "CostFinalize"); ok( r == ERROR_SUCCESS, "cost finalize failed: %d\n", r); @@ -3128,20 +3398,35 @@ static void test_states(void) r = MsiGetFeatureState(hpkg, "six", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetFeatureState(hpkg, "seven", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; @@ -3218,85 +3503,82 @@ static void test_states(void) r = MsiGetComponentState(hpkg, "lambda", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "mu", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "nu", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "xi", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "omicron", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "pi", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "rho", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "sigma", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); MsiCloseHandle( hpkg ); /* publish the features and components */ - r = MsiInstallProduct(msifile, "ADDLOCAL=one,four ADDSOURCE=two,three REMOVE=six,seven"); + r = MsiInstallProduct(msifile, "ADDLOCAL=one,four ADDSOURCE=two,three REMOVE=six,seven REINSTALL=eight,nine,ten"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb); @@ -3312,6 +3594,9 @@ static void test_states(void) r = add_property_entry( hdb, "'REMOVE', 'six,seven'"); ok( r == ERROR_SUCCESS, "cannot add property: %d\n", r ); + r = add_property_entry( hdb, "'REINSTALL', 'eight,nine,ten'"); + ok( r == ERROR_SUCCESS, "cannot add property: %d\n", r ); + hpkg = package_from_db( hdb ); ok( hpkg, "failed to create package\n"); @@ -3366,6 +3651,27 @@ static void test_states(void) ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "alpha", &state, &action); @@ -3492,6 +3798,27 @@ static void test_states(void) ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + r = MsiDoAction( hpkg, "CostInitialize"); ok( r == ERROR_SUCCESS, "cost init failed\n"); @@ -3544,6 +3871,27 @@ static void test_states(void) ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "alpha", &state, &action); @@ -3670,6 +4018,27 @@ static void test_states(void) ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + r = MsiDoAction( hpkg, "FileCost"); ok( r == ERROR_SUCCESS, "file cost failed\n"); @@ -3722,6 +4091,20 @@ static void test_states(void) ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "alpha", &state, &action); @@ -3848,6 +4231,27 @@ static void test_states(void) ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + r = MsiDoAction( hpkg, "CostFinalize"); ok( r == ERROR_SUCCESS, "cost finalize failed: %d\n", r); @@ -3855,40 +4259,28 @@ static void test_states(void) action = 0xdeadbee; r = MsiGetFeatureState(hpkg, "one", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetFeatureState(hpkg, "two", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); - } ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetFeatureState(hpkg, "three", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetFeatureState(hpkg, "four", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; @@ -3903,109 +4295,97 @@ static void test_states(void) r = MsiGetFeatureState(hpkg, "six", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetFeatureState(hpkg, "seven", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "alpha", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "beta", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); - } ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "gamma", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "theta", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "delta", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "epsilon", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "zeta", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "iota", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "eta", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); - todo_wine - { ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - } ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); state = 0xdeadbee; @@ -4020,80 +4400,77 @@ static void test_states(void) r = MsiGetComponentState(hpkg, "lambda", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "mu", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "nu", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "xi", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "omicron", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "pi", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "rho", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } state = 0xdeadbee; action = 0xdeadbee; r = MsiGetComponentState(hpkg, "sigma", &state, &action); ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); - todo_wine - { ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); - } + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); MsiCloseHandle(hpkg); @@ -4101,7 +4478,2697 @@ static void test_states(void) r = MsiInstallProduct(msifile, "REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + /* all features installed locally */ + r = MsiInstallProduct(msifile2, "ADDLOCAL=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiOpenDatabase(msifile2, MSIDBOPEN_DIRECT, &hdb); + ok(r == ERROR_SUCCESS, "failed to open database: %d\n", r); + + /* these properties must not be in the saved msi file */ + r = add_property_entry( hdb, "'ADDLOCAL', 'one,two,three,four,five,six,seven,eight,nine,ten'"); + ok( r == ERROR_SUCCESS, "cannot add property: %d\n", r ); + + hpkg = package_from_db( hdb ); + ok( hpkg, "failed to create package\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + r = MsiDoAction( hpkg, "CostInitialize"); + ok( r == ERROR_SUCCESS, "cost init failed\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + r = MsiDoAction( hpkg, "FileCost"); + ok( r == ERROR_SUCCESS, "file cost failed\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + r = MsiDoAction( hpkg, "CostFinalize"); + ok( r == ERROR_SUCCESS, "cost finalize failed: %d\n", r); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + todo_wine ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + todo_wine ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + todo_wine ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + MsiCloseHandle(hpkg); + + /* uninstall the product */ + r = MsiInstallProduct(msifile2, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* all features installed from source */ + r = MsiInstallProduct(msifile3, "ADDSOURCE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiOpenDatabase(msifile3, MSIDBOPEN_DIRECT, &hdb); + ok(r == ERROR_SUCCESS, "failed to open database: %d\n", r); + + /* this property must not be in the saved msi file */ + r = add_property_entry( hdb, "'ADDSOURCE', 'one,two,three,four,five,six,seven,eight,nine,ten'"); + ok( r == ERROR_SUCCESS, "cannot add property: %d\n", r ); + + hpkg = package_from_db( hdb ); + ok( hpkg, "failed to create package\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + r = MsiDoAction( hpkg, "CostInitialize"); + ok( r == ERROR_SUCCESS, "cost init failed\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + r = MsiDoAction( hpkg, "FileCost"); + ok( r == ERROR_SUCCESS, "file cost failed\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + r = MsiDoAction( hpkg, "CostFinalize"); + ok( r == ERROR_SUCCESS, "cost finalize failed: %d\n", r); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + MsiCloseHandle(hpkg); + + /* reinstall the product */ + r = MsiInstallProduct(msifile3, "REINSTALL=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiOpenDatabase(msifile4, MSIDBOPEN_DIRECT, &hdb); + ok(r == ERROR_SUCCESS, "failed to open database: %d\n", r); + + /* this property must not be in the saved msi file */ + r = add_property_entry( hdb, "'ADDSOURCE', 'one,two,three,four,five,six,seven,eight,nine,ten'"); + ok( r == ERROR_SUCCESS, "cannot add property: %d\n", r ); + + hpkg = package_from_db( hdb ); + ok( hpkg, "failed to create package\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_UNKNOWN_FEATURE, "Expected ERROR_UNKNOWN_FEATURE, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r ); + ok( state == 0xdeadbee, "Expected 0xdeadbee, got %d\n", state); + ok( action == 0xdeadbee, "Expected 0xdeadbee, got %d\n", action); + + r = MsiDoAction( hpkg, "CostInitialize"); + ok( r == ERROR_SUCCESS, "cost init failed\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + r = MsiDoAction( hpkg, "FileCost"); + ok( r == ERROR_SUCCESS, "file cost failed\n"); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + r = MsiDoAction( hpkg, "CostFinalize"); + ok( r == ERROR_SUCCESS, "cost finalize failed: %d\n", r); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "one", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "two", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "three", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "four", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "five", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "six", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "seven", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "eight", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "nine", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetFeatureState(hpkg, "ten", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "alpha", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "beta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "gamma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "theta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "delta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "epsilon", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "zeta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "iota", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "eta", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( action == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "kappa", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "lambda", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "mu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "nu", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "xi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "omicron", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "pi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "rho", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "sigma", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok( state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "tau", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "phi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + state = 0xdeadbee; + action = 0xdeadbee; + r = MsiGetComponentState(hpkg, "chi", &state, &action); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r ); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + ok( state == INSTALLSTATE_SOURCE, "Expected INSTALLSTATE_SOURCE, got %d\n", state); + + MsiCloseHandle(hpkg); + + /* uninstall the product */ + r = MsiInstallProduct(msifile4, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + DeleteFileA(msifile); + DeleteFileA(msifile2); + DeleteFileA(msifile3); + DeleteFileA(msifile4); } static void test_getproperty(void) @@ -4331,12 +7398,1520 @@ static void test_appsearch(void) r = MsiGetPropertyA( hpkg, "WEBBROWSERPROG", prop, &size ); ok( r == ERROR_SUCCESS, "get property failed: %d\n", r); + todo_wine + { ok( lstrlenA(prop) != 0, "Expected non-zero length\n"); + } MsiCloseHandle( hpkg ); DeleteFileA(msifile); } +static void test_appsearch_complocator(void) +{ + MSIHANDLE hpkg, hdb; + CHAR path[MAX_PATH]; + CHAR prop[MAX_PATH]; + LPSTR usersid; + DWORD size; + UINT r; + + if (!get_user_sid(&usersid)) + return; + + create_test_file("FileName1"); + create_test_file("FileName4"); + set_component_path("FileName1", MSIINSTALLCONTEXT_MACHINE, + "{A8AE6692-96BA-4198-8399-145D7D1D0D0E}", NULL, FALSE); + + create_test_file("FileName2"); + set_component_path("FileName2", MSIINSTALLCONTEXT_USERUNMANAGED, + "{1D2CE6F3-E81C-4949-AB81-78D7DAD2AF2E}", usersid, FALSE); + + create_test_file("FileName3"); + set_component_path("FileName3", MSIINSTALLCONTEXT_USERMANAGED, + "{19E0B999-85F5-4973-A61B-DBE4D66ECB1D}", usersid, FALSE); + + create_test_file("FileName5"); + set_component_path("FileName5", MSIINSTALLCONTEXT_MACHINE, + "{F0CCA976-27A3-4808-9DDD-1A6FD50A0D5A}", NULL, TRUE); + + create_test_file("FileName6"); + set_component_path("FileName6", MSIINSTALLCONTEXT_MACHINE, + "{C0ECD96F-7898-4410-9667-194BD8C1B648}", NULL, TRUE); + + create_test_file("FileName7"); + set_component_path("FileName7", MSIINSTALLCONTEXT_MACHINE, + "{DB20F535-9C26-4127-9C2B-CC45A8B51DA1}", NULL, FALSE); + + /* dir is FALSE, but we're pretending it's a directory */ + set_component_path("IDontExist\\", MSIINSTALLCONTEXT_MACHINE, + "{91B7359B-07F2-4221-AA8D-DE102BB87A5F}", NULL, FALSE); + + create_file_with_version("FileName8.dll", MAKELONG(2, 1), MAKELONG(4, 3)); + set_component_path("FileName8.dll", MSIINSTALLCONTEXT_MACHINE, + "{4A2E1B5B-4034-4177-833B-8CC35F1B3EF1}", NULL, FALSE); + + create_file_with_version("FileName9.dll", MAKELONG(1, 2), MAKELONG(3, 4)); + set_component_path("FileName9.dll", MSIINSTALLCONTEXT_MACHINE, + "{A204DF48-7346-4635-BA2E-66247DBAC9DF}", NULL, FALSE); + + create_file_with_version("FileName10.dll", MAKELONG(2, 1), MAKELONG(4, 3)); + set_component_path("FileName10.dll", MSIINSTALLCONTEXT_MACHINE, + "{EC30CE73-4CF9-4908-BABD-1ED82E1515FD}", NULL, FALSE); + + hdb = create_package_db(); + ok(hdb, "Expected a valid database handle\n"); + + r = create_appsearch_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP1', 'NewSignature1'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP2', 'NewSignature2'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP3', 'NewSignature3'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP4', 'NewSignature4'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP5', 'NewSignature5'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP6', 'NewSignature6'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP7', 'NewSignature7'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP8', 'NewSignature8'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP9', 'NewSignature9'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP10', 'NewSignature10'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP11', 'NewSignature11'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP12', 'NewSignature12'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = create_complocator_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, machine, file, signature, misdbLocatorTypeFile */ + r = add_complocator_entry(hdb, "'NewSignature1', '{A8AE6692-96BA-4198-8399-145D7D1D0D0E}', 1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, user-unmanaged, file, signature, misdbLocatorTypeFile */ + r = add_complocator_entry(hdb, "'NewSignature2', '{1D2CE6F3-E81C-4949-AB81-78D7DAD2AF2E}', 1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, user-managed, file, signature, misdbLocatorTypeFile */ + r = add_complocator_entry(hdb, "'NewSignature3', '{19E0B999-85F5-4973-A61B-DBE4D66ECB1D}', 1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, machine, file, signature, misdbLocatorTypeDirectory */ + r = add_complocator_entry(hdb, "'NewSignature4', '{A8AE6692-96BA-4198-8399-145D7D1D0D0E}', 0"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, machine, dir, signature, misdbLocatorTypeDirectory */ + r = add_complocator_entry(hdb, "'NewSignature5', '{F0CCA976-27A3-4808-9DDD-1A6FD50A0D5A}', 0"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, machine, dir, no signature, misdbLocatorTypeDirectory */ + r = add_complocator_entry(hdb, "'NewSignature6', '{C0ECD96F-7898-4410-9667-194BD8C1B648}', 0"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, machine, file, no signature, misdbLocatorTypeFile */ + r = add_complocator_entry(hdb, "'NewSignature7', '{DB20F535-9C26-4127-9C2B-CC45A8B51DA1}', 1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* unpublished component, no signature, misdbLocatorTypeDir */ + r = add_complocator_entry(hdb, "'NewSignature8', '{FB671D5B-5083-4048-90E0-481C48D8F3A5}', 0"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, no signature, dir does not exist misdbLocatorTypeDir */ + r = add_complocator_entry(hdb, "'NewSignature9', '{91B7359B-07F2-4221-AA8D-DE102BB87A5F}', 0"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, signature w/ ver, misdbLocatorTypeFile */ + r = add_complocator_entry(hdb, "'NewSignature10', '{4A2E1B5B-4034-4177-833B-8CC35F1B3EF1}', 1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, signature w/ ver, ver > max, misdbLocatorTypeFile */ + r = add_complocator_entry(hdb, "'NewSignature11', '{A204DF48-7346-4635-BA2E-66247DBAC9DF}', 1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* published component, signature w/ ver, sig->name ignored, misdbLocatorTypeFile */ + r = add_complocator_entry(hdb, "'NewSignature12', '{EC30CE73-4CF9-4908-BABD-1ED82E1515FD}', 1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = create_signature_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature1', 'FileName1', '', '', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature2', 'FileName2', '', '', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature3', 'FileName3', '', '', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature4', 'FileName4', '', '', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature5', 'FileName5', '', '', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature10', 'FileName8.dll', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature11', 'FileName9.dll', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature12', 'ignored', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + hpkg = package_from_db(hdb); + ok(hpkg, "Expected a valid package handle\n"); + + r = MsiSetPropertyA(hpkg, "SIGPROP8", "october"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiDoAction(hpkg, "AppSearch"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + sprintf(path, "%s\\FileName1", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP1", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName2", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP2", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName3", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP3", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName4", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP4", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName5", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP5", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP6", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP7", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP8", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "october"), "Expected \"october\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP9", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName8.dll", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP10", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP11", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName10.dll", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP12", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + delete_component_path("{A8AE6692-96BA-4198-8399-145D7D1D0D0E}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{1D2CE6F3-E81C-4949-AB81-78D7DAD2AF2E}", + MSIINSTALLCONTEXT_USERUNMANAGED, usersid); + delete_component_path("{19E0B999-85F5-4973-A61B-DBE4D66ECB1D}", + MSIINSTALLCONTEXT_USERMANAGED, usersid); + delete_component_path("{F0CCA976-27A3-4808-9DDD-1A6FD50A0D5A}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{C0ECD96F-7898-4410-9667-194BD8C1B648}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{DB20F535-9C26-4127-9C2B-CC45A8B51DA1}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{91B7359B-07F2-4221-AA8D-DE102BB87A5F}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{4A2E1B5B-4034-4177-833B-8CC35F1B3EF1}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{A204DF48-7346-4635-BA2E-66247DBAC9DF}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{EC30CE73-4CF9-4908-BABD-1ED82E1515FD}", + MSIINSTALLCONTEXT_MACHINE, NULL); + + DeleteFileA("FileName1"); + DeleteFileA("FileName2"); + DeleteFileA("FileName3"); + DeleteFileA("FileName4"); + DeleteFileA("FileName5"); + DeleteFileA("FileName6"); + DeleteFileA("FileName7"); + DeleteFileA("FileName8.dll"); + DeleteFileA("FileName9.dll"); + DeleteFileA("FileName10.dll"); + MsiCloseHandle(hpkg); + DeleteFileA(msifile); + LocalFree(usersid); +} + +static void test_appsearch_reglocator(void) +{ + MSIHANDLE hpkg, hdb; + CHAR path[MAX_PATH]; + CHAR prop[MAX_PATH]; + DWORD binary[2]; + DWORD size, val; + BOOL space, version; + HKEY hklm, classes; + HKEY hkcu, users; + LPSTR pathdata; + LPSTR pathvar; + LPCSTR str; + LPSTR ptr; + LONG res; + UINT r; + + version = TRUE; + if (!create_file_with_version("test.dll", MAKELONG(2, 1), MAKELONG(4, 3))) + version = FALSE; + + DeleteFileA("test.dll"); + + res = RegCreateKeyA(HKEY_CLASSES_ROOT, "Software\\Wine", &classes); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(classes, "Value1", 0, REG_SZ, + (const BYTE *)"regszdata", 10); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine", &hkcu); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(hkcu, "Value1", 0, REG_SZ, + (const BYTE *)"regszdata", 10); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + users = 0; + res = RegCreateKeyA(HKEY_USERS, "S-1-5-18\\Software\\Wine", &users); + ok(res == ERROR_SUCCESS || + broken(res == ERROR_INVALID_PARAMETER), + "Expected ERROR_SUCCESS, got %d\n", res); + + if (res == ERROR_SUCCESS) + { + res = RegSetValueExA(users, "Value1", 0, REG_SZ, + (const BYTE *)"regszdata", 10); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + } + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine", &hklm); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueA(hklm, NULL, REG_SZ, "defvalue", 8); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(hklm, "Value1", 0, REG_SZ, + (const BYTE *)"regszdata", 10); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + val = 42; + res = RegSetValueExA(hklm, "Value2", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + val = -42; + res = RegSetValueExA(hklm, "Value3", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(hklm, "Value4", 0, REG_EXPAND_SZ, + (const BYTE *)"%PATH%", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(hklm, "Value5", 0, REG_EXPAND_SZ, + (const BYTE *)"my%NOVAR%", 10); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(hklm, "Value6", 0, REG_MULTI_SZ, + (const BYTE *)"one\0two\0", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + binary[0] = 0x1234abcd; + binary[1] = 0x567890ef; + res = RegSetValueExA(hklm, "Value7", 0, REG_BINARY, + (const BYTE *)binary, sizeof(binary)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(hklm, "Value8", 0, REG_SZ, + (const BYTE *)"#regszdata", 11); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + create_test_file("FileName1"); + sprintf(path, "%s\\FileName1", CURR_DIR); + res = RegSetValueExA(hklm, "Value9", 0, REG_SZ, + (const BYTE *)path, lstrlenA(path) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + sprintf(path, "%s\\FileName2", CURR_DIR); + res = RegSetValueExA(hklm, "Value10", 0, REG_SZ, + (const BYTE *)path, lstrlenA(path) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + lstrcpyA(path, CURR_DIR); + res = RegSetValueExA(hklm, "Value11", 0, REG_SZ, + (const BYTE *)path, lstrlenA(path) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(hklm, "Value12", 0, REG_SZ, + (const BYTE *)"", 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + create_file_with_version("FileName3.dll", MAKELONG(2, 1), MAKELONG(4, 3)); + sprintf(path, "%s\\FileName3.dll", CURR_DIR); + res = RegSetValueExA(hklm, "Value13", 0, REG_SZ, + (const BYTE *)path, lstrlenA(path) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + create_file_with_version("FileName4.dll", MAKELONG(1, 2), MAKELONG(3, 4)); + sprintf(path, "%s\\FileName4.dll", CURR_DIR); + res = RegSetValueExA(hklm, "Value14", 0, REG_SZ, + (const BYTE *)path, lstrlenA(path) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + create_file_with_version("FileName5.dll", MAKELONG(2, 1), MAKELONG(4, 3)); + sprintf(path, "%s\\FileName5.dll", CURR_DIR); + res = RegSetValueExA(hklm, "Value15", 0, REG_SZ, + (const BYTE *)path, lstrlenA(path) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + sprintf(path, "\"%s\\FileName1\" -option", CURR_DIR); + res = RegSetValueExA(hklm, "value16", 0, REG_SZ, + (const BYTE *)path, lstrlenA(path) + 1); + + space = (strchr(CURR_DIR, ' ')) ? TRUE : FALSE; + sprintf(path, "%s\\FileName1 -option", CURR_DIR); + res = RegSetValueExA(hklm, "value17", 0, REG_SZ, + (const BYTE *)path, lstrlenA(path) + 1); + + hdb = create_package_db(); + ok(hdb, "Expected a valid database handle\n"); + + r = create_appsearch_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP1', 'NewSignature1'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP2', 'NewSignature2'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP3', 'NewSignature3'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP4', 'NewSignature4'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP5', 'NewSignature5'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP6', 'NewSignature6'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP7', 'NewSignature7'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP8', 'NewSignature8'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP9', 'NewSignature9'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP10', 'NewSignature10'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP11', 'NewSignature11'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP12', 'NewSignature12'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP13', 'NewSignature13'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP14', 'NewSignature14'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP15', 'NewSignature15'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP16', 'NewSignature16'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP17', 'NewSignature17'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP18', 'NewSignature18'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP19', 'NewSignature19'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP20', 'NewSignature20'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP21', 'NewSignature21'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP22', 'NewSignature22'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP23', 'NewSignature23'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP24', 'NewSignature24'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP25', 'NewSignature25'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP26', 'NewSignature26'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP27', 'NewSignature27'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP28', 'NewSignature28'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP29', 'NewSignature29'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP30', 'NewSignature30'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = create_reglocator_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_SZ */ + str = "'NewSignature1', 2, 'Software\\Wine', 'Value1', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, positive DWORD */ + str = "'NewSignature2', 2, 'Software\\Wine', 'Value2', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, negative DWORD */ + str = "'NewSignature3', 2, 'Software\\Wine', 'Value3', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_EXPAND_SZ */ + str = "'NewSignature4', 2, 'Software\\Wine', 'Value4', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_EXPAND_SZ */ + str = "'NewSignature5', 2, 'Software\\Wine', 'Value5', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_MULTI_SZ */ + str = "'NewSignature6', 2, 'Software\\Wine', 'Value6', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_BINARY */ + str = "'NewSignature7', 2, 'Software\\Wine', 'Value7', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_SZ first char is # */ + str = "'NewSignature8', 2, 'Software\\Wine', 'Value8', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFileName, signature, file exists */ + str = "'NewSignature9', 2, 'Software\\Wine', 'Value9', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFileName, signature, file does not exist */ + str = "'NewSignature10', 2, 'Software\\Wine', 'Value10', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFileName, no signature */ + str = "'NewSignature11', 2, 'Software\\Wine', 'Value9', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeDirectory, no signature, file exists */ + str = "'NewSignature12', 2, 'Software\\Wine', 'Value9', 0"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeDirectory, no signature, directory exists */ + str = "'NewSignature13', 2, 'Software\\Wine', 'Value11', 0"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeDirectory, signature, file exists */ + str = "'NewSignature14', 2, 'Software\\Wine', 'Value9', 0"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKCR, msidbLocatorTypeRawValue, REG_SZ */ + str = "'NewSignature15', 0, 'Software\\Wine', 'Value1', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKCU, msidbLocatorTypeRawValue, REG_SZ */ + str = "'NewSignature16', 1, 'Software\\Wine', 'Value1', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKU, msidbLocatorTypeRawValue, REG_SZ */ + str = "'NewSignature17', 3, 'S-1-5-18\\Software\\Wine', 'Value1', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_SZ, NULL Name */ + str = "'NewSignature18', 2, 'Software\\Wine', '', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_SZ, key does not exist */ + str = "'NewSignature19', 2, 'Software\\IDontExist', '', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeRawValue, REG_SZ, value is empty */ + str = "'NewSignature20', 2, 'Software\\Wine', 'Value12', 2"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFileName, signature, file exists w/ version */ + str = "'NewSignature21', 2, 'Software\\Wine', 'Value13', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFileName, file exists w/ version, version > max */ + str = "'NewSignature22', 2, 'Software\\Wine', 'Value14', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFileName, file exists w/ version, sig->name ignored */ + str = "'NewSignature23', 2, 'Software\\Wine', 'Value15', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFileName, no signature, directory exists */ + str = "'NewSignature24', 2, 'Software\\Wine', 'Value11', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFileName, no signature, file does not exist */ + str = "'NewSignature25', 2, 'Software\\Wine', 'Value10', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeDirectory, signature, directory exists */ + str = "'NewSignature26', 2, 'Software\\Wine', 'Value11', 0"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeDirectory, signature, file does not exist */ + str = "'NewSignature27', 2, 'Software\\Wine', 'Value10', 0"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeDirectory, no signature, file does not exist */ + str = "'NewSignature28', 2, 'Software\\Wine', 'Value10', 0"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFile, file exists, in quotes */ + str = "'NewSignature29', 2, 'Software\\Wine', 'Value16', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* HKLM, msidbLocatorTypeFile, file exists, no quotes */ + str = "'NewSignature30', 2, 'Software\\Wine', 'Value17', 1"; + r = add_reglocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = create_signature_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature9', 'FileName1', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature10', 'FileName2', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature14', 'FileName1', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature21', 'FileName3.dll', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature22', 'FileName4.dll', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature23', 'ignored', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + ptr = strrchr(CURR_DIR, '\\') + 1; + sprintf(path, "'NewSignature26', '%s', '', '', '', '', '', '', ''", ptr); + r = add_signature_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature27', 'FileName2', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature29', 'FileName1', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature30', 'FileName1', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + hpkg = package_from_db(hdb); + ok(hpkg, "Expected a valid package handle\n"); + + r = MsiDoAction(hpkg, "AppSearch"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP1", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "regszdata"), + "Expected \"regszdata\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP2", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "#42"), "Expected \"#42\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP3", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "#-42"), "Expected \"#-42\", got \"%s\"\n", prop); + + size = ExpandEnvironmentStringsA("%PATH%", NULL, 0); + if (size == 0 && GetLastError() == ERROR_INVALID_PARAMETER) + { + /* Workaround for Win95 */ + CHAR tempbuf[1]; + size = ExpandEnvironmentStringsA("%PATH%", tempbuf, 0); + } + pathvar = HeapAlloc(GetProcessHeap(), 0, size); + ExpandEnvironmentStringsA("%PATH%", pathvar, size); + + size = 0; + r = MsiGetPropertyA(hpkg, "SIGPROP4", NULL, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + pathdata = HeapAlloc(GetProcessHeap(), 0, ++size); + r = MsiGetPropertyA(hpkg, "SIGPROP4", pathdata, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(pathdata, pathvar), + "Expected \"%s\", got \"%s\"\n", pathvar, pathdata); + + HeapFree(GetProcessHeap(), 0, pathvar); + HeapFree(GetProcessHeap(), 0, pathdata); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP5", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, + "my%NOVAR%"), "Expected \"my%%NOVAR%%\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP6", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine + { + ok(!memcmp(prop, "\0one\0two\0\0", 10), + "Expected \"\\0one\\0two\\0\\0\"\n"); + } + + size = MAX_PATH; + lstrcpyA(path, "#xCDAB3412EF907856"); + r = MsiGetPropertyA(hpkg, "SIGPROP7", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP8", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "##regszdata"), + "Expected \"##regszdata\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName1", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP9", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP10", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP11", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP12", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP13", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP14", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP15", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "regszdata"), + "Expected \"regszdata\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP16", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "regszdata"), + "Expected \"regszdata\", got \"%s\"\n", prop); + + if (users) + { + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP17", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "regszdata"), + "Expected \"regszdata\", got \"%s\"\n", prop); + } + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP18", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "defvalue"), + "Expected \"defvalue\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP19", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP20", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + if (version) + { + size = MAX_PATH; + sprintf(path, "%s\\FileName3.dll", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP21", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP22", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName5.dll", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP23", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + } + + size = MAX_PATH; + lstrcpyA(path, CURR_DIR); + ptr = strrchr(path, '\\') + 1; + *ptr = '\0'; + r = MsiGetPropertyA(hpkg, "SIGPROP24", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP25", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP26", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP27", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP28", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName1", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP29", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName1", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP30", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + if (space) + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + else + todo_wine ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + RegSetValueA(hklm, NULL, REG_SZ, "", 0); + RegDeleteValueA(hklm, "Value1"); + RegDeleteValueA(hklm, "Value2"); + RegDeleteValueA(hklm, "Value3"); + RegDeleteValueA(hklm, "Value4"); + RegDeleteValueA(hklm, "Value5"); + RegDeleteValueA(hklm, "Value6"); + RegDeleteValueA(hklm, "Value7"); + RegDeleteValueA(hklm, "Value8"); + RegDeleteValueA(hklm, "Value9"); + RegDeleteValueA(hklm, "Value10"); + RegDeleteValueA(hklm, "Value11"); + RegDeleteValueA(hklm, "Value12"); + RegDeleteValueA(hklm, "Value13"); + RegDeleteValueA(hklm, "Value14"); + RegDeleteValueA(hklm, "Value15"); + RegDeleteValueA(hklm, "Value16"); + RegDeleteValueA(hklm, "Value17"); + RegDeleteKeyA(hklm, ""); + RegCloseKey(hklm); + + RegDeleteValueA(classes, "Value1"); + RegDeleteKeyA(classes, ""); + RegCloseKey(classes); + + RegDeleteValueA(hkcu, "Value1"); + RegDeleteKeyA(hkcu, ""); + RegCloseKey(hkcu); + + RegDeleteValueA(users, "Value1"); + RegDeleteKeyA(users, ""); + RegCloseKey(users); + + DeleteFileA("FileName1"); + DeleteFileA("FileName3.dll"); + DeleteFileA("FileName4.dll"); + DeleteFileA("FileName5.dll"); + MsiCloseHandle(hpkg); + DeleteFileA(msifile); +} + +static void delete_win_ini(LPCSTR file) +{ + CHAR path[MAX_PATH]; + + GetWindowsDirectoryA(path, MAX_PATH); + lstrcatA(path, "\\"); + lstrcatA(path, file); + + DeleteFileA(path); +} + +static void test_appsearch_inilocator(void) +{ + MSIHANDLE hpkg, hdb; + CHAR path[MAX_PATH]; + CHAR prop[MAX_PATH]; + BOOL version; + LPCSTR str; + LPSTR ptr; + DWORD size; + UINT r; + + version = TRUE; + if (!create_file_with_version("test.dll", MAKELONG(2, 1), MAKELONG(4, 3))) + version = FALSE; + + DeleteFileA("test.dll"); + + WritePrivateProfileStringA("Section", "Key", "keydata,field2", "IniFile.ini"); + + create_test_file("FileName1"); + sprintf(path, "%s\\FileName1", CURR_DIR); + WritePrivateProfileStringA("Section", "Key2", path, "IniFile.ini"); + + WritePrivateProfileStringA("Section", "Key3", CURR_DIR, "IniFile.ini"); + + sprintf(path, "%s\\IDontExist", CURR_DIR); + WritePrivateProfileStringA("Section", "Key4", path, "IniFile.ini"); + + create_file_with_version("FileName2.dll", MAKELONG(2, 1), MAKELONG(4, 3)); + sprintf(path, "%s\\FileName2.dll", CURR_DIR); + WritePrivateProfileStringA("Section", "Key5", path, "IniFile.ini"); + + create_file_with_version("FileName3.dll", MAKELONG(1, 2), MAKELONG(3, 4)); + sprintf(path, "%s\\FileName3.dll", CURR_DIR); + WritePrivateProfileStringA("Section", "Key6", path, "IniFile.ini"); + + create_file_with_version("FileName4.dll", MAKELONG(2, 1), MAKELONG(4, 3)); + sprintf(path, "%s\\FileName4.dll", CURR_DIR); + WritePrivateProfileStringA("Section", "Key7", path, "IniFile.ini"); + + hdb = create_package_db(); + ok(hdb, "Expected a valid database handle\n"); + + r = create_appsearch_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP1', 'NewSignature1'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP2', 'NewSignature2'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP3', 'NewSignature3'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP4', 'NewSignature4'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP5', 'NewSignature5'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP6', 'NewSignature6'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP7', 'NewSignature7'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP8', 'NewSignature8'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP9', 'NewSignature9'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP10', 'NewSignature10'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP11', 'NewSignature11'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP12', 'NewSignature12'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = create_inilocator_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeRawValue, field 1 */ + str = "'NewSignature1', 'IniFile.ini', 'Section', 'Key', 1, 2"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeRawValue, field 2 */ + str = "'NewSignature2', 'IniFile.ini', 'Section', 'Key', 2, 2"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeRawValue, entire field */ + str = "'NewSignature3', 'IniFile.ini', 'Section', 'Key', 0, 2"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeFile */ + str = "'NewSignature4', 'IniFile.ini', 'Section', 'Key2', 1, 1"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeDirectory, file */ + str = "'NewSignature5', 'IniFile.ini', 'Section', 'Key2', 1, 0"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeDirectory, directory */ + str = "'NewSignature6', 'IniFile.ini', 'Section', 'Key3', 1, 0"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeFile, file, no signature */ + str = "'NewSignature7', 'IniFile.ini', 'Section', 'Key2', 1, 1"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeFile, dir, no signature */ + str = "'NewSignature8', 'IniFile.ini', 'Section', 'Key3', 1, 1"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeFile, file does not exist */ + str = "'NewSignature9', 'IniFile.ini', 'Section', 'Key4', 1, 1"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeFile, signature with version */ + str = "'NewSignature10', 'IniFile.ini', 'Section', 'Key5', 1, 1"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeFile, signature with version, ver > max */ + str = "'NewSignature11', 'IniFile.ini', 'Section', 'Key6', 1, 1"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* msidbLocatorTypeFile, signature with version, sig->name ignored */ + str = "'NewSignature12', 'IniFile.ini', 'Section', 'Key7', 1, 1"; + r = add_inilocator_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = create_signature_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature4', 'FileName1', '', '', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature9', 'IDontExist', '', '', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature10', 'FileName2.dll', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature11', 'FileName3.dll', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_signature_entry(hdb, "'NewSignature12', 'ignored', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + hpkg = package_from_db(hdb); + ok(hpkg, "Expected a valid package handle\n"); + + r = MsiDoAction(hpkg, "AppSearch"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP1", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "keydata"), "Expected \"keydata\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP2", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "field2"), "Expected \"field2\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP3", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, "keydata,field2"), + "Expected \"keydata,field2\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName1", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP4", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP5", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP6", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP7", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + lstrcpyA(path, CURR_DIR); + ptr = strrchr(path, '\\'); + *(ptr + 1) = '\0'; + r = MsiGetPropertyA(hpkg, "SIGPROP8", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP9", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + if (version) + { + size = MAX_PATH; + sprintf(path, "%s\\FileName2.dll", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP10", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP11", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\FileName4.dll", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP12", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + } + + delete_win_ini("IniFile.ini"); + DeleteFileA("FileName1"); + DeleteFileA("FileName2.dll"); + DeleteFileA("FileName3.dll"); + DeleteFileA("FileName4.dll"); + MsiCloseHandle(hpkg); + DeleteFileA(msifile); +} + +/* + * MSI AppSearch action on DrLocator table always returns absolute paths. + * If a relative path was set, it returns the first absolute path that + * matches or an empty string if it didn't find anything. + * This helper function replicates this behaviour. + */ +static void search_absolute_directory(LPSTR absolute, LPCSTR relative) +{ + int i, size; + DWORD attr, drives; + + size = lstrlenA(relative); + drives = GetLogicalDrives(); + lstrcpyA(absolute, "A:\\"); + for (i = 0; i < 26; absolute[0] = '\0', i++) + { + if (!(drives & (1 << i))) + continue; + + absolute[0] = 'A' + i; + if (GetDriveType(absolute) != DRIVE_FIXED) + continue; + + lstrcpynA(absolute + 3, relative, size + 1); + attr = GetFileAttributesA(absolute); + if (attr != INVALID_FILE_ATTRIBUTES && + (attr & FILE_ATTRIBUTE_DIRECTORY)) + { + if (absolute[3 + size - 1] != '\\') + lstrcatA(absolute, "\\"); + break; + } + absolute[3] = '\0'; + } +} + +static void test_appsearch_drlocator(void) +{ + MSIHANDLE hpkg, hdb; + CHAR path[MAX_PATH]; + CHAR prop[MAX_PATH]; + BOOL version; + LPCSTR str; + DWORD size; + UINT r; + + version = TRUE; + if (!create_file_with_version("test.dll", MAKELONG(2, 1), MAKELONG(4, 3))) + version = FALSE; + + DeleteFileA("test.dll"); + + create_test_file("FileName1"); + CreateDirectoryA("one", NULL); + CreateDirectoryA("one\\two", NULL); + CreateDirectoryA("one\\two\\three", NULL); + create_test_file("one\\two\\three\\FileName2"); + CreateDirectoryA("another", NULL); + create_file_with_version("FileName3.dll", MAKELONG(2, 1), MAKELONG(4, 3)); + create_file_with_version("FileName4.dll", MAKELONG(1, 2), MAKELONG(3, 4)); + create_file_with_version("FileName5.dll", MAKELONG(2, 1), MAKELONG(4, 3)); + + hdb = create_package_db(); + ok(hdb, "Expected a valid database handle\n"); + + r = create_appsearch_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP1', 'NewSignature1'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP2', 'NewSignature2'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP3', 'NewSignature3'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP4', 'NewSignature4'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP5', 'NewSignature5'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP6', 'NewSignature6'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP7', 'NewSignature7'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP8', 'NewSignature8'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP9', 'NewSignature9'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP10', 'NewSignature10'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_appsearch_entry(hdb, "'SIGPROP11', 'NewSignature11'"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = create_drlocator_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, full path, depth 0, signature */ + sprintf(path, "'NewSignature1', '', '%s', 0", CURR_DIR); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, full path, depth 0, no signature */ + sprintf(path, "'NewSignature2', '', '%s', 0", CURR_DIR); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, relative path, depth 0, no signature */ + sprintf(path, "'NewSignature3', '', '%s', 0", CURR_DIR + 3); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, full path, depth 2, signature */ + sprintf(path, "'NewSignature4', '', '%s', 2", CURR_DIR); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, full path, depth 3, signature */ + sprintf(path, "'NewSignature5', '', '%s', 3", CURR_DIR); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, full path, depth 1, signature is dir */ + sprintf(path, "'NewSignature6', '', '%s', 1", CURR_DIR); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* parent is in DrLocator, relative path, depth 0, signature */ + sprintf(path, "'NewSignature7', 'NewSignature1', 'one\\two\\three', 1"); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, full path, depth 0, signature w/ version */ + sprintf(path, "'NewSignature8', '', '%s', 0", CURR_DIR); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, full path, depth 0, signature w/ version, ver > max */ + sprintf(path, "'NewSignature9', '', '%s', 0", CURR_DIR); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, full path, depth 0, signature w/ version, sig->name not ignored */ + sprintf(path, "'NewSignature10', '', '%s', 0", CURR_DIR); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* no parent, relative empty path, depth 0, no signature */ + sprintf(path, "'NewSignature11', '', '', 0"); + r = add_drlocator_entry(hdb, path); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = create_signature_table(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature1', 'FileName1', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature4', 'FileName2', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature5', 'FileName2', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature6', 'another', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature7', 'FileName2', '', '', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature8', 'FileName3.dll', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature9', 'FileName4.dll', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + str = "'NewSignature10', 'necessary', '1.1.1.1', '2.1.1.1', '', '', '', '', ''"; + r = add_signature_entry(hdb, str); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + hpkg = package_from_db(hdb); + ok(hpkg, "Expected a valid package handle\n"); + + r = MsiDoAction(hpkg, "AppSearch"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + sprintf(path, "%s\\FileName1", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP1", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + sprintf(path, "%s\\", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP2", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + search_absolute_directory(path, CURR_DIR + 3); + r = MsiGetPropertyA(hpkg, "SIGPROP3", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpiA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP4", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\one\\two\\three\\FileName2", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP5", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP6", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + sprintf(path, "%s\\one\\two\\three\\FileName2", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP7", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + if (version) + { + size = MAX_PATH; + sprintf(path, "%s\\FileName3.dll", CURR_DIR); + r = MsiGetPropertyA(hpkg, "SIGPROP8", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP9", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "SIGPROP10", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(prop, ""), "Expected \"\", got \"%s\"\n", prop); + } + + size = MAX_PATH; + search_absolute_directory(path, ""); + r = MsiGetPropertyA(hpkg, "SIGPROP11", prop, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpiA(prop, path), "Expected \"%s\", got \"%s\"\n", path, prop); + + DeleteFileA("FileName1"); + DeleteFileA("FileName3.dll"); + DeleteFileA("FileName4.dll"); + DeleteFileA("FileName5.dll"); + DeleteFileA("one\\two\\three\\FileName2"); + RemoveDirectoryA("one\\two\\three"); + RemoveDirectoryA("one\\two"); + RemoveDirectoryA("one"); + RemoveDirectoryA("another"); + MsiCloseHandle(hpkg); + DeleteFileA(msifile); +} + static void test_featureparents(void) { MSIHANDLE hpkg; @@ -4858,168 +9433,6 @@ static void test_installprops(void) DeleteFile(msifile); } -static void test_sourcedirprop(void) -{ - MSIHANDLE hpkg, hdb; - CHAR source_dir[MAX_PATH]; - CHAR path[MAX_PATH]; - DWORD size; - UINT r; - - hdb = create_package_db(); - ok ( hdb, "failed to create package database\n" ); - - r = add_directory_entry( hdb, "'TARGETDIR', '', 'SourceDir'"); - ok( r == ERROR_SUCCESS, "cannot add directory: %d\n", r ); - - hpkg = package_from_db( hdb ); - ok( hpkg, "failed to create package\n"); - - MsiCloseHandle( hdb ); - - size = MAX_PATH; - r = MsiGetProperty( hpkg, "SourceDir", source_dir, &size ); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrlenA(source_dir), "Expected emtpy source dir, got %s\n", source_dir); - - size = MAX_PATH; - r = MsiGetProperty( hpkg, "SOURCEDIR", source_dir, &size ); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrlenA(source_dir), "Expected emtpy source dir, got %s\n", source_dir); - - r = MsiDoAction( hpkg, "CostInitialize"); - ok( r == ERROR_SUCCESS, "cost init failed\n"); - - size = MAX_PATH; - r = MsiGetProperty( hpkg, "SourceDir", source_dir, &size ); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrlenA(source_dir), "Expected emtpy source dir, got %s\n", source_dir); - - size = MAX_PATH; - r = MsiGetProperty( hpkg, "SOURCEDIR", source_dir, &size ); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrlenA(source_dir), "Expected emtpy source dir, got %s\n", source_dir); - - r = MsiDoAction( hpkg, "ResolveSource"); - ok( r == ERROR_SUCCESS, "file cost failed\n"); - - GetCurrentDirectory(MAX_PATH, path); - lstrcatA(path, "\\"); - - size = MAX_PATH; - r = MsiGetProperty( hpkg, "SourceDir", source_dir, &size ); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrcmpA(source_dir, path), "Expected %s, got %s\n", path, source_dir); - - size = MAX_PATH; - r = MsiGetProperty( hpkg, "SOURCEDIR", source_dir, &size ); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrcmpA(source_dir, path), "Expected %s, got %s\n", path, source_dir); - - size = MAX_PATH; - r = MsiGetProperty( hpkg, "SoUrCeDiR", source_dir, &size ); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrlenA(source_dir), "Expected emtpy source dir, got %s\n", source_dir); - - MsiCloseHandle(hpkg); - DeleteFileA(msifile); -} - -static void test_prop_path(void) -{ - MSIHANDLE hpkg, hdb; - char buffer[MAX_PATH], cwd[MAX_PATH]; - DWORD sz; - UINT r; - - GetCurrentDirectory(MAX_PATH, cwd); - strcat(cwd, "\\"); - - hdb = create_package_db(); - ok( hdb, "failed to create database\n"); - - r = add_directory_entry( hdb, "'TARGETDIR','','SourceDir'" ); - ok( r == ERROR_SUCCESS, "cannot add directory: %d\n", r ); - - r = add_directory_entry( hdb, "'foo','TARGETDIR','foosrc:footgt'" ); - ok( r == ERROR_SUCCESS, "cannot add directory: %d\n", r ); - - hpkg = package_from_db(hdb); - ok( hpkg, "failed to create package\n"); - - r = MsiGetSourcePath(hpkg, "SourceDir", buffer, &sz ); - ok( r == ERROR_DIRECTORY, "failed to get source path\n"); - - r = MsiGetSourcePath(hpkg, "SOURCEDIR", buffer, &sz ); - ok( r == ERROR_DIRECTORY, "failed to get source path\n"); - - r = MsiDoAction( hpkg, "CostInitialize"); - ok( r == ERROR_SUCCESS, "cost init failed\n"); - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetProperty(hpkg, "SourceDir", buffer, &sz); - ok( r == ERROR_SUCCESS, "property not set\n"); - ok( !buffer[0], "SourceDir should be empty\n"); - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetProperty(hpkg, "SOURCEDIR", buffer, &sz); - ok( r == ERROR_SUCCESS, "property not set\n"); - ok( !buffer[0], "SourceDir should be empty\n"); - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetSourcePath(hpkg, "SourceDir", buffer, &sz ); - ok( r == ERROR_SUCCESS, "failed to get source path\n"); - ok( !lstrcmpi(cwd, buffer), "SourceDir (%s) should be current dir (%s)\n", buffer, cwd); - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetProperty(hpkg, "SourceDir", buffer, &sz); - ok( r == ERROR_SUCCESS, "property not set\n"); - todo_wine { - ok( !lstrcmpi(cwd, buffer), "SourceDir (%s) should be current dir (%s)\n", buffer, cwd); - } - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetSourcePath(hpkg, "SOURCEDIR", buffer, &sz ); - ok( r == ERROR_DIRECTORY, "failed to get source path\n"); - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetProperty(hpkg, "SOURCEDIR", buffer, &sz); - ok( r == ERROR_SUCCESS, "property not set\n"); - todo_wine { - ok( !lstrcmpi(cwd, buffer), "SourceDir (%s) should be current dir (%s)\n", buffer, cwd); - } - - r = MsiSetProperty(hpkg, "SourceDir", "goo"); - ok( r == ERROR_SUCCESS, "property not set\n"); - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetProperty(hpkg, "SourceDir", buffer, &sz); - ok( r == ERROR_SUCCESS, "property not set\n"); - ok( !lstrcmpi(buffer, "goo"), "SourceDir (%s) should be goo\n", buffer); - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetSourcePath(hpkg, "SourceDir", buffer, &sz ); - ok( r == ERROR_SUCCESS, "failed to get source path\n"); - ok( !lstrcmpi(buffer, cwd), "SourceDir (%s) should be goo\n", buffer); - - sz = sizeof buffer; - buffer[0] = 0; - r = MsiGetProperty(hpkg, "SourceDir", buffer, &sz); - ok( r == ERROR_SUCCESS, "property not set\n"); - ok( !lstrcmpi(buffer, "goo"), "SourceDir (%s) should be goo\n", buffer); - - MsiCloseHandle( hpkg ); - DeleteFile(msifile); -} - static void test_launchconditions(void) { MSIHANDLE hpkg; @@ -5116,95 +9529,6 @@ static void test_ccpsearch(void) DeleteFileA(msifile); } -static BOOL squash_guid(LPCWSTR in, LPWSTR out) -{ - DWORD i,n=1; - GUID guid; - - if (FAILED(CLSIDFromString((LPOLESTR)in, &guid))) - return FALSE; - - for(i=0; i<8; i++) - out[7-i] = in[n++]; - n++; - for(i=0; i<4; i++) - out[11-i] = in[n++]; - n++; - for(i=0; i<4; i++) - out[15-i] = in[n++]; - n++; - for(i=0; i<2; i++) - { - out[17+i*2] = in[n++]; - out[16+i*2] = in[n++]; - } - n++; - for( ; i<8; i++) - { - out[17+i*2] = in[n++]; - out[16+i*2] = in[n++]; - } - out[32]=0; - return TRUE; -} - -static void set_component_path(LPCSTR filename, LPCSTR guid) -{ - WCHAR guidW[MAX_PATH]; - WCHAR squashedW[MAX_PATH]; - CHAR squashed[MAX_PATH]; - CHAR substr[MAX_PATH]; - CHAR path[MAX_PATH]; - HKEY hkey; - - MultiByteToWideChar(CP_ACP, 0, guid, -1, guidW, MAX_PATH); - squash_guid(guidW, squashedW); - WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL); - - lstrcpyA(substr, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" - "Installer\\UserData\\S-1-5-18\\Components\\"); - lstrcatA(substr, squashed); - - RegCreateKeyA(HKEY_LOCAL_MACHINE, substr, &hkey); - - lstrcpyA(path, CURR_DIR); - lstrcatA(path, "\\"); - lstrcatA(path, filename); - - /* just using a random squashed product code */ - RegSetValueExA(hkey, "7D2F387510109040002000060BECB6AB", 0, - REG_SZ, (LPBYTE)path, lstrlenA(path)); - - RegCloseKey(hkey); - - lstrcpyA(substr, "SOFTWARE\\Classes\\Installer\\Products\\7D2F387510109040002000060BECB6AB"); - RegCreateKeyA(HKEY_LOCAL_MACHINE, substr, &hkey); -} - -static void delete_component_path(LPCSTR guid) -{ - WCHAR guidW[MAX_PATH]; - WCHAR squashedW[MAX_PATH]; - WCHAR substrW[MAX_PATH]; - CHAR squashed[MAX_PATH]; - CHAR substr[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, 0, guid, -1, guidW, MAX_PATH); - squash_guid(guidW, squashedW); - WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL); - - lstrcpyA(substr, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" - "Installer\\UserData\\S-1-5-18\\Components\\"); - lstrcatA(substr, squashed); - - MultiByteToWideChar(CP_ACP, 0, substr, -1, substrW, MAX_PATH); - package_RegDeleteTreeW(HKEY_LOCAL_MACHINE, substrW); - - lstrcpyA(substr, "SOFTWARE\\Classes\\Installer\\Products\\7D2F387510109040002000060BECB6AB"); - MultiByteToWideChar(CP_ACP, 0, substr, -1, substrW, MAX_PATH); - package_RegDeleteTreeW(HKEY_LOCAL_MACHINE, substrW); -} - static void test_complocator(void) { MSIHANDLE hdb, hpkg; @@ -5367,14 +9691,22 @@ static void test_complocator(void) CreateDirectoryA("olorotitan", NULL); CreateDirectoryA("pantydraco", NULL); - set_component_path("abelisaurus", "{E3619EED-305A-418C-B9C7-F7D7377F0934}"); - set_component_path("bactrosaurus", "{D56B688D-542F-42Ef-90FD-B6DA76EE8119}"); - set_component_path("echinodon", "{A19E16C5-C75D-4699-8111-C4338C40C3CB}"); - set_component_path("falcarius", "{17762FA1-A7AE-4CC6-8827-62873C35361D}"); - set_component_path("iguanodon", "{8E0DA02E-F6A7-4A8F-B25D-6F564C492308}"); - set_component_path("jobaria", "{243C22B1-8C51-4151-B9D1-1AE5265E079E}"); - set_component_path("megaraptor", "{8B1034B7-BD5E-41ac-B52C-0105D3DFD74D}"); - set_component_path("neosodon", "{0B499649-197A-48EF-93D2-AF1C17ED6E90}"); + set_component_path("abelisaurus", MSIINSTALLCONTEXT_MACHINE, + "{E3619EED-305A-418C-B9C7-F7D7377F0934}", NULL, FALSE); + set_component_path("bactrosaurus", MSIINSTALLCONTEXT_MACHINE, + "{D56B688D-542F-42Ef-90FD-B6DA76EE8119}", NULL, FALSE); + set_component_path("echinodon", MSIINSTALLCONTEXT_MACHINE, + "{A19E16C5-C75D-4699-8111-C4338C40C3CB}", NULL, FALSE); + set_component_path("falcarius", MSIINSTALLCONTEXT_MACHINE, + "{17762FA1-A7AE-4CC6-8827-62873C35361D}", NULL, FALSE); + set_component_path("iguanodon", MSIINSTALLCONTEXT_MACHINE, + "{8E0DA02E-F6A7-4A8F-B25D-6F564C492308}", NULL, FALSE); + set_component_path("jobaria", MSIINSTALLCONTEXT_MACHINE, + "{243C22B1-8C51-4151-B9D1-1AE5265E079E}", NULL, FALSE); + set_component_path("megaraptor", MSIINSTALLCONTEXT_MACHINE, + "{8B1034B7-BD5E-41ac-B52C-0105D3DFD74D}", NULL, FALSE); + set_component_path("neosodon", MSIINSTALLCONTEXT_MACHINE, + "{0B499649-197A-48EF-93D2-AF1C17ED6E90}", NULL, FALSE); r = MsiDoAction(hpkg, "AppSearch"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); @@ -5492,24 +9824,2130 @@ static void test_complocator(void) RemoveDirectoryA("neosodon"); RemoveDirectoryA("olorotitan"); RemoveDirectoryA("pantydraco"); - delete_component_path("{E3619EED-305A-418C-B9C7-F7D7377F0934}"); - delete_component_path("{D56B688D-542F-42Ef-90FD-B6DA76EE8119}"); - delete_component_path("{A19E16C5-C75D-4699-8111-C4338C40C3CB}"); - delete_component_path("{17762FA1-A7AE-4CC6-8827-62873C35361D}"); - delete_component_path("{8E0DA02E-F6A7-4A8F-B25D-6F564C492308}"); - delete_component_path("{243C22B1-8C51-4151-B9D1-1AE5265E079E}"); - delete_component_path("{8B1034B7-BD5E-41ac-B52C-0105D3DFD74D}"); - delete_component_path("{0B499649-197A-48EF-93D2-AF1C17ED6E90}"); + delete_component_path("{E3619EED-305A-418C-B9C7-F7D7377F0934}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{D56B688D-542F-42Ef-90FD-B6DA76EE8119}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{A19E16C5-C75D-4699-8111-C4338C40C3CB}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{17762FA1-A7AE-4CC6-8827-62873C35361D}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{8E0DA02E-F6A7-4A8F-B25D-6F564C492308}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{243C22B1-8C51-4151-B9D1-1AE5265E079E}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{8B1034B7-BD5E-41ac-B52C-0105D3DFD74D}", + MSIINSTALLCONTEXT_MACHINE, NULL); + delete_component_path("{0B499649-197A-48EF-93D2-AF1C17ED6E90}", + MSIINSTALLCONTEXT_MACHINE, NULL); DeleteFileA(msifile); } +static void set_suminfo_prop(MSIHANDLE db, DWORD prop, DWORD val) +{ + MSIHANDLE summary; + UINT r; + + r = MsiGetSummaryInformationA(db, NULL, 1, &summary); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiSummaryInfoSetPropertyA(summary, prop, VT_I4, val, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiSummaryInfoPersist(summary); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + MsiCloseHandle(summary); +} + +static void test_MsiGetSourcePath(void) +{ + MSIHANDLE hdb, hpkg; + CHAR path[MAX_PATH]; + CHAR cwd[MAX_PATH]; + CHAR subsrc[MAX_PATH]; + CHAR sub2[MAX_PATH]; + DWORD size; + UINT r; + + lstrcpyA(cwd, CURR_DIR); + lstrcatA(cwd, "\\"); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "subsource"); + lstrcatA(subsrc, "\\"); + + lstrcpyA(sub2, subsrc); + lstrcatA(sub2, "sub2"); + lstrcatA(sub2, "\\"); + + /* uncompressed source */ + + hdb = create_package_db(); + ok( hdb, "failed to create database\n"); + + set_suminfo_prop(hdb, PID_WORDCOUNT, 0); + + r = add_directory_entry(hdb, "'TARGETDIR', '', 'SourceDir'"); + ok(r == S_OK, "failed\n"); + + r = add_directory_entry(hdb, "'SubDir', 'TARGETDIR', 'subtarget:subsource'"); + ok(r == S_OK, "failed\n"); + + r = add_directory_entry(hdb, "'SubDir2', 'SubDir', 'sub2'"); + ok(r == S_OK, "failed\n"); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS , "Failed to commit database\n"); + + hpkg = package_from_db(hdb); + ok(hpkg, "failed to create package\n"); + + MsiCloseHandle(hdb); + + /* invalid database handle */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(-1, "TARGETDIR", path, &size); + ok(r == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* NULL szFolder */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, NULL, path, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* empty szFolder */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* try TARGETDIR */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* try SourceDir */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* try SOURCEDIR */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* source path does not exist, but the property exists */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + /* try SubDir */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* try SubDir2 */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + r = MsiDoAction(hpkg, "CostInitialize"); + ok(r == ERROR_SUCCESS, "cost init failed\n"); + + /* try TARGETDIR after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SourceDir after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SOURCEDIR after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* source path does not exist, but the property exists */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine + { + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + } + + /* try SubDir after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + /* try SubDir2 after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, sub2), "Expected \"%s\", got \"%s\"\n", sub2, path); + ok(size == lstrlenA(sub2), "Expected %d, got %d\n", lstrlenA(sub2), size); + + r = MsiDoAction(hpkg, "ResolveSource"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* try TARGETDIR after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SourceDir after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SOURCEDIR after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* source path does not exist, but the property exists */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + /* try SubDir2 after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, sub2), "Expected \"%s\", got \"%s\"\n", sub2, path); + ok(size == lstrlenA(sub2), "Expected %d, got %d\n", lstrlenA(sub2), size); + + r = MsiDoAction(hpkg, "FileCost"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* try TARGETDIR after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SourceDir after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SOURCEDIR after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* source path does not exist, but the property exists */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + /* try SubDir2 after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, sub2), "Expected \"%s\", got \"%s\"\n", sub2, path); + ok(size == lstrlenA(sub2), "Expected %d, got %d\n", lstrlenA(sub2), size); + + r = MsiDoAction(hpkg, "CostFinalize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* try TARGETDIR after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SourceDir after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SOURCEDIR after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* source path does not exist, but the property exists */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + /* try SubDir2 after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, sub2), "Expected \"%s\", got \"%s\"\n", sub2, path); + ok(size == lstrlenA(sub2), "Expected %d, got %d\n", lstrlenA(sub2), size); + + /* nonexistent directory */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "IDontExist", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* NULL szPathBuf */ + size = MAX_PATH; + r = MsiGetSourcePath(hpkg, "SourceDir", NULL, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* NULL pcchPathBuf */ + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + + /* pcchPathBuf is 0 */ + size = 0; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* pcchPathBuf does not have room for NULL terminator */ + size = lstrlenA(cwd); + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!strncmp(path, cwd, lstrlenA(cwd) - 1), + "Expected path with no backslash, got \"%s\"\n", path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* pcchPathBuf has room for NULL terminator */ + size = lstrlenA(cwd) + 1; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + MsiCloseHandle(hpkg); + + /* compressed source */ + + r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + set_suminfo_prop(hdb, PID_WORDCOUNT, msidbSumInfoSourceTypeCompressed); + + hpkg = package_from_db(hdb); + ok(hpkg, "failed to create package\n"); + + /* try TARGETDIR */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* try SourceDir */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* try SOURCEDIR */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* source path nor the property exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + /* try SubDir */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* try SubDir2 */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + r = MsiDoAction(hpkg, "CostInitialize"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* try TARGETDIR after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SourceDir after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SOURCEDIR after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + } + + /* source path does not exist, but the property exists */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine + { + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + } + + /* try SubDir after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir2 after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + r = MsiDoAction(hpkg, "ResolveSource"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* try TARGETDIR after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SourceDir after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SOURCEDIR after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + } + + /* source path and the property exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir2 after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + r = MsiDoAction(hpkg, "FileCost"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* try TARGETDIR after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SourceDir after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SOURCEDIR after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + } + + /* source path and the property exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir2 after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + r = MsiDoAction(hpkg, "CostFinalize"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* try TARGETDIR after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "TARGETDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SourceDir after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SOURCEDIR after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + } + + /* source path and the property exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* try SubDir2 after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + MsiCloseHandle(hpkg); + DeleteFile(msifile); +} + +static void test_shortlongsource(void) +{ + MSIHANDLE hdb, hpkg; + CHAR path[MAX_PATH]; + CHAR cwd[MAX_PATH]; + CHAR subsrc[MAX_PATH]; + DWORD size; + UINT r; + + lstrcpyA(cwd, CURR_DIR); + lstrcatA(cwd, "\\"); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "long"); + lstrcatA(subsrc, "\\"); + + /* long file names */ + + hdb = create_package_db(); + ok( hdb, "failed to create database\n"); + + set_suminfo_prop(hdb, PID_WORDCOUNT, 0); + + r = add_directory_entry(hdb, "'TARGETDIR', '', 'SourceDir'"); + ok(r == S_OK, "failed\n"); + + r = add_directory_entry(hdb, "'SubDir', 'TARGETDIR', 'short|long'"); + ok(r == S_OK, "failed\n"); + + /* CostInitialize:short */ + r = add_directory_entry(hdb, "'SubDir2', 'TARGETDIR', 'one|two'"); + ok(r == S_OK, "failed\n"); + + /* CostInitialize:long */ + r = add_directory_entry(hdb, "'SubDir3', 'TARGETDIR', 'three|four'"); + ok(r == S_OK, "failed\n"); + + /* FileCost:short */ + r = add_directory_entry(hdb, "'SubDir4', 'TARGETDIR', 'five|six'"); + ok(r == S_OK, "failed\n"); + + /* FileCost:long */ + r = add_directory_entry(hdb, "'SubDir5', 'TARGETDIR', 'seven|eight'"); + ok(r == S_OK, "failed\n"); + + /* CostFinalize:short */ + r = add_directory_entry(hdb, "'SubDir6', 'TARGETDIR', 'nine|ten'"); + ok(r == S_OK, "failed\n"); + + /* CostFinalize:long */ + r = add_directory_entry(hdb, "'SubDir7', 'TARGETDIR', 'eleven|twelve'"); + ok(r == S_OK, "failed\n"); + + MsiDatabaseCommit(hdb); + + hpkg = package_from_db(hdb); + ok(hpkg, "failed to create package\n"); + + MsiCloseHandle(hdb); + + CreateDirectoryA("one", NULL); + CreateDirectoryA("four", NULL); + + r = MsiDoAction(hpkg, "CostInitialize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + CreateDirectory("five", NULL); + CreateDirectory("eight", NULL); + + r = MsiDoAction(hpkg, "FileCost"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + CreateDirectory("nine", NULL); + CreateDirectory("twelve", NULL); + + r = MsiDoAction(hpkg, "CostFinalize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* neither short nor long source directories exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + CreateDirectoryA("short", NULL); + + /* short source directory exists */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + CreateDirectoryA("long", NULL); + + /* both short and long source directories exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "two"); + lstrcatA(subsrc, "\\"); + + /* short dir exists before CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "four"); + lstrcatA(subsrc, "\\"); + + /* long dir exists before CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir3", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "six"); + lstrcatA(subsrc, "\\"); + + /* short dir exists before FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir4", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "eight"); + lstrcatA(subsrc, "\\"); + + /* long dir exists before FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir5", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "ten"); + lstrcatA(subsrc, "\\"); + + /* short dir exists before CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir6", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "twelve"); + lstrcatA(subsrc, "\\"); + + /* long dir exists before CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir7", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + MsiCloseHandle(hpkg); + RemoveDirectoryA("short"); + RemoveDirectoryA("long"); + RemoveDirectoryA("one"); + RemoveDirectoryA("four"); + RemoveDirectoryA("five"); + RemoveDirectoryA("eight"); + RemoveDirectoryA("nine"); + RemoveDirectoryA("twelve"); + + /* short file names */ + + r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + set_suminfo_prop(hdb, PID_WORDCOUNT, msidbSumInfoSourceTypeSFN); + + hpkg = package_from_db(hdb); + ok(hpkg, "failed to create package\n"); + + MsiCloseHandle(hdb); + + CreateDirectoryA("one", NULL); + CreateDirectoryA("four", NULL); + + r = MsiDoAction(hpkg, "CostInitialize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + CreateDirectory("five", NULL); + CreateDirectory("eight", NULL); + + r = MsiDoAction(hpkg, "FileCost"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + CreateDirectory("nine", NULL); + CreateDirectory("twelve", NULL); + + r = MsiDoAction(hpkg, "CostFinalize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "short"); + lstrcatA(subsrc, "\\"); + + /* neither short nor long source directories exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + CreateDirectoryA("short", NULL); + + /* short source directory exists */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + CreateDirectoryA("long", NULL); + + /* both short and long source directories exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "one"); + lstrcatA(subsrc, "\\"); + + /* short dir exists before CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir2", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "three"); + lstrcatA(subsrc, "\\"); + + /* long dir exists before CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir3", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "five"); + lstrcatA(subsrc, "\\"); + + /* short dir exists before FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir4", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "seven"); + lstrcatA(subsrc, "\\"); + + /* long dir exists before FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir5", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "nine"); + lstrcatA(subsrc, "\\"); + + /* short dir exists before CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir6", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "eleven"); + lstrcatA(subsrc, "\\"); + + /* long dir exists before CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SubDir7", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, subsrc), "Expected \"%s\", got \"%s\"\n", subsrc, path); + ok(size == lstrlenA(subsrc), "Expected %d, got %d\n", lstrlenA(subsrc), size); + + MsiCloseHandle(hpkg); + RemoveDirectoryA("short"); + RemoveDirectoryA("long"); + RemoveDirectoryA("one"); + RemoveDirectoryA("four"); + RemoveDirectoryA("five"); + RemoveDirectoryA("eight"); + RemoveDirectoryA("nine"); + RemoveDirectoryA("twelve"); + DeleteFileA(msifile); +} + +static void test_sourcedir(void) +{ + MSIHANDLE hdb, hpkg; + CHAR package[10]; + CHAR path[MAX_PATH]; + CHAR cwd[MAX_PATH]; + CHAR subsrc[MAX_PATH]; + DWORD size; + UINT r; + + lstrcpyA(cwd, CURR_DIR); + lstrcatA(cwd, "\\"); + + lstrcpyA(subsrc, cwd); + lstrcatA(subsrc, "long"); + lstrcatA(subsrc, "\\"); + + hdb = create_package_db(); + ok( hdb, "failed to create database\n"); + + r = add_directory_entry(hdb, "'TARGETDIR', '', 'SourceDir'"); + ok(r == S_OK, "failed\n"); + + sprintf(package, "#%i", hdb); + r = MsiOpenPackage(package, &hpkg); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* properties only */ + + /* SourceDir prop */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + /* SOURCEDIR prop */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + r = MsiDoAction(hpkg, "CostInitialize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* SourceDir after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + /* SOURCEDIR after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + r = MsiDoAction(hpkg, "FileCost"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* SourceDir after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + /* SOURCEDIR after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + r = MsiDoAction(hpkg, "CostFinalize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* SourceDir after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + /* SOURCEDIR after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + r = MsiDoAction(hpkg, "ResolveSource"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* SourceDir after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* random casing */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SoUrCeDiR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + + MsiCloseHandle(hpkg); + + /* reset the package state */ + sprintf(package, "#%i", hdb); + r = MsiOpenPackage(package, &hpkg); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* test how MsiGetSourcePath affects the properties */ + + /* SourceDir prop */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine + { + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + } + + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* SourceDir after MsiGetSourcePath */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine + { + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + } + + /* SOURCEDIR prop */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine + { + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + } + + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* SOURCEDIR prop after MsiGetSourcePath */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine + { + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + } + + r = MsiDoAction(hpkg, "CostInitialize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* SourceDir after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + todo_wine + { + ok(!lstrcmpA(path, ""), "Expected \"\", got \"%s\"\n", path); + ok(size == 0, "Expected 0, got %d\n", size); + } + + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SourceDir after MsiGetSourcePath */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR after CostInitialize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR source path still does not exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + r = MsiDoAction(hpkg, "FileCost"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* SourceDir after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR after FileCost */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR source path still does not exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + r = MsiDoAction(hpkg, "CostFinalize"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* SourceDir after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR after CostFinalize */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR source path still does not exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + r = MsiDoAction(hpkg, "ResolveSource"); + ok(r == ERROR_SUCCESS, "file cost failed\n"); + + /* SourceDir after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SourceDir", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR after ResolveSource */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetProperty(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(path, cwd), "Expected \"%s\", got \"%s\"\n", cwd, path); + ok(size == lstrlenA(cwd), "Expected %d, got %d\n", lstrlenA(cwd), size); + + /* SOURCEDIR source path still does not exist */ + size = MAX_PATH; + lstrcpyA(path, "kiwi"); + r = MsiGetSourcePath(hpkg, "SOURCEDIR", path, &size); + ok(r == ERROR_DIRECTORY, "Expected ERROR_DIRECTORY, got %d\n", r); + ok(!lstrcmpA(path, "kiwi"), + "Expected path to be unchanged, got \"%s\"\n", path); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + MsiCloseHandle(hdb); + MsiCloseHandle(hpkg); + DeleteFileA(msifile); +} + +struct access_res +{ + BOOL gothandle; + DWORD lasterr; + BOOL ignore; +}; + +static const struct access_res create[16] = +{ + { TRUE, ERROR_SUCCESS, TRUE }, + { TRUE, ERROR_SUCCESS, TRUE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, TRUE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, TRUE } +}; + +static const struct access_res create_commit[16] = +{ + { TRUE, ERROR_SUCCESS, TRUE }, + { TRUE, ERROR_SUCCESS, TRUE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, TRUE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, TRUE } +}; + +static const struct access_res create_close[16] = +{ + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS } +}; + +static void _test_file_access(LPCSTR file, const struct access_res *ares, DWORD line) +{ + DWORD access = 0, share = 0; + DWORD lasterr; + HANDLE hfile; + int i, j, idx = 0; + + for (i = 0; i < 4; i++) + { + if (i == 0) access = 0; + if (i == 1) access = GENERIC_READ; + if (i == 2) access = GENERIC_WRITE; + if (i == 3) access = GENERIC_READ | GENERIC_WRITE; + + for (j = 0; j < 4; j++) + { + if (ares[idx].ignore) + continue; + + if (j == 0) share = 0; + if (j == 1) share = FILE_SHARE_READ; + if (j == 2) share = FILE_SHARE_WRITE; + if (j == 3) share = FILE_SHARE_READ | FILE_SHARE_WRITE; + + SetLastError(0xdeadbeef); + hfile = CreateFileA(file, access, share, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + lasterr = GetLastError(); + + ok((hfile != INVALID_HANDLE_VALUE) == ares[idx].gothandle, + "(%d, handle, %d): Expected %d, got %d\n", + line, idx, ares[idx].gothandle, + (hfile != INVALID_HANDLE_VALUE)); + + ok(lasterr == ares[idx].lasterr || + lasterr == 0xdeadbeef, /* win9x */ + "(%d, lasterr, %d): Expected %d, got %d\n", + line, idx, ares[idx].lasterr, lasterr); + + CloseHandle(hfile); + idx++; + } + } +} + +#define test_file_access(file, ares) _test_file_access(file, ares, __LINE__) + +static void test_access(void) +{ + MSIHANDLE hdb; + UINT r; + + r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + test_file_access(msifile, create); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + test_file_access(msifile, create_commit); + + MsiCloseHandle(hdb); + + test_file_access(msifile, create_close); + + DeleteFileA(msifile); + + r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATEDIRECT, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + test_file_access(msifile, create); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + test_file_access(msifile, create_commit); + + MsiCloseHandle(hdb); + + test_file_access(msifile, create_close); + + DeleteFileA(msifile); +} + +static void test_emptypackage(void) +{ + MSIHANDLE hpkg = 0, hdb = 0, hsuminfo = 0; + MSIHANDLE hview = 0, hrec = 0; + MSICONDITION condition; + CHAR buffer[MAX_PATH]; + DWORD size; + UINT r; + + r = MsiOpenPackageA("", &hpkg); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + hdb = MsiGetActiveDatabase(hpkg); + todo_wine + { + ok(hdb != 0, "Expected a valid database handle\n"); + } + + r = MsiDatabaseOpenView(hdb, "SELECT * FROM `_Tables`", &hview); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + r = MsiViewExecute(hview, 0); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + r = MsiViewFetch(hview, &hrec); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + buffer[0] = 0; + size = MAX_PATH; + r = MsiRecordGetString(hrec, 1, buffer, &size); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buffer, "_Property"), + "Expected \"_Property\", got \"%s\"\n", buffer); + } + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + size = MAX_PATH; + r = MsiRecordGetString(hrec, 1, buffer, &size); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buffer, "#_FolderCache"), + "Expected \"_Property\", got \"%s\"\n", buffer); + } + + MsiCloseHandle(hrec); + MsiViewClose(hview); + MsiCloseHandle(hview); + + condition = MsiDatabaseIsTablePersistentA(hdb, "_Property"); + todo_wine + { + ok(condition == MSICONDITION_FALSE, + "Expected MSICONDITION_FALSE, got %d\n", condition); + } + + r = MsiDatabaseOpenView(hdb, "SELECT * FROM `_Property`", &hview); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + r = MsiViewExecute(hview, 0); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + /* _Property table is not empty */ + r = MsiViewFetch(hview, &hrec); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + MsiCloseHandle(hrec); + MsiViewClose(hview); + MsiCloseHandle(hview); + + condition = MsiDatabaseIsTablePersistentA(hdb, "#_FolderCache"); + todo_wine + { + ok(condition == MSICONDITION_FALSE, + "Expected MSICONDITION_FALSE, got %d\n", condition); + } + + r = MsiDatabaseOpenView(hdb, "SELECT * FROM `#_FolderCache`", &hview); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + r = MsiViewExecute(hview, 0); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + /* #_FolderCache is not empty */ + r = MsiViewFetch(hview, &hrec); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + MsiCloseHandle(hrec); + MsiViewClose(hview); + MsiCloseHandle(hview); + + r = MsiDatabaseOpenView(hdb, "SELECT * FROM `_Streams`", &hview); + todo_wine + { + ok(r == ERROR_BAD_QUERY_SYNTAX, + "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + } + + r = MsiDatabaseOpenView(hdb, "SELECT * FROM `_Storages`", &hview); + todo_wine + { + ok(r == ERROR_BAD_QUERY_SYNTAX, + "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + } + + r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsuminfo); + todo_wine + { + ok(r == ERROR_INSTALL_PACKAGE_INVALID, + "Expected ERROR_INSTALL_PACKAGE_INVALID, got %d\n", r); + } + + MsiCloseHandle(hsuminfo); + + r = MsiDatabaseCommit(hdb); + todo_wine + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + } + + MsiCloseHandle(hdb); + MsiCloseHandle(hpkg); +} + +static void test_MsiGetProductProperty(void) +{ + MSIHANDLE hprod, hdb; + CHAR val[MAX_PATH]; + CHAR path[MAX_PATH]; + CHAR query[MAX_PATH]; + CHAR keypath[MAX_PATH*2]; + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + HKEY prodkey, userkey, props; + DWORD size; + LONG res; + UINT r; + SC_HANDLE scm; + + scm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + if (!scm && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) + { + win_skip("Different registry keys on Win9x and WinMe\n"); + return; + } + CloseServiceHandle(scm); + + GetCurrentDirectoryA(MAX_PATH, path); + lstrcatA(path, "\\"); + + create_test_guid(prodcode, prod_squashed); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = set_summary_info(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = run_query(hdb, + "CREATE TABLE `Directory` ( " + "`Directory` CHAR(255) NOT NULL, " + "`Directory_Parent` CHAR(255), " + "`DefaultDir` CHAR(255) NOT NULL " + "PRIMARY KEY `Directory`)"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = run_query(hdb, + "CREATE TABLE `Property` ( " + "`Property` CHAR(72) NOT NULL, " + "`Value` CHAR(255) " + "PRIMARY KEY `Property`)"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sprintf(query, "INSERT INTO `Property` " + "(`Property`, `Value`) " + "VALUES( 'ProductCode', '%s' )", prodcode); + r = run_query(hdb, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + MsiCloseHandle(hdb); + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\S-1-5-18\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + if (res == ERROR_ACCESS_DENIED) + { + skip("Not enough rights to perform tests\n"); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + return; + } + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegCreateKeyA(userkey, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + lstrcpyA(val, path); + lstrcatA(val, "\\winetest.msi"); + res = RegSetValueExA(props, "LocalPackage", 0, REG_SZ, + (const BYTE *)val, lstrlenA(val) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + hprod = 0xdeadbeef; + r = MsiOpenProductA(prodcode, &hprod); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(hprod != 0 && hprod != 0xdeadbeef, "Expected a valid product handle\n"); + + /* hProduct is invalid */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(0xdeadbeef, "ProductCode", val, &size); + ok(r == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* szProperty is NULL */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, NULL, val, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == MAX_PATH, "Expected size to be unchanged, got %d\n", size); + + /* szProperty is empty */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, ""), "Expected \"\", got \"%s\"\n", val); + ok(size == 0, "Expected 0, got %d\n", size); + + /* get the property */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "ProductCode", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, val); + ok(size == lstrlenA(prodcode), + "Expected %d, got %d\n", lstrlenA(prodcode), size); + + /* lpValueBuf is NULL */ + size = MAX_PATH; + r = MsiGetProductPropertyA(hprod, "ProductCode", NULL, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(size == lstrlenA(prodcode), + "Expected %d, got %d\n", lstrlenA(prodcode), size); + + /* pcchValueBuf is NULL */ + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "ProductCode", val, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(val, "apple"), + "Expected val to be unchanged, got \"%s\"\n", val); + ok(size == lstrlenA(prodcode), + "Expected %d, got %d\n", lstrlenA(prodcode), size); + + /* pcchValueBuf is too small */ + size = 4; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "ProductCode", val, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!strncmp(val, prodcode, 3), + "Expected first 3 chars of \"%s\", got \"%s\"\n", prodcode, val); + ok(size == lstrlenA(prodcode), + "Expected %d, got %d\n", lstrlenA(prodcode), size); + + /* pcchValueBuf does not leave room for NULL terminator */ + size = lstrlenA(prodcode); + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "ProductCode", val, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!strncmp(val, prodcode, lstrlenA(prodcode) - 1), + "Expected first 37 chars of \"%s\", got \"%s\"\n", prodcode, val); + ok(size == lstrlenA(prodcode), + "Expected %d, got %d\n", lstrlenA(prodcode), size); + + /* pcchValueBuf has enough room for NULL terminator */ + size = lstrlenA(prodcode) + 1; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "ProductCode", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, val); + ok(size == lstrlenA(prodcode), + "Expected %d, got %d\n", lstrlenA(prodcode), size); + + /* nonexistent property */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "IDontExist", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, ""), "Expected \"\", got \"%s\"\n", val); + ok(size == 0, "Expected 0, got %d\n", size); + + r = MsiSetPropertyA(hprod, "NewProperty", "value"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* non-product property set */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "NewProperty", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, ""), "Expected \"\", got \"%s\"\n", val); + ok(size == 0, "Expected 0, got %d\n", size); + + r = MsiSetPropertyA(hprod, "ProductCode", "value"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* non-product property that is also a product property set */ + size = MAX_PATH; + lstrcpyA(val, "apple"); + r = MsiGetProductPropertyA(hprod, "ProductCode", val, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(val, prodcode), + "Expected \"%s\", got \"%s\"\n", prodcode, val); + ok(size == lstrlenA(prodcode), + "Expected %d, got %d\n", lstrlenA(prodcode), size); + + MsiCloseHandle(hprod); + + RegDeleteValueA(props, "LocalPackage"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + DeleteFileA(msifile); +} + +static void test_MsiSetProperty(void) +{ + MSIHANDLE hpkg, hdb, hrec; + CHAR buf[MAX_PATH]; + LPCSTR query; + DWORD size; + UINT r; + + hpkg = package_from_db(create_package_db()); + ok(hpkg != 0, "Expected a valid package\n"); + + /* invalid hInstall */ + r = MsiSetPropertyA(0, "Prop", "Val"); + ok(r == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", r); + + /* invalid hInstall */ + r = MsiSetPropertyA(0xdeadbeef, "Prop", "Val"); + ok(r == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", r); + + /* szName is NULL */ + r = MsiSetPropertyA(hpkg, NULL, "Val"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* both szName and szValue are NULL */ + r = MsiSetPropertyA(hpkg, NULL, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* szName is empty */ + r = MsiSetPropertyA(hpkg, "", "Val"); + ok(r == ERROR_FUNCTION_FAILED, + "Expected ERROR_FUNCTION_FAILED, got %d\n", r); + + /* szName is empty and szValue is NULL */ + r = MsiSetPropertyA(hpkg, "", NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* set a property */ + r = MsiSetPropertyA(hpkg, "Prop", "Val"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* get the property */ + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "Prop", buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "Val"), "Expected \"Val\", got \"%s\"\n", buf); + ok(size == 3, "Expected 3, got %d\n", size); + + /* update the property */ + r = MsiSetPropertyA(hpkg, "Prop", "Nuvo"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* get the property */ + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "Prop", buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "Nuvo"), "Expected \"Nuvo\", got \"%s\"\n", buf); + ok(size == 4, "Expected 4, got %d\n", size); + + hdb = MsiGetActiveDatabase(hpkg); + ok(hdb != 0, "Expected a valid database handle\n"); + + /* set prop is not in the _Property table */ + query = "SELECT * FROM `_Property` WHERE `Property` = 'Prop'"; + r = do_query(hdb, query, &hrec); + ok(r == ERROR_BAD_QUERY_SYNTAX, + "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + /* set prop is not in the Property table */ + query = "SELECT * FROM `Property` WHERE `Property` = 'Prop'"; + r = do_query(hdb, query, &hrec); + ok(r == ERROR_BAD_QUERY_SYNTAX, + "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + MsiCloseHandle(hdb); + + /* szValue is an empty string */ + r = MsiSetPropertyA(hpkg, "Prop", ""); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* try to get the property */ + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "Prop", buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(size == 0, "Expected 0, got %d\n", size); + + /* reset the property */ + r = MsiSetPropertyA(hpkg, "Prop", "BlueTap"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* delete the property */ + r = MsiSetPropertyA(hpkg, "Prop", NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* try to get the property */ + size = MAX_PATH; + r = MsiGetPropertyA(hpkg, "Prop", buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(size == 0, "Expected 0, got %d\n", size); + + MsiCloseHandle(hpkg); + DeleteFileA(msifile); +} + +static void test_MsiApplyMultiplePatches(void) +{ + UINT r, type = GetDriveType(NULL); + + if (!pMsiApplyMultiplePatchesA) { + win_skip("MsiApplyMultiplePatchesA not found\n"); + return; + } + + r = pMsiApplyMultiplePatchesA(NULL, NULL, NULL); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r); + + r = pMsiApplyMultiplePatchesA("", NULL, NULL); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r); + + r = pMsiApplyMultiplePatchesA(";", NULL, NULL); + todo_wine + { + if (type == DRIVE_FIXED) + ok(r == ERROR_PATH_NOT_FOUND, + "Expected ERROR_PATH_NOT_FOUND, got %u\n", r); + else + ok(r == ERROR_INVALID_NAME, + "Expected ERROR_INVALID_NAME, got %u\n", r); + } + + r = pMsiApplyMultiplePatchesA(" ;", NULL, NULL); + todo_wine + { + if (type == DRIVE_FIXED) + ok(r == ERROR_PATCH_PACKAGE_OPEN_FAILED, + "Expected ERROR_PATCH_PACKAGE_OPEN_FAILED, got %u\n", r); + else + ok(r == ERROR_INVALID_NAME, + "Expected ERROR_INVALID_NAME, got %u\n", r); + } + + r = pMsiApplyMultiplePatchesA(";;", NULL, NULL); + todo_wine + { + if (type == DRIVE_FIXED) + ok(r == ERROR_PATH_NOT_FOUND, + "Expected ERROR_PATH_NOT_FOUND, got %u\n", r); + else + ok(r == ERROR_INVALID_NAME, + "Expected ERROR_INVALID_NAME, got %u\n", r); + } + + r = pMsiApplyMultiplePatchesA("nosuchpatchpackage;", NULL, NULL); + todo_wine ok(r == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %u\n", r); + + r = pMsiApplyMultiplePatchesA(";nosuchpatchpackage", NULL, NULL); + todo_wine + { + if (type == DRIVE_FIXED) + ok(r == ERROR_PATH_NOT_FOUND, + "Expected ERROR_PATH_NOT_FOUND, got %u\n", r); + else + ok(r == ERROR_INVALID_NAME, + "Expected ERROR_INVALID_NAME, got %u\n", r); + } + + r = pMsiApplyMultiplePatchesA("nosuchpatchpackage;nosuchpatchpackage", NULL, NULL); + todo_wine ok(r == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %u\n", r); + + r = pMsiApplyMultiplePatchesA(" nosuchpatchpackage ; nosuchpatchpackage ", NULL, NULL); + todo_wine ok(r == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %u\n", r); +} + +static void test_MsiApplyPatch(void) +{ + UINT r; + + r = MsiApplyPatch(NULL, NULL, INSTALLTYPE_DEFAULT, NULL); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r); + + r = MsiApplyPatch("", NULL, INSTALLTYPE_DEFAULT, NULL); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", r); +} + START_TEST(package) { + STATEMGRSTATUS status; + BOOL ret = FALSE; + + init_functionpointers(); + GetCurrentDirectoryA(MAX_PATH, CURR_DIR); + /* Create a restore point ourselves so we circumvent the multitude of restore points + * that would have been created by all the installation and removal tests. + */ + if (pSRSetRestorePointA) + { + memset(&status, 0, sizeof(status)); + ret = notify_system_change(BEGIN_NESTED_SYSTEM_CHANGE, &status); + } + test_createpackage(); - test_getsourcepath_bad(); - test_getsourcepath(); test_doaction(); test_gettargetpath_bad(); test_settargetpath(); @@ -5522,11 +11960,29 @@ START_TEST(package) test_getproperty(); test_removefiles(); test_appsearch(); + test_appsearch_complocator(); + test_appsearch_reglocator(); + test_appsearch_inilocator(); + test_appsearch_drlocator(); test_featureparents(); test_installprops(); - test_sourcedirprop(); - test_prop_path(); test_launchconditions(); test_ccpsearch(); test_complocator(); + test_MsiGetSourcePath(); + test_shortlongsource(); + test_sourcedir(); + test_access(); + test_emptypackage(); + test_MsiGetProductProperty(); + test_MsiSetProperty(); + test_MsiApplyMultiplePatches(); + test_MsiApplyPatch(); + + if (pSRSetRestorePointA && ret) + { + ret = notify_system_change(END_NESTED_SYSTEM_CHANGE, &status); + if (ret) + remove_restore_point(status.llSequenceNumber); +} } diff --git a/rostests/winetests/msi/record.c b/rostests/winetests/msi/record.c index 471fc9ce372..e8dd6f55596 100644 --- a/rostests/winetests/msi/record.c +++ b/rostests/winetests/msi/record.c @@ -24,6 +24,8 @@ #include "wine/test.h" +static const char *msifile = "winetest.msi"; + static BOOL create_temp_file(char *name) { UINT r; @@ -120,15 +122,45 @@ static void test_msirecord(void) r = MsiRecordGetInteger(h, 0); ok(r == 1, "failed to get integer\n"); - /* same record, but add a string to it */ + /* same record, but add a null or empty string to it */ r = MsiRecordSetString(h, 0, NULL); ok(r == ERROR_SUCCESS, "Failed to set null string at 0\n"); r = MsiRecordIsNull(h, 0); ok(r == TRUE, "null string not null field\n"); + r = MsiRecordDataSize(h, 0); + ok(r == 0, "size of string record is strlen\n"); + buf[0] = 0; + sz = sizeof buf; + r = MsiRecordGetStringA(h, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(buf[0] == 0, "MsiRecordGetStringA returned the wrong string\n"); + ok(sz == 0, "MsiRecordGetStringA returned the wrong length\n"); + bufW[0] = 0; + sz = sizeof bufW / sizeof bufW[0]; + r = MsiRecordGetStringW(h, 0, bufW, &sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(bufW[0] == 0, "MsiRecordGetStringW returned the wrong string\n"); + ok(sz == 0, "MsiRecordGetStringW returned the wrong length\n"); r = MsiRecordSetString(h, 0, ""); ok(r == ERROR_SUCCESS, "Failed to set empty string at 0\n"); r = MsiRecordIsNull(h, 0); ok(r == TRUE, "null string not null field\n"); + r = MsiRecordDataSize(h, 0); + ok(r == 0, "size of string record is strlen\n"); + buf[0] = 0; + sz = sizeof buf; + r = MsiRecordGetStringA(h, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(buf[0] == 0, "MsiRecordGetStringA returned the wrong string\n"); + ok(sz == 0, "MsiRecordGetStringA returned the wrong length\n"); + bufW[0] = 0; + sz = sizeof bufW / sizeof bufW[0]; + r = MsiRecordGetStringW(h, 0, bufW, &sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(bufW[0] == 0, "MsiRecordGetStringW returned the wrong string\n"); + ok(sz == 0, "MsiRecordGetStringW returned the wrong length\n"); + + /* same record, but add a string to it */ r = MsiRecordSetString(h,0,str); ok(r == ERROR_SUCCESS, "Failed to set string at 0\n"); r = MsiRecordGetInteger(h, 0); @@ -361,6 +393,11 @@ static void test_MsiRecordGetString(void) rec = MsiCreateRecord(2); ok(rec != 0, "Expected a valid handle\n"); + sz = MAX_PATH; + r = MsiRecordGetString(rec, 1, NULL, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n",r); + ok(sz == 0, "Expected 0, got %d\n",sz); + sz = MAX_PATH; lstrcpyA(buf, "apple"); r = MsiRecordGetString(rec, 1, buf, &sz); @@ -376,10 +413,205 @@ static void test_MsiRecordGetString(void) ok(sz == 0, "Expected 0, got %d\n", sz); MsiCloseHandle(rec); + + rec = MsiCreateRecord(1); + ok(rec != 0, "Expected a valid handle\n"); + + r = MsiRecordSetInteger(rec, 1, 5); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + r = MsiRecordGetString(rec, 1, NULL, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n",r); + ok(sz == 1, "Expected 1, got %d\n",sz); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "5"), "Expected \"5\", got \"%s\"\n", buf); + ok(sz == 1, "Expectd 1, got %d\n", sz); + + r = MsiRecordSetInteger(rec, 1, -5); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "-5"), "Expected \"-5\", got \"%s\"\n", buf); + ok(sz == 2, "Expectd 2, got %d\n", sz); + + MsiCloseHandle(rec); +} + +static void test_MsiRecordGetInteger(void) +{ + MSIHANDLE rec; + INT val; + UINT r; + + rec = MsiCreateRecord(1); + ok(rec != 0, "Expected a valid handle\n"); + + r = MsiRecordSetString(rec, 1, "5"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + val = MsiRecordGetInteger(rec, 1); + ok(val == 5, "Expected 5, got %d\n", val); + + r = MsiRecordSetString(rec, 1, "-5"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + val = MsiRecordGetInteger(rec, 1); + ok(val == -5, "Expected -5, got %d\n", val); + + r = MsiRecordSetString(rec, 1, "5apple"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + val = MsiRecordGetInteger(rec, 1); + ok(val == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", val); + + MsiCloseHandle(rec); +} + +static void test_fieldzero(void) +{ + MSIHANDLE hdb, hview, rec; + CHAR buf[MAX_PATH]; + LPCSTR query; + DWORD sz; + UINT r; + + rec = MsiCreateRecord(1); + ok(rec != 0, "Expected a valid handle\n"); + + r = MsiRecordGetInteger(rec, 0); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expectd 0, got %d\n", sz); + + r = MsiRecordIsNull(rec, 0); + ok(r == TRUE, "Expected TRUE, got %d\n", r); + + r = MsiRecordGetInteger(rec, 1); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + r = MsiRecordSetInteger(rec, 1, 42); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 0); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expectd 0, got %d\n", sz); + + r = MsiRecordIsNull(rec, 0); + ok(r == TRUE, "Expected TRUE, got %d\n", r); + + r = MsiRecordGetInteger(rec, 1); + ok(r == 42, "Expected 42, got %d\n", r); + + r = MsiRecordSetString(rec, 1, "bologna"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 0); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expectd 0, got %d\n", sz); + + r = MsiRecordIsNull(rec, 0); + ok(r == TRUE, "Expected TRUE, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "bologna"), "Expected \"bologna\", got \"%s\"\n", buf); + ok(sz == 7, "Expectd 7, got %d\n", sz); + + MsiCloseHandle(rec); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + query = "CREATE TABLE `drone` ( " + "`id` INT, `name` CHAR(32), `number` CHAR(32) " + "PRIMARY KEY `id`)"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + query = "INSERT INTO `drone` ( `id`, `name`, `number` )" + "VALUES('1', 'Abe', '8675309')"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = MsiDatabaseGetPrimaryKeysA(hdb, "drone", &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 0); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "drone"), "Expected \"drone\", got \"%s\"\n", buf); + ok(sz == 5, "Expectd 5, got %d\n", sz); + + r = MsiRecordIsNull(rec, 0); + ok(r == FALSE, "Expected FALSE, got %d\n", r); + + MsiCloseHandle(rec); + + query = "SELECT * FROM `drone` WHERE `id` = 1"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewFetch(hview, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 0); + ok(r != MSI_NULL_INTEGER && r != 0, "Expected non-NULL value, got %d\n", r); + + r = MsiRecordIsNull(rec, 0); + ok(r == FALSE, "Expected FALSE, got %d\n", r); + + MsiCloseHandle(hdb); + DeleteFileA(msifile); } START_TEST(record) { test_msirecord(); test_MsiRecordGetString(); + test_MsiRecordGetInteger(); + test_fieldzero(); } diff --git a/rostests/winetests/msi/source.c b/rostests/winetests/msi/source.c index 148ea40382c..0bfe8896885 100644 --- a/rostests/winetests/msi/source.c +++ b/rostests/winetests/msi/source.c @@ -27,10 +27,12 @@ #include #include #include +#include #include "wine/test.h" static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*); +static BOOLEAN (WINAPI *pGetUserNameExA)(EXTENDED_NAME_FORMAT, LPSTR, PULONG); static UINT (WINAPI *pMsiSourceListAddMediaDiskA) (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPCSTR, LPCSTR); static UINT (WINAPI *pMsiSourceListAddSourceExA) @@ -51,6 +53,7 @@ static void init_functionpointers(void) { HMODULE hmsi = GetModuleHandleA("msi.dll"); HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); + HMODULE hsecur32 = LoadLibraryA("secur32.dll"); #define GET_PROC(dll, func) \ p ## func = (void *)GetProcAddress(dll, #func); \ @@ -67,6 +70,8 @@ static void init_functionpointers(void) GET_PROC(hadvapi32, ConvertSidToStringSidA) + GET_PROC(hsecur32, GetUserNameExA) + #undef GET_PROC } @@ -114,7 +119,7 @@ static void create_test_guid(LPSTR prodcode, LPSTR squashed) hr = CoCreateGuid(&guid); ok(hr == S_OK, "Expected S_OK, got %d\n", hr); - size = StringFromGUID2(&guid, (LPOLESTR)guidW, MAX_PATH); + size = StringFromGUID2(&guid, guidW, MAX_PATH); ok(size == 39, "Expected 39, got %d\n", hr); WideCharToMultiByte(CP_ACP, 0, guidW, size, prodcode, MAX_PATH, NULL, NULL); @@ -130,13 +135,16 @@ static int get_user_sid(LPSTR *usersid) PTOKEN_USER user; BOOL rc; + if (!pConvertSidToStringSidA) + return 0; rc=OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token); if (!rc && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) return 0; size = sizeof(buf); - GetTokenInformation(token, TokenUser, (void *)buf, size, &size); + GetTokenInformation(token, TokenUser, buf, size, &size); user = (PTOKEN_USER)buf; pConvertSidToStringSidA(user->User.Sid, usersid); + CloseHandle(token); return 1; } @@ -185,7 +193,7 @@ static void test_MsiSourceListGetInfo(void) if (!pMsiSourceListGetInfoA) { - skip("Skipping MsiSourceListGetInfoA tests\n"); + win_skip("Skipping MsiSourceListGetInfoA tests\n"); return; } @@ -275,7 +283,8 @@ static void test_MsiSourceListGetInfo(void) size = MAX_PATH; r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(r == ERROR_UNKNOWN_PRODUCT || r == ERROR_INVALID_PARAMETER, + "Expected ERROR_UNKNOWN_PRODUCT or ERROR_INVALID_PARAMETER, got %d\n", r); lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); lstrcatA(keypath, prod_squashed); @@ -285,19 +294,23 @@ static void test_MsiSourceListGetInfo(void) /* user product key exists */ size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); res = RegCreateKeyA(userkey, "SourceList", &hkey); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); /* SourceList key exists */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(size == 0, "Expected 0, got %d\n", size); + ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value); data = "msitest.msi"; res = RegSetValueExA(hkey, "PackageName", 0, REG_SZ, (const BYTE *)data, lstrlenA(data) + 1); @@ -307,10 +320,12 @@ static void test_MsiSourceListGetInfo(void) size = 0xdeadbeef; r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(size == 11, "Expected 11, got %d\n", size); + ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER, + "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r); + ok(size == 11 || r != ERROR_SUCCESS, "Expected 11, got %d\n", size); /* read the value, don't change size */ + size = 11; lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); @@ -327,34 +342,40 @@ static void test_MsiSourceListGetInfo(void) ok(size == 11, "Expected 11, got %d\n", size); /* empty property now that product key exists */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, "", NULL, &size); + MSICODE_PRODUCT, "", value, &size); ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); /* nonexistent property now that product key exists */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, "nonexistent", NULL, &size); + MSICODE_PRODUCT, "nonexistent", value, &size); ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); data = "tester"; res = RegSetValueExA(hkey, "nonexistent", 0, REG_SZ, (const BYTE *)data, lstrlenA(data) + 1); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); /* nonexistent property now that nonexistent value exists */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, "nonexistent", NULL, &size); + MSICODE_PRODUCT, "nonexistent", value, &size); ok(r == ERROR_UNKNOWN_PROPERTY, "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); /* invalid option now that product key exists */ - size = 0xdeadbeef; + size = MAX_PATH; r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - 4, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + 4, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(size == 11, "Expected 11, got %d\n", size); @@ -566,11 +587,13 @@ static void test_MsiSourceListGetInfo(void) RegCloseKey(userkey); /* try a patch */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Patches\\"); lstrcatA(keypath, prod_squashed); @@ -581,26 +604,31 @@ static void test_MsiSourceListGetInfo(void) /* patch key exists * NOTE: using prodcode guid, but it really doesn't matter */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); - ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + ok(size == MAX_PATH, "Expected %d, got %d\n", MAX_PATH, size); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got \"%s\"\n", value); res = RegCreateKeyA(userkey, "SourceList", &hkey); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); /* SourceList key exists */ - size = 0xdeadbeef; + size = MAX_PATH; + lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PATCH, INSTALLPROPERTY_PACKAGENAME, value, &size); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value); ok(size == 0, "Expected 0, got %d\n", size); RegDeleteKeyA(hkey, ""); RegDeleteKeyA(userkey, ""); RegCloseKey(hkey); RegCloseKey(userkey); + LocalFree(usersid); } static void test_MsiSourceListAddSourceEx(void) @@ -618,7 +646,7 @@ static void test_MsiSourceListAddSourceEx(void) if (!pMsiSourceListAddSourceExA) { - skip("Skipping MsiSourceListAddSourceExA tests\n"); + win_skip("Skipping MsiSourceListAddSourceExA tests\n"); return; } @@ -991,7 +1019,7 @@ static void test_MsiSourceListEnumSources(void) if (!pMsiSourceListEnumSourcesA) { - skip("MsiSourceListEnumSourcesA is not available\n"); + win_skip("MsiSourceListEnumSourcesA is not available\n"); return; } @@ -1578,6 +1606,7 @@ static void test_MsiSourceListEnumSources(void) RegCloseKey(source); RegDeleteKeyA(prodkey, ""); RegCloseKey(prodkey); + LocalFree(usersid); } static void test_MsiSourceListSetInfo(void) @@ -1593,7 +1622,7 @@ static void test_MsiSourceListSetInfo(void) if (!pMsiSourceListSetInfoA) { - skip("MsiSourceListSetInfoA is not available\n"); + win_skip("MsiSourceListSetInfoA is not available\n"); return; } @@ -1988,6 +2017,7 @@ static void test_MsiSourceListSetInfo(void) RegCloseKey(source); RegDeleteKeyA(prodkey, ""); RegCloseKey(prodkey); + LocalFree(usersid); } static void test_MsiSourceListAddMediaDisk(void) @@ -2003,7 +2033,7 @@ static void test_MsiSourceListAddMediaDisk(void) if (!pMsiSourceListAddMediaDiskA) { - skip("MsiSourceListAddMediaDiskA is not available\n"); + win_skip("MsiSourceListAddMediaDiskA is not available\n"); return; } @@ -2285,6 +2315,7 @@ static void test_MsiSourceListAddMediaDisk(void) RegCloseKey(source); RegDeleteKeyA(prodkey, ""); RegCloseKey(prodkey); + LocalFree(usersid); } static void test_MsiSourceListEnumMediaDisks(void) @@ -2305,7 +2336,7 @@ static void test_MsiSourceListEnumMediaDisks(void) if (!pMsiSourceListEnumMediaDisksA) { - skip("MsiSourceListEnumMediaDisksA is not available\n"); + win_skip("MsiSourceListEnumMediaDisksA is not available\n"); return; } @@ -2480,10 +2511,14 @@ static void test_MsiSourceListEnumMediaDisks(void) r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 1, &id, NULL, &labelsz, NULL, &promptsz); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER, + "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r); + if (r == ERROR_SUCCESS) + { ok(id == 2, "Expected 2, got %d\n", id); ok(labelsz == 3, "Expected 3, got %d\n", labelsz); ok(promptsz == 3, "Expected 3, got %d\n", promptsz); + } /* now fill in the values */ id = 0xbeef; @@ -2494,13 +2529,24 @@ static void test_MsiSourceListEnumMediaDisks(void) r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 1, &id, label, &labelsz, prompt, &promptsz); - ok(r == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER, + "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r); + if (r == ERROR_SUCCESS) + { + ok(id == 2, "Expected 2, got %d\n", id); + ok(!lstrcmpA(label, "one"), "Expected \"one\", got \"%s\"\n", label); + ok(labelsz == 3, "Expected 3, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "two"), "Expected \"two\", got \"%s\"\n", prompt); + ok(promptsz == 3, "Expected 3, got %d\n", promptsz); + } + else if (r == ERROR_INVALID_PARAMETER) + { ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz); ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz); + } res = RegSetValueExA(media, "4", 0, REG_SZ, (LPBYTE)"three;four", 11); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); @@ -2672,11 +2718,15 @@ static void test_MsiSourceListEnumMediaDisks(void) r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, NULL, &labelsz, prompt, &promptsz); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER, + "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r); + if (r == ERROR_SUCCESS) + { ok(id == 1, "Expected 1, got %d\n", id); ok(labelsz == 5, "Expected 5, got %d\n", labelsz); ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + } /* szVolumeLabel and pcchVolumeLabel are NULL */ id = 0; @@ -2698,11 +2748,15 @@ static void test_MsiSourceListEnumMediaDisks(void) r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, label, NULL, prompt, &promptsz); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER, + "Expected ERROR_SUCCESS or ERROR_INVALID_PARAMETER, got %d\n", r); + if (r == ERROR_SUCCESS) + { ok(id == 1, "Expected 1, got %d\n", id); ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + } /* szDiskPrompt is NULL */ id = 0; @@ -2712,11 +2766,14 @@ static void test_MsiSourceListEnumMediaDisks(void) r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, label, &labelsz, NULL, &promptsz); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(r == ERROR_SUCCESS || r == ERROR_INVALID_PARAMETER, "Expected ERROR_SUCCESS, got %d\n", r); + if (r == ERROR_SUCCESS) + { ok(id == 1, "Expected 1, got %d\n", id); ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); ok(labelsz == 5, "Expected 5, got %d\n", labelsz); ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + } /* szDiskPrompt and pcchDiskPrompt are NULL */ id = 0; @@ -2864,13 +2921,10 @@ static void test_MsiSourceListEnumMediaDisks(void) prompt, &promptsz); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(id == 1, "Expected 1, got %d\n", id); - todo_wine - { ok(!lstrcmpA(label, "#42"), "Expected \"#42\", got \"%s\"\n", label); ok(labelsz == 3, "Expected 3, got %d\n", labelsz); ok(!lstrcmpA(prompt, "#42"), "Expected \"#42\", got \"%s\"\n", prompt); ok(promptsz == 3, "Expected 3, got %d\n", promptsz); - } RegDeleteValueA(media, "1"); RegDeleteValueA(media, "2"); @@ -3064,6 +3118,7 @@ static void test_MsiSourceListEnumMediaDisks(void) RegCloseKey(source); RegDeleteKeyA(prodkey, ""); RegCloseKey(prodkey); + LocalFree(usersid); } static void test_MsiSourceListAddSource(void) @@ -3081,7 +3136,7 @@ static void test_MsiSourceListAddSource(void) if (!pMsiSourceListAddSourceA) { - skip("Skipping MsiSourceListAddSourceA tests\n"); + win_skip("Skipping MsiSourceListAddSourceA tests\n"); return; } @@ -3094,11 +3149,17 @@ static void test_MsiSourceListAddSource(void) /* MACHINENAME\username */ size = MAX_PATH; + if (pGetUserNameExA != NULL) + pGetUserNameExA(NameSamCompatible, username, &size); + else + { GetComputerNameA(username, &size); lstrcatA(username, "\\"); ptr = username + lstrlenA(username); - size = MAX_PATH; + size = MAX_PATH - (ptr - username); GetUserNameA(ptr, &size); + } + trace("username: %s\n", username); /* GetLastError is not set by the function */ @@ -3313,6 +3374,7 @@ static void test_MsiSourceListAddSource(void) RegCloseKey(source); RegDeleteKeyA(prodkey, ""); RegCloseKey(prodkey); + LocalFree(usersid); } START_TEST(source) diff --git a/rostests/winetests/msi/suminfo.c b/rostests/winetests/msi/suminfo.c index 3afd0d50d24..f0e7fddc8d2 100644 --- a/rostests/winetests/msi/suminfo.c +++ b/rostests/winetests/msi/suminfo.c @@ -239,6 +239,32 @@ static void test_suminfo(void) r = MsiCloseHandle(hdb); ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + /* filename, non-zero update count */ + MsiGetSummaryInformation(0, msifile, 1, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, PID_AUTHOR, VT_LPSTR, 1, &ft, "Mike"); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoPersist(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoPersist failed %u\n", r); + + r = MsiCloseHandle(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed %u\n", r); + + /* filename, zero update count */ + MsiGetSummaryInformation(0, msifile, 0, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed %u\n", r); + + r = MsiSummaryInfoSetProperty(hsuminfo, PID_AUTHOR, VT_LPSTR, 1, &ft, "Mike"); + todo_wine ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty wrong error, %u\n", r); + + r = MsiSummaryInfoPersist(hsuminfo); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoPersist wrong error %u\n", r); + + r = MsiCloseHandle(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + r = DeleteFile(msifile); ok(r, "DeleteFile failed\n"); } @@ -409,6 +435,12 @@ static void test_summary_binary(void) ok(r == ERROR_SUCCESS, "getpropcount failed\n"); todo_wine ok(count == 10, "prop count incorrect\n"); + r = MsiSummaryInfoSetProperty( hsuminfo, PID_TITLE, VT_LPSTR, 0, NULL, "Mike" ); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty failed %u\n", r); + + r = MsiSummaryInfoPersist( hsuminfo ); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoPersist failed %u\n", r); + MsiCloseHandle( hsuminfo ); MsiCloseHandle( hdb ); diff --git a/rostests/winetests/mstask/mstask.rbuild b/rostests/winetests/mstask/mstask.rbuild new file mode 100644 index 00000000000..9085f9ca1ce --- /dev/null +++ b/rostests/winetests/mstask/mstask.rbuild @@ -0,0 +1,15 @@ + + + + + . + + task.c + task_scheduler.c + task_trigger.c + testlist.c + wine + ole32 + ntdll + + diff --git a/rostests/winetests/mstask/task.c b/rostests/winetests/mstask/task.c new file mode 100644 index 00000000000..328dd76958a --- /dev/null +++ b/rostests/winetests/mstask/task.c @@ -0,0 +1,533 @@ +/* + * Test suite for Task interface + * + * Copyright (C) 2008 Google (Roy Shea) + * + * 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 + */ + +#define COBJMACROS + +#include "corerror.h" +#include "mstask.h" +#include "wine/test.h" + +static ITaskScheduler *test_task_scheduler; +static ITask *test_task; +static const WCHAR empty[] = {0}; + +/* allocate some tmp string space */ +/* FIXME: this is not 100% thread-safe */ +static char *get_tmp_space(int size) +{ + static char *list[16]; + static long pos; + char *ret; + int idx; + + idx = ++pos % (sizeof(list)/sizeof(list[0])); + if ((ret = realloc(list[idx], size))) + list[idx] = ret; + return ret; +} + +static const char *dbgstr_w(LPCWSTR str) +{ + char *buf; + int len; + if(!str) + return "(null)"; + len = lstrlenW(str) + 1; + buf = get_tmp_space(len); + WideCharToMultiByte(CP_ACP, 0, str, -1, buf, len, NULL, NULL); + return buf; +} + +static BOOL setup_task(void) +{ + HRESULT hres; + const WCHAR task_name[] = {'T','e','s','t','i','n','g', 0}; + + hres = CoCreateInstance(&CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, + &IID_ITaskScheduler, (void **) &test_task_scheduler); + if(hres != S_OK) + return FALSE; + hres = ITaskScheduler_NewWorkItem(test_task_scheduler, task_name, &CLSID_CTask, + &IID_ITask, (IUnknown**)&test_task); + if(hres != S_OK) + { + ITaskScheduler_Release(test_task_scheduler); + return FALSE; + } + return TRUE; +} + +static void cleanup_task(void) +{ + ITask_Release(test_task); + ITaskScheduler_Release(test_task_scheduler); +} + +static LPCWSTR path_resolve_name(LPCWSTR base_name) +{ + static WCHAR buffer[MAX_PATH]; + int len; + + len = SearchPathW(NULL, base_name, NULL, 0, NULL, NULL); + if (len == 0) + return base_name; + else if (len < MAX_PATH) + { + SearchPathW(NULL, base_name, NULL, MAX_PATH, buffer, NULL); + return buffer; + } + return NULL; +} + +static void test_SetApplicationName_GetApplicationName(void) +{ + BOOL setup; + HRESULT hres; + LPWSTR stored_name; + LPCWSTR full_name; + const WCHAR non_application_name[] = {'N','o','S','u','c','h', + 'A','p','p','l','i','c','a','t','i','o','n', 0}; + const WCHAR notepad_exe[] = { + 'n','o','t','e','p','a','d','.','e','x','e', 0}; + const WCHAR notepad[] = {'n','o','t','e','p','a','d', 0}; + + setup = setup_task(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + /* Attempt getting before setting application name */ + hres = ITask_GetApplicationName(test_task, &stored_name); + ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpiW(stored_name, empty), + "Got %s, expected empty string\n", dbgstr_w(stored_name)); + CoTaskMemFree(stored_name); + } + + /* Set application name to a nonexistent application and then get + * the application name that is actually stored */ + hres = ITask_SetApplicationName(test_task, non_application_name); + ok(hres == S_OK, "Failed setting name %s: %08x\n", + dbgstr_w(non_application_name), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + full_name = path_resolve_name(non_application_name); + ok(!lstrcmpiW(stored_name, full_name), "Got %s, expected %s\n", + dbgstr_w(stored_name), dbgstr_w(full_name)); + CoTaskMemFree(stored_name); + } + + /* Set a valid application name with program type extension and then + * get the stored name */ + hres = ITask_SetApplicationName(test_task, notepad_exe); + ok(hres == S_OK, "Failed setting name %s: %08x\n", + dbgstr_w(notepad_exe), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + full_name = path_resolve_name(notepad_exe); + ok(!lstrcmpiW(stored_name, full_name), "Got %s, expected %s\n", + dbgstr_w(stored_name), dbgstr_w(full_name)); + CoTaskMemFree(stored_name); + } + + /* Set a valid application name without program type extension and + * then get the stored name */ + hres = ITask_SetApplicationName(test_task, notepad); + ok(hres == S_OK, "Failed setting name %s: %08x\n", dbgstr_w(notepad), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + full_name = path_resolve_name(notepad_exe); /* XP SP1 appends .exe */ + if (lstrcmpiW(stored_name, full_name) != 0) + { + full_name = path_resolve_name(notepad); + ok(!lstrcmpiW(stored_name, full_name), "Got %s, expected %s\n", + dbgstr_w(stored_name), dbgstr_w(full_name)); + } + CoTaskMemFree(stored_name); + } + + /* After having a valid application name set, set application the name + * to a nonexistent application and then get the name that is + * actually stored */ + hres = ITask_SetApplicationName(test_task, non_application_name); + ok(hres == S_OK, "Failed setting name %s: %08x\n", + dbgstr_w(non_application_name), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + full_name = path_resolve_name(non_application_name); + ok(!lstrcmpiW(stored_name, full_name), "Got %s, expected %s\n", + dbgstr_w(stored_name), dbgstr_w(full_name)); + CoTaskMemFree(stored_name); + } + + /* Clear application name */ + hres = ITask_SetApplicationName(test_task, empty); + ok(hres == S_OK, "Failed setting name %s: %08x\n", dbgstr_w(empty), hres); + hres = ITask_GetApplicationName(test_task, &stored_name); + ok(hres == S_OK, "GetApplicationName failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpiW(stored_name, empty), + "Got %s, expected empty string\n", dbgstr_w(stored_name)); + CoTaskMemFree(stored_name); + } + + cleanup_task(); + return; +} + +static void test_CreateTrigger(void) +{ + BOOL setup; + HRESULT hres; + WORD trigger_index; + ITaskTrigger *test_trigger; + + setup = setup_task(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + hres = ITask_CreateTrigger(test_task, &trigger_index, &test_trigger); + ok(hres == S_OK, "Failed to create trigger: 0x%08x\n", hres); + if (hres != S_OK) + { + cleanup_task(); + return; + } + + ITaskTrigger_Release(test_trigger); + cleanup_task(); + return; +} + +static void test_SetParameters_GetParameters(void) +{ + BOOL setup; + HRESULT hres; + LPWSTR parameters; + const WCHAR parameters_a[] = {'f','o','o','.','t','x','t', 0}; + const WCHAR parameters_b[] = {'f','o','o','.','t','x','t',' ', + 'b','a','r','.','t','x','t', 0}; + + setup = setup_task(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + /* Get parameters before setting them */ + hres = ITask_GetParameters(test_task, ¶meters); + ok(hres == S_OK, "GetParameters failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(parameters, empty), + "Got %s, expected empty string\n", dbgstr_w(parameters)); + CoTaskMemFree(parameters); + } + + /* Set parameters to a simple string */ + hres = ITask_SetParameters(test_task, parameters_a); + ok(hres == S_OK, "Failed setting parameters %s: %08x\n", + dbgstr_w(parameters_a), hres); + hres = ITask_GetParameters(test_task, ¶meters); + ok(hres == S_OK, "GetParameters failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(parameters, parameters_a), "Got %s, expected %s\n", + dbgstr_w(parameters), dbgstr_w(parameters_a)); + CoTaskMemFree(parameters); + } + + /* Update parameters to a different simple string */ + hres = ITask_SetParameters(test_task, parameters_b); + ok(hres == S_OK, "Failed setting parameters %s: %08x\n", + dbgstr_w(parameters_b), hres); + hres = ITask_GetParameters(test_task, ¶meters); + ok(hres == S_OK, "GetParameters failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(parameters, parameters_b), "Got %s, expected %s\n", + dbgstr_w(parameters), dbgstr_w(parameters_b)); + CoTaskMemFree(parameters); + } + + /* Clear parameters */ + hres = ITask_SetParameters(test_task, empty); + ok(hres == S_OK, "Failed setting parameters %s: %08x\n", + dbgstr_w(empty), hres); + hres = ITask_GetParameters(test_task, ¶meters); + ok(hres == S_OK, "GetParameters failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(parameters, empty), + "Got %s, expected empty string\n", dbgstr_w(parameters)); + CoTaskMemFree(parameters); + } + + cleanup_task(); + return; +} + +static void test_SetComment_GetComment(void) +{ + BOOL setup; + HRESULT hres; + LPWSTR comment; + const WCHAR comment_a[] = {'C','o','m','m','e','n','t','.', 0}; + const WCHAR comment_b[] = {'L','o','n','g','e','r',' ', + 'c','o','m','m','e','n','t','.', 0}; + + setup = setup_task(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + /* Get comment before setting it*/ + hres = ITask_GetComment(test_task, &comment); + ok(hres == S_OK, "GetComment failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(comment, empty), + "Got %s, expected empty string\n", dbgstr_w(comment)); + CoTaskMemFree(comment); + } + + /* Set comment to a simple string */ + hres = ITask_SetComment(test_task, comment_a); + ok(hres == S_OK, "Failed setting comment %s: %08x\n", + dbgstr_w(comment_a), hres); + hres = ITask_GetComment(test_task, &comment); + ok(hres == S_OK, "GetComment failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(comment, comment_a), "Got %s, expected %s\n", + dbgstr_w(comment), dbgstr_w(comment_a)); + CoTaskMemFree(comment); + } + + /* Update comment to a different simple string */ + hres = ITask_SetComment(test_task, comment_b); + ok(hres == S_OK, "Failed setting comment %s: %08x\n", + dbgstr_w(comment_b), hres); + hres = ITask_GetComment(test_task, &comment); + ok(hres == S_OK, "GetComment failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(comment, comment_b), "Got %s, expected %s\n", + dbgstr_w(comment), dbgstr_w(comment_b)); + CoTaskMemFree(comment); + } + + /* Clear comment */ + hres = ITask_SetComment(test_task, empty); + ok(hres == S_OK, "Failed setting comment %s: %08x\n", + dbgstr_w(empty), hres); + hres = ITask_GetComment(test_task, &comment); + ok(hres == S_OK, "GetComment failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(comment, empty), + "Got %s, expected empty string\n", dbgstr_w(comment)); + CoTaskMemFree(comment); + } + + cleanup_task(); + return; +} + +static void test_SetMaxRunTime_GetMaxRunTime(void) +{ + BOOL setup; + HRESULT hres; + DWORD max_run_time; + + setup = setup_task(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + /* Default time is 3 days: + * 3 days * 24 hours * 60 minutes * 60 seconds * 1000 ms = 259200000 */ + max_run_time = 0; + hres = ITask_GetMaxRunTime(test_task, &max_run_time); + ok(hres == S_OK, "Failed to get max runtime: 0x%08x\n", hres); + ok(max_run_time == 259200000, "Expected 259200000: %d\n", max_run_time); + + /* Basic set test */ + max_run_time = 0; + hres = ITask_SetMaxRunTime(test_task, 1234); + ok(hres == S_OK, "Failed to set max runtime: 0x%08x\n", hres); + hres = ITask_GetMaxRunTime(test_task, &max_run_time); + ok(hres == S_OK, "Failed to get max runtime: 0x%08x\n", hres); + ok(max_run_time == 1234, "Expected 1234: %d\n", max_run_time); + + /* Verify that time can be set to zero */ + max_run_time = 1; + hres = ITask_SetMaxRunTime(test_task, 0); + ok(hres == S_OK, "Failed to set max runtime: 0x%08x\n", hres); + hres = ITask_GetMaxRunTime(test_task, &max_run_time); + ok(hres == S_OK, "Failed to get max runtime: 0x%08x\n", hres); + ok(max_run_time == 0, "Expected 0: %d\n", max_run_time); + + /* Check resolution by setting time to one */ + max_run_time = 0; + hres = ITask_SetMaxRunTime(test_task, 1); + ok(hres == S_OK, "Failed to set max runtime: 0x%08x\n", hres); + hres = ITask_GetMaxRunTime(test_task, &max_run_time); + ok(hres == S_OK, "Failed to get max runtime: 0x%08x\n", hres); + ok(max_run_time == 1, "Expected 1: %d\n", max_run_time); + + /* Verify that time can be set to INFINITE */ + max_run_time = 0; + hres = ITask_SetMaxRunTime(test_task, INFINITE); + ok(hres == S_OK, "Failed to set max runtime: 0x%08x\n", hres); + hres = ITask_GetMaxRunTime(test_task, &max_run_time); + ok(hres == S_OK, "Failed to get max runtime: 0x%08x\n", hres); + ok(max_run_time == INFINITE, "Expected INFINITE: %d\n", max_run_time); + + cleanup_task(); + return; +} + +static void test_SetAccountInformation_GetAccountInformation(void) +{ + BOOL setup; + HRESULT hres; + LPWSTR account_name; + const WCHAR dummy_account_name[] = {'N', 'o', 'S', 'u', 'c', 'h', + 'A', 'c', 'c', 'o', 'u', 'n', 't', 0}; + const WCHAR dummy_account_name_b[] = {'N', 'o', 'S', 'u', 'c', 'h', + 'A', 'c', 'c', 'o', 'u', 'n', 't', 'B', 0}; + + setup = setup_task(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + /* Get account information before it is set */ + hres = ITask_GetAccountInformation(test_task, &account_name); + /* WinXP returns HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): 0x80070002 but + * Win2K returns SCHED_E_CANNOT_OPEN_TASK: 0x8004130d + * Win9x doesn't support security services */ + if (hres == SCHED_E_NO_SECURITY_SERVICES) + { + win_skip("Security services are not supported\n"); + cleanup_task(); + return; + } + ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hres == SCHED_E_CANNOT_OPEN_TASK, + "Unset account name generated: 0x%08x\n", hres); + + /* Attempt to set to a dummy account without a password */ + /* This test passes on WinXP but fails on Win2K */ + hres = ITask_SetAccountInformation(test_task, dummy_account_name, NULL); + ok(hres == S_OK, + "Failed setting dummy account with no password: %08x\n", hres); + hres = ITask_GetAccountInformation(test_task, &account_name); + ok(hres == S_OK || + broken(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hres == SCHED_E_CANNOT_OPEN_TASK), + "GetAccountInformation failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(account_name, dummy_account_name), + "Got %s, expected %s\n", dbgstr_w(account_name), + dbgstr_w(dummy_account_name)); + CoTaskMemFree(account_name); + } + + /* Attempt to set to a dummy account with a (invalid) password */ + /* This test passes on WinXP but fails on Win2K */ + hres = ITask_SetAccountInformation(test_task, dummy_account_name_b, + dummy_account_name_b); + ok(hres == S_OK, + "Failed setting dummy account with password: %08x\n", hres); + hres = ITask_GetAccountInformation(test_task, &account_name); + ok(hres == S_OK || + broken(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hres == SCHED_E_CANNOT_OPEN_TASK), + "GetAccountInformation failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(account_name, dummy_account_name_b), + "Got %s, expected %s\n", dbgstr_w(account_name), + dbgstr_w(dummy_account_name_b)); + CoTaskMemFree(account_name); + } + + /* Attempt to set to the local system account */ + hres = ITask_SetAccountInformation(test_task, empty, NULL); + ok(hres == S_OK, "Failed setting system account: %08x\n", hres); + hres = ITask_GetAccountInformation(test_task, &account_name); + ok(hres == S_OK || + broken(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hres == SCHED_E_CANNOT_OPEN_TASK), + "GetAccountInformation failed: %08x\n", hres); + if (hres == S_OK) + { + ok(!lstrcmpW(account_name, empty), + "Got %s, expected empty string\n", dbgstr_w(account_name)); + CoTaskMemFree(account_name); + } + + cleanup_task(); + return; +} + +START_TEST(task) +{ + CoInitialize(NULL); + test_SetApplicationName_GetApplicationName(); + test_CreateTrigger(); + test_SetParameters_GetParameters(); + test_SetComment_GetComment(); + test_SetMaxRunTime_GetMaxRunTime(); + test_SetAccountInformation_GetAccountInformation(); + CoUninitialize(); +} diff --git a/rostests/winetests/mstask/task_scheduler.c b/rostests/winetests/mstask/task_scheduler.c new file mode 100644 index 00000000000..2de0e160496 --- /dev/null +++ b/rostests/winetests/mstask/task_scheduler.c @@ -0,0 +1,111 @@ +/* + * Test suite for TaskScheduler interface + * + * Copyright (C) 2008 Google (Roy Shea) + * + * 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 + */ + +#define COBJMACROS + +#include "corerror.h" + +#include "initguid.h" +#include "mstask.h" +#include "wine/test.h" + +static ITaskScheduler *test_task_scheduler; + +static void test_NewWorkItem(void) +{ + HRESULT hres; + ITask *task; + const WCHAR task_name[] = {'T', 'e', 's', 't', 'i', 'n', 'g', 0}; + GUID GUID_BAD; + + /* Initialize a GUID that will not be a recognized CLSID or a IID */ + CoCreateGuid(&GUID_BAD); + + /* Create TaskScheduler */ + hres = CoCreateInstance(&CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, + &IID_ITaskScheduler, (void **) &test_task_scheduler); + ok(hres == S_OK, "CTaskScheduler CoCreateInstance failed: %08x\n", hres); + if (hres != S_OK) + { + skip("Failed to create task scheduler. Skipping tests.\n"); + return; + } + + /* Test basic task creation */ + hres = ITaskScheduler_NewWorkItem(test_task_scheduler, task_name, + &CLSID_CTask, &IID_ITask, (IUnknown**)&task); + ok(hres == S_OK, "NewNetworkItem failed: %08x\n", hres); + if (hres == S_OK) + ITask_Release(task); + + /* Task creation attempt using invalid work item class ID */ + hres = ITaskScheduler_NewWorkItem(test_task_scheduler, task_name, + &GUID_BAD, &IID_ITask, (IUnknown**)&task); + ok(hres == CLASS_E_CLASSNOTAVAILABLE, + "Expected CLASS_E_CLASSNOTAVAILABLE: %08x\n", hres); + + /* Task creation attempt using invalid interface ID */ + hres = ITaskScheduler_NewWorkItem(test_task_scheduler, task_name, + &CLSID_CTask, &GUID_BAD, (IUnknown**)&task); + ok(hres == E_NOINTERFACE, "Expected E_NOINTERFACE: %08x\n", hres); + + /* Task creation attempt using invalid work item class and interface ID */ + hres = ITaskScheduler_NewWorkItem(test_task_scheduler, task_name, + &GUID_BAD, &GUID_BAD, (IUnknown**)&task); + ok(hres == CLASS_E_CLASSNOTAVAILABLE, + "Expected CLASS_E_CLASSNOTAVAILABLE: %08x\n", hres); + + ITaskScheduler_Release(test_task_scheduler); + return; +} + +static void test_Activate(void) +{ + HRESULT hres; + ITask *task = NULL; + const WCHAR not_task_name[] = + {'N', 'o', 'S', 'u', 'c', 'h', 'T', 'a', 's', 'k', 0}; + + /* Create TaskScheduler */ + hres = CoCreateInstance(&CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, + &IID_ITaskScheduler, (void **) &test_task_scheduler); + ok(hres == S_OK, "CTaskScheduler CoCreateInstance failed: %08x\n", hres); + if (hres != S_OK) + { + skip("Failed to create task scheduler. Skipping tests.\n"); + return; + } + + /* Attempt to activate a nonexistent task */ + hres = ITaskScheduler_Activate(test_task_scheduler, not_task_name, + &IID_ITask, (IUnknown**)&task); + ok(hres == COR_E_FILENOTFOUND, "Expected COR_E_FILENOTFOUND: %08x\n", hres); + + ITaskScheduler_Release(test_task_scheduler); + return; +} + +START_TEST(task_scheduler) +{ + CoInitialize(NULL); + test_NewWorkItem(); + test_Activate(); + CoUninitialize(); +} diff --git a/rostests/winetests/mstask/task_trigger.c b/rostests/winetests/mstask/task_trigger.c new file mode 100644 index 00000000000..7f1c57799be --- /dev/null +++ b/rostests/winetests/mstask/task_trigger.c @@ -0,0 +1,380 @@ +/* + * Test suite for Task interface + * + * Copyright (C) 2008 Google (Roy Shea) + * + * 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 + */ + +#define COBJMACROS + +#include + +#include "mstask.h" +#include "wine/test.h" + +static ITaskScheduler *test_task_scheduler; +static ITask *test_task; +static ITaskTrigger *test_trigger; +static WORD trigger_index; + +static BOOL setup_trigger(void) +{ + HRESULT hres; + const WCHAR task_name[] = {'T','e','s','t','i','n','g', 0}; + + hres = CoCreateInstance(&CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, + &IID_ITaskScheduler, (void **) &test_task_scheduler); + if(hres != S_OK) + return FALSE; + hres = ITaskScheduler_NewWorkItem(test_task_scheduler, task_name, + &CLSID_CTask, &IID_ITask, (IUnknown**)&test_task); + if(hres != S_OK) + { + ITaskScheduler_Release(test_task_scheduler); + return FALSE; + } + hres = ITask_CreateTrigger(test_task, &trigger_index, &test_trigger); + if(hres != S_OK) + { + ITask_Release(test_task); + ITaskScheduler_Release(test_task_scheduler); + return FALSE; + } + return TRUE; +} + +static void cleanup_trigger(void) +{ + ITaskTrigger_Release(test_trigger); + ITask_Release(test_task); + ITaskScheduler_Release(test_task_scheduler); +} + +static BOOL compare_trigger_state(TASK_TRIGGER found_state, + TASK_TRIGGER expected_state) +{ + ok(found_state.cbTriggerSize == expected_state.cbTriggerSize, + "cbTriggerSize: Found %d but expected %d\n", + found_state.cbTriggerSize, expected_state.cbTriggerSize); + + ok(found_state.Reserved1 == expected_state.Reserved1, + "Reserved1: Found %d but expected %d\n", + found_state.Reserved1, expected_state.Reserved1); + + ok(found_state.wBeginYear == expected_state.wBeginYear, + "wBeginYear: Found %d but expected %d\n", + found_state.wBeginYear, expected_state.wBeginYear); + + ok(found_state.wBeginMonth == expected_state.wBeginMonth, + "wBeginMonth: Found %d but expected %d\n", + found_state.wBeginMonth, expected_state.wBeginMonth); + + ok(found_state.wBeginDay == expected_state.wBeginDay, + "wBeginDay: Found %d but expected %d\n", + found_state.wBeginDay, expected_state.wBeginDay); + + ok(found_state.wEndYear == expected_state.wEndYear, + "wEndYear: Found %d but expected %d\n", + found_state.wEndYear, expected_state.wEndYear); + + ok(found_state.wEndMonth == expected_state.wEndMonth, + "wEndMonth: Found %d but expected %d\n", + found_state.wEndMonth, expected_state.wEndMonth); + + ok(found_state.wEndDay == expected_state.wEndDay, + "wEndDay: Found %d but expected %d\n", + found_state.wEndDay, expected_state.wEndDay); + + ok(found_state.wStartHour == expected_state.wStartHour, + "wStartHour: Found %d but expected %d\n", + found_state.wStartHour, expected_state.wStartHour); + + ok(found_state.wStartMinute == expected_state.wStartMinute, + "wStartMinute: Found %d but expected %d\n", + found_state.wStartMinute, expected_state.wStartMinute); + + ok(found_state.MinutesDuration == expected_state.MinutesDuration, + "MinutesDuration: Found %d but expected %d\n", + found_state.MinutesDuration, expected_state.MinutesDuration); + + ok(found_state.MinutesInterval == expected_state.MinutesInterval, + "MinutesInterval: Found %d but expected %d\n", + found_state.MinutesInterval, expected_state.MinutesInterval); + + ok(found_state.rgFlags == expected_state.rgFlags, + "rgFlags: Found %d but expected %d\n", + found_state.rgFlags, expected_state.rgFlags); + + ok(found_state.TriggerType == expected_state.TriggerType, + "TriggerType: Found %d but expected %d\n", + found_state.TriggerType, expected_state.TriggerType); + + ok(found_state.Type.Daily.DaysInterval == expected_state.Type.Daily.DaysInterval, + "Type.Daily.DaysInterval: Found %d but expected %d\n", + found_state.Type.Daily.DaysInterval, expected_state.Type.Daily.DaysInterval); + + ok(found_state.Reserved2 == expected_state.Reserved2, + "Reserved2: Found %d but expected %d\n", + found_state.Reserved2, expected_state.Reserved2); + + ok(found_state.wRandomMinutesInterval == expected_state.wRandomMinutesInterval, + "wRandomMinutesInterval: Found %d but expected %d\n", + found_state.wRandomMinutesInterval, expected_state.wRandomMinutesInterval); + + return TRUE; +} + +static void test_SetTrigger_GetTrigger(void) +{ + BOOL setup; + HRESULT hres; + TASK_TRIGGER trigger_state; + TASK_TRIGGER empty_trigger_state = { + sizeof(trigger_state), 0, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, + TASK_TRIGGER_FLAG_DISABLED, TASK_TIME_TRIGGER_DAILY, {{1}}, + 0, 0 + }; + TASK_TRIGGER normal_trigger_state = { + sizeof(trigger_state), 0, + 1980, 1, 1, + 2980, 2, 2, + 3, 3, + 0, 0, + TASK_TRIGGER_FLAG_DISABLED, TASK_TIME_TRIGGER_DAILY, {{1}}, + 0, 0 + }; + SYSTEMTIME time; + + setup = setup_trigger(); + ok(setup, "Failed to setup test_task\n"); + if (!setup) + { + skip("Failed to create task. Skipping tests.\n"); + return; + } + + /* Setup a trigger with base values for this test run */ + GetLocalTime(&time); + empty_trigger_state.wStartHour = time.wHour; + empty_trigger_state.wStartMinute = time.wMinute; + empty_trigger_state.wBeginYear = time.wYear; + empty_trigger_state.wBeginMonth = time.wMonth; + empty_trigger_state.wBeginDay = time.wDay; + + /* Test trigger state after trigger creation but before setting * state */ + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = sizeof(trigger_state); + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + compare_trigger_state(trigger_state, empty_trigger_state); + + /* Test setting basic empty trigger */ + hres = ITaskTrigger_SetTrigger(test_trigger, &empty_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = sizeof(trigger_state); + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(hres == S_OK, "Failed to GetTrigger\n"); + compare_trigger_state(trigger_state, empty_trigger_state); + + /* Test setting basic non-empty trigger */ + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = sizeof(trigger_state); + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(hres == S_OK, "Failed to GetTrigger\n"); + compare_trigger_state(trigger_state, normal_trigger_state); + + /* The following tests modify the normal_trigger_state structure + * before each test, and return the normal_trigger_state structure + * back to its original valid state after each test. This keeps + * each test run independent. */ + + /* Test setting trigger with invalid cbTriggerSize */ + normal_trigger_state.cbTriggerSize = sizeof(trigger_state) - 1; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.cbTriggerSize = sizeof(trigger_state) + 1; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.cbTriggerSize = sizeof(trigger_state); + + /* Test setting trigger with invalid Reserved fields */ + normal_trigger_state.Reserved1 = 80; + normal_trigger_state.Reserved2 = 80; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = sizeof(trigger_state); + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(trigger_state.Reserved1 == 0 && trigger_state.Reserved2 == 0, + "Reserved fields should be set to zero\n"); + normal_trigger_state.Reserved1 = 0; + normal_trigger_state.Reserved2 = 0; + + /* Test setting trigger with invalid month */ + normal_trigger_state.wBeginMonth = 0; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.wBeginMonth = 13; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.wBeginMonth = 1; + + /* Test setting trigger with invalid begin date */ + normal_trigger_state.wBeginDay = 0; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.wBeginDay = 32; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.wBeginMonth = 2; + normal_trigger_state.wBeginDay = 30; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.wBeginMonth = 1; + normal_trigger_state.wBeginDay = 1; + + /* Test setting trigger invalid end date */ + normal_trigger_state.wEndYear = 0; + normal_trigger_state.wEndMonth = 200; + normal_trigger_state.wEndDay = 200; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = sizeof(trigger_state); + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(trigger_state.wEndYear == 0, "End year should be 0: %d\n", + trigger_state.wEndYear); + ok(trigger_state.wEndMonth == 200, "End month should be 200: %d\n", + trigger_state.wEndMonth); + ok(trigger_state.wEndDay == 200, "End day should be 200: %d\n", + trigger_state.wEndDay); + normal_trigger_state.rgFlags = + TASK_TRIGGER_FLAG_DISABLED | TASK_TRIGGER_FLAG_HAS_END_DATE; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.rgFlags = TASK_TRIGGER_FLAG_DISABLED; + normal_trigger_state.wEndYear = 2980; + normal_trigger_state.wEndMonth = 1; + normal_trigger_state.wEndDay = 1; + + /* Test setting trigger with invalid hour or minute*/ + normal_trigger_state.wStartHour = 24; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.wStartHour = 3; + normal_trigger_state.wStartHour = 60; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.wStartHour = 3; + + /* Test setting trigger with invalid duration / interval pairs */ + normal_trigger_state.MinutesDuration = 5; + normal_trigger_state.MinutesInterval = 5; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.MinutesDuration = 5; + normal_trigger_state.MinutesInterval = 6; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.MinutesDuration = 0; + normal_trigger_state.MinutesInterval = 6; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.MinutesDuration = 5; + normal_trigger_state.MinutesInterval = 0; + ok(hres == E_INVALIDARG, "Expected E_INVALIDARG: 0x%08x\n", hres); + normal_trigger_state.MinutesDuration = 0; + normal_trigger_state.MinutesInterval = 0; + + /* Test setting trigger with end date before start date */ + normal_trigger_state.wEndYear = 1979; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + normal_trigger_state.rgFlags = + TASK_TRIGGER_FLAG_DISABLED | TASK_TRIGGER_FLAG_HAS_END_DATE; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + normal_trigger_state.rgFlags = TASK_TRIGGER_FLAG_DISABLED; + normal_trigger_state.wEndYear = 2980; + normal_trigger_state.wEndMonth = 1; + normal_trigger_state.wEndDay = 1; + + + /* Test setting trigger with invalid TriggerType and Type */ + normal_trigger_state.TriggerType = TASK_TIME_TRIGGER_ONCE; + normal_trigger_state.Type.Weekly.WeeksInterval = 2; + normal_trigger_state.Type.Weekly.rgfDaysOfTheWeek = (TASK_MONDAY | TASK_TUESDAY); + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = sizeof(trigger_state); + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(trigger_state.Type.Weekly.WeeksInterval == 0xcfcf, + "Expected WeeksInterval set remain untouched: %d\n", + trigger_state.Type.Weekly.WeeksInterval); + ok(trigger_state.Type.Weekly.rgfDaysOfTheWeek == 0xcfcf, + "Expected WeeksInterval set remain untouched: %d\n", + trigger_state.Type.Weekly.rgfDaysOfTheWeek); + normal_trigger_state.TriggerType = TASK_TIME_TRIGGER_DAILY; + normal_trigger_state.Type.Daily.DaysInterval = 1; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + + /* Test setting trigger with set wRandomMinutesInterval */ + normal_trigger_state.wRandomMinutesInterval = 5; + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = sizeof(trigger_state); + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(trigger_state.wRandomMinutesInterval == 0, + "wRandomMinutesInterval should be set to zero\n"); + normal_trigger_state.wRandomMinutesInterval = 0; + + /* Test GetTrigger using invalid cbTriggerSiz in pTrigger. In + * contrast to available documentation, this succeeds in practice. */ + hres = ITaskTrigger_SetTrigger(test_trigger, &normal_trigger_state); + ok(hres == S_OK, "Failed to set trigger: 0x%08x\n", hres); + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = sizeof(trigger_state) - 1; + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(hres == S_OK, "Failed to GetTrigger\n"); + ok(compare_trigger_state(trigger_state, normal_trigger_state), + "Invalid state\n"); + memset(&trigger_state, 0xcf, sizeof(trigger_state)); + trigger_state.cbTriggerSize = 0; + hres = ITaskTrigger_GetTrigger(test_trigger, &trigger_state); + ok(hres == S_OK, "Failed to GetTrigger\n"); + ok(compare_trigger_state(trigger_state, normal_trigger_state), + "Invalid state\n"); + + + cleanup_trigger(); + return; +} + + +START_TEST(task_trigger) +{ + CoInitialize(NULL); + test_SetTrigger_GetTrigger(); + CoUninitialize(); +} diff --git a/rostests/winetests/mstask/testlist.c b/rostests/winetests/mstask/testlist.c new file mode 100644 index 00000000000..f27d0222901 --- /dev/null +++ b/rostests/winetests/mstask/testlist.c @@ -0,0 +1,19 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_task(void); +extern void func_task_scheduler(void); +extern void func_task_trigger(void); + +const struct test winetest_testlist[] = +{ + { "task", func_task }, + { "task_scheduler", func_task_scheduler }, + { "task_trigger", func_task_trigger }, + { 0, 0 } +}; diff --git a/rostests/winetests/msvcrt/cpp.c b/rostests/winetests/msvcrt/cpp.c index ef80cac2c4f..d640d674e3e 100644 --- a/rostests/winetests/msvcrt/cpp.c +++ b/rostests/winetests/msvcrt/cpp.c @@ -55,10 +55,10 @@ typedef struct __type_info /* Function pointers. We need to use these to call these funcs as __thiscall */ static HMODULE hMsvcrt; -static void* (*poperator_new)(unsigned int); -static void (*poperator_delete)(void*); -static void* (*pmalloc)(unsigned int); -static void (*pfree)(void*); +static void* (__cdecl *poperator_new)(unsigned int); +static void (__cdecl *poperator_delete)(void*); +static void* (__cdecl *pmalloc)(unsigned int); +static void (__cdecl *pfree)(void*); /* exception */ static void (WINAPI *pexception_ctor)(exception*,LPCSTR*); @@ -113,12 +113,12 @@ static int (WINAPI *ptype_info_opequals_equals)(type_info*,type_info*); static int (WINAPI *ptype_info_opnot_equals)(type_info*,type_info*); /* RTTI */ -static type_info* (*p__RTtypeid)(void*); -static void* (*p__RTCastToVoid)(void*); -static void* (*p__RTDynamicCast)(void*,int,void*,void*,int); +static type_info* (__cdecl *p__RTtypeid)(void*); +static void* (__cdecl *p__RTCastToVoid)(void*); +static void* (__cdecl *p__RTDynamicCast)(void*,int,void*,void*,int); /*Demangle*/ -static char* (*p__unDName)(char*,const char*,int,void*,void*,unsigned short int); +static char* (__cdecl *p__unDName)(char*,const char*,int,void*,void*,unsigned short int); /* _very_ early native versions have serious RTTI bugs, so we check */ @@ -157,20 +157,20 @@ static inline void* do_call_func2(void *func, void *_this, const void* arg) #else static void* do_call_func1(void *func, void *_this) { - void* ret; - __asm__ __volatile__ ("call *%1" - : "=a" (ret) - : "g" (func), "c" (_this) - : "memory" ); + void *ret, *dummy; + __asm__ __volatile__ ("call *%2" + : "=a" (ret), "=c" (dummy) + : "g" (func), "1" (_this) + : "edx", "memory" ); return ret; } static void* do_call_func2(void *func, void *_this, const void* arg) { - void* ret; - __asm__ __volatile__ ("pushl %2\n\tcall *%1" - : "=a" (ret) - : "r" (func), "g" (arg), "c" (_this) - : "memory" ); + void *ret, *dummy; + __asm__ __volatile__ ("pushl %3\n\tcall *%2" + : "=a" (ret), "=c" (dummy) + : "r" (func), "r" (arg), "1" (_this) + : "edx", "memory" ); return ret; } #endif @@ -301,6 +301,7 @@ static void test_exception(void) /* Operator equals */ memset(&e2, 0, sizeof(e2)); + call_func1(pexception_default_ctor, &e2); pe = call_func2(pexception_opequals, &e2, &e); ok(e2.vtable != NULL, "Null exception vtable for e2\n"); ok(e2.name && e2.name != e.name && !strcmp(e2.name, "An exception name"), "Bad exception name for e2\n"); @@ -425,6 +426,7 @@ static void test_bad_typeid(void) /* Operator equals */ memset(&e2, 1, sizeof(e2)); + call_func1(pexception_default_ctor, &e2); pe = call_func2(pbad_typeid_opequals, &e2, &e); ok(e2.vtable != NULL, "Null bad_typeid vtable for e2\n"); ok(e2.name && e2.name != e.name && !strcmp(e2.name, "A bad_typeid name"), "Bad bad_typeid name for e2\n"); @@ -552,6 +554,7 @@ static void test_bad_cast(void) /* Operator equals */ memset(&e2, 1, sizeof(e2)); + call_func1(pexception_default_ctor, &e2); pe = call_func2(pbad_cast_opequals, &e2, &e); ok(e2.vtable != NULL, "Null bad_cast vtable for e2\n"); ok(e2.name && e2.name != e.name && !strcmp(e2.name, "A bad_cast name"), "Bad bad_cast name for e2\n"); @@ -653,6 +656,7 @@ static void test___non_rtti_object(void) /* Operator equals */ memset(&e2, 1, sizeof(e2)); + call_func1(pexception_default_ctor, &e2); pe = call_func2(p__non_rtti_object_opequals, &e2, &e); ok(e2.vtable != NULL, "Null __non_rtti_object vtable for e2\n"); ok(e2.name && e2.name != e.name && !strcmp(e2.name, "A __non_rtti_object name"), "Bad __non_rtti_object name for e2\n"); @@ -813,7 +817,11 @@ static void test_rtti(void) bti = p__RTtypeid(&b); casted = p__RTDynamicCast(&b, 0, NULL, ti, 0); - ok (casted == (void*)&b, "failed cast from bad_cast to exception\n"); + if (casted) + { + /* New versions do not allow this conversion due to compiler changes */ + ok (casted == (void*)&b, "failed cast from bad_typeid to exception\n"); + } /* dynamic_cast down */ casted = p__RTDynamicCast(&e, 0, NULL, bti, 0); @@ -873,121 +881,157 @@ static int strcmp_space(const char *s1, const char *s2) static void test_demangle(void) { - static struct {const char* in; const char* out; unsigned int flags;} test[] = { -{"??0bad_alloc@std@@QAE@ABV01@@Z", "public: __thiscall std::bad_alloc::bad_alloc(class std::bad_alloc const &)"}, -{"??0bad_alloc@std@@QAE@PBD@Z", "public: __thiscall std::bad_alloc::bad_alloc(char const *)"}, -{"??0bad_cast@@AAE@PBQBD@Z", "private: __thiscall bad_cast::bad_cast(char const * const *)"}, -{"??0bad_cast@@QAE@ABQBD@Z", "public: __thiscall bad_cast::bad_cast(char const * const &)"}, -{"??0bad_cast@@QAE@ABV0@@Z", "public: __thiscall bad_cast::bad_cast(class bad_cast const &)"}, -{"??0bad_exception@std@@QAE@ABV01@@Z", "public: __thiscall std::bad_exception::bad_exception(class std::bad_exception const &)"}, -{"??0bad_exception@std@@QAE@PBD@Z", "public: __thiscall std::bad_exception::bad_exception(char const *)"}, -{"??0?$basic_filebuf@DU?$char_traits@D@std@@@std@@QAE@ABV01@@Z", "public: __thiscall std::basic_filebuf >::basic_filebuf >(class std::basic_filebuf > const &)"}, -{"??0?$basic_filebuf@DU?$char_traits@D@std@@@std@@QAE@PAU_iobuf@@@Z", "public: __thiscall std::basic_filebuf >::basic_filebuf >(struct _iobuf *)"}, -{"??0?$basic_filebuf@DU?$char_traits@D@std@@@std@@QAE@W4_Uninitialized@1@@Z", "public: __thiscall std::basic_filebuf >::basic_filebuf >(enum std::_Uninitialized)"}, -{"??0?$basic_filebuf@GU?$char_traits@G@std@@@std@@QAE@ABV01@@Z", "public: __thiscall std::basic_filebuf >::basic_filebuf >(class std::basic_filebuf > const &)"}, -{"??0?$basic_filebuf@GU?$char_traits@G@std@@@std@@QAE@PAU_iobuf@@@Z", "public: __thiscall std::basic_filebuf >::basic_filebuf >(struct _iobuf *)"}, -{"??0?$basic_filebuf@GU?$char_traits@G@std@@@std@@QAE@W4_Uninitialized@1@@Z", "public: __thiscall std::basic_filebuf >::basic_filebuf >(enum std::_Uninitialized)"}, -{"??0?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV01@@Z", "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class std::basic_stringstream,class std::allocator > const &)"}, -{"??0?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@1@H@Z", "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class std::basic_string,class std::allocator > const &,int)"}, -{"??0?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@H@Z", "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(int)"}, -{"??0?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@ABV01@@Z", "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class std::basic_stringstream,class std::allocator > const &)"}, -{"??0?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@ABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@1@H@Z", "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class std::basic_string,class std::allocator > const &,int)"}, -{"??0?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@H@Z", "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(int)"}, -{"??0?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@QAE@ABV_Locinfo@1@I@Z", "public: __thiscall std::num_get > >::num_get > >(class std::_Locinfo const &,unsigned int)"}, -{"??0?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@QAE@I@Z", "public: __thiscall std::num_get > >::num_get > >(unsigned int)"}, -{"??0?$num_get@GV?$istreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@QAE@ABV_Locinfo@1@I@Z", "public: __thiscall std::num_get > >::num_get > >(class std::_Locinfo const &,unsigned int)"}, -{"??0?$num_get@GV?$istreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@QAE@I@Z", "public: __thiscall std::num_get > >::num_get > >(unsigned int)"}, -{"??0streambuf@@QAE@ABV0@@Z", "public: __thiscall streambuf::streambuf(class streambuf const &)"}, -{"??0strstreambuf@@QAE@ABV0@@Z", "public: __thiscall strstreambuf::strstreambuf(class strstreambuf const &)"}, -{"??0strstreambuf@@QAE@H@Z", "public: __thiscall strstreambuf::strstreambuf(int)"}, -{"??0strstreambuf@@QAE@P6APAXJ@ZP6AXPAX@Z@Z", "public: __thiscall strstreambuf::strstreambuf(void * (__cdecl*)(long),void (__cdecl*)(void *))"}, -{"??0strstreambuf@@QAE@PADH0@Z", "public: __thiscall strstreambuf::strstreambuf(char *,int,char *)"}, -{"??0strstreambuf@@QAE@PAEH0@Z", "public: __thiscall strstreambuf::strstreambuf(unsigned char *,int,unsigned char *)"}, -{"??0strstreambuf@@QAE@XZ", "public: __thiscall strstreambuf::strstreambuf(void)"}, -{"??1__non_rtti_object@std@@UAE@XZ", "public: virtual __thiscall std::__non_rtti_object::~__non_rtti_object(void)"}, -{"??1__non_rtti_object@@UAE@XZ", "public: virtual __thiscall __non_rtti_object::~__non_rtti_object(void)"}, -{"??1?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@UAE@XZ", "public: virtual __thiscall std::num_get > >::~num_get > >(void)"}, -{"??1?$num_get@GV?$istreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@UAE@XZ", "public: virtual __thiscall std::num_get > >::~num_get > >(void)"}, -{"??4istream_withassign@@QAEAAV0@ABV0@@Z", "public: class istream_withassign & __thiscall istream_withassign::operator=(class istream_withassign const &)"}, -{"??4istream_withassign@@QAEAAVistream@@ABV1@@Z", "public: class istream & __thiscall istream_withassign::operator=(class istream const &)"}, -{"??4istream_withassign@@QAEAAVistream@@PAVstreambuf@@@Z", "public: class istream & __thiscall istream_withassign::operator=(class streambuf *)"}, -{"??5std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAC@Z", "class std::basic_istream > & __cdecl std::operator>>(class std::basic_istream > &,signed char &)"}, -{"??5std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAD@Z", "class std::basic_istream > & __cdecl std::operator>>(class std::basic_istream > &,char &)"}, -{"??5std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAE@Z", "class std::basic_istream > & __cdecl std::operator>>(class std::basic_istream > &,unsigned char &)"}, -{"??6?$basic_ostream@GU?$char_traits@G@std@@@std@@QAEAAV01@P6AAAVios_base@1@AAV21@@Z@Z", "public: class std::basic_ostream > & __thiscall std::basic_ostream >::operator<<(class std::ios_base & (__cdecl*)(class std::ios_base &))"}, -{"??6?$basic_ostream@GU?$char_traits@G@std@@@std@@QAEAAV01@PAV?$basic_streambuf@GU?$char_traits@G@std@@@1@@Z", "public: class std::basic_ostream > & __thiscall std::basic_ostream >::operator<<(class std::basic_streambuf > *)"}, -{"??6?$basic_ostream@GU?$char_traits@G@std@@@std@@QAEAAV01@PBX@Z", "public: class std::basic_ostream > & __thiscall std::basic_ostream >::operator<<(void const *)"}, -{"??_8?$basic_fstream@DU?$char_traits@D@std@@@std@@7B?$basic_ostream@DU?$char_traits@D@std@@@1@@", "const std::basic_fstream >::`vbtable'{for `std::basic_ostream >'}"}, -{"??_8?$basic_fstream@GU?$char_traits@G@std@@@std@@7B?$basic_istream@GU?$char_traits@G@std@@@1@@", "const std::basic_fstream >::`vbtable'{for `std::basic_istream >'}"}, -{"??_8?$basic_fstream@GU?$char_traits@G@std@@@std@@7B?$basic_ostream@GU?$char_traits@G@std@@@1@@", "const std::basic_fstream >::`vbtable'{for `std::basic_ostream >'}"}, -{"??9std@@YA_NPBDABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z", "bool __cdecl std::operator!=(char const *,class std::basic_string,class std::allocator > const &)"}, -{"??9std@@YA_NPBGABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@0@@Z", "bool __cdecl std::operator!=(unsigned short const *,class std::basic_string,class std::allocator > const &)"}, -{"??A?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAADI@Z", "public: char & __thiscall std::basic_string,class std::allocator >::operator[](unsigned int)"}, -{"??A?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEABDI@Z", "public: char const & __thiscall std::basic_string,class std::allocator >::operator[](unsigned int)const "}, -{"??A?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEAAGI@Z", "public: unsigned short & __thiscall std::basic_string,class std::allocator >::operator[](unsigned int)"}, -{"??A?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBEABGI@Z", "public: unsigned short const & __thiscall std::basic_string,class std::allocator >::operator[](unsigned int)const "}, -{"?abs@std@@YAMABV?$complex@M@1@@Z", "float __cdecl std::abs(class std::complex const &)"}, -{"?abs@std@@YANABV?$complex@N@1@@Z", "double __cdecl std::abs(class std::complex const &)"}, -{"?abs@std@@YAOABV?$complex@O@1@@Z", "long double __cdecl std::abs(class std::complex const &)"}, -{"?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A", "class std::basic_istream > std::cin"}, -{"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAG@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,unsigned short &)const "}, -{"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAI@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,unsigned int &)const "}, -{"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAJ@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,long &)const "}, -{"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAK@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,unsigned long &)const "}, -{"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAM@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,float &)const "}, -{"?_query_new_handler@@YAP6AHI@ZXZ", "int (__cdecl*__cdecl _query_new_handler(void))(unsigned int)"}, -{"?register_callback@ios_base@std@@QAEXP6AXW4event@12@AAV12@H@ZH@Z", "public: void __thiscall std::ios_base::register_callback(void (__cdecl*)(enum std::ios_base::event,class std::ios_base &,int),int)"}, -{"?seekg@?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV12@JW4seekdir@ios_base@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(long,enum std::ios_base::seekdir)"}, -{"?seekg@?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV12@V?$fpos@H@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(class std::fpos)"}, -{"?seekg@?$basic_istream@GU?$char_traits@G@std@@@std@@QAEAAV12@JW4seekdir@ios_base@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(long,enum std::ios_base::seekdir)"}, -{"?seekg@?$basic_istream@GU?$char_traits@G@std@@@std@@QAEAAV12@V?$fpos@H@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(class std::fpos)"}, -{"?seekoff@?$basic_filebuf@DU?$char_traits@D@std@@@std@@MAE?AV?$fpos@H@2@JW4seekdir@ios_base@2@H@Z", "protected: virtual class std::fpos __thiscall std::basic_filebuf >::seekoff(long,enum std::ios_base::seekdir,int)"}, -{"?seekoff@?$basic_filebuf@GU?$char_traits@G@std@@@std@@MAE?AV?$fpos@H@2@JW4seekdir@ios_base@2@H@Z", "protected: virtual class std::fpos __thiscall std::basic_filebuf >::seekoff(long,enum std::ios_base::seekdir,int)"}, -{"?set_new_handler@@YAP6AXXZP6AXXZ@Z", "void (__cdecl*__cdecl set_new_handler(void (__cdecl*)(void)))(void)"}, -{"?str@?$basic_istringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z", "public: void __thiscall std::basic_istringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, -{"?str@?$basic_istringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_istringstream,class std::allocator >::str(void)const "}, -{"?str@?$basic_istringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@@Z", "public: void __thiscall std::basic_istringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, -{"?str@?$basic_istringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBE?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_istringstream,class std::allocator >::str(void)const "}, -{"?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z", "public: void __thiscall std::basic_ostringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, -{"?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_ostringstream,class std::allocator >::str(void)const "}, -{"?str@?$basic_ostringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@@Z", "public: void __thiscall std::basic_ostringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, -{"?str@?$basic_ostringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBE?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_ostringstream,class std::allocator >::str(void)const "}, -{"?str@?$basic_stringbuf@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z", "public: void __thiscall std::basic_stringbuf,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, -{"?str@?$basic_stringbuf@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_stringbuf,class std::allocator >::str(void)const "}, -{"?str@?$basic_stringbuf@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@@Z", "public: void __thiscall std::basic_stringbuf,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, -{"?str@?$basic_stringbuf@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBE?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_stringbuf,class std::allocator >::str(void)const "}, -{"?str@?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z", "public: void __thiscall std::basic_stringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, -{"?str@?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_stringstream,class std::allocator >::str(void)const "}, -{"?str@?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@@Z", "public: void __thiscall std::basic_stringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, -{"?str@?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBE?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_stringstream,class std::allocator >::str(void)const "}, -{"?_Sync@ios_base@std@@0_NA", "private: static bool std::ios_base::_Sync"}, -{"??_U@YAPAXI@Z", "void * __cdecl operator new[](unsigned int)"}, -{"??_V@YAXPAX@Z", "void __cdecl operator delete[](void *)"}, -{"??X?$_Complex_base@M@std@@QAEAAV01@ABM@Z", "public: class std::_Complex_base & __thiscall std::_Complex_base::operator*=(float const &)"}, -{"??Xstd@@YAAAV?$complex@M@0@AAV10@ABV10@@Z", "class std::complex & __cdecl std::operator*=(class std::complex &,class std::complex const &)"}, -{"?aaa@@YAHAAUbbb@@@Z", "int __cdecl aaa(struct bbb &)"}, -{"?aaa@@YAHBAUbbb@@@Z", "int __cdecl aaa(struct bbb & volatile)"}, -{"?aaa@@YAHPAUbbb@@@Z", "int __cdecl aaa(struct bbb *)"}, -{"?aaa@@YAHQAUbbb@@@Z", "int __cdecl aaa(struct bbb * const)"}, -{"?aaa@@YAHRAUbbb@@@Z", "int __cdecl aaa(struct bbb * volatile)"}, -{"?aaa@@YAHSAUbbb@@@Z", "int __cdecl aaa(struct bbb * const volatile)"}, -{"??0aa.a@@QAE@XZ", "??0aa.a@@QAE@XZ"}, -{"??0aa$_3a@@QAE@XZ", "public: __thiscall aa$_3a::aa$_3a(void)"}, -{"??2?$aaa@AAUbbb@@AAUccc@@AAU2@@ddd@1eee@2@QAEHXZ", "public: int __thiscall eee::eee::ddd::ddd::aaa::operator new(void)"}, -{"?pSW@@3P6GHKPAX0PAU_tagSTACKFRAME@@0P6GH0K0KPAK@ZP6GPAX0K@ZP6GK0K@ZP6GK00PAU_tagADDRESS@@@Z@ZA", "int (__stdcall* pSW)(unsigned long,void *,void *,struct _tagSTACKFRAME *,void *,int (__stdcall*)(void *,unsigned long,void *,unsigned long,unsigned long *),void * (__stdcall*)(void *,unsigned long),unsigned long (__stdcall*)(void *,unsigned long),unsigned long (__stdcall*)(void *,void *,struct _tagADDRESS *))"}, -{"?$_aaa@Vbbb@@", "_aaa"}, -{"?$aaa@Vbbb@ccc@@Vddd@2@", "aaa"}, -{ "??0?$Foo@P6GHPAX0@Z@@QAE@PAD@Z", "public: __thiscall Foo::Foo(char *)"}, -{ "??0?$Foo@P6GHPAX0@Z@@QAE@PAD@Z", "__thiscall Foo::Foo(char *)", 0x880}, -{ "?Qux@Bar@@0PAP6AHPAV1@AAH1PAH@ZA", "private: static int (__cdecl** Bar::Qux)(class Bar *,int &,int &,int *)" }, -{ "?Qux@Bar@@0PAP6AHPAV1@AAH1PAH@ZA", "Bar::Qux", 0x1800}, -{"?$AAA@$DBAB@", "AAA<`template-parameter257'>"}, -{"?$AAA@?C@", "AAA<`template-parameter-2'>"}, -{"?$AAA@PAUBBB@@", "AAA"}, -{"??$ccccc@PAVaaa@@@bar@bb@foo@@DGPAV0@PAV0@PAVee@@IPAPAVaaa@@1@Z", "private: static class bar * __stdcall foo::bb::bar::ccccc(class bar *,class ee *,unsigned int,class aaa * *,class ee *)"}, -{"?f@T@@QAEHQCY1BE@BO@D@Z", "public: int __thiscall T::f(char (volatile * const)[20][30])"}, -{"?f@T@@QAEHQAY2BE@BO@CI@D@Z", "public: int __thiscall T::f(char (* const)[20][30][40])"}, -{"?f@T@@QAEHQAY1BE@BO@$$CBD@Z", "public: int __thiscall T::f(char const (* const)[20][30])"}, + static struct {const char* in; const char* out; const char *broken; unsigned int flags;} test[] = { +/* 0 */ {"??0bad_alloc@std@@QAE@ABV01@@Z", + "public: __thiscall std::bad_alloc::bad_alloc(class std::bad_alloc const &)", + "public: __thiscall std::bad_alloc::bad_alloc(class bad_alloc::bad_alloc const &)"}, +/* 1 */ {"??0bad_alloc@std@@QAE@PBD@Z", + "public: __thiscall std::bad_alloc::bad_alloc(char const *)"}, +/* 2 */ {"??0bad_cast@@AAE@PBQBD@Z", + "private: __thiscall bad_cast::bad_cast(char const * const *)"}, +/* 3 */ {"??0bad_cast@@QAE@ABQBD@Z", + "public: __thiscall bad_cast::bad_cast(char const * const &)"}, +/* 4 */ {"??0bad_cast@@QAE@ABV0@@Z", + "public: __thiscall bad_cast::bad_cast(class bad_cast const &)"}, +/* 5 */ {"??0bad_exception@std@@QAE@ABV01@@Z", + "public: __thiscall std::bad_exception::bad_exception(class std::bad_exception const &)", + "public: __thiscall std::bad_exception::bad_exception(class bad_exception::bad_exception const &)"}, +/* 6 */ {"??0bad_exception@std@@QAE@PBD@Z", + "public: __thiscall std::bad_exception::bad_exception(char const *)"}, +/* 7 */ {"??0?$basic_filebuf@DU?$char_traits@D@std@@@std@@QAE@ABV01@@Z", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(class std::basic_filebuf > const &)", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(class basic_filebuf >::basic_filebuf > const &)"}, +/* 8 */ {"??0?$basic_filebuf@DU?$char_traits@D@std@@@std@@QAE@PAU_iobuf@@@Z", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(struct _iobuf *)"}, +/* 9 */ {"??0?$basic_filebuf@DU?$char_traits@D@std@@@std@@QAE@W4_Uninitialized@1@@Z", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(enum std::_Uninitialized)", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(enum basic_filebuf >::_Uninitialized)"}, +/* 10 */ {"??0?$basic_filebuf@GU?$char_traits@G@std@@@std@@QAE@ABV01@@Z", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(class std::basic_filebuf > const &)", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(class basic_filebuf >::basic_filebuf > const &)"}, +/* 11 */ {"??0?$basic_filebuf@GU?$char_traits@G@std@@@std@@QAE@PAU_iobuf@@@Z", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(struct _iobuf *)"}, +/* 12 */ {"??0?$basic_filebuf@GU?$char_traits@G@std@@@std@@QAE@W4_Uninitialized@1@@Z", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(enum std::_Uninitialized)", + "public: __thiscall std::basic_filebuf >::basic_filebuf >(enum basic_filebuf >::_Uninitialized)"}, +/* 13 */ {"??0?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV01@@Z", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class std::basic_stringstream,class std::allocator > const &)", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator > const &)"}, +/* 14 */ {"??0?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@1@H@Z", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class std::basic_string,class std::allocator > const &,int)", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class basic_stringstream,class std::allocator >::basic_string,class std::allocator > const &,int)"}, +/* 15 */ {"??0?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@H@Z", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(int)"}, +/* 16 */ {"??0?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@ABV01@@Z", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class std::basic_stringstream,class std::allocator > const &)", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator > const &)"}, +/* 17 */ {"??0?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@ABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@1@H@Z", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class std::basic_string,class std::allocator > const &,int)", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(class basic_stringstream,class std::allocator >::basic_string,class std::allocator > const &,int)"}, +/* 18 */ {"??0?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@H@Z", + "public: __thiscall std::basic_stringstream,class std::allocator >::basic_stringstream,class std::allocator >(int)"}, +/* 19 */ {"??0?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@QAE@ABV_Locinfo@1@I@Z", + "public: __thiscall std::num_get > >::num_get > >(class std::_Locinfo const &,unsigned int)", + "public: __thiscall std::num_get > >::num_get > >(class num_get > >::_Locinfo const &,unsigned int)"}, +/* 20 */ {"??0?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@QAE@I@Z", + "public: __thiscall std::num_get > >::num_get > >(unsigned int)"}, +/* 21 */ {"??0?$num_get@GV?$istreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@QAE@ABV_Locinfo@1@I@Z", + "public: __thiscall std::num_get > >::num_get > >(class std::_Locinfo const &,unsigned int)", + "public: __thiscall std::num_get > >::num_get > >(class num_get > >::_Locinfo const &,unsigned int)"}, +/* 22 */ {"??0?$num_get@GV?$istreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@QAE@I@Z", "public: __thiscall std::num_get > >::num_get > >(unsigned int)"}, +/* 23 */ {"??0streambuf@@QAE@ABV0@@Z", "public: __thiscall streambuf::streambuf(class streambuf const &)"}, +/* 24 */ {"??0strstreambuf@@QAE@ABV0@@Z", "public: __thiscall strstreambuf::strstreambuf(class strstreambuf const &)"}, +/* 25 */ {"??0strstreambuf@@QAE@H@Z", "public: __thiscall strstreambuf::strstreambuf(int)"}, +/* 26 */ {"??0strstreambuf@@QAE@P6APAXJ@ZP6AXPAX@Z@Z", "public: __thiscall strstreambuf::strstreambuf(void * (__cdecl*)(long),void (__cdecl*)(void *))"}, +/* 27 */ {"??0strstreambuf@@QAE@PADH0@Z", "public: __thiscall strstreambuf::strstreambuf(char *,int,char *)"}, +/* 28 */ {"??0strstreambuf@@QAE@PAEH0@Z", "public: __thiscall strstreambuf::strstreambuf(unsigned char *,int,unsigned char *)"}, +/* 29 */ {"??0strstreambuf@@QAE@XZ", "public: __thiscall strstreambuf::strstreambuf(void)"}, +/* 30 */ {"??1__non_rtti_object@std@@UAE@XZ", "public: virtual __thiscall std::__non_rtti_object::~__non_rtti_object(void)"}, +/* 31 */ {"??1__non_rtti_object@@UAE@XZ", "public: virtual __thiscall __non_rtti_object::~__non_rtti_object(void)"}, +/* 32 */ {"??1?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@UAE@XZ", "public: virtual __thiscall std::num_get > >::~num_get > >(void)"}, +/* 33 */ {"??1?$num_get@GV?$istreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@UAE@XZ", "public: virtual __thiscall std::num_get > >::~num_get > >(void)"}, +/* 34 */ {"??4istream_withassign@@QAEAAV0@ABV0@@Z", "public: class istream_withassign & __thiscall istream_withassign::operator=(class istream_withassign const &)"}, +/* 35 */ {"??4istream_withassign@@QAEAAVistream@@ABV1@@Z", "public: class istream & __thiscall istream_withassign::operator=(class istream const &)"}, +/* 36 */ {"??4istream_withassign@@QAEAAVistream@@PAVstreambuf@@@Z", "public: class istream & __thiscall istream_withassign::operator=(class streambuf *)"}, +/* 37 */ {"??5std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAC@Z", "class std::basic_istream > & __cdecl std::operator>>(class std::basic_istream > &,signed char &)"}, +/* 38 */ {"??5std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAD@Z", "class std::basic_istream > & __cdecl std::operator>>(class std::basic_istream > &,char &)"}, +/* 39 */ {"??5std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAE@Z", "class std::basic_istream > & __cdecl std::operator>>(class std::basic_istream > &,unsigned char &)"}, +/* 40 */ {"??6?$basic_ostream@GU?$char_traits@G@std@@@std@@QAEAAV01@P6AAAVios_base@1@AAV21@@Z@Z", "public: class std::basic_ostream > & __thiscall std::basic_ostream >::operator<<(class std::ios_base & (__cdecl*)(class std::ios_base &))"}, +/* 41 */ {"??6?$basic_ostream@GU?$char_traits@G@std@@@std@@QAEAAV01@PAV?$basic_streambuf@GU?$char_traits@G@std@@@1@@Z", "public: class std::basic_ostream > & __thiscall std::basic_ostream >::operator<<(class std::basic_streambuf > *)"}, +/* 42 */ {"??6?$basic_ostream@GU?$char_traits@G@std@@@std@@QAEAAV01@PBX@Z", "public: class std::basic_ostream > & __thiscall std::basic_ostream >::operator<<(void const *)"}, +/* 43 */ {"??_8?$basic_fstream@DU?$char_traits@D@std@@@std@@7B?$basic_ostream@DU?$char_traits@D@std@@@1@@", "const std::basic_fstream >::`vbtable'{for `std::basic_ostream >'}"}, +/* 44 */ {"??_8?$basic_fstream@GU?$char_traits@G@std@@@std@@7B?$basic_istream@GU?$char_traits@G@std@@@1@@", "const std::basic_fstream >::`vbtable'{for `std::basic_istream >'}"}, +/* 45 */ {"??_8?$basic_fstream@GU?$char_traits@G@std@@@std@@7B?$basic_ostream@GU?$char_traits@G@std@@@1@@", "const std::basic_fstream >::`vbtable'{for `std::basic_ostream >'}"}, +/* 46 */ {"??9std@@YA_NPBDABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z", "bool __cdecl std::operator!=(char const *,class std::basic_string,class std::allocator > const &)"}, +/* 47 */ {"??9std@@YA_NPBGABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@0@@Z", "bool __cdecl std::operator!=(unsigned short const *,class std::basic_string,class std::allocator > const &)"}, +/* 48 */ {"??A?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAADI@Z", "public: char & __thiscall std::basic_string,class std::allocator >::operator[](unsigned int)"}, +/* 49 */ {"??A?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEABDI@Z", "public: char const & __thiscall std::basic_string,class std::allocator >::operator[](unsigned int)const "}, +/* 50 */ {"??A?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEAAGI@Z", "public: unsigned short & __thiscall std::basic_string,class std::allocator >::operator[](unsigned int)"}, +/* 51 */ {"??A?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBEABGI@Z", "public: unsigned short const & __thiscall std::basic_string,class std::allocator >::operator[](unsigned int)const "}, +/* 52 */ {"?abs@std@@YAMABV?$complex@M@1@@Z", "float __cdecl std::abs(class std::complex const &)"}, +/* 53 */ {"?abs@std@@YANABV?$complex@N@1@@Z", "double __cdecl std::abs(class std::complex const &)"}, +/* 54 */ {"?abs@std@@YAOABV?$complex@O@1@@Z", "long double __cdecl std::abs(class std::complex const &)"}, +/* 55 */ {"?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A", "class std::basic_istream > std::cin"}, +/* 56 */ {"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAG@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,unsigned short &)const "}, +/* 57 */ {"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAI@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,unsigned int &)const "}, +/* 58 */ {"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAJ@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,long &)const "}, +/* 59 */ {"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAK@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,unsigned long &)const "}, +/* 60 */ {"?do_get@?$num_get@DV?$istreambuf_iterator@DU?$char_traits@D@std@@@std@@@std@@MBE?AV?$istreambuf_iterator@DU?$char_traits@D@std@@@2@V32@0AAVios_base@2@AAHAAM@Z", "protected: virtual class std::istreambuf_iterator > __thiscall std::num_get > >::do_get(class std::istreambuf_iterator >,class std::istreambuf_iterator >,class std::ios_base &,int &,float &)const "}, +/* 61 */ {"?_query_new_handler@@YAP6AHI@ZXZ", "int (__cdecl*__cdecl _query_new_handler(void))(unsigned int)"}, +/* 62 */ {"?register_callback@ios_base@std@@QAEXP6AXW4event@12@AAV12@H@ZH@Z", "public: void __thiscall std::ios_base::register_callback(void (__cdecl*)(enum std::ios_base::event,class std::ios_base &,int),int)"}, +/* 63 */ {"?seekg@?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV12@JW4seekdir@ios_base@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(long,enum std::ios_base::seekdir)"}, +/* 64 */ {"?seekg@?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV12@V?$fpos@H@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(class std::fpos)"}, +/* 65 */ {"?seekg@?$basic_istream@GU?$char_traits@G@std@@@std@@QAEAAV12@JW4seekdir@ios_base@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(long,enum std::ios_base::seekdir)"}, +/* 66 */ {"?seekg@?$basic_istream@GU?$char_traits@G@std@@@std@@QAEAAV12@V?$fpos@H@2@@Z", "public: class std::basic_istream > & __thiscall std::basic_istream >::seekg(class std::fpos)"}, +/* 67 */ {"?seekoff@?$basic_filebuf@DU?$char_traits@D@std@@@std@@MAE?AV?$fpos@H@2@JW4seekdir@ios_base@2@H@Z", "protected: virtual class std::fpos __thiscall std::basic_filebuf >::seekoff(long,enum std::ios_base::seekdir,int)"}, +/* 68 */ {"?seekoff@?$basic_filebuf@GU?$char_traits@G@std@@@std@@MAE?AV?$fpos@H@2@JW4seekdir@ios_base@2@H@Z", "protected: virtual class std::fpos __thiscall std::basic_filebuf >::seekoff(long,enum std::ios_base::seekdir,int)"}, +/* 69 */ {"?set_new_handler@@YAP6AXXZP6AXXZ@Z", "void (__cdecl*__cdecl set_new_handler(void (__cdecl*)(void)))(void)"}, +/* 70 */ {"?str@?$basic_istringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z", "public: void __thiscall std::basic_istringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, +/* 71 */ {"?str@?$basic_istringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_istringstream,class std::allocator >::str(void)const "}, +/* 72 */ {"?str@?$basic_istringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@@Z", "public: void __thiscall std::basic_istringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, +/* 73 */ {"?str@?$basic_istringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBE?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_istringstream,class std::allocator >::str(void)const "}, +/* 74 */ {"?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z", "public: void __thiscall std::basic_ostringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, +/* 75 */ {"?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_ostringstream,class std::allocator >::str(void)const "}, +/* 76 */ {"?str@?$basic_ostringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@@Z", "public: void __thiscall std::basic_ostringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, +/* 77 */ {"?str@?$basic_ostringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBE?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_ostringstream,class std::allocator >::str(void)const "}, +/* 78 */ {"?str@?$basic_stringbuf@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z", "public: void __thiscall std::basic_stringbuf,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, +/* 79 */ {"?str@?$basic_stringbuf@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_stringbuf,class std::allocator >::str(void)const "}, +/* 80 */ {"?str@?$basic_stringbuf@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@@Z", "public: void __thiscall std::basic_stringbuf,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, +/* 81 */ {"?str@?$basic_stringbuf@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBE?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_stringbuf,class std::allocator >::str(void)const "}, +/* 82 */ {"?str@?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z", "public: void __thiscall std::basic_stringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, +/* 83 */ {"?str@?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_stringstream,class std::allocator >::str(void)const "}, +/* 84 */ {"?str@?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAEXABV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@@Z", "public: void __thiscall std::basic_stringstream,class std::allocator >::str(class std::basic_string,class std::allocator > const &)"}, +/* 85 */ {"?str@?$basic_stringstream@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QBE?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@2@XZ", "public: class std::basic_string,class std::allocator > __thiscall std::basic_stringstream,class std::allocator >::str(void)const "}, +/* 86 */ {"?_Sync@ios_base@std@@0_NA", "private: static bool std::ios_base::_Sync"}, +/* 87 */ {"??_U@YAPAXI@Z", "void * __cdecl operator new[](unsigned int)"}, +/* 88 */ {"??_V@YAXPAX@Z", "void __cdecl operator delete[](void *)"}, +/* 89 */ {"??X?$_Complex_base@M@std@@QAEAAV01@ABM@Z", "public: class std::_Complex_base & __thiscall std::_Complex_base::operator*=(float const &)"}, +/* 90 */ {"??Xstd@@YAAAV?$complex@M@0@AAV10@ABV10@@Z", "class std::complex & __cdecl std::operator*=(class std::complex &,class std::complex const &)"}, +/* 91 */ {"?aaa@@YAHAAUbbb@@@Z", "int __cdecl aaa(struct bbb &)"}, +/* 92 */ {"?aaa@@YAHBAUbbb@@@Z", "int __cdecl aaa(struct bbb & volatile)"}, +/* 93 */ {"?aaa@@YAHPAUbbb@@@Z", "int __cdecl aaa(struct bbb *)"}, +/* 94 */ {"?aaa@@YAHQAUbbb@@@Z", "int __cdecl aaa(struct bbb * const)"}, +/* 95 */ {"?aaa@@YAHRAUbbb@@@Z", "int __cdecl aaa(struct bbb * volatile)"}, +/* 96 */ {"?aaa@@YAHSAUbbb@@@Z", "int __cdecl aaa(struct bbb * const volatile)"}, +/* 97 */ {"??0aa.a@@QAE@XZ", "??0aa.a@@QAE@XZ"}, +/* 98 */ {"??0aa$_3a@@QAE@XZ", "public: __thiscall aa$_3a::aa$_3a(void)"}, +/* 99 */ {"??2?$aaa@AAUbbb@@AAUccc@@AAU2@@ddd@1eee@2@QAEHXZ", "public: int __thiscall eee::eee::ddd::ddd::aaa::operator new(void)"}, +/* 100 */ {"?pSW@@3P6GHKPAX0PAU_tagSTACKFRAME@@0P6GH0K0KPAK@ZP6GPAX0K@ZP6GK0K@ZP6GK00PAU_tagADDRESS@@@Z@ZA", "int (__stdcall* pSW)(unsigned long,void *,void *,struct _tagSTACKFRAME *,void *,int (__stdcall*)(void *,unsigned long,void *,unsigned long,unsigned long *),void * (__stdcall*)(void *,unsigned long),unsigned long (__stdcall*)(void *,unsigned long),unsigned long (__stdcall*)(void *,void *,struct _tagADDRESS *))"}, +/* 101 */ {"?$_aaa@Vbbb@@", "_aaa"}, +/* 102 */ {"?$aaa@Vbbb@ccc@@Vddd@2@", "aaa"}, +/* 103 */ { "??0?$Foo@P6GHPAX0@Z@@QAE@PAD@Z", "public: __thiscall Foo::Foo(char *)"}, +/* 104 */ { "??0?$Foo@P6GHPAX0@Z@@QAE@PAD@Z", "__thiscall Foo::Foo(char *)", NULL, 0x880}, +/* 105 */ { "?Qux@Bar@@0PAP6AHPAV1@AAH1PAH@ZA", "private: static int (__cdecl** Bar::Qux)(class Bar *,int &,int &,int *)" }, +/* 106 */ { "?Qux@Bar@@0PAP6AHPAV1@AAH1PAH@ZA", "Bar::Qux", NULL, 0x1800}, +/* 107 */ {"?$AAA@$DBAB@", "AAA<`template-parameter257'>"}, +/* 108 */ {"?$AAA@?C@", "AAA<`template-parameter-2'>"}, +/* 109 */ {"?$AAA@PAUBBB@@", "AAA"}, +/* 110 */ {"??$ccccc@PAVaaa@@@bar@bb@foo@@DGPAV0@PAV0@PAVee@@IPAPAVaaa@@1@Z", + "private: static class bar * __stdcall foo::bb::bar::ccccc(class bar *,class ee *,unsigned int,class aaa * *,class ee *)", + "??$ccccc@PAVaaa@@@bar@bb@foo@@DGPAV0@PAV0@PAVee@@IPAPAVaaa@@1@Z"}, +/* 111 */ {"?f@T@@QAEHQCY1BE@BO@D@Z", "public: int __thiscall T::f(char (volatile * const)[20][30])"}, +/* 112 */ {"?f@T@@QAEHQAY2BE@BO@CI@D@Z", "public: int __thiscall T::f(char (* const)[20][30][40])"}, +/* 113 */ {"?f@T@@QAEHQAY1BE@BO@$$CBD@Z", "public: int __thiscall T::f(char const (* const)[20][30])"}, }; int i, num_test = (sizeof(test)/sizeof(test[0])); @@ -996,10 +1040,14 @@ static void test_demangle(void) for (i = 0; i < num_test; i++) { name = p__unDName(0, test[i].in, 0, pmalloc, pfree, test[i].flags); - ok(name != NULL && !strcmp_space(test[i].out, name), - "Got name \"%s\" for %d\n", name, i ); - ok(name != NULL && !strcmp_space(test[i].out, name), - "Expected \"%s\"\n", test[i].out ); + ok(name != NULL, "%u: unDName failed\n", i); + if (!name) continue; + ok( !strcmp_space(test[i].out, name) || + broken(test[i].broken && !strcmp_space(test[i].broken, name)), + "%u: Got name \"%s\"\n", i, name ); + ok( !strcmp_space(test[i].out, name) || + broken(test[i].broken && !strcmp_space(test[i].broken, name)), + "%u: Expected \"%s\"\n", i, test[i].out ); pfree(name); } } diff --git a/rostests/winetests/msvcrt/data.c b/rostests/winetests/msvcrt/data.c index a981c876cb9..a27ca27f3a6 100644 --- a/rostests/winetests/msvcrt/data.c +++ b/rostests/winetests/msvcrt/data.c @@ -31,12 +31,12 @@ #include #include -typedef void (*_INITTERMFUN)(void); -static void (*p_initterm)(_INITTERMFUN *start, _INITTERMFUN *end); +typedef void (__cdecl *_INITTERMFUN)(void); +static void (__cdecl *p_initterm)(_INITTERMFUN *start, _INITTERMFUN *end); static int callbacked; -static void initcallback(void) +static void __cdecl initcallback(void) { callbacked++; } @@ -67,13 +67,51 @@ static void test_initterm(void) initterm_test(&callbacks[0], &callbacks[3], 2); } +static void test_initvar( HMODULE hmsvcrt ) +{ + OSVERSIONINFO osvi = { sizeof(OSVERSIONINFO) }; + int *pp_winver = (int*)GetProcAddress(hmsvcrt, "_winver"); + int *pp_winmajor = (int*)GetProcAddress(hmsvcrt, "_winmajor"); + int *pp_winminor = (int*)GetProcAddress(hmsvcrt, "_winminor"); + int *pp_osver = (int*)GetProcAddress(hmsvcrt, "_osver"); + unsigned int winver, winmajor, winminor, osver; + + if( !( pp_winmajor && pp_winminor && pp_winver)) { + win_skip("_winver variables are not available\n"); + return; + } + winver = *pp_winver; + winminor = *pp_winminor; + winmajor = *pp_winmajor; + GetVersionEx( &osvi); + ok( winminor == osvi.dwMinorVersion, "Wrong value for _winminor %02x expected %02x\n", + winminor, osvi.dwMinorVersion); + ok( winmajor == osvi.dwMajorVersion, "Wrong value for _winmajor %02x expected %02x\n", + winmajor, osvi.dwMajorVersion); + ok( winver == ((osvi.dwMajorVersion << 8) | osvi.dwMinorVersion), + "Wrong value for _winver %02x expected %02x\n", + winver, ((osvi.dwMajorVersion << 8) | osvi.dwMinorVersion)); + if( !pp_osver) { + win_skip("_osver variables are not available\n"); + return; + } + osver = *pp_osver; + ok( osver == (osvi.dwBuildNumber & 0xffff) || + ((osvi.dwBuildNumber >> 24) == osvi.dwMajorVersion && + ((osvi.dwBuildNumber >> 16) & 0xff) == osvi.dwMinorVersion), /* 95/98/ME */ + "Wrong value for _osver %04x expected %04x\n", + osver, osvi.dwBuildNumber); +} + START_TEST(data) { HMODULE hmsvcrt; + hmsvcrt = GetModuleHandleA("msvcrt.dll"); if (!hmsvcrt) hmsvcrt = GetModuleHandleA("msvcrtd.dll"); if (hmsvcrt) p_initterm=(void*)GetProcAddress(hmsvcrt, "_initterm"); test_initterm(); + test_initvar(hmsvcrt); } diff --git a/rostests/winetests/msvcrt/dir.c b/rostests/winetests/msvcrt/dir.c index 6929a76a5eb..f4793bc8b6f 100644 --- a/rostests/winetests/msvcrt/dir.c +++ b/rostests/winetests/msvcrt/dir.c @@ -31,19 +31,94 @@ #include #include +typedef struct +{ + const char* buffer; + const char* drive; + const char* dir; + const char* file; + const char* ext; + const char* expected; +} makepath_case; + +#define USE_BUFF ((char*)~0ul) +static const makepath_case makepath_cases[] = +{ + { NULL, NULL, NULL, NULL, NULL, "" }, /* 0 */ + { NULL, "c", NULL, NULL, NULL, "c:" }, + { NULL, "c:", NULL, NULL, NULL, "c:" }, + { NULL, "c:\\", NULL, NULL, NULL, "c:" }, + { NULL, NULL, "dir", NULL, NULL, "dir\\" }, + { NULL, NULL, "dir\\", NULL, NULL, "dir\\" }, + { NULL, NULL, "\\dir", NULL, NULL, "\\dir\\" }, + { NULL, NULL, NULL, "file", NULL, "file" }, + { NULL, NULL, NULL, "\\file", NULL, "\\file" }, + { NULL, NULL, NULL, "file", NULL, "file" }, + { NULL, NULL, NULL, NULL, "ext", ".ext" }, /* 10 */ + { NULL, NULL, NULL, NULL, ".ext", ".ext" }, + { "foo", NULL, NULL, NULL, NULL, "" }, + { "foo", USE_BUFF, NULL, NULL, NULL, "f:" }, + { "foo", NULL, USE_BUFF, NULL, NULL, "foo\\" }, + { "foo", NULL, NULL, USE_BUFF, NULL, "foo" }, + { "foo", NULL, USE_BUFF, "file", NULL, "foo\\file" }, + { "foo", NULL, USE_BUFF, "file", "ext", "foo\\file.ext" }, + { "foo", NULL, NULL, USE_BUFF, "ext", "foo.ext" }, + /* remaining combinations of USE_BUFF crash native */ + { NULL, "c", "dir", "file", "ext", "c:dir\\file.ext" }, + { NULL, "c:", "dir", "file", "ext", "c:dir\\file.ext" }, /* 20 */ + { NULL, "c:\\", "dir", "file", "ext", "c:dir\\file.ext" } +}; + static void test_makepath(void) { + WCHAR driveW[MAX_PATH]; + WCHAR dirW[MAX_PATH]; + WCHAR fileW[MAX_PATH]; + WCHAR extW[MAX_PATH]; + WCHAR bufferW[MAX_PATH]; char buffer[MAX_PATH]; - _makepath(buffer, "C", "\\foo", "dummy", "txt"); - ok( strcmp(buffer, "C:\\foo\\dummy.txt") == 0, "unexpected result: %s\n", buffer); - _makepath(buffer, "C:", "\\foo\\", "dummy", ".txt"); - ok( strcmp(buffer, "C:\\foo\\dummy.txt") == 0, "unexpected result: %s\n", buffer); + unsigned int i, n; - /* this works with native and e.g. Freelancer depends on it */ - strcpy(buffer, "foo"); - _makepath(buffer, NULL, buffer, "dummy.txt", NULL); - ok( strcmp(buffer, "foo\\dummy.txt") == 0, "unexpected result: %s\n", buffer); + for (i = 0; i < sizeof(makepath_cases)/sizeof(makepath_cases[0]); ++i) + { + const makepath_case* p = &makepath_cases[i]; + + memset(buffer, 'X', MAX_PATH); + if (p->buffer) + strcpy(buffer, p->buffer); + + /* Ascii */ + _makepath(buffer, + p->drive == USE_BUFF ? buffer : p->drive, + p->dir == USE_BUFF ? buffer : p->dir, + p->file == USE_BUFF? buffer : p->file, + p->ext == USE_BUFF ? buffer : p->ext); + + buffer[MAX_PATH - 1] = '\0'; + ok(!strcmp(p->expected, buffer), "got '%s' for case %d\n", buffer, i); + + /* Unicode */ + if (p->drive != USE_BUFF) MultiByteToWideChar(CP_ACP, 0, p->drive, -1, driveW, MAX_PATH); + if (p->dir != USE_BUFF) MultiByteToWideChar(CP_ACP, 0, p->dir, -1, dirW, MAX_PATH); + if (p->file != USE_BUFF) MultiByteToWideChar(CP_ACP, 0, p->file, -1, fileW, MAX_PATH); + if (p->ext != USE_BUFF) MultiByteToWideChar(CP_ACP, 0, p->ext, -1, extW, MAX_PATH); + + memset(buffer, 0, MAX_PATH); + for (n = 0; n < MAX_PATH; ++n) + bufferW[n] = 'X'; + if (p->buffer) MultiByteToWideChar( CP_ACP, 0, p->buffer, -1, bufferW, MAX_PATH); + + _wmakepath(bufferW, + p->drive == USE_BUFF ? bufferW : p->drive ? driveW : NULL, + p->dir == USE_BUFF ? bufferW : p->dir ? dirW : NULL, + p->file == USE_BUFF? bufferW : p->file ? fileW : NULL, + p->ext == USE_BUFF ? bufferW : p->ext ? extW : NULL); + + bufferW[MAX_PATH - 1] = '\0'; + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL); + ok(!strcmp(p->expected, buffer), "got '%s' for unicode case %d\n", buffer, i); +} } static void test_fullpath(void) diff --git a/rostests/winetests/msvcrt/file.c b/rostests/winetests/msvcrt/file.c index aa58a329c65..8afc0e1f593 100644 --- a/rostests/winetests/msvcrt/file.c +++ b/rostests/winetests/msvcrt/file.c @@ -36,6 +36,37 @@ static HANDLE proc_handles[2]; +static void test_filbuf( void ) +{ + FILE *fp; + int c; + fpos_t pos; + + fp = fopen("filbuf.tst", "wb"); + fwrite("\n\n\n\n", 1, 4, fp); + fclose(fp); + + fp = fopen("filbuf.tst", "rt"); + c = _filbuf(fp); + ok(c == '\n', "read wrong byte\n"); + /* See bug 16970 for why we care about _filbuf. + * ftell returns screwy values on files with lots + * of bare LFs in ascii mode because it assumes + * that ascii files contain only CRLFs, removes + * the CR's early in _filbuf, and adjusts the return + * value of ftell to compensate. + * native _filbuf will read the whole file, then consume and return + * the first one. That leaves fp->_fd at offset 4, and fp->_ptr + * pointing to a buffer of three bare LFs, so + * ftell will return 4 - 3 - 3 = -2. + */ + ok(ftell(fp) == -2, "ascii crlf removal does not match native\n"); + ok(fgetpos(fp, &pos) == 0, "fgetpos fail\n"); + ok(pos == -2, "ftell does not match fgetpos\n"); + fclose(fp); + unlink("filbuf.tst"); +} + static void test_fdopen( void ) { static const char buffer[] = {0,1,2,3,4,5,6,7,8,9}; @@ -105,22 +136,22 @@ static void test_fileops( void ) rewind(file); ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n"); - ok(pos == 0, "Unexpected result of fgetpos 0x%Lx\n", pos); - pos = (ULONGLONG)sizeof (outbuffer); + ok(pos == 0, "Unexpected result of fgetpos %x%08x\n", (DWORD)(pos >> 32), (DWORD)pos); + pos = sizeof (outbuffer); ok(fsetpos(file, &pos) == 0, "fsetpos failed unexpected\n"); ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n"); - ok(pos == (ULONGLONG)sizeof (outbuffer), "Unexpected result of fgetpos 0x%Lx\n", pos); + ok(pos == sizeof (outbuffer), "Unexpected result of fgetpos %x%08x\n", (DWORD)(pos >> 32), (DWORD)pos); fclose (file); fd = open ("fdopen.tst", O_RDONLY | O_TEXT); file = fdopen (fd, "rt"); /* open in TEXT mode */ - ok(fgetws(wbuffer,sizeof(wbuffer),file) !=0,"fgetws failed unexpected\n"); - ok(fgetws(wbuffer,sizeof(wbuffer),file) ==0,"fgetws didn't signal EOF\n"); + ok(fgetws(wbuffer,sizeof(wbuffer)/sizeof(wbuffer[0]),file) !=0,"fgetws failed unexpected\n"); + ok(fgetws(wbuffer,sizeof(wbuffer)/sizeof(wbuffer[0]),file) ==0,"fgetws didn't signal EOF\n"); ok(feof(file) !=0,"feof doesn't signal EOF\n"); rewind(file); ok(fgetws(wbuffer,strlen(outbuffer),file) !=0,"fgetws failed unexpected\n"); ok(lstrlenW(wbuffer) == (lstrlenA(outbuffer) -1),"fgetws didn't read right size\n"); - ok(fgetws(wbuffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected\n"); + ok(fgetws(wbuffer,sizeof(outbuffer)/sizeof(outbuffer[0]),file) !=0,"fgets failed unexpected\n"); ok(lstrlenW(wbuffer) == 1,"fgets dropped chars\n"); fclose (file); @@ -148,7 +179,7 @@ static void test_readmode( BOOL ascii_mode ) const int *ip; int i, j, m, ao, pl; unsigned int fp; - long l; + LONG l; fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE); /* an internal buffer of BUFSIZ is maintained, so make a file big @@ -181,7 +212,7 @@ static void test_readmode( BOOL ascii_mode ) ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE); l = ftell(file); pl = 2*BUFSIZ-2; - ok(l == pl,"padding line ftell got %ld should be %d in %s\n", l, pl, IOMODE); + ok(l == pl,"padding line ftell got %d should be %d in %s\n", l, pl, IOMODE); ok(lstrlenA(buffer) == pl+ao,"padding line fgets got size %d should be %d in %s\n", lstrlenA(buffer), pl+ao, IOMODE); for (fp=0; fp=0; i--) { + ok((c = fgetc(fp)) == '0'+ i, "fgetc after fseek with neg Offset failed in line %d\n", i); + fseek(fp, -4 ,SEEK_CUR); + } + /* Show what happens if fseek positions filepointer on \\r */ + fclose(fp); + fp = fopen("ascii.tst", "r"); + fseek(fp, 3 ,SEEK_SET); + ok((c = fgetc(fp)) == '1', "fgetc fails to read next char when positioned on \\r\n"); + fclose(fp); + unlink("ascii.tst"); } +static void test_asciimode2(void) +{ + /* Error sequence from one app was getchar followed by small fread + * with one \r removed had last byte of buffer filled with + * next byte of *unbuffered* data rather than next byte from buffer + * Test case is a short string of one byte followed by a newline + * followed by filler to fill out the sector, then a sector of + * some different byte. + */ + + FILE *fp; + char ibuf[4]; + int i; + static const char obuf[] = +"00\n" +"000000000000000000000000000000000000000000000000000000000000000000000000000000\n" +"000000000000000000000000000000000000000000000000000000000000000000000000000000\n" +"000000000000000000000000000000000000000000000000000000000000000000000000000000\n" +"000000000000000000000000000000000000000000000000000000000000000000000000000000\n" +"000000000000000000000000000000000000000000000000000000000000000000000000000000\n" +"000000000000000000000000000000000000000000000000000000000000000000000000000000\n" +"000000000000000000\n" +"1111111111111111111"; + + fp = fopen("ascii2.tst", "wt"); + fwrite(obuf, 1, sizeof(obuf), fp); + fclose(fp); + + fp = fopen("ascii2.tst", "rt"); + ok(getc(fp) == '0', "first char not 0\n"); + memset(ibuf, 0, sizeof(ibuf)); + i = fread(ibuf, 1, sizeof(ibuf), fp); + ok(i == sizeof(ibuf), "fread i %d != sizeof(ibuf)\n", i); + ok(0 == strncmp(ibuf, obuf+1, sizeof(ibuf)), "ibuf != obuf\n"); + fclose(fp); + unlink("ascii2.tst"); +} + static WCHAR* AtoW( const char* p ) { WCHAR* buffer; @@ -334,6 +441,84 @@ static void test_fgetc( void ) unlink(tempf); } +static void test_fputc( void ) +{ + char* tempf; + FILE *tempfh; + int ret; + + tempf=_tempnam(".","wne"); + tempfh = fopen(tempf,"wb"); + ret = fputc(0,tempfh); + ok(0 == ret, "fputc(0,tempfh) expected %x got %x\n", 0, ret); + ret = fputc(0xff,tempfh); + ok(0xff == ret, "fputc(0xff,tempfh) expected %x got %x\n", 0xff, ret); + ret = fputc(0xffffffff,tempfh); + ok(0xff == ret, "fputc(0xffffffff,tempfh) expected %x got %x\n", 0xff, ret); + fclose(tempfh); + + tempfh = fopen(tempf,"rb"); + ret = fputc(0,tempfh); + ok(EOF == ret, "fputc(0,tempfh) on r/o file expected %x got %x\n", EOF, ret); + fclose(tempfh); + + unlink(tempf); +} + +static void test_flsbuf( void ) +{ + char* tempf; + FILE *tempfh; + int c; + int ret; + int bufmode; + static const int bufmodes[] = {_IOFBF,_IONBF}; + + tempf=_tempnam(".","wne"); + for (bufmode=0; bufmode < sizeof(bufmodes)/sizeof(bufmodes[0]); bufmode++) + { + tempfh = fopen(tempf,"wb"); + setvbuf(tempfh,NULL,bufmodes[bufmode],2048); + ret = _flsbuf(0,tempfh); + ok(0 == ret, "_flsbuf(0,tempfh) with bufmode %x expected %x got %x\n", + bufmodes[bufmode], 0, ret); + ret = _flsbuf(0xff,tempfh); + ok(0xff == ret, "_flsbuf(0xff,tempfh) with bufmode %x expected %x got %x\n", + bufmodes[bufmode], 0, ret); + ret = _flsbuf(0xffffffff,tempfh); + ok(0xff == ret, "_flsbuf(0xffffffff,tempfh) with bufmode %x expected %x got %x\n", + bufmodes[bufmode], 0, ret); + fclose(tempfh); + } + + tempfh = fopen(tempf,"rb"); + ret = _flsbuf(0,tempfh); + ok(EOF == ret, "_flsbuf(0,tempfh) on r/o file expected %x got %x\n", EOF, ret); + fclose(tempfh); + + /* See bug 17123, exposed by WinAVR's make */ + tempfh = fopen(tempf,"w"); + ok(tempfh->_cnt == 0, "_cnt on freshly opened file was %d\n", tempfh->_cnt); + setbuf(tempfh, NULL); + ok(tempfh->_cnt == 0, "_cnt on unbuffered file was %d\n", tempfh->_cnt); + /* Inlined putchar sets _cnt to -1. Native seems to ignore the value... */ + tempfh->_cnt = 1234; + ret = _flsbuf('Q',tempfh); + ok('Q' == ret, "_flsbuf('Q',tempfh) expected %x got %x\n", 'Q', ret); + /* ... and reset it to zero */ + ok(tempfh->_cnt == 0, "after unbuf _flsbuf, _cnt was %d\n", tempfh->_cnt); + fclose(tempfh); + /* And just for grins, make sure the file is correct */ + tempfh = fopen(tempf,"r"); + c = fgetc(tempfh); + ok(c == 'Q', "first byte should be 'Q'\n"); + c = fgetc(tempfh); + ok(c == EOF, "there should only be one byte\n"); + fclose(tempfh); + + unlink(tempf); +} + static void test_fgetwc( void ) { #define LLEN 512 @@ -346,7 +531,7 @@ static void test_fgetwc( void ) BOOL diff_found = FALSE; int j; unsigned int i; - long l; + LONG l; tempf=_tempnam(".","wne"); tempfh = fopen(tempf,"wb"); @@ -365,11 +550,10 @@ static void test_fgetwc( void ) tempfh = fopen(tempf,"rt"); /* open in TEXT mode */ fgetws(wtextW,LLEN,tempfh); l=ftell(tempfh); - ok(l==BUFSIZ-2, "ftell expected %d got %ld\n", BUFSIZ-2, l); + ok(l==BUFSIZ-2, "ftell expected %d got %d\n", BUFSIZ-2, l); fgetws(wtextW,LLEN,tempfh); l=ftell(tempfh); - ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %ld\n", - BUFSIZ-2+strlen(mytext), l); + ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %d\n", BUFSIZ-2+lstrlen(mytext), l); mytextW = AtoW (mytext); aptr = mytextW; wptr = wtextW; @@ -402,25 +586,25 @@ static void test_fgetwc( void ) fgetws(wtextW,j,tempfh); l=ftell(tempfh); j=(j-1)*sizeof(WCHAR); - ok(l==j, "ftell expected %d got %ld\n", j, l); + ok(l==j, "ftell expected %d got %d\n", j, l); i=fgetc(tempfh); ok(i=='a', "fgetc expected %d got %d\n", 0x61, i); l=ftell(tempfh); j++; - ok(l==j, "ftell expected %d got %ld\n", j, l); + ok(l==j, "ftell expected %d got %d\n", j, l); fgetws(wtextW,3,tempfh); ok(wtextW[0]=='\r',"expected carriage return got %04hx\n", wtextW[0]); ok(wtextW[1]=='\n',"expected newline got %04hx\n", wtextW[1]); l=ftell(tempfh); j += 4; - ok(l==j, "ftell expected %d got %ld\n", j, l); + ok(l==j, "ftell expected %d got %d\n", j, l); for(i=0; ilpReserved2 = block; + startup->cbReserved2 = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * count; + wxflag_ptr = block + sizeof(unsigned); + handle_ptr = (HANDLE *)(wxflag_ptr + count); + + *(unsigned*)block = count; + for (i = 0; i < count; i++) + { + wxflag_ptr[i] = 0x81; + handle_ptr[i] = handles[i]; + } +} + +static const char *read_file( HANDLE file ) +{ + static char buffer[128]; + DWORD ret; + SetFilePointer( file, 0, NULL, FILE_BEGIN ); + if (!ReadFile( file, buffer, sizeof(buffer) - 1, &ret, NULL)) ret = 0; + buffer[ret] = 0; + return buffer; +} + +static void test_stdout_handle( STARTUPINFO *startup, char *cmdline, HANDLE hstdout, BOOL expect_stdout, + const char *descr ) +{ + const char *data; + HANDLE hErrorFile; + SECURITY_ATTRIBUTES sa; + PROCESS_INFORMATION proc; + + /* make file handle inheritable */ + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + hErrorFile = CreateFileA( "fdopen.err", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + startup->dwFlags = STARTF_USESTDHANDLES; + startup->hStdInput = GetStdHandle( STD_INPUT_HANDLE ); + startup->hStdOutput = hErrorFile; + startup->hStdError = GetStdHandle( STD_ERROR_HANDLE ); + + CreateProcessA( NULL, cmdline, NULL, NULL, TRUE, + CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, NULL, startup, &proc ); + winetest_wait_child_process( proc.hProcess ); + + data = read_file( hErrorFile ); + if (expect_stdout) + ok( strcmp( data, "Success" ), "%s: Error file shouldn't contain data\n", descr ); + else + ok( !strcmp( data, "Success" ), "%s: Wrong error data (%s)\n", descr, data ); + + if (hstdout) + { + data = read_file( hstdout ); + if (expect_stdout) + ok( !strcmp( data, "Success" ), "%s: Wrong stdout data (%s)\n", descr, data ); + else + ok( strcmp( data, "Success" ), "%s: Stdout file shouldn't contain data\n", descr ); + } + + CloseHandle( hErrorFile ); + DeleteFile( "fdopen.err" ); +} + static void test_file_inherit( const char* selfname ) { int fd; const char* arg_v[5]; char buffer[16]; + char cmdline[MAX_PATH]; + STARTUPINFO startup; + SECURITY_ATTRIBUTES sa; + HANDLE handles[3]; fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE); ok(fd != -1, "Couldn't create test file\n"); @@ -688,7 +949,7 @@ static void test_file_inherit( const char* selfname ) arg_v[3] = buffer; sprintf(buffer, "%d", fd); arg_v[4] = 0; _spawnvp(_P_WAIT, selfname, arg_v); - ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd)); + ok(tell(fd) == 8, "bad position %u expecting 8\n", tell(fd)); lseek(fd, 0, SEEK_SET); ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n"); close (fd); @@ -702,10 +963,68 @@ static void test_file_inherit( const char* selfname ) arg_v[3] = buffer; sprintf(buffer, "%d", fd); arg_v[4] = 0; _spawnvp(_P_WAIT, selfname, arg_v); - ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd)); + ok(tell(fd) == 0, "bad position %u expecting 0\n", tell(fd)); ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer); close (fd); ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n"); + + /* make file handle inheritable */ + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + sprintf(cmdline, "%s file inherit 1", selfname); + + /* init an empty Reserved2, which should not be recognized as inherit-block */ + ZeroMemory(&startup, sizeof(STARTUPINFO)); + startup.cb = sizeof(startup); + create_io_inherit_block( &startup, 0, NULL ); + test_stdout_handle( &startup, cmdline, 0, FALSE, "empty block" ); + + /* test with valid inheritblock */ + handles[0] = GetStdHandle( STD_INPUT_HANDLE ); + handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + handles[2] = GetStdHandle( STD_ERROR_HANDLE ); + create_io_inherit_block( &startup, 3, handles ); + test_stdout_handle( &startup, cmdline, handles[1], TRUE, "valid block" ); + CloseHandle( handles[1] ); + DeleteFile("fdopen.tst"); + + /* test inherit block starting with unsigned zero */ + handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + create_io_inherit_block( &startup, 3, handles ); + *(unsigned int *)startup.lpReserved2 = 0; + test_stdout_handle( &startup, cmdline, handles[1], FALSE, "zero count block" ); + CloseHandle( handles[1] ); + DeleteFile("fdopen.tst"); + + /* test inherit block with smaller size */ + handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + create_io_inherit_block( &startup, 3, handles ); + startup.cbReserved2 -= 3; + test_stdout_handle( &startup, cmdline, handles[1], TRUE, "small size block" ); + CloseHandle( handles[1] ); + DeleteFile("fdopen.tst"); + + /* test inherit block with even smaller size */ + handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + create_io_inherit_block( &startup, 3, handles ); + startup.cbReserved2 = sizeof(unsigned int) + sizeof(HANDLE) + sizeof(char); + test_stdout_handle( &startup, cmdline, handles[1], FALSE, "smaller size block" ); + CloseHandle( handles[1] ); + DeleteFile("fdopen.tst"); + + /* test inherit block with larger size */ + handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + create_io_inherit_block( &startup, 3, handles ); + startup.cbReserved2 += 7; + test_stdout_handle( &startup, cmdline, handles[1], TRUE, "large size block" ); + CloseHandle( handles[1] ); + DeleteFile("fdopen.tst"); } static void test_tmpnam( void ) @@ -730,7 +1049,7 @@ static void test_tmpnam( void ) static void test_chsize( void ) { int fd; - long cur, pos, count; + LONG cur, pos, count; char temptext[] = "012345678"; char *tempfile = _tempnam( ".", "tst" ); @@ -749,14 +1068,14 @@ static void test_chsize( void ) ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" ); pos = _lseek( fd, 0, SEEK_CUR ); - ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos ); + ok( cur == pos, "File pointer changed from: %d to: %d\n", cur, pos ); ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" ); /* enlarge the file */ ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); pos = _lseek( fd, 0, SEEK_CUR ); - ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos ); + ok( cur == pos, "File pointer changed from: %d to: %d\n", cur, pos ); ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" ); _close( fd ); @@ -783,8 +1102,8 @@ static void test_fopen_fclose_fcloseall( void ) ok(stream3 != NULL, "The file '%s' should be opened now\n", fname3 ); errno = 0xfaceabad; stream4 = fopen("", "w+"); - ok(stream4 == NULL && errno == ENOENT, - "filename is empty, errno = %d (expected 2)\n", errno); + ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), + "filename is empty, errno = %d (expected 2 or 22)\n", errno); errno = 0xfaceabad; stream4 = fopen(NULL, "w+"); ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), @@ -846,23 +1165,21 @@ static void test_stat(void) fd = open("stat.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE); if (fd >= 0) { - if (fstat(fd, &buf) == 0) - { - if ((buf.st_mode & _S_IFMT) == _S_IFREG) - { + ok(fstat(fd, &buf) == 0, "fstat failed: errno=%d\n", errno); + ok((buf.st_mode & _S_IFMT) == _S_IFREG, "bad format = %06o\n", buf.st_mode); + ok((buf.st_mode & 0777) == 0666, "bad st_mode = %06o\n", buf.st_mode); ok(buf.st_dev == 0, "st_dev is %d, expected 0\n", buf.st_dev); - ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", - buf.st_dev, buf.st_rdev); - ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", - buf.st_nlink); - ok(buf.st_size == 0, "st_size is %d, expected 0\n", - buf.st_size); - } - else - skip("file is not a file?\n"); - } - else - skip("fstat failed, errno %d\n", errno); + ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev); + ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink); + ok(buf.st_size == 0, "st_size is %d, expected 0\n", buf.st_size); + + ok(stat("stat.tst", &buf) == 0, "stat failed: errno=%d\n", errno); + ok((buf.st_mode & _S_IFMT) == _S_IFREG, "bad format = %06o\n", buf.st_mode); + ok((buf.st_mode & 0777) == 0666, "bad st_mode = %06o\n", buf.st_mode); + ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev); + ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink); + ok(buf.st_size == 0, "st_size is %d, expected 0\n", buf.st_size); + close(fd); remove("stat.tst"); } @@ -872,19 +1189,16 @@ static void test_stat(void) /* Tests for a char device */ if (_dup2(0, 10) == 0) { - if (fstat(10, &buf) == 0) + ok(fstat(10, &buf) == 0, "fstat(stdin) failed: errno=%d\n", errno); + if ((buf.st_mode & _S_IFMT) == _S_IFCHR) { - if (buf.st_mode == _S_IFCHR) - { + ok(buf.st_mode == _S_IFCHR, "bad st_mode=%06o\n", buf.st_mode); ok(buf.st_dev == 10, "st_dev is %d, expected 10\n", buf.st_dev); ok(buf.st_rdev == 10, "st_rdev is %d, expected 10\n", buf.st_rdev); ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink); } else - skip("stdin is not a char device?\n"); - } - else - skip("fstat failed with errno %d\n", errno); + skip("stdin is not a char device? st_mode=%06o\n", buf.st_mode); close(10); } else @@ -893,22 +1207,11 @@ static void test_stat(void) /* Tests for pipes */ if (_pipe(pipes, 1024, O_BINARY) == 0) { - if (fstat(pipes[0], &buf) == 0) - { - if (buf.st_mode == _S_IFIFO) - { - ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n", - buf.st_dev, pipes[0]); - ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n", - buf.st_rdev, pipes[0]); - ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", - buf.st_nlink); - } - else - skip("pipe() didn't make a pipe?\n"); - } - else - skip("fstat failed with errno %d\n", errno); + ok(fstat(pipes[0], &buf) == 0, "fstat(pipe) failed: errno=%d\n", errno); + ok(buf.st_mode == _S_IFIFO, "bad st_mode=%06o\n", buf.st_mode); + ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n", buf.st_dev, pipes[0]); + ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n", buf.st_rdev, pipes[0]); + ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink); close(pipes[0]); close(pipes[1]); } @@ -940,7 +1243,7 @@ static void test_pipes_child(int argc, char** args) for (i=0; i 0) buf[r]='\0'; ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf); @@ -1013,7 +1316,7 @@ static void test_pipes(const char* selfname) for (i=0; i 0) buf[r]='\0'; ok(strcmp(buf, expected) == 0, "got '%s' expected '%s'\n", buf, expected); @@ -1028,6 +1331,19 @@ static void test_pipes(const char* selfname) ok(fclose(file) == 0, "unable to close the pipe: %d\n", errno); } +static void test_unlink(void) +{ + FILE* file; + ok(mkdir("test_unlink") == 0, "unable to create test dir\n"); + file = fopen("test_unlink\\empty", "w"); + ok(file != NULL, "unable to create test file\n"); + if(file) + fclose(file); + ok(_unlink("test_unlink") != 0, "unlinking a non-empty directory must fail\n"); + unlink("test_unlink\\empty"); + rmdir("test_unlink"); +} + START_TEST(file) { int arg_c; @@ -1052,15 +1368,20 @@ START_TEST(file) test_file_write_read(); test_chsize(); test_stat(); + test_unlink(); /* testing stream I/O */ + test_filbuf(); test_fdopen(); test_fopen_fclose_fcloseall(); test_fileops(); test_asciimode(); + test_asciimode2(); test_readmode(FALSE); /* binary mode */ test_readmode(TRUE); /* ascii mode */ test_fgetc(); + test_fputc(); + test_flsbuf(); test_fgetwc(); test_ctrlz(); test_file_put_get(); diff --git a/rostests/winetests/msvcrt/headers.c b/rostests/winetests/msvcrt/headers.c index d909ac7bf43..80c614b2950 100644 --- a/rostests/winetests/msvcrt/headers.c +++ b/rostests/winetests/msvcrt/headers.c @@ -32,7 +32,7 @@ #include "stdio.h" #include "wchar.h" #include "ctype.h" -//#include "crtdbg.h" +#include "crtdbg.h" #include "share.h" #include "search.h" #include "wctype.h" @@ -87,7 +87,7 @@ static void test_types(void) CHECK_TYPE(_dev_t); CHECK_TYPE(_off_t); CHECK_TYPE(clock_t); - CHECK_TYPE(time_t); + CHECK_TYPE(__time32_t); CHECK_TYPE(__time64_t); CHECK_TYPE(fpos_t); CHECK_SIZE(FILE); @@ -114,11 +114,16 @@ static void test_structs(void) CHECK_FIELD(tm, tm_wday); CHECK_FIELD(tm, tm_yday); CHECK_FIELD(tm, tm_isdst); - CHECK_STRUCT(_timeb); - CHECK_FIELD(_timeb, time); - CHECK_FIELD(_timeb, millitm); - CHECK_FIELD(_timeb, timezone); - CHECK_FIELD(_timeb, dstflag); + CHECK_STRUCT(__timeb32); + CHECK_FIELD(__timeb32, time); + CHECK_FIELD(__timeb32, millitm); + CHECK_FIELD(__timeb32, timezone); + CHECK_FIELD(__timeb32, dstflag); + CHECK_STRUCT(__timeb64); + CHECK_FIELD(__timeb64, time); + CHECK_FIELD(__timeb64, millitm); + CHECK_FIELD(__timeb64, timezone); + CHECK_FIELD(__timeb64, dstflag); CHECK_STRUCT(_iobuf); CHECK_FIELD(_iobuf, _ptr); CHECK_FIELD(_iobuf, _cnt); @@ -213,9 +218,12 @@ static void test_structs(void) CHECK_FIELD(_wfinddatai64_t, time_write); CHECK_FIELD(_wfinddatai64_t, size); CHECK_FIELD(_wfinddatai64_t, name[260]); - CHECK_STRUCT(_utimbuf); - CHECK_FIELD(_utimbuf, actime); - CHECK_FIELD(_utimbuf, modtime); + CHECK_STRUCT(__utimbuf32); + CHECK_FIELD(__utimbuf32, actime); + CHECK_FIELD(__utimbuf32, modtime); + CHECK_STRUCT(__utimbuf64); + CHECK_FIELD(__utimbuf64, actime); + CHECK_FIELD(__utimbuf64, modtime); CHECK_STRUCT(_stat); CHECK_FIELD(_stat, st_dev); CHECK_FIELD(_stat, st_ino); @@ -228,62 +236,6 @@ static void test_structs(void) CHECK_FIELD(_stat, st_atime); CHECK_FIELD(_stat, st_mtime); CHECK_FIELD(_stat, st_ctime); - CHECK_FIELD(_stat, st_dev); - CHECK_FIELD(_stat, st_ino); - CHECK_FIELD(_stat, st_mode); - CHECK_FIELD(_stat, st_nlink); - CHECK_FIELD(_stat, st_uid); - CHECK_FIELD(_stat, st_gid); - CHECK_FIELD(_stat, st_rdev); - CHECK_FIELD(_stat, st_size); - CHECK_FIELD(_stat, st_atime); - CHECK_FIELD(_stat, st_mtime); - CHECK_FIELD(_stat, st_ctime); - CHECK_FIELD(_stat, st_dev); - CHECK_FIELD(_stat, st_ino); - CHECK_FIELD(_stat, st_mode); - CHECK_FIELD(_stat, st_nlink); - CHECK_FIELD(_stat, st_uid); - CHECK_FIELD(_stat, st_gid); - CHECK_FIELD(_stat, st_rdev); - CHECK_FIELD(_stat, st_size); - CHECK_FIELD(_stat, st_atime); - CHECK_FIELD(_stat, st_mtime); - CHECK_FIELD(_stat, st_ctime); - CHECK_STRUCT(stat); - CHECK_FIELD(stat, st_dev); - CHECK_FIELD(stat, st_ino); - CHECK_FIELD(stat, st_mode); - CHECK_FIELD(stat, st_nlink); - CHECK_FIELD(stat, st_uid); - CHECK_FIELD(stat, st_gid); - CHECK_FIELD(stat, st_rdev); - CHECK_FIELD(stat, st_size); - CHECK_FIELD(stat, st_atime); - CHECK_FIELD(stat, st_mtime); - CHECK_FIELD(stat, st_ctime); - CHECK_FIELD(stat, st_dev); - CHECK_FIELD(stat, st_ino); - CHECK_FIELD(stat, st_mode); - CHECK_FIELD(stat, st_nlink); - CHECK_FIELD(stat, st_uid); - CHECK_FIELD(stat, st_gid); - CHECK_FIELD(stat, st_rdev); - CHECK_FIELD(stat, st_size); - CHECK_FIELD(stat, st_atime); - CHECK_FIELD(stat, st_mtime); - CHECK_FIELD(stat, st_ctime); - CHECK_FIELD(stat, st_dev); - CHECK_FIELD(stat, st_ino); - CHECK_FIELD(stat, st_mode); - CHECK_FIELD(stat, st_nlink); - CHECK_FIELD(stat, st_uid); - CHECK_FIELD(stat, st_gid); - CHECK_FIELD(stat, st_rdev); - CHECK_FIELD(stat, st_size); - CHECK_FIELD(stat, st_atime); - CHECK_FIELD(stat, st_mtime); - CHECK_FIELD(stat, st_ctime); CHECK_STRUCT(_stati64); CHECK_FIELD(_stati64, st_dev); CHECK_FIELD(_stati64, st_ino); @@ -462,6 +414,17 @@ static void test_defines(void) CHECK_DEF(SIGBREAK); CHECK_DEF(SIGABRT); CHECK_DEF(NSIG); + CHECK_DEF(_FPE_INVALID); + CHECK_DEF(_FPE_DENORMAL); + CHECK_DEF(_FPE_ZERODIVIDE); + CHECK_DEF(_FPE_OVERFLOW); + CHECK_DEF(_FPE_UNDERFLOW); + CHECK_DEF(_FPE_INEXACT); + CHECK_DEF(_FPE_UNEMULATED); + CHECK_DEF(_FPE_SQRTNEG); + CHECK_DEF(_FPE_STACKOVERFLOW); + CHECK_DEF(_FPE_STACKUNDERFLOW); + CHECK_DEF(_FPE_EXPLICITGEN); #ifdef __i386__ CHECK_DEF(_EM_INVALID); CHECK_DEF(_EM_DENORMAL); diff --git a/rostests/winetests/msvcrt/heap.c b/rostests/winetests/msvcrt/heap.c index ae98e3b8975..3587e0e56f5 100644 --- a/rostests/winetests/msvcrt/heap.c +++ b/rostests/winetests/msvcrt/heap.c @@ -23,13 +23,13 @@ #include #include "wine/test.h" -static void (*p_aligned_free)(void*) = NULL; -static void * (*p_aligned_malloc)(size_t,size_t) = NULL; -static void * (*p_aligned_offset_malloc)(size_t,size_t,size_t) = NULL; -static void * (*p_aligned_realloc)(void*,size_t,size_t) = NULL; -static void * (*p_aligned_offset_realloc)(void*,size_t,size_t,size_t) = NULL; +static void (__cdecl *p_aligned_free)(void*) = NULL; +static void * (__cdecl *p_aligned_malloc)(size_t,size_t) = NULL; +static void * (__cdecl *p_aligned_offset_malloc)(size_t,size_t,size_t) = NULL; +static void * (__cdecl *p_aligned_realloc)(void*,size_t,size_t) = NULL; +static void * (__cdecl *p_aligned_offset_realloc)(void*,size_t,size_t,size_t) = NULL; -static void test_aligned_malloc(size_t size, size_t alignment) +static void test_aligned_malloc(unsigned int size, unsigned int alignment) { void *mem; @@ -48,8 +48,7 @@ static void test_aligned_malloc(size_t size, size_t alignment) { void *saved; saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1)); - trace("_aligned_malloc(%3d, %3d) returns %p, saved = %p, diff = %d\n", - size, alignment, mem, saved, (char *)saved - (char *)mem); + trace("_aligned_malloc(%3d, %3d) returns %p, saved = %p\n", size, alignment, mem, saved ); } p_aligned_free(mem); } @@ -57,7 +56,7 @@ static void test_aligned_malloc(size_t size, size_t alignment) ok(errno == EINVAL, "_aligned_malloc(%d, %d) errno: %d != %d\n", size, alignment, errno, EINVAL); } -static void test_aligned_offset_malloc(size_t size, size_t alignment, size_t offset) +static void test_aligned_offset_malloc(unsigned int size, unsigned int alignment, unsigned int offset) { void *mem; @@ -79,8 +78,8 @@ static void test_aligned_offset_malloc(size_t size, size_t alignment, size_t off { void *saved; saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1)); - trace("_aligned_offset_malloc(%3d, %3d, %3d) returns %p, saved = %p, diff = %d\n", - size, alignment, offset, mem, saved, (char *)saved - (char *)mem); + trace("_aligned_offset_malloc(%3d, %3d, %3d) returns %p, saved = %p\n", + size, alignment, offset, mem, saved); } p_aligned_free(mem); } @@ -88,7 +87,7 @@ static void test_aligned_offset_malloc(size_t size, size_t alignment, size_t off ok(errno == EINVAL, "_aligned_offset_malloc(%d, %d, %d) errno: %d != %d\n", size, alignment, offset, errno, EINVAL); } -static void test_aligned_realloc(size_t size1, size_t size2, size_t alignment) +static void test_aligned_realloc(unsigned int size1, unsigned int size2, unsigned int alignment) { void *mem, *mem1, *mem2; @@ -104,7 +103,7 @@ static void test_aligned_realloc(size_t size1, size_t size2, size_t alignment) mem1 = malloc(size1); if (mem1) { - int i; + unsigned int i; for (i = 0; i < size1; i++) ((char *)mem)[i] = i + 1; memcpy(mem1, mem, size1); @@ -116,8 +115,7 @@ static void test_aligned_realloc(size_t size1, size_t size2, size_t alignment) { void *saved; saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1)); - trace("_aligned_malloc(%3d, %3d) returns %p, saved = %p, diff = %d\n", - size1, alignment, mem, saved, (char *)saved - (char *)mem); + trace("_aligned_malloc(%3d, %3d) returns %p, saved = %p\n", size1, alignment, mem, saved); } mem2 = p_aligned_realloc(mem, size2, alignment); @@ -132,15 +130,15 @@ static void test_aligned_realloc(size_t size1, size_t size2, size_t alignment) { void *saved; saved = *(void **)((DWORD_PTR)((char *)mem2 - sizeof(void *)) & ~(sizeof(void *) - 1)); - trace("_aligned_realloc(%p, %3d, %3d) returns %p, saved = %p, diff = %d\n", - mem, size2, alignment, mem2, saved, (char *)saved - (char *)mem2); + trace("_aligned_realloc(%p, %3d, %3d) returns %p, saved = %p\n", + mem, size2, alignment, mem2, saved); } if (mem1) { ok(memcmp(mem2, mem1, min(size1, size2))==0, "_aligned_realloc(%p, %d, %d) has different data\n", mem, size2, alignment); if (memcmp(mem2, mem1, min(size1, size2)) && winetest_debug > 1) { - int i; + unsigned int i; for (i = 0; i < min(size1, size2); i++) { if (((char *)mem2)[i] != ((char *)mem1)[i]) @@ -160,7 +158,8 @@ static void test_aligned_realloc(size_t size1, size_t size2, size_t alignment) ok(errno == EINVAL, "_aligned_malloc(%d, %d) errno: %d != %d\n", size1, alignment, errno, EINVAL); } -static void test_aligned_offset_realloc(size_t size1, size_t size2, size_t alignment, size_t offset) +static void test_aligned_offset_realloc(unsigned int size1, unsigned int size2, + unsigned int alignment, unsigned int offset) { void *mem, *mem1, *mem2; @@ -176,7 +175,7 @@ static void test_aligned_offset_realloc(size_t size1, size_t size2, size_t align mem1 = malloc(size1); if (mem1) { - int i; + unsigned int i; for (i = 0; i < size1; i++) ((char *)mem)[i] = i + 1; memcpy(mem1, mem, size1); @@ -188,8 +187,8 @@ static void test_aligned_offset_realloc(size_t size1, size_t size2, size_t align { void *saved; saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1)); - trace("_aligned_offset_malloc(%3d, %3d, %3d) returns %p, saved = %p, diff = %d\n", - size1, alignment, offset, mem, saved, (char *)saved - (char *)mem); + trace("_aligned_offset_malloc(%3d, %3d, %3d) returns %p, saved = %p\n", + size1, alignment, offset, mem, saved); } mem2 = p_aligned_offset_realloc(mem, size2, alignment, offset); @@ -204,15 +203,15 @@ static void test_aligned_offset_realloc(size_t size1, size_t size2, size_t align { void *saved; saved = *(void **)((DWORD_PTR)((char *)mem2 - sizeof(void *)) & ~(sizeof(void *) - 1)); - trace("_aligned_offset_realloc(%p, %3d, %3d, %3d) returns %p, saved = %p, diff = %d\n", - mem, size2, alignment, offset, mem2, saved, (char *)saved - (char *)mem2); + trace("_aligned_offset_realloc(%p, %3d, %3d, %3d) returns %p, saved = %p\n", + mem, size2, alignment, offset, mem2, saved); } if (mem1) { ok(memcmp(mem2, mem1, min(size1, size2))==0, "_aligned_offset_realloc(%p, %d, %d, %d) has different data\n", mem, size2, alignment, offset); if (memcmp(mem2, mem1, min(size1, size2)) && winetest_debug > 1) { - int i; + unsigned int i; for (i = 0; i < min(size1, size2); i++) { if (((char *)mem2)[i] != ((char *)mem1)[i]) diff --git a/rostests/winetests/msvcrt/msvcrt.rbuild b/rostests/winetests/msvcrt/msvcrt.rbuild index 7a63b850d3d..ca047facb44 100644 --- a/rostests/winetests/msvcrt/msvcrt.rbuild +++ b/rostests/winetests/msvcrt/msvcrt.rbuild @@ -4,9 +4,22 @@ . include/reactos/wine/msvcrt - - kernel32 - ntdll + + + + + _open + _close + _tell + _unlink + _fdopen + _lseek + _read + _write + _mkdir + _rmdir + _putenv + cpp.c data.c dir.c diff --git a/rostests/winetests/msvcrt/printf.c b/rostests/winetests/msvcrt/printf.c index 7e07241f9b8..a4d5b0b5f0d 100644 --- a/rostests/winetests/msvcrt/printf.c +++ b/rostests/winetests/msvcrt/printf.c @@ -27,6 +27,10 @@ #include +#include "windef.h" +#include "winbase.h" +#include "winnls.h" + #include "wine/test.h" static void test_sprintf( void ) @@ -39,11 +43,24 @@ static void test_sprintf( void ) format = "%+#23.15e"; r = sprintf(buffer,format,pnumber); - todo_wine { - ok(!strcmp(buffer,"+7.894561230000000e+008"),"exponent format incorrect\n"); - } + ok(!strcmp(buffer,"+7.894561230000000e+008"),"+#23.15e failed: '%s'\n", buffer); ok( r==23, "return count wrong\n"); + format = "%-#23.15e"; + r = sprintf(buffer,format,pnumber); + ok(!strcmp(buffer,"7.894561230000000e+008 "),"-#23.15e failed: '%s'\n", buffer); + ok( r==23, "return count wrong\n"); + + format = "%#23.15e"; + r = sprintf(buffer,format,pnumber); + ok(!strcmp(buffer," 7.894561230000000e+008"),"#23.15e failed: '%s'\n", buffer); + ok( r==23, "return count wrong\n"); + + format = "%#1.1g"; + r = sprintf(buffer,format,pnumber); + ok(!strcmp(buffer,"8.e+008"),"#1.1g failed: '%s'\n", buffer); + ok( r==7, "return count wrong\n"); + format = "%I64d"; r = sprintf(buffer,format,((ULONGLONG)0xffffffff)*0xffffffff); ok(!strcmp(buffer,"-8589934591"),"Problem with long long\n"); @@ -206,8 +223,11 @@ static void test_sprintf( void ) format = "%lld"; r = sprintf(buffer,format,((ULONGLONG)0xffffffff)*0xffffffff); - ok(!strcmp(buffer, "1"), "Problem with \"ll\" interpretation\n"); - ok( r==1, "return count wrong\n"); + ok( r == 1 || r == 11, "return count wrong %d\n", r); + if (r == 11) /* %ll works on Vista */ + ok(!strcmp(buffer, "-8589934591"), "Problem with \"ll\" interpretation '%s'\n", buffer); + else + ok(!strcmp(buffer, "1"), "Problem with \"ll\" interpretation '%s'\n", buffer); format = "%I"; r = sprintf(buffer,format,1); @@ -221,8 +241,15 @@ static void test_sprintf( void ) format = "%I32d"; r = sprintf(buffer,format,1); - ok(!strcmp(buffer,"1"),"I32d failed\n"); - ok( r==1, "return count wrong\n"); + if (r == 1) + { + ok(!strcmp(buffer,"1"),"I32d failed, got '%s'\n",buffer); + } + else + { + /* Older versions don't grok I32 format */ + ok(r == 4 && !strcmp(buffer,"I32d"),"I32d failed, got '%s',%d\n",buffer,r); + } format = "%I64D"; r = sprintf(buffer,format,(LONGLONG)-1); @@ -254,8 +281,32 @@ static void test_sprintf( void ) ok(!strcmp(buffer,"1 "),"Character zero-padded and/or not left-adjusted \"%s\"\n",buffer); ok( r==4, "return count wrong\n"); + if (sizeof(void *) == 8) + { format = "%p"; r = sprintf(buffer,format,(void *)57); + ok(!strcmp(buffer,"0000000000000039"),"Pointer formatted incorrectly \"%s\"\n",buffer); + ok( r==16, "return count wrong\n"); + + format = "%#020p"; + r = sprintf(buffer,format,(void *)57); + ok(!strcmp(buffer," 0X0000000000000039"),"Pointer formatted incorrectly\n"); + ok( r==20, "return count wrong\n"); + + format = "%Fp"; + r = sprintf(buffer,format,(void *)57); + ok(!strcmp(buffer,"0000000000000039"),"Pointer formatted incorrectly \"%s\"\n",buffer); + ok( r==16, "return count wrong\n"); + + format = "%#-020p"; + r = sprintf(buffer,format,(void *)57); + ok(!strcmp(buffer,"0X0000000000000039 "),"Pointer formatted incorrectly\n"); + ok( r==20, "return count wrong\n"); + } + else + { + format = "%p"; + r = sprintf(buffer,format,(void *)57); ok(!strcmp(buffer,"00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer); ok( r==8, "return count wrong\n"); @@ -269,6 +320,12 @@ static void test_sprintf( void ) ok(!strcmp(buffer,"00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer); ok( r==8, "return count wrong\n"); + format = "%#-012p"; + r = sprintf(buffer,format,(void *)57); + ok(!strcmp(buffer,"0X00000039 "),"Pointer formatted incorrectly\n"); + ok( r==12, "return count wrong\n"); + } + format = "%04s"; r = sprintf(buffer,format,"foo"); ok(!strcmp(buffer,"0foo"),"String not zero-prefixed \"%s\"\n",buffer); @@ -289,11 +346,6 @@ static void test_sprintf( void ) ok(!strcmp(buffer,"foo "),"Negative field width ignored \"%s\"\n",buffer); ok( r==5, "return count wrong\n"); - format = "%#-012p"; - r = sprintf(buffer,format,(void *)57); - ok(!strcmp(buffer,"0X00000039 "),"Pointer formatted incorrectly\n"); - ok( r==12, "return count wrong\n"); - format = "hello"; r = sprintf(buffer, format); ok(!strcmp(buffer,"hello"), "failed\n"); @@ -367,9 +419,18 @@ static void test_sprintf( void ) format = "asdf%n"; x = 0; r = sprintf(buffer, format, &x ); - ok(x == 4, "should write to x\n"); + if (r == -1) + { + /* %n format is disabled by default on vista */ + /* FIXME: should test with _set_printf_count_output */ + ok(x == 0, "should not write to x: %d\n", x); + } + else + { + ok(x == 4, "should write to x: %d\n", x); ok(!strcmp(buffer,"asdf"), "failed\n"); - ok( r==4, "return count wrong\n"); + ok( r==4, "return count wrong: %d\n", r); + } format = "%-1d"; r = sprintf(buffer, format,2); @@ -391,12 +452,10 @@ static void test_sprintf( void ) ok(!strcmp(buffer,"1"), "failed\n"); ok( r==1, "return count wrong\n"); - todo_wine { format = "%2.4e"; r = sprintf(buffer, format,8.6); ok(!strcmp(buffer,"8.6000e+000"), "failed\n"); ok( r==11, "return count wrong\n"); - } format = "%2.4g"; r = sprintf(buffer, format,8.6); @@ -425,8 +484,16 @@ static void test_sprintf( void ) format = "%p"; r = sprintf(buffer, format,0); + if (sizeof(void *) == 8) + { + ok(!strcmp(buffer,"0000000000000000"), "failed\n"); + ok( r==16, "return count wrong\n"); + } + else + { ok(!strcmp(buffer,"00000000"), "failed\n"); ok( r==8, "return count wrong\n"); + } format = "%s"; r = sprintf(buffer, format,0); @@ -497,10 +564,7 @@ static void test_swprintf( void ) const wchar_t hs[] = {'%', 'h', 's', 0}; swprintf(buffer,TwentyThreePoint15e,pnumber); - todo_wine - { ok(wcsstr(buffer,e008) != 0,"Sprintf different\n"); - } swprintf(buffer,I64d,((ULONGLONG)0xffffffff)*0xffffffff); ok(wcslen(buffer) == 11,"Problem with long long\n"); swprintf(buffer,S,string); @@ -509,16 +573,6 @@ static void test_swprintf( void ) ok( wcscmp(string_w,buffer) == 0, "swprintf failed with %%hs\n"); } -static void test_fwprintf( void ) -{ - const char *string="not a wide string"; - todo_wine - { - ok(fwprintf(fopen("nul","r+"),(const wchar_t *)string) == -1, - "Non-wide string should not be printed by fwprintf\n"); - } -} - static void test_snprintf (void) { struct snprintf_test { @@ -644,11 +698,172 @@ static void test_fcvt(void) ok( 0 == sign, "sign wrong\n"); } +static struct { + double value; + int nrdigits; + const char *expstr_e; + const char *expstr_f; + int expdecpt_e; + int expdecpt_f; + int expsign; +} test_cvt_testcases[] = { + { 45.0, 2, "45", "4500", 2, 2, 0 }, + /* Numbers less than 1.0 with different precisions */ + { 0.0001, 1, "1", "", -3, -3, 0 }, + { 0.0001, -10, "", "", -3, -3, 0 }, + { 0.0001, 10,"1000000000", "1000000", -3, -3, 0 }, + /* Basic sign test */ + { -111.0001, 5, "11100", "11100010", 3, 3, 1 }, + { 111.0001, 5, "11100", "11100010", 3, 3, 0 }, + /* big numbers with low precision */ + { 3333.3, 2, "33", "333330", 4, 4, 0 }, + {999999999999.9, 3, "100","999999999999900", 13, 12, 0 }, + /* 0.0 with different precisions */ + { 0.0, 5, "00000", "00000", 0, 0, 0 }, + { 0.0, 0, "", "", 0, 0, 0 }, + { 0.0, -1, "", "", 0, 0, 0 }, + /* Numbers > 1.0 with 0 or -ve precision */ + { -123.0001, 0, "", "123", 3, 3, 1 }, + { -123.0001, -1, "", "12", 3, 3, 1 }, + { -123.0001, -2, "", "1", 3, 3, 1 }, + { -123.0001, -3, "", "", 3, 3, 1 }, + /* Numbers > 1.0, but with rounding at the point of precision */ + { 99.99, 1, "1", "1000", 3, 3, 0 }, + /* Numbers < 1.0 where rounding occurs at the point of precision */ + { 0.0063, 2, "63", "1", -2, -1, 0 }, + { 0.0063, 3, "630", "6", -2, -2, 0 }, + { 0.09999999996, 2, "10", "10", 0, 0, 0 }, + { 0.6, 1, "6", "6", 0, 0, 0 }, + { 0.6, 0, "", "1", 1, 1, 0 }, + { 0.4, 0, "", "", 0, 0, 0 }, + { 0.49, 0, "", "", 0, 0, 0 }, + { 0.51, 0, "", "1", 1, 1, 0 }, + /* ask ridiculous amunt of precision, ruin formatting this table */ + { 1.0, 30, "100000000000000000000000000000", + "1000000000000000000000000000000", 1, 1, 0}, + { 123456789012345678901.0, 30, "123456789012345680000000000000", + "123456789012345680000000000000000000000000000000000", 21, 21, 0}, + /* end marker */ + { 0, 0, "END"} +}; + +static void test_xcvt(void) +{ + char *str; + int i, decpt, sign; + for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){ + decpt = sign = 100; + str = _ecvt( test_cvt_testcases[i].value, + test_cvt_testcases[i].nrdigits, + &decpt, + &sign); + ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_e, 15), + "_ecvt() bad return, got \n'%s' expected \n'%s'\n", str, + test_cvt_testcases[i].expstr_e); + ok( decpt == test_cvt_testcases[i].expdecpt_e, + "_ecvt() decimal point wrong, got %d expected %d\n", decpt, + test_cvt_testcases[i].expdecpt_e); + } + for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){ + decpt = sign = 100; + str = _fcvt( test_cvt_testcases[i].value, + test_cvt_testcases[i].nrdigits, + &decpt, + &sign); + ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_f, 15), + "_fcvt() bad return, got \n'%s' expected \n'%s'\n", str, + test_cvt_testcases[i].expstr_f); + ok( decpt == test_cvt_testcases[i].expdecpt_f, + "_fcvt() decimal point wrong, got %d expected %d\n", decpt, + test_cvt_testcases[i].expdecpt_f); + ok( sign == test_cvt_testcases[i].expsign, + "_ecvt() sign wrong, got %d expected %d\n", sign, + test_cvt_testcases[i].expsign); + } +} + +static int __cdecl _vsnwprintf_wrapper(wchar_t *str, size_t len, const wchar_t *format, ...) +{ + int ret; + __ms_va_list valist; + __ms_va_start(valist, format); + ret = _vsnwprintf(str, len, format, valist); + __ms_va_end(valist); + return ret; +} + +static void test_vsnwprintf(void) +{ + const wchar_t format[] = {'%','w','s','%','w','s','%','w','s',0}; + const wchar_t one[] = {'o','n','e',0}; + const wchar_t two[] = {'t','w','o',0}; + const wchar_t three[] = {'t','h','r','e','e',0}; + + int ret; + wchar_t str[32]; + char buf[32]; + + ret = _vsnwprintf_wrapper( str, sizeof(str)/sizeof(str[0]), format, one, two, three ); + + ok( ret == 11, "got %d expected 11\n", ret ); + WideCharToMultiByte( CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL ); + ok( !strcmp(buf, "onetwothree"), "got %s expected 'onetwothree'\n", buf ); +} + +static int (__cdecl *p__vscprintf)(const char *format, __ms_va_list valist); +static int (__cdecl *p__vscwprintf)(const wchar_t *format, __ms_va_list valist); + +static int __cdecl _vscprintf_wrapper(const char *format, ...) +{ + int ret; + __ms_va_list valist; + __ms_va_start(valist, format); + ret = p__vscprintf(format, valist); + __ms_va_end(valist); + return ret; +} + +static void test_vscprintf(void) +{ + int ret; + + ret = _vscprintf_wrapper( "%s %d", "number", 1 ); + ok( ret == 8, "got %d expected 8\n", ret ); +} + +static int __cdecl _vscwprintf_wrapper(const wchar_t *format, ...) +{ + int ret; + __ms_va_list valist; + __ms_va_start(valist, format); + ret = p__vscwprintf(format, valist); + __ms_va_end(valist); + return ret; +} + +static void test_vscwprintf(void) +{ + const wchar_t format[] = {'%','s',' ','%','d',0}; + const wchar_t number[] = {'n','u','m','b','e','r',0}; + + int ret; + + ret = _vscwprintf_wrapper( format, number, 1 ); + ok( ret == 8, "got %d expected 8\n", ret ); +} + START_TEST(printf) { test_sprintf(); test_swprintf(); - test_fwprintf(); test_snprintf(); test_fcvt(); + test_xcvt(); + test_vsnwprintf(); + + p__vscprintf = (void *)GetProcAddress(GetModuleHandle("msvcrt.dll"), "_vscprintf"); + p__vscwprintf = (void *)GetProcAddress(GetModuleHandle("msvcrt.dll"), "_vscwprintf"); + + if (p__vscprintf) test_vscprintf(); + if (p__vscwprintf) test_vscwprintf(); } diff --git a/rostests/winetests/msvcrt/scanf.c b/rostests/winetests/msvcrt/scanf.c index 65bea469036..0ec89ff5193 100644 --- a/rostests/winetests/msvcrt/scanf.c +++ b/rostests/winetests/msvcrt/scanf.c @@ -28,6 +28,7 @@ static void test_sscanf( void ) char format[20]; int result, ret; char c; + void *ptr; float res1= -82.6267f, res2= 27.76f, res11, res12; static const char pname[]=" St. Petersburg, Florida\n"; int hour=21,min=59,sec=20; @@ -39,6 +40,33 @@ static void test_sscanf( void ) ret = sscanf(buffer, "%d", &result); ok( ret == EOF,"sscanf returns %x instead of %x\n", ret, EOF ); + /* check %p */ + ok( sscanf("000000000046F170", "%p", &ptr) == 1, "sscanf failed\n" ); + ok( ptr == (void *)0x46F170,"sscanf reads %p instead of %x\n", ptr, 0x46F170 ); + + ok( sscanf("0046F171", "%p", &ptr) == 1, "sscanf failed\n" ); + ok( ptr == (void *)0x46F171,"sscanf reads %p instead of %x\n", ptr, 0x46F171 ); + + ok( sscanf("46F172", "%p", &ptr) == 1, "sscanf failed\n" ); + ok( ptr == (void *)0x46F172,"sscanf reads %p instead of %x\n", ptr, 0x46F172 ); + + ok( sscanf("0x46F173", "%p", &ptr) == 1, "sscanf failed\n" ); + ok( ptr == NULL,"sscanf reads %p instead of %x\n", ptr, 0 ); + + ok( sscanf("-46F174", "%p", &ptr) == 1, "sscanf failed\n" ); + ok( ptr == (void *)(ULONG_PTR)-0x46f174,"sscanf reads %p instead of %p\n", + ptr, (void *)(ULONG_PTR)-0x46f174 ); + + ok( sscanf("+46F175", "%p", &ptr) == 1, "sscanf failed\n" ); + ok( ptr == (void *)0x46F175,"sscanf reads %p instead of %x\n", ptr, 0x46F175 ); + + /* check %p with no hex digits */ + ok( sscanf("1233", "%p", &ptr) == 1, "sscanf failed\n" ); + ok( ptr == (void *)0x1233,"sscanf reads %p instead of %x\n", ptr, 0x1233 ); + + ok( sscanf("1234", "%P", &ptr) == 1, "sscanf failed\n" ); + ok( ptr == (void *)0x1234,"sscanf reads %p instead of %x\n", ptr, 0x1234 ); + /* check %x */ strcpy(buffer,"0x519"); ok( sscanf(buffer, "%x", &result) == 1, "sscanf failed\n" ); diff --git a/rostests/winetests/msvcrt/string.c b/rostests/winetests/msvcrt/string.c index 4febeea2d27..7d4eb88effb 100644 --- a/rostests/winetests/msvcrt/string.c +++ b/rostests/winetests/msvcrt/string.c @@ -26,8 +26,7 @@ #include #include #include - -size_t _mbstrlen(const char*); +#include static char *buf_to_string(const unsigned char *bin, int len, int nr) { @@ -46,8 +45,14 @@ static char *buf_to_string(const unsigned char *bin, int len, int nr) #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); } #define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, "Binary buffer mismatch - expected %s, got %s\n", buf_to_string((unsigned char *)value, len, 1), buf_to_string((buf), len, 0)); } -static void* (*pmemcpy)(void *, const void *, size_t n); -static int* (*pmemcmp)(void *, const void *, size_t n); +static void* (__cdecl *pmemcpy)(void *, const void *, size_t n); +static int* (__cdecl *pmemcmp)(void *, const void *, size_t n); +static int (__cdecl *pstrcpy_s)(char *dst, size_t len, const char *src); +static int (__cdecl *pstrcat_s)(char *dst, size_t len, const char *src); +static int (__cdecl *p_mbsnbcpy_s)(unsigned char * dst, size_t size, const unsigned char * src, size_t count); +static int (__cdecl *p_wcscpy_s)(wchar_t *wcDest, size_t size, const wchar_t *wcSrc); +static int *p__mb_cur_max; +static unsigned char *p_mbctype; #define SETNOFAIL(x,y) x = (void*)GetProcAddress(hMsvcrt,y) #define SET(x,y) SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y) @@ -108,14 +113,14 @@ static void test_codepage(int cp) ok(_setmbcp(cp) == 0, "Couldn't set mbcp\n"); - prev = _mbctype[0]; + prev = p_mbctype[0]; printf("static int result_cp_%d_mbctype[] = { ", cp); for (i = 1; i < 257; i++) { - if (_mbctype[i] != prev) + if (p_mbctype[i] != prev) { printf("0x%x,%d, ", prev, count); - prev = _mbctype[i]; + prev = p_mbctype[i]; count = 1; } else @@ -124,8 +129,6 @@ static void test_codepage(int cp) printf("0x%x,%d };\n", prev, count); } -#define test_codepage_todo(cp, todo) test_codepage(cp) - #else /* RLE-encoded mbctype tables for given codepages */ @@ -138,10 +141,7 @@ static int result_cp_949_mbctype[] = { 0x0,66, 0x18,26, 0x8,6, 0x28,26, 0x8,6, 0 static int result_cp_950_mbctype[] = { 0x0,65, 0x8,1, 0x18,26, 0x8,6, 0x28,26, 0x8,4, 0x0,2, 0x4,32, 0xc,94, 0,1 }; -static int todo_none[] = { -2 }; -static int todo_cp_932[] = { 254, -2 }; -#if 0 -void test_cp_table(int cp, int *result, int *todo) +static void test_cp_table(int cp, int *result) { int i; int count = 0; @@ -155,25 +155,18 @@ void test_cp_table(int cp, int *result, int *todo) count = result[1]; result += 2; } - if (i == *todo + 1) - { - todo_wine ok(_mbctype[i] == curr, "CP%d: Mismatch in ctype for character %d - %d instead of %d\n", cp, i-1, _mbctype[i], curr); - todo++; - } - else - ok(_mbctype[i] == curr, "CP%d: Mismatch in ctype for character %d - %d instead of %d\n", cp, i-1, _mbctype[i], curr); + ok(p_mbctype[i] == curr, "CP%d: Mismatch in ctype for character %d - %d instead of %d\n", cp, i-1, p_mbctype[i], curr); count--; } } -#define test_codepage(num) test_cp_table(num, result_cp_##num##_mbctype, todo_none); -#define test_codepage_todo(num, todo) test_cp_table(num, result_cp_##num##_mbctype, todo); -#endif +#define test_codepage(num) test_cp_table(num, result_cp_##num##_mbctype); + #endif static void test_mbcp(void) { - int mb_orig_max = __mb_cur_max; + int mb_orig_max = *p__mb_cur_max; int curr_mbcp = _getmbcp(); unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2 \xb3\xb4 \xb5"; /* incorrect string */ unsigned char *mbstring2 = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5"; /* correct string */ @@ -187,26 +180,26 @@ static void test_mbcp(void) * between versions of Windows. Also Windows 9x seems to ignore the codepage and always uses * CP1252 (or the ACP?) so we test only a few ASCII characters */ _setmbcp(1252); - expect_eq(_mbctype[10], 0, char, "%x"); - expect_eq(_mbctype[50], 0, char, "%x"); - expect_eq(_mbctype[66], _SBUP, char, "%x"); - expect_eq(_mbctype[100], _SBLOW, char, "%x"); - expect_eq(_mbctype[128], 0, char, "%x"); + expect_eq(p_mbctype[10], 0, char, "%x"); + expect_eq(p_mbctype[50], 0, char, "%x"); + expect_eq(p_mbctype[66], _SBUP, char, "%x"); + expect_eq(p_mbctype[100], _SBLOW, char, "%x"); + expect_eq(p_mbctype[128], 0, char, "%x"); _setmbcp(1250); - expect_eq(_mbctype[10], 0, char, "%x"); - expect_eq(_mbctype[50], 0, char, "%x"); - expect_eq(_mbctype[66], _SBUP, char, "%x"); - expect_eq(_mbctype[100], _SBLOW, char, "%x"); - expect_eq(_mbctype[128], 0, char, "%x"); + expect_eq(p_mbctype[10], 0, char, "%x"); + expect_eq(p_mbctype[50], 0, char, "%x"); + expect_eq(p_mbctype[66], _SBUP, char, "%x"); + expect_eq(p_mbctype[100], _SBLOW, char, "%x"); + expect_eq(p_mbctype[128], 0, char, "%x"); /* double byte code pages */ - //test_codepage_todo(932, todo_cp_932); - //test_codepage(936); - //test_codepage(949); - //test_codepage(950); + test_codepage(932); + test_codepage(936); + test_codepage(949); + test_codepage(950); _setmbcp(936); - ok(__mb_cur_max == mb_orig_max, "__mb_cur_max shouldn't be updated (is %d != %d)\n", __mb_cur_max, mb_orig_max); + ok(*p__mb_cur_max == mb_orig_max, "__mb_cur_max shouldn't be updated (is %d != %d)\n", *p__mb_cur_max, mb_orig_max); ok(_ismbblead('\354'), "\354 should be a lead byte\n"); ok(_ismbblead(' ') == FALSE, "' ' should not be a lead byte\n"); ok(_ismbblead(0x1234b0), "0x1234b0 should not be a lead byte\n"); @@ -343,7 +336,7 @@ static void test_mbcp(void) * we hope the current locale to be SBCS because setlocale(LC_ALL, ".1252") seems not to work yet * (as of Wine 0.9.43) */ - if (__mb_cur_max == 1) + if (*p__mb_cur_max == 1) { expect_eq(mblen((char *)mbstring, 3), 1, int, "%x"); expect_eq(_mbstrlen((char *)mbstring2), 7, int, "%d"); @@ -395,6 +388,321 @@ static void test_strdup(void) free( str ); } +static void test_strcpy_s(void) +{ + char dest[8]; + const char *small = "small"; + const char *big = "atoolongstringforthislittledestination"; + int ret; + + if(!pstrcpy_s) + { + skip("strcpy_s not found\n"); + return; + } + + memset(dest, 'X', sizeof(dest)); + ret = pstrcpy_s(dest, sizeof(dest), small); + ok(ret == 0, "Copying a string into a big enough destination returned %d, expected 0\n", ret); + ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == 'l' && + dest[4] == 'l' && dest[5] == '\0'&& dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + memset(dest, 'X', sizeof(dest)); + ret = pstrcpy_s(dest, 0, big); + ok(ret == EINVAL, "Copying into a destination of size 0 returned %d, expected EINVAL\n", ret); + ok(dest[0] == 'X' && dest[1] == 'X' && dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + ret = pstrcpy_s(dest, 0, NULL); + ok(ret == EINVAL, "Copying into a destination of size 0 returned %d, expected EINVAL\n", ret); + ok(dest[0] == 'X' && dest[1] == 'X' && dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + memset(dest, 'X', sizeof(dest)); + ret = pstrcpy_s(dest, sizeof(dest), big); + ok(ret == ERANGE, "Copying a big string in a small location returned %d, expected ERANGE\n", ret); + ok(dest[0] == '\0'&& dest[1] == 't' && dest[2] == 'o' && dest[3] == 'o' && + dest[4] == 'l' && dest[5] == 'o' && dest[6] == 'n' && dest[7] == 'g', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + memset(dest, 'X', sizeof(dest)); + ret = pstrcpy_s(dest, sizeof(dest), NULL); + ok(ret == EINVAL, "Copying from a NULL source string returned %d, expected EINVAL\n", ret); + ok(dest[0] == '\0'&& dest[1] == 'X' && dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcpy_s(NULL, sizeof(dest), small); + ok(ret == EINVAL, "Copying a big string a NULL dest returned %d, expected EINVAL\n", ret); +} + +static void test_strcat_s(void) +{ + char dest[8]; + const char *small = "sma"; + int ret; + + if(!pstrcat_s) + { + skip("strcat_s not found\n"); + return; + } + + memset(dest, 'X', sizeof(dest)); + dest[0] = '\0'; + ret = pstrcat_s(dest, sizeof(dest), small); + ok(ret == 0, "strcat_s: Copying a string into a big enough destination returned %d, expected 0\n", ret); + ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == '\0'&& + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + ret = pstrcat_s(dest, sizeof(dest), small); + ok(ret == 0, "strcat_s: Attaching a string to a big enough destination returned %d, expected 0\n", ret); + ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == 's' && + dest[4] == 'm' && dest[5] == 'a' && dest[6] == '\0'&& dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcat_s(dest, sizeof(dest), small); + ok(ret == ERANGE, "strcat_s: Attaching a string to a filled up destination returned %d, expected ERANGE\n", ret); + ok(dest[0] == '\0'&& dest[1] == 'm' && dest[2] == 'a' && dest[3] == 's' && + dest[4] == 'm' && dest[5] == 'a' && dest[6] == 's' && dest[7] == 'm', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + memset(dest, 'X', sizeof(dest)); + dest[0] = 'a'; + dest[1] = '\0'; + + ret = pstrcat_s(dest, 0, small); + ok(ret == EINVAL, "strcat_s: Source len = 0 returned %d, expected EINVAL\n", ret); + ok(dest[0] == 'a' && dest[1] == '\0'&& dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcat_s(dest, 0, NULL); + ok(ret == EINVAL, "strcat_s: len = 0 and src = NULL returned %d, expected EINVAL\n", ret); + ok(dest[0] == 'a' && dest[1] == '\0'&& dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcat_s(dest, sizeof(dest), NULL); + ok(ret == EINVAL, "strcat_s: Sourcing from NULL returned %d, expected EINVAL\n", ret); + ok(dest[0] == '\0'&& dest[1] == '\0'&& dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcat_s(NULL, sizeof(dest), small); + ok(ret == EINVAL, "strcat_s: Writing to a NULL string returned %d, expected EINVAL\n", ret); +} + +static void test__mbsnbcpy_s(void) +{ + unsigned char dest[8]; + const unsigned char big[] = "atoolongstringforthislittledestination"; + const unsigned char small[] = "small"; + int ret; + + if(!p_mbsnbcpy_s) + { + skip("_mbsnbcpy_s not found\n"); + return; + } + + memset(dest, 'X', sizeof(dest)); + ret = p_mbsnbcpy_s(dest, sizeof(dest), small, sizeof(small)); + ok(ret == 0, "_mbsnbcpy_s: Copying a string into a big enough destination returned %d, expected 0\n", ret); + ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == 'l' && + dest[4] == 'l' && dest[5] == '\0'&& dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from _mbsnbcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + /* WTF? */ + memset(dest, 'X', sizeof(dest)); + ret = p_mbsnbcpy_s(dest, sizeof(dest) - 2, big, sizeof(small)); + ok(ret == ERANGE, "_mbsnbcpy_s: Copying a too long string returned %d, expected ERANGE\n", ret); + ok(dest[0] == '\0'&& dest[1] == 't' && dest[2] == 'o' && dest[3] == 'o' && + dest[4] == 'l' && dest[5] == 'o' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from _mbsnbcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + memset(dest, 'X', sizeof(dest)); + ret = p_mbsnbcpy_s(dest, sizeof(dest) - 2, big, 4); + ok(ret == 0, "_mbsnbcpy_s: Copying a too long string with a count cap returned %d, expected 0\n", ret); + ok(dest[0] == 'a' && dest[1] == 't' && dest[2] == 'o' && dest[3] == 'o' && + dest[4] == '\0'&& dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from _mbsnbcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + memset(dest, 'X', sizeof(dest)); + ret = p_mbsnbcpy_s(dest, sizeof(dest) - 2, small, sizeof(small) + 10); + ok(ret == 0, "_mbsnbcpy_s: Copying more data than the source string len returned %d, expected 0\n", ret); + ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == 'l' && + dest[4] == 'l' && dest[5] == '\0'&& dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from _mbsnbcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); +} + +static void test_wcscpy_s(void) +{ + static const WCHAR szLongText[] = { 'T','h','i','s','A','L','o','n','g','s','t','r','i','n','g',0 }; + static WCHAR szDest[18]; + static WCHAR szDestShort[8]; + int ret; + + if(!p_wcscpy_s) + { + skip("wcscpy_s not found\n"); + return; + } + + /* Test NULL Dest */ + ret = p_wcscpy_s(NULL, 18, szLongText); + ok(ret == EINVAL, "p_wcscpy_s expect EINVAL got %d\n", ret); + + /* Test NULL Source */ + szDest[0] = 'A'; + ret = p_wcscpy_s(szDest, 18, NULL); + ok(ret == EINVAL, "expected EINVAL got %d\n", ret); + ok(szDest[0] == 0, "szDest[0] not 0\n"); + + /* Test invalid size */ + szDest[0] = 'A'; + ret = p_wcscpy_s(szDest, 0, szLongText); + /* Later versions changed the return value for this case to EINVAL, + * and don't modify the result if the dest size is 0. + */ + ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret); + ok(szDest[0] == 0 || ret == EINVAL, "szDest[0] not 0\n"); + + /* Copy same buffer size */ + ret = p_wcscpy_s(szDest, 18, szLongText); + ok(ret == 0, "expected 0 got %d\n", ret); + ok(lstrcmpW(szDest, szLongText) == 0, "szDest != szLongText\n"); + + /* Copy smaller buffer size */ + szDest[0] = 'A'; + ret = p_wcscpy_s(szDestShort, 8, szLongText); + ok(ret == ERANGE || ret == EINVAL, "expected ERANGE/EINVAL got %d\n", ret); + ok(szDestShort[0] == 0, "szDestShort[0] not 0\n"); +} + +static void test_mbcjisjms(void) +{ + /* List of value-pairs to test. The test assumes the last pair to be {0, ..} */ + unsigned int jisjms[][2] = { {0x2020, 0}, {0x2021, 0}, {0x2120, 0}, {0x2121, 0x8140}, + {0x7f7f, 0}, {0x7f7e, 0}, {0x7e7f, 0}, {0x7e7e, 0xeffc}, + {0x2121FFFF, 0}, {0x2223, 0x81a1}, {0x237e, 0x829e}, {0, 0}}; + unsigned int ret, exp, i; + + i = 0; + do + { + ret = _mbcjistojms(jisjms[i][0]); + + if(_getmbcp() == 932) /* Japanese codepage? */ + exp = jisjms[i][1]; + else + exp = jisjms[i][0]; /* If not, no conversion */ + + ok(ret == exp, "Expected 0x%x, got 0x%x\n", exp, ret); + } while(jisjms[i++][0] != 0); +} + +static const struct { + const char* string; + const char* delimiter; + int exp_offsetret1; /* returned offset from string after first call to strtok() + -1 means NULL */ + int exp_offsetret2; /* returned offset from string after second call to strtok() + -1 means NULL */ + int exp_offsetret3; /* returned offset from string after third call to strtok() + -1 means NULL */ +} testcases_strtok[] = { + { "red cabernet", " ", 0, 4, -1 }, + { "sparkling white riesling", " ", 0, 10, 16 }, + { " pale cream sherry", "e ", 1, 6, 9 }, + /* end mark */ + { 0} +}; + +static void test_strtok(void) +{ + int i; + char *strret; + char teststr[100]; + for( i = 0; testcases_strtok[i].string; i++){ + strcpy( teststr, testcases_strtok[i].string); + strret = strtok( teststr, testcases_strtok[i].delimiter); + ok( (int)(strret - teststr) == testcases_strtok[i].exp_offsetret1 || + (!strret && testcases_strtok[i].exp_offsetret1 == -1), + "string (%p) \'%s\' return %p\n", + teststr, testcases_strtok[i].string, strret); + if( !strret) continue; + strret = strtok( NULL, testcases_strtok[i].delimiter); + ok( (int)(strret - teststr) == testcases_strtok[i].exp_offsetret2 || + (!strret && testcases_strtok[i].exp_offsetret2 == -1), + "second call string (%p) \'%s\' return %p\n", + teststr, testcases_strtok[i].string, strret); + if( !strret) continue; + strret = strtok( NULL, testcases_strtok[i].delimiter); + ok( (int)(strret - teststr) == testcases_strtok[i].exp_offsetret3 || + (!strret && testcases_strtok[i].exp_offsetret3 == -1), + "third call string (%p) \'%s\' return %p\n", + teststr, testcases_strtok[i].string, strret); + } +} + +static void test_strtol(void) +{ + char* e; + LONG l; + ULONG ul; + + /* errno is only set in case of error, so reset errno to EBADF to check for errno modification */ + /* errno is modified on W2K8+ */ + errno = EBADF; + l = strtol("-1234", &e, 0); + ok(l==-1234, "wrong value %d\n", l); + ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); + errno = EBADF; + ul = strtoul("1234", &e, 0); + ok(ul==1234, "wrong value %u\n", ul); + ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); + + errno = EBADF; + l = strtol("2147483647L", &e, 0); + ok(l==2147483647, "wrong value %d\n", l); + ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); + errno = EBADF; + l = strtol("-2147483648L", &e, 0); + ok(l==-2147483647L - 1, "wrong value %d\n", l); + ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); + errno = EBADF; + ul = strtoul("4294967295UL", &e, 0); + ok(ul==4294967295ul, "wrong value %u\n", ul); + ok(errno == EBADF || broken(errno == 0), "wrong errno %d\n", errno); + + errno = 0; + l = strtol("9223372036854775807L", &e, 0); + ok(l==2147483647, "wrong value %d\n", l); + ok(errno == ERANGE, "wrong errno %d\n", errno); + errno = 0; + ul = strtoul("9223372036854775807L", &e, 0); + ok(ul==4294967295ul, "wrong value %u\n", ul); + ok(errno == ERANGE, "wrong errno %d\n", errno); +} + START_TEST(string) { char mem[100]; @@ -407,6 +715,12 @@ START_TEST(string) ok(hMsvcrt != 0, "GetModuleHandleA failed\n"); SET(pmemcpy,"memcpy"); SET(pmemcmp,"memcmp"); + SET(p_mbctype,"_mbctype"); + SET(p__mb_cur_max,"__mb_cur_max"); + pstrcpy_s = (void *)GetProcAddress( hMsvcrt,"strcpy_s" ); + pstrcat_s = (void *)GetProcAddress( hMsvcrt,"strcat_s" ); + p_mbsnbcpy_s = (void *)GetProcAddress( hMsvcrt,"_mbsnbcpy_s" ); + p_wcscpy_s = (void *)GetProcAddress( hMsvcrt,"wcscpy_s" ); /* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -426,4 +740,11 @@ START_TEST(string) test_mbsspnp(); /* test _strdup */ test_strdup(); + test_strcpy_s(); + test_strcat_s(); + test__mbsnbcpy_s(); + test_mbcjisjms(); + test_strtok(); + test_wcscpy_s(); + test_strtol(); } diff --git a/rostests/winetests/msvcrt/time.c b/rostests/winetests/msvcrt/time.c index 1fe6cbf3340..cf287460d17 100644 --- a/rostests/winetests/msvcrt/time.c +++ b/rostests/winetests/msvcrt/time.c @@ -20,6 +20,7 @@ #include "wine/test.h" #include "winbase.h" +#include "winnls.h" #include "time.h" #include /*setenv*/ @@ -31,9 +32,29 @@ #define MINSPERHOUR 60 #define HOURSPERDAY 24 +static int get_test_year(time_t *start) +{ + time_t now = time(NULL); + struct tm *tm = localtime(&now); + + /* compute start of year in seconds */ + *start = SECSPERDAY * ((tm->tm_year - 70) * 365 + + (tm->tm_year - 69) / 4 - + (tm->tm_year - 1) / 100 + + (tm->tm_year + 299) / 400); + return tm->tm_year; +} + +static void test_ctime(void) +{ + time_t badtime = -1; + char* ret; + ret = ctime(&badtime); + ok(ret == NULL, "expected ctime to return NULL, got %s\n", ret); +} static void test_gmtime(void) { - time_t gmt = (time_t)NULL; + time_t gmt = 0; struct tm* gmt_tm = gmtime(&gmt); if(gmt_tm == 0) { @@ -56,11 +77,21 @@ static void test_mktime(void) struct tm my_tm, sav_tm; time_t nulltime, local_time; char TZ_env[256]; - int secs; + char buffer[64]; + int year; + time_t ref, secs; + + year = get_test_year( &ref ); + ref += SECSPERDAY; ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n"); + WideCharToMultiByte( CP_ACP, 0, tzinfo.StandardName, -1, buffer, sizeof(buffer), NULL, NULL ); + trace( "bias %d std %d dst %d zone %s\n", + tzinfo.Bias, tzinfo.StandardBias, tzinfo.DaylightBias, buffer ); /* Bias may be positive or negative, to use offset of one day */ + my_tm = *localtime(&ref); /* retrieve current dst flag */ secs= SECSPERDAY - tzinfo.Bias * SECSPERMIN; + secs -= (my_tm.tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN; my_tm.tm_mday = 1 + secs/SECSPERDAY; secs = secs % SECSPERDAY; my_tm.tm_hour = secs / SECSPERHOUR; @@ -69,22 +100,21 @@ static void test_mktime(void) secs = secs % SECSPERMIN; my_tm.tm_sec = secs; - my_tm.tm_year = 70; + my_tm.tm_year = year; my_tm.tm_mon = 0; - my_tm.tm_isdst= 0; sav_tm = my_tm; local_time = mktime(&my_tm); - ok(((DWORD)local_time == SECSPERDAY), "mktime returned %u, expected %u\n", - (DWORD)local_time, SECSPERDAY); + ok(local_time == ref, "mktime returned %u, expected %u\n", + (DWORD)local_time, (DWORD)ref); /* now test some unnormalized struct tm's */ my_tm = sav_tm; my_tm.tm_sec += 60; my_tm.tm_min -= 1; local_time = mktime(&my_tm); - ok(((DWORD)local_time == SECSPERDAY), "Unnormalized mktime returned %u, expected %u\n", - (DWORD)local_time, SECSPERDAY); + ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", + (DWORD)local_time, (DWORD)ref); ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && my_tm.tm_sec == sav_tm.tm_sec, @@ -97,8 +127,8 @@ static void test_mktime(void) my_tm.tm_min -= 60; my_tm.tm_hour += 1; local_time = mktime(&my_tm); - ok(((DWORD)local_time == SECSPERDAY), "Unnormalized mktime returned %u, expected %u\n", - (DWORD)local_time, SECSPERDAY); + ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", + (DWORD)local_time, (DWORD)ref); ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && my_tm.tm_sec == sav_tm.tm_sec, @@ -111,8 +141,8 @@ static void test_mktime(void) my_tm.tm_mon -= 12; my_tm.tm_year += 1; local_time = mktime(&my_tm); - ok(((DWORD)local_time == SECSPERDAY), "Unnormalized mktime returned %u, expected %u\n", - (DWORD)local_time, SECSPERDAY); + ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", + (DWORD)local_time, (DWORD)ref); ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && my_tm.tm_sec == sav_tm.tm_sec, @@ -125,8 +155,8 @@ static void test_mktime(void) my_tm.tm_mon += 12; my_tm.tm_year -= 1; local_time = mktime(&my_tm); - ok(((DWORD)local_time == SECSPERDAY), "Unnormalized mktime returned %u, expected %u\n", - (DWORD)local_time, SECSPERDAY); + ok(local_time == ref, "Unnormalized mktime returned %u, expected %u\n", + (DWORD)local_time, (DWORD)ref); ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon && my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour && my_tm.tm_sec == sav_tm.tm_sec, @@ -137,7 +167,7 @@ static void test_mktime(void) sav_tm.tm_hour,sav_tm.tm_sec); /* now a bad time example */ my_tm = sav_tm; - my_tm.tm_year -= 1; + my_tm.tm_year = 69; local_time = mktime(&my_tm); ok((local_time == -1), "(bad time) mktime returned %d, expected -1\n", (int)local_time); @@ -147,7 +177,7 @@ static void test_mktime(void) _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):"")); putenv("TZ=GMT"); nulltime = mktime(&my_tm); - ok(((DWORD)nulltime == SECSPERDAY),"mktime returned 0x%08x\n",(DWORD)nulltime); + ok(nulltime == ref,"mktime returned 0x%08x\n",(DWORD)nulltime); putenv(TZ_env); } @@ -155,16 +185,21 @@ static void test_localtime(void) { TIME_ZONE_INFORMATION tzinfo; DWORD res = GetTimeZoneInformation(&tzinfo); - time_t gmt = (time_t)(SECSPERDAY + tzinfo.Bias * SECSPERMIN); + time_t gmt, ref; char TZ_env[256]; struct tm* lt; + int year = get_test_year( &ref ); + int is_leap = !(year % 4) && ((year % 100) || !((year + 300) % 400)); + gmt = ref + SECSPERDAY + tzinfo.Bias * SECSPERMIN; ok (res != TIME_ZONE_ID_INVALID, "GetTimeZoneInformation failed\n"); lt = localtime(&gmt); - ok(((lt->tm_year == 70) && (lt->tm_mon == 0) && (lt->tm_yday == 1) && - (lt->tm_mday == 2) && (lt->tm_wday == 5) && (lt->tm_hour == 0) && - (lt->tm_min == 0) && (lt->tm_sec == 0) && (lt->tm_isdst == 0)), + gmt += (lt->tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN; + lt = localtime(&gmt); + ok(((lt->tm_year == year) && (lt->tm_mon == 0) && (lt->tm_yday == 1) && + (lt->tm_mday == 2) && (lt->tm_hour == 0) && + (lt->tm_min == 0) && (lt->tm_sec == 0)), "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n", lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, lt->tm_min, lt->tm_sec, lt->tm_isdst); @@ -172,21 +207,21 @@ static void test_localtime(void) _snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):"")); putenv("TZ=GMT"); lt = localtime(&gmt); - ok(((lt->tm_year == 70) && (lt->tm_mon == 0) && (lt->tm_yday == 1) && - (lt->tm_mday == 2) && (lt->tm_wday == 5) && (lt->tm_hour == 0) && - (lt->tm_min == 0) && (lt->tm_sec == 0) && (lt->tm_isdst == 0)), + ok(((lt->tm_year == year) && (lt->tm_mon == 0) && (lt->tm_yday == 1) && + (lt->tm_mday == 2) && (lt->tm_hour == 0) && + (lt->tm_min == 0) && (lt->tm_sec == 0)), "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n", lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, lt->tm_min, lt->tm_sec, lt->tm_isdst); putenv(TZ_env); /* June 22 */ - gmt += 201 * SECSPERDAY; + gmt = ref + 202 * SECSPERDAY + tzinfo.Bias * SECSPERMIN; lt = localtime(&gmt); gmt += (lt->tm_isdst ? tzinfo.DaylightBias : tzinfo.StandardBias) * SECSPERMIN; lt = localtime(&gmt); - ok(((lt->tm_year == 70) && (lt->tm_mon == 6) && (lt->tm_yday == 202) && - (lt->tm_mday == 22) && (lt->tm_wday == 3) && (lt->tm_hour == 0) && + ok(((lt->tm_year == year) && (lt->tm_mon == 6) && (lt->tm_yday == 202) && + (lt->tm_mday == 22 - is_leap) && (lt->tm_hour == 0) && (lt->tm_min == 0) && (lt->tm_sec == 0)), "Wrong date:Year %d mon %d yday %d mday %d wday %d hour %d min %d sec %d dst %d\n", lt->tm_year, lt->tm_mon, lt->tm_yday, lt->tm_mday, lt->tm_wday, lt->tm_hour, @@ -249,6 +284,7 @@ static void test_wstrtime(void) START_TEST(time) { + test_ctime(); test_gmtime(); test_mktime(); test_localtime(); diff --git a/rostests/winetests/msvcrtd/debug.c b/rostests/winetests/msvcrtd/debug.c new file mode 100644 index 00000000000..fbfcdc5ea4d --- /dev/null +++ b/rostests/winetests/msvcrtd/debug.c @@ -0,0 +1,73 @@ +/* + * Unit test suite for debug functions. + * + * Copyright 2004 Patrik Stridvall + * + * 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 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnt.h" + +#include "crtdbg.h" + +#include "wine/test.h" + +/**********************************************************************/ + +static void * (*pMSVCRTD_operator_new_dbg)(unsigned long, int, const char *, int) = NULL; + +/* Some exports are only available in later versions */ +#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hModule,y) +#define SET(x,y) SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y) + +static int init_functions(void) +{ + HMODULE hModule = LoadLibraryA("msvcrtd.dll"); + + if (!hModule) { + trace("LoadLibraryA failed to load msvcrtd.dll with GLE=%d\n", GetLastError()); + return FALSE; + } + + SET(pMSVCRTD_operator_new_dbg, "??2@YAPAXIHPBDH@Z"); + if (pMSVCRTD_operator_new_dbg == NULL) + return FALSE; + + return TRUE; +} + +/**********************************************************************/ + +static void test_new(void) +{ + void *mem; + + mem = pMSVCRTD_operator_new_dbg(42, _NORMAL_BLOCK, __FILE__, __LINE__); + ok(mem != NULL, "memory not allocated\n"); +} + +/**********************************************************************/ + +START_TEST(debug) +{ + if (!init_functions()) + return; + + test_new(); +} diff --git a/rostests/winetests/msvcrtd/msvcrtd.rbuild b/rostests/winetests/msvcrtd/msvcrtd.rbuild new file mode 100644 index 00000000000..3c77e151cbc --- /dev/null +++ b/rostests/winetests/msvcrtd/msvcrtd.rbuild @@ -0,0 +1,8 @@ + + . + + debug.c + testlist.c + wine + ntdll + diff --git a/rostests/winetests/msvcrtd/testlist.c b/rostests/winetests/msvcrtd/testlist.c new file mode 100644 index 00000000000..e17c0185376 --- /dev/null +++ b/rostests/winetests/msvcrtd/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_debug(void); + +const struct test winetest_testlist[] = +{ + { "debug", func_debug }, + { 0, 0 } +}; diff --git a/rostests/winetests/msvfw32/msvfw.c b/rostests/winetests/msvfw32/msvfw.c new file mode 100644 index 00000000000..b0d820815a1 --- /dev/null +++ b/rostests/winetests/msvfw32/msvfw.c @@ -0,0 +1,69 @@ +/* + * Unit tests for video playback + * + * Copyright 2008 Jörg Höhle + * Copyright 2008 Austin English + * + * 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 + */ + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "wine/test.h" + +static void test_OpenCase(void) +{ + HIC h; + /* Open a compressor with combinations of lowercase + * and uppercase compressortype and handler. + */ + h = ICOpen(mmioFOURCC('v','i','d','c'),mmioFOURCC('m','s','v','c'),ICMODE_DECOMPRESS); + ok(0!=h,"ICOpen(vidc.msvc) failed\n"); + if (h) { + ok(ICClose(h)==ICERR_OK,"ICClose failed\n"); + } + h = ICOpen(mmioFOURCC('v','i','d','c'),mmioFOURCC('M','S','V','C'),ICMODE_DECOMPRESS); + ok(0!=h,"ICOpen(vidc.MSVC) failed\n"); + if (h) { + ok(ICClose(h)==ICERR_OK,"ICClose failed\n"); + } + h = ICOpen(mmioFOURCC('V','I','D','C'),mmioFOURCC('m','s','v','c'),ICMODE_DECOMPRESS); + ok(0!=h,"ICOpen(VIDC.msvc) failed\n"); + if (h) { + ok(ICClose(h)==ICERR_OK,"ICClose failed\n"); + } + h = ICOpen(mmioFOURCC('V','I','D','C'),mmioFOURCC('M','S','V','C'),ICMODE_DECOMPRESS); + ok(0!=h,"ICOpen(VIDC.MSVC) failed\n"); + if (h) { + ok(ICClose(h)==ICERR_OK,"ICClose failed\n"); + } + h = ICOpen(mmioFOURCC('v','i','d','c'),mmioFOURCC('m','S','v','C'),ICMODE_DECOMPRESS); + ok(0!=h,"ICOpen(vidc.mSvC) failed\n"); + if (h) { + ok(ICClose(h)==ICERR_OK,"ICClose failed\n"); + } + h = ICOpen(mmioFOURCC('v','I','d','C'),mmioFOURCC('m','s','v','c'),ICMODE_DECOMPRESS); + ok(0!=h,"ICOpen(vIdC.msvc) failed\n"); + if (h) { + ok(ICClose(h)==ICERR_OK,"ICClose failed\n"); + } +} + +START_TEST(msvfw) +{ + test_OpenCase(); +} diff --git a/rostests/winetests/msvfw32/msvfw32.rbuild b/rostests/winetests/msvfw32/msvfw32.rbuild new file mode 100644 index 00000000000..2328b4f5b33 --- /dev/null +++ b/rostests/winetests/msvfw32/msvfw32.rbuild @@ -0,0 +1,9 @@ + + . + + msvfw.c + testlist.c + wine + msvfw32 + ntdll + diff --git a/rostests/winetests/msvfw32/testlist.c b/rostests/winetests/msvfw32/testlist.c new file mode 100644 index 00000000000..1aa529c6574 --- /dev/null +++ b/rostests/winetests/msvfw32/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_msvfw(void); + +const struct test winetest_testlist[] = +{ + { "msvfw", func_msvfw }, + { 0, 0 } +}; diff --git a/rostests/winetests/msxml3/domdoc.c b/rostests/winetests/msxml3/domdoc.c new file mode 100644 index 00000000000..de78b6550ce --- /dev/null +++ b/rostests/winetests/msxml3/domdoc.c @@ -0,0 +1,4460 @@ +/* + * XML test + * + * Copyright 2005 Mike McCormack for CodeWeavers + * Copyright 2007-2008 Alistair Leslie-Hughes + * + * 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 + */ + + +#define COBJMACROS + +#include "windows.h" +#include "ole2.h" +#include "xmldom.h" +#include "msxml2.h" +#include "msxml2did.h" +#include "dispex.h" +#include +#include + +#include "wine/test.h" + +static const WCHAR szEmpty[] = { 0 }; +static const WCHAR szIncomplete[] = { + '<','?','x','m','l',' ', + 'v','e','r','s','i','o','n','=','\'','1','.','0','\'','?','>','\n',0 +}; +static const WCHAR szComplete1[] = { + '<','?','x','m','l',' ', + 'v','e','r','s','i','o','n','=','\'','1','.','0','\'','?','>','\n', + '<','o','p','e','n','>','<','/','o','p','e','n','>','\n',0 +}; +static const WCHAR szComplete2[] = { + '<','?','x','m','l',' ', + 'v','e','r','s','i','o','n','=','\'','1','.','0','\'','?','>','\n', + '<','o','>','<','/','o','>','\n',0 +}; +static const WCHAR szComplete3[] = { + '<','?','x','m','l',' ', + 'v','e','r','s','i','o','n','=','\'','1','.','0','\'','?','>','\n', + '<','a','>','<','/','a','>','\n',0 +}; +static const WCHAR szComplete4[] = { + '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\'','1','.','0','\'','?','>','\n', + '<','l','c',' ','d','l','=','\'','s','t','r','1','\'','>','\n', + '<','b','s',' ','v','r','=','\'','s','t','r','2','\'',' ','s','z','=','\'','1','2','3','4','\'','>', + 'f','n','1','.','t','x','t','\n', + '<','/','b','s','>','\n', + '<','p','r',' ','i','d','=','\'','s','t','r','3','\'',' ','v','r','=','\'','1','.','2','.','3','\'',' ', + 'p','n','=','\'','w','i','n','e',' ','2','0','0','5','0','8','0','4','\'','>','\n', + 'f','n','2','.','t','x','t','\n', + '<','/','p','r','>','\n', + '<','e','m','p','t','y','>','<','/','e','m','p','t','y','>','\n', + '<','f','o','>','\n', + '<','b','a','>','\n', + 'f','1','\n', + '<','/','b','a','>','\n', + '<','/','f','o','>','\n', + '<','/','l','c','>','\n',0 +}; +static const WCHAR szComplete5[] = { + '<','S',':','s','e','a','r','c','h',' ','x','m','l','n','s',':','D','=','"','D','A','V',':','"',' ', + 'x','m','l','n','s',':','C','=','"','u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','o','f','f','i','c','e',':','c','l','i','p','g','a','l','l','e','r','y','"', + ' ','x','m','l','n','s',':','S','=','"','u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','o','f','f','i','c','e',':','c','l','i','p','g','a','l','l','e','r','y',':','s','e','a','r','c','h','"','>', + '<','S',':','s','c','o','p','e','>', + '<','S',':','d','e','e','p','>','/','<','/','S',':','d','e','e','p','>', + '<','/','S',':','s','c','o','p','e','>', + '<','S',':','c','o','n','t','e','n','t','f','r','e','e','t','e','x','t','>', + '<','C',':','t','e','x','t','o','r','p','r','o','p','e','r','t','y','/','>', + 'c','o','m','p','u','t','e','r', + '<','/','S',':','c','o','n','t','e','n','t','f','r','e','e','t','e','x','t','>', + '<','/','S',':','s','e','a','r','c','h','>',0 +}; + +static const CHAR szExampleXML[] = +"\n" +"\n" +" \n" +" A1 field\n" +" B1 field\n" +" C1 field\n" +" \n" +" \n" +" This is a description. \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" A2 field\n" +" B2 field\n" +" C2 field\n" +" \n" +"\n" +" \n" +" A3 field\n" +" B3 field\n" +" C3 field\n" +" \n" +"\n" +" \n" +" A4 field\n" +" B4 field\n" +" C4 field\n" +" \n" +"\n"; + +static const CHAR szTransformXML[] = +"\n" +"\n" +"Hello World\n" +""; + +static const CHAR szTransformSSXML[] = +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"

\n" +" \n" +"

\n" +" \n" +" \n" +"
\n" +"
"; + +static const CHAR szTransformOutput[] = +"

" +"Hello World" +"

"; + +static const CHAR szTypeValueXML[] = +"\n" +"\n" +" Wine\n" +" String\n" +" 12.44\n" +" -3.71e3\n" +" -13\n" +" 7322.9371\n" +" 1\n" +" 2009-11-18T03:21:33.12\n" +" 2003-07-11T11:13:57+03:00\n" +" 3721-11-01\n" +" \n" +" 23:21:01.13+03:21\n" +" -13\n" +" 31915\n" +" -312232\n" +" 123\n" +" 48282\n" +" 949281\n" +" 213124.0\n" +" 0.412\n" +" 41221.421\n" +" 333C7BC4-460F-11D0-BC04-0080C7055a83\n" +" fffca012003c\n" +" YmFzZTY0IHRlc3Q=\n" +""; + +static const CHAR szBasicTransformSSXMLPart1[] = +"" +"" +"\n" +"" +"" +" " +" " +" " +"
" +"
" +"" +" " +"" +"" +" " +"" +"" +" " +"" +"
"; + +static const CHAR szBasicTransformXML[] = +"Wine$25.00"; + +static const CHAR szBasicTransformOutput[] = +"
Wine$25.00
"; + +static const WCHAR szNonExistentFile[] = { + 'c', ':', '\\', 'N', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', '.', 'x', 'm', 'l', 0 +}; +static const WCHAR szNonExistentAttribute[] = { + 'n','o','n','E','x','i','s','i','t','i','n','g','A','t','t','r','i','b','u','t','e',0 +}; +static const WCHAR szDocument[] = { + '#', 'd', 'o', 'c', 'u', 'm', 'e', 'n', 't', 0 +}; + +static const WCHAR szOpen[] = { 'o','p','e','n',0 }; +static WCHAR szdl[] = { 'd','l',0 }; +static const WCHAR szvr[] = { 'v','r',0 }; +static const WCHAR szlc[] = { 'l','c',0 }; +static WCHAR szbs[] = { 'b','s',0 }; +static const WCHAR szstr1[] = { 's','t','r','1',0 }; +static const WCHAR szstr2[] = { 's','t','r','2',0 }; +static const WCHAR szstar[] = { '*',0 }; +static const WCHAR szfn1_txt[] = {'f','n','1','.','t','x','t',0}; + +static WCHAR szComment[] = {'A',' ','C','o','m','m','e','n','t',0 }; +static WCHAR szCommentXML[] = {'<','!','-','-','A',' ','C','o','m','m','e','n','t','-','-','>',0 }; +static WCHAR szCommentNodeText[] = {'#','c','o','m','m','e','n','t',0 }; + +static WCHAR szElement[] = {'E','l','e','T','e','s','t', 0 }; +static WCHAR szElementXML[] = {'<','E','l','e','T','e','s','t','/','>',0 }; +static WCHAR szElementXML2[] = {'<','E','l','e','T','e','s','t',' ','A','t','t','r','=','"','"','/','>',0 }; +static WCHAR szElementXML3[] = {'<','E','l','e','T','e','s','t',' ','A','t','t','r','=','"','"','>', + 'T','e','s','t','i','n','g','N','o','d','e','<','/','E','l','e','T','e','s','t','>',0 }; +static WCHAR szElementXML4[] = {'<','E','l','e','T','e','s','t',' ','A','t','t','r','=','"','"','>', + '&','a','m','p',';','x',' ',0x2103,'<','/','E','l','e','T','e','s','t','>',0 }; + +static WCHAR szAttribute[] = {'A','t','t','r',0 }; +static WCHAR szAttributeXML[] = {'A','t','t','r','=','"','"',0 }; + +static WCHAR szCData[] = {'[','1',']','*','2','=','3',';',' ','&','g','e','e',' ','t','h','a','t','s', + ' ','n','o','t',' ','r','i','g','h','t','!', 0}; +static WCHAR szCDataXML[] = {'<','!','[','C','D','A','T','A','[','[','1',']','*','2','=','3',';',' ','&', + 'g','e','e',' ','t','h','a','t','s',' ','n','o','t',' ','r','i','g','h','t', + '!',']',']','>',0}; +static WCHAR szCDataNodeText[] = {'#','c','d','a','t','a','-','s','e','c','t','i','o','n',0 }; +static WCHAR szDocFragmentText[] = {'#','d','o','c','u','m','e','n','t','-','f','r','a','g','m','e','n','t',0 }; + +static WCHAR szEntityRef[] = {'e','n','t','i','t','y','r','e','f',0 }; +static WCHAR szEntityRefXML[] = {'&','e','n','t','i','t','y','r','e','f',';',0 }; +static WCHAR szStrangeChars[] = {'&','x',' ',0x2103, 0}; + +#define expect_bstr_eq_and_free(bstr, expect) { \ + BSTR bstrExp = alloc_str_from_narrow(expect); \ + ok(lstrcmpW(bstr, bstrExp) == 0, "String differs\n"); \ + SysFreeString(bstr); \ + SysFreeString(bstrExp); \ +} + +#define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); } + +#define ole_check(expr) { \ + HRESULT r = expr; \ + ok(r == S_OK, #expr " returned %x\n", r); \ +} + +#define ole_expect(expr, expect) { \ + HRESULT r = expr; \ + ok(r == (expect), #expr " returned %x, expected %x\n", r, expect); \ +} + +#define double_eq(x, y) ok((x)-(y)<=1e-14*(x) && (x)-(y)>=-1e-14*(x), "expected %.16g, got %.16g\n", x, y) + +static BSTR alloc_str_from_narrow(const char *str) +{ + int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */ + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + return ret; +} + +BSTR alloced_bstrs[256]; +int alloced_bstrs_count = 0; + +static BSTR _bstr_(const char *str) +{ + assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0])); + alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str); + return alloced_bstrs[alloced_bstrs_count++]; +} + +static void free_bstrs(void) +{ + int i; + for (i = 0; i < alloced_bstrs_count; i++) + SysFreeString(alloced_bstrs[i]); + alloced_bstrs_count = 0; +} + +static VARIANT _variantbstr_(const char *str) +{ + VARIANT v; + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = _bstr_(str); + return v; +} + +static BOOL compareIgnoreReturns(BSTR sLeft, BSTR sRight) +{ + for (;;) + { + while (*sLeft == '\r' || *sLeft == '\n') sLeft++; + while (*sRight == '\r' || *sRight == '\n') sRight++; + if (*sLeft != *sRight) return FALSE; + if (!*sLeft) return TRUE; + sLeft++; + sRight++; + } +} + +static BOOL compareIgnoreReturnsWhitespace(BSTR sLeft, BSTR sRight) +{ + /* MSXML3 inserts whitespace where as libxml doesn't. */ + for (;;) + { + while (*sLeft == '\r' || *sLeft == '\n' || *sLeft == ' ') sLeft++; + while (*sRight == '\r' || *sRight == '\n' || *sRight == ' ') sRight++; + if (*sLeft != *sRight) return FALSE; + if (!*sLeft) return TRUE; + sLeft++; + sRight++; + } +} + +static void get_str_for_type(DOMNodeType type, char *buf) +{ + switch (type) + { + case NODE_ATTRIBUTE: + strcpy(buf, "A"); + break; + case NODE_ELEMENT: + strcpy(buf, "E"); + break; + case NODE_DOCUMENT: + strcpy(buf, "D"); + break; + default: + wsprintfA(buf, "[%d]", type); + } +} + +#define test_disp(u) _test_disp(__LINE__,u) +static void _test_disp(unsigned line, IUnknown *unk) +{ + DISPID dispid = DISPID_XMLDOM_NODELIST_RESET; + IDispatchEx *dispex; + DWORD dwProps = 0; + BSTR sName; + UINT ticnt; + IUnknown *pUnk; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); + ok_(__FILE__,line) (hres == S_OK, "Could not get IDispatch: %08x\n", hres); + if(FAILED(hres)) + return; + + ticnt = 0xdeadbeef; + hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); + ok_(__FILE__,line) (hres == S_OK, "GetTypeInfoCount failed: %08x\n", hres); + ok_(__FILE__,line) (ticnt == 1, "ticnt=%u\n", ticnt); + + sName = SysAllocString( szstar ); + hres = IDispatchEx_DeleteMemberByName(dispex, sName, fdexNameCaseSensitive); + ok(hres == E_NOTIMPL, "expected E_NOTIMPL got %08x\n", hres); + SysFreeString( sName ); + + hres = IDispatchEx_DeleteMemberByDispID(dispex, dispid); + ok(hres == E_NOTIMPL, "expected E_NOTIMPL got %08x\n", hres); + + hres = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &dwProps); + ok(hres == E_NOTIMPL, "expected E_NOTIMPL got %08x\n", hres); + ok(dwProps == 0, "expected 0 got %d\n", dwProps); + + hres = IDispatchEx_GetMemberName(dispex, dispid, &sName); + ok(hres == E_NOTIMPL, "expected E_NOTIMPL got %08x\n", hres); + if(SUCCEEDED(hres)) + SysFreeString(sName); + + hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_XMLDOM_NODELIST_RESET, &dispid); + ok(hres == E_NOTIMPL, "expected E_NOTIMPL got %08x\n", hres); + + hres = IDispatchEx_GetNameSpaceParent(dispex, &pUnk); + ok(hres == E_NOTIMPL, "expected E_NOTIMPL got %08x\n", hres); + if(hres == S_OK && pUnk) + IUnknown_Release(pUnk); + + IDispatchEx_Release(dispex); +} + +static int get_node_position(IXMLDOMNode *node) +{ + HRESULT r; + int pos = 0; + + IXMLDOMNode_AddRef(node); + do + { + IXMLDOMNode *new_node; + + pos++; + r = IXMLDOMNode_get_previousSibling(node, &new_node); + ok(SUCCEEDED(r), "get_previousSibling failed\n"); + IXMLDOMNode_Release(node); + node = new_node; + } while (r == S_OK); + return pos; +} + +static void node_to_string(IXMLDOMNode *node, char *buf) +{ + HRESULT r = S_OK; + DOMNodeType type; + + if (node == NULL) + { + lstrcpyA(buf, "(null)"); + return; + } + + IXMLDOMNode_AddRef(node); + while (r == S_OK) + { + IXMLDOMNode *new_node; + + ole_check(IXMLDOMNode_get_nodeType(node, &type)); + get_str_for_type(type, buf); + buf+=strlen(buf); + + if (type == NODE_ATTRIBUTE) + { + BSTR bstr; + ole_check(IXMLDOMNode_get_nodeName(node, &bstr)); + *(buf++) = '\''; + wsprintfA(buf, "%ws", bstr); + buf += strlen(buf); + *(buf++) = '\''; + SysFreeString(bstr); + + r = IXMLDOMNode_selectSingleNode(node, _bstr_(".."), &new_node); + } + else + { + int pos = get_node_position(node); + DOMNodeType parent_type = NODE_INVALID; + r = IXMLDOMNode_get_parentNode(node, &new_node); + + /* currently wine doesn't create a node for the . To be able to test query + * results we "fix" it */ + if (r == S_OK) + ole_check(IXMLDOMNode_get_nodeType(new_node, &parent_type)); + if ((parent_type == NODE_DOCUMENT) && type != NODE_PROCESSING_INSTRUCTION && pos==1) + { + todo_wine ok(FALSE, "The first child of the document node in MSXML is the processing instruction\n"); + pos++; + } + wsprintf(buf, "%d", pos); + buf += strlen(buf); + } + + ok(SUCCEEDED(r), "get_parentNode failed (%08x)\n", r); + IXMLDOMNode_Release(node); + node = new_node; + if (r == S_OK) + *(buf++) = '.'; + } + + *buf = 0; +} + +static char *list_to_string(IXMLDOMNodeList *list) +{ + static char buf[4096]; + char *pos = buf; + LONG len = 0; + int i; + + if (list == NULL) + { + lstrcpyA(buf, "(null)"); + return buf; + } + ole_check(IXMLDOMNodeList_get_length(list, &len)); + for (i = 0; i < len; i++) + { + IXMLDOMNode *node; + if (i > 0) + *(pos++) = ' '; + ole_check(IXMLDOMNodeList_nextNode(list, &node)); + node_to_string(node, pos); + pos += strlen(pos); + IXMLDOMNode_Release(node); + } + *pos = 0; + return buf; +} + +#define expect_node(node, expstr) { char str[4096]; node_to_string(node, str); ok(strcmp(str, expstr)==0, "Invalid node: %s, exptected %s\n", str, expstr); } +#define expect_list_and_release(list, expstr) { char *str = list_to_string(list); ok(strcmp(str, expstr)==0, "Invalid node list: %s, exptected %s\n", str, expstr); if (list) IXMLDOMNodeList_Release(list); } + +static void test_domdoc( void ) +{ + HRESULT r; + IXMLDOMDocument *doc = NULL; + IXMLDOMParseError *error; + IXMLDOMElement *element = NULL; + IXMLDOMNode *node; + IXMLDOMText *nodetext = NULL; + IXMLDOMComment *node_comment = NULL; + IXMLDOMAttribute *node_attr = NULL; + IXMLDOMNode *nodeChild = NULL; + IXMLDOMProcessingInstruction *nodePI = NULL; + ISupportErrorInfo *support_error = NULL; + VARIANT_BOOL b; + VARIANT var; + BSTR str; + LONG code; + LONG nLength = 0; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + test_disp((IUnknown*)doc); + + /* try some stupid things */ + r = IXMLDOMDocument_loadXML( doc, NULL, NULL ); + ok( r == S_FALSE, "loadXML failed\n"); + + b = VARIANT_TRUE; + r = IXMLDOMDocument_loadXML( doc, NULL, &b ); + ok( r == S_FALSE, "loadXML failed\n"); + ok( b == VARIANT_FALSE, "failed to load XML string\n"); + + /* try to load a document from a nonexistent file */ + b = VARIANT_TRUE; + str = SysAllocString( szNonExistentFile ); + VariantInit(&var); + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = str; + + r = IXMLDOMDocument_load( doc, var, &b); + ok( r == S_FALSE, "load (from file) failed\n"); + ok( b == VARIANT_FALSE, "failed to load XML file\n"); + SysFreeString( str ); + + /* try load an empty document */ + b = VARIANT_TRUE; + str = SysAllocString( szEmpty ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_FALSE, "loadXML failed\n"); + ok( b == VARIANT_FALSE, "failed to load XML string\n"); + SysFreeString( str ); + + r = IXMLDOMDocument_get_async( doc, &b ); + ok( r == S_OK, "get_async failed (%08x)\n", r); + ok( b == VARIANT_TRUE, "Wrong default value\n"); + + /* check that there's no document element */ + element = NULL; + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_FALSE, "should be no document element\n"); + + /* try finding a node */ + node = NULL; + str = SysAllocString( szstr1 ); + r = IXMLDOMDocument_selectSingleNode( doc, str, &node ); + ok( r == S_FALSE, "ret %08x\n", r ); + SysFreeString( str ); + + b = VARIANT_TRUE; + str = SysAllocString( szIncomplete ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_FALSE, "loadXML failed\n"); + ok( b == VARIANT_FALSE, "failed to load XML string\n"); + SysFreeString( str ); + + /* check that there's no document element */ + element = (IXMLDOMElement*)1; + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_FALSE, "should be no document element\n"); + ok( element == NULL, "Element should be NULL\n"); + + /* try to load something valid */ + b = VARIANT_FALSE; + str = SysAllocString( szComplete1 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + /* check if nodename is correct */ + r = IXMLDOMDocument_get_nodeName( doc, NULL ); + ok ( r == E_INVALIDARG, "get_nodeName (NULL) wrong code\n"); + + /* content doesn't matter here */ + str = NULL; + r = IXMLDOMDocument_get_nodeName( doc, &str ); + ok ( r == S_OK, "get_nodeName wrong code\n"); + ok ( str != NULL, "str is null\n"); + ok( !lstrcmpW( str, szDocument ), "incorrect nodeName\n"); + SysFreeString( str ); + + /* test put_text */ + r = IXMLDOMDocument_put_text( doc, _bstr_("Should Fail") ); + ok( r == E_FAIL, "ret %08x\n", r ); + + /* check that there's a document element */ + element = NULL; + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "should be a document element\n"); + if( element ) + { + IObjectIdentity *ident; + BSTR tag = NULL; + + test_disp((IUnknown*)element); + + r = IXMLDOMElement_QueryInterface( element, &IID_IObjectIdentity, (LPVOID*)&ident ); + ok( r == E_NOINTERFACE, "ret %08x\n", r); + + /* check if the tag is correct */ + r = IXMLDOMElement_get_tagName( element, &tag ); + ok( r == S_OK, "couldn't get tag name\n"); + ok( tag != NULL, "tag was null\n"); + ok( !lstrcmpW( tag, szOpen ), "incorrect tag name\n"); + SysFreeString( tag ); + + /* figure out what happens if we try to reload the document */ + str = SysAllocString( szComplete2 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + /* check if the tag is still correct */ + tag = NULL; + r = IXMLDOMElement_get_tagName( element, &tag ); + ok( r == S_OK, "couldn't get tag name\n"); + ok( tag != NULL, "tag was null\n"); + ok( !lstrcmpW( tag, szOpen ), "incorrect tag name\n"); + SysFreeString( tag ); + + IXMLDOMElement_Release( element ); + element = NULL; + } + + /* as soon as we call loadXML again, the document element will disappear */ + b = 2; + r = IXMLDOMDocument_loadXML( doc, NULL, NULL ); + ok( r == S_FALSE, "loadXML failed\n"); + ok( b == 2, "variant modified\n"); + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_FALSE, "should be no document element\n"); + + /* try to load something else simple and valid */ + b = VARIANT_FALSE; + str = SysAllocString( szComplete3 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + /* try something a little more complicated */ + b = FALSE; + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + r = IXMLDOMDocument_get_parseError( doc, &error ); + ok( r == S_OK, "returns %08x\n", r ); + + r = IXMLDOMParseError_get_errorCode( error, &code ); + ok( r == S_FALSE, "returns %08x\n", r ); + ok( code == 0, "code %d\n", code ); + IXMLDOMParseError_Release( error ); + + /* test createTextNode */ + str = SysAllocString( szOpen ); + r = IXMLDOMDocument_createTextNode(doc, str, NULL); + ok( r == E_INVALIDARG, "returns %08x\n", r ); + r = IXMLDOMDocument_createTextNode(doc, str, &nodetext); + ok( r == S_OK, "returns %08x\n", r ); + SysFreeString( str ); + if(nodetext) + { + IXMLDOMNamedNodeMap *pAttribs; + + r = IXMLDOMText_QueryInterface(nodetext, &IID_IXMLDOMElement, (LPVOID*)&element); + ok(r == E_NOINTERFACE, "ret %08x\n", r ); + + /* Text Last Child Checks */ + r = IXMLDOMText_get_lastChild(nodetext, NULL); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + + nodeChild = (IXMLDOMNode*)0x1; + r = IXMLDOMText_get_lastChild(nodetext, &nodeChild); + ok(r == S_FALSE, "ret %08x\n", r ); + ok(nodeChild == NULL, "nodeChild not NULL\n"); + + /* test get_attributes */ + r = IXMLDOMText_get_attributes( nodetext, NULL ); + ok( r == E_INVALIDARG, "get_attributes returned wrong code\n"); + + pAttribs = (IXMLDOMNamedNodeMap*)0x1; + r = IXMLDOMText_get_attributes( nodetext, &pAttribs); + ok(r == S_FALSE, "ret %08x\n", r ); + ok( pAttribs == NULL, "pAttribs not NULL\n"); + + /* test get_dataType */ + r = IXMLDOMText_get_dataType(nodetext, &var); + ok(r == S_FALSE, "ret %08x\n", r ); + ok( V_VT(&var) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&var); + + /* test length property */ + r = IXMLDOMText_get_length(nodetext, NULL); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + + r = IXMLDOMText_get_length(nodetext, &nLength); + ok(r == S_OK, "ret %08x\n", r ); + ok(nLength == 4, "expected 4 got %d\n", nLength); + + /* test nodeTypeString */ + r = IXMLDOMText_get_nodeTypeString(nodetext, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("text") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + /* put data Tests */ + r = IXMLDOMText_put_data(nodetext, _bstr_("This &is a ; test <>\\")); + ok(r == S_OK, "ret %08x\n", r ); + + /* get data Tests */ + r = IXMLDOMText_get_data(nodetext, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\") ), "incorrect put_data string\n"); + SysFreeString(str); + + /* Confirm XML text is good */ + r = IXMLDOMText_get_xml(nodetext, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\") ), "incorrect xml string\n"); + SysFreeString(str); + + /* Confirm we get the put_data Text back */ + r = IXMLDOMText_get_text(nodetext, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\") ), "incorrect xml string\n"); + SysFreeString(str); + + /* test substringData */ + r = IXMLDOMText_substringData(nodetext, 0, 4, NULL); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + + /* test substringData - Invalid offset */ + str = (BSTR)&szElement; + r = IXMLDOMText_substringData(nodetext, -1, 4, &str); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid offset */ + str = (BSTR)&szElement; + r = IXMLDOMText_substringData(nodetext, 30, 0, &str); + ok(r == S_FALSE, "ret %08x\n", r ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid size */ + str = (BSTR)&szElement; + r = IXMLDOMText_substringData(nodetext, 0, -1, &str); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid size */ + str = (BSTR)&szElement; + r = IXMLDOMText_substringData(nodetext, 2, 0, &str); + ok(r == S_FALSE, "ret %08x\n", r ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Start of string */ + r = IXMLDOMText_substringData(nodetext, 0, 4, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("This") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test substringData - Middle of string */ + r = IXMLDOMText_substringData(nodetext, 13, 4, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("test") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test substringData - End of string */ + r = IXMLDOMText_substringData(nodetext, 20, 4, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("\\") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test appendData */ + r = IXMLDOMText_appendData(nodetext, NULL); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_appendData(nodetext, _bstr_("")); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_appendData(nodetext, _bstr_("Append")); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_get_text(nodetext, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\Append") ), "incorrect get_text string\n"); + SysFreeString(str); + + /* test insertData */ + str = SysAllocStringLen(NULL, 0); + r = IXMLDOMText_insertData(nodetext, -1, str); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, -1, NULL); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, 1000, str); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, 1000, NULL); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, 0, NULL); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, 0, str); + ok(r == S_OK, "ret %08x\n", r ); + SysFreeString(str); + + r = IXMLDOMText_insertData(nodetext, -1, _bstr_("Inserting")); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, 1000, _bstr_("Inserting")); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, 0, _bstr_("Begin ")); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, 17, _bstr_("Middle")); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_insertData(nodetext, 39, _bstr_(" End")); + ok(r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMText_get_text(nodetext, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("Begin This &is a Middle; test <>\\Append End") ), "incorrect get_text string\n"); + SysFreeString(str); + + /* test put_data */ + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(szstr1); + r = IXMLDOMText_put_nodeValue(nodetext, var); + ok(r == S_OK, "ret %08x\n", r ); + VariantClear(&var); + + r = IXMLDOMText_get_text(nodetext, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, szstr1 ), "incorrect get_text string\n"); + SysFreeString(str); + + /* test put_data */ + V_VT(&var) = VT_I4; + V_I4(&var) = 99; + r = IXMLDOMText_put_nodeValue(nodetext, var); + ok(r == S_OK, "ret %08x\n", r ); + VariantClear(&var); + + r = IXMLDOMText_get_text(nodetext, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("99") ), "incorrect get_text string\n"); + SysFreeString(str); + + IXMLDOMText_Release( nodetext ); + } + + /* test Create Comment */ + r = IXMLDOMDocument_createComment(doc, NULL, NULL); + ok( r == E_INVALIDARG, "returns %08x\n", r ); + r = IXMLDOMDocument_createComment(doc, szComment, &node_comment); + ok( r == S_OK, "returns %08x\n", r ); + if(node_comment) + { + /* Last Child Checks */ + r = IXMLDOMComment_get_lastChild(node_comment, NULL); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + + nodeChild = (IXMLDOMNode*)0x1; + r = IXMLDOMComment_get_lastChild(node_comment, &nodeChild); + ok(r == S_FALSE, "ret %08x\n", r ); + ok(nodeChild == NULL, "pLastChild not NULL\n"); + + IXMLDOMComment_Release( node_comment ); + } + + /* test Create Attribute */ + r = IXMLDOMDocument_createAttribute(doc, NULL, NULL); + ok( r == E_INVALIDARG, "returns %08x\n", r ); + r = IXMLDOMDocument_createAttribute(doc, szAttribute, &node_attr); + ok( r == S_OK, "returns %08x\n", r ); + IXMLDOMText_Release( node_attr); + + /* test Processing Instruction */ + str = SysAllocStringLen(NULL, 0); + r = IXMLDOMDocument_createProcessingInstruction(doc, str, str, NULL); + ok( r == E_INVALIDARG, "returns %08x\n", r ); + r = IXMLDOMDocument_createProcessingInstruction(doc, NULL, str, &nodePI); + ok( r == E_FAIL, "returns %08x\n", r ); + r = IXMLDOMDocument_createProcessingInstruction(doc, str, str, &nodePI); + ok( r == E_FAIL, "returns %08x\n", r ); + SysFreeString(str); + + r = IXMLDOMDocument_createProcessingInstruction(doc, _bstr_("xml"), _bstr_("version=\"1.0\""), &nodePI); + ok( r == S_OK, "returns %08x\n", r ); + if(nodePI) + { + /* Last Child Checks */ + r = IXMLDOMProcessingInstruction_get_lastChild(nodePI, NULL); + ok(r == E_INVALIDARG, "ret %08x\n", r ); + + nodeChild = (IXMLDOMNode*)0x1; + r = IXMLDOMProcessingInstruction_get_lastChild(nodePI, &nodeChild); + ok(r == S_FALSE, "ret %08x\n", r ); + ok(nodeChild == NULL, "nodeChild not NULL\n"); + + r = IXMLDOMProcessingInstruction_get_dataType(nodePI, &var); + ok(r == S_FALSE, "ret %08x\n", r ); + ok( V_VT(&var) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&var); + + /* test nodeName */ + r = IXMLDOMProcessingInstruction_get_nodeName(nodePI, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("xml") ), "incorrect nodeName string\n"); + SysFreeString(str); + + /* test Target */ + r = IXMLDOMProcessingInstruction_get_target(nodePI, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("xml") ), "incorrect target string\n"); + SysFreeString(str); + + /* test nodeTypeString */ + r = IXMLDOMProcessingInstruction_get_nodeTypeString(nodePI, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("processinginstruction") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + /* test get_nodeValue */ + r = IXMLDOMProcessingInstruction_get_nodeValue(nodePI, &var); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( V_BSTR(&var), _bstr_("version=\"1.0\"") ), "incorrect data string\n"); + VariantClear(&var); + + /* test get_data */ + r = IXMLDOMProcessingInstruction_get_data(nodePI, &str); + ok(r == S_OK, "ret %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("version=\"1.0\"") ), "incorrect data string\n"); + SysFreeString(str); + + /* test put_data */ + r = IXMLDOMProcessingInstruction_put_data(nodePI, _bstr_("version=\"1.0\" encoding=\"UTF-8\"")); + ok(r == E_FAIL, "ret %08x\n", r ); + + /* test put_data */ + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(szOpen); /* Doesn't matter what the string is, cannot set an xml node. */ + r = IXMLDOMProcessingInstruction_put_nodeValue(nodePI, var); + ok(r == E_FAIL, "ret %08x\n", r ); + VariantClear(&var); + + /* test get nodeName */ + r = IXMLDOMProcessingInstruction_get_nodeName(nodePI, &str); + ok( !lstrcmpW( str, _bstr_("xml") ), "incorrect nodeName string\n"); + ok(r == S_OK, "ret %08x\n", r ); + SysFreeString(str); + + IXMLDOMProcessingInstruction_Release(nodePI); + } + + r = IXMLDOMDocument_QueryInterface( doc, &IID_ISupportErrorInfo, (LPVOID*)&support_error ); + ok( r == S_OK, "ret %08x\n", r ); + if(r == S_OK) + { + r = ISupportErrorInfo_InterfaceSupportsErrorInfo( support_error, &IID_IXMLDOMDocument ); + todo_wine ok( r == S_OK, "ret %08x\n", r ); + ISupportErrorInfo_Release( support_error ); + } + + r = IXMLDOMDocument_Release( doc ); + ok( r == 0, "document ref count incorrect\n"); + + free_bstrs(); +} + +static void test_domnode( void ) +{ + HRESULT r; + IXMLDOMDocument *doc = NULL, *owner = NULL; + IXMLDOMElement *element = NULL; + IXMLDOMNamedNodeMap *map = NULL; + IXMLDOMNode *node = NULL, *next = NULL; + IXMLDOMNodeList *list = NULL; + IXMLDOMAttribute *attr = NULL; + DOMNodeType type = NODE_INVALID; + VARIANT_BOOL b; + BSTR str; + VARIANT var; + LONG count; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + if (!doc) { + ok( FALSE, "no document\n"); + return; + } + + b = FALSE; + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + b = 1; + r = IXMLDOMNode_hasChildNodes( doc, &b ); + ok( r == S_OK, "hasChildNoes bad return\n"); + ok( b == VARIANT_TRUE, "hasChildNoes wrong result\n"); + + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "should be a document element\n"); + ok( element != NULL, "should be an element\n"); + + VariantInit(&var); + ok( V_VT(&var) == VT_EMPTY, "variant init failed\n"); + + r = IXMLDOMNode_get_nodeValue( doc, NULL ); + ok(r == E_INVALIDARG, "get_nodeValue ret %08x\n", r ); + + r = IXMLDOMNode_get_nodeValue( doc, &var ); + ok( r == S_FALSE, "nextNode returned wrong code\n"); + ok( V_VT(&var) == VT_NULL, "variant wasn't empty\n"); + ok( V_BSTR(&var) == NULL, "variant value wasn't null\n"); + + if (element) + { + owner = NULL; + r = IXMLDOMNode_get_ownerDocument( element, &owner ); + ok( r == S_OK, "get_ownerDocument return code\n"); + ok( owner != doc, "get_ownerDocument return\n"); + + type = NODE_INVALID; + r = IXMLDOMNode_get_nodeType( element, &type); + ok( r == S_OK, "getNamedItem returned wrong code\n"); + ok( type == NODE_ELEMENT, "node not an element\n"); + + str = NULL; + r = IXMLDOMNode_get_baseName( element, &str ); + ok( r == S_OK, "get_baseName returned wrong code\n"); + ok( lstrcmpW(str,szlc) == 0, "basename was wrong\n"); + SysFreeString(str); + + /* check if nodename is correct */ + r = IXMLDOMElement_get_nodeName( element, NULL ); + ok ( r == E_INVALIDARG, "get_nodeName (NULL) wrong code\n"); + + /* content doesn't matter here */ + str = NULL; + r = IXMLDOMElement_get_nodeName( element, &str ); + ok ( r == S_OK, "get_nodeName wrong code\n"); + ok ( str != NULL, "str is null\n"); + ok( !lstrcmpW( str, szlc ), "incorrect nodeName\n"); + SysFreeString( str ); + + str = SysAllocString( szNonExistentFile ); + V_VT(&var) = VT_I4; + V_I4(&var) = 0x1234; + r = IXMLDOMElement_getAttribute( element, str, &var ); + ok( r == E_FAIL, "getAttribute ret %08x\n", r ); + ok( V_VT(&var) == VT_NULL || V_VT(&var) == VT_EMPTY, "vt = %x\n", V_VT(&var)); + VariantClear(&var); + + r = IXMLDOMElement_getAttributeNode( element, str, NULL); + ok( r == E_FAIL, "getAttributeNode ret %08x\n", r ); + + attr = (IXMLDOMAttribute*)0xdeadbeef; + r = IXMLDOMElement_getAttributeNode( element, str, &attr); + ok( r == E_FAIL, "getAttributeNode ret %08x\n", r ); + ok( attr == NULL, "getAttributeNode ret %p, expected NULL\n", attr ); + SysFreeString( str ); + + attr = (IXMLDOMAttribute*)0xdeadbeef; + str = SysAllocString( szNonExistentAttribute ); + r = IXMLDOMElement_getAttributeNode( element, str, &attr); + ok( r == S_FALSE, "getAttributeNode ret %08x\n", r ); + ok( attr == NULL, "getAttributeNode ret %p, expected NULL\n", attr ); + SysFreeString( str ); + + str = SysAllocString( szdl ); + V_VT(&var) = VT_I4; + V_I4(&var) = 0x1234; + r = IXMLDOMElement_getAttribute( element, str, &var ); + ok( r == S_OK, "getAttribute ret %08x\n", r ); + ok( V_VT(&var) == VT_BSTR, "vt = %x\n", V_VT(&var)); + ok( !lstrcmpW(V_BSTR(&var), szstr1), "wrong attr value\n"); + VariantClear( &var ); + + r = IXMLDOMElement_getAttribute( element, NULL, &var ); + ok( r == E_INVALIDARG, "getAttribute ret %08x\n", r ); + + r = IXMLDOMElement_getAttribute( element, str, NULL ); + ok( r == E_INVALIDARG, "getAttribute ret %08x\n", r ); + + attr = NULL; + r = IXMLDOMElement_getAttributeNode( element, str, &attr); + ok( r == S_OK, "GetAttributeNode ret %08x\n", r ); + ok( attr != NULL, "getAttributeNode returned NULL\n" ); + if(attr) + IXMLDOMAttribute_Release(attr); + + SysFreeString( str ); + + r = IXMLDOMElement_get_attributes( element, &map ); + ok( r == S_OK, "get_attributes returned wrong code\n"); + ok( map != NULL, "should be attributes\n"); + + b = 1; + r = IXMLDOMNode_hasChildNodes( element, &b ); + ok( r == S_OK, "hasChildNoes bad return\n"); + ok( b == VARIANT_TRUE, "hasChildNoes wrong result\n"); + } + else + ok( FALSE, "no element\n"); + + if (map) + { + ISupportErrorInfo *support_error; + r = IXMLDOMNamedNodeMap_QueryInterface( map, &IID_ISupportErrorInfo, (LPVOID*)&support_error ); + ok( r == S_OK, "ret %08x\n", r ); + + r = ISupportErrorInfo_InterfaceSupportsErrorInfo( support_error, &IID_IXMLDOMNamedNodeMap ); +todo_wine +{ + ok( r == S_OK, "ret %08x\n", r ); +} + ISupportErrorInfo_Release( support_error ); + + str = SysAllocString( szdl ); + r = IXMLDOMNamedNodeMap_getNamedItem( map, str, &node ); + ok( r == S_OK, "getNamedItem returned wrong code\n"); + ok( node != NULL, "should be attributes\n"); + IXMLDOMNode_Release(node); + SysFreeString( str ); + + str = SysAllocString( szdl ); + r = IXMLDOMNamedNodeMap_getNamedItem( map, str, NULL ); + ok( r == E_INVALIDARG, "getNamedItem should return E_INVALIDARG\n"); + SysFreeString( str ); + + /* something that isn't in szComplete4 */ + str = SysAllocString( szOpen ); + node = (IXMLDOMNode *) 1; + r = IXMLDOMNamedNodeMap_getNamedItem( map, str, &node ); + ok( r == S_FALSE, "getNamedItem found a node that wasn't there\n"); + ok( node == NULL, "getNamedItem should have returned NULL\n"); + SysFreeString( str ); + + /* test indexed access of attributes */ + r = IXMLDOMNamedNodeMap_get_length( map, NULL ); + ok ( r == E_INVALIDARG, "get_length should return E_INVALIDARG\n"); + + r = IXMLDOMNamedNodeMap_get_length( map, &count ); + ok ( r == S_OK, "get_length wrong code\n"); + ok ( count == 1, "get_length != 1\n"); + + node = NULL; + r = IXMLDOMNamedNodeMap_get_item( map, -1, &node); + ok ( r == S_FALSE, "get_item (-1) wrong code\n"); + ok ( node == NULL, "there is no node\n"); + + node = NULL; + r = IXMLDOMNamedNodeMap_get_item( map, 1, &node); + ok ( r == S_FALSE, "get_item (1) wrong code\n"); + ok ( node == NULL, "there is no attribute\n"); + + node = NULL; + r = IXMLDOMNamedNodeMap_get_item( map, 0, &node); + ok ( r == S_OK, "get_item (0) wrong code\n"); + ok ( node != NULL, "should be attribute\n"); + + r = IXMLDOMNode_get_nodeName( node, NULL ); + ok ( r == E_INVALIDARG, "get_nodeName (NULL) wrong code\n"); + + /* content doesn't matter here */ + str = NULL; + r = IXMLDOMNode_get_nodeName( node, &str ); + ok ( r == S_OK, "get_nodeName wrong code\n"); + ok ( str != NULL, "str is null\n"); + ok( !lstrcmpW( str, szdl ), "incorrect node name\n"); + SysFreeString( str ); + + /* test sequential access of attributes */ + node = NULL; + r = IXMLDOMNamedNodeMap_nextNode( map, &node ); + ok ( r == S_OK, "nextNode (first time) wrong code\n"); + ok ( node != NULL, "nextNode, should be attribute\n"); + + r = IXMLDOMNamedNodeMap_nextNode( map, &node ); + ok ( r != S_OK, "nextNode (second time) wrong code\n"); + ok ( node == NULL, "nextNode, there is no attribute\n"); + + r = IXMLDOMNamedNodeMap_reset( map ); + ok ( r == S_OK, "reset should return S_OK\n"); + + r = IXMLDOMNamedNodeMap_nextNode( map, &node ); + ok ( r == S_OK, "nextNode (third time) wrong code\n"); + ok ( node != NULL, "nextNode, should be attribute\n"); + } + else + ok( FALSE, "no map\n"); + + if (node) + { + type = NODE_INVALID; + r = IXMLDOMNode_get_nodeType( node, &type); + ok( r == S_OK, "getNamedItem returned wrong code\n"); + ok( type == NODE_ATTRIBUTE, "node not an attribute\n"); + + str = NULL; + r = IXMLDOMNode_get_baseName( node, NULL ); + ok( r == E_INVALIDARG, "get_baseName returned wrong code\n"); + + str = NULL; + r = IXMLDOMNode_get_baseName( node, &str ); + ok( r == S_OK, "get_baseName returned wrong code\n"); + ok( lstrcmpW(str,szdl) == 0, "basename was wrong\n"); + SysFreeString( str ); + + r = IXMLDOMNode_get_nodeValue( node, &var ); + ok( r == S_OK, "returns %08x\n", r ); + ok( V_VT(&var) == VT_BSTR, "vt %x\n", V_VT(&var)); + ok( !lstrcmpW(V_BSTR(&var), szstr1), "nodeValue incorrect\n"); + VariantClear(&var); + + r = IXMLDOMNode_get_childNodes( node, NULL ); + ok( r == E_INVALIDARG, "get_childNodes returned wrong code\n"); + + r = IXMLDOMNode_get_childNodes( node, &list ); + ok( r == S_OK, "get_childNodes returned wrong code\n"); + + if (list) + { + r = IXMLDOMNodeList_nextNode( list, &next ); + ok( r == S_OK, "nextNode returned wrong code\n"); + } + else + ok( FALSE, "no childlist\n"); + + if (next) + { + b = 1; + r = IXMLDOMNode_hasChildNodes( next, &b ); + ok( r == S_FALSE, "hasChildNoes bad return\n"); + ok( b == VARIANT_FALSE, "hasChildNoes wrong result\n"); + + type = NODE_INVALID; + r = IXMLDOMNode_get_nodeType( next, &type); + ok( r == S_OK, "getNamedItem returned wrong code\n"); + ok( type == NODE_TEXT, "node not text\n"); + + str = (BSTR) 1; + r = IXMLDOMNode_get_baseName( next, &str ); + ok( r == S_FALSE, "get_baseName returned wrong code\n"); + ok( str == NULL, "basename was wrong\n"); + SysFreeString(str); + } + else + ok( FALSE, "no next\n"); + + if (next) + IXMLDOMNode_Release( next ); + next = NULL; + if (list) + IXMLDOMNodeList_Release( list ); + list = NULL; + if (node) + IXMLDOMNode_Release( node ); + } + else + ok( FALSE, "no node\n"); + node = NULL; + + if (map) + IXMLDOMNamedNodeMap_Release( map ); + + /* now traverse the tree from the root element */ + if (element) + { + r = IXMLDOMNode_get_childNodes( element, &list ); + ok( r == S_OK, "get_childNodes returned wrong code\n"); + + /* using get_item for child list doesn't advance the position */ + ole_check(IXMLDOMNodeList_get_item(list, 1, &node)); + expect_node(node, "E2.E2.D1"); + IXMLDOMNode_Release(node); + ole_check(IXMLDOMNodeList_nextNode(list, &node)); + expect_node(node, "E1.E2.D1"); + IXMLDOMNode_Release(node); + ole_check(IXMLDOMNodeList_reset(list)); + + IXMLDOMNodeList_AddRef(list); + expect_list_and_release(list, "E1.E2.D1 E2.E2.D1 E3.E2.D1 E4.E2.D1"); + ole_check(IXMLDOMNodeList_reset(list)); + + node = (void*)0xdeadbeef; + r = IXMLDOMNode_selectSingleNode( element, szdl, &node ); + ok( r == S_FALSE, "ret %08x\n", r ); + ok( node == NULL, "node %p\n", node ); + r = IXMLDOMNode_selectSingleNode( element, szbs, &node ); + ok( r == S_OK, "ret %08x\n", r ); + r = IXMLDOMNode_Release( node ); + ok( r == 0, "ret %08x\n", r ); + } + else + ok( FALSE, "no element\n"); + + if (list) + { + r = IXMLDOMNodeList_QueryInterface(list, &IID_IDispatch, NULL); + ok( r == E_INVALIDARG || r == E_POINTER, "ret %08x\n", r ); + + r = IXMLDOMNodeList_get_item(list, 0, NULL); + ok(r == E_INVALIDARG, "Exected E_INVALIDARG got %08x\n", r); + + r = IXMLDOMNodeList_get_length(list, NULL); + ok(r == E_INVALIDARG, "Exected E_INVALIDARG got %08x\n", r); + + r = IXMLDOMNodeList_get_length( list, &count ); + ok( r == S_OK, "get_length returns %08x\n", r ); + ok( count == 4, "get_length got %d\n", count ); + + r = IXMLDOMNodeList_nextNode(list, NULL); + ok(r == E_INVALIDARG, "Exected E_INVALIDARG got %08x\n", r); + + r = IXMLDOMNodeList_nextNode( list, &node ); + ok( r == S_OK, "nextNode returned wrong code\n"); + } + else + ok( FALSE, "no list\n"); + + if (node) + { + type = NODE_INVALID; + r = IXMLDOMNode_get_nodeType( node, &type); + ok( r == S_OK, "getNamedItem returned wrong code\n"); + ok( type == NODE_ELEMENT, "node not text\n"); + + VariantInit(&var); + ok( V_VT(&var) == VT_EMPTY, "variant init failed\n"); + r = IXMLDOMNode_get_nodeValue( node, &var ); + ok( r == S_FALSE, "nextNode returned wrong code\n"); + ok( V_VT(&var) == VT_NULL, "variant wasn't empty\n"); + ok( V_BSTR(&var) == NULL, "variant value wasn't null\n"); + + r = IXMLDOMNode_hasChildNodes( node, NULL ); + ok( r == E_INVALIDARG, "hasChildNoes bad return\n"); + + b = 1; + r = IXMLDOMNode_hasChildNodes( node, &b ); + ok( r == S_OK, "hasChildNoes bad return\n"); + ok( b == VARIANT_TRUE, "hasChildNoes wrong result\n"); + + str = NULL; + r = IXMLDOMNode_get_baseName( node, &str ); + ok( r == S_OK, "get_baseName returned wrong code\n"); + ok( lstrcmpW(str,szbs) == 0, "basename was wrong\n"); + SysFreeString(str); + } + else + ok( FALSE, "no node\n"); + + if (node) + IXMLDOMNode_Release( node ); + if (list) + IXMLDOMNodeList_Release( list ); + if (element) + IXMLDOMElement_Release( element ); + + b = FALSE; + str = SysAllocString( szComplete5 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + b = 1; + r = IXMLDOMNode_hasChildNodes( doc, &b ); + ok( r == S_OK, "hasChildNoes bad return\n"); + ok( b == VARIANT_TRUE, "hasChildNoes wrong result\n"); + + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "should be a document element\n"); + ok( element != NULL, "should be an element\n"); + + if (element) + { + static const WCHAR szSSearch[] = {'S',':','s','e','a','r','c','h',0}; + BSTR tag = NULL; + + /* check if the tag is correct */ + r = IXMLDOMElement_get_tagName( element, &tag ); + ok( r == S_OK, "couldn't get tag name\n"); + ok( tag != NULL, "tag was null\n"); + ok( !lstrcmpW( tag, szSSearch ), "incorrect tag name\n"); + SysFreeString( tag ); + } + + if (element) + IXMLDOMElement_Release( element ); + ok(IXMLDOMDocument_Release( doc ) == 0, "document is not destroyed\n"); +} + +static void test_refs(void) +{ + HRESULT r; + BSTR str; + VARIANT_BOOL b; + IXMLDOMDocument *doc = NULL; + IXMLDOMElement *element = NULL; + IXMLDOMNode *node = NULL, *node2; + IXMLDOMNodeList *node_list = NULL; + LONG ref; + IUnknown *unk, *unk2; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + ref = IXMLDOMDocument_Release(doc); + ok( ref == 0, "ref %d\n", ref); + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + ref = IXMLDOMDocument_AddRef( doc ); + ok( ref == 2, "ref %d\n", ref ); + ref = IXMLDOMDocument_AddRef( doc ); + ok( ref == 3, "ref %d\n", ref ); + IXMLDOMDocument_Release( doc ); + IXMLDOMDocument_Release( doc ); + + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "should be a document element\n"); + ok( element != NULL, "should be an element\n"); + + ref = IXMLDOMDocument_AddRef( doc ); + ok( ref == 2, "ref %d\n", ref ); + IXMLDOMDocument_Release( doc ); + + r = IXMLDOMElement_get_childNodes( element, &node_list ); + ok( r == S_OK, "rets %08x\n", r); + + ref = IXMLDOMNodeList_AddRef( node_list ); + ok( ref == 2, "ref %d\n", ref ); + IXMLDOMNodeList_Release( node_list ); + + IXMLDOMNodeList_get_item( node_list, 0, &node ); + ok( r == S_OK, "rets %08x\n", r); + + IXMLDOMNodeList_get_item( node_list, 0, &node2 ); + ok( r == S_OK, "rets %08x\n", r); + + ref = IXMLDOMNode_AddRef( node ); + ok( ref == 2, "ref %d\n", ref ); + IXMLDOMNode_Release( node ); + + ref = IXMLDOMNode_Release( node ); + ok( ref == 0, "ref %d\n", ref ); + ref = IXMLDOMNode_Release( node2 ); + ok( ref == 0, "ref %d\n", ref ); + + ref = IXMLDOMNodeList_Release( node_list ); + ok( ref == 0, "ref %d\n", ref ); + + ok( node != node2, "node %p node2 %p\n", node, node2 ); + + ref = IXMLDOMDocument_Release( doc ); + ok( ref == 0, "ref %d\n", ref ); + + ref = IXMLDOMElement_AddRef( element ); + todo_wine { + ok( ref == 3, "ref %d\n", ref ); + } + IXMLDOMElement_Release( element ); + + /* IUnknown must be unique however we obtain it */ + r = IXMLDOMElement_QueryInterface( element, &IID_IUnknown, (LPVOID*)&unk ); + ok( r == S_OK, "rets %08x\n", r ); + r = IXMLDOMElement_QueryInterface( element, &IID_IXMLDOMNode, (LPVOID*)&node ); + ok( r == S_OK, "rets %08x\n", r ); + r = IXMLDOMNode_QueryInterface( node, &IID_IUnknown, (LPVOID*)&unk2 ); + ok( r == S_OK, "rets %08x\n", r ); + ok( unk == unk2, "unk %p unk2 %p\n", unk, unk2 ); + + IUnknown_Release( unk2 ); + IUnknown_Release( unk ); + IXMLDOMNode_Release( node ); + + IXMLDOMElement_Release( element ); + +} + +static void test_create(void) +{ + static const WCHAR szOne[] = {'1',0}; + static const WCHAR szOneGarbage[] = {'1','G','a','r','b','a','g','e',0}; + HRESULT r; + VARIANT var; + BSTR str, name; + IXMLDOMDocument *doc; + IXMLDOMElement *element; + IXMLDOMNode *root, *node, *child; + IXMLDOMNamedNodeMap *attr_map; + IUnknown *unk; + LONG ref; + LONG num; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + V_VT(&var) = VT_I1; + V_I1(&var) = NODE_ELEMENT; + str = SysAllocString( szlc ); + r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node ); + ok( r == S_OK, "returns %08x\n", r ); + if( SUCCEEDED(r) ) IXMLDOMNode_Release( node ); + + V_VT(&var) = VT_R4; + V_R4(&var) = NODE_ELEMENT; + r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node ); + ok( r == S_OK, "returns %08x\n", r ); + if( SUCCEEDED(r) ) IXMLDOMNode_Release( node ); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString( szOne ); + r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node ); + ok( r == S_OK, "returns %08x\n", r ); + if( SUCCEEDED(r) ) IXMLDOMNode_Release( node ); + VariantClear(&var); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString( szOneGarbage ); + r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node ); + ok( r == E_INVALIDARG, "returns %08x\n", r ); + if( SUCCEEDED(r) ) IXMLDOMNode_Release( node ); + VariantClear(&var); + + V_VT(&var) = VT_I4; + V_I4(&var) = NODE_ELEMENT; + r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node ); + ok( r == S_OK, "returns %08x\n", r ); + r = IXMLDOMDocument_appendChild( doc, node, &root ); + ok( r == S_OK, "returns %08x\n", r ); + ok( node == root, "%p %p\n", node, root ); + + ref = IXMLDOMNode_AddRef( node ); + ok(ref == 3, "ref %d\n", ref); + IXMLDOMNode_Release( node ); + + ref = IXMLDOMNode_Release( node ); + ok(ref == 1, "ref %d\n", ref); + SysFreeString( str ); + + V_VT(&var) = VT_I4; + V_I4(&var) = NODE_ELEMENT; + str = SysAllocString( szbs ); + r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node ); + ok( r == S_OK, "returns %08x\n", r ); + SysFreeString( str ); + + ref = IXMLDOMNode_AddRef( node ); + ok(ref == 2, "ref = %d\n", ref); + IXMLDOMNode_Release( node ); + + r = IXMLDOMNode_QueryInterface( node, &IID_IUnknown, (LPVOID*)&unk ); + ok( r == S_OK, "returns %08x\n", r ); + + ref = IXMLDOMNode_AddRef( unk ); + ok(ref == 3, "ref = %d\n", ref); + IXMLDOMNode_Release( unk ); + + V_VT(&var) = VT_EMPTY; + r = IXMLDOMNode_insertBefore( root, (IXMLDOMNode*)unk, var, &child ); + ok( r == S_OK, "returns %08x\n", r ); + ok( unk == (IUnknown*)child, "%p %p\n", unk, child ); + IXMLDOMNode_Release( child ); + IUnknown_Release( unk ); + + + V_VT(&var) = VT_NULL; + V_DISPATCH(&var) = (IDispatch*)node; + r = IXMLDOMNode_insertBefore( root, node, var, &child ); + ok( r == S_OK, "returns %08x\n", r ); + ok( node == child, "%p %p\n", node, child ); + IXMLDOMNode_Release( child ); + + + V_VT(&var) = VT_NULL; + V_DISPATCH(&var) = (IDispatch*)node; + r = IXMLDOMNode_insertBefore( root, node, var, NULL ); + ok( r == S_OK, "returns %08x\n", r ); + IXMLDOMNode_Release( node ); + + r = IXMLDOMNode_QueryInterface( root, &IID_IXMLDOMElement, (LPVOID*)&element ); + ok( r == S_OK, "returns %08x\n", r ); + + r = IXMLDOMElement_get_attributes( element, &attr_map ); + ok( r == S_OK, "returns %08x\n", r ); + r = IXMLDOMNamedNodeMap_get_length( attr_map, &num ); + ok( r == S_OK, "returns %08x\n", r ); + ok( num == 0, "num %d\n", num ); + IXMLDOMNamedNodeMap_Release( attr_map ); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString( szstr1 ); + name = SysAllocString( szdl ); + r = IXMLDOMElement_setAttribute( element, name, var ); + ok( r == S_OK, "returns %08x\n", r ); + r = IXMLDOMElement_get_attributes( element, &attr_map ); + ok( r == S_OK, "returns %08x\n", r ); + r = IXMLDOMNamedNodeMap_get_length( attr_map, &num ); + ok( r == S_OK, "returns %08x\n", r ); + ok( num == 1, "num %d\n", num ); + IXMLDOMNamedNodeMap_Release( attr_map ); + VariantClear(&var); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString( szstr2 ); + r = IXMLDOMElement_setAttribute( element, name, var ); + ok( r == S_OK, "returns %08x\n", r ); + r = IXMLDOMElement_get_attributes( element, &attr_map ); + ok( r == S_OK, "returns %08x\n", r ); + r = IXMLDOMNamedNodeMap_get_length( attr_map, &num ); + ok( r == S_OK, "returns %08x\n", r ); + ok( num == 1, "num %d\n", num ); + IXMLDOMNamedNodeMap_Release( attr_map ); + VariantClear(&var); + r = IXMLDOMElement_getAttribute( element, name, &var ); + ok( r == S_OK, "returns %08x\n", r ); + ok( !lstrcmpW(V_BSTR(&var), szstr2), "wrong attr value\n"); + VariantClear(&var); + SysFreeString(name); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString( szstr1 ); + name = SysAllocString( szlc ); + r = IXMLDOMElement_setAttribute( element, name, var ); + ok( r == S_OK, "returns %08x\n", r ); + r = IXMLDOMElement_get_attributes( element, &attr_map ); + ok( r == S_OK, "returns %08x\n", r ); + r = IXMLDOMNamedNodeMap_get_length( attr_map, &num ); + ok( r == S_OK, "returns %08x\n", r ); + ok( num == 2, "num %d\n", num ); + IXMLDOMNamedNodeMap_Release( attr_map ); + VariantClear(&var); + SysFreeString(name); + + V_VT(&var) = VT_I4; + V_I4(&var) = 10; + name = SysAllocString( szbs ); + r = IXMLDOMElement_setAttribute( element, name, var ); + ok( r == S_OK, "returns %08x\n", r ); + VariantClear(&var); + r = IXMLDOMElement_getAttribute( element, name, &var ); + ok( r == S_OK, "returns %08x\n", r ); + ok( V_VT(&var) == VT_BSTR, "variant type %x\n", V_VT(&var)); + VariantClear(&var); + SysFreeString(name); + + /* Create an Attribute */ + V_VT(&var) = VT_I4; + V_I4(&var) = NODE_ATTRIBUTE; + str = SysAllocString( szAttribute ); + r = IXMLDOMDocument_createNode( doc, var, str, NULL, &node ); + ok( r == S_OK, "returns %08x\n", r ); + ok( node != NULL, "node was null\n"); + SysFreeString(str); + + if(r == S_OK) + { + r = IXMLDOMNode_get_nodeTypeString(node, &str); + ok( r == S_OK, "returns %08x\n", r ); + ok( !lstrcmpW( str, _bstr_("attribute") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + IXMLDOMNode_Release( node ); + } + + IXMLDOMElement_Release( element ); + IXMLDOMNode_Release( root ); + IXMLDOMDocument_Release( doc ); +} + +static void test_getElementsByTagName(void) +{ + HRESULT r; + BSTR str; + VARIANT_BOOL b; + IXMLDOMDocument *doc; + IXMLDOMNodeList *node_list; + LONG len; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + str = SysAllocString( szstar ); + r = IXMLDOMDocument_getElementsByTagName(doc, str, &node_list); + ok( r == S_OK, "ret %08x\n", r ); + r = IXMLDOMNodeList_get_length( node_list, &len ); + ok( r == S_OK, "ret %08x\n", r ); + ok( len == 6, "len %d\n", len ); + + test_disp((IUnknown*)node_list); + + IXMLDOMNodeList_Release( node_list ); + SysFreeString( str ); + + str = SysAllocString( szbs ); + r = IXMLDOMDocument_getElementsByTagName(doc, str, &node_list); + ok( r == S_OK, "ret %08x\n", r ); + r = IXMLDOMNodeList_get_length( node_list, &len ); + ok( r == S_OK, "ret %08x\n", r ); + ok( len == 1, "len %d\n", len ); + IXMLDOMNodeList_Release( node_list ); + SysFreeString( str ); + + str = SysAllocString( szdl ); + r = IXMLDOMDocument_getElementsByTagName(doc, str, &node_list); + ok( r == S_OK, "ret %08x\n", r ); + r = IXMLDOMNodeList_get_length( node_list, &len ); + ok( r == S_OK, "ret %08x\n", r ); + ok( len == 0, "len %d\n", len ); + IXMLDOMNodeList_Release( node_list ); + SysFreeString( str ); + + str = SysAllocString( szstr1 ); + r = IXMLDOMDocument_getElementsByTagName(doc, str, &node_list); + ok( r == S_OK, "ret %08x\n", r ); + r = IXMLDOMNodeList_get_length( node_list, &len ); + ok( r == S_OK, "ret %08x\n", r ); + ok( len == 0, "len %d\n", len ); + IXMLDOMNodeList_Release( node_list ); + SysFreeString( str ); + + IXMLDOMDocument_Release( doc ); +} + +static void test_get_text(void) +{ + HRESULT r; + BSTR str; + VARIANT_BOOL b; + IXMLDOMDocument *doc; + IXMLDOMNode *node, *node2, *node3; + IXMLDOMNode *nodeRoot; + IXMLDOMNodeList *node_list; + IXMLDOMNamedNodeMap *node_map; + LONG len; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + str = SysAllocString( szbs ); + r = IXMLDOMDocument_getElementsByTagName( doc, str, &node_list ); + ok( r == S_OK, "ret %08x\n", r ); + SysFreeString(str); + + /* Test to get all child node text. */ + r = IXMLDOMDocument_QueryInterface(doc, &IID_IXMLDOMNode, (LPVOID*)&nodeRoot); + ok( r == S_OK, "ret %08x\n", r ); + if(r == S_OK) + { + r = IXMLDOMNode_get_text( nodeRoot, &str ); + ok( r == S_OK, "ret %08x\n", r ); + ok( compareIgnoreReturnsWhitespace(str, _bstr_("fn1.txt\n\n fn2.txt \n\nf1\n")), "wrong get_text\n"); + SysFreeString(str); + + IXMLDOMNode_Release(nodeRoot); + } + + if (0) { + /* this test crashes on win9x */ + r = IXMLDOMNodeList_QueryInterface(node_list, &IID_IDispatch, NULL); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + } + + r = IXMLDOMNodeList_get_length( node_list, NULL ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + + r = IXMLDOMNodeList_get_length( node_list, &len ); + ok( r == S_OK, "ret %08x\n", r ); + ok( len == 1, "expect 1 got %d\n", len ); + + r = IXMLDOMNodeList_get_item( node_list, 0, NULL ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + + r = IXMLDOMNodeList_nextNode( node_list, NULL ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + + r = IXMLDOMNodeList_get_item( node_list, 0, &node ); + ok( r == S_OK, "ret %08x\n", r ); + IXMLDOMNodeList_Release( node_list ); + + /* Invalid output parameter*/ + r = IXMLDOMNode_get_text( node, NULL ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + + r = IXMLDOMNode_get_text( node, &str ); + ok( r == S_OK, "ret %08x\n", r ); + ok( !memcmp(str, szfn1_txt, lstrlenW(szfn1_txt) ), "wrong string\n" ); + SysFreeString(str); + + r = IXMLDOMNode_get_attributes( node, &node_map ); + ok( r == S_OK, "ret %08x\n", r ); + + str = SysAllocString( szvr ); + r = IXMLDOMNamedNodeMap_getNamedItem( node_map, str, &node2 ); + ok( r == S_OK, "ret %08x\n", r ); + SysFreeString(str); + + r = IXMLDOMNode_get_text( node2, &str ); + ok( r == S_OK, "ret %08x\n", r ); + ok( !memcmp(str, szstr2, sizeof(szstr2)), "wrong string\n" ); + SysFreeString(str); + + r = IXMLDOMNode_get_firstChild( node2, &node3 ); + ok( r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMNode_get_text( node3, &str ); + ok( r == S_OK, "ret %08x\n", r ); + ok( !memcmp(str, szstr2, sizeof(szstr2)), "wrong string\n" ); + SysFreeString(str); + + + IXMLDOMNode_Release( node3 ); + IXMLDOMNode_Release( node2 ); + IXMLDOMNamedNodeMap_Release( node_map ); + IXMLDOMNode_Release( node ); + IXMLDOMDocument_Release( doc ); +} + +static void test_get_childNodes(void) +{ + HRESULT r; + BSTR str; + VARIANT_BOOL b; + IXMLDOMDocument *doc; + IXMLDOMElement *element; + IXMLDOMNode *node, *node2; + IXMLDOMNodeList *node_list, *node_list2; + LONG len; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMElement_get_childNodes( element, &node_list ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNodeList_get_length( node_list, &len ); + ok( r == S_OK, "ret %08x\n", r); + ok( len == 4, "len %d\n", len); + + r = IXMLDOMNodeList_get_item( node_list, 2, &node ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNode_get_childNodes( node, &node_list2 ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNodeList_get_length( node_list2, &len ); + ok( r == S_OK, "ret %08x\n", r); + ok( len == 0, "len %d\n", len); + + r = IXMLDOMNodeList_get_item( node_list2, 0, &node2); + ok( r == S_FALSE, "ret %08x\n", r); + + IXMLDOMNodeList_Release( node_list2 ); + IXMLDOMNode_Release( node ); + IXMLDOMNodeList_Release( node_list ); + IXMLDOMElement_Release( element ); + IXMLDOMDocument_Release( doc ); +} + +static void test_removeChild(void) +{ + HRESULT r; + BSTR str; + VARIANT_BOOL b; + IXMLDOMDocument *doc; + IXMLDOMElement *element, *lc_element; + IXMLDOMNode *fo_node, *ba_node, *removed_node, *temp_node, *lc_node; + IXMLDOMNodeList *root_list, *fo_list; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMElement_get_childNodes( element, &root_list ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNodeList_get_item( root_list, 3, &fo_node ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNode_get_childNodes( fo_node, &fo_list ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNodeList_get_item( fo_list, 0, &ba_node ); + ok( r == S_OK, "ret %08x\n", r); + + /* invalid parameter: NULL ptr */ + removed_node = (void*)0xdeadbeef; + r = IXMLDOMElement_removeChild( element, NULL, &removed_node ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + ok( removed_node == (void*)0xdeadbeef, "%p\n", removed_node ); + + /* ba_node is a descendant of element, but not a direct child. */ + removed_node = (void*)0xdeadbeef; + r = IXMLDOMElement_removeChild( element, ba_node, &removed_node ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + ok( removed_node == NULL, "%p\n", removed_node ); + + r = IXMLDOMElement_removeChild( element, fo_node, &removed_node ); + ok( r == S_OK, "ret %08x\n", r); + ok( fo_node == removed_node, "node %p node2 %p\n", fo_node, removed_node ); + + /* try removing already removed child */ + temp_node = (void*)0xdeadbeef; + r = IXMLDOMElement_removeChild( element, fo_node, &temp_node ); + ok( r == E_INVALIDARG, "ret %08x\n", r); + ok( temp_node == NULL, "%p\n", temp_node ); + + /* the removed node has no parent anymore */ + r = IXMLDOMNode_get_parentNode( removed_node, &temp_node ); + ok( r == S_FALSE, "ret %08x\n", r); + ok( temp_node == NULL, "%p\n", temp_node ); + + IXMLDOMNode_Release( removed_node ); + IXMLDOMNode_Release( ba_node ); + IXMLDOMNodeList_Release( fo_list ); + + r = IXMLDOMNodeList_get_item( root_list, 0, &lc_node ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMElement_QueryInterface( lc_node, &IID_IXMLDOMElement, (LPVOID*)&lc_element ); + ok( r == S_OK, "ret %08x\n", r); + + /* MS quirk: passing wrong interface pointer works, too */ + r = IXMLDOMElement_removeChild( element, (IXMLDOMNode*)lc_element, NULL ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNode_get_parentNode( lc_node, &temp_node ); + ok( r == S_FALSE, "ret %08x\n", r); + ok( temp_node == NULL, "%p\n", temp_node ); + + IXMLDOMNode_Release( lc_node ); + IXMLDOMNodeList_Release( root_list ); + IXMLDOMElement_Release( element ); + IXMLDOMDocument_Release( doc ); +} + +static void test_replaceChild(void) +{ + HRESULT r; + BSTR str; + VARIANT_BOOL b; + IXMLDOMDocument *doc; + IXMLDOMElement *element, *ba_element; + IXMLDOMNode *fo_node, *ba_node, *lc_node, *removed_node, *temp_node; + IXMLDOMNodeList *root_list, *fo_list; + IUnknown * unk1, *unk2; + LONG len; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMElement_get_childNodes( element, &root_list ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNodeList_get_item( root_list, 0, &lc_node ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNodeList_get_item( root_list, 3, &fo_node ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNode_get_childNodes( fo_node, &fo_list ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNodeList_get_item( fo_list, 0, &ba_node ); + ok( r == S_OK, "ret %08x\n", r); + + IXMLDOMNodeList_Release( fo_list ); + + /* invalid parameter: NULL ptr for element to remove */ + removed_node = (void*)0xdeadbeef; + r = IXMLDOMElement_replaceChild( element, ba_node, NULL, &removed_node ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + ok( removed_node == (void*)0xdeadbeef, "%p\n", removed_node ); + + /* invalid parameter: NULL for replacement element. (Sic!) */ + removed_node = (void*)0xdeadbeef; + r = IXMLDOMElement_replaceChild( element, NULL, fo_node, &removed_node ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + ok( removed_node == (void*)0xdeadbeef, "%p\n", removed_node ); + + /* invalid parameter: OldNode is not a child */ + removed_node = (void*)0xdeadbeef; + r = IXMLDOMElement_replaceChild( element, lc_node, ba_node, &removed_node ); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + ok( removed_node == NULL, "%p\n", removed_node ); + + /* invalid parameter: would create loop */ + removed_node = (void*)0xdeadbeef; + r = IXMLDOMNode_replaceChild( fo_node, fo_node, ba_node, &removed_node ); + ok( r == E_FAIL, "ret %08x\n", r ); + ok( removed_node == NULL, "%p\n", removed_node ); + + r = IXMLDOMElement_replaceChild( element, ba_node, fo_node, NULL ); + ok( r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMNodeList_get_item( root_list, 3, &temp_node ); + ok( r == S_OK, "ret %08x\n", r ); + + /* ba_node and temp_node refer to the same node, yet they + are different interface pointers */ + ok( ba_node != temp_node, "ba_node %p temp_node %p\n", ba_node, temp_node); + r = IXMLDOMNode_QueryInterface( temp_node, &IID_IUnknown, (void**)&unk1); + ok( r == S_OK, "ret %08x\n", r ); + r = IXMLDOMNode_QueryInterface( ba_node, &IID_IUnknown, (void**)&unk2); + ok( r == S_OK, "ret %08x\n", r ); + todo_wine ok( unk1 == unk2, "unk1 %p unk2 %p\n", unk1, unk2); + + IUnknown_Release( unk1 ); + IUnknown_Release( unk2 ); + + /* ba_node should have been removed from below fo_node */ + r = IXMLDOMNode_get_childNodes( fo_node, &fo_list ); + ok( r == S_OK, "ret %08x\n", r ); + + /* MS quirk: replaceChild also accepts elements instead of nodes */ + r = IXMLDOMNode_QueryInterface( ba_node, &IID_IXMLDOMElement, (void**)&ba_element); + ok( r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMElement_replaceChild( element, ba_node, (IXMLDOMNode*)ba_element, &removed_node ); + ok( r == S_OK, "ret %08x\n", r ); + + r = IXMLDOMNodeList_get_length( fo_list, &len); + ok( r == S_OK, "ret %08x\n", r ); + ok( len == 0, "len %d\n", len); + + IXMLDOMNodeList_Release( fo_list ); + + IXMLDOMNode_Release(ba_node); + IXMLDOMNode_Release(fo_node); + IXMLDOMNode_Release(temp_node); + IXMLDOMNodeList_Release( root_list ); + IXMLDOMElement_Release( element ); + IXMLDOMDocument_Release( doc ); +} + +static void test_removeNamedItem(void) +{ + IXMLDOMDocument *doc; + IXMLDOMElement *element; + IXMLDOMNode *pr_node, *removed_node, *removed_node2; + IXMLDOMNodeList *root_list; + IXMLDOMNamedNodeMap * pr_attrs; + VARIANT_BOOL b; + BSTR str; + LONG len; + HRESULT r; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMElement_get_childNodes( element, &root_list ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNodeList_get_item( root_list, 1, &pr_node ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNode_get_attributes( pr_node, &pr_attrs ); + ok( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNamedNodeMap_get_length( pr_attrs, &len ); + ok( r == S_OK, "ret %08x\n", r); + ok( len == 3, "length %d\n", len); + + removed_node = (void*)0xdeadbeef; + r = IXMLDOMNamedNodeMap_removeNamedItem( pr_attrs, NULL, &removed_node); + ok ( r == E_INVALIDARG, "ret %08x\n", r); + ok ( removed_node == (void*)0xdeadbeef, "removed_node == %p\n", removed_node); + + removed_node = (void*)0xdeadbeef; + str = SysAllocString(szvr); + r = IXMLDOMNamedNodeMap_removeNamedItem( pr_attrs, str, &removed_node); + ok ( r == S_OK, "ret %08x\n", r); + + removed_node2 = (void*)0xdeadbeef; + r = IXMLDOMNamedNodeMap_removeNamedItem( pr_attrs, str, &removed_node2); + ok ( r == S_FALSE, "ret %08x\n", r); + ok ( removed_node2 == NULL, "removed_node == %p\n", removed_node2 ); + + r = IXMLDOMNamedNodeMap_get_length( pr_attrs, &len ); + ok( r == S_OK, "ret %08x\n", r); + ok( len == 2, "length %d\n", len); + + r = IXMLDOMNamedNodeMap_setNamedItem( pr_attrs, removed_node, NULL); + ok ( r == S_OK, "ret %08x\n", r); + IXMLDOMNode_Release(removed_node); + + r = IXMLDOMNamedNodeMap_get_length( pr_attrs, &len ); + ok( r == S_OK, "ret %08x\n", r); + ok( len == 3, "length %d\n", len); + + r = IXMLDOMNamedNodeMap_removeNamedItem( pr_attrs, str, NULL); + ok ( r == S_OK, "ret %08x\n", r); + + r = IXMLDOMNamedNodeMap_get_length( pr_attrs, &len ); + ok( r == S_OK, "ret %08x\n", r); + ok( len == 2, "length %d\n", len); + + r = IXMLDOMNamedNodeMap_removeNamedItem( pr_attrs, str, NULL); + ok ( r == S_FALSE, "ret %08x\n", r); + + SysFreeString(str); + + IXMLDOMNamedNodeMap_Release( pr_attrs ); + IXMLDOMNode_Release( pr_node ); + IXMLDOMNodeList_Release( root_list ); + IXMLDOMElement_Release( element ); + IXMLDOMDocument_Release( doc ); +} + +static void test_XMLHTTP(void) +{ + static const WCHAR wszBody[] = {'m','o','d','e','=','T','e','s','t',0}; + static WCHAR wszPOST[] = {'P','O','S','T',0}; + static WCHAR wszUrl[] = {'h','t','t','p',':','/','/', + 'c','r','o','s','s','o','v','e','r','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m','/', + 'p','o','s','t','t','e','s','t','.','p','h','p',0}; + static const WCHAR wszExpectedResponse[] = {'F','A','I','L','E','D',0}; + IXMLHttpRequest *pXMLHttpRequest; + BSTR bstrResponse; + VARIANT dummy; + VARIANT varfalse; + VARIANT varbody; + HRESULT hr = CoCreateInstance(&CLSID_XMLHTTPRequest, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLHttpRequest, + (void **)&pXMLHttpRequest); + ok(hr == S_OK, "CoCreateInstance(CLSID_XMLHTTPRequest) should have succeeded instead of failing with 0x%08x\n", hr); + if (hr != S_OK) + return; + + VariantInit(&dummy); + V_VT(&dummy) = VT_ERROR; + V_ERROR(&dummy) = DISP_E_MEMBERNOTFOUND; + VariantInit(&varfalse); + V_VT(&varfalse) = VT_BOOL; + V_BOOL(&varfalse) = VARIANT_FALSE; + V_VT(&varbody) = VT_BSTR; + V_BSTR(&varbody) = SysAllocString(wszBody); + + hr = IXMLHttpRequest_open(pXMLHttpRequest, wszPOST, wszUrl, varfalse, dummy, dummy); + todo_wine ok(hr == S_OK, "IXMLHttpRequest_open should have succeeded instead of failing with 0x%08x\n", hr); + + hr = IXMLHttpRequest_send(pXMLHttpRequest, varbody); + todo_wine ok(hr == S_OK, "IXMLHttpRequest_send should have succeeded instead of failing with 0x%08x\n", hr); + VariantClear(&varbody); + + hr = IXMLHttpRequest_get_responseText(pXMLHttpRequest, &bstrResponse); + todo_wine ok(hr == S_OK, "IXMLHttpRequest_get_responseText should have succeeded instead of failing with 0x%08x\n", hr); + /* the server currently returns "FAILED" because the Content-Type header is + * not what the server expects */ + if(hr == S_OK) + { + ok(!memcmp(bstrResponse, wszExpectedResponse, sizeof(wszExpectedResponse)), "bstrResponse differs from what was expected\n"); + SysFreeString(bstrResponse); + } + + IXMLHttpRequest_Release(pXMLHttpRequest); +} + +static void test_IXMLDOMDocument2(void) +{ + HRESULT r; + VARIANT_BOOL b; + BSTR str; + IXMLDOMDocument *doc; + IXMLDOMDocument2 *doc2; + IDispatchEx *dispex; + VARIANT var; + int ref; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + r = IXMLDOMDocument_QueryInterface( doc, &IID_IXMLDOMDocument2, (void**)&doc2 ); + ok( r == S_OK, "ret %08x\n", r ); + ok( doc == (IXMLDOMDocument*)doc2, "interfaces differ\n"); + + r = IXMLDOMDocument_QueryInterface( doc, &IID_IDispatchEx, (void**)&dispex ); + ok( r == S_OK, "ret %08x\n", r ); + if(r == S_OK) + { + IDispatchEx_Release(dispex); + } + + /* we will check if the variant got cleared */ + ref = IXMLDOMDocument2_AddRef(doc2); + expect_eq(ref, 3, int, "%d"); /* doc, doc2, AddRef*/ + V_VT(&var) = VT_UNKNOWN; + V_UNKNOWN(&var) = (IUnknown *)doc2; + + /* invalid calls */ + ole_expect(IXMLDOMDocument2_getProperty(doc2, _bstr_("askldhfaklsdf"), &var), E_FAIL); + expect_eq(V_VT(&var), VT_UNKNOWN, int, "%x"); + ole_expect(IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionLanguage"), NULL), E_INVALIDARG); + + /* valid call */ + ole_check(IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionLanguage"), &var)); + expect_eq(V_VT(&var), VT_BSTR, int, "%x"); + expect_bstr_eq_and_free(V_BSTR(&var), "XSLPattern"); + V_VT(&var) = VT_R4; + + /* the variant didn't get cleared*/ + expect_eq(IXMLDOMDocument2_Release(doc2), 2, int, "%d"); + + /* setProperty tests */ + ole_expect(IXMLDOMDocument2_setProperty(doc2, _bstr_("askldhfaklsdf"), var), E_FAIL); + ole_expect(IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionLanguage"), var), E_FAIL); + ole_expect(IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionLanguage"), _variantbstr_("alskjdh faklsjd hfk")), E_FAIL); + ole_check(IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionLanguage"), _variantbstr_("XSLPattern"))); + ole_check(IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionLanguage"), _variantbstr_("XPath"))); + ole_check(IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionLanguage"), _variantbstr_("XSLPattern"))); + + /* contrary to what MSDN claims you can switch back from XPath to XSLPattern */ + ole_check(IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionLanguage"), &var)); + expect_eq(V_VT(&var), VT_BSTR, int, "%x"); + expect_bstr_eq_and_free(V_BSTR(&var), "XSLPattern"); + + IXMLDOMDocument2_Release( doc2 ); + IXMLDOMDocument_Release( doc ); + free_bstrs(); +} + +static void test_XPath(void) +{ + HRESULT r; + VARIANT var; + VARIANT_BOOL b; + IXMLDOMDocument2 *doc; + IXMLDOMNode *rootNode; + IXMLDOMNode *elem1Node; + IXMLDOMNode *node; + IXMLDOMNodeList *list; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + ole_check(IXMLDOMDocument_loadXML(doc, _bstr_(szExampleXML), &b)); + ok(b == VARIANT_TRUE, "failed to load XML string\n"); + + /* switch to XPath */ + ole_check(IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionLanguage"), _variantbstr_("XPath"))); + + /* some simple queries*/ + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("root"), &list)); + ole_check(IXMLDOMNodeList_get_item(list, 0, &rootNode)); + ole_check(IXMLDOMNodeList_reset(list)); + expect_list_and_release(list, "E2.D1"); + if (rootNode == NULL) + return; + + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("root//c"), &list)); + expect_list_and_release(list, "E3.E1.E2.D1 E3.E2.E2.D1"); + + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("//c[@type]"), &list)); + expect_list_and_release(list, "E3.E2.E2.D1"); + + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_("elem"), &list)); + /* using get_item for query results advances the position */ + ole_check(IXMLDOMNodeList_get_item(list, 1, &node)); + expect_node(node, "E2.E2.D1"); + IXMLDOMNode_Release(node); + ole_check(IXMLDOMNodeList_nextNode(list, &node)); + expect_node(node, "E4.E2.D1"); + IXMLDOMNode_Release(node); + ole_check(IXMLDOMNodeList_reset(list)); + expect_list_and_release(list, "E1.E2.D1 E2.E2.D1 E4.E2.D1"); + + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_("."), &list)); + expect_list_and_release(list, "E2.D1"); + + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_("elem[3]/preceding-sibling::*"), &list)); + ole_check(IXMLDOMNodeList_get_item(list, 0, &elem1Node)); + ole_check(IXMLDOMNodeList_reset(list)); + expect_list_and_release(list, "E1.E2.D1 E2.E2.D1 E3.E2.D1"); + + /* select an attribute */ + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_(".//@type"), &list)); + expect_list_and_release(list, "A'type'.E3.E2.E2.D1"); + + /* would evaluate to a number */ + ole_expect(IXMLDOMNode_selectNodes(rootNode, _bstr_("count(*)"), &list), E_FAIL); + /* would evaluate to a boolean */ + ole_expect(IXMLDOMNode_selectNodes(rootNode, _bstr_("position()>0"), &list), E_FAIL); + /* would evaluate to a string */ + ole_expect(IXMLDOMNode_selectNodes(rootNode, _bstr_("name()"), &list), E_FAIL); + + /* no results */ + ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_("c"), &list)); + expect_list_and_release(list, ""); + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("elem//c"), &list)); + expect_list_and_release(list, ""); + ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("//elem[4]"), &list)); + expect_list_and_release(list, ""); + + /* foo undeclared in document node */ + ole_expect(IXMLDOMDocument_selectNodes(doc, _bstr_("root//foo:c"), &list), E_FAIL); + /* undeclared in node */ + ole_expect(IXMLDOMNode_selectNodes(rootNode, _bstr_(".//foo:c"), &list), E_FAIL); + /* undeclared in node */ + ole_expect(IXMLDOMNode_selectNodes(elem1Node, _bstr_("//foo:c"), &list), E_FAIL); + /* but this trick can be used */ + ole_check(IXMLDOMNode_selectNodes(elem1Node, _bstr_("//*[name()='foo:c']"), &list)); + expect_list_and_release(list, "E3.E4.E2.D1"); + + /* it has to be declared in SelectionNamespaces */ + todo_wine ole_check(IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionNamespaces"), + _variantbstr_("xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'"))); + + /* now the namespace can be used */ + todo_wine ole_check(IXMLDOMDocument_selectNodes(doc, _bstr_("root//test:c"), &list)); + todo_wine expect_list_and_release(list, "E3.E3.E2.D1 E3.E4.E2.D1"); + todo_wine ole_check(IXMLDOMNode_selectNodes(rootNode, _bstr_(".//test:c"), &list)); + todo_wine expect_list_and_release(list, "E3.E3.E2.D1 E3.E4.E2.D1"); + todo_wine ole_check(IXMLDOMNode_selectNodes(elem1Node, _bstr_("//test:c"), &list)); + todo_wine expect_list_and_release(list, "E3.E3.E2.D1 E3.E4.E2.D1"); + todo_wine ole_check(IXMLDOMNode_selectNodes(elem1Node, _bstr_(".//test:x"), &list)); + todo_wine expect_list_and_release(list, "E5.E1.E4.E1.E2.D1"); + + /* SelectionNamespaces syntax error - the namespaces doesn't work anymore but the value is stored */ + ole_expect(IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionNamespaces"), + _variantbstr_("xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' xmlns:foo=###")), E_FAIL); + + ole_expect(IXMLDOMDocument_selectNodes(doc, _bstr_("root//foo:c"), &list), E_FAIL); + + VariantInit(&var); + todo_wine ole_check(IXMLDOMDocument2_getProperty(doc, _bstr_("SelectionNamespaces"), &var)); + todo_wine expect_eq(V_VT(&var), VT_BSTR, int, "%x"); + if (V_VT(&var) == VT_BSTR) + expect_bstr_eq_and_free(V_BSTR(&var), "xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' xmlns:foo=###"); + + /* extra attributes - same thing*/ + ole_expect(IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionNamespaces"), + _variantbstr_("xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' param='test'")), E_FAIL); + ole_expect(IXMLDOMDocument_selectNodes(doc, _bstr_("root//foo:c"), &list), E_FAIL); + + IXMLDOMNode_Release(rootNode); + IXMLDOMNode_Release(elem1Node); + IXMLDOMDocument_Release(doc); + free_bstrs(); +} + +static void test_cloneNode(void ) +{ + IXMLDOMDocument *doc = NULL; + VARIANT_BOOL b; + IXMLDOMNodeList *pList; + IXMLDOMNamedNodeMap *mapAttr; + LONG nLength = 0, nLength1 = 0; + LONG nAttrCnt = 0, nAttrCnt1 = 0; + IXMLDOMNode *node; + IXMLDOMNode *node_clone; + IXMLDOMNode *node_first; + HRESULT r; + BSTR str; + static const WCHAR szSearch[] = { 'l', 'c', '/', 'p', 'r', 0 }; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + ole_check(IXMLDOMDocument_loadXML(doc, str, &b)); + ok(b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString(str); + + if(!b) + return; + + str = SysAllocString( szSearch); + r = IXMLDOMNode_selectSingleNode(doc, str, &node); + ok( r == S_OK, "ret %08x\n", r ); + ok( node != NULL, "node %p\n", node ); + SysFreeString(str); + + if(!node) + { + IXMLDOMDocument_Release(doc); + return; + } + + /* Check invalid parameter */ + r = IXMLDOMNode_cloneNode(node, VARIANT_TRUE, NULL); + ok( r == E_INVALIDARG, "ret %08x\n", r ); + + /* All Children */ + r = IXMLDOMNode_cloneNode(node, VARIANT_TRUE, &node_clone); + ok( r == S_OK, "ret %08x\n", r ); + ok( node_clone != NULL, "node %p\n", node ); + + if(!node_clone) + { + IXMLDOMDocument_Release(doc); + IXMLDOMNode_Release(node); + return; + } + + r = IXMLDOMNode_get_firstChild(node_clone, &node_first); + ok( r == S_OK, "ret %08x\n", r ); + if(r == S_OK) + { + IXMLDOMDocument *doc2; + + r = IXMLDOMNode_get_ownerDocument(node_clone, &doc2); + ok( r == S_OK, "ret %08x\n", r ); + if(r == S_OK) + IXMLDOMDocument_Release(doc2); + + IXMLDOMNode_Release(node_first); + } + + r = IXMLDOMNode_get_childNodes(node, &pList); + ok( r == S_OK, "ret %08x\n", r ); + if (pList) + { + IXMLDOMNodeList_get_length(pList, &nLength); + IXMLDOMNodeList_Release(pList); + } + + r = IXMLDOMNode_get_attributes(node, &mapAttr); + ok( r == S_OK, "ret %08x\n", r ); + if(mapAttr) + { + IXMLDOMNamedNodeMap_get_length(mapAttr, &nAttrCnt); + IXMLDOMNamedNodeMap_Release(mapAttr); + } + + r = IXMLDOMNode_get_childNodes(node_clone, &pList); + ok( r == S_OK, "ret %08x\n", r ); + if (pList) + { + IXMLDOMNodeList_get_length(pList, &nLength1); + IXMLDOMNodeList_Release(pList); + } + + r = IXMLDOMNode_get_attributes(node_clone, &mapAttr); + ok( r == S_OK, "ret %08x\n", r ); + if(mapAttr) + { + IXMLDOMNamedNodeMap_get_length(mapAttr, &nAttrCnt1); + IXMLDOMNamedNodeMap_Release(mapAttr); + } + + ok(nLength == nLength1, "wrong Child count (%d, %d)\n", nLength, nLength1); + ok(nAttrCnt == nAttrCnt1, "wrong Attribute count (%d, %d)\n", nAttrCnt, nAttrCnt1); + IXMLDOMNode_Release(node_clone); + + /* No Children */ + r = IXMLDOMNode_cloneNode(node, VARIANT_FALSE, &node_clone); + ok( r == S_OK, "ret %08x\n", r ); + ok( node_clone != NULL, "node %p\n", node ); + + if(!node_clone) + { + IXMLDOMDocument_Release(doc); + IXMLDOMNode_Release(node); + return; + } + + r = IXMLDOMNode_get_firstChild(node_clone, &node_first); + ok( r == S_FALSE, "ret %08x\n", r ); + if(r == S_OK) + { + IXMLDOMDocument *doc2; + + r = IXMLDOMNode_get_ownerDocument(node_clone, &doc2); + ok( r == S_OK, "ret %08x\n", r ); + if(r == S_OK) + IXMLDOMDocument_Release(doc2); + + IXMLDOMNode_Release(node_first); + } + + r = IXMLDOMNode_get_childNodes(node_clone, &pList); + ok( r == S_OK, "ret %08x\n", r ); + if (pList) + { + IXMLDOMNodeList_get_length(pList, &nLength1); + ok( nLength1 == 0, "Length should be 0 (%d)\n", nLength1); + IXMLDOMNodeList_Release(pList); + } + + r = IXMLDOMNode_get_attributes(node_clone, &mapAttr); + ok( r == S_OK, "ret %08x\n", r ); + if(mapAttr) + { + IXMLDOMNamedNodeMap_get_length(mapAttr, &nAttrCnt1); + ok( nAttrCnt1 == 3, "Attribute count should be 3 (%d)\n", nAttrCnt1); + IXMLDOMNamedNodeMap_Release(mapAttr); + } + + ok(nLength != nLength1, "wrong Child count (%d, %d)\n", nLength, nLength1); + ok(nAttrCnt == nAttrCnt1, "wrong Attribute count (%d, %d)\n", nAttrCnt, nAttrCnt1); + IXMLDOMNode_Release(node_clone); + + + IXMLDOMNode_Release(node); + IXMLDOMDocument_Release(doc); +} + +static void test_xmlTypes(void) +{ + IXMLDOMDocument *doc = NULL; + IXMLDOMElement *pRoot; + HRESULT hr; + IXMLDOMComment *pComment; + IXMLDOMElement *pElement; + IXMLDOMAttribute *pAttrubute; + IXMLDOMNamedNodeMap *pAttribs; + IXMLDOMCDATASection *pCDataSec; + IXMLDOMImplementation *pIXMLDOMImplementation = NULL; + IXMLDOMDocumentFragment *pDocFrag = NULL; + IXMLDOMEntityReference *pEntityRef = NULL; + BSTR str; + IXMLDOMNode *pNextChild = (IXMLDOMNode *)0x1; /* Used for testing Siblings */ + VARIANT v; + LONG len = 0; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = IXMLDOMDocument_get_nextSibling(doc, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_get_nextSibling(doc, &pNextChild); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pNextChild == NULL, "pDocChild not NULL\n"); + + /* test previous Sibling */ + hr = IXMLDOMDocument_get_previousSibling(doc, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + pNextChild = (IXMLDOMNode *)0x1; + hr = IXMLDOMDocument_get_previousSibling(doc, &pNextChild); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pNextChild == NULL, "pNextChild not NULL\n"); + + /* test get_attributes */ + hr = IXMLDOMDocument_get_attributes( doc, NULL ); + ok( hr == E_INVALIDARG, "get_attributes returned wrong code\n"); + + pAttribs = (IXMLDOMNamedNodeMap*)0x1; + hr = IXMLDOMDocument_get_attributes( doc, &pAttribs); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( pAttribs == NULL, "pAttribs not NULL\n"); + + /* test get_dataType */ + hr = IXMLDOMDocument_get_dataType(doc, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( V_VT(&v) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&v); + + /* test nodeTypeString */ + hr = IXMLDOMDocument_get_nodeTypeString(doc, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("document") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + /* test implementation */ + hr = IXMLDOMDocument_get_implementation(doc, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_get_implementation(doc, &pIXMLDOMImplementation); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + VARIANT_BOOL hasFeature = VARIANT_TRUE; + BSTR sEmpty = SysAllocStringLen(NULL, 0); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, NULL, sEmpty, &hasFeature); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, sEmpty, sEmpty, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("DOM"), sEmpty, &hasFeature); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(hasFeature == VARIANT_FALSE, "hasFeature returned false\n"); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, sEmpty, sEmpty, &hasFeature); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(hasFeature == VARIANT_FALSE, "hasFeature returned true\n"); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("DOM"), NULL, &hasFeature); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(hasFeature == VARIANT_TRUE, "hasFeature returned false\n"); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("DOM"), sEmpty, &hasFeature); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(hasFeature == VARIANT_FALSE, "hasFeature returned false\n"); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("DOM"), _bstr_("1.0"), &hasFeature); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(hasFeature == VARIANT_TRUE, "hasFeature returned true\n"); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("XML"), _bstr_("1.0"), &hasFeature); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(hasFeature == VARIANT_TRUE, "hasFeature returned true\n"); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("MS-DOM"), _bstr_("1.0"), &hasFeature); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(hasFeature == VARIANT_TRUE, "hasFeature returned true\n"); + + hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("SSS"), NULL, &hasFeature); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(hasFeature == VARIANT_FALSE, "hasFeature returned false\n"); + + SysFreeString(sEmpty); + IXMLDOMImplementation_Release(pIXMLDOMImplementation); + } + + + + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing"), &pRoot); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode*)pRoot, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + /* Comment */ + hr = IXMLDOMDocument_createComment(doc, szComment, &pComment); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + /* test get_attributes */ + hr = IXMLDOMComment_get_attributes( pComment, NULL ); + ok( hr == E_INVALIDARG, "get_attributes returned wrong code\n"); + + pAttribs = (IXMLDOMNamedNodeMap*)0x1; + hr = IXMLDOMComment_get_attributes( pComment, &pAttribs); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( pAttribs == NULL, "pAttribs not NULL\n"); + + /* test nodeTypeString */ + hr = IXMLDOMComment_get_nodeTypeString(pComment, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("comment") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pComment, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_get_nodeName(pComment, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szCommentNodeText ), "incorrect comment node Name\n"); + SysFreeString(str); + + hr = IXMLDOMComment_get_xml(pComment, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szCommentXML ), "incorrect comment xml\n"); + SysFreeString(str); + + hr = IXMLDOMComment_get_dataType(pComment, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( V_VT(&v) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&v); + + /* put data Tests */ + hr = IXMLDOMComment_put_data(pComment, _bstr_("This &is a ; test <>\\")); + ok(hr == S_OK, "ret %08x\n", hr ); + + /* get data Tests */ + hr = IXMLDOMComment_get_data(pComment, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\") ), "incorrect get_data string\n"); + SysFreeString(str); + + /* get data Tests */ + hr = IXMLDOMComment_get_nodeValue(pComment, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( V_VT(&v) == VT_BSTR, "incorrect dataType type\n"); + ok( !lstrcmpW( V_BSTR(&v), _bstr_("This &is a ; test <>\\") ), "incorrect get_nodeValue string\n"); + VariantClear(&v); + + /* Confirm XML text is good */ + hr = IXMLDOMComment_get_xml(pComment, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("") ), "incorrect xml string\n"); + SysFreeString(str); + + /* Confirm we get the put_data Text back */ + hr = IXMLDOMComment_get_text(pComment, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\") ), "incorrect xml string\n"); + SysFreeString(str); + + /* test length property */ + hr = IXMLDOMComment_get_length(pComment, &len); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(len == 21, "expected 21 got %d\n", len); + + /* test substringData */ + hr = IXMLDOMComment_substringData(pComment, 0, 4, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + /* test substringData - Invalid offset */ + str = (BSTR)&szElement; + hr = IXMLDOMComment_substringData(pComment, -1, 4, &str); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid offset */ + str = (BSTR)&szElement; + hr = IXMLDOMComment_substringData(pComment, 30, 0, &str); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid size */ + str = (BSTR)&szElement; + hr = IXMLDOMComment_substringData(pComment, 0, -1, &str); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid size */ + str = (BSTR)&szElement; + hr = IXMLDOMComment_substringData(pComment, 2, 0, &str); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Start of string */ + hr = IXMLDOMComment_substringData(pComment, 0, 4, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test substringData - Middle of string */ + hr = IXMLDOMComment_substringData(pComment, 13, 4, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("test") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test substringData - End of string */ + hr = IXMLDOMComment_substringData(pComment, 20, 4, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("\\") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test appendData */ + hr = IXMLDOMComment_appendData(pComment, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_appendData(pComment, _bstr_("")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_appendData(pComment, _bstr_("Append")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_get_text(pComment, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\Append") ), "incorrect get_text string\n"); + SysFreeString(str); + + /* test insertData */ + str = SysAllocStringLen(NULL, 0); + hr = IXMLDOMComment_insertData(pComment, -1, str); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, -1, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, 1000, str); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, 1000, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, 0, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, 0, str); + ok(hr == S_OK, "ret %08x\n", hr ); + SysFreeString(str); + + hr = IXMLDOMComment_insertData(pComment, -1, _bstr_("Inserting")); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, 1000, _bstr_("Inserting")); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, 0, _bstr_("Begin ")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, 17, _bstr_("Middle")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_insertData(pComment, 39, _bstr_(" End")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMComment_get_text(pComment, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("Begin This &is a Middle; test <>\\Append End") ), "incorrect get_text string\n"); + SysFreeString(str); + + IXMLDOMComment_Release(pComment); + } + + /* Element */ + hr = IXMLDOMDocument_createElement(doc, szElement, &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + /* test nodeTypeString */ + hr = IXMLDOMDocument_get_nodeTypeString(pElement, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("element") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + hr = IXMLDOMElement_get_nodeName(pElement, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szElement ), "incorrect element node Name\n"); + SysFreeString(str); + + hr = IXMLDOMElement_get_xml(pElement, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szElementXML ), "incorrect element xml\n"); + SysFreeString(str); + + hr = IXMLDOMElement_get_dataType(pElement, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( V_VT(&v) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&v); + + /* Attribute */ + hr = IXMLDOMDocument_createAttribute(doc, szAttribute, &pAttrubute); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMNode *pNewChild = (IXMLDOMNode *)0x1; + + hr = IXMLDOMAttribute_get_nextSibling(pAttrubute, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + pNextChild = (IXMLDOMNode *)0x1; + hr = IXMLDOMAttribute_get_nextSibling(pAttrubute, &pNextChild); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pNextChild == NULL, "pNextChild not NULL\n"); + + /* test Previous Sibling*/ + hr = IXMLDOMAttribute_get_previousSibling(pAttrubute, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + pNextChild = (IXMLDOMNode *)0x1; + hr = IXMLDOMAttribute_get_previousSibling(pAttrubute, &pNextChild); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pNextChild == NULL, "pNextChild not NULL\n"); + + /* test get_attributes */ + hr = IXMLDOMAttribute_get_attributes( pAttrubute, NULL ); + ok( hr == E_INVALIDARG, "get_attributes returned wrong code\n"); + + pAttribs = (IXMLDOMNamedNodeMap*)0x1; + hr = IXMLDOMAttribute_get_attributes( pAttrubute, &pAttribs); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( pAttribs == NULL, "pAttribs not NULL\n"); + + hr = IXMLDOMElement_appendChild(pElement, (IXMLDOMNode*)pAttrubute, &pNewChild); + ok(hr == E_FAIL, "ret %08x\n", hr ); + ok(pNewChild == NULL, "pNewChild not NULL\n"); + + hr = IXMLDOMElement_get_attributes(pElement, &pAttribs); + ok(hr == S_OK, "ret %08x\n", hr ); + if ( hr == S_OK ) + { + hr = IXMLDOMNamedNodeMap_setNamedItem(pAttribs, (IXMLDOMNode*)pAttrubute, NULL ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMNamedNodeMap_Release(pAttribs); + } + + hr = IXMLDOMAttribute_get_nodeName(pAttrubute, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szAttribute ), "incorrect attribute node Name\n"); + SysFreeString(str); + + /* test nodeTypeString */ + hr = IXMLDOMAttribute_get_nodeTypeString(pAttrubute, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("attribute") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + /* test nodeName */ + hr = IXMLDOMAttribute_get_nodeName(pAttrubute, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szAttribute ), "incorrect nodeName string\n"); + SysFreeString(str); + + /* test name property */ + hr = IXMLDOMAttribute_get_name(pAttrubute, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szAttribute ), "incorrect name string\n"); + SysFreeString(str); + + hr = IXMLDOMAttribute_get_xml(pAttrubute, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szAttributeXML ), "incorrect attribute xml\n"); + SysFreeString(str); + + hr = IXMLDOMAttribute_get_dataType(pAttrubute, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( V_VT(&v) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&v); + + IXMLDOMAttribute_Release(pAttrubute); + + /* Check Element again with the Add Attribute*/ + hr = IXMLDOMElement_get_xml(pElement, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szElementXML2 ), "incorrect element xml\n"); + SysFreeString(str); + } + + hr = IXMLDOMElement_put_text(pElement, _bstr_("TestingNode")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMElement_get_xml(pElement, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szElementXML3 ), "incorrect element xml\n"); + SysFreeString(str); + + /* Test for reversible escaping */ + str = SysAllocString( szStrangeChars ); + hr = IXMLDOMElement_put_text(pElement, str); + ok(hr == S_OK, "ret %08x\n", hr ); + SysFreeString( str ); + + hr = IXMLDOMElement_get_xml(pElement, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szElementXML4 ), "incorrect element xml\n"); + SysFreeString(str); + + hr = IXMLDOMElement_get_text(pElement, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szStrangeChars ), "incorrect element text\n"); + SysFreeString(str); + + IXMLDOMElement_Release(pElement); + } + + /* CData Section */ + hr = IXMLDOMDocument_createCDATASection(doc, szCData, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_createCDATASection(doc, szCData, &pCDataSec); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMNode *pNextChild = (IXMLDOMNode *)0x1; + VARIANT var; + + hr = IXMLDOMCDATASection_QueryInterface(pCDataSec, &IID_IXMLDOMElement, (LPVOID*)&pElement); + ok(hr == E_NOINTERFACE, "ret %08x\n", hr); + + hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pCDataSec, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + /* get Attribute Tests */ + hr = IXMLDOMCDATASection_get_attributes(pCDataSec, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + pAttribs = (IXMLDOMNamedNodeMap*)0x1; + hr = IXMLDOMCDATASection_get_attributes(pCDataSec, &pAttribs); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pAttribs == NULL, "pAttribs != NULL\n"); + + hr = IXMLDOMCDATASection_get_nodeName(pCDataSec, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szCDataNodeText ), "incorrect cdata node Name\n"); + SysFreeString(str); + + hr = IXMLDOMCDATASection_get_xml(pCDataSec, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szCDataXML ), "incorrect cdata xml\n"); + SysFreeString(str); + + /* test lastChild */ + pNextChild = (IXMLDOMNode*)0x1; + hr = IXMLDOMCDATASection_get_lastChild(pCDataSec, &pNextChild); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pNextChild == NULL, "pNextChild not NULL\n"); + + /* test get_dataType */ + hr = IXMLDOMCDATASection_get_dataType(pCDataSec, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_get_dataType(pCDataSec, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( V_VT(&v) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&v); + + /* test nodeTypeString */ + hr = IXMLDOMCDATASection_get_nodeTypeString(pCDataSec, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("cdatasection") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + /* put data Tests */ + hr = IXMLDOMCDATASection_put_data(pCDataSec, _bstr_("This &is a ; test <>\\")); + ok(hr == S_OK, "ret %08x\n", hr ); + + /* Confirm XML text is good */ + hr = IXMLDOMCDATASection_get_xml(pCDataSec, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("\\]]>") ), "incorrect xml string\n"); + SysFreeString(str); + + /* Confirm we get the put_data Text back */ + hr = IXMLDOMCDATASection_get_text(pCDataSec, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\") ), "incorrect text string\n"); + SysFreeString(str); + + /* test length property */ + hr = IXMLDOMCDATASection_get_length(pCDataSec, &len); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(len == 21, "expected 21 got %d\n", len); + + /* test get nodeValue */ + hr = IXMLDOMCDATASection_get_nodeValue(pCDataSec, &var); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\") ), "incorrect text string\n"); + VariantClear(&var); + + /* test get data */ + hr = IXMLDOMCDATASection_get_data(pCDataSec, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\") ), "incorrect text string\n"); + SysFreeString(str); + + /* test substringData */ + hr = IXMLDOMCDATASection_substringData(pCDataSec, 0, 4, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + /* test substringData - Invalid offset */ + str = (BSTR)&szElement; + hr = IXMLDOMCDATASection_substringData(pCDataSec, -1, 4, &str); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid offset */ + str = (BSTR)&szElement; + hr = IXMLDOMCDATASection_substringData(pCDataSec, 30, 0, &str); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid size */ + str = (BSTR)&szElement; + hr = IXMLDOMCDATASection_substringData(pCDataSec, 0, -1, &str); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Invalid size */ + str = (BSTR)&szElement; + hr = IXMLDOMCDATASection_substringData(pCDataSec, 2, 0, &str); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( str == NULL, "incorrect string\n"); + + /* test substringData - Start of string */ + hr = IXMLDOMCDATASection_substringData(pCDataSec, 0, 4, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test substringData - Middle of string */ + hr = IXMLDOMCDATASection_substringData(pCDataSec, 13, 4, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("test") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test substringData - End of string */ + hr = IXMLDOMCDATASection_substringData(pCDataSec, 20, 4, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("\\") ), "incorrect substringData string\n"); + SysFreeString(str); + + /* test appendData */ + hr = IXMLDOMCDATASection_appendData(pCDataSec, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_appendData(pCDataSec, _bstr_("")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_appendData(pCDataSec, _bstr_("Append")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_get_text(pCDataSec, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("This &is a ; test <>\\Append") ), "incorrect get_text string\n"); + SysFreeString(str); + + /* test insertData */ + str = SysAllocStringLen(NULL, 0); + hr = IXMLDOMCDATASection_insertData(pCDataSec, -1, str); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, -1, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, 1000, str); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, 1000, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, 0, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, 0, str); + ok(hr == S_OK, "ret %08x\n", hr ); + SysFreeString(str); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, -1, _bstr_("Inserting")); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, 1000, _bstr_("Inserting")); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, 0, _bstr_("Begin ")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, 17, _bstr_("Middle")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_insertData(pCDataSec, 39, _bstr_(" End")); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMCDATASection_get_text(pCDataSec, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("Begin This &is a Middle; test <>\\Append End") ), "incorrect get_text string\n"); + SysFreeString(str); + + IXMLDOMCDATASection_Release(pCDataSec); + } + + /* Document Fragments */ + hr = IXMLDOMDocument_createDocumentFragment(doc, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_createDocumentFragment(doc, &pDocFrag); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMNode *pNextChild = (IXMLDOMNode *)0x1; + + hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pDocFrag, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + /* get Attribute Tests */ + hr = IXMLDOMDocumentFragment_get_attributes(pDocFrag, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + pAttribs = (IXMLDOMNamedNodeMap*)0x1; + hr = IXMLDOMDocumentFragment_get_attributes(pDocFrag, &pAttribs); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pAttribs == NULL, "pAttribs != NULL\n"); + + hr = IXMLDOMDocumentFragment_get_nodeName(pDocFrag, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szDocFragmentText ), "incorrect docfragment node Name\n"); + SysFreeString(str); + + /* test next Sibling*/ + hr = IXMLDOMDocumentFragment_get_nextSibling(pDocFrag, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + pNextChild = (IXMLDOMNode *)0x1; + hr = IXMLDOMDocumentFragment_get_nextSibling(pDocFrag, &pNextChild); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pNextChild == NULL, "pNextChild not NULL\n"); + + /* test Previous Sibling*/ + hr = IXMLDOMDocumentFragment_get_previousSibling(pDocFrag, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + pNextChild = (IXMLDOMNode *)0x1; + hr = IXMLDOMDocumentFragment_get_previousSibling(pDocFrag, &pNextChild); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pNextChild == NULL, "pNextChild not NULL\n"); + + /* test get_dataType */ + hr = IXMLDOMDocumentFragment_get_dataType(pDocFrag, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMDocumentFragment_get_dataType(pDocFrag, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( V_VT(&v) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&v); + + /* test nodeTypeString */ + hr = IXMLDOMDocumentFragment_get_nodeTypeString(pDocFrag, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("documentfragment") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + IXMLDOMDocumentFragment_Release(pDocFrag); + } + + /* Entity References */ + hr = IXMLDOMDocument_createEntityReference(doc, szEntityRef, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_createEntityReference(doc, szEntityRef, &pEntityRef); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pEntityRef, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + + /* get Attribute Tests */ + hr = IXMLDOMEntityReference_get_attributes(pEntityRef, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + pAttribs = (IXMLDOMNamedNodeMap*)0x1; + hr = IXMLDOMEntityReference_get_attributes(pEntityRef, &pAttribs); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(pAttribs == NULL, "pAttribs != NULL\n"); + + /* test dataType */ + hr = IXMLDOMEntityReference_get_dataType(pEntityRef, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok( V_VT(&v) == VT_NULL, "incorrect dataType type\n"); + VariantClear(&v); + + /* test nodeTypeString */ + hr = IXMLDOMEntityReference_get_nodeTypeString(pEntityRef, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("entityreference") ), "incorrect nodeTypeString string\n"); + SysFreeString(str); + + /* test get_xml*/ + hr = IXMLDOMEntityReference_get_xml(pEntityRef, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, szEntityRefXML ), "incorrect xml string\n"); + SysFreeString(str); + + IXMLDOMEntityReference_Release(pEntityRef); + } + + IXMLDOMElement_Release( pRoot ); + } + } + + IXMLDOMDocument_Release(doc); + + free_bstrs(); +} + +static void test_nodeTypeTests( void ) +{ + IXMLDOMDocument *doc = NULL; + IXMLDOMElement *pRoot; + IXMLDOMElement *pElement; + HRESULT hr; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing"), &pRoot); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode*)pRoot, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMElement_put_dataType(pRoot, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + /* Invalid Value */ + hr = IXMLDOMElement_put_dataType(pRoot, _bstr_("abcdefg") ); + ok(hr == E_FAIL, "ret %08x\n", hr ); + + /* NOTE: + * The name passed into put_dataType is case-insensitive. So many of the names + * have been changed to reflect this. + */ + /* Boolean */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_Boolean"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("Boolean") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* String */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_String"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("String") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* Number */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_Number"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("number") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* Int */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_Int"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("InT") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* Fixed */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_Fixed"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("fixed.14.4") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* DateTime */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_DateTime"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("DateTime") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* DateTime TZ */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_DateTime_tz"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("DateTime.tz") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* Date */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_Date"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("Date") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* Time */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_Time"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("Time") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* Time.tz */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_Time_TZ"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("Time.tz") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* I1 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_I1"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("I1") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* I2 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_I2"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("I2") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* I4 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_I4"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("I4") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* UI1 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_UI1"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("UI1") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* UI2 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_UI2"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("UI2") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* UI4 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_UI4"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("UI4") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* r4 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_r4"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("r4") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* r8 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_r8"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("r8") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* float */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_float"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("float") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* uuid */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_uuid"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("UuId") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* bin.hex */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_bin_hex"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("bin.hex") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* bin.base64 */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_bin_base64"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("bin.base64") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + /* Check changing types */ + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing_Change"), &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("DateTime.tz") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMElement_put_dataType(pElement, _bstr_("string") ); + ok(hr == S_OK, "ret %08x\n", hr ); + + IXMLDOMElement_Release(pElement); + } + + IXMLDOMElement_Release(pRoot); + } + } + + IXMLDOMDocument_Release(doc); + + free_bstrs(); +} + +static void test_DocumentSaveToDocument(void) +{ + IXMLDOMDocument *doc = NULL; + IXMLDOMDocument *doc2 = NULL; + IXMLDOMElement *pRoot; + + HRESULT hr; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc2 ); + if( hr != S_OK ) + { + IXMLDOMDocument_Release(doc); + return; + } + + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing"), &pRoot); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode*)pRoot, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + VARIANT vDoc; + BSTR sOrig; + BSTR sNew; + + V_VT(&vDoc) = VT_UNKNOWN; + V_UNKNOWN(&vDoc) = (IUnknown*)doc2; + + hr = IXMLDOMDocument_save(doc, vDoc); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_get_xml(doc, &sOrig); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_get_xml(doc2, &sNew); + ok(hr == S_OK, "ret %08x\n", hr ); + + ok( !lstrcmpW( sOrig, sNew ), "New document is not the same as origial\n"); + + SysFreeString(sOrig); + SysFreeString(sNew); + } + } + + IXMLDOMDocument_Release(doc2); + IXMLDOMDocument_Release(doc); +} + +static void test_DocumentSaveToFile(void) +{ + IXMLDOMDocument *doc = NULL; + IXMLDOMElement *pRoot; + HANDLE file; + char buffer[100]; + DWORD read = 0; + HRESULT hr; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = IXMLDOMDocument_createElement(doc, _bstr_("Testing"), &pRoot); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode*)pRoot, NULL); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + VARIANT vFile; + + V_VT(&vFile) = VT_BSTR; + V_BSTR(&vFile) = _bstr_("test.xml"); + + hr = IXMLDOMDocument_save(doc, vFile); + ok(hr == S_OK, "ret %08x\n", hr ); + } + } + + IXMLDOMElement_Release(pRoot); + IXMLDOMDocument_Release(doc); + + file = CreateFile("test.xml", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + ok(file != INVALID_HANDLE_VALUE, "Could not open file: %u\n", GetLastError()); + if(file == INVALID_HANDLE_VALUE) + return; + + ReadFile(file, buffer, sizeof(buffer), &read, NULL); + ok(read != 0, "could not read file\n"); + ok(buffer[0] != '<' || buffer[1] != '?', "File contains processing instruction\n"); + + CloseHandle(file); + DeleteFile("test.xml"); +} + +static void test_testTransforms(void) +{ + IXMLDOMDocument *doc = NULL; + IXMLDOMDocument *docSS = NULL; + IXMLDOMNode *pNode; + VARIANT_BOOL bSucc; + + HRESULT hr; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&docSS ); + if( hr != S_OK ) + { + IXMLDOMDocument_Release(doc); + return; + } + + hr = IXMLDOMDocument_loadXML(doc, _bstr_(szTransformXML), &bSucc); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_loadXML(docSS, _bstr_(szTransformSSXML), &bSucc); + ok(hr == S_OK, "ret %08x\n", hr ); + + hr = IXMLDOMDocument_QueryInterface(docSS, &IID_IXMLDOMNode, (LPVOID*)&pNode ); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + BSTR bOut; + + hr = IXMLDOMDocument_transformNode(doc, pNode, &bOut); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( compareIgnoreReturns( bOut, _bstr_(szTransformOutput)), "Stylesheet output not correct\n"); + SysFreeString(bOut); + + IXMLDOMNode_Release(pNode); + } + + IXMLDOMDocument_Release(docSS); + IXMLDOMDocument_Release(doc); + + free_bstrs(); +} + +static void test_Namespaces(void) +{ + IXMLDOMDocument2 *doc = NULL; + IXMLDOMNode *pNode; + IXMLDOMNode *pNode2 = NULL; + VARIANT_BOOL bSucc; + HRESULT hr; + BSTR str; + static const CHAR szNamespacesXML[] = +"\n" +"\n" +"\n" +""; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = IXMLDOMDocument2_loadXML(doc, _bstr_(szNamespacesXML), &bSucc); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n"); + + hr = IXMLDOMDocument_selectSingleNode(doc, _bstr_("root"), &pNode ); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_firstChild( pNode, &pNode2 ); + ok( hr == S_OK, "ret %08x\n", hr ); + ok( pNode2 != NULL, "pNode2 == NULL\n"); + + /* Test get_prefix */ + hr = IXMLDOMNode_get_prefix(pNode2, NULL); + ok( hr == E_INVALIDARG, "ret %08x\n", hr ); + /* NOTE: Need to test that arg2 gets cleared on Error. */ + + hr = IXMLDOMNode_get_prefix(pNode2, &str); + ok( hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("WEB")), "incorrect prefix string\n"); + SysFreeString(str); + + /* Test get_namespaceURI */ + hr = IXMLDOMNode_get_namespaceURI(pNode2, NULL); + ok( hr == E_INVALIDARG, "ret %08x\n", hr ); + /* NOTE: Need to test that arg2 gets cleared on Error. */ + + hr = IXMLDOMNode_get_namespaceURI(pNode2, &str); + ok( hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_("http://www.winehq.org")), "incorrect namespaceURI string\n"); + SysFreeString(str); + + IXMLDOMNode_Release(pNode2); + IXMLDOMNode_Release(pNode); + } + + IXMLDOMDocument2_Release(doc); + + free_bstrs(); +} + +static void test_FormattingXML(void) +{ + IXMLDOMDocument2 *doc = NULL; + IXMLDOMElement *pElement; + VARIANT_BOOL bSucc; + HRESULT hr; + BSTR str; + static const CHAR szLinefeedXML[] = "\n\n\t\n"; + static const CHAR szLinefeedRootXML[] = "\r\n\t\r\n"; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = IXMLDOMDocument2_loadXML(doc, _bstr_(szLinefeedXML), &bSucc); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n"); + + if(bSucc == VARIANT_TRUE) + { + hr = IXMLDOMDocument2_get_documentElement(doc, &pElement); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMElement_get_xml(pElement, &str); + ok(hr == S_OK, "ret %08x\n", hr ); + ok( !lstrcmpW( str, _bstr_(szLinefeedRootXML) ), "incorrect element xml\n"); + SysFreeString(str); + + IXMLDOMElement_Release(pElement); + } + } + + IXMLDOMDocument2_Release(doc); + + free_bstrs(); +} + +static void test_NodeTypeValue(void) +{ + IXMLDOMDocument2 *doc = NULL; + IXMLDOMNode *pNode; + VARIANT_BOOL bSucc; + HRESULT hr; + VARIANT v; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = IXMLDOMDocument2_loadXML(doc, _bstr_(szTypeValueXML), &bSucc); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n"); + if(bSucc == VARIANT_TRUE) + { + hr = IXMLDOMDocument2_get_nodeValue(doc, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = NULL; + hr = IXMLDOMDocument2_get_nodeValue(doc, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_NULL, "expect VT_NULL got %d\n", V_VT(&v)); + + hr = IXMLDOMDocument2_get_nodeTypedValue(doc, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMDocument2_get_nodeTypedValue(doc, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/string"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = NULL; + hr = IXMLDOMNode_get_nodeValue(pNode, &v); + ok(hr == S_FALSE, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_NULL, "expect VT_NULL got %d\n", V_VT(&v)); + + hr = IXMLDOMNode_get_nodeTypedValue(pNode, NULL); + ok(hr == E_INVALIDARG, "ret %08x\n", hr ); + + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW( V_BSTR(&v), _bstr_("Wine") ), "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/string2"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW( V_BSTR(&v), _bstr_("String") ), "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/number"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW( V_BSTR(&v), _bstr_("12.44") ), "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/number2"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW( V_BSTR(&v), _bstr_("-3.71e3") ), "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/int"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_I4, "incorrect type\n"); + ok(V_I4(&v) == -13, "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/fixed"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_CY, "incorrect type\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/bool"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BOOL, "incorrect type\n"); + ok(V_BOOL(&v) == VARIANT_TRUE, "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/datetime"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(40135.13996527778, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/datetimetz"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(37813.59302083334, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/date"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(665413.0, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/time"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(0.5813888888888888, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/timetz"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_DATE, "incorrect type\n"); + double_eq(1.112511574074074, V_DATE(&v)); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/i1"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_I1, "incorrect type\n"); + ok(V_I1(&v) == -13, "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/i2"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_I2, "incorrect type\n"); + ok(V_I2(&v) == 31915, "incorrect value\n"); + VariantClear( &v ); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/i4"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_I4, "incorrect type\n"); + ok(V_I4(&v) == -312232, "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/ui1"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_UI1, "incorrect type\n"); + ok(V_UI1(&v) == 123, "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/ui2"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_UI2, "incorrect type\n"); + ok(V_UI2(&v) == 48282, "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/ui4"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_UI4, "incorrect type\n"); + ok(V_UI4(&v) == 949281, "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/r4"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_R4, "incorrect type\n"); + double_eq(213124.0, V_R4(&v)); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/r8"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_R8, "incorrect type\n"); + double_eq(0.412, V_R8(&v)); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/float"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_R8, "incorrect type\n"); + double_eq(41221.421, V_R8(&v)); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/uuid"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == VT_BSTR, "incorrect type\n"); + ok(!lstrcmpW(V_BSTR(&v), _bstr_("333C7BC4-460F-11D0-BC04-0080C7055a83")), "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/binhex"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + BYTE bytes[] = {0xff,0xfc,0xa0,0x12,0x00,0x3c}; + + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == (VT_ARRAY|VT_UI1), "incorrect type\n"); + ok(V_ARRAY(&v)->rgsabound[0].cElements == 6, "incorrect array size\n"); + if(V_ARRAY(&v)->rgsabound[0].cElements == 6) + ok(!memcmp(bytes, V_ARRAY(&v)->pvData, sizeof(bytes)), "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + + hr = IXMLDOMDocument2_selectSingleNode(doc, _bstr_("root/binbase64"), &pNode); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + BYTE bytes[] = {0x62,0x61,0x73,0x65,0x36,0x34,0x20,0x74,0x65,0x73,0x74}; + + hr = IXMLDOMNode_get_nodeTypedValue(pNode, &v); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(V_VT(&v) == (VT_ARRAY|VT_UI1), "incorrect type\n"); + ok(V_ARRAY(&v)->rgsabound[0].cElements == 11, "incorrect array size\n"); + if(V_ARRAY(&v)->rgsabound[0].cElements == 11) + ok(!memcmp(bytes, V_ARRAY(&v)->pvData, sizeof(bytes)), "incorrect value\n"); + VariantClear(&v); + + IXMLDOMNode_Release(pNode); + } + } + + IXMLDOMDocument2_Release(doc); + + free_bstrs(); +} + +static void test_TransformWithLoadingLocalFile(void) +{ + IXMLDOMDocument2 *doc = NULL; + IXMLDOMDocument2 *xsl = NULL; + IXMLDOMNode *pNode; + VARIANT_BOOL bSucc; + HRESULT hr; + HANDLE file; + DWORD dwWritten; + char lpPathBuffer[MAX_PATH]; + int i; + + /* Create a Temp File. */ + GetTempPathA(MAX_PATH, lpPathBuffer); + strcat(lpPathBuffer, "customers.xml" ); + + file = CreateFile(lpPathBuffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError()); + if(file == INVALID_HANDLE_VALUE) + return; + + WriteFile(file, szBasicTransformXML, strlen(szBasicTransformXML), &dwWritten, NULL); + CloseHandle(file); + + /* Correct path to not include a escape character. */ + for(i=0; i < strlen(lpPathBuffer); i++) + { + if(lpPathBuffer[i] == '\\') + lpPathBuffer[i] = '/'; + } + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( hr != S_OK ) + return; + + hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&xsl ); + if( hr != S_OK ) + { + IXMLDOMDocument2_Release(doc); + return; + } + + hr = IXMLDOMDocument2_loadXML(doc, _bstr_(szTypeValueXML), &bSucc); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n"); + if(bSucc == VARIANT_TRUE) + { + BSTR sXSL; + BSTR sPart1 = _bstr_(szBasicTransformSSXMLPart1); + BSTR sPart2 = _bstr_(szBasicTransformSSXMLPart2); + BSTR sFileName = _bstr_(lpPathBuffer); + int nLegnth = lstrlenW(sPart1) + lstrlenW(sPart2) + lstrlenW(sFileName) + 1; + + sXSL = SysAllocStringLen(NULL, nLegnth); + lstrcpyW(sXSL, sPart1); + lstrcatW(sXSL, sFileName); + lstrcatW(sXSL, sPart2); + + hr = IXMLDOMDocument2_loadXML(xsl, sXSL, &bSucc); + ok(hr == S_OK, "ret %08x\n", hr ); + ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n"); + if(bSucc == VARIANT_TRUE) + { + BSTR sResult; + + hr = IXMLDOMDocument_QueryInterface(xsl, &IID_IXMLDOMNode, (LPVOID*)&pNode ); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + /* This will load the temp file via the XSL */ + hr = IXMLDOMDocument2_transformNode(doc, pNode, &sResult); + ok(hr == S_OK, "ret %08x\n", hr ); + if(hr == S_OK) + { + ok( compareIgnoreReturns( sResult, _bstr_(szBasicTransformOutput)), "Stylesheet output not correct\n"); + SysFreeString(sResult); + } + + IXMLDOMNode_Release(pNode); + } + } + + SysFreeString(sXSL); + } + + IXMLDOMDocument2_Release(doc); + IXMLDOMDocument2_Release(xsl); + + DeleteFile(lpPathBuffer); + free_bstrs(); +} + +START_TEST(domdoc) +{ + HRESULT r; + + r = CoInitialize( NULL ); + ok( r == S_OK, "failed to init com\n"); + + test_domdoc(); + test_domnode(); + test_refs(); + test_create(); + test_getElementsByTagName(); + test_get_text(); + test_get_childNodes(); + test_removeChild(); + test_replaceChild(); + test_removeNamedItem(); + test_XMLHTTP(); + test_IXMLDOMDocument2(); + test_XPath(); + test_cloneNode(); + test_xmlTypes(); + test_nodeTypeTests(); + test_DocumentSaveToDocument(); + test_DocumentSaveToFile(); + test_testTransforms(); + test_Namespaces(); + test_FormattingXML(); + test_NodeTypeValue(); + test_TransformWithLoadingLocalFile(); + + CoUninitialize(); +} diff --git a/rostests/winetests/msxml3/msxml3.rbuild b/rostests/winetests/msxml3/msxml3.rbuild new file mode 100644 index 00000000000..d57321d38af --- /dev/null +++ b/rostests/winetests/msxml3/msxml3.rbuild @@ -0,0 +1,19 @@ + + + + + . + + domdoc.c + saxreader.c + schema.c + testlist.c + xmldoc.c + xmlelem.c + wine + user32 + ole32 + oleaut32 + ntdll + + diff --git a/rostests/winetests/msxml3/saxreader.c b/rostests/winetests/msxml3/saxreader.c new file mode 100644 index 00000000000..dd0e42c282b --- /dev/null +++ b/rostests/winetests/msxml3/saxreader.c @@ -0,0 +1,606 @@ +/* + * XML test + * + * Copyright 2008 Piotr Caban + * + * 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 + */ + +#define COBJMACROS +#define CONST_VTABLE + +#include +#include "windows.h" +#include "ole2.h" +#include "msxml2.h" +#include "ocidl.h" + +#include "wine/test.h" + +typedef enum _CH { + CH_ENDTEST, + CH_PUTDOCUMENTLOCATOR, + CH_STARTDOCUMENT, + CH_ENDDOCUMENT, + CH_STARTPREFIXMAPPING, + CH_ENDPREFIXMAPPING, + CH_STARTELEMENT, + CH_ENDELEMENT, + CH_CHARACTERS, + CH_IGNORABLEWHITESPACE, + CH_PROCESSINGINSTRUCTION, + CH_SKIPPEDENTITY +} CH; + +static const WCHAR szSimpleXML[] = { +'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n', +'<','B','a','n','k','A','c','c','o','u','n','t','>','\n', +' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n', +' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n', +'<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0' +}; + +static const WCHAR szCarriageRetTest[] = { +'<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n', +'<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n', +'\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n', +'\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n', +'<','/','B','a','n','k','A','c','c','o','u','n','t','>','\0' +}; + +static const CHAR szTestXML[] = +"\n" +"\n" +" 1234\n" +" Captain Ahab\n" +"\n"; + +typedef struct _contenthandlercheck { + CH id; + int line; + int column; + const char *arg1; + const char *arg2; + const char *arg3; +} content_handler_test; + +static content_handler_test contentHandlerTest1[] = { + { CH_PUTDOCUMENTLOCATOR, 0, 0 }, + { CH_STARTDOCUMENT, 0, 0 }, + { CH_STARTELEMENT, 2, 14, "", "BankAccount", "BankAccount" }, + { CH_CHARACTERS, 2, 14, "\n " }, + { CH_STARTELEMENT, 3, 12, "", "Number", "Number" }, + { CH_CHARACTERS, 3, 12, "1234" }, + { CH_ENDELEMENT, 3, 18, "", "Number", "Number" }, + { CH_CHARACTERS, 3, 25, "\n " }, + { CH_STARTELEMENT, 4, 10, "", "Name", "Name" }, + { CH_CHARACTERS, 4, 10, "Captain Ahab" }, + { CH_ENDELEMENT, 4, 24, "", "Name", "Name" }, + { CH_CHARACTERS, 4, 29, "\n" }, + { CH_ENDELEMENT, 5, 3, "", "BankAccount", "BankAccount" }, + { CH_ENDDOCUMENT, 0, 0 }, + { CH_ENDTEST } +}; + +static content_handler_test contentHandlerTest2[] = { + { CH_PUTDOCUMENTLOCATOR, 0, 0 }, + { CH_STARTDOCUMENT, 0, 0 }, + { CH_STARTELEMENT, 2, 14, "", "BankAccount", "BankAccount" }, + { CH_CHARACTERS, 2, 14, "\n" }, + { CH_CHARACTERS, 2, 16, "\t" }, + { CH_STARTELEMENT, 3, 10, "", "Number", "Number" }, + { CH_CHARACTERS, 3, 10, "1234" }, + { CH_ENDELEMENT, 3, 16, "", "Number", "Number" }, + { CH_CHARACTERS, 3, 23, "\n" }, + { CH_CHARACTERS, 3, 25, "\t" }, + { CH_STARTELEMENT, 4, 8, "", "Name", "Name" }, + { CH_CHARACTERS, 4, 8, "Captain Ahab" }, + { CH_ENDELEMENT, 4, 22, "", "Name", "Name" }, + { CH_CHARACTERS, 4, 27, "\n" }, + { CH_ENDELEMENT, 5, 3, "", "BankAccount", "BankAccount" }, + { CH_ENDDOCUMENT, 0, 0 }, + { CH_ENDTEST } +}; + +static content_handler_test *expectCall; +static ISAXLocator *locator; + +static void test_saxstr(unsigned line, const WCHAR *szStr, int nStr, const char *szTest) +{ + WCHAR buf[1024]; + int len; + + if(!szTest) { + ok_(__FILE__,line) (szStr == NULL, "szStr != NULL\n"); + ok_(__FILE__,line) (nStr == 0, "nStr = %d, expected 0\n", nStr); + return; + } + + len = strlen(szTest); + ok_(__FILE__,line) (len == nStr, "nStr = %d, expected %d (%s)\n", nStr, len, szTest); + if(len != nStr) + return; + + MultiByteToWideChar(CP_ACP, 0, szTest, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok_(__FILE__,line) (!memcmp(szStr, buf, len*sizeof(WCHAR)), "unexpected szStr %s, expected %s\n", + wine_dbgstr_wn(szStr, nStr), szTest); +} + +static BOOL test_expect_call(CH id) +{ + ok(expectCall->id == id, "unexpected call %d, expected %d\n", id, expectCall->id); + return expectCall->id == id; +} + +static void test_locator(unsigned line, int loc_line, int loc_column) +{ + int rcolumn, rline; + ISAXLocator_getLineNumber(locator, &rline); + ISAXLocator_getColumnNumber(locator, &rcolumn); + + ok_(__FILE__,line) (rline == loc_line, + "unexpected line %d, expected %d\n", rline, loc_line); + ok_(__FILE__,line) (rcolumn == loc_column, + "unexpected column %d, expected %d\n", rcolumn, loc_column); +} + +static HRESULT WINAPI contentHandler_QueryInterface( + ISAXContentHandler* iface, + REFIID riid, + void **ppvObject) +{ + *ppvObject = NULL; + + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler)) + { + *ppvObject = iface; + } + else + { + return E_NOINTERFACE; + } + + return S_OK; +} + +static ULONG WINAPI contentHandler_AddRef( + ISAXContentHandler* iface) +{ + return 2; +} + +static ULONG WINAPI contentHandler_Release( + ISAXContentHandler* iface) +{ + return 1; +} + +static HRESULT WINAPI contentHandler_putDocumentLocator( + ISAXContentHandler* iface, + ISAXLocator *pLocator) +{ + if(!test_expect_call(CH_PUTDOCUMENTLOCATOR)) + return E_FAIL; + + locator = pLocator; + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_startDocument( + ISAXContentHandler* iface) +{ + if(!test_expect_call(CH_STARTDOCUMENT)) + return E_FAIL; + + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_endDocument( + ISAXContentHandler* iface) +{ + if(!test_expect_call(CH_ENDDOCUMENT)) + return E_FAIL; + + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_startPrefixMapping( + ISAXContentHandler* iface, + const WCHAR *pPrefix, + int nPrefix, + const WCHAR *pUri, + int nUri) +{ + if(!test_expect_call(CH_ENDDOCUMENT)) + return E_FAIL; + + test_saxstr(__LINE__, pPrefix, nPrefix, expectCall->arg1); + test_saxstr(__LINE__, pUri, nUri, expectCall->arg2); + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_endPrefixMapping( + ISAXContentHandler* iface, + const WCHAR *pPrefix, + int nPrefix) +{ + if(!test_expect_call(CH_ENDPREFIXMAPPING)) + return E_FAIL; + + test_saxstr(__LINE__, pPrefix, nPrefix, expectCall->arg1); + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_startElement( + ISAXContentHandler* iface, + const WCHAR *pNamespaceUri, + int nNamespaceUri, + const WCHAR *pLocalName, + int nLocalName, + const WCHAR *pQName, + int nQName, + ISAXAttributes *pAttr) +{ + if(!test_expect_call(CH_STARTELEMENT)) + return E_FAIL; + + test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, expectCall->arg1); + test_saxstr(__LINE__, pLocalName, nLocalName, expectCall->arg2); + test_saxstr(__LINE__, pQName, nQName, expectCall->arg3); + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_endElement( + ISAXContentHandler* iface, + const WCHAR *pNamespaceUri, + int nNamespaceUri, + const WCHAR *pLocalName, + int nLocalName, + const WCHAR *pQName, + int nQName) +{ + if(!test_expect_call(CH_ENDELEMENT)) + return E_FAIL; + + test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, expectCall->arg1); + test_saxstr(__LINE__, pLocalName, nLocalName, expectCall->arg2); + test_saxstr(__LINE__, pQName, nQName, expectCall->arg3); + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_characters( + ISAXContentHandler* iface, + const WCHAR *pChars, + int nChars) +{ + if(!test_expect_call(CH_CHARACTERS)) + return E_FAIL; + + test_saxstr(__LINE__, pChars, nChars, expectCall->arg1); + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_ignorableWhitespace( + ISAXContentHandler* iface, + const WCHAR *pChars, + int nChars) +{ + if(!test_expect_call(CH_IGNORABLEWHITESPACE)) + return E_FAIL; + + test_saxstr(__LINE__, pChars, nChars, expectCall->arg1); + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_processingInstruction( + ISAXContentHandler* iface, + const WCHAR *pTarget, + int nTarget, + const WCHAR *pData, + int nData) +{ + if(!test_expect_call(CH_PROCESSINGINSTRUCTION)) + return E_FAIL; + + test_saxstr(__LINE__, pTarget, nTarget, expectCall->arg1); + test_saxstr(__LINE__, pData, nData, expectCall->arg2); + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + +static HRESULT WINAPI contentHandler_skippedEntity( + ISAXContentHandler* iface, + const WCHAR *pName, + int nName) +{ + if(!test_expect_call(CH_SKIPPEDENTITY)) + return E_FAIL; + + test_saxstr(__LINE__, pName, nName, expectCall->arg1); + test_locator(__LINE__, expectCall->line, expectCall->column); + + expectCall++; + return S_OK; +} + + +static const ISAXContentHandlerVtbl contentHandlerVtbl = +{ + contentHandler_QueryInterface, + contentHandler_AddRef, + contentHandler_Release, + contentHandler_putDocumentLocator, + contentHandler_startDocument, + contentHandler_endDocument, + contentHandler_startPrefixMapping, + contentHandler_endPrefixMapping, + contentHandler_startElement, + contentHandler_endElement, + contentHandler_characters, + contentHandler_ignorableWhitespace, + contentHandler_processingInstruction, + contentHandler_skippedEntity +}; + +static ISAXContentHandler contentHandler = { &contentHandlerVtbl }; + +static HRESULT WINAPI isaxerrorHandler_QueryInterface( + ISAXErrorHandler* iface, + REFIID riid, + void **ppvObject) +{ + *ppvObject = NULL; + + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler)) + { + *ppvObject = iface; + } + else + { + return E_NOINTERFACE; + } + + return S_OK; +} + +static ULONG WINAPI isaxerrorHandler_AddRef( + ISAXErrorHandler* iface) +{ + return 2; +} + +static ULONG WINAPI isaxerrorHandler_Release( + ISAXErrorHandler* iface) +{ + return 1; +} + +static HRESULT WINAPI isaxerrorHandler_error( + ISAXErrorHandler* iface, + ISAXLocator *pLocator, + const WCHAR *pErrorMessage, + HRESULT hrErrorCode) +{ + return S_OK; +} + +static HRESULT WINAPI isaxerrorHandler_fatalError( + ISAXErrorHandler* iface, + ISAXLocator *pLocator, + const WCHAR *pErrorMessage, + HRESULT hrErrorCode) +{ + return S_OK; +} + +static HRESULT WINAPI isaxerrorHanddler_ignorableWarning( + ISAXErrorHandler* iface, + ISAXLocator *pLocator, + const WCHAR *pErrorMessage, + HRESULT hrErrorCode) +{ + return S_OK; +} + +static const ISAXErrorHandlerVtbl errorHandlerVtbl = +{ + isaxerrorHandler_QueryInterface, + isaxerrorHandler_AddRef, + isaxerrorHandler_Release, + isaxerrorHandler_error, + isaxerrorHandler_fatalError, + isaxerrorHanddler_ignorableWarning +}; + +static ISAXErrorHandler errorHandler = { &errorHandlerVtbl }; + +static void test_saxreader(void) +{ + HRESULT hr; + ISAXXMLReader *reader = NULL; + VARIANT var; + ISAXContentHandler *lpContentHandler; + ISAXErrorHandler *lpErrorHandler; + SAFEARRAY *pSA; + SAFEARRAYBOUND SADim[1]; + char *pSAData = NULL; + IStream *iStream; + ULARGE_INTEGER liSize; + LARGE_INTEGER liPos; + ULONG bytesWritten; + HANDLE file; + static const CHAR testXmlA[] = "test.xml"; + static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0}; + IXMLDOMDocument *domDocument; + BSTR bstrData; + VARIANT_BOOL vBool; + + hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER, + &IID_ISAXXMLReader, (LPVOID*)&reader); + + if(FAILED(hr)) + { + skip("Failed to create SAXXMLReader instance\n"); + return; + } + + hr = ISAXXMLReader_getContentHandler(reader, NULL); + ok(hr == E_POINTER, "Expected E_POINTER, got %08x\n", hr); + + hr = ISAXXMLReader_getErrorHandler(reader, NULL); + ok(hr == E_POINTER, "Expected E_POINTER, got %08x\n", hr); + + hr = ISAXXMLReader_getContentHandler(reader, &lpContentHandler); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(lpContentHandler == NULL, "Expected %p, got %p\n", NULL, lpContentHandler); + + hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler); + + hr = ISAXXMLReader_putContentHandler(reader, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + hr = ISAXXMLReader_putContentHandler(reader, &contentHandler); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + hr = ISAXXMLReader_getContentHandler(reader, &lpContentHandler); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(lpContentHandler == &contentHandler, "Expected %p, got %p\n", &contentHandler, lpContentHandler); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(szSimpleXML); + + expectCall = contentHandlerTest1; + hr = ISAXXMLReader_parse(reader, var); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + test_expect_call(CH_ENDTEST); + + SADim[0].lLbound= 0; + SADim[0].cElements= sizeof(szTestXML)-1; + pSA = SafeArrayCreate(VT_UI1, 1, SADim); + SafeArrayAccessData(pSA, (void**)&pSAData); + memcpy(pSAData, szTestXML, sizeof(szTestXML)-1); + SafeArrayUnaccessData(pSA); + V_VT(&var) = VT_ARRAY|VT_UI1; + V_ARRAY(&var) = pSA; + + expectCall = contentHandlerTest1; + hr = ISAXXMLReader_parse(reader, var); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + test_expect_call(CH_ENDTEST); + + SafeArrayDestroy(pSA); + + CreateStreamOnHGlobal(NULL, TRUE, &iStream); + liSize.QuadPart = strlen(szTestXML); + IStream_SetSize(iStream, liSize); + IStream_Write(iStream, szTestXML, strlen(szTestXML), &bytesWritten); + liPos.QuadPart = 0; + IStream_Seek(iStream, liPos, STREAM_SEEK_SET, NULL); + V_VT(&var) = VT_UNKNOWN|VT_DISPATCH; + V_UNKNOWN(&var) = (IUnknown*)iStream; + + expectCall = contentHandlerTest1; + hr = ISAXXMLReader_parse(reader, var); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + test_expect_call(CH_ENDTEST); + + IStream_Release(iStream); + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = SysAllocString(szCarriageRetTest); + + expectCall = contentHandlerTest2; + hr = ISAXXMLReader_parse(reader, var); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + test_expect_call(CH_ENDTEST); + + file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError()); + WriteFile(file, szTestXML, sizeof(szTestXML)-1, &bytesWritten, NULL); + CloseHandle(file); + + expectCall = contentHandlerTest1; + hr = ISAXXMLReader_parseURL(reader, testXmlW); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + test_expect_call(CH_ENDTEST); + + DeleteFileA(testXmlA); + + hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLDOMDocument, (LPVOID*)&domDocument); + if(FAILED(hr)) + { + skip("Failed to create DOMDocument instance\n"); + return; + } + bstrData = SysAllocString(szSimpleXML); + hr = IXMLDOMDocument_loadXML(domDocument, bstrData, &vBool); + V_VT(&var) = VT_UNKNOWN; + V_UNKNOWN(&var) = (IUnknown*)domDocument; + + expectCall = contentHandlerTest2; + hr = ISAXXMLReader_parse(reader, var); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + test_expect_call(CH_ENDTEST); + IXMLDOMDocument_Release(domDocument); + + ISAXXMLReader_Release(reader); +} + +START_TEST(saxreader) +{ + HRESULT hr; + + hr = CoInitialize(NULL); + ok(hr == S_OK, "failed to init com\n"); + + test_saxreader(); + + CoUninitialize(); +} diff --git a/rostests/winetests/msxml3/schema.c b/rostests/winetests/msxml3/schema.c new file mode 100644 index 00000000000..d4fb6f7aa7c --- /dev/null +++ b/rostests/winetests/msxml3/schema.c @@ -0,0 +1,212 @@ +/* + * Schema test + * + * Copyright 2007 Huw Davies + * + * 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 + */ + +#include +#define COBJMACROS + +#include "initguid.h" +#include "windows.h" +#include "ole2.h" +#include "xmldom.h" +#include "msxml2.h" +#include "dispex.h" + +#include "wine/test.h" + +static const WCHAR schema_uri[] = {'x','-','s','c','h','e','m','a',':','t','e','s','t','.','x','m','l',0}; + +static const WCHAR schema_xml[] = { + '<','S','c','h','e','m','a',' ','x','m','l','n','s','=','\"','u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','x','m','l','-','d','a','t','a','\"','\n', + 'x','m','l','n','s',':','d','t','=','\"','u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','d','a','t','a','t','y','p','e','s','\"','>','\n', + '<','/','S','c','h','e','m','a','>','\n',0 +}; + +static void test_schema_refs(void) +{ + IXMLDOMDocument2 *doc; + IXMLDOMSchemaCollection *schema; + HRESULT r; + LONG ref; + VARIANT v; + VARIANT_BOOL b; + BSTR str; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument2, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + r = CoCreateInstance( &CLSID_XMLSchemaCache, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMSchemaCollection, (LPVOID*)&schema ); + if( r != S_OK ) + { + IXMLDOMDocument2_Release(doc); + return; + } + + str = SysAllocString(schema_xml); + r = IXMLDOMDocument2_loadXML(doc, str, &b); + ok(r == S_OK, "ret %08x\n", r); + ok(b == VARIANT_TRUE, "b %04x\n", b); + SysFreeString(str); + + ref = IXMLDOMDocument2_AddRef(doc); + ok(ref == 2, "ref %d\n", ref); + VariantInit(&v); + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)doc; + + str = SysAllocString(schema_uri); + r = IXMLDOMSchemaCollection_add(schema, str, v); + ok(r == S_OK, "ret %08x\n", r); + + /* IXMLDOMSchemaCollection_add doesn't add a ref on doc */ + ref = IXMLDOMDocument2_AddRef(doc); + ok(ref == 3, "ref %d\n", ref); + IXMLDOMDocument2_Release(doc); + + SysFreeString(str); + VariantClear(&v); + + V_VT(&v) = VT_INT; + r = IXMLDOMDocument2_get_schemas(doc, &v); + ok(r == S_FALSE, "ret %08x\n", r); + ok(V_VT(&v) == VT_NULL, "vt %x\n", V_VT(&v)); + + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 2, "ref %d\n", ref); + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)schema; + + /* check that putref_schemas takes a ref */ + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 4, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + VariantClear(&v); + + /* refs now 2 */ + V_VT(&v) = VT_INT; + /* check that get_schemas adds a ref */ + r = IXMLDOMDocument2_get_schemas(doc, &v); + ok(r == S_OK, "ret %08x\n", r); + ok(V_VT(&v) == VT_DISPATCH, "vt %x\n", V_VT(&v)); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 4, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 3 */ + /* get_schemas doesn't release a ref if passed VT_DISPATCH - ie it doesn't call VariantClear() */ + r = IXMLDOMDocument2_get_schemas(doc, &v); + ok(r == S_OK, "ret %08x\n", r); + ok(V_VT(&v) == VT_DISPATCH, "vt %x\n", V_VT(&v)); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 5, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 4 */ + /* release the two refs returned by get_schemas */ + IXMLDOMSchemaCollection_Release(schema); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 2 */ + + /* check that taking another ref on the document doesn't change the schema's ref count */ + IXMLDOMDocument2_AddRef(doc); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 3, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + IXMLDOMDocument2_Release(doc); + + + /* refs now 2 */ + /* call putref_schema with some odd variants */ + V_VT(&v) = VT_INT; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == E_FAIL, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 3, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 2 */ + /* calling with VT_EMPTY releases the schema */ + V_VT(&v) = VT_EMPTY; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 2, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 1 */ + /* try setting with VT_UNKNOWN */ + IXMLDOMSchemaCollection_AddRef(schema); + V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = (IUnknown*)schema; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 4, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + VariantClear(&v); + + /* refs now 2 */ + /* calling with VT_NULL releases the schema */ + V_VT(&v) = VT_NULL; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 2, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 1 */ + /* set again */ + IXMLDOMSchemaCollection_AddRef(schema); + V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = (IUnknown*)schema; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 4, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + VariantClear(&v); + + /* refs now 2 */ + + /* release the final ref on the doc which should release its ref on the schema */ + IXMLDOMDocument2_Release(doc); + + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 2, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + IXMLDOMSchemaCollection_Release(schema); +} + +START_TEST(schema) +{ + HRESULT r; + + r = CoInitialize( NULL ); + ok( r == S_OK, "failed to init com\n"); + + test_schema_refs(); + + CoUninitialize(); +} diff --git a/rostests/winetests/msxml3/testlist.c b/rostests/winetests/msxml3/testlist.c new file mode 100644 index 00000000000..6059b4bfe4a --- /dev/null +++ b/rostests/winetests/msxml3/testlist.c @@ -0,0 +1,23 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_domdoc(void); +extern void func_saxreader(void); +extern void func_schema(void); +extern void func_xmldoc(void); +extern void func_xmlelem(void); + +const struct test winetest_testlist[] = +{ + { "domdoc", func_domdoc }, + { "saxreader", func_saxreader }, + { "schema", func_schema }, + { "xmldoc", func_xmldoc }, + { "xmlelem", func_xmlelem }, + { 0, 0 } +}; diff --git a/rostests/winetests/msxml3/xmldoc.c b/rostests/winetests/msxml3/xmldoc.c new file mode 100644 index 00000000000..d2d99fc23f1 --- /dev/null +++ b/rostests/winetests/msxml3/xmldoc.c @@ -0,0 +1,348 @@ +/* + * IXMLDocument tests + * + * Copyright 2007 James Hawkins + * + * 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 + */ + +#define COBJMACROS + +#include +#include "windows.h" +#include "ole2.h" +#include "msxml2.h" +#include "ocidl.h" + +#include "wine/test.h" + +/* Deprecated Error Code */ +#define XML_E_INVALIDATROOTLEVEL 0xc00ce556 + +static void create_xml_file(LPCSTR filename) +{ + DWORD dwNumberOfBytesWritten; + HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + static const char data[] = + "\n" + "\n" + " 1234\n" + " Captain Ahab\n" + ""; + + WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL); + CloseHandle(hf); +} + +static void test_xmldoc(void) +{ + HRESULT hr; + IXMLDocument *doc = NULL; + IXMLElement *element = NULL, *child = NULL, *value = NULL; + IXMLElementCollection *collection = NULL, *inner = NULL; + IPersistStreamInit *psi = NULL; + IStream *stream = NULL; + HGLOBAL hglobal; + HANDLE hfile; + LPVOID ptr; + DWORD file_size, read; + CHAR path[MAX_PATH]; + LONG type, num_child; + VARIANT vIndex, vName; + BSTR name = NULL; + + static const WCHAR szBankAccount[] = {'B','A','N','K','A','C','C','O','U','N','T',0}; + static const WCHAR szNumber[] = {'N','U','M','B','E','R',0}; + static const WCHAR szNumVal[] = {'1','2','3','4',0}; + static const WCHAR szName[] = {'N','A','M','E',0}; + static const WCHAR szNameVal[] = {'C','a','p','t','a','i','n',' ','A','h','a','b',0}; + + hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLDocument, (LPVOID*)&doc); + if (FAILED(hr)) + { + skip("Failed to create XMLDocument instance\n"); + return; + } + + create_xml_file("bank.xml"); + GetFullPathNameA("bank.xml", MAX_PATH, path, NULL); + + hfile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hfile != INVALID_HANDLE_VALUE, "Expected a valid file handle\n"); + file_size = GetFileSize(hfile, NULL); + + hglobal = GlobalAlloc(GHND, file_size); + ptr = GlobalLock(hglobal); + + ReadFile(hfile, ptr, file_size, &read, NULL); + ok(file_size == read, "Expected to read the whole file, read %d\n", read); + + hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(stream != NULL, "Expected non-NULL stream\n"); + + CloseHandle(hfile); + GlobalUnlock(hglobal); + + hr = IXMLDocument_QueryInterface(doc, &IID_IPersistStreamInit, (LPVOID *)&psi); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(psi != NULL, "Expected non-NULL psi\n"); + + hr = IXMLDocument_get_root(doc, &element); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + ok(element == NULL, "Expected NULL element\n"); + + hr = IPersistStreamInit_Load(psi, stream); + ok(hr == S_OK || hr == XML_E_INVALIDATROOTLEVEL, "Expected S_OK, got %08x\n", hr); + if(hr == XML_E_INVALIDATROOTLEVEL) + goto cleanup; + + ok(stream != NULL, "Expected non-NULL stream\n"); + + hr = IXMLDocument_get_root(doc, &element); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(element != NULL, "Expected non-NULL element\n"); + + hr = IXMLElement_get_type(element, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + hr = IXMLElement_get_tagName(element, &name); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(name, szBankAccount), "Expected BANKACCOUNT\n"); + SysFreeString(name); + + hr = IXMLElement_get_children(element, &collection); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(collection != NULL, "Expected non-NULL collection\n"); + + hr = IXMLElementCollection_get_length(collection, &num_child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(num_child == 2, "Expected 2, got %d\n", num_child); + + V_VT(&vIndex) = VT_I4; + V_I4(&vIndex) = 0; + V_VT(&vName) = VT_ERROR; + V_ERROR(&vName) = DISP_E_PARAMNOTFOUND; + hr = IXMLElementCollection_item(collection, vIndex, vName, (IDispatch **)&child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(child != NULL, "Expected non-NULL child\n"); + + hr = IXMLElement_get_type(child, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + hr = IXMLElement_get_tagName(child, &name); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(name, szNumber), "Expected NUMBER\n"); + SysFreeString(name); + + hr = IXMLElement_get_children(child, &inner); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(inner != NULL, "Expected non-NULL inner\n"); + + hr = IXMLElementCollection_get_length(inner, &num_child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(num_child == 1, "Expected 1, got %d\n", num_child); + + hr = IXMLElementCollection_item(inner, vIndex, vName, (IDispatch **)&value); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(value != NULL, "Expected non-NULL value\n"); + + hr = IXMLElement_get_type(value, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_TEXT, "Expected XMLELEMTYPE_TEXT, got %d\n", type); + + hr = IXMLElement_get_text(value, &name); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(name, szNumVal), "Expected '1234'\n"); + SysFreeString(name); + + IXMLElementCollection_Release(inner); + + inner = (IXMLElementCollection *)0xdeadbeef; + hr = IXMLElement_get_children(value, &inner); + ok(hr == 1, "Expected 1, got %08x\n", hr); + ok(inner == NULL, "Expected NULL inner, got %p\n", inner); + + IXMLElement_Release(value); + IXMLElement_Release(child); + value = NULL; + child = NULL; + + V_I4(&vIndex) = 1; + hr = IXMLElementCollection_item(collection, vIndex, vName, (IDispatch **)&child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(child != NULL, "Expected non-NULL child\n"); + + hr = IXMLElement_get_type(child, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + hr = IXMLElement_get_tagName(child, &name); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(name, szName), "Expected NAME\n"); + SysFreeString(name); + + hr = IXMLElement_get_children(child, &inner); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(inner != NULL, "Expected non-NULL inner\n"); + + hr = IXMLElementCollection_get_length(inner, &num_child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(num_child == 1, "Expected 1, got %d\n", num_child); + + V_I4(&vIndex) = 0; + hr = IXMLElementCollection_item(inner, vIndex, vName, (IDispatch **)&value); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(value != NULL, "Expected non-NULL value\n"); + + hr = IXMLElement_get_type(value, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_TEXT, "Expected XMLELEMTYPE_TEXT, got %d\n", type); + + hr = IXMLElement_get_text(value, &name); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(name, szNameVal), "Expected 'Captain Ahab'\n"); + SysFreeString(name); + + IXMLElementCollection_Release(inner); + + inner = (IXMLElementCollection *)0xdeadbeef; + hr = IXMLElement_get_children(value, &inner); + ok(hr == 1, "Expected 1, got %08x\n", hr); + ok(inner == NULL, "Expected NULL inner, got %p\n", inner); + + IXMLElement_Release(value); + IXMLElement_Release(child); + IXMLElementCollection_Release(collection); + IXMLElement_Release(element); +cleanup: + IStream_Release(stream); + IPersistStreamInit_Release(psi); + IXMLDocument_Release(doc); + + DeleteFileA("bank.xml"); +} + +static void test_createElement(void) +{ + HRESULT hr; + IXMLDocument *doc = NULL; + IXMLElement *element = NULL, *root = NULL; + VARIANT vType, vName; + LONG type; + + hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLDocument, (LPVOID*)&doc); + if (FAILED(hr)) + { + skip("Failed to create XMLDocument instance\n"); + return; + } + + /* invalid vType type */ + V_VT(&vType) = VT_NULL; + V_VT(&vName) = VT_NULL; + element = (IXMLElement *)0xdeadbeef; + hr = IXMLDocument_createElement(doc, vType, vName, &element); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(element == NULL, "Expected NULL element\n"); + + /* invalid vType value */ + V_VT(&vType) = VT_I4; + V_I4(&vType) = -1; + V_VT(&vName) = VT_NULL; + hr = IXMLDocument_createElement(doc, vType, vName, &element); + /* Up to and including SP7, createElement returns an element. */ + if(hr == S_OK) + { + ok(element != NULL, "Expected element\n"); + if (element != NULL) + { + hr = IXMLElement_get_type(element, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + /* SP7 returns an XMLELEMTYPE_ELEMENT */ + ok(type == XMLELEMTYPE_OTHER || type == XMLELEMTYPE_ELEMENT, + "Expected XMLELEMTYPE_OTHER || XMLELEMTYPE_ELEMENT, got %d\n", type); + + IXMLElement_Release(element); + } + } + else + { + ok(hr == E_NOTIMPL, "Expected E_NOTIMPL, got %08x\n", hr); + ok(element == NULL, "Expected NULL element\n"); + } + + /* invalid vName type */ + V_VT(&vType) = VT_I4; + V_I4(&vType) = XMLELEMTYPE_ELEMENT; + V_VT(&vName) = VT_I4; + hr = IXMLDocument_createElement(doc, vType, vName, &element); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(element != NULL, "Expected non-NULL element\n"); + + hr = IXMLElement_get_type(element, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + IXMLElement_Release(element); + + /* NULL element */ + V_VT(&vType) = VT_I4; + V_I4(&vType) = XMLELEMTYPE_ELEMENT; + V_VT(&vName) = VT_I4; + hr = IXMLDocument_createElement(doc, vType, vName, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + + root = (IXMLElement *)0xdeadbeef; + hr = IXMLDocument_get_root(doc, &root); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + ok(root == NULL, "Expected NULL root\n"); + + V_VT(&vType) = VT_I4; + V_I4(&vType) = XMLELEMTYPE_ELEMENT; + V_VT(&vName) = VT_NULL; + hr = IXMLDocument_createElement(doc, vType, vName, &element); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(element != NULL, "Expected non-NULL element\n"); + + /* createElement does not set the new element as root */ + root = (IXMLElement *)0xdeadbeef; + hr = IXMLDocument_get_root(doc, &root); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + ok(root == NULL, "Expected NULL root\n"); + + IXMLElement_Release(element); + IXMLDocument_Release(doc); +} + +START_TEST(xmldoc) +{ + HRESULT hr; + + hr = CoInitialize(NULL); + ok(hr == S_OK, "failed to init com\n"); + + test_xmldoc(); + test_createElement(); + + CoUninitialize(); +} diff --git a/rostests/winetests/msxml3/xmlelem.c b/rostests/winetests/msxml3/xmlelem.c new file mode 100644 index 00000000000..1738b2ce50b --- /dev/null +++ b/rostests/winetests/msxml3/xmlelem.c @@ -0,0 +1,452 @@ +/* + * IXMLElement tests + * + * Copyright 2007 James Hawkins + * + * 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 + */ + +#define COBJMACROS + +#include + +#include "windows.h" +#include "ole2.h" +#include "xmldom.h" +#include "msxml2.h" +#include "ocidl.h" + +#include "wine/test.h" + +#define ERROR_URL_NOT_FOUND 0x800c0006 + +static void test_xmlelem(void) +{ + HRESULT hr; + IXMLDocument *doc = NULL; + IXMLElement *element = NULL, *parent; + IXMLElement *child, *child2; + IXMLElementCollection *children; + VARIANT vType, vName; + VARIANT vIndex, vValue; + BSTR str, val; + LONG type, num_child; + + static const WCHAR propName[] = {'p','r','o','p',0}; + static const WCHAR propVal[] = {'v','a','l',0}; + static const WCHAR nextVal[] = {'n','e','x','t',0}; + static const WCHAR noexist[] = {'n','o','e','x','i','s','t',0}; + static const WCHAR crazyCase1[] = {'C','R','a','z','Y','c','A','S','E',0}; + static const WCHAR crazyCase2[] = {'C','R','A','Z','Y','C','A','S','E',0}; + + hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLDocument, (LPVOID*)&doc); + if (FAILED(hr)) + { + skip("Failed to create XMLDocument instance\n"); + return; + } + + V_VT(&vType) = VT_I4; + V_I4(&vType) = XMLELEMTYPE_ELEMENT; + V_VT(&vName) = VT_NULL; + hr = IXMLDocument_createElement(doc, vType, vName, &element); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(element != NULL, "Expected non-NULL element\n"); + + hr = IXMLElement_get_tagName(element, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(lstrlenW(str) == 0, "Expected empty tag name\n"); + SysFreeString(str); + + parent = (IXMLElement *)0xdeadbeef; + hr = IXMLElement_get_parent(element, &parent); + ok(hr == 1, "Expected 1, got %08x\n", hr); + ok(parent == NULL, "Expected NULL parent\n"); + + str = SysAllocString(noexist); + hr = IXMLElement_getAttribute(element, str, &vValue); + ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); + ok(V_VT(&vValue) == VT_EMPTY, "Expected VT_EMPTY, got %d\n", V_VT(&vValue)); + ok(V_BSTR(&vValue) == NULL, "Expected null value\n"); + VariantClear(&vValue); + SysFreeString(str); + + str = SysAllocString(crazyCase1); + val = SysAllocString(propVal); + V_VT(&vValue) = VT_BSTR; + V_BSTR(&vValue) = val; + hr = IXMLElement_setAttribute(element, str, vValue); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + SysFreeString(str); + SysFreeString(val); + + str = SysAllocString(crazyCase2); + hr = IXMLElement_getAttribute(element, str, &vValue); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(V_VT(&vValue) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&vValue)); + ok(!lstrcmpW(V_BSTR(&vValue), propVal), "Expected 'val'\n"); + VariantClear(&vValue); + SysFreeString(str); + + str = SysAllocString(propName); + val = SysAllocString(propVal); + V_VT(&vValue) = VT_BSTR; + V_BSTR(&vValue) = val; + hr = IXMLElement_setAttribute(element, str, vValue); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + SysFreeString(val); + + hr = IXMLElement_getAttribute(element, str, &vValue); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(V_VT(&vValue) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&vValue)); + ok(!lstrcmpW(V_BSTR(&vValue), propVal), "Expected 'val'\n"); + VariantClear(&vValue); + + hr = IXMLElement_removeAttribute(element, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + /* remove now nonexistent attribute */ + hr = IXMLElement_removeAttribute(element, str); + ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); + + hr = IXMLElement_getAttribute(element, str, &vValue); + ok(hr == 1, "Expected 1, got %08x\n", hr); + ok(V_VT(&vValue) == VT_EMPTY, "Expected VT_EMPTY, got %d\n", V_VT(&vValue)); + ok(V_BSTR(&vValue) == NULL, "Expected null value\n"); + SysFreeString(str); + VariantClear(&vValue); + + children = (IXMLElementCollection *)0xdeadbeef; + hr = IXMLElement_get_children(element, &children); + ok(hr == 1, "Expected 1, got %08x\n", hr); + ok(children == NULL, "Expected NULL collection\n"); + + hr = IXMLElement_get_type(element, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + hr = IXMLElement_get_text(element, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(lstrlenW(str) == 0, "Expected empty text\n"); + SysFreeString(str); + + /* put_text with an ELEMENT */ + str = SysAllocString(propVal); + hr = IXMLElement_put_text(element, str); + ok(hr == E_NOTIMPL, "Expected E_NOTIMPL, got %08x\n", hr); + SysFreeString(str); + + V_VT(&vType) = VT_I4; + V_I4(&vType) = XMLELEMTYPE_TEXT; + V_VT(&vName) = VT_NULL; + hr = IXMLDocument_createElement(doc, vType, vName, &child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(child != NULL, "Expected non-NULL child\n"); + + hr = IXMLElement_addChild(element, child, 0, -1); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + str = SysAllocString(propVal); + hr = IXMLElement_put_text(child, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + SysFreeString(str); + + parent = (IXMLElement *)0xdeadbeef; + hr = IXMLElement_get_parent(child, &parent); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(parent != element, "Expected parent != element\n"); + + hr = IXMLElement_get_type(parent, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + children = (IXMLElementCollection *)0xdeadbeef; + hr = IXMLElement_get_children(element, &children); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(children != NULL, "Expected non-NULL collection\n"); + + hr = IXMLElementCollection_get_length(children, &num_child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(num_child == 1, "Expected 1, got %d\n", num_child); + + V_VT(&vIndex) = VT_I4; + V_I4(&vIndex) = 0; + V_VT(&vName) = VT_ERROR; + V_ERROR(&vName) = DISP_E_PARAMNOTFOUND; + hr = IXMLElementCollection_item(children, vIndex, vName, (IDispatch **)&child2); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(child2 != NULL, "Expected non-NULL child\n"); + + hr = IXMLElement_get_type(child2, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_TEXT, "Expected XMLELEMTYPE_TEXT, got %d\n", type); + + hr = IXMLElement_get_text(element, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(str, propVal), "Expected 'val'\n"); + SysFreeString(str); + + hr = IXMLElement_get_text(child2, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(str, propVal), "Expected 'val'\n"); + SysFreeString(str); + + /* try put_text on ELEMENT again, now that it has a text child */ + str = SysAllocString(nextVal); + hr = IXMLElement_put_text(element, str); + ok(hr == E_NOTIMPL, "Expected E_NOTIMPL, got %08x\n", hr); + SysFreeString(str); + + str = SysAllocString(nextVal); + hr = IXMLElement_put_text(child2, str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + SysFreeString(str); + + hr = IXMLElement_get_text(element, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(str, nextVal), "Expected 'val'\n"); + SysFreeString(str); + + IXMLElement_Release(child2); + IXMLElementCollection_Release(children); + IXMLElement_Release(parent); + IXMLElement_Release(child); + IXMLElement_Release(element); + IXMLDocument_Release(doc); +} + +static void create_xml_file(LPCSTR filename) +{ + DWORD dwNumberOfBytesWritten; + HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + static const char data[] = + "\n" + "\n" + " 1234\n" + " Captain Ahab\n" + "\n"; + + WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL); + CloseHandle(hf); +} + +static void test_xmlelem_collection(void) +{ + HRESULT hr; + IUnknown *unk = NULL; + IXMLDocument *doc = NULL; + IXMLElement *element = NULL, *child; + IXMLElementCollection *collection = NULL; + IEnumVARIANT *enumVar = NULL; + CHAR pathA[MAX_PATH]; + WCHAR path[MAX_PATH]; + LONG length, type; + ULONG num_vars; + VARIANT var, vIndex, vName; + BSTR url, str; + static const CHAR szBankXML[] = "bank.xml"; + static const WCHAR szNumber[] = {'N','U','M','B','E','R',0}; + static const WCHAR szName[] = {'N','A','M','E',0}; + + hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLDocument, (LPVOID*)&doc); + if (FAILED(hr)) + { + skip("Failed to create XMLDocument instance\n"); + return; + } + + create_xml_file(szBankXML); + GetFullPathNameA(szBankXML, MAX_PATH, pathA, NULL); + MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH); + + url = SysAllocString(path); + hr = IXMLDocument_put_URL(doc, url); + ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr); + SysFreeString(url); + + if(hr != S_OK) + goto cleanup; + + hr = IXMLDocument_get_root(doc, &element); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(element != NULL, "Expected non-NULL element\n"); + + hr = IXMLElement_get_children(element, &collection); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(collection != NULL, "Expected non-NULL collection\n"); + + hr = IXMLElementCollection_get_length(collection, NULL); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + + hr = IXMLElementCollection_get_length(collection, &length); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(length == 2, "Expected 2, got %d\n", length); + + /* IXMLElementCollection:put_length does nothing */ + hr = IXMLElementCollection_put_length(collection, -1); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + + hr = IXMLElementCollection_put_length(collection, 0); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + + hr = IXMLElementCollection_put_length(collection, 1); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + + hr = IXMLElementCollection_put_length(collection, 2); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + + hr = IXMLElementCollection_put_length(collection, 3); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + + hr = IXMLElementCollection_put_length(collection, 50); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + + /* make sure the length hasn't changed */ + hr = IXMLElementCollection_get_length(collection, &length); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(length == 2, "Expected 2, got %d\n", length); + + /* IXMLElementCollection implements IEnumVARIANT */ + hr = IXMLElementCollection_QueryInterface(collection, &IID_IEnumVARIANT, (LPVOID *)&enumVar); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(enumVar != NULL, "Expected non-NULL enumVar\n"); + IEnumVARIANT_Release(enumVar); + + hr = IXMLElementCollection_get__newEnum(collection, &unk); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(unk != NULL, "Expected non-NULL unk\n"); + + hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (LPVOID *)&enumVar); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(enumVar != NULL, "Expected non-NULL enumVar\n"); + IUnknown_Release(unk); + + /* 1234 */ + hr = IEnumVARIANT_Next(enumVar, 1, &var, &num_vars); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(V_VT(&var) == VT_DISPATCH, "Expected VT_DISPATCH, got %d\n", V_VT(&var)); + ok(num_vars == 1, "Expected 1, got %d\n", num_vars); + + hr = IUnknown_QueryInterface(V_DISPATCH(&var), &IID_IXMLElement, (LPVOID *)&child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(child != NULL, "Expected non-NULL child\n"); + + VariantClear(&var); + + hr = IXMLElement_get_type(child, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + hr = IXMLElement_get_tagName(child, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(str, szNumber), "Expected NUMBER\n"); + SysFreeString(str); + IXMLElement_Release(child); + + /* Captain Ahab */ + hr = IEnumVARIANT_Next(enumVar, 1, &var, &num_vars); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(V_VT(&var) == VT_DISPATCH, "Expected VT_DISPATCH, got %d\n", V_VT(&var)); + ok(num_vars == 1, "Expected 1, got %d\n", num_vars); + + hr = IUnknown_QueryInterface(V_DISPATCH(&var), &IID_IXMLElement, (LPVOID *)&child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(child != NULL, "Expected non-NULL child\n"); + + VariantClear(&var); + + hr = IXMLElement_get_type(child, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + hr = IXMLElement_get_tagName(child, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(str, szName), "Expected NAME\n"); + SysFreeString(str); + IXMLElement_Release(child); + + /* 1234 */ + V_VT(&vIndex) = VT_I4; + V_I4(&vIndex) = 0; + V_VT(&vName) = VT_ERROR; + V_ERROR(&vName) = DISP_E_PARAMNOTFOUND; + hr = IXMLElementCollection_item(collection, vIndex, vName, (IDispatch **)&child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(child != NULL, "Expected non-NULL child\n"); + + hr = IXMLElement_get_type(child, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + hr = IXMLElement_get_tagName(child, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(str, szNumber), "Expected NUMBER\n"); + SysFreeString(str); + IXMLElement_Release(child); + + /* Captain Ahab */ + V_VT(&vIndex) = VT_I4; + V_I4(&vIndex) = 1; + V_VT(&vName) = VT_ERROR; + V_ERROR(&vName) = DISP_E_PARAMNOTFOUND; + hr = IXMLElementCollection_item(collection, vIndex, vName, (IDispatch **)&child); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(child != NULL, "Expected non-NULL child\n"); + + hr = IXMLElement_get_type(child, &type); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); + + hr = IXMLElement_get_tagName(child, &str); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpW(str, szName), "Expected NAME\n"); + SysFreeString(str); + IXMLElement_Release(child); + + V_I4(&vIndex) = 100; + hr = IXMLElementCollection_item(collection, vIndex, vName, (IDispatch **)&child); + ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); + ok(child == NULL, "Expected NULL child\n"); + + V_I4(&vIndex) = -1; + child = (IXMLElement *)0xdeadbeef; + hr = IXMLElementCollection_item(collection, vIndex, vName, (IDispatch **)&child); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); + ok(child == NULL, "Expected NULL child\n"); + + IEnumVARIANT_Release(enumVar); + IXMLElement_Release(element); + IXMLElementCollection_Release(collection); +cleanup: + IXMLDocument_Release(doc); + DeleteFileA("bank.xml"); +} + +START_TEST(xmlelem) +{ + HRESULT hr; + + hr = CoInitialize(NULL); + ok(hr == S_OK, "failed to init com\n"); + + test_xmlelem(); + test_xmlelem_collection(); + + CoUninitialize(); +} diff --git a/rostests/winetests/netapi32/access.c b/rostests/winetests/netapi32/access.c index f46cb7faf00..2f296844e6f 100644 --- a/rostests/winetests/netapi32/access.c +++ b/rostests/winetests/netapi32/access.c @@ -70,17 +70,17 @@ static int init_access_tests(void) BOOL rc; user_name[0] = 0; - dwSize = sizeof(user_name); + dwSize = sizeof(user_name)/sizeof(WCHAR); rc=GetUserNameW(user_name, &dwSize); if (rc==FALSE && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { - skip("GetUserNameW is not available.\n"); + win_skip("GetUserNameW is not available.\n"); return 0; } ok(rc, "User Name Retrieved\n"); computer_name[0] = 0; - dwSize = sizeof(computer_name); + dwSize = sizeof(computer_name)/sizeof(WCHAR); ok(GetComputerNameW(computer_name, &dwSize), "Computer Name Retrieved\n"); return 1; } @@ -155,24 +155,25 @@ static void run_usergetinfo_tests(void) todo_wine { /* FIXME - Currently Wine can't verify whether the network path is good or bad */ rc=pNetUserGetInfo(sBadNetPath, sTestUserName, 0, (LPBYTE *)&ui0); - ok(rc == ERROR_BAD_NETPATH || rc == ERROR_NETWORK_UNREACHABLE, + ok(rc == ERROR_BAD_NETPATH || + rc == ERROR_NETWORK_UNREACHABLE || + rc == RPC_S_SERVER_UNAVAILABLE || + rc == RPC_S_INVALID_NET_ADDR, /* Some Win7 */ "Bad Network Path: rc=%d\n",rc); } rc=pNetUserGetInfo(sEmptyStr, sTestUserName, 0, (LPBYTE *)&ui0); ok(rc == ERROR_BAD_NETPATH || rc == NERR_Success, "Bad Network Path: rc=%d\n",rc); rc=pNetUserGetInfo(sInvalidName, sTestUserName, 0, (LPBYTE *)&ui0); - ok(rc == ERROR_INVALID_NAME,"Invalid Server Name: rc=%d\n",rc); + ok(rc == ERROR_INVALID_NAME || rc == ERROR_INVALID_HANDLE,"Invalid Server Name: rc=%d\n",rc); rc=pNetUserGetInfo(sInvalidName2, sTestUserName, 0, (LPBYTE *)&ui0); - ok(rc == ERROR_INVALID_NAME,"Invalid Server Name: rc=%d\n",rc); + ok(rc == ERROR_INVALID_NAME || rc == ERROR_INVALID_HANDLE,"Invalid Server Name: rc=%d\n",rc); if(delete_test_user() != NERR_Success) trace("Deleting the test user failed. You might have to manually delete it.\n"); } -/* checks Level 1 of NetQueryDisplayInformation - * FIXME: Needs to be rewritten to not depend on the spelling of the users, - * ideally based on the admin and guest user SIDs/RIDs.*/ +/* Checks Level 1 of NetQueryDisplayInformation */ static void run_querydisplayinformation1_tests(void) { PNET_DISPLAY_USER Buffer, rec; @@ -180,9 +181,6 @@ static void run_querydisplayinformation1_tests(void) DWORD i = 0; BOOL hasAdmin = FALSE; BOOL hasGuest = FALSE; - static const WCHAR sAdminUserName[] = {'A','d','m','i','n','i','s','t','r','a', - 't','o','r',0}; - static const WCHAR sGuestUserName[] = {'G','u','e','s','t',0}; do { @@ -195,14 +193,14 @@ static void run_querydisplayinformation1_tests(void) rec = Buffer; for(; EntryCount > 0; EntryCount--) { - if (!lstrcmpW(rec->usri1_name, sAdminUserName)) + if (rec->usri1_user_id == DOMAIN_USER_RID_ADMIN) { ok(!hasAdmin, "One admin user\n"); ok(rec->usri1_flags & UF_SCRIPT, "UF_SCRIPT flag is set\n"); ok(rec->usri1_flags & UF_NORMAL_ACCOUNT, "UF_NORMAL_ACCOUNT flag is set\n"); hasAdmin = TRUE; } - else if (!lstrcmpW(rec->usri1_name, sGuestUserName)) + else if (rec->usri1_user_id == DOMAIN_USER_RID_GUEST) { ok(!hasGuest, "One guest record\n"); ok(rec->usri1_flags & UF_SCRIPT, "UF_SCRIPT flag is set\n"); @@ -217,7 +215,7 @@ static void run_querydisplayinformation1_tests(void) pNetApiBufferFree(Buffer); } while (Result == ERROR_MORE_DATA); - ok(hasAdmin, "Has Administrator account\n"); + ok(hasAdmin, "Doesn't have 'Administrator' account\n"); } static void run_usermodalsget_tests(void) @@ -256,14 +254,22 @@ static void run_userhandling_tests(void) ret = pNetUserDel(NULL, sTooLongName); ok(ret == NERR_Success, "Deleting the user failed : %d\n", ret); } + else if (ret == ERROR_ACCESS_DENIED) + { + skip("not enough permissions to add a user\n"); + return; + } else - ok(ret == NERR_BadUsername, "Adding user with too long username returned 0x%08x\n", ret); + ok(ret == NERR_BadUsername || + broken(ret == NERR_PasswordTooShort), /* NT4 */ + "Adding user with too long username returned 0x%08x\n", ret); usri.usri1_name = sTestUserName; usri.usri1_password = sTooLongPassword; ret = pNetUserAdd(NULL, 1, (LPBYTE)&usri, NULL); - ok(ret == NERR_PasswordTooShort, "Adding user with too long password returned 0x%08x\n", ret); + ok(ret == NERR_PasswordTooShort || ret == ERROR_ACCESS_DENIED /* Win2003 */, + "Adding user with too long password returned 0x%08x\n", ret); usri.usri1_name = sTooLongName; usri.usri1_password = sTooLongPassword; @@ -293,7 +299,9 @@ static void run_userhandling_tests(void) return; } - ok(ret == NERR_Success, "Adding user failed with error 0x%08x\n", ret); + ok(ret == NERR_Success || + broken(ret == NERR_PasswordTooShort), /* NT4 */ + "Adding user failed with error 0x%08x\n", ret); if(ret != NERR_Success) return; @@ -328,7 +336,7 @@ START_TEST(access) * if one is not available, none are. */ if (!pNetApiBufferFree) { - skip("Needed functions are not available\n"); + win_skip("Needed functions are not available\n"); FreeLibrary(hnetapi32); return; } diff --git a/rostests/winetests/netapi32/apibuf.c b/rostests/winetests/netapi32/apibuf.c index 5589c1819d6..de8613b8fb3 100644 --- a/rostests/winetests/netapi32/apibuf.c +++ b/rostests/winetests/netapi32/apibuf.c @@ -42,30 +42,29 @@ static void run_apibuf_tests(void) NET_API_STATUS res; /* test normal logic */ - ok(pNetApiBufferAllocate(1024, (LPVOID *)&p) == NERR_Success, + ok(pNetApiBufferAllocate(1024, &p) == NERR_Success, "Reserved memory\n"); ok(pNetApiBufferSize(p, &dwSize) == NERR_Success, "Got size\n"); ok(dwSize >= 1024, "The size is correct\n"); - ok(pNetApiBufferReallocate(p, 1500, (LPVOID *) &p) == NERR_Success, + ok(pNetApiBufferReallocate(p, 1500, &p) == NERR_Success, "Reallocated\n"); ok(pNetApiBufferSize(p, &dwSize) == NERR_Success, "Got size\n"); ok(dwSize >= 1500, "The size is correct\n"); ok(pNetApiBufferFree(p) == NERR_Success, "Freed\n"); - ok(pNetApiBufferSize(p, &dwSize) == NERR_Success, "Got size\n"); ok(pNetApiBufferSize(NULL, &dwSize) == ERROR_INVALID_PARAMETER, "Error for NULL pointer\n"); /* border reallocate cases */ - ok(pNetApiBufferReallocate(0, 1500, (LPVOID *) &p) == NERR_Success, "Reallocate with OldBuffer = NULL failed\n"); + ok(pNetApiBufferReallocate(0, 1500, &p) == NERR_Success, "Reallocate with OldBuffer = NULL failed\n"); ok(p != NULL, "No memory got allocated\n"); - ok(pNetApiBufferAllocate(1024, (LPVOID *)&p) == NERR_Success, "Memory not reserved\n"); - ok(pNetApiBufferReallocate(p, 0, (LPVOID *) &p) == NERR_Success, "Not freed\n"); + ok(pNetApiBufferAllocate(1024, &p) == NERR_Success, "Memory not reserved\n"); + ok(pNetApiBufferReallocate(p, 0, &p) == NERR_Success, "Not freed\n"); ok(p == NULL, "Pointer not cleared\n"); /* 0-length buffer */ - ok(pNetApiBufferAllocate(0, (LPVOID *)&p) == NERR_Success, + ok(pNetApiBufferAllocate(0, &p) == NERR_Success, "Reserved memory\n"); ok(pNetApiBufferSize(p, &dwSize) == NERR_Success, "Got size\n"); ok(dwSize < 0xFFFFFFFF, "The size of the 0-length buffer\n"); @@ -74,13 +73,13 @@ static void run_apibuf_tests(void) /* NULL-Pointer */ /* NT: ERROR_INVALID_PARAMETER, lasterror is untouched) */ SetLastError(0xdeadbeef); - res = pNetApiBufferAllocate(0, (LPVOID *)NULL); + res = pNetApiBufferAllocate(0, NULL); ok( (res == ERROR_INVALID_PARAMETER) && (GetLastError() == 0xdeadbeef), "returned %d with 0x%x (expected ERROR_INVALID_PARAMETER with " "0xdeadbeef)\n", res, GetLastError()); SetLastError(0xdeadbeef); - res = pNetApiBufferAllocate(1024, (LPVOID *)NULL); + res = pNetApiBufferAllocate(1024, NULL); ok( (res == ERROR_INVALID_PARAMETER) && (GetLastError() == 0xdeadbeef), "returned %d with 0x%x (expected ERROR_INVALID_PARAMETER with " "0xdeadbeef)\n", res, GetLastError()); @@ -98,7 +97,7 @@ START_TEST(apibuf) if (pNetApiBufferAllocate && pNetApiBufferFree && pNetApiBufferReallocate && pNetApiBufferSize) run_apibuf_tests(); else - skip("Needed functions are not available\n"); + win_skip("Needed functions are not available\n"); FreeLibrary(hnetapi32); } diff --git a/rostests/winetests/netapi32/ds.c b/rostests/winetests/netapi32/ds.c index 277a589b8ca..be9597d79ef 100644 --- a/rostests/winetests/netapi32/ds.c +++ b/rostests/winetests/netapi32/ds.c @@ -87,7 +87,7 @@ START_TEST(ds) test_get(); } else - skip("DsRoleGetPrimaryDomainInformation is not available\n"); + win_skip("DsRoleGetPrimaryDomainInformation is not available\n"); FreeLibrary(hnetapi32); } diff --git a/rostests/winetests/netapi32/netapi32.rbuild b/rostests/winetests/netapi32/netapi32.rbuild index b8774cde957..65791cb29f9 100644 --- a/rostests/winetests/netapi32/netapi32.rbuild +++ b/rostests/winetests/netapi32/netapi32.rbuild @@ -3,8 +3,7 @@ . - 0x600 - 0x600 + access.c apibuf.c ds.c @@ -12,7 +11,6 @@ testlist.c wine advapi32 - kernel32 ntdll diff --git a/rostests/winetests/netapi32/wksta.c b/rostests/winetests/netapi32/wksta.c index b4994f8a2d3..9df7f0889e9 100644 --- a/rostests/winetests/netapi32/wksta.c +++ b/rostests/winetests/netapi32/wksta.c @@ -51,7 +51,7 @@ static int init_wksta_tests(void) dwSize = sizeof(user_name)/sizeof(user_name[0]); rc=GetUserNameW(user_name, &dwSize); if (rc==FALSE && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { - skip("GetUserNameW is not implemented\n"); + win_skip("GetUserNameW is not implemented\n"); return 0; } ok(rc, "User Name Retrieved\n"); @@ -173,7 +173,8 @@ static void run_wkstatransportenum_tests(void) ok(bufPtr != NULL, "got data back\n"); ok(entriesRead > 0, "read at least one transport\n"); - ok(totalEntries > 0, "at least one transport\n"); + ok(totalEntries > 0 || broken(totalEntries == 0) /* Win7 */, + "at least one transport\n"); pNetApiBufferFree(bufPtr); } } @@ -192,13 +193,16 @@ START_TEST(wksta) * if one is not available, none are. */ if (!pNetApiBufferFree) { - skip("Needed functions are not available\n"); + win_skip("Needed functions are not available\n"); FreeLibrary(hnetapi32); return; } if (init_wksta_tests()) { + if (pNetpGetComputerName) run_get_comp_name_tests(); + else + win_skip("Function NetpGetComputerName not available\n"); run_wkstausergetinfo_tests(); run_wkstatransportenum_tests(); } diff --git a/rostests/winetests/ntdll/atom.c b/rostests/winetests/ntdll/atom.c index 87ea222a8f7..27405e18012 100755 --- a/rostests/winetests/ntdll/atom.c +++ b/rostests/winetests/ntdll/atom.c @@ -54,6 +54,7 @@ static NTSTATUS (WINAPI *pRtlPinAtomInAtomTable)(RTL_ATOM_TABLE,RTL_ATOM); static NTSTATUS (WINAPI *pRtlQueryAtomInAtomTable)(RTL_ATOM_TABLE,RTL_ATOM,PULONG,PULONG,PWSTR,PULONG); static NTSTATUS (WINAPI* pNtAddAtom)(LPCWSTR,ULONG,RTL_ATOM*); +static NTSTATUS (WINAPI* pNtAddAtomNT4)(LPCWSTR,RTL_ATOM*); static NTSTATUS (WINAPI* pNtQueryInformationAtom)(RTL_ATOM,DWORD,void*,ULONG,PULONG); static const WCHAR EmptyAtom[] = {0}; @@ -266,7 +267,8 @@ static void test_NtAtom(void) Len = 0; res = pRtlQueryAtomInAtomTable(AtomTable, Atom1, NULL, NULL, Name, &Len); ok(res == STATUS_BUFFER_TOO_SMALL, "Got wrong retval, retval: %x\n", res); - ok((lstrlenW(testAtom1) * sizeof(WCHAR)) == Len, "Got wrong length %x\n", Len); + ok((lstrlenW(testAtom1) * sizeof(WCHAR)) == Len || broken(!Len) /* nt4 */, "Got wrong length %x\n", Len); + if (!Len) pNtAddAtomNT4 = (void *)pNtAddAtom; res = pRtlPinAtomInAtomTable(AtomTable, Atom1); ok(!res, "Unable to pin atom in atom table, retval: %x\n", res); @@ -293,7 +295,7 @@ static void test_NtIntAtom(void) RTL_ATOM_TABLE AtomTable; RTL_ATOM testAtom; ULONG RefCount = 0, PinCount = 0; - int i; + INT_PTR i; WCHAR Name[64]; ULONG Len; @@ -305,29 +307,29 @@ static void test_NtIntAtom(void) { /* According to the kernel32 functions, integer atoms are only allowed from * 0x0001 to 0xbfff and not 0xc000 to 0xffff, which is correct */ - res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)0, &testAtom); + res = pRtlAddAtomToAtomTable(AtomTable, NULL, &testAtom); ok(res == STATUS_INVALID_PARAMETER, "Didn't get expected result from adding 0 int atom, retval: %x\n", res); for (i = 1; i <= 0xbfff; i++) { - res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)i, &testAtom); - ok(!res, "Unable to add valid integer atom %i, retval: %x\n", i, res); + res = pRtlAddAtomToAtomTable(AtomTable, (LPWSTR)i, &testAtom); + ok(!res, "Unable to add valid integer atom %li, retval: %x\n", i, res); } for (i = 1; i <= 0xbfff; i++) { - res = pRtlLookupAtomInAtomTable(AtomTable, (PWSTR)i, &testAtom); - ok(!res, "Unable to find int atom %i, retval: %x\n", i, res); + res = pRtlLookupAtomInAtomTable(AtomTable, (LPWSTR)i, &testAtom); + ok(!res, "Unable to find int atom %li, retval: %x\n", i, res); if (!res) { res = pRtlPinAtomInAtomTable(AtomTable, testAtom); - ok(!res, "Unable to pin int atom %i, retval: %x\n", i, res); + ok(!res, "Unable to pin int atom %li, retval: %x\n", i, res); } } for (i = 0xc000; i <= 0xffff; i++) { - res = pRtlAddAtomToAtomTable(AtomTable, (PWSTR)i, &testAtom); - ok(res, "Able to illeageal integer atom %i, retval: %x\n", i, res); + res = pRtlAddAtomToAtomTable(AtomTable, (LPWSTR)i, &testAtom); + ok(res, "Able to illeageal integer atom %li, retval: %x\n", i, res); } res = pRtlDestroyAtomTable(AtomTable); @@ -433,7 +435,11 @@ static void test_Global(void) ATOM_BASIC_INFORMATION* abi = (ATOM_BASIC_INFORMATION*)ptr; ULONG ptr_size = sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR); + if (pNtAddAtomNT4) + res = pNtAddAtomNT4(testAtom1, &atom); + else res = pNtAddAtom(testAtom1, lstrlenW(testAtom1) * sizeof(WCHAR), &atom); + ok(!res, "Added atom (%x)\n", res); memset(abi->Name, 0xcc, 255 * sizeof(WCHAR)); @@ -447,7 +453,8 @@ static void test_Global(void) ptr_size = sizeof(ATOM_BASIC_INFORMATION); res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL ); ok(res == STATUS_BUFFER_TOO_SMALL, "wrong return status (%x)\n", res); - ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "ok string length\n"); + ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR) || broken(abi->NameLength == sizeof(WCHAR)), /* nt4 */ + "string length %u\n",abi->NameLength); memset(abi->Name, 0xcc, lstrlenW(testAtom1) * sizeof(WCHAR)); ptr_size = sizeof(ATOM_BASIC_INFORMATION) + lstrlenW(testAtom1) * sizeof(WCHAR); @@ -476,4 +483,8 @@ START_TEST(atom) test_NtRefPinAtom(); test_Global(); } + else + win_skip("Needed atom functions are not available\n"); + + FreeLibrary(hntdll); } diff --git a/rostests/winetests/ntdll/change.c b/rostests/winetests/ntdll/change.c index d3ba58fc1c1..f395962ec23 100644 --- a/rostests/winetests/ntdll/change.c +++ b/rostests/winetests/ntdll/change.c @@ -318,7 +318,7 @@ START_TEST(change) HMODULE hntdll = GetModuleHandle("ntdll"); if (!hntdll) { - skip("not running on NT, skipping test\n"); + win_skip("not running on NT, skipping test\n"); return; } @@ -329,7 +329,7 @@ START_TEST(change) if (!pNtNotifyChangeDirectoryFile || !pNtCancelIoFile) { - skip("missing functions, skipping test\n"); + win_skip("missing functions, skipping test\n"); return; } diff --git a/rostests/winetests/ntdll/env.c b/rostests/winetests/ntdll/env.c index 3363e73484e..82898412643 100755 --- a/rostests/winetests/ntdll/env.c +++ b/rostests/winetests/ntdll/env.c @@ -57,6 +57,7 @@ static void testQuery(void) int len; NTSTATUS status; const char *val; + NTSTATUS alt; }; static const struct test tests[] = @@ -67,12 +68,13 @@ static void testQuery(void) {"foo ", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, {"foo", 1, STATUS_BUFFER_TOO_SMALL, "toto"}, {"foo", 3, STATUS_BUFFER_TOO_SMALL, "toto"}, - {"foo", 4, STATUS_SUCCESS, "toto"}, + {"foo", 4, STATUS_SUCCESS, "toto", STATUS_BUFFER_TOO_SMALL}, + {"foo", 5, STATUS_SUCCESS, "toto"}, {"fooo", 256, STATUS_SUCCESS, "tutu"}, {"f", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, {"g", 256, STATUS_SUCCESS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, - {"sr=an", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, + {"sr=an", 256, STATUS_SUCCESS, "ouo", STATUS_VARIABLE_NOT_FOUND}, {"sr", 256, STATUS_SUCCESS, "an=ouo"}, {"=oOH", 256, STATUS_SUCCESS, "III"}, {"", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, @@ -84,11 +86,12 @@ static void testQuery(void) WCHAR bv[257]; UNICODE_STRING name; UNICODE_STRING value; - const struct test* test; NTSTATUS nts; + unsigned int i; - for (test = tests; test->var; test++) + for (i = 0; tests[i].var; i++) { + const struct test *test = &tests[i]; name.Length = strlen(test->var) * 2; name.MaximumLength = name.Length + 2; name.Buffer = bn; @@ -99,8 +102,9 @@ static void testQuery(void) pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->var, strlen(test->var)+1 ); nts = pRtlQueryEnvironmentVariable_U(small_env, &name, &value); - ok( nts == test->status, "[%d]: Wrong status for '%s', expecting %x got %x\n", - test - tests, test->var, test->status, nts ); + ok( nts == test->status || (test->alt && nts == test->alt), + "[%d]: Wrong status for '%s', expecting %x got %x\n", + i, test->var, test->status, nts ); if (nts == test->status) switch (nts) { case STATUS_SUCCESS: @@ -120,7 +124,7 @@ static void testQuery(void) } } -static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATUS ret) +static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATUS ret, NTSTATUS alt) { WCHAR bvar[256], bval1[256], bval2[256]; UNICODE_STRING uvar; @@ -139,7 +143,7 @@ static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATU pRtlMultiByteToUnicodeN( bval1, sizeof(bval1), NULL, val, strlen(val)+1 ); } nts = pRtlSetEnvironmentVariable(env, &uvar, val ? &uval : NULL); - ok(nts == ret, "Setting var %s=%s (%x/%x)\n", var, val, nts, ret); + ok(nts == ret || (alt && nts == alt), "Setting var %s=%s (%x/%x)\n", var, val, nts, ret); if (nts == STATUS_SUCCESS) { uval.Length = 0; @@ -152,7 +156,9 @@ static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATU ok(lstrcmpW(bval1, bval2) == 0, "Cannot get value written to environment\n"); break; case STATUS_VARIABLE_NOT_FOUND: - ok(val == NULL, "Couldn't find variable, but didn't delete it. val = %s\n", val); + ok(val == NULL || + broken(strchr(var,'=') != NULL), /* variable containing '=' may be set but not found again on NT4 */ + "Couldn't find variable, but didn't delete it. val = %s\n", val); break; default: ok(0, "Wrong ret %u for %s\n", nts, var); @@ -168,31 +174,30 @@ static void testSet(void) int i; ok(pRtlCreateEnvironment(FALSE, &env) == STATUS_SUCCESS, "Creating environment\n"); - memmove(env, small_env, sizeof(small_env)); - testSetHelper(&env, "cat", "dog", STATUS_SUCCESS); - testSetHelper(&env, "cat", "horse", STATUS_SUCCESS); - testSetHelper(&env, "cat", "zz", STATUS_SUCCESS); - testSetHelper(&env, "cat", NULL, STATUS_SUCCESS); - testSetHelper(&env, "cat", NULL, STATUS_VARIABLE_NOT_FOUND); - testSetHelper(&env, "foo", "meouw", STATUS_SUCCESS); - testSetHelper(&env, "me=too", "also", STATUS_INVALID_PARAMETER); - testSetHelper(&env, "me", "too=also", STATUS_SUCCESS); - testSetHelper(&env, "=too", "also", STATUS_SUCCESS); - testSetHelper(&env, "=", "also", STATUS_SUCCESS); + testSetHelper(&env, "cat", "dog", STATUS_SUCCESS, 0); + testSetHelper(&env, "cat", "horse", STATUS_SUCCESS, 0); + testSetHelper(&env, "cat", "zz", STATUS_SUCCESS, 0); + testSetHelper(&env, "cat", NULL, STATUS_SUCCESS, 0); + testSetHelper(&env, "cat", NULL, STATUS_SUCCESS, STATUS_VARIABLE_NOT_FOUND); + testSetHelper(&env, "foo", "meouw", STATUS_SUCCESS, 0); + testSetHelper(&env, "me=too", "also", STATUS_SUCCESS, STATUS_INVALID_PARAMETER); + testSetHelper(&env, "me", "too=also", STATUS_SUCCESS, 0); + testSetHelper(&env, "=too", "also", STATUS_SUCCESS, 0); + testSetHelper(&env, "=", "also", STATUS_SUCCESS, 0); for (i = 0; i < 128; i++) { sprintf(tmp, "zork%03d", i); - testSetHelper(&env, tmp, "is alive", STATUS_SUCCESS); + testSetHelper(&env, tmp, "is alive", STATUS_SUCCESS, 0); } for (i = 0; i < 128; i++) { sprintf(tmp, "zork%03d", i); - testSetHelper(&env, tmp, NULL, STATUS_SUCCESS); + testSetHelper(&env, tmp, NULL, STATUS_SUCCESS, 0); } - testSetHelper(&env, "fOo", NULL, STATUS_SUCCESS); + testSetHelper(&env, "fOo", NULL, STATUS_SUCCESS, 0); ok(pRtlDestroyEnvironment(env) == STATUS_SUCCESS, "Destroying environment\n"); } @@ -263,9 +268,6 @@ static void testExpand(void) ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%u)\n", nts); ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), "Wrong returned length for %s (with buffer too small): %u\n", test->src, ul); - ok(memcmp(dst, rst, 8*sizeof(WCHAR)) == 0, - "Wrong result for %s (with buffer too small): expecting %s\n", - test->src, test->dst); ok(dst[8] == '-', "Writing too far in buffer (got %c/%d)\n", dst[8], dst[8]); } @@ -274,6 +276,11 @@ static void testExpand(void) START_TEST(env) { HMODULE mod = GetModuleHandleA("ntdll.dll"); + if (!mod) + { + win_skip("Not running on NT, skipping tests\n"); + return; + } pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN"); pRtlCreateEnvironment = (void*)GetProcAddress(mod, "RtlCreateEnvironment"); diff --git a/rostests/winetests/ntdll/error.c b/rostests/winetests/ntdll/error.c index b00b83bd661..b65d7d0ccd7 100755 --- a/rostests/winetests/ntdll/error.c +++ b/rostests/winetests/ntdll/error.c @@ -57,7 +57,10 @@ static int prepare_test(void) ntdll = LoadLibraryA("ntdll.dll"); pRtlNtStatusToDosError = (void*)GetProcAddress(ntdll, "RtlNtStatusToDosError"); if (!pRtlNtStatusToDosError) + { + win_skip("RtlNtStatusToDosError is not available\n"); return 0; + } argc = winetest_get_mainargs(&argv); strict=(argc >= 3 && strcmp(argv[2],"strict")==0); @@ -186,7 +189,7 @@ static void run_error_tests(void) cmp(STATUS_HANDLE_NOT_CLOSABLE, ERROR_INVALID_HANDLE); cmp(STATUS_NOT_COMMITTED, ERROR_INVALID_ADDRESS); cmp(STATUS_PARTIAL_COPY, ERROR_PARTIAL_COPY); - cmp(STATUS_LPC_REPLY_LOST, ERROR_INTERNAL_ERROR); + cmp3(STATUS_LPC_REPLY_LOST, ERROR_INTERNAL_ERROR, ERROR_CONNECTION_ABORTED); cmp(STATUS_INVALID_PARAMETER, ERROR_INVALID_PARAMETER); cmp(STATUS_INVALID_PARAMETER_1, ERROR_INVALID_PARAMETER); cmp(STATUS_INVALID_PARAMETER_2, ERROR_INVALID_PARAMETER); @@ -735,8 +738,8 @@ static void run_error_tests(void) cmp(STATUS_LOGIN_WKSTA_RESTRICTION, ERROR_LOGIN_WKSTA_RESTRICTION); cmp(STATUS_LICENSE_QUOTA_EXCEEDED, ERROR_LICENSE_QUOTA_EXCEEDED); cmp(STATUS_RESOURCE_NOT_OWNED, ERROR_NOT_OWNER); - cmp(STATUS_DUPLICATE_OBJECTID, STATUS_DUPLICATE_OBJECTID); - cmp(STATUS_OBJECTID_EXISTS, STATUS_OBJECTID_EXISTS); + cmp3(STATUS_DUPLICATE_OBJECTID, STATUS_DUPLICATE_OBJECTID, ERROR_OBJECT_ALREADY_EXISTS); + cmp3(STATUS_OBJECTID_EXISTS, STATUS_OBJECTID_EXISTS, ERROR_OBJECT_ALREADY_EXISTS); cmp2(STATUS_OBJECTID_NOT_FOUND, ERROR_FILE_NOT_FOUND); cmp2(STATUS_MFT_TOO_FRAGMENTED, ERROR_DISK_TOO_FRAGMENTED); cmp(SEC_E_INSUFFICIENT_MEMORY, ERROR_NO_SYSTEM_RESOURCES); diff --git a/rostests/winetests/ntdll/exception.c b/rostests/winetests/ntdll/exception.c index e256e187066..6ed641c6dad 100644 --- a/rostests/winetests/ntdll/exception.c +++ b/rostests/winetests/ntdll/exception.c @@ -21,6 +21,10 @@ #include #include +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x500 /* For NTSTATUS */ +#endif + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -61,110 +65,115 @@ static const struct exception } exceptions[] = { /* test some privileged instructions */ - { { 0xfb, 0xc3 }, /* sti; ret */ + { { 0xfb, 0xc3 }, /* 0: sti; ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x6c, 0xc3 }, /* insb (%dx); ret */ + { { 0x6c, 0xc3 }, /* 1: insb (%dx); ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x6d, 0xc3 }, /* insl (%dx); ret */ + { { 0x6d, 0xc3 }, /* 2: insl (%dx); ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x6e, 0xc3 }, /* outsb (%dx); ret */ + { { 0x6e, 0xc3 }, /* 3: outsb (%dx); ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x6f, 0xc3 }, /* outsl (%dx); ret */ + { { 0x6f, 0xc3 }, /* 4: outsl (%dx); ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xe4, 0x11, 0xc3 }, /* inb $0x11,%al; ret */ + { { 0xe4, 0x11, 0xc3 }, /* 5: inb $0x11,%al; ret */ 0, 2, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xe5, 0x11, 0xc3 }, /* inl $0x11,%eax; ret */ + { { 0xe5, 0x11, 0xc3 }, /* 6: inl $0x11,%eax; ret */ 0, 2, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xe6, 0x11, 0xc3 }, /* outb %al,$0x11; ret */ + { { 0xe6, 0x11, 0xc3 }, /* 7: outb %al,$0x11; ret */ 0, 2, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xe7, 0x11, 0xc3 }, /* outl %eax,$0x11; ret */ + { { 0xe7, 0x11, 0xc3 }, /* 8: outl %eax,$0x11; ret */ 0, 2, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xed, 0xc3 }, /* inl (%dx),%eax; ret */ + { { 0xed, 0xc3 }, /* 9: inl (%dx),%eax; ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xee, 0xc3 }, /* outb %al,(%dx); ret */ + { { 0xee, 0xc3 }, /* 10: outb %al,(%dx); ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xef, 0xc3 }, /* outl %eax,(%dx); ret */ + { { 0xef, 0xc3 }, /* 11: outl %eax,(%dx); ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xf4, 0xc3 }, /* hlt; ret */ + { { 0xf4, 0xc3 }, /* 12: hlt; ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0xfa, 0xc3 }, /* cli; ret */ + { { 0xfa, 0xc3 }, /* 13: cli; ret */ 0, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* test long jump to invalid selector */ - { { 0xea, 0, 0, 0, 0, 0, 0, 0xc3 }, /* ljmp $0,$0; ret */ + { { 0xea, 0, 0, 0, 0, 0, 0, 0xc3 }, /* 14: ljmp $0,$0; ret */ 0, 7, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* test iret to invalid selector */ { { 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0xcf, 0x83, 0xc4, 0x0c, 0xc3 }, - /* pushl $0; pushl $0; pushl $0; iret; addl $12,%esp; ret */ + /* 15: pushl $0; pushl $0; pushl $0; iret; addl $12,%esp; ret */ 6, 1, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* test loading an invalid selector */ - { { 0xb8, 0xef, 0xbe, 0x00, 0x00, 0x8e, 0xe8, 0xc3 }, /* mov $beef,%ax; mov %ax,%gs; ret */ + { { 0xb8, 0xef, 0xbe, 0x00, 0x00, 0x8e, 0xe8, 0xc3 }, /* 16: mov $beef,%ax; mov %ax,%gs; ret */ 5, 2, STATUS_ACCESS_VIOLATION, 2, { 0, 0xbee8 } }, /* 0xbee8 or 0xffffffff */ /* test accessing a zero selector */ { { 0x06, 0x31, 0xc0, 0x8e, 0xc0, 0x26, 0xa1, 0, 0, 0, 0, 0x07, 0xc3 }, - /* push %es; xor %eax,%eax; mov %ax,%es; mov %es:(0),%ax; pop %es */ + /* 17: push %es; xor %eax,%eax; mov %ax,%es; mov %es:(0),%ax; pop %es; ret */ 5, 6, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* test moving %cs -> %ss */ - { { 0x0e, 0x17, 0x58, 0xc3 }, /* pushl %cs; popl %ss; popl %eax; ret */ + { { 0x0e, 0x17, 0x58, 0xc3 }, /* 18: pushl %cs; popl %ss; popl %eax; ret */ 1, 1, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, - /* test overlong instruction (limit is 16 bytes) */ + /* 19: test overlong instruction (limit is 16 bytes) */ { { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 }, 0, 16, STATUS_ILLEGAL_INSTRUCTION, 0 }, { { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 }, 0, 15, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* test invalid interrupt */ - { { 0xcd, 0xff, 0xc3 }, /* int $0xff; ret */ + { { 0xcd, 0xff, 0xc3 }, /* 21: int $0xff; ret */ 0, 2, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* test moves to/from Crx */ - { { 0x0f, 0x20, 0xc0, 0xc3 }, /* movl %cr0,%eax; ret */ + { { 0x0f, 0x20, 0xc0, 0xc3 }, /* 22: movl %cr0,%eax; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x20, 0xe0, 0xc3 }, /* movl %cr4,%eax; ret */ + { { 0x0f, 0x20, 0xe0, 0xc3 }, /* 23: movl %cr4,%eax; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x22, 0xc0, 0xc3 }, /* movl %eax,%cr0; ret */ + { { 0x0f, 0x22, 0xc0, 0xc3 }, /* 24: movl %eax,%cr0; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x22, 0xe0, 0xc3 }, /* movl %eax,%cr4; ret */ + { { 0x0f, 0x22, 0xe0, 0xc3 }, /* 25: movl %eax,%cr4; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* test moves to/from Drx */ - { { 0x0f, 0x21, 0xc0, 0xc3 }, /* movl %dr0,%eax; ret */ + { { 0x0f, 0x21, 0xc0, 0xc3 }, /* 26: movl %dr0,%eax; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x21, 0xc8, 0xc3 }, /* movl %dr1,%eax; ret */ + { { 0x0f, 0x21, 0xc8, 0xc3 }, /* 27: movl %dr1,%eax; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x21, 0xf8, 0xc3 }, /* movl %dr7,%eax; ret */ + { { 0x0f, 0x21, 0xf8, 0xc3 }, /* 28: movl %dr7,%eax; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x23, 0xc0, 0xc3 }, /* movl %eax,%dr0; ret */ + { { 0x0f, 0x23, 0xc0, 0xc3 }, /* 29: movl %eax,%dr0; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x23, 0xc8, 0xc3 }, /* movl %eax,%dr1; ret */ + { { 0x0f, 0x23, 0xc8, 0xc3 }, /* 30: movl %eax,%dr1; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x23, 0xf8, 0xc3 }, /* movl %eax,%dr7; ret */ + { { 0x0f, 0x23, 0xf8, 0xc3 }, /* 31: movl %eax,%dr7; ret */ 0, 3, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* test memory reads */ - { { 0xa1, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffc,%eax; ret */ + { { 0xa1, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* 32: movl 0xfffffffc,%eax; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffc } }, - { { 0xa1, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffd,%eax; ret */ + { { 0xa1, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* 33: movl 0xfffffffd,%eax; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffd } }, - { { 0xa1, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffe,%eax; ret */ + { { 0xa1, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* 34: movl 0xfffffffe,%eax; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffe } }, - { { 0xa1, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xffffffff,%eax; ret */ + { { 0xa1, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* 35: movl 0xffffffff,%eax; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* test memory writes */ - { { 0xa3, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffc; ret */ + { { 0xa3, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* 36: movl %eax,0xfffffffc; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffc } }, - { { 0xa3, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffd; ret */ + { { 0xa3, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* 37: movl %eax,0xfffffffd; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffd } }, - { { 0xa3, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffe; ret */ + { { 0xa3, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* 38: movl %eax,0xfffffffe; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffe } }, - { { 0xa3, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xffffffff; ret */ + { { 0xa3, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* 39: movl %eax,0xffffffff; ret */ 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xffffffff } }, + + /* 40: test exception with cleared %ds and %es */ + { { 0x1e, 0x06, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfa, 0x07, 0x1f, 0xc3 }, + /* push %ds; push %es; xorl %eax,%eax; mov %ax,%ds; mov %ax,%es; cli; pop %es; pop %ds; ret */ + 8, 1, STATUS_PRIVILEGED_INSTRUCTION, 0 }, }; static int got_exception; @@ -190,29 +199,29 @@ static void run_exception_test(void *handler, const void* context, pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev; } -LONG CALLBACK rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) +static LONG CALLBACK rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) { PCONTEXT context = ExceptionInfo->ContextRecord; PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; trace("vect. handler %08x addr:%p context.Eip:%x\n", rec->ExceptionCode, rec->ExceptionAddress, context->Eip); - todo_wine { ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n", rec->ExceptionAddress, (char *)code_mem + 0xb); if (pNtCurrentTeb()->Peb->BeingDebugged) ok((void *)context->Eax == pRtlRaiseException, "debugger managed to modify Eax to %x should be %p\n", context->Eax, pRtlRaiseException); - } /* check that context.Eip is fixed up only for EXCEPTION_BREAKPOINT * even if raised by RtlRaiseException */ if(rec->ExceptionCode == EXCEPTION_BREAKPOINT) { - ok(context->Eip == (DWORD)code_mem + 0xa, "Eip at %x instead of %x\n", - context->Eip, (DWORD)code_mem + 0xa); + ok(context->Eip == (DWORD)code_mem + 0xa || + broken(context->Eip == (DWORD)code_mem + 0xb), /* win2k3 */ + "Eip at %x instead of %x or %x\n", context->Eip, + (DWORD)code_mem + 0xa, (DWORD)code_mem + 0xb); } else { @@ -231,18 +240,18 @@ static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR trace( "exception: %08x flags:%x addr:%p context: Eip:%x\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Eip ); - todo_wine { ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n", rec->ExceptionAddress, (char *)code_mem + 0xb); - } /* check that context.Eip is fixed up only for EXCEPTION_BREAKPOINT * even if raised by RtlRaiseException */ if(rec->ExceptionCode == EXCEPTION_BREAKPOINT) { - ok(context->Eip == (DWORD)code_mem + 0xa, "Eip at %x instead of %x\n", - context->Eip, (DWORD)code_mem + 0xa); + ok(context->Eip == (DWORD)code_mem + 0xa || + broken(context->Eip == (DWORD)code_mem + 0xb), /* win2k3 */ + "Eip at %x instead of %x or %x\n", context->Eip, + (DWORD)code_mem + 0xa, (DWORD)code_mem + 0xb); } else { @@ -307,6 +316,8 @@ static void run_rtlraiseexception_test(DWORD exceptioncode) } func(pRtlRaiseException, &record); + ok( record.ExceptionAddress == (char *)code_mem + 0x0b, + "address set to %p instead of %p\n", record.ExceptionAddress, (char *)code_mem + 0x0b ); if (have_vectored_api) pRtlRemoveVectoredExceptionHandler(vectored_handler); @@ -488,13 +499,14 @@ static DWORD direction_flag_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATI { #ifdef __GNUC__ unsigned int flags; - __asm__("pushfl; popl %0" : "=r" (flags) ); + __asm__("pushfl; popl %0; cld" : "=r" (flags) ); /* older windows versions don't clear DF properly so don't test */ if (flags & 0x400) trace( "eflags has DF bit set\n" ); #endif ok( context->EFlags & 0x400, "context eflags has DF bit cleared\n" ); got_exception++; context->Eip++; /* skip cli */ + context->EFlags &= ~0x400; /* make sure it is cleared on return */ return ExceptionContinueExecution; } @@ -827,6 +839,82 @@ static void test_simd_exceptions(void) ok( got_exception == 1, "got exception: %i, should be 1\n", got_exception); } +struct fpu_exception_info +{ + DWORD exception_code; + DWORD exception_offset; + DWORD eip_offset; +}; + +static DWORD fpu_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher) +{ + struct fpu_exception_info *info = *(struct fpu_exception_info **)(frame + 1); + + info->exception_code = rec->ExceptionCode; + info->exception_offset = (BYTE *)rec->ExceptionAddress - (BYTE *)code_mem; + info->eip_offset = context->Eip - (DWORD)code_mem; + + ++context->Eip; + return ExceptionContinueExecution; +} + +static void test_fpu_exceptions(void) +{ + static const BYTE fpu_exception_test_ie[] = + { + 0x83, 0xec, 0x04, /* sub $0x4,%esp */ + 0x66, 0xc7, 0x04, 0x24, 0xfe, 0x03, /* movw $0x3fe,(%esp) */ + 0x9b, 0xd9, 0x7c, 0x24, 0x02, /* fstcw 0x2(%esp) */ + 0xd9, 0x2c, 0x24, /* fldcw (%esp) */ + 0xd9, 0xee, /* fldz */ + 0xd9, 0xe8, /* fld1 */ + 0xde, 0xf1, /* fdivp */ + 0xdd, 0xd8, /* fstp %st(0) */ + 0xdd, 0xd8, /* fstp %st(0) */ + 0x9b, /* fwait */ + 0xdb, 0xe2, /* fnclex */ + 0xd9, 0x6c, 0x24, 0x02, /* fldcw 0x2(%esp) */ + 0x83, 0xc4, 0x04, /* add $0x4,%esp */ + 0xc3, /* ret */ + }; + + static const BYTE fpu_exception_test_de[] = + { + 0x83, 0xec, 0x04, /* sub $0x4,%esp */ + 0x66, 0xc7, 0x04, 0x24, 0xfb, 0x03, /* movw $0x3fb,(%esp) */ + 0x9b, 0xd9, 0x7c, 0x24, 0x02, /* fstcw 0x2(%esp) */ + 0xd9, 0x2c, 0x24, /* fldcw (%esp) */ + 0xdd, 0xd8, /* fstp %st(0) */ + 0xd9, 0xee, /* fldz */ + 0xd9, 0xe8, /* fld1 */ + 0xde, 0xf1, /* fdivp */ + 0x9b, /* fwait */ + 0xdb, 0xe2, /* fnclex */ + 0xdd, 0xd8, /* fstp %st(0) */ + 0xdd, 0xd8, /* fstp %st(0) */ + 0xd9, 0x6c, 0x24, 0x02, /* fldcw 0x2(%esp) */ + 0x83, 0xc4, 0x04, /* add $0x4,%esp */ + 0xc3, /* ret */ + }; + + struct fpu_exception_info info; + + memset(&info, 0, sizeof(info)); + run_exception_test(fpu_exception_handler, &info, fpu_exception_test_ie, sizeof(fpu_exception_test_ie)); + ok(info.exception_code == EXCEPTION_FLT_STACK_CHECK, + "Got exception code %#x, expected EXCEPTION_FLT_STACK_CHECK\n", info.exception_code); + ok(info.exception_offset == 0x19, "Got exception offset %#x, expected 0x19\n", info.exception_offset); + ok(info.eip_offset == 0x1b, "Got EIP offset %#x, expected 0x1b\n", info.eip_offset); + + memset(&info, 0, sizeof(info)); + run_exception_test(fpu_exception_handler, &info, fpu_exception_test_de, sizeof(fpu_exception_test_de)); + ok(info.exception_code == EXCEPTION_FLT_DIVIDE_BY_ZERO, + "Got exception code %#x, expected EXCEPTION_FLT_DIVIDE_BY_ZERO\n", info.exception_code); + ok(info.exception_offset == 0x17, "Got exception offset %#x, expected 0x17\n", info.exception_offset); + ok(info.eip_offset == 0x19, "Got EIP offset %#x, expected 0x19\n", info.eip_offset); +} + #endif /* __i386__ */ START_TEST(exception) @@ -904,6 +992,7 @@ START_TEST(exception) test_rtlraiseexception(); test_debugger(); test_simd_exceptions(); + test_fpu_exceptions(); VirtualFree(code_mem, 1024, MEM_RELEASE); #endif diff --git a/rostests/winetests/ntdll/file.c b/rostests/winetests/ntdll/file.c index 6d37390f0b9..66250070ea0 100644 --- a/rostests/winetests/ntdll/file.c +++ b/rostests/winetests/ntdll/file.c @@ -2,6 +2,7 @@ * * Copyright 2007 Jeff Latimer * Copyright 2007 Andrey Turkin + * Copyright 2008 Jeff Zaroyko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,7 +27,6 @@ #include #include "ntstatus.h" - /* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro * definition errors when we get to winnt.h */ @@ -39,9 +39,12 @@ #define IO_COMPLETION_ALL_ACCESS 0x001F0003 #endif +static NTSTATUS (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING ); static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); +static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* ); static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG, ULONG, PLARGE_INTEGER ); +static NTSTATUS (WINAPI *pNtDeleteFile)(POBJECT_ATTRIBUTES ObjectAttributes); static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent, PIO_APC_ROUTINE apc, void* apc_user, PIO_STATUS_BLOCK io_status, void* buffer, ULONG length, @@ -66,6 +69,7 @@ static inline BOOL is_signaled( HANDLE obj ) } #define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c" +#define TEST_BUF_LEN 3 static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size ) { @@ -104,7 +108,7 @@ static long get_pending_msgs(HANDLE h) NTSTATUS res; ULONG a, req; - res = pNtQueryIoCompletion( h, IoCompletionBasicInformation, (PVOID)&a, sizeof(a), &req ); + res = pNtQueryIoCompletion( h, IoCompletionBasicInformation, &a, sizeof(a), &req ); ok( res == STATUS_SUCCESS, "NtQueryIoCompletion failed: %x\n", res ); if (res != STATUS_SUCCESS) return -1; ok( req == sizeof(a), "Unexpected response size: %x\n", req ); @@ -136,6 +140,68 @@ static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved ) ok( !reserved, "reserved is not 0: %x\n", reserved ); } +static void delete_file_test(void) +{ + NTSTATUS ret; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING nameW; + WCHAR pathW[MAX_PATH]; + WCHAR pathsubW[MAX_PATH]; + static const WCHAR testdirW[] = {'n','t','d','e','l','e','t','e','f','i','l','e',0}; + static const WCHAR subdirW[] = {'\\','s','u','b',0}; + + ret = GetTempPathW(MAX_PATH, pathW); + if (!ret) + { + ok(0, "couldn't get temp dir\n"); + return; + } + if (ret + sizeof(testdirW)/sizeof(WCHAR)-1 + sizeof(subdirW)/sizeof(WCHAR)-1 >= MAX_PATH) + { + ok(0, "MAX_PATH exceeded in constructing paths\n"); + return; + } + + lstrcatW(pathW, testdirW); + lstrcpyW(pathsubW, pathW); + lstrcatW(pathsubW, subdirW); + + ret = CreateDirectoryW(pathW, NULL); + ok(ret == TRUE, "couldn't create directory ntdeletefile\n"); + if (!pRtlDosPathNameToNtPathName_U(pathW, &nameW, NULL, NULL)) + { + ok(0,"RtlDosPathNametoNtPathName_U failed\n"); + return; + } + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = &nameW; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + /* test NtDeleteFile on an empty directory */ + ret = pNtDeleteFile(&attr); + ok(ret == STATUS_SUCCESS, "NtDeleteFile should succeed in removing an empty directory\n"); + ret = RemoveDirectoryW(pathW); + ok(ret == FALSE, "expected to fail removing directory, NtDeleteFile should have removed it\n"); + + /* test NtDeleteFile on a non-empty directory */ + ret = CreateDirectoryW(pathW, NULL); + ok(ret == TRUE, "couldn't create directory ntdeletefile ?!\n"); + ret = CreateDirectoryW(pathsubW, NULL); + ok(ret == TRUE, "couldn't create directory subdir\n"); + ret = pNtDeleteFile(&attr); + ok(ret == STATUS_SUCCESS, "expected NtDeleteFile to ret STATUS_SUCCESS\n"); + ret = RemoveDirectoryW(pathsubW); + ok(ret == TRUE, "expected to remove directory ntdeletefile\\sub\n"); + ret = RemoveDirectoryW(pathW); + ok(ret == TRUE, "expected to remove directory ntdeletefile, NtDeleteFile failed.\n"); + + pRtlFreeUnicodeString( &nameW ); +} + static void read_file_test(void) { const char text[] = "foobar"; @@ -311,7 +377,9 @@ static void read_file_test(void) offset.QuadPart = 0; ResetEvent( event ); status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL ); - ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( status == STATUS_SUCCESS || + status == STATUS_PENDING, /* vista */ + "wrong status %x\n", status ); ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); ok( is_signaled( event ), "event is signaled\n" ); @@ -325,6 +393,17 @@ static void read_file_test(void) iosb.Information = 0xdeadbeef; offset.QuadPart = strlen(text) + 2; status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL ); + if (status == STATUS_PENDING) /* vista */ + { + ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is signaled\n" ); + ok( !apc_count, "apc was called\n" ); + SleepEx( 1, TRUE ); /* alertable sleep */ + ok( apc_count == 1, "apc was not called\n" ); + } + else + { ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status ); ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); @@ -332,6 +411,7 @@ static void read_file_test(void) ok( !apc_count, "apc was called\n" ); SleepEx( 1, TRUE ); /* alertable sleep */ ok( !apc_count, "apc was called\n" ); + } CloseHandle( handle ); /* now a non-overlapped file */ @@ -341,7 +421,9 @@ static void read_file_test(void) iosb.Information = 0xdeadbeef; offset.QuadPart = 0; pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL ); - ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status ); + ok( status == STATUS_END_OF_FILE || + status == STATUS_PENDING, /* vista */ + "wrong status %x\n", status ); ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); ok( is_signaled( event ), "event is signaled\n" ); @@ -403,7 +485,8 @@ static void nt_mailslot_test(void) pRtlInitUnicodeString(&str, buffer1); InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); - DesiredAccess = CreateOptions = MailslotQuota = MaxMessageSize = 0; + CreateOptions = MailslotQuota = MaxMessageSize = 0; + DesiredAccess = GENERIC_READ; /* * Check for NULL pointer handling @@ -411,15 +494,20 @@ static void nt_mailslot_test(void) rc = pNtCreateMailslotFile(NULL, DesiredAccess, &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, &TimeOut); - ok( rc == STATUS_ACCESS_VIOLATION, "rc = %x not c0000005 STATUS_ACCESS_VIOLATION\n", rc); + ok( rc == STATUS_ACCESS_VIOLATION || + rc == STATUS_INVALID_PARAMETER, /* win2k3 */ + "rc = %x not STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER\n", rc); /* * Test to see if the Timeout can be NULL */ + hslot = (HANDLE)0xdeadbeef; rc = pNtCreateMailslotFile(&hslot, DesiredAccess, &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, NULL); - ok( rc == STATUS_SUCCESS, "rc = %x not STATUS_SUCCESS\n", rc); + ok( rc == STATUS_SUCCESS || + rc == STATUS_INVALID_PARAMETER, /* win2k3 */ + "rc = %x not STATUS_SUCCESS or STATUS_INVALID_PARAMETER\n", rc); ok( hslot != 0, "Handle is invalid\n"); if ( rc == STATUS_SUCCESS ) rc = pNtClose(hslot); @@ -451,7 +539,9 @@ static void nt_mailslot_test(void) rc = pNtCreateMailslotFile(&hslot, DesiredAccess, &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, &TimeOut); - ok( rc == STATUS_OBJECT_PATH_SYNTAX_BAD, "rc = %x not c000003b STATUS_OBJECT_PATH_SYNTAX_BAD\n", rc); + ok( rc == STATUS_OBJECT_PATH_SYNTAX_BAD || + rc == STATUS_INVALID_PARAMETER, + "rc = %x not STATUS_OBJECT_PATH_SYNTAX_BAD or STATUS_INVALID_PARAMETER\n", rc); if (rc == STATUS_SUCCESS) pNtClose(hslot); @@ -462,7 +552,7 @@ static void nt_mailslot_test(void) rc = pNtCreateMailslotFile(&hslot, DesiredAccess, &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize, &TimeOut); - ok( rc == STATUS_SUCCESS, "Create MailslotFile failed rc = %x %u\n", rc, GetLastError()); + ok( rc == STATUS_SUCCESS, "Create MailslotFile failed rc = %x\n", rc); ok( hslot != 0, "Handle is invalid\n"); rc = pNtClose(hslot); @@ -526,7 +616,7 @@ static void test_iocp_fileio(HANDLE h) if (hPipeClt != INVALID_HANDLE_VALUE) { OVERLAPPED o = {0,}; - BYTE buf[3]; + BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN]; DWORD read; long count; @@ -534,12 +624,14 @@ static void test_iocp_fileio(HANDLE h) ok( res == STATUS_SUCCESS, "NtSetInformationFile failed: %x\n", res ); ok( U(iosb).Status == STATUS_SUCCESS, "iosb.Status invalid: %x\n", U(iosb).Status ); + memset( send_buf, 0, TEST_BUF_LEN ); + memset( recv_buf, 0xde, TEST_BUF_LEN ); count = get_pending_msgs(h); ok( !count, "Unexpected msg count: %ld\n", count ); - ReadFile( hPipeSrv, buf, 3, &read, &o); + ReadFile( hPipeSrv, recv_buf, TEST_BUF_LEN, &read, &o); count = get_pending_msgs(h); ok( !count, "Unexpected msg count: %ld\n", count ); - WriteFile( hPipeClt, buf, 3, &read, NULL ); + WriteFile( hPipeClt, send_buf, TEST_BUF_LEN, &read, NULL ); if (get_msg(h)) { @@ -547,14 +639,17 @@ static void test_iocp_fileio(HANDLE h) ok( ioSb.Information == 3, "Invalid ioSb.Information: %ld\n", ioSb.Information ); ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status); ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue ); + ok( !memcmp( send_buf, recv_buf, TEST_BUF_LEN ), "Receive buffer (%x %x %x) did not match send buffer (%x %x %x)\n", recv_buf[0], recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2] ); } count = get_pending_msgs(h); ok( !count, "Unexpected msg count: %ld\n", count ); - WriteFile( hPipeClt, buf, 2, &read, NULL ); + memset( send_buf, 0, TEST_BUF_LEN ); + memset( recv_buf, 0xde, TEST_BUF_LEN ); + WriteFile( hPipeClt, send_buf, 2, &read, NULL ); count = get_pending_msgs(h); ok( !count, "Unexpected msg count: %ld\n", count ); - ReadFile( hPipeSrv, buf, 2, &read, &o); + ReadFile( hPipeSrv, recv_buf, 2, &read, &o); count = get_pending_msgs(h); ok( count == 1, "Unexpected msg count: %ld\n", count ); if (get_msg(h)) @@ -563,9 +658,10 @@ static void test_iocp_fileio(HANDLE h) ok( ioSb.Information == 2, "Invalid ioSb.Information: %ld\n", ioSb.Information ); ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status); ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue ); + ok( !memcmp( send_buf, recv_buf, 2 ), "Receive buffer (%x %x) did not match send buffer (%x %x)\n", recv_buf[0], recv_buf[1], send_buf[0], send_buf[1] ); } - ReadFile( hPipeSrv, buf, sizeof(buf), &read, &o); + ReadFile( hPipeSrv, recv_buf, TEST_BUF_LEN, &read, &o); CloseHandle( hPipeSrv ); count = get_pending_msgs(h); ok( count == 1, "Unexpected msg count: %ld\n", count ); @@ -609,8 +705,11 @@ START_TEST(file) return; } + pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); + pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U"); pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); + pNtDeleteFile = (void *)GetProcAddress(hntdll, "NtDeleteFile"); pNtReadFile = (void *)GetProcAddress(hntdll, "NtReadFile"); pNtWriteFile = (void *)GetProcAddress(hntdll, "NtWriteFile"); pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); @@ -621,6 +720,7 @@ START_TEST(file) pNtSetIoCompletion = (void *)GetProcAddress(hntdll, "NtSetIoCompletion"); pNtSetInformationFile = (void *)GetProcAddress(hntdll, "NtSetInformationFile"); + delete_file_test(); read_file_test(); nt_mailslot_test(); test_iocompletion(); diff --git a/rostests/winetests/ntdll/generated.c b/rostests/winetests/ntdll/generated.c index 4818c9e50eb..861d95b62ac 100755 --- a/rostests/winetests/ntdll/generated.c +++ b/rostests/winetests/ntdll/generated.c @@ -1,4 +1,4 @@ -/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* File generated automatically from tools/winapi/tests.dat; do not edit! */ /* This file can be copied, modified and distributed without restriction. */ /* @@ -27,22 +27,14 @@ * Windows API extension */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) -# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) -#elif defined(__GNUC__) -# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) -#else -/* FIXME: Not sure if is possible to do without compiler extension */ -#endif - #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) #elif defined(__GNUC__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* - * FIXME: Not sure if is possible to do without compiler extension - * (if type is not just a name that is, if so the normal) + * FIXME: May not be possible without a compiler extension + * (if type is not just a name that is, otherwise the normal * TYPE_ALIGNMENT can be used) */ #endif @@ -59,392 +51,517 @@ * Test helper macros */ -#ifdef FIELD_ALIGNMENT -# define TEST_FIELD_ALIGNMENT(type, field, align) \ - ok(FIELD_ALIGNMENT(type, field) == align, \ - "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ - (int)FIELD_ALIGNMENT(type, field)) +#ifdef _WIN64 + +# define TEST_TYPE_SIZE(type, size) +# define TEST_TYPE_ALIGN(type, align) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) +# define TEST_FIELD_OFFSET(type, field, offset) + #else -# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) + +# define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); + +# ifdef TYPE_ALIGNMENT +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +#else +# define TEST_TYPE_ALIGN(type, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) \ - ok(FIELD_OFFSET(type, field) == offset, \ - "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ - (long int)FIELD_OFFSET(type, field)) - -#ifdef _TYPE_ALIGNMENT -#define TEST__TYPE_ALIGNMENT(type, align) \ - ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +# ifdef _TYPE_ALIGNMENT +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else -# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) #endif -#ifdef TYPE_ALIGNMENT -#define TEST_TYPE_ALIGNMENT(type, align) \ - ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) -#else -# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); + #endif -#define TEST_TYPE_SIZE(type, size) \ - ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) +#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) +#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) +#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0); +#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0); -/*********************************************************************** - * Test macros - */ - -#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ - TEST_TYPE_SIZE(field_type, field_size); \ - TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ - TEST_FIELD_OFFSET(type, field_name, field_offset); \ - -#define TEST_TYPE(type, size, align) \ - TEST_TYPE_ALIGNMENT(type, align); \ - TEST_TYPE_SIZE(type, size) - -#define TEST_TYPE_POINTER(type, size, align) \ - TEST__TYPE_ALIGNMENT(*(type)0, align); \ - TEST_TYPE_SIZE(*(type)0, size) - -#define TEST_TYPE_SIGNED(type) \ - ok((type) -1 < 0, "(" #type ") -1 < 0\n"); - -#define TEST_TYPE_UNSIGNED(type) \ - ok((type) -1 > 0, "(" #type ") -1 > 0\n"); static void test_pack_DWORD32(void) { /* DWORD32 */ - TEST_TYPE(DWORD32, 4, 4); - TEST_TYPE_UNSIGNED(DWORD32); + TEST_TYPE_SIZE (DWORD32, 4) + TEST_TYPE_ALIGN (DWORD32, 4) + TEST_TYPE_UNSIGNED(DWORD32) } static void test_pack_DWORD64(void) { /* DWORD64 */ - TEST_TYPE(DWORD64, 8, 8); - TEST_TYPE_UNSIGNED(DWORD64); + TEST_TYPE_SIZE (DWORD64, 8) + TEST_TYPE_ALIGN (DWORD64, 8) + TEST_TYPE_UNSIGNED(DWORD64) } static void test_pack_DWORD_PTR(void) { /* DWORD_PTR */ - TEST_TYPE(DWORD_PTR, 4, 4); + TEST_TYPE_SIZE (DWORD_PTR, 4) + TEST_TYPE_ALIGN (DWORD_PTR, 4) } static void test_pack_HALF_PTR(void) { /* HALF_PTR */ - TEST_TYPE(HALF_PTR, 2, 2); - TEST_TYPE_SIGNED(HALF_PTR); + TEST_TYPE_SIZE (HALF_PTR, 2) + TEST_TYPE_ALIGN (HALF_PTR, 2) + TEST_TYPE_SIGNED(HALF_PTR) } static void test_pack_INT16(void) { /* INT16 */ - TEST_TYPE(INT16, 2, 2); - TEST_TYPE_SIGNED(INT16); + TEST_TYPE_SIZE (INT16, 2) + TEST_TYPE_ALIGN (INT16, 2) + TEST_TYPE_SIGNED(INT16) } static void test_pack_INT32(void) { /* INT32 */ - TEST_TYPE(INT32, 4, 4); - TEST_TYPE_SIGNED(INT32); + TEST_TYPE_SIZE (INT32, 4) + TEST_TYPE_ALIGN (INT32, 4) + TEST_TYPE_SIGNED(INT32) } static void test_pack_INT64(void) { /* INT64 */ - TEST_TYPE(INT64, 8, 8); - TEST_TYPE_SIGNED(INT64); + TEST_TYPE_SIZE (INT64, 8) + TEST_TYPE_ALIGN (INT64, 8) + TEST_TYPE_SIGNED(INT64) } static void test_pack_INT8(void) { /* INT8 */ - TEST_TYPE(INT8, 1, 1); - TEST_TYPE_SIGNED(INT8); + TEST_TYPE_SIZE (INT8, 1) + TEST_TYPE_ALIGN (INT8, 1) + TEST_TYPE_SIGNED(INT8) } static void test_pack_INT_PTR(void) { /* INT_PTR */ - TEST_TYPE(INT_PTR, 4, 4); - TEST_TYPE_SIGNED(INT_PTR); + TEST_TYPE_SIZE (INT_PTR, 4) + TEST_TYPE_ALIGN (INT_PTR, 4) + TEST_TYPE_SIGNED(INT_PTR) } static void test_pack_LONG32(void) { /* LONG32 */ - TEST_TYPE(LONG32, 4, 4); - TEST_TYPE_SIGNED(LONG32); + TEST_TYPE_SIZE (LONG32, 4) + TEST_TYPE_ALIGN (LONG32, 4) + TEST_TYPE_SIGNED(LONG32) } static void test_pack_LONG64(void) { /* LONG64 */ - TEST_TYPE(LONG64, 8, 8); - TEST_TYPE_SIGNED(LONG64); + TEST_TYPE_SIZE (LONG64, 8) + TEST_TYPE_ALIGN (LONG64, 8) + TEST_TYPE_SIGNED(LONG64) } static void test_pack_LONG_PTR(void) { /* LONG_PTR */ - TEST_TYPE(LONG_PTR, 4, 4); - TEST_TYPE_SIGNED(LONG_PTR); + TEST_TYPE_SIZE (LONG_PTR, 4) + TEST_TYPE_ALIGN (LONG_PTR, 4) + TEST_TYPE_SIGNED(LONG_PTR) } static void test_pack_SIZE_T(void) { /* SIZE_T */ - TEST_TYPE(SIZE_T, 4, 4); + TEST_TYPE_SIZE (SIZE_T, 4) + TEST_TYPE_ALIGN (SIZE_T, 4) } static void test_pack_SSIZE_T(void) { /* SSIZE_T */ - TEST_TYPE(SSIZE_T, 4, 4); + TEST_TYPE_SIZE (SSIZE_T, 4) + TEST_TYPE_ALIGN (SSIZE_T, 4) } static void test_pack_UHALF_PTR(void) { /* UHALF_PTR */ - TEST_TYPE(UHALF_PTR, 2, 2); - TEST_TYPE_UNSIGNED(UHALF_PTR); + TEST_TYPE_SIZE (UHALF_PTR, 2) + TEST_TYPE_ALIGN (UHALF_PTR, 2) + TEST_TYPE_UNSIGNED(UHALF_PTR) } static void test_pack_UINT16(void) { /* UINT16 */ - TEST_TYPE(UINT16, 2, 2); - TEST_TYPE_UNSIGNED(UINT16); + TEST_TYPE_SIZE (UINT16, 2) + TEST_TYPE_ALIGN (UINT16, 2) + TEST_TYPE_UNSIGNED(UINT16) } static void test_pack_UINT32(void) { /* UINT32 */ - TEST_TYPE(UINT32, 4, 4); - TEST_TYPE_UNSIGNED(UINT32); + TEST_TYPE_SIZE (UINT32, 4) + TEST_TYPE_ALIGN (UINT32, 4) + TEST_TYPE_UNSIGNED(UINT32) } static void test_pack_UINT64(void) { /* UINT64 */ - TEST_TYPE(UINT64, 8, 8); - TEST_TYPE_UNSIGNED(UINT64); + TEST_TYPE_SIZE (UINT64, 8) + TEST_TYPE_ALIGN (UINT64, 8) + TEST_TYPE_UNSIGNED(UINT64) } static void test_pack_UINT8(void) { /* UINT8 */ - TEST_TYPE(UINT8, 1, 1); - TEST_TYPE_UNSIGNED(UINT8); + TEST_TYPE_SIZE (UINT8, 1) + TEST_TYPE_ALIGN (UINT8, 1) + TEST_TYPE_UNSIGNED(UINT8) } static void test_pack_UINT_PTR(void) { /* UINT_PTR */ - TEST_TYPE(UINT_PTR, 4, 4); - TEST_TYPE_UNSIGNED(UINT_PTR); + TEST_TYPE_SIZE (UINT_PTR, 4) + TEST_TYPE_ALIGN (UINT_PTR, 4) + TEST_TYPE_UNSIGNED(UINT_PTR) } static void test_pack_ULONG32(void) { /* ULONG32 */ - TEST_TYPE(ULONG32, 4, 4); - TEST_TYPE_UNSIGNED(ULONG32); + TEST_TYPE_SIZE (ULONG32, 4) + TEST_TYPE_ALIGN (ULONG32, 4) + TEST_TYPE_UNSIGNED(ULONG32) } static void test_pack_ULONG64(void) { /* ULONG64 */ - TEST_TYPE(ULONG64, 8, 8); - TEST_TYPE_UNSIGNED(ULONG64); + TEST_TYPE_SIZE (ULONG64, 8) + TEST_TYPE_ALIGN (ULONG64, 8) + TEST_TYPE_UNSIGNED(ULONG64) } static void test_pack_ULONG_PTR(void) { /* ULONG_PTR */ - TEST_TYPE(ULONG_PTR, 4, 4); - TEST_TYPE_UNSIGNED(ULONG_PTR); + TEST_TYPE_SIZE (ULONG_PTR, 4) + TEST_TYPE_ALIGN (ULONG_PTR, 4) + TEST_TYPE_UNSIGNED(ULONG_PTR) } static void test_pack_ACCESS_ALLOWED_ACE(void) { /* ACCESS_ALLOWED_ACE (pack 4) */ - TEST_TYPE(ACCESS_ALLOWED_ACE, 12, 4); - TEST_FIELD(ACCESS_ALLOWED_ACE, ACE_HEADER, Header, 0, 4, 2); - TEST_FIELD(ACCESS_ALLOWED_ACE, DWORD, Mask, 4, 4, 4); - TEST_FIELD(ACCESS_ALLOWED_ACE, DWORD, SidStart, 8, 4, 4); + TEST_TYPE_SIZE (ACCESS_ALLOWED_ACE, 12) + TEST_TYPE_ALIGN (ACCESS_ALLOWED_ACE, 4) + TEST_FIELD_SIZE (ACCESS_ALLOWED_ACE, Header, 4) + TEST_FIELD_ALIGN (ACCESS_ALLOWED_ACE, Header, 2) + TEST_FIELD_OFFSET(ACCESS_ALLOWED_ACE, Header, 0) + TEST_FIELD_SIZE (ACCESS_ALLOWED_ACE, Mask, 4) + TEST_FIELD_ALIGN (ACCESS_ALLOWED_ACE, Mask, 4) + TEST_FIELD_OFFSET(ACCESS_ALLOWED_ACE, Mask, 4) + TEST_FIELD_SIZE (ACCESS_ALLOWED_ACE, SidStart, 4) + TEST_FIELD_ALIGN (ACCESS_ALLOWED_ACE, SidStart, 4) + TEST_FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart, 8) } static void test_pack_ACCESS_DENIED_ACE(void) { /* ACCESS_DENIED_ACE (pack 4) */ - TEST_TYPE(ACCESS_DENIED_ACE, 12, 4); - TEST_FIELD(ACCESS_DENIED_ACE, ACE_HEADER, Header, 0, 4, 2); - TEST_FIELD(ACCESS_DENIED_ACE, DWORD, Mask, 4, 4, 4); - TEST_FIELD(ACCESS_DENIED_ACE, DWORD, SidStart, 8, 4, 4); + TEST_TYPE_SIZE (ACCESS_DENIED_ACE, 12) + TEST_TYPE_ALIGN (ACCESS_DENIED_ACE, 4) + TEST_FIELD_SIZE (ACCESS_DENIED_ACE, Header, 4) + TEST_FIELD_ALIGN (ACCESS_DENIED_ACE, Header, 2) + TEST_FIELD_OFFSET(ACCESS_DENIED_ACE, Header, 0) + TEST_FIELD_SIZE (ACCESS_DENIED_ACE, Mask, 4) + TEST_FIELD_ALIGN (ACCESS_DENIED_ACE, Mask, 4) + TEST_FIELD_OFFSET(ACCESS_DENIED_ACE, Mask, 4) + TEST_FIELD_SIZE (ACCESS_DENIED_ACE, SidStart, 4) + TEST_FIELD_ALIGN (ACCESS_DENIED_ACE, SidStart, 4) + TEST_FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart, 8) } static void test_pack_ACCESS_MASK(void) { /* ACCESS_MASK */ - TEST_TYPE(ACCESS_MASK, 4, 4); - TEST_TYPE_UNSIGNED(ACCESS_MASK); + TEST_TYPE_SIZE (ACCESS_MASK, 4) + TEST_TYPE_ALIGN (ACCESS_MASK, 4) + TEST_TYPE_UNSIGNED(ACCESS_MASK) } static void test_pack_ACE_HEADER(void) { /* ACE_HEADER (pack 4) */ - TEST_TYPE(ACE_HEADER, 4, 2); - TEST_FIELD(ACE_HEADER, BYTE, AceType, 0, 1, 1); - TEST_FIELD(ACE_HEADER, BYTE, AceFlags, 1, 1, 1); - TEST_FIELD(ACE_HEADER, WORD, AceSize, 2, 2, 2); + TEST_TYPE_SIZE (ACE_HEADER, 4) + TEST_TYPE_ALIGN (ACE_HEADER, 2) + TEST_FIELD_SIZE (ACE_HEADER, AceType, 1) + TEST_FIELD_ALIGN (ACE_HEADER, AceType, 1) + TEST_FIELD_OFFSET(ACE_HEADER, AceType, 0) + TEST_FIELD_SIZE (ACE_HEADER, AceFlags, 1) + TEST_FIELD_ALIGN (ACE_HEADER, AceFlags, 1) + TEST_FIELD_OFFSET(ACE_HEADER, AceFlags, 1) + TEST_FIELD_SIZE (ACE_HEADER, AceSize, 2) + TEST_FIELD_ALIGN (ACE_HEADER, AceSize, 2) + TEST_FIELD_OFFSET(ACE_HEADER, AceSize, 2) } static void test_pack_ACL(void) { /* ACL (pack 4) */ - TEST_TYPE(ACL, 8, 2); - TEST_FIELD(ACL, BYTE, AclRevision, 0, 1, 1); - TEST_FIELD(ACL, BYTE, Sbz1, 1, 1, 1); - TEST_FIELD(ACL, WORD, AclSize, 2, 2, 2); - TEST_FIELD(ACL, WORD, AceCount, 4, 2, 2); - TEST_FIELD(ACL, WORD, Sbz2, 6, 2, 2); + TEST_TYPE_SIZE (ACL, 8) + TEST_TYPE_ALIGN (ACL, 2) + TEST_FIELD_SIZE (ACL, AclRevision, 1) + TEST_FIELD_ALIGN (ACL, AclRevision, 1) + TEST_FIELD_OFFSET(ACL, AclRevision, 0) + TEST_FIELD_SIZE (ACL, Sbz1, 1) + TEST_FIELD_ALIGN (ACL, Sbz1, 1) + TEST_FIELD_OFFSET(ACL, Sbz1, 1) + TEST_FIELD_SIZE (ACL, AclSize, 2) + TEST_FIELD_ALIGN (ACL, AclSize, 2) + TEST_FIELD_OFFSET(ACL, AclSize, 2) + TEST_FIELD_SIZE (ACL, AceCount, 2) + TEST_FIELD_ALIGN (ACL, AceCount, 2) + TEST_FIELD_OFFSET(ACL, AceCount, 4) + TEST_FIELD_SIZE (ACL, Sbz2, 2) + TEST_FIELD_ALIGN (ACL, Sbz2, 2) + TEST_FIELD_OFFSET(ACL, Sbz2, 6) } static void test_pack_ACL_REVISION_INFORMATION(void) { /* ACL_REVISION_INFORMATION (pack 4) */ - TEST_TYPE(ACL_REVISION_INFORMATION, 4, 4); - TEST_FIELD(ACL_REVISION_INFORMATION, DWORD, AclRevision, 0, 4, 4); + TEST_TYPE_SIZE (ACL_REVISION_INFORMATION, 4) + TEST_TYPE_ALIGN (ACL_REVISION_INFORMATION, 4) + TEST_FIELD_SIZE (ACL_REVISION_INFORMATION, AclRevision, 4) + TEST_FIELD_ALIGN (ACL_REVISION_INFORMATION, AclRevision, 4) + TEST_FIELD_OFFSET(ACL_REVISION_INFORMATION, AclRevision, 0) } static void test_pack_ACL_SIZE_INFORMATION(void) { /* ACL_SIZE_INFORMATION (pack 4) */ - TEST_TYPE(ACL_SIZE_INFORMATION, 12, 4); - TEST_FIELD(ACL_SIZE_INFORMATION, DWORD, AceCount, 0, 4, 4); - TEST_FIELD(ACL_SIZE_INFORMATION, DWORD, AclBytesInUse, 4, 4, 4); - TEST_FIELD(ACL_SIZE_INFORMATION, DWORD, AclBytesFree, 8, 4, 4); + TEST_TYPE_SIZE (ACL_SIZE_INFORMATION, 12) + TEST_TYPE_ALIGN (ACL_SIZE_INFORMATION, 4) + TEST_FIELD_SIZE (ACL_SIZE_INFORMATION, AceCount, 4) + TEST_FIELD_ALIGN (ACL_SIZE_INFORMATION, AceCount, 4) + TEST_FIELD_OFFSET(ACL_SIZE_INFORMATION, AceCount, 0) + TEST_FIELD_SIZE (ACL_SIZE_INFORMATION, AclBytesInUse, 4) + TEST_FIELD_ALIGN (ACL_SIZE_INFORMATION, AclBytesInUse, 4) + TEST_FIELD_OFFSET(ACL_SIZE_INFORMATION, AclBytesInUse, 4) + TEST_FIELD_SIZE (ACL_SIZE_INFORMATION, AclBytesFree, 4) + TEST_FIELD_ALIGN (ACL_SIZE_INFORMATION, AclBytesFree, 4) + TEST_FIELD_OFFSET(ACL_SIZE_INFORMATION, AclBytesFree, 8) } static void test_pack_BOOLEAN(void) { /* BOOLEAN */ - TEST_TYPE(BOOLEAN, 1, 1); - TEST_TYPE_UNSIGNED(BOOLEAN); + TEST_TYPE_SIZE (BOOLEAN, 1) + TEST_TYPE_ALIGN (BOOLEAN, 1) + TEST_TYPE_UNSIGNED(BOOLEAN) } static void test_pack_CCHAR(void) { /* CCHAR */ - TEST_TYPE(CCHAR, 1, 1); - TEST_TYPE_SIGNED(CCHAR); + TEST_TYPE_SIZE (CCHAR, 1) + TEST_TYPE_ALIGN (CCHAR, 1) + TEST_TYPE_SIGNED(CCHAR) } static void test_pack_CHAR(void) { /* CHAR */ - TEST_TYPE(CHAR, 1, 1); - TEST_TYPE_SIGNED(CHAR); + TEST_TYPE_SIZE (CHAR, 1) + TEST_TYPE_ALIGN (CHAR, 1) + TEST_TYPE_SIGNED(CHAR) } static void test_pack_DWORDLONG(void) { /* DWORDLONG */ - TEST_TYPE(DWORDLONG, 8, 8); - TEST_TYPE_UNSIGNED(DWORDLONG); + TEST_TYPE_SIZE (DWORDLONG, 8) + TEST_TYPE_ALIGN (DWORDLONG, 8) + TEST_TYPE_UNSIGNED(DWORDLONG) } static void test_pack_EXCEPTION_POINTERS(void) { /* EXCEPTION_POINTERS (pack 4) */ - TEST_TYPE(EXCEPTION_POINTERS, 8, 4); - TEST_FIELD(EXCEPTION_POINTERS, PEXCEPTION_RECORD, ExceptionRecord, 0, 4, 4); - TEST_FIELD(EXCEPTION_POINTERS, PCONTEXT, ContextRecord, 4, 4, 4); + TEST_TYPE_SIZE (EXCEPTION_POINTERS, 8) + TEST_TYPE_ALIGN (EXCEPTION_POINTERS, 4) + TEST_FIELD_SIZE (EXCEPTION_POINTERS, ExceptionRecord, 4) + TEST_FIELD_ALIGN (EXCEPTION_POINTERS, ExceptionRecord, 4) + TEST_FIELD_OFFSET(EXCEPTION_POINTERS, ExceptionRecord, 0) + TEST_FIELD_SIZE (EXCEPTION_POINTERS, ContextRecord, 4) + TEST_FIELD_ALIGN (EXCEPTION_POINTERS, ContextRecord, 4) + TEST_FIELD_OFFSET(EXCEPTION_POINTERS, ContextRecord, 4) } static void test_pack_EXCEPTION_RECORD(void) { /* EXCEPTION_RECORD (pack 4) */ - TEST_TYPE(EXCEPTION_RECORD, 80, 4); - TEST_FIELD(EXCEPTION_RECORD, DWORD, ExceptionCode, 0, 4, 4); - TEST_FIELD(EXCEPTION_RECORD, DWORD, ExceptionFlags, 4, 4, 4); - TEST_FIELD(EXCEPTION_RECORD, struct _EXCEPTION_RECORD *, ExceptionRecord, 8, 4, 4); - TEST_FIELD(EXCEPTION_RECORD, PVOID, ExceptionAddress, 12, 4, 4); - TEST_FIELD(EXCEPTION_RECORD, DWORD, NumberParameters, 16, 4, 4); - TEST_FIELD(EXCEPTION_RECORD, ULONG_PTR[EXCEPTION_MAXIMUM_PARAMETERS], ExceptionInformation, 20, 60, 4); + TEST_TYPE_SIZE (EXCEPTION_RECORD, 80) + TEST_TYPE_ALIGN (EXCEPTION_RECORD, 4) + TEST_FIELD_SIZE (EXCEPTION_RECORD, ExceptionCode, 4) + TEST_FIELD_ALIGN (EXCEPTION_RECORD, ExceptionCode, 4) + TEST_FIELD_OFFSET(EXCEPTION_RECORD, ExceptionCode, 0) + TEST_FIELD_SIZE (EXCEPTION_RECORD, ExceptionFlags, 4) + TEST_FIELD_ALIGN (EXCEPTION_RECORD, ExceptionFlags, 4) + TEST_FIELD_OFFSET(EXCEPTION_RECORD, ExceptionFlags, 4) + TEST_FIELD_SIZE (EXCEPTION_RECORD, ExceptionRecord, 4) + TEST_FIELD_ALIGN (EXCEPTION_RECORD, ExceptionRecord, 4) + TEST_FIELD_OFFSET(EXCEPTION_RECORD, ExceptionRecord, 8) + TEST_FIELD_SIZE (EXCEPTION_RECORD, ExceptionAddress, 4) + TEST_FIELD_ALIGN (EXCEPTION_RECORD, ExceptionAddress, 4) + TEST_FIELD_OFFSET(EXCEPTION_RECORD, ExceptionAddress, 12) + TEST_FIELD_SIZE (EXCEPTION_RECORD, NumberParameters, 4) + TEST_FIELD_ALIGN (EXCEPTION_RECORD, NumberParameters, 4) + TEST_FIELD_OFFSET(EXCEPTION_RECORD, NumberParameters, 16) + TEST_FIELD_SIZE (EXCEPTION_RECORD, ExceptionInformation, 60) + TEST_FIELD_ALIGN (EXCEPTION_RECORD, ExceptionInformation, 4) + TEST_FIELD_OFFSET(EXCEPTION_RECORD, ExceptionInformation, 20) } static void test_pack_EXECUTION_STATE(void) { /* EXECUTION_STATE */ - TEST_TYPE(EXECUTION_STATE, 4, 4); - TEST_TYPE_UNSIGNED(EXECUTION_STATE); + TEST_TYPE_SIZE (EXECUTION_STATE, 4) + TEST_TYPE_ALIGN (EXECUTION_STATE, 4) + TEST_TYPE_UNSIGNED(EXECUTION_STATE) } static void test_pack_FLOATING_SAVE_AREA(void) { /* FLOATING_SAVE_AREA (pack 4) */ - TEST_TYPE(FLOATING_SAVE_AREA, 112, 4); - TEST_FIELD(FLOATING_SAVE_AREA, DWORD, ControlWord, 0, 4, 4); - TEST_FIELD(FLOATING_SAVE_AREA, DWORD, StatusWord, 4, 4, 4); - TEST_FIELD(FLOATING_SAVE_AREA, DWORD, TagWord, 8, 4, 4); - TEST_FIELD(FLOATING_SAVE_AREA, DWORD, ErrorOffset, 12, 4, 4); - TEST_FIELD(FLOATING_SAVE_AREA, DWORD, ErrorSelector, 16, 4, 4); - TEST_FIELD(FLOATING_SAVE_AREA, DWORD, DataOffset, 20, 4, 4); - TEST_FIELD(FLOATING_SAVE_AREA, DWORD, DataSelector, 24, 4, 4); - TEST_FIELD(FLOATING_SAVE_AREA, BYTE[SIZE_OF_80387_REGISTERS], RegisterArea, 28, 80, 1); - TEST_FIELD(FLOATING_SAVE_AREA, DWORD, Cr0NpxState, 108, 4, 4); + TEST_TYPE_SIZE (FLOATING_SAVE_AREA, 112) + TEST_TYPE_ALIGN (FLOATING_SAVE_AREA, 4) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, ControlWord, 4) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, ControlWord, 4) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, ControlWord, 0) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, StatusWord, 4) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, StatusWord, 4) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, StatusWord, 4) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, TagWord, 4) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, TagWord, 4) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, TagWord, 8) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, ErrorOffset, 4) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, ErrorOffset, 4) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, ErrorOffset, 12) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, ErrorSelector, 4) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, ErrorSelector, 4) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, ErrorSelector, 16) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, DataOffset, 4) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, DataOffset, 4) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, DataOffset, 20) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, DataSelector, 4) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, DataSelector, 4) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, DataSelector, 24) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, RegisterArea, 80) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, RegisterArea, 1) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, RegisterArea, 28) + TEST_FIELD_SIZE (FLOATING_SAVE_AREA, Cr0NpxState, 4) + TEST_FIELD_ALIGN (FLOATING_SAVE_AREA, Cr0NpxState, 4) + TEST_FIELD_OFFSET(FLOATING_SAVE_AREA, Cr0NpxState, 108) } static void test_pack_FPO_DATA(void) { /* FPO_DATA (pack 4) */ - TEST_TYPE(FPO_DATA, 16, 4); - TEST_FIELD(FPO_DATA, DWORD, ulOffStart, 0, 4, 4); - TEST_FIELD(FPO_DATA, DWORD, cbProcSize, 4, 4, 4); - TEST_FIELD(FPO_DATA, DWORD, cdwLocals, 8, 4, 4); - TEST_FIELD(FPO_DATA, WORD, cdwParams, 12, 2, 2); + TEST_TYPE_SIZE (FPO_DATA, 16) + TEST_TYPE_ALIGN (FPO_DATA, 4) + TEST_FIELD_SIZE (FPO_DATA, ulOffStart, 4) + TEST_FIELD_ALIGN (FPO_DATA, ulOffStart, 4) + TEST_FIELD_OFFSET(FPO_DATA, ulOffStart, 0) + TEST_FIELD_SIZE (FPO_DATA, cbProcSize, 4) + TEST_FIELD_ALIGN (FPO_DATA, cbProcSize, 4) + TEST_FIELD_OFFSET(FPO_DATA, cbProcSize, 4) + TEST_FIELD_SIZE (FPO_DATA, cdwLocals, 4) + TEST_FIELD_ALIGN (FPO_DATA, cdwLocals, 4) + TEST_FIELD_OFFSET(FPO_DATA, cdwLocals, 8) + TEST_FIELD_SIZE (FPO_DATA, cdwParams, 2) + TEST_FIELD_ALIGN (FPO_DATA, cdwParams, 2) + TEST_FIELD_OFFSET(FPO_DATA, cdwParams, 12) } static void test_pack_GENERIC_MAPPING(void) { /* GENERIC_MAPPING (pack 4) */ - TEST_TYPE(GENERIC_MAPPING, 16, 4); - TEST_FIELD(GENERIC_MAPPING, ACCESS_MASK, GenericRead, 0, 4, 4); - TEST_FIELD(GENERIC_MAPPING, ACCESS_MASK, GenericWrite, 4, 4, 4); - TEST_FIELD(GENERIC_MAPPING, ACCESS_MASK, GenericExecute, 8, 4, 4); - TEST_FIELD(GENERIC_MAPPING, ACCESS_MASK, GenericAll, 12, 4, 4); + TEST_TYPE_SIZE (GENERIC_MAPPING, 16) + TEST_TYPE_ALIGN (GENERIC_MAPPING, 4) + TEST_FIELD_SIZE (GENERIC_MAPPING, GenericRead, 4) + TEST_FIELD_ALIGN (GENERIC_MAPPING, GenericRead, 4) + TEST_FIELD_OFFSET(GENERIC_MAPPING, GenericRead, 0) + TEST_FIELD_SIZE (GENERIC_MAPPING, GenericWrite, 4) + TEST_FIELD_ALIGN (GENERIC_MAPPING, GenericWrite, 4) + TEST_FIELD_OFFSET(GENERIC_MAPPING, GenericWrite, 4) + TEST_FIELD_SIZE (GENERIC_MAPPING, GenericExecute, 4) + TEST_FIELD_ALIGN (GENERIC_MAPPING, GenericExecute, 4) + TEST_FIELD_OFFSET(GENERIC_MAPPING, GenericExecute, 8) + TEST_FIELD_SIZE (GENERIC_MAPPING, GenericAll, 4) + TEST_FIELD_ALIGN (GENERIC_MAPPING, GenericAll, 4) + TEST_FIELD_OFFSET(GENERIC_MAPPING, GenericAll, 12) } static void test_pack_HANDLE(void) { /* HANDLE */ - TEST_TYPE(HANDLE, 4, 4); + TEST_TYPE_SIZE (HANDLE, 4) + TEST_TYPE_ALIGN (HANDLE, 4) } static void test_pack_HRESULT(void) { /* HRESULT */ - TEST_TYPE(HRESULT, 4, 4); + TEST_TYPE_SIZE (HRESULT, 4) + TEST_TYPE_ALIGN (HRESULT, 4) } static void test_pack_IMAGE_ARCHIVE_MEMBER_HEADER(void) { /* IMAGE_ARCHIVE_MEMBER_HEADER (pack 4) */ - TEST_TYPE(IMAGE_ARCHIVE_MEMBER_HEADER, 60, 1); - TEST_FIELD(IMAGE_ARCHIVE_MEMBER_HEADER, BYTE[16], Name, 0, 16, 1); - TEST_FIELD(IMAGE_ARCHIVE_MEMBER_HEADER, BYTE[12], Date, 16, 12, 1); - TEST_FIELD(IMAGE_ARCHIVE_MEMBER_HEADER, BYTE[6], UserID, 28, 6, 1); - TEST_FIELD(IMAGE_ARCHIVE_MEMBER_HEADER, BYTE[6], GroupID, 34, 6, 1); - TEST_FIELD(IMAGE_ARCHIVE_MEMBER_HEADER, BYTE[8], Mode, 40, 8, 1); - TEST_FIELD(IMAGE_ARCHIVE_MEMBER_HEADER, BYTE[10], Size, 48, 10, 1); - TEST_FIELD(IMAGE_ARCHIVE_MEMBER_HEADER, BYTE[2], EndHeader, 58, 2, 1); + TEST_TYPE_SIZE (IMAGE_ARCHIVE_MEMBER_HEADER, 60) + TEST_TYPE_ALIGN (IMAGE_ARCHIVE_MEMBER_HEADER, 1) + TEST_FIELD_SIZE (IMAGE_ARCHIVE_MEMBER_HEADER, Name, 16) + TEST_FIELD_ALIGN (IMAGE_ARCHIVE_MEMBER_HEADER, Name, 1) + TEST_FIELD_OFFSET(IMAGE_ARCHIVE_MEMBER_HEADER, Name, 0) + TEST_FIELD_SIZE (IMAGE_ARCHIVE_MEMBER_HEADER, Date, 12) + TEST_FIELD_ALIGN (IMAGE_ARCHIVE_MEMBER_HEADER, Date, 1) + TEST_FIELD_OFFSET(IMAGE_ARCHIVE_MEMBER_HEADER, Date, 16) + TEST_FIELD_SIZE (IMAGE_ARCHIVE_MEMBER_HEADER, UserID, 6) + TEST_FIELD_ALIGN (IMAGE_ARCHIVE_MEMBER_HEADER, UserID, 1) + TEST_FIELD_OFFSET(IMAGE_ARCHIVE_MEMBER_HEADER, UserID, 28) + TEST_FIELD_SIZE (IMAGE_ARCHIVE_MEMBER_HEADER, GroupID, 6) + TEST_FIELD_ALIGN (IMAGE_ARCHIVE_MEMBER_HEADER, GroupID, 1) + TEST_FIELD_OFFSET(IMAGE_ARCHIVE_MEMBER_HEADER, GroupID, 34) + TEST_FIELD_SIZE (IMAGE_ARCHIVE_MEMBER_HEADER, Mode, 8) + TEST_FIELD_ALIGN (IMAGE_ARCHIVE_MEMBER_HEADER, Mode, 1) + TEST_FIELD_OFFSET(IMAGE_ARCHIVE_MEMBER_HEADER, Mode, 40) + TEST_FIELD_SIZE (IMAGE_ARCHIVE_MEMBER_HEADER, Size, 10) + TEST_FIELD_ALIGN (IMAGE_ARCHIVE_MEMBER_HEADER, Size, 1) + TEST_FIELD_OFFSET(IMAGE_ARCHIVE_MEMBER_HEADER, Size, 48) + TEST_FIELD_SIZE (IMAGE_ARCHIVE_MEMBER_HEADER, EndHeader, 2) + TEST_FIELD_ALIGN (IMAGE_ARCHIVE_MEMBER_HEADER, EndHeader, 1) + TEST_FIELD_OFFSET(IMAGE_ARCHIVE_MEMBER_HEADER, EndHeader, 58) } static void test_pack_IMAGE_AUX_SYMBOL(void) @@ -455,146 +572,304 @@ static void test_pack_IMAGE_AUX_SYMBOL(void) static void test_pack_IMAGE_BASE_RELOCATION(void) { /* IMAGE_BASE_RELOCATION (pack 4) */ - TEST_TYPE(IMAGE_BASE_RELOCATION, 8, 4); - TEST_FIELD(IMAGE_BASE_RELOCATION, DWORD, VirtualAddress, 0, 4, 4); - TEST_FIELD(IMAGE_BASE_RELOCATION, DWORD, SizeOfBlock, 4, 4, 4); + TEST_TYPE_SIZE (IMAGE_BASE_RELOCATION, 8) + TEST_TYPE_ALIGN (IMAGE_BASE_RELOCATION, 4) + TEST_FIELD_SIZE (IMAGE_BASE_RELOCATION, VirtualAddress, 4) + TEST_FIELD_ALIGN (IMAGE_BASE_RELOCATION, VirtualAddress, 4) + TEST_FIELD_OFFSET(IMAGE_BASE_RELOCATION, VirtualAddress, 0) + TEST_FIELD_SIZE (IMAGE_BASE_RELOCATION, SizeOfBlock, 4) + TEST_FIELD_ALIGN (IMAGE_BASE_RELOCATION, SizeOfBlock, 4) + TEST_FIELD_OFFSET(IMAGE_BASE_RELOCATION, SizeOfBlock, 4) } static void test_pack_IMAGE_BOUND_FORWARDER_REF(void) { /* IMAGE_BOUND_FORWARDER_REF (pack 4) */ - TEST_TYPE(IMAGE_BOUND_FORWARDER_REF, 8, 4); - TEST_FIELD(IMAGE_BOUND_FORWARDER_REF, DWORD, TimeDateStamp, 0, 4, 4); - TEST_FIELD(IMAGE_BOUND_FORWARDER_REF, WORD, OffsetModuleName, 4, 2, 2); - TEST_FIELD(IMAGE_BOUND_FORWARDER_REF, WORD, Reserved, 6, 2, 2); + TEST_TYPE_SIZE (IMAGE_BOUND_FORWARDER_REF, 8) + TEST_TYPE_ALIGN (IMAGE_BOUND_FORWARDER_REF, 4) + TEST_FIELD_SIZE (IMAGE_BOUND_FORWARDER_REF, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_BOUND_FORWARDER_REF, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_BOUND_FORWARDER_REF, TimeDateStamp, 0) + TEST_FIELD_SIZE (IMAGE_BOUND_FORWARDER_REF, OffsetModuleName, 2) + TEST_FIELD_ALIGN (IMAGE_BOUND_FORWARDER_REF, OffsetModuleName, 2) + TEST_FIELD_OFFSET(IMAGE_BOUND_FORWARDER_REF, OffsetModuleName, 4) + TEST_FIELD_SIZE (IMAGE_BOUND_FORWARDER_REF, Reserved, 2) + TEST_FIELD_ALIGN (IMAGE_BOUND_FORWARDER_REF, Reserved, 2) + TEST_FIELD_OFFSET(IMAGE_BOUND_FORWARDER_REF, Reserved, 6) } static void test_pack_IMAGE_BOUND_IMPORT_DESCRIPTOR(void) { /* IMAGE_BOUND_IMPORT_DESCRIPTOR (pack 4) */ - TEST_TYPE(IMAGE_BOUND_IMPORT_DESCRIPTOR, 8, 4); - TEST_FIELD(IMAGE_BOUND_IMPORT_DESCRIPTOR, DWORD, TimeDateStamp, 0, 4, 4); - TEST_FIELD(IMAGE_BOUND_IMPORT_DESCRIPTOR, WORD, OffsetModuleName, 4, 2, 2); - TEST_FIELD(IMAGE_BOUND_IMPORT_DESCRIPTOR, WORD, NumberOfModuleForwarderRefs, 6, 2, 2); + TEST_TYPE_SIZE (IMAGE_BOUND_IMPORT_DESCRIPTOR, 8) + TEST_TYPE_ALIGN (IMAGE_BOUND_IMPORT_DESCRIPTOR, 4) + TEST_FIELD_SIZE (IMAGE_BOUND_IMPORT_DESCRIPTOR, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_BOUND_IMPORT_DESCRIPTOR, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_BOUND_IMPORT_DESCRIPTOR, TimeDateStamp, 0) + TEST_FIELD_SIZE (IMAGE_BOUND_IMPORT_DESCRIPTOR, OffsetModuleName, 2) + TEST_FIELD_ALIGN (IMAGE_BOUND_IMPORT_DESCRIPTOR, OffsetModuleName, 2) + TEST_FIELD_OFFSET(IMAGE_BOUND_IMPORT_DESCRIPTOR, OffsetModuleName, 4) + TEST_FIELD_SIZE (IMAGE_BOUND_IMPORT_DESCRIPTOR, NumberOfModuleForwarderRefs, 2) + TEST_FIELD_ALIGN (IMAGE_BOUND_IMPORT_DESCRIPTOR, NumberOfModuleForwarderRefs, 2) + TEST_FIELD_OFFSET(IMAGE_BOUND_IMPORT_DESCRIPTOR, NumberOfModuleForwarderRefs, 6) } static void test_pack_IMAGE_COFF_SYMBOLS_HEADER(void) { /* IMAGE_COFF_SYMBOLS_HEADER (pack 4) */ - TEST_TYPE(IMAGE_COFF_SYMBOLS_HEADER, 32, 4); - TEST_FIELD(IMAGE_COFF_SYMBOLS_HEADER, DWORD, NumberOfSymbols, 0, 4, 4); - TEST_FIELD(IMAGE_COFF_SYMBOLS_HEADER, DWORD, LvaToFirstSymbol, 4, 4, 4); - TEST_FIELD(IMAGE_COFF_SYMBOLS_HEADER, DWORD, NumberOfLinenumbers, 8, 4, 4); - TEST_FIELD(IMAGE_COFF_SYMBOLS_HEADER, DWORD, LvaToFirstLinenumber, 12, 4, 4); - TEST_FIELD(IMAGE_COFF_SYMBOLS_HEADER, DWORD, RvaToFirstByteOfCode, 16, 4, 4); - TEST_FIELD(IMAGE_COFF_SYMBOLS_HEADER, DWORD, RvaToLastByteOfCode, 20, 4, 4); - TEST_FIELD(IMAGE_COFF_SYMBOLS_HEADER, DWORD, RvaToFirstByteOfData, 24, 4, 4); - TEST_FIELD(IMAGE_COFF_SYMBOLS_HEADER, DWORD, RvaToLastByteOfData, 28, 4, 4); + TEST_TYPE_SIZE (IMAGE_COFF_SYMBOLS_HEADER, 32) + TEST_TYPE_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, 4) + TEST_FIELD_SIZE (IMAGE_COFF_SYMBOLS_HEADER, NumberOfSymbols, 4) + TEST_FIELD_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, NumberOfSymbols, 4) + TEST_FIELD_OFFSET(IMAGE_COFF_SYMBOLS_HEADER, NumberOfSymbols, 0) + TEST_FIELD_SIZE (IMAGE_COFF_SYMBOLS_HEADER, LvaToFirstSymbol, 4) + TEST_FIELD_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, LvaToFirstSymbol, 4) + TEST_FIELD_OFFSET(IMAGE_COFF_SYMBOLS_HEADER, LvaToFirstSymbol, 4) + TEST_FIELD_SIZE (IMAGE_COFF_SYMBOLS_HEADER, NumberOfLinenumbers, 4) + TEST_FIELD_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, NumberOfLinenumbers, 4) + TEST_FIELD_OFFSET(IMAGE_COFF_SYMBOLS_HEADER, NumberOfLinenumbers, 8) + TEST_FIELD_SIZE (IMAGE_COFF_SYMBOLS_HEADER, LvaToFirstLinenumber, 4) + TEST_FIELD_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, LvaToFirstLinenumber, 4) + TEST_FIELD_OFFSET(IMAGE_COFF_SYMBOLS_HEADER, LvaToFirstLinenumber, 12) + TEST_FIELD_SIZE (IMAGE_COFF_SYMBOLS_HEADER, RvaToFirstByteOfCode, 4) + TEST_FIELD_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, RvaToFirstByteOfCode, 4) + TEST_FIELD_OFFSET(IMAGE_COFF_SYMBOLS_HEADER, RvaToFirstByteOfCode, 16) + TEST_FIELD_SIZE (IMAGE_COFF_SYMBOLS_HEADER, RvaToLastByteOfCode, 4) + TEST_FIELD_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, RvaToLastByteOfCode, 4) + TEST_FIELD_OFFSET(IMAGE_COFF_SYMBOLS_HEADER, RvaToLastByteOfCode, 20) + TEST_FIELD_SIZE (IMAGE_COFF_SYMBOLS_HEADER, RvaToFirstByteOfData, 4) + TEST_FIELD_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, RvaToFirstByteOfData, 4) + TEST_FIELD_OFFSET(IMAGE_COFF_SYMBOLS_HEADER, RvaToFirstByteOfData, 24) + TEST_FIELD_SIZE (IMAGE_COFF_SYMBOLS_HEADER, RvaToLastByteOfData, 4) + TEST_FIELD_ALIGN (IMAGE_COFF_SYMBOLS_HEADER, RvaToLastByteOfData, 4) + TEST_FIELD_OFFSET(IMAGE_COFF_SYMBOLS_HEADER, RvaToLastByteOfData, 28) } static void test_pack_IMAGE_DATA_DIRECTORY(void) { /* IMAGE_DATA_DIRECTORY (pack 4) */ - TEST_TYPE(IMAGE_DATA_DIRECTORY, 8, 4); - TEST_FIELD(IMAGE_DATA_DIRECTORY, DWORD, VirtualAddress, 0, 4, 4); - TEST_FIELD(IMAGE_DATA_DIRECTORY, DWORD, Size, 4, 4, 4); + TEST_TYPE_SIZE (IMAGE_DATA_DIRECTORY, 8) + TEST_TYPE_ALIGN (IMAGE_DATA_DIRECTORY, 4) + TEST_FIELD_SIZE (IMAGE_DATA_DIRECTORY, VirtualAddress, 4) + TEST_FIELD_ALIGN (IMAGE_DATA_DIRECTORY, VirtualAddress, 4) + TEST_FIELD_OFFSET(IMAGE_DATA_DIRECTORY, VirtualAddress, 0) + TEST_FIELD_SIZE (IMAGE_DATA_DIRECTORY, Size, 4) + TEST_FIELD_ALIGN (IMAGE_DATA_DIRECTORY, Size, 4) + TEST_FIELD_OFFSET(IMAGE_DATA_DIRECTORY, Size, 4) } static void test_pack_IMAGE_DEBUG_DIRECTORY(void) { /* IMAGE_DEBUG_DIRECTORY (pack 4) */ - TEST_TYPE(IMAGE_DEBUG_DIRECTORY, 28, 4); - TEST_FIELD(IMAGE_DEBUG_DIRECTORY, DWORD, Characteristics, 0, 4, 4); - TEST_FIELD(IMAGE_DEBUG_DIRECTORY, DWORD, TimeDateStamp, 4, 4, 4); - TEST_FIELD(IMAGE_DEBUG_DIRECTORY, WORD, MajorVersion, 8, 2, 2); - TEST_FIELD(IMAGE_DEBUG_DIRECTORY, WORD, MinorVersion, 10, 2, 2); - TEST_FIELD(IMAGE_DEBUG_DIRECTORY, DWORD, Type, 12, 4, 4); - TEST_FIELD(IMAGE_DEBUG_DIRECTORY, DWORD, SizeOfData, 16, 4, 4); - TEST_FIELD(IMAGE_DEBUG_DIRECTORY, DWORD, AddressOfRawData, 20, 4, 4); - TEST_FIELD(IMAGE_DEBUG_DIRECTORY, DWORD, PointerToRawData, 24, 4, 4); + TEST_TYPE_SIZE (IMAGE_DEBUG_DIRECTORY, 28) + TEST_TYPE_ALIGN (IMAGE_DEBUG_DIRECTORY, 4) + TEST_FIELD_SIZE (IMAGE_DEBUG_DIRECTORY, Characteristics, 4) + TEST_FIELD_ALIGN (IMAGE_DEBUG_DIRECTORY, Characteristics, 4) + TEST_FIELD_OFFSET(IMAGE_DEBUG_DIRECTORY, Characteristics, 0) + TEST_FIELD_SIZE (IMAGE_DEBUG_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_DEBUG_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_DEBUG_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_DEBUG_DIRECTORY, MajorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_DEBUG_DIRECTORY, MajorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_DEBUG_DIRECTORY, MajorVersion, 8) + TEST_FIELD_SIZE (IMAGE_DEBUG_DIRECTORY, MinorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_DEBUG_DIRECTORY, MinorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_DEBUG_DIRECTORY, MinorVersion, 10) + TEST_FIELD_SIZE (IMAGE_DEBUG_DIRECTORY, Type, 4) + TEST_FIELD_ALIGN (IMAGE_DEBUG_DIRECTORY, Type, 4) + TEST_FIELD_OFFSET(IMAGE_DEBUG_DIRECTORY, Type, 12) + TEST_FIELD_SIZE (IMAGE_DEBUG_DIRECTORY, SizeOfData, 4) + TEST_FIELD_ALIGN (IMAGE_DEBUG_DIRECTORY, SizeOfData, 4) + TEST_FIELD_OFFSET(IMAGE_DEBUG_DIRECTORY, SizeOfData, 16) + TEST_FIELD_SIZE (IMAGE_DEBUG_DIRECTORY, AddressOfRawData, 4) + TEST_FIELD_ALIGN (IMAGE_DEBUG_DIRECTORY, AddressOfRawData, 4) + TEST_FIELD_OFFSET(IMAGE_DEBUG_DIRECTORY, AddressOfRawData, 20) + TEST_FIELD_SIZE (IMAGE_DEBUG_DIRECTORY, PointerToRawData, 4) + TEST_FIELD_ALIGN (IMAGE_DEBUG_DIRECTORY, PointerToRawData, 4) + TEST_FIELD_OFFSET(IMAGE_DEBUG_DIRECTORY, PointerToRawData, 24) } static void test_pack_IMAGE_DEBUG_MISC(void) { /* IMAGE_DEBUG_MISC (pack 4) */ - TEST_TYPE(IMAGE_DEBUG_MISC, 16, 4); - TEST_FIELD(IMAGE_DEBUG_MISC, DWORD, DataType, 0, 4, 4); - TEST_FIELD(IMAGE_DEBUG_MISC, DWORD, Length, 4, 4, 4); - TEST_FIELD(IMAGE_DEBUG_MISC, BYTE, Unicode, 8, 1, 1); - TEST_FIELD(IMAGE_DEBUG_MISC, BYTE[ 3 ], Reserved, 9, 3, 1); - TEST_FIELD(IMAGE_DEBUG_MISC, BYTE[ 1 ], Data, 12, 1, 1); + TEST_TYPE_SIZE (IMAGE_DEBUG_MISC, 16) + TEST_TYPE_ALIGN (IMAGE_DEBUG_MISC, 4) + TEST_FIELD_SIZE (IMAGE_DEBUG_MISC, DataType, 4) + TEST_FIELD_ALIGN (IMAGE_DEBUG_MISC, DataType, 4) + TEST_FIELD_OFFSET(IMAGE_DEBUG_MISC, DataType, 0) + TEST_FIELD_SIZE (IMAGE_DEBUG_MISC, Length, 4) + TEST_FIELD_ALIGN (IMAGE_DEBUG_MISC, Length, 4) + TEST_FIELD_OFFSET(IMAGE_DEBUG_MISC, Length, 4) + TEST_FIELD_SIZE (IMAGE_DEBUG_MISC, Unicode, 1) + TEST_FIELD_ALIGN (IMAGE_DEBUG_MISC, Unicode, 1) + TEST_FIELD_OFFSET(IMAGE_DEBUG_MISC, Unicode, 8) + TEST_FIELD_SIZE (IMAGE_DEBUG_MISC, Reserved, 3) + TEST_FIELD_ALIGN (IMAGE_DEBUG_MISC, Reserved, 1) + TEST_FIELD_OFFSET(IMAGE_DEBUG_MISC, Reserved, 9) + TEST_FIELD_SIZE (IMAGE_DEBUG_MISC, Data, 1) + TEST_FIELD_ALIGN (IMAGE_DEBUG_MISC, Data, 1) + TEST_FIELD_OFFSET(IMAGE_DEBUG_MISC, Data, 12) } static void test_pack_IMAGE_DOS_HEADER(void) { /* IMAGE_DOS_HEADER (pack 2) */ - TEST_TYPE(IMAGE_DOS_HEADER, 64, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_magic, 0, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_cblp, 2, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_cp, 4, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_crlc, 6, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_cparhdr, 8, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_minalloc, 10, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_maxalloc, 12, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_ss, 14, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_sp, 16, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_csum, 18, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_ip, 20, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_cs, 22, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_lfarlc, 24, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_ovno, 26, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD[4], e_res, 28, 8, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_oemid, 36, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD, e_oeminfo, 38, 2, 2); - TEST_FIELD(IMAGE_DOS_HEADER, WORD[10], e_res2, 40, 20, 2); - TEST_FIELD(IMAGE_DOS_HEADER, DWORD, e_lfanew, 60, 4, 2); + TEST_TYPE_SIZE (IMAGE_DOS_HEADER, 64) + TEST_TYPE_ALIGN (IMAGE_DOS_HEADER, 2) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_magic, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_magic, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_magic, 0) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_cblp, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_cblp, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_cblp, 2) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_cp, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_cp, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_cp, 4) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_crlc, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_crlc, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_crlc, 6) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_cparhdr, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_cparhdr, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_cparhdr, 8) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_minalloc, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_minalloc, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_minalloc, 10) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_maxalloc, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_maxalloc, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_maxalloc, 12) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_ss, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_ss, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_ss, 14) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_sp, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_sp, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_sp, 16) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_csum, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_csum, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_csum, 18) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_ip, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_ip, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_ip, 20) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_cs, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_cs, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_cs, 22) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_lfarlc, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_lfarlc, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_lfarlc, 24) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_ovno, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_ovno, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_ovno, 26) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_res, 8) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_res, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_res, 28) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_oemid, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_oemid, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_oemid, 36) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_oeminfo, 2) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_oeminfo, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_oeminfo, 38) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_res2, 20) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_res2, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_res2, 40) + TEST_FIELD_SIZE (IMAGE_DOS_HEADER, e_lfanew, 4) + TEST_FIELD_ALIGN (IMAGE_DOS_HEADER, e_lfanew, 2) + TEST_FIELD_OFFSET(IMAGE_DOS_HEADER, e_lfanew, 60) } static void test_pack_IMAGE_EXPORT_DIRECTORY(void) { /* IMAGE_EXPORT_DIRECTORY (pack 4) */ - TEST_TYPE(IMAGE_EXPORT_DIRECTORY, 40, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, Characteristics, 0, 4, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, TimeDateStamp, 4, 4, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, WORD, MajorVersion, 8, 2, 2); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, WORD, MinorVersion, 10, 2, 2); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, Name, 12, 4, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, Base, 16, 4, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, NumberOfFunctions, 20, 4, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, NumberOfNames, 24, 4, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, AddressOfFunctions, 28, 4, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, AddressOfNames, 32, 4, 4); - TEST_FIELD(IMAGE_EXPORT_DIRECTORY, DWORD, AddressOfNameOrdinals, 36, 4, 4); + TEST_TYPE_SIZE (IMAGE_EXPORT_DIRECTORY, 40) + TEST_TYPE_ALIGN (IMAGE_EXPORT_DIRECTORY, 4) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, Characteristics, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, Characteristics, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, Characteristics, 0) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, MajorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, MajorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, MajorVersion, 8) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, MinorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, MinorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, MinorVersion, 10) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, Name, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, Name, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, Name, 12) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, Base, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, Base, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, Base, 16) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, NumberOfFunctions, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, NumberOfFunctions, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, NumberOfFunctions, 20) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, NumberOfNames, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, NumberOfNames, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, NumberOfNames, 24) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, AddressOfFunctions, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, AddressOfFunctions, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, AddressOfFunctions, 28) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, AddressOfNames, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, AddressOfNames, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, AddressOfNames, 32) + TEST_FIELD_SIZE (IMAGE_EXPORT_DIRECTORY, AddressOfNameOrdinals, 4) + TEST_FIELD_ALIGN (IMAGE_EXPORT_DIRECTORY, AddressOfNameOrdinals, 4) + TEST_FIELD_OFFSET(IMAGE_EXPORT_DIRECTORY, AddressOfNameOrdinals, 36) } static void test_pack_IMAGE_FILE_HEADER(void) { /* IMAGE_FILE_HEADER (pack 4) */ - TEST_TYPE(IMAGE_FILE_HEADER, 20, 4); - TEST_FIELD(IMAGE_FILE_HEADER, WORD, Machine, 0, 2, 2); - TEST_FIELD(IMAGE_FILE_HEADER, WORD, NumberOfSections, 2, 2, 2); - TEST_FIELD(IMAGE_FILE_HEADER, DWORD, TimeDateStamp, 4, 4, 4); - TEST_FIELD(IMAGE_FILE_HEADER, DWORD, PointerToSymbolTable, 8, 4, 4); - TEST_FIELD(IMAGE_FILE_HEADER, DWORD, NumberOfSymbols, 12, 4, 4); - TEST_FIELD(IMAGE_FILE_HEADER, WORD, SizeOfOptionalHeader, 16, 2, 2); - TEST_FIELD(IMAGE_FILE_HEADER, WORD, Characteristics, 18, 2, 2); + TEST_TYPE_SIZE (IMAGE_FILE_HEADER, 20) + TEST_TYPE_ALIGN (IMAGE_FILE_HEADER, 4) + TEST_FIELD_SIZE (IMAGE_FILE_HEADER, Machine, 2) + TEST_FIELD_ALIGN (IMAGE_FILE_HEADER, Machine, 2) + TEST_FIELD_OFFSET(IMAGE_FILE_HEADER, Machine, 0) + TEST_FIELD_SIZE (IMAGE_FILE_HEADER, NumberOfSections, 2) + TEST_FIELD_ALIGN (IMAGE_FILE_HEADER, NumberOfSections, 2) + TEST_FIELD_OFFSET(IMAGE_FILE_HEADER, NumberOfSections, 2) + TEST_FIELD_SIZE (IMAGE_FILE_HEADER, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_FILE_HEADER, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_FILE_HEADER, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_FILE_HEADER, PointerToSymbolTable, 4) + TEST_FIELD_ALIGN (IMAGE_FILE_HEADER, PointerToSymbolTable, 4) + TEST_FIELD_OFFSET(IMAGE_FILE_HEADER, PointerToSymbolTable, 8) + TEST_FIELD_SIZE (IMAGE_FILE_HEADER, NumberOfSymbols, 4) + TEST_FIELD_ALIGN (IMAGE_FILE_HEADER, NumberOfSymbols, 4) + TEST_FIELD_OFFSET(IMAGE_FILE_HEADER, NumberOfSymbols, 12) + TEST_FIELD_SIZE (IMAGE_FILE_HEADER, SizeOfOptionalHeader, 2) + TEST_FIELD_ALIGN (IMAGE_FILE_HEADER, SizeOfOptionalHeader, 2) + TEST_FIELD_OFFSET(IMAGE_FILE_HEADER, SizeOfOptionalHeader, 16) + TEST_FIELD_SIZE (IMAGE_FILE_HEADER, Characteristics, 2) + TEST_FIELD_ALIGN (IMAGE_FILE_HEADER, Characteristics, 2) + TEST_FIELD_OFFSET(IMAGE_FILE_HEADER, Characteristics, 18) } static void test_pack_IMAGE_FUNCTION_ENTRY(void) { /* IMAGE_FUNCTION_ENTRY (pack 4) */ - TEST_TYPE(IMAGE_FUNCTION_ENTRY, 12, 4); - TEST_FIELD(IMAGE_FUNCTION_ENTRY, DWORD, StartingAddress, 0, 4, 4); - TEST_FIELD(IMAGE_FUNCTION_ENTRY, DWORD, EndingAddress, 4, 4, 4); - TEST_FIELD(IMAGE_FUNCTION_ENTRY, DWORD, EndOfPrologue, 8, 4, 4); + TEST_TYPE_SIZE (IMAGE_FUNCTION_ENTRY, 12) + TEST_TYPE_ALIGN (IMAGE_FUNCTION_ENTRY, 4) + TEST_FIELD_SIZE (IMAGE_FUNCTION_ENTRY, StartingAddress, 4) + TEST_FIELD_ALIGN (IMAGE_FUNCTION_ENTRY, StartingAddress, 4) + TEST_FIELD_OFFSET(IMAGE_FUNCTION_ENTRY, StartingAddress, 0) + TEST_FIELD_SIZE (IMAGE_FUNCTION_ENTRY, EndingAddress, 4) + TEST_FIELD_ALIGN (IMAGE_FUNCTION_ENTRY, EndingAddress, 4) + TEST_FIELD_OFFSET(IMAGE_FUNCTION_ENTRY, EndingAddress, 4) + TEST_FIELD_SIZE (IMAGE_FUNCTION_ENTRY, EndOfPrologue, 4) + TEST_FIELD_ALIGN (IMAGE_FUNCTION_ENTRY, EndOfPrologue, 4) + TEST_FIELD_OFFSET(IMAGE_FUNCTION_ENTRY, EndOfPrologue, 8) } static void test_pack_IMAGE_IMPORT_BY_NAME(void) { /* IMAGE_IMPORT_BY_NAME (pack 4) */ - TEST_TYPE(IMAGE_IMPORT_BY_NAME, 4, 2); - TEST_FIELD(IMAGE_IMPORT_BY_NAME, WORD, Hint, 0, 2, 2); - TEST_FIELD(IMAGE_IMPORT_BY_NAME, BYTE[1], Name, 2, 1, 1); + TEST_TYPE_SIZE (IMAGE_IMPORT_BY_NAME, 4) + TEST_TYPE_ALIGN (IMAGE_IMPORT_BY_NAME, 2) + TEST_FIELD_SIZE (IMAGE_IMPORT_BY_NAME, Hint, 2) + TEST_FIELD_ALIGN (IMAGE_IMPORT_BY_NAME, Hint, 2) + TEST_FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Hint, 0) + TEST_FIELD_SIZE (IMAGE_IMPORT_BY_NAME, Name, 1) + TEST_FIELD_ALIGN (IMAGE_IMPORT_BY_NAME, Name, 1) + TEST_FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name, 2) } static void test_pack_IMAGE_IMPORT_DESCRIPTOR(void) @@ -610,69 +885,172 @@ static void test_pack_IMAGE_LINENUMBER(void) static void test_pack_IMAGE_LOAD_CONFIG_DIRECTORY(void) { /* IMAGE_LOAD_CONFIG_DIRECTORY (pack 4) */ - TEST_TYPE(IMAGE_LOAD_CONFIG_DIRECTORY, 72, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, Size, 0, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, TimeDateStamp, 4, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, WORD, MajorVersion, 8, 2, 2); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, WORD, MinorVersion, 10, 2, 2); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, GlobalFlagsClear, 12, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, GlobalFlagsSet, 16, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, CriticalSectionDefaultTimeout, 20, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, DeCommitFreeBlockThreshold, 24, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, DeCommitTotalFreeThreshold, 28, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, PVOID, LockPrefixTable, 32, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, MaximumAllocationSize, 36, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, VirtualMemoryThreshold, 40, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, ProcessHeapFlags, 44, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, ProcessAffinityMask, 48, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, WORD, CSDVersion, 52, 2, 2); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, WORD, Reserved1, 54, 2, 2); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, PVOID, EditList, 56, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, SecurityCookie, 60, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, SEHandlerTable, 64, 4, 4); - TEST_FIELD(IMAGE_LOAD_CONFIG_DIRECTORY, DWORD, SEHandlerCount, 68, 4, 4); + TEST_TYPE_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, 72) + TEST_TYPE_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, 4) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, Size, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, Size, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, Size, 0) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 8) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 10) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 12) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 16) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 20) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 24) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 28) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 32) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 36) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 40) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 44) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 48) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 52) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 54) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 56) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 60) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 64) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 68) } static void test_pack_IMAGE_NT_HEADERS(void) { /* IMAGE_NT_HEADERS */ - TEST_TYPE(IMAGE_NT_HEADERS, 248, 4); + TEST_TYPE_SIZE (IMAGE_NT_HEADERS, 248) + TEST_TYPE_ALIGN (IMAGE_NT_HEADERS, 4) } static void test_pack_IMAGE_OS2_HEADER(void) { /* IMAGE_OS2_HEADER (pack 2) */ - TEST_TYPE(IMAGE_OS2_HEADER, 64, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_magic, 0, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, BYTE, ne_ver, 2, 1, 1); - TEST_FIELD(IMAGE_OS2_HEADER, BYTE, ne_rev, 3, 1, 1); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_enttab, 4, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_cbenttab, 6, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, LONG, ne_crc, 8, 4, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_flags, 12, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_autodata, 14, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_heap, 16, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_stack, 18, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, DWORD, ne_csip, 20, 4, 2); - TEST_FIELD(IMAGE_OS2_HEADER, DWORD, ne_sssp, 24, 4, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_cseg, 28, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_cmod, 30, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_cbnrestab, 32, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_segtab, 34, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_rsrctab, 36, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_restab, 38, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_modtab, 40, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_imptab, 42, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, DWORD, ne_nrestab, 44, 4, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_cmovent, 48, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_align, 50, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_cres, 52, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, BYTE, ne_exetyp, 54, 1, 1); - TEST_FIELD(IMAGE_OS2_HEADER, BYTE, ne_flagsothers, 55, 1, 1); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_pretthunks, 56, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_psegrefbytes, 58, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_swaparea, 60, 2, 2); - TEST_FIELD(IMAGE_OS2_HEADER, WORD, ne_expver, 62, 2, 2); + TEST_TYPE_SIZE (IMAGE_OS2_HEADER, 64) + TEST_TYPE_ALIGN (IMAGE_OS2_HEADER, 2) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_magic, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_magic, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_magic, 0) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_ver, 1) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_ver, 1) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_ver, 2) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_rev, 1) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_rev, 1) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_rev, 3) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_enttab, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_enttab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_enttab, 4) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_cbenttab, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_cbenttab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_cbenttab, 6) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_crc, 4) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_crc, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_crc, 8) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_flags, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_flags, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_flags, 12) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_autodata, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_autodata, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_autodata, 14) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_heap, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_heap, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_heap, 16) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_stack, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_stack, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_stack, 18) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_csip, 4) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_csip, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_csip, 20) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_sssp, 4) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_sssp, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_sssp, 24) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_cseg, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_cseg, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_cseg, 28) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_cmod, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_cmod, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_cmod, 30) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_cbnrestab, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_cbnrestab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_cbnrestab, 32) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_segtab, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_segtab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_segtab, 34) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_rsrctab, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_rsrctab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_rsrctab, 36) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_restab, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_restab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_restab, 38) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_modtab, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_modtab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_modtab, 40) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_imptab, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_imptab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_imptab, 42) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_nrestab, 4) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_nrestab, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_nrestab, 44) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_cmovent, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_cmovent, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_cmovent, 48) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_align, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_align, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_align, 50) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_cres, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_cres, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_cres, 52) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_exetyp, 1) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_exetyp, 1) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_exetyp, 54) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_flagsothers, 1) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_flagsothers, 1) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_flagsothers, 55) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_pretthunks, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_pretthunks, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_pretthunks, 56) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_psegrefbytes, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_psegrefbytes, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_psegrefbytes, 58) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_swaparea, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_swaparea, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_swaparea, 60) + TEST_FIELD_SIZE (IMAGE_OS2_HEADER, ne_expver, 2) + TEST_FIELD_ALIGN (IMAGE_OS2_HEADER, ne_expver, 2) + TEST_FIELD_OFFSET(IMAGE_OS2_HEADER, ne_expver, 62) } static void test_pack_IMAGE_RELOCATION(void) @@ -683,23 +1061,45 @@ static void test_pack_IMAGE_RELOCATION(void) static void test_pack_IMAGE_RESOURCE_DATA_ENTRY(void) { /* IMAGE_RESOURCE_DATA_ENTRY (pack 4) */ - TEST_TYPE(IMAGE_RESOURCE_DATA_ENTRY, 16, 4); - TEST_FIELD(IMAGE_RESOURCE_DATA_ENTRY, DWORD, OffsetToData, 0, 4, 4); - TEST_FIELD(IMAGE_RESOURCE_DATA_ENTRY, DWORD, Size, 4, 4, 4); - TEST_FIELD(IMAGE_RESOURCE_DATA_ENTRY, DWORD, CodePage, 8, 4, 4); - TEST_FIELD(IMAGE_RESOURCE_DATA_ENTRY, DWORD, Reserved, 12, 4, 4); + TEST_TYPE_SIZE (IMAGE_RESOURCE_DATA_ENTRY, 16) + TEST_TYPE_ALIGN (IMAGE_RESOURCE_DATA_ENTRY, 4) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DATA_ENTRY, OffsetToData, 4) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DATA_ENTRY, OffsetToData, 4) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DATA_ENTRY, OffsetToData, 0) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DATA_ENTRY, Size, 4) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DATA_ENTRY, Size, 4) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DATA_ENTRY, Size, 4) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DATA_ENTRY, CodePage, 4) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DATA_ENTRY, CodePage, 4) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DATA_ENTRY, CodePage, 8) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DATA_ENTRY, Reserved, 4) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DATA_ENTRY, Reserved, 4) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DATA_ENTRY, Reserved, 12) } static void test_pack_IMAGE_RESOURCE_DIRECTORY(void) { /* IMAGE_RESOURCE_DIRECTORY (pack 4) */ - TEST_TYPE(IMAGE_RESOURCE_DIRECTORY, 16, 4); - TEST_FIELD(IMAGE_RESOURCE_DIRECTORY, DWORD, Characteristics, 0, 4, 4); - TEST_FIELD(IMAGE_RESOURCE_DIRECTORY, DWORD, TimeDateStamp, 4, 4, 4); - TEST_FIELD(IMAGE_RESOURCE_DIRECTORY, WORD, MajorVersion, 8, 2, 2); - TEST_FIELD(IMAGE_RESOURCE_DIRECTORY, WORD, MinorVersion, 10, 2, 2); - TEST_FIELD(IMAGE_RESOURCE_DIRECTORY, WORD, NumberOfNamedEntries, 12, 2, 2); - TEST_FIELD(IMAGE_RESOURCE_DIRECTORY, WORD, NumberOfIdEntries, 14, 2, 2); + TEST_TYPE_SIZE (IMAGE_RESOURCE_DIRECTORY, 16) + TEST_TYPE_ALIGN (IMAGE_RESOURCE_DIRECTORY, 4) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIRECTORY, Characteristics, 4) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIRECTORY, Characteristics, 4) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIRECTORY, Characteristics, 0) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIRECTORY, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIRECTORY, MajorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIRECTORY, MajorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIRECTORY, MajorVersion, 8) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIRECTORY, MinorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIRECTORY, MinorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIRECTORY, MinorVersion, 10) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIRECTORY, NumberOfNamedEntries, 2) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIRECTORY, NumberOfNamedEntries, 2) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIRECTORY, NumberOfNamedEntries, 12) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIRECTORY, NumberOfIdEntries, 2) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIRECTORY, NumberOfIdEntries, 2) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIRECTORY, NumberOfIdEntries, 14) } static void test_pack_IMAGE_RESOURCE_DIRECTORY_ENTRY(void) @@ -710,42 +1110,81 @@ static void test_pack_IMAGE_RESOURCE_DIRECTORY_ENTRY(void) static void test_pack_IMAGE_RESOURCE_DIRECTORY_STRING(void) { /* IMAGE_RESOURCE_DIRECTORY_STRING (pack 4) */ - TEST_TYPE(IMAGE_RESOURCE_DIRECTORY_STRING, 4, 2); - TEST_FIELD(IMAGE_RESOURCE_DIRECTORY_STRING, WORD, Length, 0, 2, 2); - TEST_FIELD(IMAGE_RESOURCE_DIRECTORY_STRING, CHAR[ 1 ], NameString, 2, 1, 1); + TEST_TYPE_SIZE (IMAGE_RESOURCE_DIRECTORY_STRING, 4) + TEST_TYPE_ALIGN (IMAGE_RESOURCE_DIRECTORY_STRING, 2) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIRECTORY_STRING, Length, 2) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIRECTORY_STRING, Length, 2) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIRECTORY_STRING, Length, 0) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIRECTORY_STRING, NameString, 1) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIRECTORY_STRING, NameString, 1) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIRECTORY_STRING, NameString, 2) } static void test_pack_IMAGE_RESOURCE_DIR_STRING_U(void) { /* IMAGE_RESOURCE_DIR_STRING_U (pack 4) */ - TEST_TYPE(IMAGE_RESOURCE_DIR_STRING_U, 4, 2); - TEST_FIELD(IMAGE_RESOURCE_DIR_STRING_U, WORD, Length, 0, 2, 2); - TEST_FIELD(IMAGE_RESOURCE_DIR_STRING_U, WCHAR[ 1 ], NameString, 2, 2, 2); + TEST_TYPE_SIZE (IMAGE_RESOURCE_DIR_STRING_U, 4) + TEST_TYPE_ALIGN (IMAGE_RESOURCE_DIR_STRING_U, 2) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIR_STRING_U, Length, 2) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIR_STRING_U, Length, 2) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIR_STRING_U, Length, 0) + TEST_FIELD_SIZE (IMAGE_RESOURCE_DIR_STRING_U, NameString, 2) + TEST_FIELD_ALIGN (IMAGE_RESOURCE_DIR_STRING_U, NameString, 2) + TEST_FIELD_OFFSET(IMAGE_RESOURCE_DIR_STRING_U, NameString, 2) } static void test_pack_IMAGE_SECTION_HEADER(void) { /* IMAGE_SECTION_HEADER (pack 4) */ - TEST_FIELD(IMAGE_SECTION_HEADER, BYTE[IMAGE_SIZEOF_SHORT_NAME], Name, 0, 8, 1); + TEST_FIELD_SIZE (IMAGE_SECTION_HEADER, Name, 8) + TEST_FIELD_ALIGN (IMAGE_SECTION_HEADER, Name, 1) + TEST_FIELD_OFFSET(IMAGE_SECTION_HEADER, Name, 0) } static void test_pack_IMAGE_SEPARATE_DEBUG_HEADER(void) { /* IMAGE_SEPARATE_DEBUG_HEADER (pack 4) */ - TEST_TYPE(IMAGE_SEPARATE_DEBUG_HEADER, 48, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, WORD, Signature, 0, 2, 2); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, WORD, Flags, 2, 2, 2); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, WORD, Machine, 4, 2, 2); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, WORD, Characteristics, 6, 2, 2); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD, TimeDateStamp, 8, 4, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD, CheckSum, 12, 4, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD, ImageBase, 16, 4, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD, SizeOfImage, 20, 4, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD, NumberOfSections, 24, 4, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD, ExportedNamesSize, 28, 4, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD, DebugDirectorySize, 32, 4, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD, SectionAlignment, 36, 4, 4); - TEST_FIELD(IMAGE_SEPARATE_DEBUG_HEADER, DWORD[ 2 ], Reserved, 40, 8, 4); + TEST_TYPE_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, 48) + TEST_TYPE_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, 4) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, Signature, 2) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, Signature, 2) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, Signature, 0) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, Flags, 2) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, Flags, 2) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, Flags, 2) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, Machine, 2) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, Machine, 2) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, Machine, 4) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, Characteristics, 2) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, Characteristics, 2) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, Characteristics, 6) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, TimeDateStamp, 8) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, CheckSum, 4) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, CheckSum, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, CheckSum, 12) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, ImageBase, 4) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, ImageBase, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, ImageBase, 16) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, SizeOfImage, 4) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, SizeOfImage, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, SizeOfImage, 20) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, NumberOfSections, 4) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, NumberOfSections, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, NumberOfSections, 24) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, ExportedNamesSize, 4) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, ExportedNamesSize, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, ExportedNamesSize, 28) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, DebugDirectorySize, 4) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, DebugDirectorySize, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, DebugDirectorySize, 32) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, SectionAlignment, 4) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, SectionAlignment, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, SectionAlignment, 36) + TEST_FIELD_SIZE (IMAGE_SEPARATE_DEBUG_HEADER, Reserved, 8) + TEST_FIELD_ALIGN (IMAGE_SEPARATE_DEBUG_HEADER, Reserved, 4) + TEST_FIELD_OFFSET(IMAGE_SEPARATE_DEBUG_HEADER, Reserved, 40) } static void test_pack_IMAGE_SYMBOL(void) @@ -761,83 +1200,201 @@ static void test_pack_IMAGE_THUNK_DATA(void) static void test_pack_IMAGE_TLS_DIRECTORY(void) { /* IMAGE_TLS_DIRECTORY */ - TEST_TYPE(IMAGE_TLS_DIRECTORY, 24, 4); + TEST_TYPE_SIZE (IMAGE_TLS_DIRECTORY, 24) + TEST_TYPE_ALIGN (IMAGE_TLS_DIRECTORY, 4) } static void test_pack_IMAGE_VXD_HEADER(void) { /* IMAGE_VXD_HEADER (pack 2) */ - TEST_TYPE(IMAGE_VXD_HEADER, 196, 2); - TEST_FIELD(IMAGE_VXD_HEADER, WORD, e32_magic, 0, 2, 2); - TEST_FIELD(IMAGE_VXD_HEADER, BYTE, e32_border, 2, 1, 1); - TEST_FIELD(IMAGE_VXD_HEADER, BYTE, e32_worder, 3, 1, 1); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_level, 4, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, WORD, e32_cpu, 8, 2, 2); - TEST_FIELD(IMAGE_VXD_HEADER, WORD, e32_os, 10, 2, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_ver, 12, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_mflags, 16, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_mpages, 20, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_startobj, 24, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_eip, 28, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_stackobj, 32, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_esp, 36, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_pagesize, 40, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_lastpagesize, 44, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_fixupsize, 48, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_fixupsum, 52, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_ldrsize, 56, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_ldrsum, 60, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_objtab, 64, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_objcnt, 68, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_objmap, 72, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_itermap, 76, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_rsrctab, 80, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_rsrccnt, 84, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_restab, 88, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_enttab, 92, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_dirtab, 96, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_dircnt, 100, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_fpagetab, 104, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_frectab, 108, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_impmod, 112, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_impmodcnt, 116, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_impproc, 120, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_pagesum, 124, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_datapage, 128, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_preload, 132, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_nrestab, 136, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_cbnrestab, 140, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_nressum, 144, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_autodata, 148, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_debuginfo, 152, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_debuglen, 156, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_instpreload, 160, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_instdemand, 164, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_heapsize, 168, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, BYTE[12], e32_res3, 172, 12, 1); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_winresoff, 184, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, DWORD, e32_winreslen, 188, 4, 2); - TEST_FIELD(IMAGE_VXD_HEADER, WORD, e32_devid, 192, 2, 2); - TEST_FIELD(IMAGE_VXD_HEADER, WORD, e32_ddkver, 194, 2, 2); + TEST_TYPE_SIZE (IMAGE_VXD_HEADER, 196) + TEST_TYPE_ALIGN (IMAGE_VXD_HEADER, 2) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_magic, 2) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_magic, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_magic, 0) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_border, 1) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_border, 1) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_border, 2) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_worder, 1) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_worder, 1) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_worder, 3) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_level, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_level, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_level, 4) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_cpu, 2) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_cpu, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_cpu, 8) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_os, 2) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_os, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_os, 10) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_ver, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_ver, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_ver, 12) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_mflags, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_mflags, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_mflags, 16) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_mpages, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_mpages, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_mpages, 20) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_startobj, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_startobj, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_startobj, 24) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_eip, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_eip, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_eip, 28) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_stackobj, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_stackobj, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_stackobj, 32) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_esp, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_esp, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_esp, 36) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_pagesize, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_pagesize, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_pagesize, 40) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_lastpagesize, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_lastpagesize, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_lastpagesize, 44) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_fixupsize, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_fixupsize, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_fixupsize, 48) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_fixupsum, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_fixupsum, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_fixupsum, 52) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_ldrsize, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_ldrsize, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_ldrsize, 56) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_ldrsum, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_ldrsum, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_ldrsum, 60) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_objtab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_objtab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_objtab, 64) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_objcnt, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_objcnt, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_objcnt, 68) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_objmap, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_objmap, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_objmap, 72) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_itermap, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_itermap, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_itermap, 76) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_rsrctab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_rsrctab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_rsrctab, 80) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_rsrccnt, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_rsrccnt, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_rsrccnt, 84) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_restab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_restab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_restab, 88) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_enttab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_enttab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_enttab, 92) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_dirtab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_dirtab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_dirtab, 96) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_dircnt, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_dircnt, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_dircnt, 100) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_fpagetab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_fpagetab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_fpagetab, 104) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_frectab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_frectab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_frectab, 108) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_impmod, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_impmod, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_impmod, 112) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_impmodcnt, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_impmodcnt, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_impmodcnt, 116) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_impproc, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_impproc, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_impproc, 120) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_pagesum, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_pagesum, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_pagesum, 124) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_datapage, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_datapage, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_datapage, 128) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_preload, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_preload, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_preload, 132) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_nrestab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_nrestab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_nrestab, 136) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_cbnrestab, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_cbnrestab, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_cbnrestab, 140) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_nressum, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_nressum, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_nressum, 144) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_autodata, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_autodata, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_autodata, 148) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_debuginfo, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_debuginfo, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_debuginfo, 152) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_debuglen, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_debuglen, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_debuglen, 156) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_instpreload, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_instpreload, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_instpreload, 160) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_instdemand, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_instdemand, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_instdemand, 164) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_heapsize, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_heapsize, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_heapsize, 168) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_res3, 12) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_res3, 1) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_res3, 172) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_winresoff, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_winresoff, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_winresoff, 184) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_winreslen, 4) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_winreslen, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_winreslen, 188) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_devid, 2) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_devid, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_devid, 192) + TEST_FIELD_SIZE (IMAGE_VXD_HEADER, e32_ddkver, 2) + TEST_FIELD_ALIGN (IMAGE_VXD_HEADER, e32_ddkver, 2) + TEST_FIELD_OFFSET(IMAGE_VXD_HEADER, e32_ddkver, 194) } static void test_pack_IO_COUNTERS(void) { /* IO_COUNTERS (pack 8) */ - TEST_TYPE(IO_COUNTERS, 48, 8); - TEST_FIELD(IO_COUNTERS, ULONGLONG, ReadOperationCount, 0, 8, 8); - TEST_FIELD(IO_COUNTERS, ULONGLONG, WriteOperationCount, 8, 8, 8); - TEST_FIELD(IO_COUNTERS, ULONGLONG, OtherOperationCount, 16, 8, 8); - TEST_FIELD(IO_COUNTERS, ULONGLONG, ReadTransferCount, 24, 8, 8); - TEST_FIELD(IO_COUNTERS, ULONGLONG, WriteTransferCount, 32, 8, 8); - TEST_FIELD(IO_COUNTERS, ULONGLONG, OtherTransferCount, 40, 8, 8); + TEST_TYPE_SIZE (IO_COUNTERS, 48) + TEST_TYPE_ALIGN (IO_COUNTERS, 8) + TEST_FIELD_SIZE (IO_COUNTERS, ReadOperationCount, 8) + TEST_FIELD_ALIGN (IO_COUNTERS, ReadOperationCount, 8) + TEST_FIELD_OFFSET(IO_COUNTERS, ReadOperationCount, 0) + TEST_FIELD_SIZE (IO_COUNTERS, WriteOperationCount, 8) + TEST_FIELD_ALIGN (IO_COUNTERS, WriteOperationCount, 8) + TEST_FIELD_OFFSET(IO_COUNTERS, WriteOperationCount, 8) + TEST_FIELD_SIZE (IO_COUNTERS, OtherOperationCount, 8) + TEST_FIELD_ALIGN (IO_COUNTERS, OtherOperationCount, 8) + TEST_FIELD_OFFSET(IO_COUNTERS, OtherOperationCount, 16) + TEST_FIELD_SIZE (IO_COUNTERS, ReadTransferCount, 8) + TEST_FIELD_ALIGN (IO_COUNTERS, ReadTransferCount, 8) + TEST_FIELD_OFFSET(IO_COUNTERS, ReadTransferCount, 24) + TEST_FIELD_SIZE (IO_COUNTERS, WriteTransferCount, 8) + TEST_FIELD_ALIGN (IO_COUNTERS, WriteTransferCount, 8) + TEST_FIELD_OFFSET(IO_COUNTERS, WriteTransferCount, 32) + TEST_FIELD_SIZE (IO_COUNTERS, OtherTransferCount, 8) + TEST_FIELD_ALIGN (IO_COUNTERS, OtherTransferCount, 8) + TEST_FIELD_OFFSET(IO_COUNTERS, OtherTransferCount, 40) } static void test_pack_LANGID(void) { /* LANGID */ - TEST_TYPE(LANGID, 2, 2); - TEST_TYPE_UNSIGNED(LANGID); + TEST_TYPE_SIZE (LANGID, 2) + TEST_TYPE_ALIGN (LANGID, 2) + TEST_TYPE_UNSIGNED(LANGID) } static void test_pack_LARGE_INTEGER(void) @@ -848,955 +1405,1361 @@ static void test_pack_LARGE_INTEGER(void) static void test_pack_LCID(void) { /* LCID */ - TEST_TYPE(LCID, 4, 4); - TEST_TYPE_UNSIGNED(LCID); + TEST_TYPE_SIZE (LCID, 4) + TEST_TYPE_ALIGN (LCID, 4) + TEST_TYPE_UNSIGNED(LCID) } static void test_pack_LIST_ENTRY(void) { /* LIST_ENTRY (pack 4) */ - TEST_TYPE(LIST_ENTRY, 8, 4); - TEST_FIELD(LIST_ENTRY, struct _LIST_ENTRY *, Flink, 0, 4, 4); - TEST_FIELD(LIST_ENTRY, struct _LIST_ENTRY *, Blink, 4, 4, 4); + TEST_TYPE_SIZE (LIST_ENTRY, 8) + TEST_TYPE_ALIGN (LIST_ENTRY, 4) + TEST_FIELD_SIZE (LIST_ENTRY, Flink, 4) + TEST_FIELD_ALIGN (LIST_ENTRY, Flink, 4) + TEST_FIELD_OFFSET(LIST_ENTRY, Flink, 0) + TEST_FIELD_SIZE (LIST_ENTRY, Blink, 4) + TEST_FIELD_ALIGN (LIST_ENTRY, Blink, 4) + TEST_FIELD_OFFSET(LIST_ENTRY, Blink, 4) } static void test_pack_LONG(void) { /* LONG */ - TEST_TYPE(LONG, 4, 4); - TEST_TYPE_SIGNED(LONG); + TEST_TYPE_SIZE (LONG, 4) + TEST_TYPE_ALIGN (LONG, 4) + TEST_TYPE_SIGNED(LONG) } static void test_pack_LONGLONG(void) { /* LONGLONG */ - TEST_TYPE(LONGLONG, 8, 8); - TEST_TYPE_SIGNED(LONGLONG); + TEST_TYPE_SIZE (LONGLONG, 8) + TEST_TYPE_ALIGN (LONGLONG, 8) + TEST_TYPE_SIGNED(LONGLONG) } static void test_pack_LUID(void) { /* LUID (pack 4) */ - TEST_TYPE(LUID, 8, 4); - TEST_FIELD(LUID, DWORD, LowPart, 0, 4, 4); - TEST_FIELD(LUID, LONG, HighPart, 4, 4, 4); + TEST_TYPE_SIZE (LUID, 8) + TEST_TYPE_ALIGN (LUID, 4) + TEST_FIELD_SIZE (LUID, LowPart, 4) + TEST_FIELD_ALIGN (LUID, LowPart, 4) + TEST_FIELD_OFFSET(LUID, LowPart, 0) + TEST_FIELD_SIZE (LUID, HighPart, 4) + TEST_FIELD_ALIGN (LUID, HighPart, 4) + TEST_FIELD_OFFSET(LUID, HighPart, 4) } static void test_pack_LUID_AND_ATTRIBUTES(void) { /* LUID_AND_ATTRIBUTES (pack 4) */ - TEST_TYPE(LUID_AND_ATTRIBUTES, 12, 4); - TEST_FIELD(LUID_AND_ATTRIBUTES, LUID, Luid, 0, 8, 4); - TEST_FIELD(LUID_AND_ATTRIBUTES, DWORD, Attributes, 8, 4, 4); + TEST_TYPE_SIZE (LUID_AND_ATTRIBUTES, 12) + TEST_TYPE_ALIGN (LUID_AND_ATTRIBUTES, 4) + TEST_FIELD_SIZE (LUID_AND_ATTRIBUTES, Luid, 8) + TEST_FIELD_ALIGN (LUID_AND_ATTRIBUTES, Luid, 4) + TEST_FIELD_OFFSET(LUID_AND_ATTRIBUTES, Luid, 0) + TEST_FIELD_SIZE (LUID_AND_ATTRIBUTES, Attributes, 4) + TEST_FIELD_ALIGN (LUID_AND_ATTRIBUTES, Attributes, 4) + TEST_FIELD_OFFSET(LUID_AND_ATTRIBUTES, Attributes, 8) } static void test_pack_MEMORY_BASIC_INFORMATION(void) { /* MEMORY_BASIC_INFORMATION (pack 4) */ - TEST_TYPE(MEMORY_BASIC_INFORMATION, 28, 4); - TEST_FIELD(MEMORY_BASIC_INFORMATION, LPVOID, BaseAddress, 0, 4, 4); - TEST_FIELD(MEMORY_BASIC_INFORMATION, LPVOID, AllocationBase, 4, 4, 4); - TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, AllocationProtect, 8, 4, 4); - TEST_FIELD(MEMORY_BASIC_INFORMATION, SIZE_T, RegionSize, 12, 4, 4); - TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, State, 16, 4, 4); - TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, Protect, 20, 4, 4); - TEST_FIELD(MEMORY_BASIC_INFORMATION, DWORD, Type, 24, 4, 4); + TEST_TYPE_SIZE (MEMORY_BASIC_INFORMATION, 28) + TEST_TYPE_ALIGN (MEMORY_BASIC_INFORMATION, 4) + TEST_FIELD_SIZE (MEMORY_BASIC_INFORMATION, BaseAddress, 4) + TEST_FIELD_ALIGN (MEMORY_BASIC_INFORMATION, BaseAddress, 4) + TEST_FIELD_OFFSET(MEMORY_BASIC_INFORMATION, BaseAddress, 0) + TEST_FIELD_SIZE (MEMORY_BASIC_INFORMATION, AllocationBase, 4) + TEST_FIELD_ALIGN (MEMORY_BASIC_INFORMATION, AllocationBase, 4) + TEST_FIELD_OFFSET(MEMORY_BASIC_INFORMATION, AllocationBase, 4) + TEST_FIELD_SIZE (MEMORY_BASIC_INFORMATION, AllocationProtect, 4) + TEST_FIELD_ALIGN (MEMORY_BASIC_INFORMATION, AllocationProtect, 4) + TEST_FIELD_OFFSET(MEMORY_BASIC_INFORMATION, AllocationProtect, 8) + TEST_FIELD_SIZE (MEMORY_BASIC_INFORMATION, RegionSize, 4) + TEST_FIELD_ALIGN (MEMORY_BASIC_INFORMATION, RegionSize, 4) + TEST_FIELD_OFFSET(MEMORY_BASIC_INFORMATION, RegionSize, 12) + TEST_FIELD_SIZE (MEMORY_BASIC_INFORMATION, State, 4) + TEST_FIELD_ALIGN (MEMORY_BASIC_INFORMATION, State, 4) + TEST_FIELD_OFFSET(MEMORY_BASIC_INFORMATION, State, 16) + TEST_FIELD_SIZE (MEMORY_BASIC_INFORMATION, Protect, 4) + TEST_FIELD_ALIGN (MEMORY_BASIC_INFORMATION, Protect, 4) + TEST_FIELD_OFFSET(MEMORY_BASIC_INFORMATION, Protect, 20) + TEST_FIELD_SIZE (MEMORY_BASIC_INFORMATION, Type, 4) + TEST_FIELD_ALIGN (MEMORY_BASIC_INFORMATION, Type, 4) + TEST_FIELD_OFFSET(MEMORY_BASIC_INFORMATION, Type, 24) } static void test_pack_MESSAGE_RESOURCE_BLOCK(void) { /* MESSAGE_RESOURCE_BLOCK (pack 4) */ - TEST_TYPE(MESSAGE_RESOURCE_BLOCK, 12, 4); - TEST_FIELD(MESSAGE_RESOURCE_BLOCK, DWORD, LowId, 0, 4, 4); - TEST_FIELD(MESSAGE_RESOURCE_BLOCK, DWORD, HighId, 4, 4, 4); - TEST_FIELD(MESSAGE_RESOURCE_BLOCK, DWORD, OffsetToEntries, 8, 4, 4); + TEST_TYPE_SIZE (MESSAGE_RESOURCE_BLOCK, 12) + TEST_TYPE_ALIGN (MESSAGE_RESOURCE_BLOCK, 4) + TEST_FIELD_SIZE (MESSAGE_RESOURCE_BLOCK, LowId, 4) + TEST_FIELD_ALIGN (MESSAGE_RESOURCE_BLOCK, LowId, 4) + TEST_FIELD_OFFSET(MESSAGE_RESOURCE_BLOCK, LowId, 0) + TEST_FIELD_SIZE (MESSAGE_RESOURCE_BLOCK, HighId, 4) + TEST_FIELD_ALIGN (MESSAGE_RESOURCE_BLOCK, HighId, 4) + TEST_FIELD_OFFSET(MESSAGE_RESOURCE_BLOCK, HighId, 4) + TEST_FIELD_SIZE (MESSAGE_RESOURCE_BLOCK, OffsetToEntries, 4) + TEST_FIELD_ALIGN (MESSAGE_RESOURCE_BLOCK, OffsetToEntries, 4) + TEST_FIELD_OFFSET(MESSAGE_RESOURCE_BLOCK, OffsetToEntries, 8) } static void test_pack_MESSAGE_RESOURCE_DATA(void) { /* MESSAGE_RESOURCE_DATA (pack 4) */ - TEST_TYPE(MESSAGE_RESOURCE_DATA, 16, 4); - TEST_FIELD(MESSAGE_RESOURCE_DATA, DWORD, NumberOfBlocks, 0, 4, 4); - TEST_FIELD(MESSAGE_RESOURCE_DATA, MESSAGE_RESOURCE_BLOCK[ 1 ], Blocks, 4, 12, 4); + TEST_TYPE_SIZE (MESSAGE_RESOURCE_DATA, 16) + TEST_TYPE_ALIGN (MESSAGE_RESOURCE_DATA, 4) + TEST_FIELD_SIZE (MESSAGE_RESOURCE_DATA, NumberOfBlocks, 4) + TEST_FIELD_ALIGN (MESSAGE_RESOURCE_DATA, NumberOfBlocks, 4) + TEST_FIELD_OFFSET(MESSAGE_RESOURCE_DATA, NumberOfBlocks, 0) + TEST_FIELD_SIZE (MESSAGE_RESOURCE_DATA, Blocks, 12) + TEST_FIELD_ALIGN (MESSAGE_RESOURCE_DATA, Blocks, 4) + TEST_FIELD_OFFSET(MESSAGE_RESOURCE_DATA, Blocks, 4) } static void test_pack_MESSAGE_RESOURCE_ENTRY(void) { /* MESSAGE_RESOURCE_ENTRY (pack 4) */ - TEST_TYPE(MESSAGE_RESOURCE_ENTRY, 6, 2); - TEST_FIELD(MESSAGE_RESOURCE_ENTRY, WORD, Length, 0, 2, 2); - TEST_FIELD(MESSAGE_RESOURCE_ENTRY, WORD, Flags, 2, 2, 2); - TEST_FIELD(MESSAGE_RESOURCE_ENTRY, BYTE[1], Text, 4, 1, 1); + TEST_TYPE_SIZE (MESSAGE_RESOURCE_ENTRY, 6) + TEST_TYPE_ALIGN (MESSAGE_RESOURCE_ENTRY, 2) + TEST_FIELD_SIZE (MESSAGE_RESOURCE_ENTRY, Length, 2) + TEST_FIELD_ALIGN (MESSAGE_RESOURCE_ENTRY, Length, 2) + TEST_FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Length, 0) + TEST_FIELD_SIZE (MESSAGE_RESOURCE_ENTRY, Flags, 2) + TEST_FIELD_ALIGN (MESSAGE_RESOURCE_ENTRY, Flags, 2) + TEST_FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Flags, 2) + TEST_FIELD_SIZE (MESSAGE_RESOURCE_ENTRY, Text, 1) + TEST_FIELD_ALIGN (MESSAGE_RESOURCE_ENTRY, Text, 1) + TEST_FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text, 4) } static void test_pack_NT_TIB(void) { /* NT_TIB (pack 4) */ - TEST_FIELD(NT_TIB, struct _EXCEPTION_REGISTRATION_RECORD *, ExceptionList, 0, 4, 4); - TEST_FIELD(NT_TIB, PVOID, StackBase, 4, 4, 4); - TEST_FIELD(NT_TIB, PVOID, StackLimit, 8, 4, 4); - TEST_FIELD(NT_TIB, PVOID, SubSystemTib, 12, 4, 4); + TEST_FIELD_SIZE (NT_TIB, ExceptionList, 4) + TEST_FIELD_ALIGN (NT_TIB, ExceptionList, 4) + TEST_FIELD_OFFSET(NT_TIB, ExceptionList, 0) + TEST_FIELD_SIZE (NT_TIB, StackBase, 4) + TEST_FIELD_ALIGN (NT_TIB, StackBase, 4) + TEST_FIELD_OFFSET(NT_TIB, StackBase, 4) + TEST_FIELD_SIZE (NT_TIB, StackLimit, 4) + TEST_FIELD_ALIGN (NT_TIB, StackLimit, 4) + TEST_FIELD_OFFSET(NT_TIB, StackLimit, 8) + TEST_FIELD_SIZE (NT_TIB, SubSystemTib, 4) + TEST_FIELD_ALIGN (NT_TIB, SubSystemTib, 4) + TEST_FIELD_OFFSET(NT_TIB, SubSystemTib, 12) } static void test_pack_OBJECT_TYPE_LIST(void) { /* OBJECT_TYPE_LIST (pack 4) */ - TEST_TYPE(OBJECT_TYPE_LIST, 8, 4); - TEST_FIELD(OBJECT_TYPE_LIST, WORD, Level, 0, 2, 2); - TEST_FIELD(OBJECT_TYPE_LIST, WORD, Sbz, 2, 2, 2); - TEST_FIELD(OBJECT_TYPE_LIST, GUID *, ObjectType, 4, 4, 4); + TEST_TYPE_SIZE (OBJECT_TYPE_LIST, 8) + TEST_TYPE_ALIGN (OBJECT_TYPE_LIST, 4) + TEST_FIELD_SIZE (OBJECT_TYPE_LIST, Level, 2) + TEST_FIELD_ALIGN (OBJECT_TYPE_LIST, Level, 2) + TEST_FIELD_OFFSET(OBJECT_TYPE_LIST, Level, 0) + TEST_FIELD_SIZE (OBJECT_TYPE_LIST, Sbz, 2) + TEST_FIELD_ALIGN (OBJECT_TYPE_LIST, Sbz, 2) + TEST_FIELD_OFFSET(OBJECT_TYPE_LIST, Sbz, 2) + TEST_FIELD_SIZE (OBJECT_TYPE_LIST, ObjectType, 4) + TEST_FIELD_ALIGN (OBJECT_TYPE_LIST, ObjectType, 4) + TEST_FIELD_OFFSET(OBJECT_TYPE_LIST, ObjectType, 4) } static void test_pack_PACCESS_ALLOWED_ACE(void) { /* PACCESS_ALLOWED_ACE */ - TEST_TYPE(PACCESS_ALLOWED_ACE, 4, 4); - TEST_TYPE_POINTER(PACCESS_ALLOWED_ACE, 12, 4); + TEST_TYPE_SIZE (PACCESS_ALLOWED_ACE, 4) + TEST_TYPE_ALIGN (PACCESS_ALLOWED_ACE, 4) + TEST_TARGET_SIZE (PACCESS_ALLOWED_ACE, 12) + TEST_TARGET_ALIGN(PACCESS_ALLOWED_ACE, 4) } static void test_pack_PACCESS_DENIED_ACE(void) { /* PACCESS_DENIED_ACE */ - TEST_TYPE(PACCESS_DENIED_ACE, 4, 4); - TEST_TYPE_POINTER(PACCESS_DENIED_ACE, 12, 4); + TEST_TYPE_SIZE (PACCESS_DENIED_ACE, 4) + TEST_TYPE_ALIGN (PACCESS_DENIED_ACE, 4) + TEST_TARGET_SIZE (PACCESS_DENIED_ACE, 12) + TEST_TARGET_ALIGN(PACCESS_DENIED_ACE, 4) } static void test_pack_PACCESS_TOKEN(void) { /* PACCESS_TOKEN */ - TEST_TYPE(PACCESS_TOKEN, 4, 4); + TEST_TYPE_SIZE (PACCESS_TOKEN, 4) + TEST_TYPE_ALIGN (PACCESS_TOKEN, 4) } static void test_pack_PACE_HEADER(void) { /* PACE_HEADER */ - TEST_TYPE(PACE_HEADER, 4, 4); - TEST_TYPE_POINTER(PACE_HEADER, 4, 2); + TEST_TYPE_SIZE (PACE_HEADER, 4) + TEST_TYPE_ALIGN (PACE_HEADER, 4) + TEST_TARGET_SIZE (PACE_HEADER, 4) + TEST_TARGET_ALIGN(PACE_HEADER, 2) } static void test_pack_PACL(void) { /* PACL */ - TEST_TYPE(PACL, 4, 4); - TEST_TYPE_POINTER(PACL, 8, 2); + TEST_TYPE_SIZE (PACL, 4) + TEST_TYPE_ALIGN (PACL, 4) + TEST_TARGET_SIZE (PACL, 8) + TEST_TARGET_ALIGN(PACL, 2) } static void test_pack_PACL_REVISION_INFORMATION(void) { /* PACL_REVISION_INFORMATION */ - TEST_TYPE(PACL_REVISION_INFORMATION, 4, 4); - TEST_TYPE_POINTER(PACL_REVISION_INFORMATION, 4, 4); + TEST_TYPE_SIZE (PACL_REVISION_INFORMATION, 4) + TEST_TYPE_ALIGN (PACL_REVISION_INFORMATION, 4) + TEST_TARGET_SIZE (PACL_REVISION_INFORMATION, 4) + TEST_TARGET_ALIGN(PACL_REVISION_INFORMATION, 4) } static void test_pack_PACL_SIZE_INFORMATION(void) { /* PACL_SIZE_INFORMATION */ - TEST_TYPE(PACL_SIZE_INFORMATION, 4, 4); - TEST_TYPE_POINTER(PACL_SIZE_INFORMATION, 12, 4); + TEST_TYPE_SIZE (PACL_SIZE_INFORMATION, 4) + TEST_TYPE_ALIGN (PACL_SIZE_INFORMATION, 4) + TEST_TARGET_SIZE (PACL_SIZE_INFORMATION, 12) + TEST_TARGET_ALIGN(PACL_SIZE_INFORMATION, 4) } static void test_pack_PCCH(void) { /* PCCH */ - TEST_TYPE(PCCH, 4, 4); - TEST_TYPE_POINTER(PCCH, 1, 1); + TEST_TYPE_SIZE (PCCH, 4) + TEST_TYPE_ALIGN (PCCH, 4) + TEST_TARGET_SIZE (PCCH, 1) + TEST_TARGET_ALIGN(PCCH, 1) } static void test_pack_PCH(void) { /* PCH */ - TEST_TYPE(PCH, 4, 4); - TEST_TYPE_POINTER(PCH, 1, 1); + TEST_TYPE_SIZE (PCH, 4) + TEST_TYPE_ALIGN (PCH, 4) + TEST_TARGET_SIZE (PCH, 1) + TEST_TARGET_ALIGN(PCH, 1) } static void test_pack_PCSTR(void) { /* PCSTR */ - TEST_TYPE(PCSTR, 4, 4); - TEST_TYPE_POINTER(PCSTR, 1, 1); + TEST_TYPE_SIZE (PCSTR, 4) + TEST_TYPE_ALIGN (PCSTR, 4) + TEST_TARGET_SIZE (PCSTR, 1) + TEST_TARGET_ALIGN(PCSTR, 1) } static void test_pack_PCTSTR(void) { /* PCTSTR */ - TEST_TYPE(PCTSTR, 4, 4); + TEST_TYPE_SIZE (PCTSTR, 4) + TEST_TYPE_ALIGN (PCTSTR, 4) } static void test_pack_PCWCH(void) { /* PCWCH */ - TEST_TYPE(PCWCH, 4, 4); - TEST_TYPE_POINTER(PCWCH, 2, 2); + TEST_TYPE_SIZE (PCWCH, 4) + TEST_TYPE_ALIGN (PCWCH, 4) + TEST_TARGET_SIZE (PCWCH, 2) + TEST_TARGET_ALIGN(PCWCH, 2) } static void test_pack_PCWSTR(void) { /* PCWSTR */ - TEST_TYPE(PCWSTR, 4, 4); - TEST_TYPE_POINTER(PCWSTR, 2, 2); + TEST_TYPE_SIZE (PCWSTR, 4) + TEST_TYPE_ALIGN (PCWSTR, 4) + TEST_TARGET_SIZE (PCWSTR, 2) + TEST_TARGET_ALIGN(PCWSTR, 2) } static void test_pack_PEXCEPTION_POINTERS(void) { /* PEXCEPTION_POINTERS */ - TEST_TYPE(PEXCEPTION_POINTERS, 4, 4); - TEST_TYPE_POINTER(PEXCEPTION_POINTERS, 8, 4); + TEST_TYPE_SIZE (PEXCEPTION_POINTERS, 4) + TEST_TYPE_ALIGN (PEXCEPTION_POINTERS, 4) + TEST_TARGET_SIZE (PEXCEPTION_POINTERS, 8) + TEST_TARGET_ALIGN(PEXCEPTION_POINTERS, 4) } static void test_pack_PEXCEPTION_RECORD(void) { /* PEXCEPTION_RECORD */ - TEST_TYPE(PEXCEPTION_RECORD, 4, 4); - TEST_TYPE_POINTER(PEXCEPTION_RECORD, 80, 4); + TEST_TYPE_SIZE (PEXCEPTION_RECORD, 4) + TEST_TYPE_ALIGN (PEXCEPTION_RECORD, 4) + TEST_TARGET_SIZE (PEXCEPTION_RECORD, 80) + TEST_TARGET_ALIGN(PEXCEPTION_RECORD, 4) } static void test_pack_PFLOATING_SAVE_AREA(void) { /* PFLOATING_SAVE_AREA */ - TEST_TYPE(PFLOATING_SAVE_AREA, 4, 4); - TEST_TYPE_POINTER(PFLOATING_SAVE_AREA, 112, 4); + TEST_TYPE_SIZE (PFLOATING_SAVE_AREA, 4) + TEST_TYPE_ALIGN (PFLOATING_SAVE_AREA, 4) + TEST_TARGET_SIZE (PFLOATING_SAVE_AREA, 112) + TEST_TARGET_ALIGN(PFLOATING_SAVE_AREA, 4) } static void test_pack_PFPO_DATA(void) { /* PFPO_DATA */ - TEST_TYPE(PFPO_DATA, 4, 4); - TEST_TYPE_POINTER(PFPO_DATA, 16, 4); + TEST_TYPE_SIZE (PFPO_DATA, 4) + TEST_TYPE_ALIGN (PFPO_DATA, 4) + TEST_TARGET_SIZE (PFPO_DATA, 16) + TEST_TARGET_ALIGN(PFPO_DATA, 4) } static void test_pack_PGENERIC_MAPPING(void) { /* PGENERIC_MAPPING */ - TEST_TYPE(PGENERIC_MAPPING, 4, 4); - TEST_TYPE_POINTER(PGENERIC_MAPPING, 16, 4); + TEST_TYPE_SIZE (PGENERIC_MAPPING, 4) + TEST_TYPE_ALIGN (PGENERIC_MAPPING, 4) + TEST_TARGET_SIZE (PGENERIC_MAPPING, 16) + TEST_TARGET_ALIGN(PGENERIC_MAPPING, 4) } static void test_pack_PHANDLE(void) { /* PHANDLE */ - TEST_TYPE(PHANDLE, 4, 4); - TEST_TYPE_POINTER(PHANDLE, 4, 4); + TEST_TYPE_SIZE (PHANDLE, 4) + TEST_TYPE_ALIGN (PHANDLE, 4) + TEST_TARGET_SIZE (PHANDLE, 4) + TEST_TARGET_ALIGN(PHANDLE, 4) } static void test_pack_PIMAGE_ARCHIVE_MEMBER_HEADER(void) { /* PIMAGE_ARCHIVE_MEMBER_HEADER */ - TEST_TYPE(PIMAGE_ARCHIVE_MEMBER_HEADER, 4, 4); - TEST_TYPE_POINTER(PIMAGE_ARCHIVE_MEMBER_HEADER, 60, 1); + TEST_TYPE_SIZE (PIMAGE_ARCHIVE_MEMBER_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_ARCHIVE_MEMBER_HEADER, 4) + TEST_TARGET_SIZE (PIMAGE_ARCHIVE_MEMBER_HEADER, 60) + TEST_TARGET_ALIGN(PIMAGE_ARCHIVE_MEMBER_HEADER, 1) } static void test_pack_PIMAGE_AUX_SYMBOL(void) { /* PIMAGE_AUX_SYMBOL */ - TEST_TYPE(PIMAGE_AUX_SYMBOL, 4, 4); + TEST_TYPE_SIZE (PIMAGE_AUX_SYMBOL, 4) + TEST_TYPE_ALIGN (PIMAGE_AUX_SYMBOL, 4) } static void test_pack_PIMAGE_BASE_RELOCATION(void) { /* PIMAGE_BASE_RELOCATION */ - TEST_TYPE(PIMAGE_BASE_RELOCATION, 4, 4); - TEST_TYPE_POINTER(PIMAGE_BASE_RELOCATION, 8, 4); + TEST_TYPE_SIZE (PIMAGE_BASE_RELOCATION, 4) + TEST_TYPE_ALIGN (PIMAGE_BASE_RELOCATION, 4) + TEST_TARGET_SIZE (PIMAGE_BASE_RELOCATION, 8) + TEST_TARGET_ALIGN(PIMAGE_BASE_RELOCATION, 4) } static void test_pack_PIMAGE_BOUND_FORWARDER_REF(void) { /* PIMAGE_BOUND_FORWARDER_REF */ - TEST_TYPE(PIMAGE_BOUND_FORWARDER_REF, 4, 4); - TEST_TYPE_POINTER(PIMAGE_BOUND_FORWARDER_REF, 8, 4); + TEST_TYPE_SIZE (PIMAGE_BOUND_FORWARDER_REF, 4) + TEST_TYPE_ALIGN (PIMAGE_BOUND_FORWARDER_REF, 4) + TEST_TARGET_SIZE (PIMAGE_BOUND_FORWARDER_REF, 8) + TEST_TARGET_ALIGN(PIMAGE_BOUND_FORWARDER_REF, 4) } static void test_pack_PIMAGE_BOUND_IMPORT_DESCRIPTOR(void) { /* PIMAGE_BOUND_IMPORT_DESCRIPTOR */ - TEST_TYPE(PIMAGE_BOUND_IMPORT_DESCRIPTOR, 4, 4); - TEST_TYPE_POINTER(PIMAGE_BOUND_IMPORT_DESCRIPTOR, 8, 4); + TEST_TYPE_SIZE (PIMAGE_BOUND_IMPORT_DESCRIPTOR, 4) + TEST_TYPE_ALIGN (PIMAGE_BOUND_IMPORT_DESCRIPTOR, 4) + TEST_TARGET_SIZE (PIMAGE_BOUND_IMPORT_DESCRIPTOR, 8) + TEST_TARGET_ALIGN(PIMAGE_BOUND_IMPORT_DESCRIPTOR, 4) } static void test_pack_PIMAGE_COFF_SYMBOLS_HEADER(void) { /* PIMAGE_COFF_SYMBOLS_HEADER */ - TEST_TYPE(PIMAGE_COFF_SYMBOLS_HEADER, 4, 4); - TEST_TYPE_POINTER(PIMAGE_COFF_SYMBOLS_HEADER, 32, 4); + TEST_TYPE_SIZE (PIMAGE_COFF_SYMBOLS_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_COFF_SYMBOLS_HEADER, 4) + TEST_TARGET_SIZE (PIMAGE_COFF_SYMBOLS_HEADER, 32) + TEST_TARGET_ALIGN(PIMAGE_COFF_SYMBOLS_HEADER, 4) } static void test_pack_PIMAGE_DATA_DIRECTORY(void) { /* PIMAGE_DATA_DIRECTORY */ - TEST_TYPE(PIMAGE_DATA_DIRECTORY, 4, 4); - TEST_TYPE_POINTER(PIMAGE_DATA_DIRECTORY, 8, 4); + TEST_TYPE_SIZE (PIMAGE_DATA_DIRECTORY, 4) + TEST_TYPE_ALIGN (PIMAGE_DATA_DIRECTORY, 4) + TEST_TARGET_SIZE (PIMAGE_DATA_DIRECTORY, 8) + TEST_TARGET_ALIGN(PIMAGE_DATA_DIRECTORY, 4) } static void test_pack_PIMAGE_DEBUG_DIRECTORY(void) { /* PIMAGE_DEBUG_DIRECTORY */ - TEST_TYPE(PIMAGE_DEBUG_DIRECTORY, 4, 4); - TEST_TYPE_POINTER(PIMAGE_DEBUG_DIRECTORY, 28, 4); + TEST_TYPE_SIZE (PIMAGE_DEBUG_DIRECTORY, 4) + TEST_TYPE_ALIGN (PIMAGE_DEBUG_DIRECTORY, 4) + TEST_TARGET_SIZE (PIMAGE_DEBUG_DIRECTORY, 28) + TEST_TARGET_ALIGN(PIMAGE_DEBUG_DIRECTORY, 4) } static void test_pack_PIMAGE_DEBUG_MISC(void) { /* PIMAGE_DEBUG_MISC */ - TEST_TYPE(PIMAGE_DEBUG_MISC, 4, 4); - TEST_TYPE_POINTER(PIMAGE_DEBUG_MISC, 16, 4); + TEST_TYPE_SIZE (PIMAGE_DEBUG_MISC, 4) + TEST_TYPE_ALIGN (PIMAGE_DEBUG_MISC, 4) + TEST_TARGET_SIZE (PIMAGE_DEBUG_MISC, 16) + TEST_TARGET_ALIGN(PIMAGE_DEBUG_MISC, 4) } static void test_pack_PIMAGE_DOS_HEADER(void) { /* PIMAGE_DOS_HEADER */ - TEST_TYPE(PIMAGE_DOS_HEADER, 4, 4); - TEST_TYPE_POINTER(PIMAGE_DOS_HEADER, 64, 2); + TEST_TYPE_SIZE (PIMAGE_DOS_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_DOS_HEADER, 4) + TEST_TARGET_SIZE (PIMAGE_DOS_HEADER, 64) + TEST_TARGET_ALIGN(PIMAGE_DOS_HEADER, 2) } static void test_pack_PIMAGE_EXPORT_DIRECTORY(void) { /* PIMAGE_EXPORT_DIRECTORY */ - TEST_TYPE(PIMAGE_EXPORT_DIRECTORY, 4, 4); - TEST_TYPE_POINTER(PIMAGE_EXPORT_DIRECTORY, 40, 4); + TEST_TYPE_SIZE (PIMAGE_EXPORT_DIRECTORY, 4) + TEST_TYPE_ALIGN (PIMAGE_EXPORT_DIRECTORY, 4) + TEST_TARGET_SIZE (PIMAGE_EXPORT_DIRECTORY, 40) + TEST_TARGET_ALIGN(PIMAGE_EXPORT_DIRECTORY, 4) } static void test_pack_PIMAGE_FILE_HEADER(void) { /* PIMAGE_FILE_HEADER */ - TEST_TYPE(PIMAGE_FILE_HEADER, 4, 4); - TEST_TYPE_POINTER(PIMAGE_FILE_HEADER, 20, 4); + TEST_TYPE_SIZE (PIMAGE_FILE_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_FILE_HEADER, 4) + TEST_TARGET_SIZE (PIMAGE_FILE_HEADER, 20) + TEST_TARGET_ALIGN(PIMAGE_FILE_HEADER, 4) } static void test_pack_PIMAGE_FUNCTION_ENTRY(void) { /* PIMAGE_FUNCTION_ENTRY */ - TEST_TYPE(PIMAGE_FUNCTION_ENTRY, 4, 4); - TEST_TYPE_POINTER(PIMAGE_FUNCTION_ENTRY, 12, 4); + TEST_TYPE_SIZE (PIMAGE_FUNCTION_ENTRY, 4) + TEST_TYPE_ALIGN (PIMAGE_FUNCTION_ENTRY, 4) + TEST_TARGET_SIZE (PIMAGE_FUNCTION_ENTRY, 12) + TEST_TARGET_ALIGN(PIMAGE_FUNCTION_ENTRY, 4) } static void test_pack_PIMAGE_IMPORT_BY_NAME(void) { /* PIMAGE_IMPORT_BY_NAME */ - TEST_TYPE(PIMAGE_IMPORT_BY_NAME, 4, 4); - TEST_TYPE_POINTER(PIMAGE_IMPORT_BY_NAME, 4, 2); + TEST_TYPE_SIZE (PIMAGE_IMPORT_BY_NAME, 4) + TEST_TYPE_ALIGN (PIMAGE_IMPORT_BY_NAME, 4) + TEST_TARGET_SIZE (PIMAGE_IMPORT_BY_NAME, 4) + TEST_TARGET_ALIGN(PIMAGE_IMPORT_BY_NAME, 2) } static void test_pack_PIMAGE_IMPORT_DESCRIPTOR(void) { /* PIMAGE_IMPORT_DESCRIPTOR */ - TEST_TYPE(PIMAGE_IMPORT_DESCRIPTOR, 4, 4); + TEST_TYPE_SIZE (PIMAGE_IMPORT_DESCRIPTOR, 4) + TEST_TYPE_ALIGN (PIMAGE_IMPORT_DESCRIPTOR, 4) } static void test_pack_PIMAGE_LINENUMBER(void) { /* PIMAGE_LINENUMBER */ - TEST_TYPE(PIMAGE_LINENUMBER, 4, 4); + TEST_TYPE_SIZE (PIMAGE_LINENUMBER, 4) + TEST_TYPE_ALIGN (PIMAGE_LINENUMBER, 4) } static void test_pack_PIMAGE_LOAD_CONFIG_DIRECTORY(void) { /* PIMAGE_LOAD_CONFIG_DIRECTORY */ - TEST_TYPE(PIMAGE_LOAD_CONFIG_DIRECTORY, 4, 4); - TEST_TYPE_POINTER(PIMAGE_LOAD_CONFIG_DIRECTORY, 72, 4); + TEST_TYPE_SIZE (PIMAGE_LOAD_CONFIG_DIRECTORY, 4) + TEST_TYPE_ALIGN (PIMAGE_LOAD_CONFIG_DIRECTORY, 4) + TEST_TARGET_SIZE (PIMAGE_LOAD_CONFIG_DIRECTORY, 72) + TEST_TARGET_ALIGN(PIMAGE_LOAD_CONFIG_DIRECTORY, 4) } static void test_pack_PIMAGE_NT_HEADERS(void) { /* PIMAGE_NT_HEADERS */ - TEST_TYPE(PIMAGE_NT_HEADERS, 4, 4); + TEST_TYPE_SIZE (PIMAGE_NT_HEADERS, 4) + TEST_TYPE_ALIGN (PIMAGE_NT_HEADERS, 4) } static void test_pack_PIMAGE_OPTIONAL_HEADER(void) { /* PIMAGE_OPTIONAL_HEADER */ - TEST_TYPE(PIMAGE_OPTIONAL_HEADER, 4, 4); + TEST_TYPE_SIZE (PIMAGE_OPTIONAL_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_OPTIONAL_HEADER, 4) } static void test_pack_PIMAGE_OS2_HEADER(void) { /* PIMAGE_OS2_HEADER */ - TEST_TYPE(PIMAGE_OS2_HEADER, 4, 4); - TEST_TYPE_POINTER(PIMAGE_OS2_HEADER, 64, 2); + TEST_TYPE_SIZE (PIMAGE_OS2_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_OS2_HEADER, 4) + TEST_TARGET_SIZE (PIMAGE_OS2_HEADER, 64) + TEST_TARGET_ALIGN(PIMAGE_OS2_HEADER, 2) } static void test_pack_PIMAGE_RELOCATION(void) { /* PIMAGE_RELOCATION */ - TEST_TYPE(PIMAGE_RELOCATION, 4, 4); + TEST_TYPE_SIZE (PIMAGE_RELOCATION, 4) + TEST_TYPE_ALIGN (PIMAGE_RELOCATION, 4) } static void test_pack_PIMAGE_RESOURCE_DATA_ENTRY(void) { /* PIMAGE_RESOURCE_DATA_ENTRY */ - TEST_TYPE(PIMAGE_RESOURCE_DATA_ENTRY, 4, 4); - TEST_TYPE_POINTER(PIMAGE_RESOURCE_DATA_ENTRY, 16, 4); + TEST_TYPE_SIZE (PIMAGE_RESOURCE_DATA_ENTRY, 4) + TEST_TYPE_ALIGN (PIMAGE_RESOURCE_DATA_ENTRY, 4) + TEST_TARGET_SIZE (PIMAGE_RESOURCE_DATA_ENTRY, 16) + TEST_TARGET_ALIGN(PIMAGE_RESOURCE_DATA_ENTRY, 4) } static void test_pack_PIMAGE_RESOURCE_DIRECTORY(void) { /* PIMAGE_RESOURCE_DIRECTORY */ - TEST_TYPE(PIMAGE_RESOURCE_DIRECTORY, 4, 4); - TEST_TYPE_POINTER(PIMAGE_RESOURCE_DIRECTORY, 16, 4); + TEST_TYPE_SIZE (PIMAGE_RESOURCE_DIRECTORY, 4) + TEST_TYPE_ALIGN (PIMAGE_RESOURCE_DIRECTORY, 4) + TEST_TARGET_SIZE (PIMAGE_RESOURCE_DIRECTORY, 16) + TEST_TARGET_ALIGN(PIMAGE_RESOURCE_DIRECTORY, 4) } static void test_pack_PIMAGE_RESOURCE_DIRECTORY_ENTRY(void) { /* PIMAGE_RESOURCE_DIRECTORY_ENTRY */ - TEST_TYPE(PIMAGE_RESOURCE_DIRECTORY_ENTRY, 4, 4); + TEST_TYPE_SIZE (PIMAGE_RESOURCE_DIRECTORY_ENTRY, 4) + TEST_TYPE_ALIGN (PIMAGE_RESOURCE_DIRECTORY_ENTRY, 4) } static void test_pack_PIMAGE_RESOURCE_DIRECTORY_STRING(void) { /* PIMAGE_RESOURCE_DIRECTORY_STRING */ - TEST_TYPE(PIMAGE_RESOURCE_DIRECTORY_STRING, 4, 4); - TEST_TYPE_POINTER(PIMAGE_RESOURCE_DIRECTORY_STRING, 4, 2); + TEST_TYPE_SIZE (PIMAGE_RESOURCE_DIRECTORY_STRING, 4) + TEST_TYPE_ALIGN (PIMAGE_RESOURCE_DIRECTORY_STRING, 4) + TEST_TARGET_SIZE (PIMAGE_RESOURCE_DIRECTORY_STRING, 4) + TEST_TARGET_ALIGN(PIMAGE_RESOURCE_DIRECTORY_STRING, 2) } static void test_pack_PIMAGE_RESOURCE_DIR_STRING_U(void) { /* PIMAGE_RESOURCE_DIR_STRING_U */ - TEST_TYPE(PIMAGE_RESOURCE_DIR_STRING_U, 4, 4); - TEST_TYPE_POINTER(PIMAGE_RESOURCE_DIR_STRING_U, 4, 2); + TEST_TYPE_SIZE (PIMAGE_RESOURCE_DIR_STRING_U, 4) + TEST_TYPE_ALIGN (PIMAGE_RESOURCE_DIR_STRING_U, 4) + TEST_TARGET_SIZE (PIMAGE_RESOURCE_DIR_STRING_U, 4) + TEST_TARGET_ALIGN(PIMAGE_RESOURCE_DIR_STRING_U, 2) } static void test_pack_PIMAGE_SECTION_HEADER(void) { /* PIMAGE_SECTION_HEADER */ - TEST_TYPE(PIMAGE_SECTION_HEADER, 4, 4); + TEST_TYPE_SIZE (PIMAGE_SECTION_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_SECTION_HEADER, 4) } static void test_pack_PIMAGE_SEPARATE_DEBUG_HEADER(void) { /* PIMAGE_SEPARATE_DEBUG_HEADER */ - TEST_TYPE(PIMAGE_SEPARATE_DEBUG_HEADER, 4, 4); - TEST_TYPE_POINTER(PIMAGE_SEPARATE_DEBUG_HEADER, 48, 4); + TEST_TYPE_SIZE (PIMAGE_SEPARATE_DEBUG_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_SEPARATE_DEBUG_HEADER, 4) + TEST_TARGET_SIZE (PIMAGE_SEPARATE_DEBUG_HEADER, 48) + TEST_TARGET_ALIGN(PIMAGE_SEPARATE_DEBUG_HEADER, 4) } static void test_pack_PIMAGE_SYMBOL(void) { /* PIMAGE_SYMBOL */ - TEST_TYPE(PIMAGE_SYMBOL, 4, 4); + TEST_TYPE_SIZE (PIMAGE_SYMBOL, 4) + TEST_TYPE_ALIGN (PIMAGE_SYMBOL, 4) } static void test_pack_PIMAGE_THUNK_DATA(void) { /* PIMAGE_THUNK_DATA */ - TEST_TYPE(PIMAGE_THUNK_DATA, 4, 4); + TEST_TYPE_SIZE (PIMAGE_THUNK_DATA, 4) + TEST_TYPE_ALIGN (PIMAGE_THUNK_DATA, 4) } static void test_pack_PIMAGE_TLS_CALLBACK(void) { /* PIMAGE_TLS_CALLBACK */ - TEST_TYPE(PIMAGE_TLS_CALLBACK, 4, 4); + TEST_TYPE_SIZE (PIMAGE_TLS_CALLBACK, 4) + TEST_TYPE_ALIGN (PIMAGE_TLS_CALLBACK, 4) } static void test_pack_PIMAGE_TLS_DIRECTORY(void) { /* PIMAGE_TLS_DIRECTORY */ - TEST_TYPE(PIMAGE_TLS_DIRECTORY, 4, 4); + TEST_TYPE_SIZE (PIMAGE_TLS_DIRECTORY, 4) + TEST_TYPE_ALIGN (PIMAGE_TLS_DIRECTORY, 4) } static void test_pack_PIMAGE_VXD_HEADER(void) { /* PIMAGE_VXD_HEADER */ - TEST_TYPE(PIMAGE_VXD_HEADER, 4, 4); - TEST_TYPE_POINTER(PIMAGE_VXD_HEADER, 196, 2); + TEST_TYPE_SIZE (PIMAGE_VXD_HEADER, 4) + TEST_TYPE_ALIGN (PIMAGE_VXD_HEADER, 4) + TEST_TARGET_SIZE (PIMAGE_VXD_HEADER, 196) + TEST_TARGET_ALIGN(PIMAGE_VXD_HEADER, 2) } static void test_pack_PIO_COUNTERS(void) { /* PIO_COUNTERS */ - TEST_TYPE(PIO_COUNTERS, 4, 4); - TEST_TYPE_POINTER(PIO_COUNTERS, 48, 8); + TEST_TYPE_SIZE (PIO_COUNTERS, 4) + TEST_TYPE_ALIGN (PIO_COUNTERS, 4) + TEST_TARGET_SIZE (PIO_COUNTERS, 48) + TEST_TARGET_ALIGN(PIO_COUNTERS, 8) } static void test_pack_PISECURITY_DESCRIPTOR(void) { /* PISECURITY_DESCRIPTOR */ - TEST_TYPE(PISECURITY_DESCRIPTOR, 4, 4); - TEST_TYPE_POINTER(PISECURITY_DESCRIPTOR, 20, 4); + TEST_TYPE_SIZE (PISECURITY_DESCRIPTOR, 4) + TEST_TYPE_ALIGN (PISECURITY_DESCRIPTOR, 4) + TEST_TARGET_SIZE (PISECURITY_DESCRIPTOR, 20) + TEST_TARGET_ALIGN(PISECURITY_DESCRIPTOR, 4) } static void test_pack_PISECURITY_DESCRIPTOR_RELATIVE(void) { /* PISECURITY_DESCRIPTOR_RELATIVE */ - TEST_TYPE(PISECURITY_DESCRIPTOR_RELATIVE, 4, 4); - TEST_TYPE_POINTER(PISECURITY_DESCRIPTOR_RELATIVE, 20, 4); + TEST_TYPE_SIZE (PISECURITY_DESCRIPTOR_RELATIVE, 4) + TEST_TYPE_ALIGN (PISECURITY_DESCRIPTOR_RELATIVE, 4) + TEST_TARGET_SIZE (PISECURITY_DESCRIPTOR_RELATIVE, 20) + TEST_TARGET_ALIGN(PISECURITY_DESCRIPTOR_RELATIVE, 4) } static void test_pack_PISID(void) { /* PISID */ - TEST_TYPE(PISID, 4, 4); - TEST_TYPE_POINTER(PISID, 12, 4); + TEST_TYPE_SIZE (PISID, 4) + TEST_TYPE_ALIGN (PISID, 4) + TEST_TARGET_SIZE (PISID, 12) + TEST_TARGET_ALIGN(PISID, 4) } static void test_pack_PLARGE_INTEGER(void) { /* PLARGE_INTEGER */ - TEST_TYPE(PLARGE_INTEGER, 4, 4); + TEST_TYPE_SIZE (PLARGE_INTEGER, 4) + TEST_TYPE_ALIGN (PLARGE_INTEGER, 4) } static void test_pack_PLIST_ENTRY(void) { /* PLIST_ENTRY */ - TEST_TYPE(PLIST_ENTRY, 4, 4); - TEST_TYPE_POINTER(PLIST_ENTRY, 8, 4); + TEST_TYPE_SIZE (PLIST_ENTRY, 4) + TEST_TYPE_ALIGN (PLIST_ENTRY, 4) + TEST_TARGET_SIZE (PLIST_ENTRY, 8) + TEST_TARGET_ALIGN(PLIST_ENTRY, 4) } static void test_pack_PLUID(void) { /* PLUID */ - TEST_TYPE(PLUID, 4, 4); - TEST_TYPE_POINTER(PLUID, 8, 4); + TEST_TYPE_SIZE (PLUID, 4) + TEST_TYPE_ALIGN (PLUID, 4) + TEST_TARGET_SIZE (PLUID, 8) + TEST_TARGET_ALIGN(PLUID, 4) } static void test_pack_PLUID_AND_ATTRIBUTES(void) { /* PLUID_AND_ATTRIBUTES */ - TEST_TYPE(PLUID_AND_ATTRIBUTES, 4, 4); - TEST_TYPE_POINTER(PLUID_AND_ATTRIBUTES, 12, 4); + TEST_TYPE_SIZE (PLUID_AND_ATTRIBUTES, 4) + TEST_TYPE_ALIGN (PLUID_AND_ATTRIBUTES, 4) + TEST_TARGET_SIZE (PLUID_AND_ATTRIBUTES, 12) + TEST_TARGET_ALIGN(PLUID_AND_ATTRIBUTES, 4) } static void test_pack_PMEMORY_BASIC_INFORMATION(void) { /* PMEMORY_BASIC_INFORMATION */ - TEST_TYPE(PMEMORY_BASIC_INFORMATION, 4, 4); - TEST_TYPE_POINTER(PMEMORY_BASIC_INFORMATION, 28, 4); + TEST_TYPE_SIZE (PMEMORY_BASIC_INFORMATION, 4) + TEST_TYPE_ALIGN (PMEMORY_BASIC_INFORMATION, 4) + TEST_TARGET_SIZE (PMEMORY_BASIC_INFORMATION, 28) + TEST_TARGET_ALIGN(PMEMORY_BASIC_INFORMATION, 4) } static void test_pack_PMESSAGE_RESOURCE_BLOCK(void) { /* PMESSAGE_RESOURCE_BLOCK */ - TEST_TYPE(PMESSAGE_RESOURCE_BLOCK, 4, 4); - TEST_TYPE_POINTER(PMESSAGE_RESOURCE_BLOCK, 12, 4); + TEST_TYPE_SIZE (PMESSAGE_RESOURCE_BLOCK, 4) + TEST_TYPE_ALIGN (PMESSAGE_RESOURCE_BLOCK, 4) + TEST_TARGET_SIZE (PMESSAGE_RESOURCE_BLOCK, 12) + TEST_TARGET_ALIGN(PMESSAGE_RESOURCE_BLOCK, 4) } static void test_pack_PMESSAGE_RESOURCE_DATA(void) { /* PMESSAGE_RESOURCE_DATA */ - TEST_TYPE(PMESSAGE_RESOURCE_DATA, 4, 4); - TEST_TYPE_POINTER(PMESSAGE_RESOURCE_DATA, 16, 4); + TEST_TYPE_SIZE (PMESSAGE_RESOURCE_DATA, 4) + TEST_TYPE_ALIGN (PMESSAGE_RESOURCE_DATA, 4) + TEST_TARGET_SIZE (PMESSAGE_RESOURCE_DATA, 16) + TEST_TARGET_ALIGN(PMESSAGE_RESOURCE_DATA, 4) } static void test_pack_PMESSAGE_RESOURCE_ENTRY(void) { /* PMESSAGE_RESOURCE_ENTRY */ - TEST_TYPE(PMESSAGE_RESOURCE_ENTRY, 4, 4); - TEST_TYPE_POINTER(PMESSAGE_RESOURCE_ENTRY, 6, 2); + TEST_TYPE_SIZE (PMESSAGE_RESOURCE_ENTRY, 4) + TEST_TYPE_ALIGN (PMESSAGE_RESOURCE_ENTRY, 4) + TEST_TARGET_SIZE (PMESSAGE_RESOURCE_ENTRY, 6) + TEST_TARGET_ALIGN(PMESSAGE_RESOURCE_ENTRY, 2) } static void test_pack_PNT_TIB(void) { /* PNT_TIB */ - TEST_TYPE(PNT_TIB, 4, 4); + TEST_TYPE_SIZE (PNT_TIB, 4) + TEST_TYPE_ALIGN (PNT_TIB, 4) } static void test_pack_POBJECT_TYPE_LIST(void) { /* POBJECT_TYPE_LIST */ - TEST_TYPE(POBJECT_TYPE_LIST, 4, 4); - TEST_TYPE_POINTER(POBJECT_TYPE_LIST, 8, 4); + TEST_TYPE_SIZE (POBJECT_TYPE_LIST, 4) + TEST_TYPE_ALIGN (POBJECT_TYPE_LIST, 4) + TEST_TARGET_SIZE (POBJECT_TYPE_LIST, 8) + TEST_TARGET_ALIGN(POBJECT_TYPE_LIST, 4) } static void test_pack_PPRIVILEGE_SET(void) { /* PPRIVILEGE_SET */ - TEST_TYPE(PPRIVILEGE_SET, 4, 4); - TEST_TYPE_POINTER(PPRIVILEGE_SET, 20, 4); + TEST_TYPE_SIZE (PPRIVILEGE_SET, 4) + TEST_TYPE_ALIGN (PPRIVILEGE_SET, 4) + TEST_TARGET_SIZE (PPRIVILEGE_SET, 20) + TEST_TARGET_ALIGN(PPRIVILEGE_SET, 4) } static void test_pack_PRIVILEGE_SET(void) { /* PRIVILEGE_SET (pack 4) */ - TEST_TYPE(PRIVILEGE_SET, 20, 4); - TEST_FIELD(PRIVILEGE_SET, DWORD, PrivilegeCount, 0, 4, 4); - TEST_FIELD(PRIVILEGE_SET, DWORD, Control, 4, 4, 4); - TEST_FIELD(PRIVILEGE_SET, LUID_AND_ATTRIBUTES[ANYSIZE_ARRAY], Privilege, 8, 12, 4); + TEST_TYPE_SIZE (PRIVILEGE_SET, 20) + TEST_TYPE_ALIGN (PRIVILEGE_SET, 4) + TEST_FIELD_SIZE (PRIVILEGE_SET, PrivilegeCount, 4) + TEST_FIELD_ALIGN (PRIVILEGE_SET, PrivilegeCount, 4) + TEST_FIELD_OFFSET(PRIVILEGE_SET, PrivilegeCount, 0) + TEST_FIELD_SIZE (PRIVILEGE_SET, Control, 4) + TEST_FIELD_ALIGN (PRIVILEGE_SET, Control, 4) + TEST_FIELD_OFFSET(PRIVILEGE_SET, Control, 4) + TEST_FIELD_SIZE (PRIVILEGE_SET, Privilege, 12) + TEST_FIELD_ALIGN (PRIVILEGE_SET, Privilege, 4) + TEST_FIELD_OFFSET(PRIVILEGE_SET, Privilege, 8) } static void test_pack_PRLIST_ENTRY(void) { /* PRLIST_ENTRY */ - TEST_TYPE(PRLIST_ENTRY, 4, 4); - TEST_TYPE_POINTER(PRLIST_ENTRY, 8, 4); + TEST_TYPE_SIZE (PRLIST_ENTRY, 4) + TEST_TYPE_ALIGN (PRLIST_ENTRY, 4) + TEST_TARGET_SIZE (PRLIST_ENTRY, 8) + TEST_TARGET_ALIGN(PRLIST_ENTRY, 4) } static void test_pack_PRTL_CRITICAL_SECTION(void) { /* PRTL_CRITICAL_SECTION */ - TEST_TYPE(PRTL_CRITICAL_SECTION, 4, 4); - TEST_TYPE_POINTER(PRTL_CRITICAL_SECTION, 24, 4); + TEST_TYPE_SIZE (PRTL_CRITICAL_SECTION, 4) + TEST_TYPE_ALIGN (PRTL_CRITICAL_SECTION, 4) + TEST_TARGET_SIZE (PRTL_CRITICAL_SECTION, 24) + TEST_TARGET_ALIGN(PRTL_CRITICAL_SECTION, 4) } static void test_pack_PRTL_CRITICAL_SECTION_DEBUG(void) { /* PRTL_CRITICAL_SECTION_DEBUG */ - TEST_TYPE(PRTL_CRITICAL_SECTION_DEBUG, 4, 4); + TEST_TYPE_SIZE (PRTL_CRITICAL_SECTION_DEBUG, 4) + TEST_TYPE_ALIGN (PRTL_CRITICAL_SECTION_DEBUG, 4) } static void test_pack_PRTL_OSVERSIONINFOEXW(void) { /* PRTL_OSVERSIONINFOEXW */ - TEST_TYPE(PRTL_OSVERSIONINFOEXW, 4, 4); - TEST_TYPE_POINTER(PRTL_OSVERSIONINFOEXW, 284, 4); + TEST_TYPE_SIZE (PRTL_OSVERSIONINFOEXW, 4) + TEST_TYPE_ALIGN (PRTL_OSVERSIONINFOEXW, 4) + TEST_TARGET_SIZE (PRTL_OSVERSIONINFOEXW, 284) + TEST_TARGET_ALIGN(PRTL_OSVERSIONINFOEXW, 4) } static void test_pack_PRTL_OSVERSIONINFOW(void) { /* PRTL_OSVERSIONINFOW */ - TEST_TYPE(PRTL_OSVERSIONINFOW, 4, 4); - TEST_TYPE_POINTER(PRTL_OSVERSIONINFOW, 276, 4); + TEST_TYPE_SIZE (PRTL_OSVERSIONINFOW, 4) + TEST_TYPE_ALIGN (PRTL_OSVERSIONINFOW, 4) + TEST_TARGET_SIZE (PRTL_OSVERSIONINFOW, 276) + TEST_TARGET_ALIGN(PRTL_OSVERSIONINFOW, 4) } static void test_pack_PRTL_RESOURCE_DEBUG(void) { /* PRTL_RESOURCE_DEBUG */ - TEST_TYPE(PRTL_RESOURCE_DEBUG, 4, 4); + TEST_TYPE_SIZE (PRTL_RESOURCE_DEBUG, 4) + TEST_TYPE_ALIGN (PRTL_RESOURCE_DEBUG, 4) } static void test_pack_PSECURITY_DESCRIPTOR(void) { /* PSECURITY_DESCRIPTOR */ - TEST_TYPE(PSECURITY_DESCRIPTOR, 4, 4); + TEST_TYPE_SIZE (PSECURITY_DESCRIPTOR, 4) + TEST_TYPE_ALIGN (PSECURITY_DESCRIPTOR, 4) } static void test_pack_PSECURITY_QUALITY_OF_SERVICE(void) { /* PSECURITY_QUALITY_OF_SERVICE */ - TEST_TYPE(PSECURITY_QUALITY_OF_SERVICE, 4, 4); + TEST_TYPE_SIZE (PSECURITY_QUALITY_OF_SERVICE, 4) + TEST_TYPE_ALIGN (PSECURITY_QUALITY_OF_SERVICE, 4) } static void test_pack_PSID(void) { /* PSID */ - TEST_TYPE(PSID, 4, 4); + TEST_TYPE_SIZE (PSID, 4) + TEST_TYPE_ALIGN (PSID, 4) } static void test_pack_PSID_IDENTIFIER_AUTHORITY(void) { /* PSID_IDENTIFIER_AUTHORITY */ - TEST_TYPE(PSID_IDENTIFIER_AUTHORITY, 4, 4); - TEST_TYPE_POINTER(PSID_IDENTIFIER_AUTHORITY, 6, 1); + TEST_TYPE_SIZE (PSID_IDENTIFIER_AUTHORITY, 4) + TEST_TYPE_ALIGN (PSID_IDENTIFIER_AUTHORITY, 4) + TEST_TARGET_SIZE (PSID_IDENTIFIER_AUTHORITY, 6) + TEST_TARGET_ALIGN(PSID_IDENTIFIER_AUTHORITY, 1) } static void test_pack_PSINGLE_LIST_ENTRY(void) { /* PSINGLE_LIST_ENTRY */ - TEST_TYPE(PSINGLE_LIST_ENTRY, 4, 4); - TEST_TYPE_POINTER(PSINGLE_LIST_ENTRY, 4, 4); + TEST_TYPE_SIZE (PSINGLE_LIST_ENTRY, 4) + TEST_TYPE_ALIGN (PSINGLE_LIST_ENTRY, 4) + TEST_TARGET_SIZE (PSINGLE_LIST_ENTRY, 4) + TEST_TARGET_ALIGN(PSINGLE_LIST_ENTRY, 4) } static void test_pack_PSTR(void) { /* PSTR */ - TEST_TYPE(PSTR, 4, 4); - TEST_TYPE_POINTER(PSTR, 1, 1); + TEST_TYPE_SIZE (PSTR, 4) + TEST_TYPE_ALIGN (PSTR, 4) + TEST_TARGET_SIZE (PSTR, 1) + TEST_TARGET_ALIGN(PSTR, 1) } static void test_pack_PSYSTEM_ALARM_ACE(void) { /* PSYSTEM_ALARM_ACE */ - TEST_TYPE(PSYSTEM_ALARM_ACE, 4, 4); - TEST_TYPE_POINTER(PSYSTEM_ALARM_ACE, 12, 4); + TEST_TYPE_SIZE (PSYSTEM_ALARM_ACE, 4) + TEST_TYPE_ALIGN (PSYSTEM_ALARM_ACE, 4) + TEST_TARGET_SIZE (PSYSTEM_ALARM_ACE, 12) + TEST_TARGET_ALIGN(PSYSTEM_ALARM_ACE, 4) } static void test_pack_PSYSTEM_AUDIT_ACE(void) { /* PSYSTEM_AUDIT_ACE */ - TEST_TYPE(PSYSTEM_AUDIT_ACE, 4, 4); - TEST_TYPE_POINTER(PSYSTEM_AUDIT_ACE, 12, 4); + TEST_TYPE_SIZE (PSYSTEM_AUDIT_ACE, 4) + TEST_TYPE_ALIGN (PSYSTEM_AUDIT_ACE, 4) + TEST_TARGET_SIZE (PSYSTEM_AUDIT_ACE, 12) + TEST_TARGET_ALIGN(PSYSTEM_AUDIT_ACE, 4) } static void test_pack_PTOKEN_GROUPS(void) { /* PTOKEN_GROUPS */ - TEST_TYPE(PTOKEN_GROUPS, 4, 4); - TEST_TYPE_POINTER(PTOKEN_GROUPS, 12, 4); + TEST_TYPE_SIZE (PTOKEN_GROUPS, 4) + TEST_TYPE_ALIGN (PTOKEN_GROUPS, 4) + TEST_TARGET_SIZE (PTOKEN_GROUPS, 12) + TEST_TARGET_ALIGN(PTOKEN_GROUPS, 4) } static void test_pack_PTOKEN_PRIVILEGES(void) { /* PTOKEN_PRIVILEGES */ - TEST_TYPE(PTOKEN_PRIVILEGES, 4, 4); - TEST_TYPE_POINTER(PTOKEN_PRIVILEGES, 16, 4); + TEST_TYPE_SIZE (PTOKEN_PRIVILEGES, 4) + TEST_TYPE_ALIGN (PTOKEN_PRIVILEGES, 4) + TEST_TARGET_SIZE (PTOKEN_PRIVILEGES, 16) + TEST_TARGET_ALIGN(PTOKEN_PRIVILEGES, 4) } static void test_pack_PTOKEN_USER(void) { /* PTOKEN_USER */ - TEST_TYPE(PTOKEN_USER, 4, 4); - TEST_TYPE_POINTER(PTOKEN_USER, 8, 4); + TEST_TYPE_SIZE (PTOKEN_USER, 4) + TEST_TYPE_ALIGN (PTOKEN_USER, 4) + TEST_TARGET_SIZE (PTOKEN_USER, 8) + TEST_TARGET_ALIGN(PTOKEN_USER, 4) } static void test_pack_PTSTR(void) { /* PTSTR */ - TEST_TYPE(PTSTR, 4, 4); + TEST_TYPE_SIZE (PTSTR, 4) + TEST_TYPE_ALIGN (PTSTR, 4) } static void test_pack_PULARGE_INTEGER(void) { /* PULARGE_INTEGER */ - TEST_TYPE(PULARGE_INTEGER, 4, 4); + TEST_TYPE_SIZE (PULARGE_INTEGER, 4) + TEST_TYPE_ALIGN (PULARGE_INTEGER, 4) } static void test_pack_PVECTORED_EXCEPTION_HANDLER(void) { /* PVECTORED_EXCEPTION_HANDLER */ - TEST_TYPE(PVECTORED_EXCEPTION_HANDLER, 4, 4); + TEST_TYPE_SIZE (PVECTORED_EXCEPTION_HANDLER, 4) + TEST_TYPE_ALIGN (PVECTORED_EXCEPTION_HANDLER, 4) } static void test_pack_PVOID(void) { /* PVOID */ - TEST_TYPE(PVOID, 4, 4); + TEST_TYPE_SIZE (PVOID, 4) + TEST_TYPE_ALIGN (PVOID, 4) } static void test_pack_PWCH(void) { /* PWCH */ - TEST_TYPE(PWCH, 4, 4); - TEST_TYPE_POINTER(PWCH, 2, 2); + TEST_TYPE_SIZE (PWCH, 4) + TEST_TYPE_ALIGN (PWCH, 4) + TEST_TARGET_SIZE (PWCH, 2) + TEST_TARGET_ALIGN(PWCH, 2) } static void test_pack_PWSTR(void) { /* PWSTR */ - TEST_TYPE(PWSTR, 4, 4); - TEST_TYPE_POINTER(PWSTR, 2, 2); + TEST_TYPE_SIZE (PWSTR, 4) + TEST_TYPE_ALIGN (PWSTR, 4) + TEST_TARGET_SIZE (PWSTR, 2) + TEST_TARGET_ALIGN(PWSTR, 2) } static void test_pack_RTL_CRITICAL_SECTION(void) { /* RTL_CRITICAL_SECTION (pack 4) */ - TEST_TYPE(RTL_CRITICAL_SECTION, 24, 4); - TEST_FIELD(RTL_CRITICAL_SECTION, PRTL_CRITICAL_SECTION_DEBUG, DebugInfo, 0, 4, 4); - TEST_FIELD(RTL_CRITICAL_SECTION, LONG, LockCount, 4, 4, 4); - TEST_FIELD(RTL_CRITICAL_SECTION, LONG, RecursionCount, 8, 4, 4); - TEST_FIELD(RTL_CRITICAL_SECTION, HANDLE, OwningThread, 12, 4, 4); - TEST_FIELD(RTL_CRITICAL_SECTION, HANDLE, LockSemaphore, 16, 4, 4); - TEST_FIELD(RTL_CRITICAL_SECTION, ULONG_PTR, SpinCount, 20, 4, 4); + TEST_TYPE_SIZE (RTL_CRITICAL_SECTION, 24) + TEST_TYPE_ALIGN (RTL_CRITICAL_SECTION, 4) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION, DebugInfo, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION, DebugInfo, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION, DebugInfo, 0) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION, LockCount, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION, LockCount, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION, LockCount, 4) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION, RecursionCount, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION, RecursionCount, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION, RecursionCount, 8) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION, OwningThread, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION, OwningThread, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION, OwningThread, 12) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION, LockSemaphore, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION, LockSemaphore, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION, LockSemaphore, 16) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION, SpinCount, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION, SpinCount, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION, SpinCount, 20) } static void test_pack_RTL_CRITICAL_SECTION_DEBUG(void) { /* RTL_CRITICAL_SECTION_DEBUG (pack 4) */ - TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, WORD, Type, 0, 2, 2); - TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, WORD, CreatorBackTraceIndex, 2, 2, 2); - TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, struct _RTL_CRITICAL_SECTION *, CriticalSection, 4, 4, 4); - TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, LIST_ENTRY, ProcessLocksList, 8, 8, 4); - TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, DWORD, EntryCount, 16, 4, 4); - TEST_FIELD(RTL_CRITICAL_SECTION_DEBUG, DWORD, ContentionCount, 20, 4, 4); + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION_DEBUG, Type, 2) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION_DEBUG, Type, 2) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION_DEBUG, Type, 0) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION_DEBUG, CreatorBackTraceIndex, 2) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION_DEBUG, CreatorBackTraceIndex, 2) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION_DEBUG, CreatorBackTraceIndex, 2) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION_DEBUG, CriticalSection, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION_DEBUG, CriticalSection, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION_DEBUG, CriticalSection, 4) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION_DEBUG, ProcessLocksList, 8) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION_DEBUG, ProcessLocksList, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION_DEBUG, ProcessLocksList, 8) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION_DEBUG, EntryCount, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION_DEBUG, EntryCount, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION_DEBUG, EntryCount, 16) + TEST_FIELD_SIZE (RTL_CRITICAL_SECTION_DEBUG, ContentionCount, 4) + TEST_FIELD_ALIGN (RTL_CRITICAL_SECTION_DEBUG, ContentionCount, 4) + TEST_FIELD_OFFSET(RTL_CRITICAL_SECTION_DEBUG, ContentionCount, 20) } static void test_pack_RTL_OSVERSIONINFOEXW(void) { /* RTL_OSVERSIONINFOEXW (pack 4) */ - TEST_TYPE(RTL_OSVERSIONINFOEXW, 284, 4); - TEST_FIELD(RTL_OSVERSIONINFOEXW, DWORD, dwOSVersionInfoSize, 0, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOEXW, DWORD, dwMajorVersion, 4, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOEXW, DWORD, dwMinorVersion, 8, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOEXW, DWORD, dwBuildNumber, 12, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOEXW, DWORD, dwPlatformId, 16, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOEXW, WCHAR[128], szCSDVersion, 20, 256, 2); - TEST_FIELD(RTL_OSVERSIONINFOEXW, WORD, wServicePackMajor, 276, 2, 2); - TEST_FIELD(RTL_OSVERSIONINFOEXW, WORD, wServicePackMinor, 278, 2, 2); - TEST_FIELD(RTL_OSVERSIONINFOEXW, WORD, wSuiteMask, 280, 2, 2); - TEST_FIELD(RTL_OSVERSIONINFOEXW, BYTE, wProductType, 282, 1, 1); - TEST_FIELD(RTL_OSVERSIONINFOEXW, BYTE, wReserved, 283, 1, 1); + TEST_TYPE_SIZE (RTL_OSVERSIONINFOEXW, 284) + TEST_TYPE_ALIGN (RTL_OSVERSIONINFOEXW, 4) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, dwOSVersionInfoSize, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, dwOSVersionInfoSize, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, dwOSVersionInfoSize, 0) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, dwMajorVersion, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, dwMajorVersion, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, dwMajorVersion, 4) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, dwMinorVersion, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, dwMinorVersion, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, dwMinorVersion, 8) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, dwBuildNumber, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, dwBuildNumber, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, dwBuildNumber, 12) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, dwPlatformId, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, dwPlatformId, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, dwPlatformId, 16) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, szCSDVersion, 256) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, szCSDVersion, 2) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, szCSDVersion, 20) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, wServicePackMajor, 2) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, wServicePackMajor, 2) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, wServicePackMajor, 276) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, wServicePackMinor, 2) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, wServicePackMinor, 2) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, wServicePackMinor, 278) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, wSuiteMask, 2) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, wSuiteMask, 2) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, wSuiteMask, 280) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, wProductType, 1) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, wProductType, 1) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, wProductType, 282) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOEXW, wReserved, 1) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOEXW, wReserved, 1) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOEXW, wReserved, 283) } static void test_pack_RTL_OSVERSIONINFOW(void) { /* RTL_OSVERSIONINFOW (pack 4) */ - TEST_TYPE(RTL_OSVERSIONINFOW, 276, 4); - TEST_FIELD(RTL_OSVERSIONINFOW, DWORD, dwOSVersionInfoSize, 0, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOW, DWORD, dwMajorVersion, 4, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOW, DWORD, dwMinorVersion, 8, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOW, DWORD, dwBuildNumber, 12, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOW, DWORD, dwPlatformId, 16, 4, 4); - TEST_FIELD(RTL_OSVERSIONINFOW, WCHAR[128], szCSDVersion, 20, 256, 2); + TEST_TYPE_SIZE (RTL_OSVERSIONINFOW, 276) + TEST_TYPE_ALIGN (RTL_OSVERSIONINFOW, 4) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOW, dwOSVersionInfoSize, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOW, dwOSVersionInfoSize, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOW, dwOSVersionInfoSize, 0) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOW, dwMajorVersion, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOW, dwMajorVersion, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOW, dwMajorVersion, 4) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOW, dwMinorVersion, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOW, dwMinorVersion, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOW, dwMinorVersion, 8) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOW, dwBuildNumber, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOW, dwBuildNumber, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOW, dwBuildNumber, 12) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOW, dwPlatformId, 4) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOW, dwPlatformId, 4) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOW, dwPlatformId, 16) + TEST_FIELD_SIZE (RTL_OSVERSIONINFOW, szCSDVersion, 256) + TEST_FIELD_ALIGN (RTL_OSVERSIONINFOW, szCSDVersion, 2) + TEST_FIELD_OFFSET(RTL_OSVERSIONINFOW, szCSDVersion, 20) } static void test_pack_RTL_RESOURCE_DEBUG(void) { /* RTL_RESOURCE_DEBUG (pack 4) */ - TEST_FIELD(RTL_RESOURCE_DEBUG, WORD, Type, 0, 2, 2); - TEST_FIELD(RTL_RESOURCE_DEBUG, WORD, CreatorBackTraceIndex, 2, 2, 2); - TEST_FIELD(RTL_RESOURCE_DEBUG, struct _RTL_CRITICAL_SECTION *, CriticalSection, 4, 4, 4); - TEST_FIELD(RTL_RESOURCE_DEBUG, LIST_ENTRY, ProcessLocksList, 8, 8, 4); - TEST_FIELD(RTL_RESOURCE_DEBUG, DWORD, EntryCount, 16, 4, 4); - TEST_FIELD(RTL_RESOURCE_DEBUG, DWORD, ContentionCount, 20, 4, 4); + TEST_FIELD_SIZE (RTL_RESOURCE_DEBUG, Type, 2) + TEST_FIELD_ALIGN (RTL_RESOURCE_DEBUG, Type, 2) + TEST_FIELD_OFFSET(RTL_RESOURCE_DEBUG, Type, 0) + TEST_FIELD_SIZE (RTL_RESOURCE_DEBUG, CreatorBackTraceIndex, 2) + TEST_FIELD_ALIGN (RTL_RESOURCE_DEBUG, CreatorBackTraceIndex, 2) + TEST_FIELD_OFFSET(RTL_RESOURCE_DEBUG, CreatorBackTraceIndex, 2) + TEST_FIELD_SIZE (RTL_RESOURCE_DEBUG, CriticalSection, 4) + TEST_FIELD_ALIGN (RTL_RESOURCE_DEBUG, CriticalSection, 4) + TEST_FIELD_OFFSET(RTL_RESOURCE_DEBUG, CriticalSection, 4) + TEST_FIELD_SIZE (RTL_RESOURCE_DEBUG, ProcessLocksList, 8) + TEST_FIELD_ALIGN (RTL_RESOURCE_DEBUG, ProcessLocksList, 4) + TEST_FIELD_OFFSET(RTL_RESOURCE_DEBUG, ProcessLocksList, 8) + TEST_FIELD_SIZE (RTL_RESOURCE_DEBUG, EntryCount, 4) + TEST_FIELD_ALIGN (RTL_RESOURCE_DEBUG, EntryCount, 4) + TEST_FIELD_OFFSET(RTL_RESOURCE_DEBUG, EntryCount, 16) + TEST_FIELD_SIZE (RTL_RESOURCE_DEBUG, ContentionCount, 4) + TEST_FIELD_ALIGN (RTL_RESOURCE_DEBUG, ContentionCount, 4) + TEST_FIELD_OFFSET(RTL_RESOURCE_DEBUG, ContentionCount, 20) } static void test_pack_SECURITY_CONTEXT_TRACKING_MODE(void) { /* SECURITY_CONTEXT_TRACKING_MODE */ - TEST_TYPE(SECURITY_CONTEXT_TRACKING_MODE, 1, 1); + TEST_TYPE_SIZE (SECURITY_CONTEXT_TRACKING_MODE, 1) + TEST_TYPE_ALIGN (SECURITY_CONTEXT_TRACKING_MODE, 1) } static void test_pack_SECURITY_DESCRIPTOR(void) { /* SECURITY_DESCRIPTOR (pack 4) */ - TEST_TYPE(SECURITY_DESCRIPTOR, 20, 4); - TEST_FIELD(SECURITY_DESCRIPTOR, BYTE, Revision, 0, 1, 1); - TEST_FIELD(SECURITY_DESCRIPTOR, BYTE, Sbz1, 1, 1, 1); - TEST_FIELD(SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, Control, 2, 2, 2); - TEST_FIELD(SECURITY_DESCRIPTOR, PSID, Owner, 4, 4, 4); - TEST_FIELD(SECURITY_DESCRIPTOR, PSID, Group, 8, 4, 4); - TEST_FIELD(SECURITY_DESCRIPTOR, PACL, Sacl, 12, 4, 4); - TEST_FIELD(SECURITY_DESCRIPTOR, PACL, Dacl, 16, 4, 4); + TEST_TYPE_SIZE (SECURITY_DESCRIPTOR, 20) + TEST_TYPE_ALIGN (SECURITY_DESCRIPTOR, 4) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR, Revision, 1) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR, Revision, 1) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR, Revision, 0) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR, Sbz1, 1) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR, Sbz1, 1) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR, Sbz1, 1) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR, Control, 2) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR, Control, 2) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR, Control, 2) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR, Owner, 4) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR, Owner, 4) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR, Owner, 4) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR, Group, 4) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR, Group, 4) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR, Group, 8) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR, Sacl, 4) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR, Sacl, 4) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR, Sacl, 12) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR, Dacl, 4) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR, Dacl, 4) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR, Dacl, 16) } static void test_pack_SECURITY_DESCRIPTOR_CONTROL(void) { /* SECURITY_DESCRIPTOR_CONTROL */ - TEST_TYPE(SECURITY_DESCRIPTOR_CONTROL, 2, 2); - TEST_TYPE_UNSIGNED(SECURITY_DESCRIPTOR_CONTROL); + TEST_TYPE_SIZE (SECURITY_DESCRIPTOR_CONTROL, 2) + TEST_TYPE_ALIGN (SECURITY_DESCRIPTOR_CONTROL, 2) + TEST_TYPE_UNSIGNED(SECURITY_DESCRIPTOR_CONTROL) } static void test_pack_SECURITY_DESCRIPTOR_RELATIVE(void) { /* SECURITY_DESCRIPTOR_RELATIVE (pack 4) */ - TEST_TYPE(SECURITY_DESCRIPTOR_RELATIVE, 20, 4); - TEST_FIELD(SECURITY_DESCRIPTOR_RELATIVE, BYTE, Revision, 0, 1, 1); - TEST_FIELD(SECURITY_DESCRIPTOR_RELATIVE, BYTE, Sbz1, 1, 1, 1); - TEST_FIELD(SECURITY_DESCRIPTOR_RELATIVE, SECURITY_DESCRIPTOR_CONTROL, Control, 2, 2, 2); - TEST_FIELD(SECURITY_DESCRIPTOR_RELATIVE, DWORD, Owner, 4, 4, 4); - TEST_FIELD(SECURITY_DESCRIPTOR_RELATIVE, DWORD, Group, 8, 4, 4); - TEST_FIELD(SECURITY_DESCRIPTOR_RELATIVE, DWORD, Sacl, 12, 4, 4); - TEST_FIELD(SECURITY_DESCRIPTOR_RELATIVE, DWORD, Dacl, 16, 4, 4); + TEST_TYPE_SIZE (SECURITY_DESCRIPTOR_RELATIVE, 20) + TEST_TYPE_ALIGN (SECURITY_DESCRIPTOR_RELATIVE, 4) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR_RELATIVE, Revision, 1) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR_RELATIVE, Revision, 1) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Revision, 0) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR_RELATIVE, Sbz1, 1) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR_RELATIVE, Sbz1, 1) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Sbz1, 1) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR_RELATIVE, Control, 2) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR_RELATIVE, Control, 2) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Control, 2) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR_RELATIVE, Owner, 4) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR_RELATIVE, Owner, 4) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Owner, 4) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR_RELATIVE, Group, 4) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR_RELATIVE, Group, 4) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Group, 8) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR_RELATIVE, Sacl, 4) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR_RELATIVE, Sacl, 4) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Sacl, 12) + TEST_FIELD_SIZE (SECURITY_DESCRIPTOR_RELATIVE, Dacl, 4) + TEST_FIELD_ALIGN (SECURITY_DESCRIPTOR_RELATIVE, Dacl, 4) + TEST_FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Dacl, 16) } static void test_pack_SECURITY_INFORMATION(void) { /* SECURITY_INFORMATION */ - TEST_TYPE(SECURITY_INFORMATION, 4, 4); - TEST_TYPE_UNSIGNED(SECURITY_INFORMATION); + TEST_TYPE_SIZE (SECURITY_INFORMATION, 4) + TEST_TYPE_ALIGN (SECURITY_INFORMATION, 4) + TEST_TYPE_UNSIGNED(SECURITY_INFORMATION) } static void test_pack_SECURITY_QUALITY_OF_SERVICE(void) { /* SECURITY_QUALITY_OF_SERVICE (pack 4) */ - TEST_FIELD(SECURITY_QUALITY_OF_SERVICE, DWORD, Length, 0, 4, 4); + TEST_FIELD_SIZE (SECURITY_QUALITY_OF_SERVICE, Length, 4) + TEST_FIELD_ALIGN (SECURITY_QUALITY_OF_SERVICE, Length, 4) + TEST_FIELD_OFFSET(SECURITY_QUALITY_OF_SERVICE, Length, 0) } static void test_pack_SHORT(void) { /* SHORT */ - TEST_TYPE(SHORT, 2, 2); - TEST_TYPE_SIGNED(SHORT); + TEST_TYPE_SIZE (SHORT, 2) + TEST_TYPE_ALIGN (SHORT, 2) + TEST_TYPE_SIGNED(SHORT) } static void test_pack_SID(void) { /* SID (pack 4) */ - TEST_TYPE(SID, 12, 4); - TEST_FIELD(SID, BYTE, Revision, 0, 1, 1); - TEST_FIELD(SID, BYTE, SubAuthorityCount, 1, 1, 1); - TEST_FIELD(SID, SID_IDENTIFIER_AUTHORITY, IdentifierAuthority, 2, 6, 1); - TEST_FIELD(SID, DWORD[1], SubAuthority, 8, 4, 4); + TEST_TYPE_SIZE (SID, 12) + TEST_TYPE_ALIGN (SID, 4) + TEST_FIELD_SIZE (SID, Revision, 1) + TEST_FIELD_ALIGN (SID, Revision, 1) + TEST_FIELD_OFFSET(SID, Revision, 0) + TEST_FIELD_SIZE (SID, SubAuthorityCount, 1) + TEST_FIELD_ALIGN (SID, SubAuthorityCount, 1) + TEST_FIELD_OFFSET(SID, SubAuthorityCount, 1) + TEST_FIELD_SIZE (SID, IdentifierAuthority, 6) + TEST_FIELD_ALIGN (SID, IdentifierAuthority, 1) + TEST_FIELD_OFFSET(SID, IdentifierAuthority, 2) + TEST_FIELD_SIZE (SID, SubAuthority, 4) + TEST_FIELD_ALIGN (SID, SubAuthority, 4) + TEST_FIELD_OFFSET(SID, SubAuthority, 8) } static void test_pack_SID_AND_ATTRIBUTES(void) { /* SID_AND_ATTRIBUTES (pack 4) */ - TEST_TYPE(SID_AND_ATTRIBUTES, 8, 4); - TEST_FIELD(SID_AND_ATTRIBUTES, PSID, Sid, 0, 4, 4); - TEST_FIELD(SID_AND_ATTRIBUTES, DWORD, Attributes, 4, 4, 4); + TEST_TYPE_SIZE (SID_AND_ATTRIBUTES, 8) + TEST_TYPE_ALIGN (SID_AND_ATTRIBUTES, 4) + TEST_FIELD_SIZE (SID_AND_ATTRIBUTES, Sid, 4) + TEST_FIELD_ALIGN (SID_AND_ATTRIBUTES, Sid, 4) + TEST_FIELD_OFFSET(SID_AND_ATTRIBUTES, Sid, 0) + TEST_FIELD_SIZE (SID_AND_ATTRIBUTES, Attributes, 4) + TEST_FIELD_ALIGN (SID_AND_ATTRIBUTES, Attributes, 4) + TEST_FIELD_OFFSET(SID_AND_ATTRIBUTES, Attributes, 4) } static void test_pack_SID_IDENTIFIER_AUTHORITY(void) { /* SID_IDENTIFIER_AUTHORITY (pack 4) */ - TEST_TYPE(SID_IDENTIFIER_AUTHORITY, 6, 1); - TEST_FIELD(SID_IDENTIFIER_AUTHORITY, BYTE[6], Value, 0, 6, 1); + TEST_TYPE_SIZE (SID_IDENTIFIER_AUTHORITY, 6) + TEST_TYPE_ALIGN (SID_IDENTIFIER_AUTHORITY, 1) + TEST_FIELD_SIZE (SID_IDENTIFIER_AUTHORITY, Value, 6) + TEST_FIELD_ALIGN (SID_IDENTIFIER_AUTHORITY, Value, 1) + TEST_FIELD_OFFSET(SID_IDENTIFIER_AUTHORITY, Value, 0) } static void test_pack_SINGLE_LIST_ENTRY(void) { /* SINGLE_LIST_ENTRY (pack 4) */ - TEST_TYPE(SINGLE_LIST_ENTRY, 4, 4); - TEST_FIELD(SINGLE_LIST_ENTRY, struct _SINGLE_LIST_ENTRY *, Next, 0, 4, 4); + TEST_TYPE_SIZE (SINGLE_LIST_ENTRY, 4) + TEST_TYPE_ALIGN (SINGLE_LIST_ENTRY, 4) + TEST_FIELD_SIZE (SINGLE_LIST_ENTRY, Next, 4) + TEST_FIELD_ALIGN (SINGLE_LIST_ENTRY, Next, 4) + TEST_FIELD_OFFSET(SINGLE_LIST_ENTRY, Next, 0) } static void test_pack_SYSTEM_ALARM_ACE(void) { /* SYSTEM_ALARM_ACE (pack 4) */ - TEST_TYPE(SYSTEM_ALARM_ACE, 12, 4); - TEST_FIELD(SYSTEM_ALARM_ACE, ACE_HEADER, Header, 0, 4, 2); - TEST_FIELD(SYSTEM_ALARM_ACE, DWORD, Mask, 4, 4, 4); - TEST_FIELD(SYSTEM_ALARM_ACE, DWORD, SidStart, 8, 4, 4); + TEST_TYPE_SIZE (SYSTEM_ALARM_ACE, 12) + TEST_TYPE_ALIGN (SYSTEM_ALARM_ACE, 4) + TEST_FIELD_SIZE (SYSTEM_ALARM_ACE, Header, 4) + TEST_FIELD_ALIGN (SYSTEM_ALARM_ACE, Header, 2) + TEST_FIELD_OFFSET(SYSTEM_ALARM_ACE, Header, 0) + TEST_FIELD_SIZE (SYSTEM_ALARM_ACE, Mask, 4) + TEST_FIELD_ALIGN (SYSTEM_ALARM_ACE, Mask, 4) + TEST_FIELD_OFFSET(SYSTEM_ALARM_ACE, Mask, 4) + TEST_FIELD_SIZE (SYSTEM_ALARM_ACE, SidStart, 4) + TEST_FIELD_ALIGN (SYSTEM_ALARM_ACE, SidStart, 4) + TEST_FIELD_OFFSET(SYSTEM_ALARM_ACE, SidStart, 8) } static void test_pack_SYSTEM_AUDIT_ACE(void) { /* SYSTEM_AUDIT_ACE (pack 4) */ - TEST_TYPE(SYSTEM_AUDIT_ACE, 12, 4); - TEST_FIELD(SYSTEM_AUDIT_ACE, ACE_HEADER, Header, 0, 4, 2); - TEST_FIELD(SYSTEM_AUDIT_ACE, DWORD, Mask, 4, 4, 4); - TEST_FIELD(SYSTEM_AUDIT_ACE, DWORD, SidStart, 8, 4, 4); + TEST_TYPE_SIZE (SYSTEM_AUDIT_ACE, 12) + TEST_TYPE_ALIGN (SYSTEM_AUDIT_ACE, 4) + TEST_FIELD_SIZE (SYSTEM_AUDIT_ACE, Header, 4) + TEST_FIELD_ALIGN (SYSTEM_AUDIT_ACE, Header, 2) + TEST_FIELD_OFFSET(SYSTEM_AUDIT_ACE, Header, 0) + TEST_FIELD_SIZE (SYSTEM_AUDIT_ACE, Mask, 4) + TEST_FIELD_ALIGN (SYSTEM_AUDIT_ACE, Mask, 4) + TEST_FIELD_OFFSET(SYSTEM_AUDIT_ACE, Mask, 4) + TEST_FIELD_SIZE (SYSTEM_AUDIT_ACE, SidStart, 4) + TEST_FIELD_ALIGN (SYSTEM_AUDIT_ACE, SidStart, 4) + TEST_FIELD_OFFSET(SYSTEM_AUDIT_ACE, SidStart, 8) } static void test_pack_TCHAR(void) { /* TCHAR */ - TEST_TYPE(TCHAR, 1, 1); + TEST_TYPE_SIZE (TCHAR, 1) + TEST_TYPE_ALIGN (TCHAR, 1) } static void test_pack_TOKEN_DEFAULT_DACL(void) { /* TOKEN_DEFAULT_DACL (pack 4) */ - TEST_TYPE(TOKEN_DEFAULT_DACL, 4, 4); - TEST_FIELD(TOKEN_DEFAULT_DACL, PACL, DefaultDacl, 0, 4, 4); + TEST_TYPE_SIZE (TOKEN_DEFAULT_DACL, 4) + TEST_TYPE_ALIGN (TOKEN_DEFAULT_DACL, 4) + TEST_FIELD_SIZE (TOKEN_DEFAULT_DACL, DefaultDacl, 4) + TEST_FIELD_ALIGN (TOKEN_DEFAULT_DACL, DefaultDacl, 4) + TEST_FIELD_OFFSET(TOKEN_DEFAULT_DACL, DefaultDacl, 0) } static void test_pack_TOKEN_GROUPS(void) { /* TOKEN_GROUPS (pack 4) */ - TEST_TYPE(TOKEN_GROUPS, 12, 4); - TEST_FIELD(TOKEN_GROUPS, DWORD, GroupCount, 0, 4, 4); - TEST_FIELD(TOKEN_GROUPS, SID_AND_ATTRIBUTES[ANYSIZE_ARRAY], Groups, 4, 8, 4); + TEST_TYPE_SIZE (TOKEN_GROUPS, 12) + TEST_TYPE_ALIGN (TOKEN_GROUPS, 4) + TEST_FIELD_SIZE (TOKEN_GROUPS, GroupCount, 4) + TEST_FIELD_ALIGN (TOKEN_GROUPS, GroupCount, 4) + TEST_FIELD_OFFSET(TOKEN_GROUPS, GroupCount, 0) + TEST_FIELD_SIZE (TOKEN_GROUPS, Groups, 8) + TEST_FIELD_ALIGN (TOKEN_GROUPS, Groups, 4) + TEST_FIELD_OFFSET(TOKEN_GROUPS, Groups, 4) } static void test_pack_TOKEN_OWNER(void) { /* TOKEN_OWNER (pack 4) */ - TEST_TYPE(TOKEN_OWNER, 4, 4); - TEST_FIELD(TOKEN_OWNER, PSID, Owner, 0, 4, 4); + TEST_TYPE_SIZE (TOKEN_OWNER, 4) + TEST_TYPE_ALIGN (TOKEN_OWNER, 4) + TEST_FIELD_SIZE (TOKEN_OWNER, Owner, 4) + TEST_FIELD_ALIGN (TOKEN_OWNER, Owner, 4) + TEST_FIELD_OFFSET(TOKEN_OWNER, Owner, 0) } static void test_pack_TOKEN_PRIMARY_GROUP(void) { /* TOKEN_PRIMARY_GROUP (pack 4) */ - TEST_TYPE(TOKEN_PRIMARY_GROUP, 4, 4); - TEST_FIELD(TOKEN_PRIMARY_GROUP, PSID, PrimaryGroup, 0, 4, 4); + TEST_TYPE_SIZE (TOKEN_PRIMARY_GROUP, 4) + TEST_TYPE_ALIGN (TOKEN_PRIMARY_GROUP, 4) + TEST_FIELD_SIZE (TOKEN_PRIMARY_GROUP, PrimaryGroup, 4) + TEST_FIELD_ALIGN (TOKEN_PRIMARY_GROUP, PrimaryGroup, 4) + TEST_FIELD_OFFSET(TOKEN_PRIMARY_GROUP, PrimaryGroup, 0) } static void test_pack_TOKEN_PRIVILEGES(void) { /* TOKEN_PRIVILEGES (pack 4) */ - TEST_TYPE(TOKEN_PRIVILEGES, 16, 4); - TEST_FIELD(TOKEN_PRIVILEGES, DWORD, PrivilegeCount, 0, 4, 4); - TEST_FIELD(TOKEN_PRIVILEGES, LUID_AND_ATTRIBUTES[ANYSIZE_ARRAY], Privileges, 4, 12, 4); + TEST_TYPE_SIZE (TOKEN_PRIVILEGES, 16) + TEST_TYPE_ALIGN (TOKEN_PRIVILEGES, 4) + TEST_FIELD_SIZE (TOKEN_PRIVILEGES, PrivilegeCount, 4) + TEST_FIELD_ALIGN (TOKEN_PRIVILEGES, PrivilegeCount, 4) + TEST_FIELD_OFFSET(TOKEN_PRIVILEGES, PrivilegeCount, 0) + TEST_FIELD_SIZE (TOKEN_PRIVILEGES, Privileges, 12) + TEST_FIELD_ALIGN (TOKEN_PRIVILEGES, Privileges, 4) + TEST_FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges, 4) } static void test_pack_TOKEN_SOURCE(void) { /* TOKEN_SOURCE (pack 4) */ - TEST_TYPE(TOKEN_SOURCE, 16, 4); - TEST_FIELD(TOKEN_SOURCE, char[TOKEN_SOURCE_LENGTH], SourceName, 0, 8, 1); - TEST_FIELD(TOKEN_SOURCE, LUID, SourceIdentifier, 8, 8, 4); + TEST_TYPE_SIZE (TOKEN_SOURCE, 16) + TEST_TYPE_ALIGN (TOKEN_SOURCE, 4) + TEST_FIELD_SIZE (TOKEN_SOURCE, SourceName, 8) + TEST_FIELD_ALIGN (TOKEN_SOURCE, SourceName, 1) + TEST_FIELD_OFFSET(TOKEN_SOURCE, SourceName, 0) + TEST_FIELD_SIZE (TOKEN_SOURCE, SourceIdentifier, 8) + TEST_FIELD_ALIGN (TOKEN_SOURCE, SourceIdentifier, 4) + TEST_FIELD_OFFSET(TOKEN_SOURCE, SourceIdentifier, 8) } static void test_pack_TOKEN_STATISTICS(void) { /* TOKEN_STATISTICS (pack 4) */ - TEST_FIELD(TOKEN_STATISTICS, LUID, TokenId, 0, 8, 4); - TEST_FIELD(TOKEN_STATISTICS, LUID, AuthenticationId, 8, 8, 4); - TEST_FIELD(TOKEN_STATISTICS, LARGE_INTEGER, ExpirationTime, 16, 8, 4); + TEST_FIELD_SIZE (TOKEN_STATISTICS, TokenId, 8) + TEST_FIELD_ALIGN (TOKEN_STATISTICS, TokenId, 4) + TEST_FIELD_OFFSET(TOKEN_STATISTICS, TokenId, 0) + TEST_FIELD_SIZE (TOKEN_STATISTICS, AuthenticationId, 8) + TEST_FIELD_ALIGN (TOKEN_STATISTICS, AuthenticationId, 4) + TEST_FIELD_OFFSET(TOKEN_STATISTICS, AuthenticationId, 8) + TEST_FIELD_SIZE (TOKEN_STATISTICS, ExpirationTime, 8) + TEST_FIELD_ALIGN (TOKEN_STATISTICS, ExpirationTime, 4) + TEST_FIELD_OFFSET(TOKEN_STATISTICS, ExpirationTime, 16) } static void test_pack_TOKEN_USER(void) { /* TOKEN_USER (pack 4) */ - TEST_TYPE(TOKEN_USER, 8, 4); - TEST_FIELD(TOKEN_USER, SID_AND_ATTRIBUTES, User, 0, 8, 4); + TEST_TYPE_SIZE (TOKEN_USER, 8) + TEST_TYPE_ALIGN (TOKEN_USER, 4) + TEST_FIELD_SIZE (TOKEN_USER, User, 8) + TEST_FIELD_ALIGN (TOKEN_USER, User, 4) + TEST_FIELD_OFFSET(TOKEN_USER, User, 0) } static void test_pack_ULARGE_INTEGER(void) @@ -1807,324 +2770,408 @@ static void test_pack_ULARGE_INTEGER(void) static void test_pack_ULONGLONG(void) { /* ULONGLONG */ - TEST_TYPE(ULONGLONG, 8, 8); - TEST_TYPE_UNSIGNED(ULONGLONG); + TEST_TYPE_SIZE (ULONGLONG, 8) + TEST_TYPE_ALIGN (ULONGLONG, 8) + TEST_TYPE_UNSIGNED(ULONGLONG) } static void test_pack_WAITORTIMERCALLBACKFUNC(void) { /* WAITORTIMERCALLBACKFUNC */ - TEST_TYPE(WAITORTIMERCALLBACKFUNC, 4, 4); + TEST_TYPE_SIZE (WAITORTIMERCALLBACKFUNC, 4) + TEST_TYPE_ALIGN (WAITORTIMERCALLBACKFUNC, 4) } static void test_pack_WCHAR(void) { /* WCHAR */ - TEST_TYPE(WCHAR, 2, 2); - TEST_TYPE_UNSIGNED(WCHAR); + TEST_TYPE_SIZE (WCHAR, 2) + TEST_TYPE_ALIGN (WCHAR, 2) + TEST_TYPE_UNSIGNED(WCHAR) } static void test_pack_ATOM(void) { /* ATOM */ - TEST_TYPE(ATOM, 2, 2); - TEST_TYPE_UNSIGNED(ATOM); + TEST_TYPE_SIZE (ATOM, 2) + TEST_TYPE_ALIGN (ATOM, 2) + TEST_TYPE_UNSIGNED(ATOM) } static void test_pack_BOOL(void) { /* BOOL */ - TEST_TYPE(BOOL, 4, 4); - TEST_TYPE_SIGNED(BOOL); + TEST_TYPE_SIZE (BOOL, 4) + TEST_TYPE_ALIGN (BOOL, 4) + TEST_TYPE_SIGNED(BOOL) } static void test_pack_BYTE(void) { /* BYTE */ - TEST_TYPE(BYTE, 1, 1); - TEST_TYPE_UNSIGNED(BYTE); + TEST_TYPE_SIZE (BYTE, 1) + TEST_TYPE_ALIGN (BYTE, 1) + TEST_TYPE_UNSIGNED(BYTE) } static void test_pack_COLORREF(void) { /* COLORREF */ - TEST_TYPE(COLORREF, 4, 4); - TEST_TYPE_UNSIGNED(COLORREF); + TEST_TYPE_SIZE (COLORREF, 4) + TEST_TYPE_ALIGN (COLORREF, 4) + TEST_TYPE_UNSIGNED(COLORREF) } static void test_pack_DWORD(void) { /* DWORD */ - TEST_TYPE(DWORD, 4, 4); - TEST_TYPE_UNSIGNED(DWORD); + TEST_TYPE_SIZE (DWORD, 4) + TEST_TYPE_ALIGN (DWORD, 4) + TEST_TYPE_UNSIGNED(DWORD) } static void test_pack_FARPROC(void) { /* FARPROC */ - TEST_TYPE(FARPROC, 4, 4); + TEST_TYPE_SIZE (FARPROC, 4) + TEST_TYPE_ALIGN (FARPROC, 4) } static void test_pack_FLOAT(void) { /* FLOAT */ - TEST_TYPE(FLOAT, 4, 4); + TEST_TYPE_SIZE (FLOAT, 4) + TEST_TYPE_ALIGN (FLOAT, 4) } static void test_pack_GLOBALHANDLE(void) { /* GLOBALHANDLE */ - TEST_TYPE(GLOBALHANDLE, 4, 4); + TEST_TYPE_SIZE (GLOBALHANDLE, 4) + TEST_TYPE_ALIGN (GLOBALHANDLE, 4) } static void test_pack_HCURSOR(void) { /* HCURSOR */ - TEST_TYPE(HCURSOR, 4, 4); - TEST_TYPE_UNSIGNED(HCURSOR); + TEST_TYPE_SIZE (HCURSOR, 4) + TEST_TYPE_ALIGN (HCURSOR, 4) } static void test_pack_HFILE(void) { /* HFILE */ - TEST_TYPE(HFILE, 4, 4); - TEST_TYPE_SIGNED(HFILE); + TEST_TYPE_SIZE (HFILE, 4) + TEST_TYPE_ALIGN (HFILE, 4) + TEST_TYPE_SIGNED(HFILE) } static void test_pack_HGDIOBJ(void) { /* HGDIOBJ */ - TEST_TYPE(HGDIOBJ, 4, 4); + TEST_TYPE_SIZE (HGDIOBJ, 4) + TEST_TYPE_ALIGN (HGDIOBJ, 4) } static void test_pack_HGLOBAL(void) { /* HGLOBAL */ - TEST_TYPE(HGLOBAL, 4, 4); + TEST_TYPE_SIZE (HGLOBAL, 4) + TEST_TYPE_ALIGN (HGLOBAL, 4) } static void test_pack_HLOCAL(void) { /* HLOCAL */ - TEST_TYPE(HLOCAL, 4, 4); + TEST_TYPE_SIZE (HLOCAL, 4) + TEST_TYPE_ALIGN (HLOCAL, 4) } static void test_pack_HMODULE(void) { /* HMODULE */ - TEST_TYPE(HMODULE, 4, 4); - TEST_TYPE_UNSIGNED(HMODULE); + TEST_TYPE_SIZE (HMODULE, 4) + TEST_TYPE_ALIGN (HMODULE, 4) } static void test_pack_INT(void) { /* INT */ - TEST_TYPE(INT, 4, 4); - TEST_TYPE_SIGNED(INT); + TEST_TYPE_SIZE (INT, 4) + TEST_TYPE_ALIGN (INT, 4) + TEST_TYPE_SIGNED(INT) } static void test_pack_LOCALHANDLE(void) { /* LOCALHANDLE */ - TEST_TYPE(LOCALHANDLE, 4, 4); + TEST_TYPE_SIZE (LOCALHANDLE, 4) + TEST_TYPE_ALIGN (LOCALHANDLE, 4) } static void test_pack_LPARAM(void) { /* LPARAM */ - TEST_TYPE(LPARAM, 4, 4); + TEST_TYPE_SIZE (LPARAM, 4) + TEST_TYPE_ALIGN (LPARAM, 4) } static void test_pack_LPCRECT(void) { /* LPCRECT */ - TEST_TYPE(LPCRECT, 4, 4); - TEST_TYPE_POINTER(LPCRECT, 16, 4); + TEST_TYPE_SIZE (LPCRECT, 4) + TEST_TYPE_ALIGN (LPCRECT, 4) + TEST_TARGET_SIZE (LPCRECT, 16) + TEST_TARGET_ALIGN(LPCRECT, 4) } static void test_pack_LPCRECTL(void) { /* LPCRECTL */ - TEST_TYPE(LPCRECTL, 4, 4); - TEST_TYPE_POINTER(LPCRECTL, 16, 4); + TEST_TYPE_SIZE (LPCRECTL, 4) + TEST_TYPE_ALIGN (LPCRECTL, 4) + TEST_TARGET_SIZE (LPCRECTL, 16) + TEST_TARGET_ALIGN(LPCRECTL, 4) } static void test_pack_LPCVOID(void) { /* LPCVOID */ - TEST_TYPE(LPCVOID, 4, 4); + TEST_TYPE_SIZE (LPCVOID, 4) + TEST_TYPE_ALIGN (LPCVOID, 4) } static void test_pack_LPPOINT(void) { /* LPPOINT */ - TEST_TYPE(LPPOINT, 4, 4); - TEST_TYPE_POINTER(LPPOINT, 8, 4); + TEST_TYPE_SIZE (LPPOINT, 4) + TEST_TYPE_ALIGN (LPPOINT, 4) + TEST_TARGET_SIZE (LPPOINT, 8) + TEST_TARGET_ALIGN(LPPOINT, 4) } static void test_pack_LPRECT(void) { /* LPRECT */ - TEST_TYPE(LPRECT, 4, 4); - TEST_TYPE_POINTER(LPRECT, 16, 4); + TEST_TYPE_SIZE (LPRECT, 4) + TEST_TYPE_ALIGN (LPRECT, 4) + TEST_TARGET_SIZE (LPRECT, 16) + TEST_TARGET_ALIGN(LPRECT, 4) } static void test_pack_LPRECTL(void) { /* LPRECTL */ - TEST_TYPE(LPRECTL, 4, 4); - TEST_TYPE_POINTER(LPRECTL, 16, 4); + TEST_TYPE_SIZE (LPRECTL, 4) + TEST_TYPE_ALIGN (LPRECTL, 4) + TEST_TARGET_SIZE (LPRECTL, 16) + TEST_TARGET_ALIGN(LPRECTL, 4) } static void test_pack_LPSIZE(void) { /* LPSIZE */ - TEST_TYPE(LPSIZE, 4, 4); - TEST_TYPE_POINTER(LPSIZE, 8, 4); + TEST_TYPE_SIZE (LPSIZE, 4) + TEST_TYPE_ALIGN (LPSIZE, 4) + TEST_TARGET_SIZE (LPSIZE, 8) + TEST_TARGET_ALIGN(LPSIZE, 4) } static void test_pack_LRESULT(void) { /* LRESULT */ - TEST_TYPE(LRESULT, 4, 4); + TEST_TYPE_SIZE (LRESULT, 4) + TEST_TYPE_ALIGN (LRESULT, 4) } static void test_pack_POINT(void) { /* POINT (pack 4) */ - TEST_TYPE(POINT, 8, 4); - TEST_FIELD(POINT, LONG, x, 0, 4, 4); - TEST_FIELD(POINT, LONG, y, 4, 4, 4); + TEST_TYPE_SIZE (POINT, 8) + TEST_TYPE_ALIGN (POINT, 4) + TEST_FIELD_SIZE (POINT, x, 4) + TEST_FIELD_ALIGN (POINT, x, 4) + TEST_FIELD_OFFSET(POINT, x, 0) + TEST_FIELD_SIZE (POINT, y, 4) + TEST_FIELD_ALIGN (POINT, y, 4) + TEST_FIELD_OFFSET(POINT, y, 4) } static void test_pack_POINTL(void) { /* POINTL (pack 4) */ - TEST_TYPE(POINTL, 8, 4); - TEST_FIELD(POINTL, LONG, x, 0, 4, 4); - TEST_FIELD(POINTL, LONG, y, 4, 4, 4); + TEST_TYPE_SIZE (POINTL, 8) + TEST_TYPE_ALIGN (POINTL, 4) + TEST_FIELD_SIZE (POINTL, x, 4) + TEST_FIELD_ALIGN (POINTL, x, 4) + TEST_FIELD_OFFSET(POINTL, x, 0) + TEST_FIELD_SIZE (POINTL, y, 4) + TEST_FIELD_ALIGN (POINTL, y, 4) + TEST_FIELD_OFFSET(POINTL, y, 4) } static void test_pack_PPOINT(void) { /* PPOINT */ - TEST_TYPE(PPOINT, 4, 4); - TEST_TYPE_POINTER(PPOINT, 8, 4); + TEST_TYPE_SIZE (PPOINT, 4) + TEST_TYPE_ALIGN (PPOINT, 4) + TEST_TARGET_SIZE (PPOINT, 8) + TEST_TARGET_ALIGN(PPOINT, 4) } static void test_pack_PPOINTL(void) { /* PPOINTL */ - TEST_TYPE(PPOINTL, 4, 4); - TEST_TYPE_POINTER(PPOINTL, 8, 4); + TEST_TYPE_SIZE (PPOINTL, 4) + TEST_TYPE_ALIGN (PPOINTL, 4) + TEST_TARGET_SIZE (PPOINTL, 8) + TEST_TARGET_ALIGN(PPOINTL, 4) } static void test_pack_PRECT(void) { /* PRECT */ - TEST_TYPE(PRECT, 4, 4); - TEST_TYPE_POINTER(PRECT, 16, 4); + TEST_TYPE_SIZE (PRECT, 4) + TEST_TYPE_ALIGN (PRECT, 4) + TEST_TARGET_SIZE (PRECT, 16) + TEST_TARGET_ALIGN(PRECT, 4) } static void test_pack_PRECTL(void) { /* PRECTL */ - TEST_TYPE(PRECTL, 4, 4); - TEST_TYPE_POINTER(PRECTL, 16, 4); + TEST_TYPE_SIZE (PRECTL, 4) + TEST_TYPE_ALIGN (PRECTL, 4) + TEST_TARGET_SIZE (PRECTL, 16) + TEST_TARGET_ALIGN(PRECTL, 4) } static void test_pack_PROC(void) { /* PROC */ - TEST_TYPE(PROC, 4, 4); + TEST_TYPE_SIZE (PROC, 4) + TEST_TYPE_ALIGN (PROC, 4) } static void test_pack_PSIZE(void) { /* PSIZE */ - TEST_TYPE(PSIZE, 4, 4); - TEST_TYPE_POINTER(PSIZE, 8, 4); + TEST_TYPE_SIZE (PSIZE, 4) + TEST_TYPE_ALIGN (PSIZE, 4) + TEST_TARGET_SIZE (PSIZE, 8) + TEST_TARGET_ALIGN(PSIZE, 4) } static void test_pack_PSZ(void) { /* PSZ */ - TEST_TYPE(PSZ, 4, 4); + TEST_TYPE_SIZE (PSZ, 4) + TEST_TYPE_ALIGN (PSZ, 4) } static void test_pack_RECT(void) { /* RECT (pack 4) */ - TEST_TYPE(RECT, 16, 4); - TEST_FIELD(RECT, LONG, left, 0, 4, 4); - TEST_FIELD(RECT, LONG, top, 4, 4, 4); - TEST_FIELD(RECT, LONG, right, 8, 4, 4); - TEST_FIELD(RECT, LONG, bottom, 12, 4, 4); + TEST_TYPE_SIZE (RECT, 16) + TEST_TYPE_ALIGN (RECT, 4) + TEST_FIELD_SIZE (RECT, left, 4) + TEST_FIELD_ALIGN (RECT, left, 4) + TEST_FIELD_OFFSET(RECT, left, 0) + TEST_FIELD_SIZE (RECT, top, 4) + TEST_FIELD_ALIGN (RECT, top, 4) + TEST_FIELD_OFFSET(RECT, top, 4) + TEST_FIELD_SIZE (RECT, right, 4) + TEST_FIELD_ALIGN (RECT, right, 4) + TEST_FIELD_OFFSET(RECT, right, 8) + TEST_FIELD_SIZE (RECT, bottom, 4) + TEST_FIELD_ALIGN (RECT, bottom, 4) + TEST_FIELD_OFFSET(RECT, bottom, 12) } static void test_pack_RECTL(void) { /* RECTL (pack 4) */ - TEST_TYPE(RECTL, 16, 4); - TEST_FIELD(RECTL, LONG, left, 0, 4, 4); - TEST_FIELD(RECTL, LONG, top, 4, 4, 4); - TEST_FIELD(RECTL, LONG, right, 8, 4, 4); - TEST_FIELD(RECTL, LONG, bottom, 12, 4, 4); + TEST_TYPE_SIZE (RECTL, 16) + TEST_TYPE_ALIGN (RECTL, 4) + TEST_FIELD_SIZE (RECTL, left, 4) + TEST_FIELD_ALIGN (RECTL, left, 4) + TEST_FIELD_OFFSET(RECTL, left, 0) + TEST_FIELD_SIZE (RECTL, top, 4) + TEST_FIELD_ALIGN (RECTL, top, 4) + TEST_FIELD_OFFSET(RECTL, top, 4) + TEST_FIELD_SIZE (RECTL, right, 4) + TEST_FIELD_ALIGN (RECTL, right, 4) + TEST_FIELD_OFFSET(RECTL, right, 8) + TEST_FIELD_SIZE (RECTL, bottom, 4) + TEST_FIELD_ALIGN (RECTL, bottom, 4) + TEST_FIELD_OFFSET(RECTL, bottom, 12) } static void test_pack_SIZE(void) { /* SIZE (pack 4) */ - TEST_TYPE(SIZE, 8, 4); - TEST_FIELD(SIZE, LONG, cx, 0, 4, 4); - TEST_FIELD(SIZE, LONG, cy, 4, 4, 4); + TEST_TYPE_SIZE (SIZE, 8) + TEST_TYPE_ALIGN (SIZE, 4) + TEST_FIELD_SIZE (SIZE, cx, 4) + TEST_FIELD_ALIGN (SIZE, cx, 4) + TEST_FIELD_OFFSET(SIZE, cx, 0) + TEST_FIELD_SIZE (SIZE, cy, 4) + TEST_FIELD_ALIGN (SIZE, cy, 4) + TEST_FIELD_OFFSET(SIZE, cy, 4) } static void test_pack_SIZEL(void) { /* SIZEL */ - TEST_TYPE(SIZEL, 8, 4); + TEST_TYPE_SIZE (SIZEL, 8) + TEST_TYPE_ALIGN (SIZEL, 4) } static void test_pack_UCHAR(void) { /* UCHAR */ - TEST_TYPE(UCHAR, 1, 1); - TEST_TYPE_UNSIGNED(UCHAR); + TEST_TYPE_SIZE (UCHAR, 1) + TEST_TYPE_ALIGN (UCHAR, 1) + TEST_TYPE_UNSIGNED(UCHAR) } static void test_pack_UINT(void) { /* UINT */ - TEST_TYPE(UINT, 4, 4); - TEST_TYPE_UNSIGNED(UINT); + TEST_TYPE_SIZE (UINT, 4) + TEST_TYPE_ALIGN (UINT, 4) + TEST_TYPE_UNSIGNED(UINT) } static void test_pack_ULONG(void) { /* ULONG */ - TEST_TYPE(ULONG, 4, 4); - TEST_TYPE_UNSIGNED(ULONG); + TEST_TYPE_SIZE (ULONG, 4) + TEST_TYPE_ALIGN (ULONG, 4) + TEST_TYPE_UNSIGNED(ULONG) } static void test_pack_USHORT(void) { /* USHORT */ - TEST_TYPE(USHORT, 2, 2); - TEST_TYPE_UNSIGNED(USHORT); + TEST_TYPE_SIZE (USHORT, 2) + TEST_TYPE_ALIGN (USHORT, 2) + TEST_TYPE_UNSIGNED(USHORT) } static void test_pack_WORD(void) { /* WORD */ - TEST_TYPE(WORD, 2, 2); - TEST_TYPE_UNSIGNED(WORD); + TEST_TYPE_SIZE (WORD, 2) + TEST_TYPE_ALIGN (WORD, 2) + TEST_TYPE_UNSIGNED(WORD) } static void test_pack_WPARAM(void) { /* WPARAM */ - TEST_TYPE(WPARAM, 4, 4); + TEST_TYPE_SIZE (WPARAM, 4) + TEST_TYPE_ALIGN (WPARAM, 4) } static void test_pack(void) @@ -2387,5 +3434,9 @@ static void test_pack(void) START_TEST(generated) { +#ifdef _WIN64 + ok(0, "The type size / alignment tests don't support Win64 yet\n"); +#else test_pack(); +#endif } diff --git a/rostests/winetests/ntdll/info.c b/rostests/winetests/ntdll/info.c index 9fab8065969..2882071136c 100755 --- a/rostests/winetests/ntdll/info.c +++ b/rostests/winetests/ntdll/info.c @@ -57,7 +57,7 @@ static BOOL InitFunctionPtrs(void) static void test_query_basic(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; SYSTEM_BASIC_INFORMATION sbi; @@ -68,7 +68,8 @@ static void test_query_basic(void) /* Use a nonexistent info class */ trace("Check nonexistent info class\n"); status = pNtQuerySystemInformation(-1, NULL, 0, NULL); - ok( status == STATUS_INVALID_INFO_CLASS, "Expected STATUS_INVALID_INFO_CLASS, got %08x\n", status); + ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED /* vista */, + "Expected STATUS_INVALID_INFO_CLASS or STATUS_NOT_IMPLEMENTED, got %08x\n", status); /* Use an existing class but with a zero-length buffer */ trace("Check zero-length buffer\n"); @@ -78,7 +79,8 @@ static void test_query_basic(void) /* Use an existing class, correct length but no SystemInformation buffer */ trace("Check no SystemInformation buffer\n"); status = pNtQuerySystemInformation(SystemBasicInformation, NULL, sizeof(sbi), NULL); - ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status); + ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER /* vista */, + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got %08x\n", status); /* Use a existing class, correct length, a pointer to a buffer but no ReturnLength pointer */ trace("Check no ReturnLength pointer\n"); @@ -118,7 +120,7 @@ static void test_query_cpu(void) static void test_query_performance(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; SYSTEM_PERFORMANCE_INFORMATION spi; @@ -138,7 +140,7 @@ static void test_query_performance(void) static void test_query_timeofday(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; /* Copy of our winternl.h structure turned into a private one */ @@ -202,7 +204,8 @@ static void test_query_timeofday(void) status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 49, &ReturnLength); ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); - ok( 0 == ReturnLength, "ReturnLength should be 0, it is (%d)\n", ReturnLength); + ok( ReturnLength == 0 || ReturnLength == sizeof(sti) /* vista */, + "ReturnLength should be 0, it is (%d)\n", ReturnLength); status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, sizeof(sti), &ReturnLength); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); @@ -215,7 +218,7 @@ static void test_query_timeofday(void) static void test_query_process(void) { - DWORD status; + NTSTATUS status; DWORD last_pid; ULONG ReturnLength; int i = 0, k = 0; @@ -243,20 +246,20 @@ static void test_query_process(void) } SYSTEM_PROCESS_INFORMATION_PRIVATE, *PSYSTEM_PROCESS_INFORMATION_PRIVATE; ULONG SystemInformationLength = sizeof(SYSTEM_PROCESS_INFORMATION_PRIVATE); - SYSTEM_PROCESS_INFORMATION_PRIVATE* spi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); + SYSTEM_PROCESS_INFORMATION_PRIVATE *spi, *spi_buf = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); /* Only W2K3 returns the needed length, the rest returns 0, so we have to loop */ for (;;) { - status = pNtQuerySystemInformation(SystemProcessInformation, spi, SystemInformationLength, &ReturnLength); + status = pNtQuerySystemInformation(SystemProcessInformation, spi_buf, SystemInformationLength, &ReturnLength); if (status != STATUS_INFO_LENGTH_MISMATCH) break; - spi = HeapReAlloc(GetProcessHeap(), 0, spi , SystemInformationLength *= 2); + spi_buf = HeapReAlloc(GetProcessHeap(), 0, spi_buf , SystemInformationLength *= 2); } - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + spi = spi_buf; /* Get the first dwOffset, from this we can deduce the OS version we're running * @@ -320,12 +323,12 @@ static void test_query_process(void) if (one_before_last_pid == 0) one_before_last_pid = last_pid; - HeapFree( GetProcessHeap(), 0, spi); + HeapFree( GetProcessHeap(), 0, spi_buf); } static void test_query_procperf(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; ULONG NeededLength; SYSTEM_BASIC_INFORMATION sbi; @@ -341,29 +344,57 @@ static void test_query_procperf(void) ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); /* Try it for 1 processor */ + sppi->KernelTime.QuadPart = 0xdeaddead; + sppi->UserTime.QuadPart = 0xdeaddead; + sppi->IdleTime.QuadPart = 0xdeaddead; status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), &ReturnLength); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) == ReturnLength, "Inconsistent length %d\n", ReturnLength); + ok (sppi->KernelTime.QuadPart != 0xdeaddead, "KernelTime unchanged\n"); + ok (sppi->UserTime.QuadPart != 0xdeaddead, "UserTime unchanged\n"); + ok (sppi->IdleTime.QuadPart != 0xdeaddead, "IdleTime unchanged\n"); /* Try it for all processors */ + sppi->KernelTime.QuadPart = 0xdeaddead; + sppi->UserTime.QuadPart = 0xdeaddead; + sppi->IdleTime.QuadPart = 0xdeaddead; status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, NeededLength, &ReturnLength); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( NeededLength == ReturnLength, "Inconsistent length (%d) <-> (%d)\n", NeededLength, ReturnLength); + ok (sppi->KernelTime.QuadPart != 0xdeaddead, "KernelTime unchanged\n"); + ok (sppi->UserTime.QuadPart != 0xdeaddead, "UserTime unchanged\n"); + ok (sppi->IdleTime.QuadPart != 0xdeaddead, "IdleTime unchanged\n"); /* A too large given buffer size */ sppi = HeapReAlloc(GetProcessHeap(), 0, sppi , NeededLength + 2); + sppi->KernelTime.QuadPart = 0xdeaddead; + sppi->UserTime.QuadPart = 0xdeaddead; + sppi->IdleTime.QuadPart = 0xdeaddead; status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, NeededLength + 2, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( status == STATUS_SUCCESS || status == STATUS_INFO_LENGTH_MISMATCH /* vista */, + "Expected STATUS_SUCCESS or STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); ok( NeededLength == ReturnLength, "Inconsistent length (%d) <-> (%d)\n", NeededLength, ReturnLength); + if (status == STATUS_SUCCESS) + { + ok (sppi->KernelTime.QuadPart != 0xdeaddead, "KernelTime unchanged\n"); + ok (sppi->UserTime.QuadPart != 0xdeaddead, "UserTime unchanged\n"); + ok (sppi->IdleTime.QuadPart != 0xdeaddead, "IdleTime unchanged\n"); + } + else /* vista and 2008 */ + { + ok (sppi->KernelTime.QuadPart == 0xdeaddead, "KernelTime changed\n"); + ok (sppi->UserTime.QuadPart == 0xdeaddead, "UserTime changed\n"); + ok (sppi->IdleTime.QuadPart == 0xdeaddead, "IdleTime changed\n"); + } HeapFree( GetProcessHeap(), 0, sppi); } static void test_query_module(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; ULONG ModuleCount, i; @@ -398,25 +429,22 @@ static void test_query_module(void) static void test_query_handle(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION); SYSTEM_HANDLE_INFORMATION* shi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); /* Request the needed length : a SystemInformationLength greater than one struct sets ReturnLength */ status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); - - /* The following check assumes more than one handle on any given system */ - todo_wine - { - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); - } - ok( ReturnLength > 0, "Expected ReturnLength to be > 0, it was %d\n", ReturnLength); + todo_wine ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); SystemInformationLength = ReturnLength; shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength); status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); - ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + if (status != STATUS_INFO_LENGTH_MISMATCH) /* vista */ + { + ok( status == STATUS_SUCCESS, + "Expected STATUS_SUCCESS, got %08x\n", status); /* Check if we have some return values */ trace("Number of Handles : %d\n", shi->Count); @@ -425,13 +453,13 @@ static void test_query_handle(void) /* our implementation is a stub for now */ ok( shi->Count > 1, "Expected more than 1 handles, got (%d)\n", shi->Count); } - + } HeapFree( GetProcessHeap(), 0, shi); } static void test_query_cache(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; SYSTEM_CACHE_INFORMATION sci; @@ -449,7 +477,7 @@ static void test_query_cache(void) static void test_query_interrupt(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; ULONG NeededLength; SYSTEM_BASIC_INFORMATION sbi; @@ -477,7 +505,7 @@ static void test_query_interrupt(void) static void test_query_kerndebug(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi; @@ -495,7 +523,7 @@ static void test_query_kerndebug(void) static void test_query_regquota(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; SYSTEM_REGISTRY_QUOTA_INFORMATION srqi; @@ -513,7 +541,7 @@ static void test_query_regquota(void) static void test_query_process_basic(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; typedef struct _PROCESS_BASIC_INFORMATION_PRIVATE { @@ -534,7 +562,8 @@ static void test_query_process_basic(void) /* Use a nonexistent info class */ trace("Check nonexistent info class\n"); status = pNtQueryInformationProcess(NULL, -1, NULL, 0, NULL); - ok( status == STATUS_INVALID_INFO_CLASS, "Expected STATUS_INVALID_INFO_CLASS, got %08x\n", status); + ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED /* vista */, + "Expected STATUS_INVALID_INFO_CLASS or STATUS_NOT_IMPLEMENTED, got %08x\n", status); /* Do not give a handle and buffer */ trace("Check NULL handle and buffer and zero-length buffersize\n"); @@ -581,7 +610,7 @@ static void test_query_process_basic(void) static void test_query_process_vm(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; VM_COUNTERS pvi; @@ -619,7 +648,7 @@ static void test_query_process_vm(void) static void test_query_process_io(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; IO_COUNTERS pii; @@ -659,7 +688,7 @@ static void test_query_process_io(void) static void test_query_process_times(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; HANDLE process; SYSTEMTIME UTC, Local; @@ -708,12 +737,13 @@ static void test_query_process_times(void) status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessTimes, &spti, sizeof(spti) * 2, &ReturnLength); ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); - ok( sizeof(spti) == ReturnLength, "Inconsistent length %d\n", ReturnLength); + ok( sizeof(spti) == ReturnLength || ReturnLength == 0 /* vista */, + "Inconsistent length %d\n", ReturnLength); } static void test_query_process_handlecount(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; DWORD handlecount; HANDLE process; @@ -757,7 +787,7 @@ static void test_query_process_handlecount(void) static void test_query_process_image_file_name(void) { - DWORD status; + NTSTATUS status; ULONG ReturnLength; UNICODE_STRING image_file_name; void *buffer; @@ -795,7 +825,7 @@ static void test_query_process_image_file_name(void) static void test_readvirtualmemory(void) { HANDLE process; - DWORD status; + NTSTATUS status; SIZE_T readcount; static const char teststring[] = "test string"; char buffer[12]; @@ -818,7 +848,8 @@ static void test_readvirtualmemory(void) /* illegal remote address */ todo_wine{ status = pNtReadVirtualMemory(process, (void *) 0x1234, buffer, 12, &readcount); - ok( status == STATUS_PARTIAL_COPY, "Expected STATUS_PARTIAL_COPY, got %08x\n", status); + ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_ACCESS_VIOLATION), "Expected STATUS_PARTIAL_COPY, got %08x\n", status); + if (status == STATUS_PARTIAL_COPY) ok( readcount == 0, "Expected to read 0 bytes, got %ld\n",readcount); } diff --git a/rostests/winetests/ntdll/large_int.c b/rostests/winetests/ntdll/large_int.c index bec8ad9bf8f..69de5b78947 100755 --- a/rostests/winetests/ntdll/large_int.c +++ b/rostests/winetests/ntdll/large_int.c @@ -286,6 +286,14 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const largeint2str_t STRING ansi_str; NTSTATUS result; +#ifdef _WIN64 + if (largeint2str->value >> 32 == 0xffffffff) /* this crashes on 64-bit Vista */ + { + skip( "Value ffffffff%08x broken on 64-bit windows\n", (DWORD)largeint2str->value ); + return; + } +#endif + for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) { expected_str_Buffer[pos] = largeint2str->Buffer[pos]; } /* for */ @@ -367,6 +375,14 @@ static void one_RtlLargeIntegerToChar_test(int test_num, const largeint2str_t *l char dest_str[LARGE_STRI_BUFFER_LENGTH + 1]; ULONGLONG value; +#ifdef _WIN64 + if (largeint2str->value >> 32 == 0xffffffff) /* this crashes on 64-bit Vista */ + { + skip( "Value ffffffff%08x broken on 64-bit windows\n", (DWORD)largeint2str->value ); + return; + } +#endif + memset(dest_str, '-', LARGE_STRI_BUFFER_LENGTH); dest_str[LARGE_STRI_BUFFER_LENGTH] = '\0'; value = largeint2str->value; diff --git a/rostests/winetests/ntdll/ntdll.rbuild b/rostests/winetests/ntdll/ntdll.rbuild index 7af6b4450c7..8c3f50d9eba 100644 --- a/rostests/winetests/ntdll/ntdll.rbuild +++ b/rostests/winetests/ntdll/ntdll.rbuild @@ -1,12 +1,8 @@ - . - - 0x0600 - 0x609 - kernel32 + ntdll atom.c change.c @@ -27,4 +23,3 @@ time.c testlist.c - diff --git a/rostests/winetests/ntdll/om.c b/rostests/winetests/ntdll/om.c index d211ea00432..033013b8c78 100644 --- a/rostests/winetests/ntdll/om.c +++ b/rostests/winetests/ntdll/om.c @@ -130,21 +130,24 @@ static void test_namespace_pipe(void) ok(status == STATUS_INSTANCE_NOT_AVAILABLE, "NtCreateNamedPipeFile should have failed with STATUS_INSTANCE_NOT_AVAILABLE got(%08x)\n", status); - attr.Attributes = OBJ_CASE_INSENSITIVE; - status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); - ok(status == STATUS_SUCCESS, "Failed to open NamedPipe(%08x)\n", status); + h = CreateFileA("\\\\.\\pipe\\test\\pipe", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, 0 ); + ok(h != INVALID_HANDLE_VALUE, "Failed to open NamedPipe (%u)\n", GetLastError()); pNtClose(h); pRtlInitUnicodeString(&str, buffer3); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); - ok(status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_PIPE_NOT_AVAILABLE, + ok(status == STATUS_OBJECT_PATH_NOT_FOUND || + status == STATUS_PIPE_NOT_AVAILABLE || + status == STATUS_OBJECT_NAME_INVALID, /* vista */ "NtOpenFile should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08x)\n", status); pRtlInitUnicodeString(&str, buffer4); InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); - ok(status == STATUS_OBJECT_NAME_NOT_FOUND, + ok(status == STATUS_OBJECT_NAME_NOT_FOUND || + status == STATUS_OBJECT_NAME_INVALID, /* vista */ "NtOpenFile should have failed with STATUS_OBJECT_NAME_NOT_FOUND got(%08x)\n", status); pNtClose(pipe); @@ -175,6 +178,64 @@ static void test_namespace_pipe(void) DIR_TEST_CREATE_SUCCESS(&h) pNtClose(h); DIR_TEST_OPEN_SUCCESS(&h) pNtClose(h); \ pRtlFreeUnicodeString(&str); +static BOOL is_correct_dir( HANDLE dir, const char *name ) +{ + NTSTATUS status; + UNICODE_STRING str; + OBJECT_ATTRIBUTES attr; + HANDLE h = 0; + + pRtlCreateUnicodeStringFromAsciiz(&str, name); + InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, dir, NULL); + status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE); + pRtlFreeUnicodeString(&str); + if (h) pNtClose( h ); + return (status == STATUS_OBJECT_NAME_EXISTS); +} + +/* return a handle to the BaseNamedObjects dir where kernel32 objects get created */ +static HANDLE get_base_dir(void) +{ + static const char objname[] = "om.c_get_base_dir_obj"; + NTSTATUS status; + UNICODE_STRING str; + OBJECT_ATTRIBUTES attr; + HANDLE dir, h; + unsigned int i; + + h = CreateMutexA(NULL, FALSE, objname); + ok(h != 0, "CreateMutexA failed got ret=%p (%d)\n", h, GetLastError()); + InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, 0, NULL); + + pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local"); + status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr); + pRtlFreeUnicodeString(&str); + if (!status && is_correct_dir( dir, objname )) goto done; + if (!status) pNtClose( dir ); + + pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects"); + status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr); + pRtlFreeUnicodeString(&str); + if (!status && is_correct_dir( dir, objname )) goto done; + if (!status) pNtClose( dir ); + + for (i = 0; i < 20; i++) + { + char name[40]; + sprintf( name, "\\BaseNamedObjects\\Session\\%u", i ); + pRtlCreateUnicodeStringFromAsciiz(&str, name ); + status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr); + pRtlFreeUnicodeString(&str); + if (!status && is_correct_dir( dir, objname )) goto done; + if (!status) pNtClose( dir ); + } + dir = 0; + +done: + pNtClose( h ); + return dir; +} + static void test_name_collisions(void) { NTSTATUS status; @@ -202,12 +263,13 @@ static void test_name_collisions(void) "NtCreateMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status); pRtlFreeUnicodeString(&str); - - pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects"); - DIR_TEST_OPEN_SUCCESS(&dir) + if (!(dir = get_base_dir())) + { + win_skip( "couldn't find the BaseNamedObjects dir\n" ); + return; + } pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-test"); InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, dir, NULL); - h = CreateMutexA(NULL, FALSE, "om.c-test"); ok(h != 0, "CreateMutexA failed got ret=%p (%d)\n", h, GetLastError()); status = pNtCreateMutant(&h1, GENERIC_ALL, &attr, FALSE); @@ -285,13 +347,14 @@ static void test_directory(void) UNICODE_STRING str; OBJECT_ATTRIBUTES attr; HANDLE dir, dir1, h; + BOOL is_nt4; /* No name and/or no attributes */ status = pNtCreateDirectoryObject(NULL, DIRECTORY_QUERY, &attr); - ok(status == STATUS_ACCESS_VIOLATION, + ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER, "NtCreateDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08x)\n", status); status = pNtOpenDirectoryObject(NULL, DIRECTORY_QUERY, &attr); - ok(status == STATUS_ACCESS_VIOLATION, + ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER, "NtOpenDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08x)\n", status); status = pNtCreateDirectoryObject(&h, DIRECTORY_QUERY, NULL); @@ -335,6 +398,9 @@ static void test_directory(void) pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local"); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtOpenSymbolicLinkObject(&dir, SYMBOLIC_LINK_QUERY, &attr); + is_nt4 = (status == STATUS_OBJECT_NAME_NOT_FOUND); /* nt4 doesn't have Local\\ symlink */ + if (!is_nt4) + { ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08x)\n", status); pRtlFreeUnicodeString(&str); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); @@ -343,6 +409,7 @@ static void test_directory(void) pRtlFreeUnicodeString(&str); pNtClose(h); pNtClose(dir); + } pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects"); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); @@ -393,6 +460,8 @@ static void test_directory(void) pNtClose(dir); + if (!is_nt4) + { InitializeObjectAttributes(&attr, &str, 0, 0, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Global\\om.c-test"); DIR_TEST_CREATE_SUCCESS(&dir) @@ -406,9 +475,8 @@ static void test_directory(void) DIR_TEST_CREATE_SUCCESS(&dir) pRtlFreeUnicodeString(&str); pNtClose(h); - pNtClose(dir); - + } /* Create other objects using RootDirectory */ @@ -445,26 +513,19 @@ static void test_directory(void) pNtClose(dir); } -#define SYMLNK_TEST_CREATE_FAILURE(h,e) \ - status = pNtCreateSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr, &target);\ - ok(status == e,"NtCreateSymbolicLinkObject should have failed with %s got(%08x)\n", #e, status); -#define SYMLNK_TEST_OPEN_FAILURE(h,e) \ - status = pNtOpenSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr);\ - ok(status == e,"NtOpenSymbolicLinkObject should have failed with %s got(%08x)\n", #e, status); -#define SYMLNK_TEST_CREATE_OPEN_FAILURE(h,n,t,e) \ +#define SYMLNK_TEST_CREATE_OPEN_FAILURE2(h,n,t,e,e2) \ pRtlCreateUnicodeStringFromAsciiz(&str, n);\ pRtlCreateUnicodeStringFromAsciiz(&target, t);\ - SYMLNK_TEST_CREATE_FAILURE(h,e)\ - SYMLNK_TEST_OPEN_FAILURE(h,e)\ + status = pNtCreateSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr, &target);\ + ok(status == e || status == e2, \ + "NtCreateSymbolicLinkObject should have failed with %s or %s got(%08x)\n", #e, #e2, status);\ + status = pNtOpenSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr);\ + ok(status == e || status == e2, \ + "NtOpenSymbolicLinkObject should have failed with %s or %s got(%08x)\n", #e, #e2, status);\ pRtlFreeUnicodeString(&target);\ pRtlFreeUnicodeString(&str); -#define SYMLNK_TEST_CREATE_SUCCESS(h) \ - status = pNtCreateSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr, &target); \ - ok(status == STATUS_SUCCESS, "Failed to create SymbolicLink(%08x)\n", status); -#define SYMLNK_TEST_OPEN_SUCCESS(h) \ - status = pNtOpenSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr); \ - ok(status == STATUS_SUCCESS, "Failed to open SymbolicLink(%08x)\n", status); +#define SYMLNK_TEST_CREATE_OPEN_FAILURE(h,n,t,e) SYMLNK_TEST_CREATE_OPEN_FAILURE2(h,n,t,e,e) static void test_symboliclink(void) { @@ -475,7 +536,8 @@ static void test_symboliclink(void) IO_STATUS_BLOCK iosb; /* No name and/or no attributes */ - SYMLNK_TEST_CREATE_OPEN_FAILURE(NULL, "", "", STATUS_ACCESS_VIOLATION) + InitializeObjectAttributes(&attr, NULL, 0, 0, NULL); + SYMLNK_TEST_CREATE_OPEN_FAILURE2(NULL, "", "", STATUS_ACCESS_VIOLATION, STATUS_INVALID_PARAMETER) status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, NULL); ok(status == STATUS_ACCESS_VIOLATION, @@ -487,26 +549,38 @@ static void test_symboliclink(void) /* No attributes */ pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices"); status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, &target); - ok(status == STATUS_SUCCESS, "NtCreateSymbolicLinkObject failed(%08x)\n", status); + ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_VIOLATION, /* nt4 */ + "NtCreateSymbolicLinkObject failed(%08x)\n", status); pRtlFreeUnicodeString(&target); - pNtClose(h); + if (!status) pNtClose(h); InitializeObjectAttributes(&attr, NULL, 0, 0, NULL); - SYMLNK_TEST_CREATE_FAILURE(&link, STATUS_INVALID_PARAMETER) - SYMLNK_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) + status = pNtCreateSymbolicLinkObject(&link, SYMBOLIC_LINK_QUERY, &attr, &target); + ok(status == STATUS_INVALID_PARAMETER || + broken(status == STATUS_SUCCESS), /* nt4 */ + "NtCreateSymbolicLinkObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status); + if (!status) pNtClose(h); + status = pNtOpenSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, &attr); + ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, + "NtOpenSymbolicLinkObject should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08x)\n", status); /* Bad name */ pRtlCreateUnicodeStringFromAsciiz(&target, "anywhere"); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, ""); - SYMLNK_TEST_CREATE_SUCCESS(&link) - SYMLNK_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) + status = pNtCreateSymbolicLinkObject(&link, SYMBOLIC_LINK_QUERY, &attr, &target); + ok(status == STATUS_SUCCESS, "Failed to create SymbolicLink(%08x)\n", status); + status = pNtOpenSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, &attr); + ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, + "NtOpenSymbolicLinkObject should have failed with STATUS_OBJECT_PATH_SYNTAX_BAD got(%08x)\n", status); pNtClose(link); pRtlFreeUnicodeString(&str); pRtlCreateUnicodeStringFromAsciiz(&str, "\\"); - todo_wine {SYMLNK_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_TYPE_MISMATCH)} + status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, &attr, &target); + todo_wine ok(status == STATUS_OBJECT_TYPE_MISMATCH, + "NtCreateSymbolicLinkObject should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08x)\n", status); pRtlFreeUnicodeString(&str); pRtlFreeUnicodeString(&target); @@ -514,24 +588,28 @@ static void test_symboliclink(void) SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID) SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", "->Somewhere", STATUS_OBJECT_NAME_INVALID) SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", "->Somewhere", STATUS_OBJECT_NAME_INVALID) - SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\om.c-test\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID) + SYMLNK_TEST_CREATE_OPEN_FAILURE2(&h, "\\BaseNamedObjects\\om.c-test\\", "->Somewhere", + STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND) - /* Compaund test */ - pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects"); - DIR_TEST_OPEN_SUCCESS(&dir) - pRtlFreeUnicodeString(&str); + /* Compound test */ + if (!(dir = get_base_dir())) + { + win_skip( "couldn't find the BaseNamedObjects dir\n" ); + return; + } InitializeObjectAttributes(&attr, &str, 0, dir, NULL); - pRtlCreateUnicodeStringFromAsciiz(&str, "Local\\test-link"); + pRtlCreateUnicodeStringFromAsciiz(&str, "test-link"); pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices"); - SYMLNK_TEST_CREATE_SUCCESS(&link) + status = pNtCreateSymbolicLinkObject(&link, SYMBOLIC_LINK_QUERY, &attr, &target); + ok(status == STATUS_SUCCESS, "Failed to create SymbolicLink(%08x)\n", status); pRtlFreeUnicodeString(&str); pRtlFreeUnicodeString(&target); - pRtlCreateUnicodeStringFromAsciiz(&str, "Local\\test-link\\PIPE"); + pRtlCreateUnicodeStringFromAsciiz(&str, "test-link\\NUL"); status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); - todo_wine ok(status == STATUS_SUCCESS, "Failed to open NamedPipe(%08x)\n", status); + todo_wine ok(status == STATUS_SUCCESS, "Failed to open NUL device(%08x)\n", status); pRtlFreeUnicodeString(&str); pNtClose(h); diff --git a/rostests/winetests/ntdll/path.c b/rostests/winetests/ntdll/path.c index 99d94829bcb..9d39cdcd9ab 100755 --- a/rostests/winetests/ntdll/path.c +++ b/rostests/winetests/ntdll/path.c @@ -91,6 +91,7 @@ static void test_RtlIsDosDeviceName(void) const char *path; WORD pos; WORD len; + BOOL fails; }; static const struct test tests[] = @@ -101,22 +102,26 @@ static void test_RtlIsDosDeviceName(void) { "", 0, 0 }, { "\\\\foo\\nul", 0, 0 }, { "c:\\nul:", 6, 6 }, - { "c:\\nul::", 6, 6 }, - { "c:\\nul::::::", 6, 6 }, + { "c:\\nul\\", 0, 0 }, + { "c:\\nul\\foo", 0, 0 }, + { "c:\\nul::", 6, 6, TRUE }, /* fails on nt4 */ + { "c:\\nul::::::", 6, 6, TRUE }, /* fails on nt4 */ { "c:prn ", 4, 6 }, { "c:prn.......", 4, 6 }, { "c:prn... ...", 4, 6 }, - { "c:NUL .... ", 4, 6 }, + { "c:NUL .... ", 4, 6, TRUE }, /* fails on nt4 */ { "c: . . .", 0, 0 }, { "c:", 0, 0 }, { " . . . :", 0, 0 }, { ":", 0, 0 }, { "c:nul. . . :", 4, 6 }, - { "c:nul . . :", 4, 6 }, + { "c:nul . . :", 4, 6, TRUE }, /* fails on nt4 */ { "c:nul0", 0, 0 }, + { "c:prn:aaa", 4, 6, TRUE }, /* fails on win9x */ { "c:PRN:.txt", 4, 6 }, { "c:aux:.txt...", 4, 6 }, { "c:prn:.txt:", 4, 6 }, + { "c:nul:aaa", 4, 6, TRUE }, /* fails on win9x */ { "con:", 0, 6 }, { "lpt1:", 0, 8 }, { "c:com5:", 4, 8 }, @@ -141,22 +146,11 @@ static void test_RtlIsDosDeviceName(void) { pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 ); ret = pRtlIsDosDeviceName_U( buffer ); - ok( ret == MAKELONG( test->len, test->pos ), + ok( ret == MAKELONG( test->len, test->pos ) || + (test->fails && broken( ret == 0 )), "Wrong result (%d,%d)/(%d,%d) for %s\n", HIWORD(ret), LOWORD(ret), test->pos, test->len, test->path ); } - - pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, "c:prn:aaa", strlen("c:prn:aaa")+1 ); - ret = pRtlIsDosDeviceName_U( buffer ); - ok( ret == MAKELONG( 6, 4 ) || /* NT */ - ret == MAKELONG( 0, 0), /* win9x */ - "Wrong result (%d,%d)/(4,6) or (0,0) for c:prn:aaa\n", HIWORD(ret), LOWORD(ret) ); - - pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, "c:nul:aaa", strlen("c:nul:aaa")+1 ); - ret = pRtlIsDosDeviceName_U( buffer ); - ok( ret == MAKELONG( 6, 4 ) || /* NT */ - ret == MAKELONG( 0, 0), /* win9x */ - "Wrong result (%d,%d)/(4,6) or (0,0) for c:nul:aaa\n", HIWORD(ret), LOWORD(ret) ); } static void test_RtlIsNameLegalDOS8Dot3(void) @@ -237,6 +231,8 @@ static void test_RtlGetFullPathName_U(void) const char *path; const char *rname; const char *rfile; + const char *alt_rname; + const char *alt_rfile; }; static const struct test tests[] = @@ -251,15 +247,17 @@ static void test_RtlGetFullPathName_U(void) { "c:/TEST", "c:\\test", "test"}, { "c:/test/file", "c:\\test\\file", "file"}, { "c:/test./file", "c:\\test\\file", "file"}, - { "c:/test../file", "c:\\test.\\file", "file"}, { "c:/test.. /file", "c:\\test.. \\file","file"}, { "c:/test/././file", "c:\\test\\file", "file"}, { "c:/test\\.\\.\\file", "c:\\test\\file", "file"}, { "c:/test/\\.\\.\\file", "c:\\test\\file", "file"}, { "c:/test\\\\.\\.\\file", "c:\\test\\file", "file"}, { "c:/test\\test1\\..\\.\\file", "c:\\test\\file", "file"}, - { "c:///test\\.\\.\\file//", "c:\\test\\file\\", NULL}, + { "c:///test\\.\\.\\file//", "c:\\test\\file\\", NULL, + "c:\\test\\file", "file"}, /* nt4 */ { "c:///test\\..\\file\\..\\//", "c:\\", NULL}, + { "c:/test../file", "c:\\test.\\file", "file", + "c:\\test..\\file", "file"}, /* vista */ { NULL, NULL, NULL} }; @@ -276,27 +274,36 @@ static void test_RtlGetFullPathName_U(void) len= strlen(test->rname) * sizeof(WCHAR); pRtlMultiByteToUnicodeN(pathbufW , sizeof(pathbufW), NULL, test->path, strlen(test->path)+1 ); ret = pRtlGetFullPathName_U( pathbufW,MAX_PATH, rbufferW, &file_part); - ok( ret == len, "Wrong result %d/%d for \"%s\"\n", ret, len, test->path ); + ok( ret == len || (test->alt_rname && ret == strlen(test->alt_rname)*sizeof(WCHAR)), + "Wrong result %d/%d for \"%s\"\n", ret, len, test->path ); ok(pRtlUnicodeToMultiByteN(rbufferA,MAX_PATH,&reslen,rbufferW,(lstrlenW(rbufferW) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS, "RtlUnicodeToMultiByteN failed\n"); - ok(lstrcmpiA(rbufferA,test->rname) == 0, "Got \"%s\" expected \"%s\"\n",rbufferA,test->rname); + ok(!lstrcmpiA(rbufferA,test->rname) || (test->alt_rname && !lstrcmpiA(rbufferA,test->alt_rname)), + "Got \"%s\" expected \"%s\"\n",rbufferA,test->rname); if (file_part) { ok(pRtlUnicodeToMultiByteN(rfileA,MAX_PATH,&reslen,file_part,(lstrlenW(file_part) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS, "RtlUnicodeToMultiByteN failed\n"); - ok(test->rfile && !lstrcmpiA(rfileA,test->rfile), "Got \"%s\" expected \"%s\"\n",rfileA,test->rfile); + ok((test->rfile && !lstrcmpiA(rfileA,test->rfile)) || + (test->alt_rfile && !lstrcmpiA(rfileA,test->alt_rfile)), + "Got \"%s\" expected \"%s\"\n",rfileA,test->rfile); } else { ok( !test->rfile, "Got NULL expected \"%s\"\n", test->rfile ); } } - } START_TEST(path) { HMODULE mod = GetModuleHandleA("ntdll.dll"); + if (!mod) + { + win_skip("Not running on NT, skipping tests\n"); + return; + } + pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN"); pRtlUnicodeToMultiByteN = (void *)GetProcAddress(mod,"RtlUnicodeToMultiByteN"); pRtlDetermineDosPathNameType_U = (void *)GetProcAddress(mod,"RtlDetermineDosPathNameType_U"); diff --git a/rostests/winetests/ntdll/port.c b/rostests/winetests/ntdll/port.c index 971591737a7..1d49e453003 100644 --- a/rostests/winetests/ntdll/port.c +++ b/rostests/winetests/ntdll/port.c @@ -62,8 +62,8 @@ typedef struct _LPC_MESSAGE USHORT MessageType; USHORT VirtualRangesOffset; CLIENT_ID ClientId; - ULONG MessageId; - ULONG SectionSize; + ULONG_PTR MessageId; + ULONG_PTR SectionSize; UCHAR Data[ANYSIZE_ARRAY]; } LPC_MESSAGE, *PLPC_MESSAGE; @@ -90,10 +90,7 @@ static const WCHAR PORTNAME[] = {'\\','M','y','P','o','r','t',0}; #define MAX_MESSAGE_LEN 30 -UNICODE_STRING port; -static char selfname[MAX_PATH]; -static int myARGC; -static char** myARGV; +static UNICODE_STRING port; /* Function pointers for ntdll calls */ static HMODULE hntdll = 0; @@ -118,8 +115,9 @@ static BOOL init_function_ptrs(void) { hntdll = LoadLibraryA("ntdll.dll"); - if (hntdll) - { + if (!hntdll) + return FALSE; + pNtCompleteConnectPort = (void *)GetProcAddress(hntdll, "NtCompleteConnectPort"); pNtAcceptConnectPort = (void *)GetProcAddress(hntdll, "NtAcceptConnectPort"); pNtReplyPort = (void *)GetProcAddress(hntdll, "NtReplyPort"); @@ -131,13 +129,14 @@ static BOOL init_function_ptrs(void) pNtConnectPort = (void *)GetProcAddress(hntdll, "NtConnectPort"); pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); pNtWaitForSingleObject = (void *)GetProcAddress(hntdll, "NtWaitForSingleObject"); - } if (!pNtCompleteConnectPort || !pNtAcceptConnectPort || !pNtReplyWaitReceivePort || !pNtCreatePort || !pNtRequestWaitReplyPort || !pNtRequestPort || !pNtRegisterThreadTerminatePort || !pNtConnectPort || !pRtlInitUnicodeString) { + win_skip("Needed port functions are not available\n"); + FreeLibrary(hntdll); return FALSE; } @@ -153,10 +152,10 @@ static void ProcessConnectionRequest(PLPC_MESSAGE LpcMessage, PHANDLE pAcceptPor ok(!*LpcMessage->Data, "Expected empty string!\n"); status = pNtAcceptConnectPort(pAcceptPortHandle, 0, LpcMessage, 1, 0, NULL); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); status = pNtCompleteConnectPort(*pAcceptPortHandle); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); } static void ProcessLpcRequest(HANDLE PortHandle, PLPC_MESSAGE LpcMessage) @@ -171,7 +170,7 @@ static void ProcessLpcRequest(HANDLE PortHandle, PLPC_MESSAGE LpcMessage) lstrcpy((LPSTR)LpcMessage->Data, REPLY); status = pNtReplyPort(PortHandle, LpcMessage); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); ok(LpcMessage->MessageType == LPC_REQUEST, "Expected LPC_REQUEST, got %d\n", LpcMessage->MessageType); ok(!lstrcmp((LPSTR)LpcMessage->Data, REPLY), @@ -192,11 +191,11 @@ static DWORD WINAPI test_ports_client(LPVOID arg) sqos.EffectiveOnly = TRUE; status = pNtConnectPort(&PortHandle, &port, &sqos, 0, 0, &len, NULL, NULL); - todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); if (status != STATUS_SUCCESS) return 1; status = pNtRegisterThreadTerminatePort(PortHandle); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN; LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); @@ -207,7 +206,7 @@ static DWORD WINAPI test_ports_client(LPVOID arg) lstrcpy((LPSTR)LpcMessage->Data, REQUEST1); status = pNtRequestPort(PortHandle, LpcMessage); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); ok(LpcMessage->MessageType == 0, "Expected 0, got %d\n", LpcMessage->MessageType); ok(!lstrcmp((LPSTR)LpcMessage->Data, REQUEST1), "Expected %s, got %s\n", REQUEST1, LpcMessage->Data); @@ -220,36 +219,24 @@ static DWORD WINAPI test_ports_client(LPVOID arg) /* Send the message and wait for the reply */ status = pNtRequestWaitReplyPort(PortHandle, LpcMessage, out); - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); ok(!lstrcmp((LPSTR)out->Data, REPLY), "Expected %s, got %s\n", REPLY, out->Data); ok(out->MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->MessageType); + HeapFree(GetProcessHeap(), 0, out); + HeapFree(GetProcessHeap(), 0, LpcMessage); + return 0; } -static void test_ports_server(void) +static void test_ports_server( HANDLE PortHandle ) { - OBJECT_ATTRIBUTES obj; - HANDLE PortHandle; HANDLE AcceptPortHandle; PLPC_MESSAGE LpcMessage; ULONG size; NTSTATUS status; BOOL done = FALSE; - pRtlInitUnicodeString(&port, PORTNAME); - - memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES)); - obj.Length = sizeof(OBJECT_ATTRIBUTES); - obj.ObjectName = &port; - - status = pNtCreatePort(&PortHandle, &obj, 100, 100, 0); - todo_wine - { - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); - } - if (status != STATUS_SUCCESS) return; - size = FIELD_OFFSET(LPC_MESSAGE, Data) + MAX_MESSAGE_LEN; LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); @@ -284,6 +271,7 @@ static void test_ports_server(void) case LPC_CLIENT_DIED: ok(done, "Expected LPC request to be completed!\n"); + HeapFree(GetProcessHeap(), 0, LpcMessage); return; default: @@ -291,22 +279,38 @@ static void test_ports_server(void) break; } } + + HeapFree(GetProcessHeap(), 0, LpcMessage); } START_TEST(port) { - HANDLE thread; - DWORD id; + OBJECT_ATTRIBUTES obj; + HANDLE port_handle; + NTSTATUS status; if (!init_function_ptrs()) return; - myARGC = winetest_get_mainargs(&myARGV); - strcpy(selfname, myARGV[0]); + pRtlInitUnicodeString(&port, PORTNAME); - thread = CreateThread(NULL, 0, test_ports_client, NULL, 0, &id); + memset(&obj, 0, sizeof(OBJECT_ATTRIBUTES)); + obj.Length = sizeof(OBJECT_ATTRIBUTES); + obj.ObjectName = &port; + + status = pNtCreatePort(&port_handle, &obj, 100, 100, 0); + if (status == STATUS_ACCESS_DENIED) skip("Not enough rights\n"); + else todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %d\n", status); + + if (status == STATUS_SUCCESS) + { + DWORD id; + HANDLE thread = CreateThread(NULL, 0, test_ports_client, NULL, 0, &id); ok(thread != NULL, "Expected non-NULL thread handle!\n"); - test_ports_server(); + test_ports_server( port_handle ); + ok( WaitForSingleObject( thread, 10000 ) == 0, "thread didn't exit\n" ); CloseHandle(thread); +} + FreeLibrary(hntdll); } diff --git a/rostests/winetests/ntdll/reg.c b/rostests/winetests/ntdll/reg.c index 3efdfabaf45..2a5586fc9a4 100755 --- a/rostests/winetests/ntdll/reg.c +++ b/rostests/winetests/ntdll/reg.c @@ -29,6 +29,11 @@ #include "winnls.h" #include "stdlib.h" +/* A test string */ +static const WCHAR stringW[] = {'s', 't', 'r', 'i', 'n', 'g', 'W', 0}; +/* A size, in bytes, short enough to cause truncation of the above */ +#define STR_TRUNC_SIZE (sizeof(stringW)-2*sizeof(*stringW)) + #ifndef __WINE_WINTERNL_H /* RtlQueryRegistryValues structs and defines */ @@ -129,11 +134,11 @@ static NTSTATUS (WINAPI * pNtSetValueKey)( PHKEY, const PUNICODE_STRING, ULONG, ULONG, const PVOID, ULONG ); static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING); static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR); -static NTSTATUS (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG); +static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG); static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR); static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL); static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID); -static NTSTATUS (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG); +static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG); static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG); static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*); @@ -156,8 +161,6 @@ static BOOL InitFunctionPtrs(void) trace("Could not load ntdll.dll\n"); return FALSE; } - if (hntdll) - { NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz) NTDLL_GET_PROC(RtlCreateUnicodeString) NTDLL_GET_PROC(RtlFreeUnicodeString) @@ -181,7 +184,6 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(RtlAllocateHeap) NTDLL_GET_PROC(RtlZeroMemory) NTDLL_GET_PROC(RtlpNtQueryValueKey) - } return TRUE; } #undef NTDLL_GET_PROC @@ -198,7 +200,7 @@ static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN { ValueNameLength = lstrlenW(ValueName); - ValName = (LPSTR)pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength); + ValName = pRtlAllocateHeap(GetProcessHeap(), 0, ValueNameLength); WideCharToMultiByte(0, 0, ValueName, ValueNameLength+1,ValName, ValueNameLength, 0, 0); @@ -211,12 +213,12 @@ static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN { case REG_NONE: trace("ValueType: REG_NONE\n"); - trace("ValueData: %d\n", (int)ValueData); + trace("ValueData: %p\n", ValueData); break; case REG_BINARY: trace("ValueType: REG_BINARY\n"); - trace("ValueData: %d\n", *(unsigned int *)ValueData); + trace("ValueData: %p\n", ValueData); break; case REG_SZ: @@ -236,7 +238,7 @@ static NTSTATUS WINAPI QueryRoutine (IN PCWSTR ValueName, IN ULONG ValueType, IN case REG_DWORD: trace("ValueType: REG_DWORD\n"); - trace("ValueData: %d\n", *(unsigned int *)ValueData); + trace("ValueData: %p\n", ValueData); break; }; trace("ValueLength: %d\n", (int)ValueLength); @@ -293,7 +295,7 @@ static void test_RtlQueryRegistryValues(void) PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL; RelativeTo = RTL_REGISTRY_ABSOLUTE;/*Only using absolute - no need to test all relativeto variables*/ - QueryTable = (PRTL_QUERY_REGISTRY_TABLE)pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26); + QueryTable = pRtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_QUERY_REGISTRY_TABLE)*26); pRtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE) * 26); @@ -371,7 +373,8 @@ static void test_NtCreateKey(void) /* All NULL */ status = pNtCreateKey(NULL, 0, NULL, 0, 0, 0, 0); - ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); + ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER, + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); /* Only the key */ status = pNtCreateKey(&key, 0, NULL, 0, 0, 0, 0); @@ -380,7 +383,8 @@ static void test_NtCreateKey(void) /* Only accessmask */ status = pNtCreateKey(NULL, am, NULL, 0, 0, 0, 0); - ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got: 0x%08x\n", status); + ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER, + "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); /* Key and accessmask */ status = pNtCreateKey(&key, am, NULL, 0, 0, 0, 0); @@ -413,16 +417,20 @@ static void test_NtSetValueKey(void) UNICODE_STRING ValName; DWORD data = 711; - pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest"); - InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); status = pNtOpenKey(&key, am, &attr); ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); + pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest"); status = pNtSetValueKey(key, &ValName, 0, REG_DWORD, &data, sizeof(data)); ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status); - pRtlFreeUnicodeString(&ValName); + + pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest"); + status = pNtSetValueKey(key, &ValName, 0, REG_SZ, (VOID*)stringW, STR_TRUNC_SIZE); + ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status); + pRtlFreeUnicodeString(&ValName); + pNtClose(key); } @@ -486,7 +494,7 @@ static void test_NtQueryValueKey(void) basic_info = HeapAlloc(GetProcessHeap(), 0, len); status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len); ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); - ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->Type); + ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex); ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type); ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength); ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len); @@ -494,7 +502,7 @@ static void test_NtQueryValueKey(void) basic_info = HeapReAlloc(GetProcessHeap(), 0, basic_info, len); status = pNtQueryValueKey(key, &ValName, KeyValueBasicInformation, basic_info, len, &len); ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); - ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->Type); + ok(basic_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", basic_info->TitleIndex); ok(basic_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", basic_info->Type); ok(basic_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", basic_info->NameLength); ok(len == FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[basic_info->NameLength/sizeof(WCHAR)]), "NtQueryValueKey returned wrong len %d\n", len); @@ -505,7 +513,7 @@ static void test_NtQueryValueKey(void) partial_info = HeapAlloc(GetProcessHeap(), 0, len); status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); - ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->Type); + ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex); ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type); ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len); @@ -513,7 +521,7 @@ static void test_NtQueryValueKey(void) partial_info = HeapReAlloc(GetProcessHeap(), 0, partial_info, len); status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); - ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->Type); + ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex); ok(partial_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type); ok(partial_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); ok(len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[partial_info->DataLength]), "NtQueryValueKey returned wrong len %d\n", len); @@ -524,7 +532,7 @@ static void test_NtQueryValueKey(void) full_info = HeapAlloc(GetProcessHeap(), 0, len); status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len); ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryValueKey should have returned STATUS_BUFFER_OVERFLOW instead of 0x%08x\n", status); - ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->Type); + ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex); ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type); ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength); ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength); @@ -535,7 +543,7 @@ static void test_NtQueryValueKey(void) full_info = HeapReAlloc(GetProcessHeap(), 0, full_info, len); status = pNtQueryValueKey(key, &ValName, KeyValueFullInformation, full_info, len, &len); ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); - ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->Type); + ok(full_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", full_info->TitleIndex); ok(full_info->Type == REG_DWORD, "NtQueryValueKey returned wrong Type %d\n", full_info->Type); ok(full_info->DataLength == 4, "NtQueryValueKey returned wrong DataLength %d\n", full_info->DataLength); ok(full_info->NameLength == 20, "NtQueryValueKey returned wrong NameLength %d\n", full_info->NameLength); @@ -544,6 +552,22 @@ static void test_NtQueryValueKey(void) *(DWORD *)((char *)full_info + full_info->DataOffset)); HeapFree(GetProcessHeap(), 0, full_info); + pRtlFreeUnicodeString(&ValName); + pRtlCreateUnicodeStringFromAsciiz(&ValName, "stringtest"); + + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, NULL, 0, &len); + todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status); + partial_info = HeapAlloc(GetProcessHeap(), 0, len+1); + memset(partial_info, 0xbd, len+1); + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, partial_info, len, &len); + ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_SUCCESS instead of 0x%08x\n", status); + ok(partial_info->TitleIndex == 0, "NtQueryValueKey returned wrong TitleIndex %d\n", partial_info->TitleIndex); + ok(partial_info->Type == REG_SZ, "NtQueryValueKey returned wrong Type %d\n", partial_info->Type); + ok(partial_info->DataLength == STR_TRUNC_SIZE, "NtQueryValueKey returned wrong DataLength %d\n", partial_info->DataLength); + ok(!memcmp(partial_info->Data, stringW, STR_TRUNC_SIZE), "incorrect Data returned\n"); + ok(*(partial_info->Data+STR_TRUNC_SIZE) == 0xbd, "string overflowed %02x\n", *(partial_info->Data+STR_TRUNC_SIZE)); + HeapFree(GetProcessHeap(), 0, partial_info); + pRtlFreeUnicodeString(&ValName); pNtClose(key); } @@ -575,11 +599,11 @@ static void test_RtlpNtQueryValueKey(void) START_TEST(reg) { - static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t','\\',0}; + static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0}; if(!InitFunctionPtrs()) return; pRtlFormatCurrentUserKeyPath(&winetestpath); - winetestpath.Buffer = (PWSTR)pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer, + winetestpath.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, winetestpath.Buffer, winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR)); winetestpath.MaximumLength = winetestpath.MaximumLength + sizeof(winetest)*sizeof(WCHAR); diff --git a/rostests/winetests/ntdll/rtl.c b/rostests/winetests/ntdll/rtl.c index 443b987c1f2..7beef6d9865 100755 --- a/rostests/winetests/ntdll/rtl.c +++ b/rostests/winetests/ntdll/rtl.c @@ -49,6 +49,7 @@ typedef struct _RTL_HANDLE_TABLE static HMODULE hntdll = 0; static SIZE_T (WINAPI *pRtlCompareMemory)(LPCVOID,LPCVOID,SIZE_T); static SIZE_T (WINAPI *pRtlCompareMemoryUlong)(PULONG, SIZE_T, ULONG); +static NTSTATUS (WINAPI *pRtlDeleteTimer)(HANDLE, HANDLE, HANDLE); static VOID (WINAPI *pRtlMoveMemory)(LPVOID,LPCVOID,SIZE_T); static VOID (WINAPI *pRtlFillMemory)(LPVOID,SIZE_T,BYTE); static VOID (WINAPI *pRtlFillMemoryUlong)(LPVOID,SIZE_T,ULONG); @@ -80,6 +81,7 @@ static void InitFunctionPtrs(void) if (hntdll) { pRtlCompareMemory = (void *)GetProcAddress(hntdll, "RtlCompareMemory"); pRtlCompareMemoryUlong = (void *)GetProcAddress(hntdll, "RtlCompareMemoryUlong"); + pRtlDeleteTimer = (void *)GetProcAddress(hntdll, "RtlDeleteTimer"); pRtlMoveMemory = (void *)GetProcAddress(hntdll, "RtlMoveMemory"); pRtlFillMemory = (void *)GetProcAddress(hntdll, "RtlFillMemory"); pRtlFillMemoryUlong = (void *)GetProcAddress(hntdll, "RtlFillMemoryUlong"); @@ -264,6 +266,12 @@ static void test_RtlUlonglongByteSwap(void) { ULONGLONG result; + if ( pRtlUlonglongByteSwap( 0 ) != 0 ) + { + win_skip("Broken RtlUlonglongByteSwap in win2k\n"); + return; + } + result = pRtlUlonglongByteSwap( ((ULONGLONG)0x76543210 << 32) | 0x87654321 ); ok( (((ULONGLONG)0x21436587 << 32) | 0x10325476) == result, "RtlUlonglongByteSwap(0x7654321087654321) returns 0x%x%08x, expected 0x2143658710325476\n", @@ -563,7 +571,7 @@ static void test_RtlUniform(void) } -static ULONG WINAPI my_RtlRandom(PULONG seed) +static ULONG my_RtlRandom(PULONG seed) { static ULONG saved_value[128] = { /* 0 */ 0x4c8bc0aa, 0x4c022957, 0x2232827a, 0x2f1e7626, 0x7f8bdafb, 0x5c37d02a, 0x0ab48f72, 0x2f0c4ffa, @@ -924,6 +932,15 @@ static void test_RtlAllocateAndInitializeSid(void) ok(ret == STATUS_INVALID_SID, "wrong error %08x\n", ret); } +static void test_RtlDeleteTimer(void) +{ + NTSTATUS ret; + ret = pRtlDeleteTimer(NULL, NULL, NULL); + ok(ret == STATUS_INVALID_PARAMETER_1 || + ret == STATUS_INVALID_PARAMETER, /* W2K */ + "expected STATUS_INVALID_PARAMETER_1 or STATUS_INVALID_PARAMETER, got %x\n", ret); +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -956,4 +973,6 @@ START_TEST(rtl) test_HandleTables(); if (pRtlAllocateAndInitializeSid) test_RtlAllocateAndInitializeSid(); + if (pRtlDeleteTimer) + test_RtlDeleteTimer(); } diff --git a/rostests/winetests/ntdll/rtlstr.c b/rostests/winetests/ntdll/rtlstr.c index 5239de07e04..df01cf314d0 100755 --- a/rostests/winetests/ntdll/rtlstr.c +++ b/rostests/winetests/ntdll/rtlstr.c @@ -89,7 +89,7 @@ static WCHAR* AtoW( const char* p ) { WCHAR* buffer; DWORD len = MultiByteToWideChar( CP_ACP, 0, p, -1, NULL, 0 ); - buffer = malloc( len * sizeof(WCHAR) ); + buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, p, -1, buffer, len ); return buffer; } @@ -191,7 +191,7 @@ static void test_RtlInitUnicodeStringEx(void) UNICODE_STRING uni; NTSTATUS result; - teststring2 = (WCHAR *) malloc((TESTSTRING2_LEN + 1) * sizeof(WCHAR)); + teststring2 = HeapAlloc(GetProcessHeap(), 0, (TESTSTRING2_LEN + 1) * sizeof(WCHAR)); memset(teststring2, 'X', TESTSTRING2_LEN * sizeof(WCHAR)); teststring2[TESTSTRING2_LEN] = '\0'; @@ -233,15 +233,18 @@ static void test_RtlInitUnicodeStringEx(void) ok(result == STATUS_NAME_TOO_LONG, "pRtlInitUnicodeStringEx(&uni, 0) returns %x, expected %x\n", result, STATUS_NAME_TOO_LONG); - ok(uni.Length == 12345, - "pRtlInitUnicodeStringEx(&uni, 0) sets Length to %u, expected %u\n", - uni.Length, 12345); - ok(uni.MaximumLength == 12345, - "pRtlInitUnicodeStringEx(&uni, 0) sets MaximumLength to %u, expected %u\n", - uni.MaximumLength, 12345); - ok(uni.Buffer == (void *) 0xdeadbeef, - "pRtlInitUnicodeStringEx(&uni, 0) sets Buffer to %p, expected %x\n", - uni.Buffer, 0xdeadbeef); + ok(uni.Length == 12345 || + uni.Length == 0, /* win2k3 */ + "pRtlInitUnicodeStringEx(&uni, 0) sets Length to %u, expected 12345 or 0\n", + uni.Length); + ok(uni.MaximumLength == 12345 || + uni.MaximumLength == 0, /* win2k3 */ + "pRtlInitUnicodeStringEx(&uni, 0) sets MaximumLength to %u, expected 12345 or 0\n", + uni.MaximumLength); + ok(uni.Buffer == (void *) 0xdeadbeef || + uni.Buffer == teststring2, /* win2k3 */ + "pRtlInitUnicodeStringEx(&uni, 0) sets Buffer to %p, expected %x or %p\n", + uni.Buffer, 0xdeadbeef, teststring2); uni.Length = 12345; uni.MaximumLength = 12345; @@ -290,7 +293,7 @@ static void test_RtlInitUnicodeStringEx(void) "pRtlInitUnicodeString(&uni, 0) sets Buffer to %p, expected %p\n", uni.Buffer, NULL); - free(teststring2); + HeapFree(GetProcessHeap(), 0, teststring2); } @@ -1215,7 +1218,7 @@ typedef struct { int base; const char *str; int value; - NTSTATUS result; + NTSTATUS result, alternative; } str2int_t; static const str2int_t str2int[] = { @@ -1294,7 +1297,7 @@ static const str2int_t str2int[] = { { 0, "0xF", 0xf, STATUS_SUCCESS}, /* one digit hexadecimal */ { 0, "0xG", 0, STATUS_SUCCESS}, /* empty hexadecimal */ { 0, "0x", 0, STATUS_SUCCESS}, /* empty hexadecimal */ - { 0, "", 0, STATUS_SUCCESS}, /* empty string */ + { 0, "", 0, STATUS_SUCCESS, STATUS_INVALID_PARAMETER}, /* empty string */ { 2, "1011101100", 748, STATUS_SUCCESS}, { 2, "-1011101100", -748, STATUS_SUCCESS}, { 2, "2", 0, STATUS_SUCCESS}, @@ -1302,7 +1305,7 @@ static const str2int_t str2int[] = { { 2, "0o1011101100", 0, STATUS_SUCCESS}, { 2, "0d1011101100", 0, STATUS_SUCCESS}, { 2, "0x1011101100", 0, STATUS_SUCCESS}, - { 2, "", 0, STATUS_SUCCESS}, /* empty string */ + { 2, "", 0, STATUS_SUCCESS, STATUS_INVALID_PARAMETER}, /* empty string */ { 8, "1011101100", 136610368, STATUS_SUCCESS}, { 8, "-1011101100", -136610368, STATUS_SUCCESS}, { 8, "8", 0, STATUS_SUCCESS}, @@ -1310,7 +1313,7 @@ static const str2int_t str2int[] = { { 8, "0o1011101100", 0, STATUS_SUCCESS}, { 8, "0d1011101100", 0, STATUS_SUCCESS}, { 8, "0x1011101100", 0, STATUS_SUCCESS}, - { 8, "", 0, STATUS_SUCCESS}, /* empty string */ + { 8, "", 0, STATUS_SUCCESS, STATUS_INVALID_PARAMETER}, /* empty string */ {10, "1011101100", 1011101100, STATUS_SUCCESS}, {10, "-1011101100", -1011101100, STATUS_SUCCESS}, {10, "0b1011101100", 0, STATUS_SUCCESS}, @@ -1318,7 +1321,7 @@ static const str2int_t str2int[] = { {10, "0d1011101100", 0, STATUS_SUCCESS}, {10, "0x1011101100", 0, STATUS_SUCCESS}, {10, "o12345", 0, STATUS_SUCCESS}, /* Octal although base is 10 */ - {10, "", 0, STATUS_SUCCESS}, /* empty string */ + {10, "", 0, STATUS_SUCCESS, STATUS_INVALID_PARAMETER}, /* empty string */ {16, "1011101100", 286265600, STATUS_SUCCESS}, {16, "-1011101100", -286265600, STATUS_SUCCESS}, {16, "G", 0, STATUS_SUCCESS}, @@ -1327,9 +1330,9 @@ static const str2int_t str2int[] = { {16, "0o1011101100", 0, STATUS_SUCCESS}, {16, "0d1011101100", 286265600, STATUS_SUCCESS}, {16, "0x1011101100", 0, STATUS_SUCCESS}, - {16, "", 0, STATUS_SUCCESS}, /* empty string */ - {20, "0", 0xdeadbeef, STATUS_INVALID_PARAMETER}, /* illegal base */ - {-8, "0", 0xdeadbeef, STATUS_INVALID_PARAMETER}, /* Negative base */ + {16, "", 0, STATUS_SUCCESS, STATUS_INVALID_PARAMETER}, /* empty string */ + {20, "0", 0, STATUS_INVALID_PARAMETER}, /* illegal base */ + {-8, "0", 0, STATUS_INVALID_PARAMETER}, /* Negative base */ /* { 0, NULL, 0, STATUS_SUCCESS}, */ /* NULL as string */ }; #define NB_STR2INT (sizeof(str2int)/sizeof(*str2int)) @@ -1348,13 +1351,21 @@ static void test_RtlUnicodeStringToInteger(void) value = 0xdeadbeef; pRtlInitUnicodeString(&uni, wstr); result = pRtlUnicodeStringToInteger(&uni, str2int[test_num].base, &value); - ok(result == str2int[test_num].result, - "(test %d): RtlUnicodeStringToInteger(\"%s\", %d, [out]) has result %x, expected: %x\n", - test_num, str2int[test_num].str, str2int[test_num].base, result, str2int[test_num].result); - ok(value == str2int[test_num].value, + ok(result == str2int[test_num].result || + (str2int[test_num].alternative && result == str2int[test_num].alternative), + "(test %d): RtlUnicodeStringToInteger(\"%s\", %d, [out]) has result %x, expected: %x (%x)\n", + test_num, str2int[test_num].str, str2int[test_num].base, result, + str2int[test_num].result, str2int[test_num].alternative); + if (result == STATUS_SUCCESS) + ok(value == str2int[test_num].value || + broken(str2int[test_num].str[0] == '\0' && str2int[test_num].base == 16), /* nt4 */ "(test %d): RtlUnicodeStringToInteger(\"%s\", %d, [out]) assigns value %d, expected: %d\n", test_num, str2int[test_num].str, str2int[test_num].base, value, str2int[test_num].value); - free(wstr); + else + ok(value == 0xdeadbeef || value == 0 /* vista */, + "(test %d): RtlUnicodeStringToInteger(\"%s\", %d, [out]) assigns value %d, expected 0 or deadbeef\n", + test_num, str2int[test_num].str, str2int[test_num].base, value); + HeapFree(GetProcessHeap(), 0, wstr); } wstr = AtoW(str2int[1].str); @@ -1364,7 +1375,7 @@ static void test_RtlUnicodeStringToInteger(void) "call failed: RtlUnicodeStringToInteger(\"%s\", %d, NULL) has result %x\n", str2int[1].str, str2int[1].base, result); result = pRtlUnicodeStringToInteger(&uni, 20, NULL); - ok(result == STATUS_INVALID_PARAMETER, + ok(result == STATUS_INVALID_PARAMETER || result == STATUS_ACCESS_VIOLATION, "call failed: RtlUnicodeStringToInteger(\"%s\", 20, NULL) has result %x\n", str2int[1].str, result); @@ -1379,12 +1390,11 @@ static void test_RtlUnicodeStringToInteger(void) uni.Length = 5; /* Use odd Length (2.5 WCHARS) */ result = pRtlUnicodeStringToInteger(&uni, str2int[1].base, &value); - ok(result == STATUS_SUCCESS, + ok(result == STATUS_SUCCESS || result == STATUS_INVALID_PARAMETER /* vista */, "call failed: RtlUnicodeStringToInteger(\"12\", %d, [out]) has result %x\n", str2int[1].base, result); - ok(value == 12, - "didn't return expected value (test b): expected: %d, got: %d\n", - 12, value); + if (result == STATUS_SUCCESS) + ok(value == 12, "didn't return expected value (test b): expected: %d, got: %d\n", 12, value); uni.Length = 2; result = pRtlUnicodeStringToInteger(&uni, str2int[1].base, &value); @@ -1395,7 +1405,7 @@ static void test_RtlUnicodeStringToInteger(void) "didn't return expected value (test c): expected: %d, got: %d\n", 1, value); /* w2k: uni.Length = 0 returns value 11234567 instead of 0 */ - free(wstr); + HeapFree(GetProcessHeap(), 0, wstr); } @@ -1410,12 +1420,19 @@ static void test_RtlCharToInteger(void) if (str2int[test_num].str[0] != '\0') { value = 0xdeadbeef; result = pRtlCharToInteger(str2int[test_num].str, str2int[test_num].base, &value); - ok(result == str2int[test_num].result, - "(test %d): call failed: RtlCharToInteger(\"%s\", %d, [out]) has result %x, expected: %x\n", - test_num, str2int[test_num].str, str2int[test_num].base, result, str2int[test_num].result); + ok(result == str2int[test_num].result || + (str2int[test_num].alternative && result == str2int[test_num].alternative), + "(test %d): call failed: RtlCharToInteger(\"%s\", %d, [out]) has result %x, expected: %x (%x)\n", + test_num, str2int[test_num].str, str2int[test_num].base, result, + str2int[test_num].result, str2int[test_num].alternative); + if (result == STATUS_SUCCESS) ok(value == str2int[test_num].value, "(test %d): call failed: RtlCharToInteger(\"%s\", %d, [out]) assigns value %d, expected: %d\n", test_num, str2int[test_num].str, str2int[test_num].base, value, str2int[test_num].value); + else + ok(value == 0 || value == 0xdeadbeef, + "(test %d): call failed: RtlCharToInteger(\"%s\", %d, [out]) assigns value %d, expected 0 or deadbeef\n", + test_num, str2int[test_num].str, str2int[test_num].base, value); } } @@ -1477,8 +1494,8 @@ static const int2str_t int2str[] = { { 2, 1000, 10, 33, "1111101000\0------------------------", STATUS_SUCCESS}, { 2, 10000, 14, 33, "10011100010000\0--------------------", STATUS_SUCCESS}, { 2, 32767, 15, 33, "111111111111111\0-------------------", STATUS_SUCCESS}, - { 2, 32768, 16, 33, "1000000000000000\0------------------", STATUS_SUCCESS}, - { 2, 65535, 16, 33, "1111111111111111\0------------------", STATUS_SUCCESS}, +/* { 2, 32768, 16, 33, "1000000000000000\0------------------", STATUS_SUCCESS}, broken on windows */ +/* { 2, 65535, 16, 33, "1111111111111111\0------------------", STATUS_SUCCESS}, broken on windows */ { 2, 65536, 17, 33, "10000000000000000\0-----------------", STATUS_SUCCESS}, { 2, 100000, 17, 33, "11000011010100000\0-----------------", STATUS_SUCCESS}, { 2, 1000000, 20, 33, "11110100001001000000\0--------------", STATUS_SUCCESS}, @@ -1532,8 +1549,8 @@ static const int2str_t int2str[] = { {16, 4294967294U, 8, 9, "FFFFFFFE\0--------------------------", STATUS_SUCCESS}, {16, 4294967295U, 8, 9, "FFFFFFFF\0--------------------------", STATUS_SUCCESS}, /* max unsigned int */ - { 2, 32768, 16, 17, "1000000000000000\0------------------", STATUS_SUCCESS}, - { 2, 32768, 16, 16, "1000000000000000-------------------", STATUS_SUCCESS}, +/* { 2, 32768, 16, 17, "1000000000000000\0------------------", STATUS_SUCCESS}, broken on windows */ +/* { 2, 32768, 16, 16, "1000000000000000-------------------", STATUS_SUCCESS}, broken on windows */ { 2, 65536, 17, 18, "10000000000000000\0-----------------", STATUS_SUCCESS}, { 2, 65536, 17, 17, "10000000000000000------------------", STATUS_SUCCESS}, { 2, 131072, 18, 19, "100000000000000000\0----------------", STATUS_SUCCESS}, @@ -1675,18 +1692,26 @@ static void test_RtlIsTextUnicode(void) { char ascii[] = "A simple string"; WCHAR unicode[] = {'A',' ','U','n','i','c','o','d','e',' ','s','t','r','i','n','g',0}; + WCHAR unicode_no_controls[] = {'A','U','n','i','c','o','d','e','s','t','r','i','n','g',0}; + /* String with both byte-reversed and standard Unicode control characters. */ + WCHAR mixed_controls[] = {'\t',0x9000,0x0d00,'\n',0}; WCHAR *be_unicode; + WCHAR *be_unicode_no_controls; + BOOLEAN res; int flags; int i; ok(!pRtlIsTextUnicode(ascii, sizeof(ascii), NULL), "ASCII text detected as Unicode\n"); - ok(pRtlIsTextUnicode(unicode, sizeof(unicode), NULL), "Text should be Unicode\n"); + res = pRtlIsTextUnicode(unicode, sizeof(unicode), NULL); + ok(res || + broken(res == FALSE), /* NT4 */ + "Text should be Unicode\n"); + ok(!pRtlIsTextUnicode(unicode, sizeof(unicode) - 1, NULL), "Text should be Unicode\n"); flags = IS_TEXT_UNICODE_UNICODE_MASK; ok(pRtlIsTextUnicode(unicode, sizeof(unicode), &flags), "Text should not pass a Unicode\n"); - todo_wine ok(flags == (IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_CONTROLS), "Expected flags 0x6, obtained %x\n", flags); @@ -1705,7 +1730,7 @@ static void test_RtlIsTextUnicode(void) be_unicode[i + 1] = (unicode[i] >> 8) | ((unicode[i] & 0xff) << 8); } ok(!pRtlIsTextUnicode(be_unicode, sizeof(unicode) + 2, NULL), "Reverse endian should not be Unicode\n"); - todo_wine ok(!pRtlIsTextUnicode(&be_unicode[1], sizeof(unicode), NULL), "Reverse endian should not be Unicode\n"); + ok(!pRtlIsTextUnicode(&be_unicode[1], sizeof(unicode), NULL), "Reverse endian should not be Unicode\n"); flags = IS_TEXT_UNICODE_REVERSE_MASK; ok(!pRtlIsTextUnicode(&be_unicode[1], sizeof(unicode), &flags), "Reverse endian should be Unicode\n"); @@ -1715,10 +1740,74 @@ static void test_RtlIsTextUnicode(void) flags = IS_TEXT_UNICODE_REVERSE_MASK; ok(!pRtlIsTextUnicode(be_unicode, sizeof(unicode) + 2, &flags), "Reverse endian should be Unicode\n"); - todo_wine ok(flags == (IS_TEXT_UNICODE_REVERSE_CONTROLS | IS_TEXT_UNICODE_REVERSE_SIGNATURE), "Expected flags 0xc0, obtained %x\n", flags); + + /* build byte reversed unicode string with no control chars */ + be_unicode_no_controls = HeapAlloc(GetProcessHeap(), 0, sizeof(unicode) + sizeof(WCHAR)); + ok(be_unicode_no_controls != NULL, "Expeced HeapAlloc to succeed.\n"); + be_unicode_no_controls[0] = 0xfffe; + for (i = 0; i < sizeof(unicode_no_controls)/sizeof(unicode_no_controls[0]); i++) + be_unicode_no_controls[i + 1] = (unicode_no_controls[i] >> 8) | ((unicode_no_controls[i] & 0xff) << 8); + + + /* The following tests verify that the tests for */ + /* IS_TEXT_UNICODE_CONTROLS and IS_TEXT_UNICODE_REVERSE_CONTROLS */ + /* are not mutually exclusive. Regardless of whether the strings */ + /* contain an indication of endianness, the tests are still */ + /* run if the flag is passed to (Rtl)IsTextUnicode. */ + + /* Test IS_TEXT_UNICODE_CONTROLS flag */ + flags = IS_TEXT_UNICODE_CONTROLS; + ok(!pRtlIsTextUnicode(unicode_no_controls, sizeof(unicode_no_controls), &flags), "Test should not pass on Unicode string lacking control characters.\n"); + ok(flags == 0, "Expected flags 0x0, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_CONTROLS; + ok(!pRtlIsTextUnicode(be_unicode_no_controls, sizeof(unicode_no_controls), &flags), "Test should not pass on byte-reversed Unicode string lacking control characters.\n"); + ok(flags == 0, "Expected flags 0x0, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_CONTROLS; + ok(pRtlIsTextUnicode(unicode, sizeof(unicode), &flags), "Test should pass on Unicode string lacking control characters.\n"); + ok(flags == IS_TEXT_UNICODE_CONTROLS, "Expected flags 0x04, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_CONTROLS; + ok(!pRtlIsTextUnicode(be_unicode_no_controls, sizeof(unicode_no_controls) + 2, &flags), + "Test should not pass with standard Unicode string.\n"); + ok(flags == 0, "Expected flags 0x0, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_CONTROLS; + ok(pRtlIsTextUnicode(mixed_controls, sizeof(mixed_controls), &flags), "Test should pass on a string containing control characters.\n"); + ok(flags == IS_TEXT_UNICODE_CONTROLS, "Expected flags 0x04, obtained %x\n", flags); + + /* Test IS_TEXT_UNICODE_REVERSE_CONTROLS flag */ + flags = IS_TEXT_UNICODE_REVERSE_CONTROLS; + ok(!pRtlIsTextUnicode(be_unicode_no_controls, sizeof(unicode_no_controls), &flags), "Test should not pass on Unicode string lacking control characters.\n"); + ok(flags == 0, "Expected flags 0x0, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_REVERSE_CONTROLS; + ok(!pRtlIsTextUnicode(unicode_no_controls, sizeof(unicode_no_controls), &flags), "Test should not pass on Unicode string lacking control characters.\n"); + ok(flags == 0, "Expected flags 0x0, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_REVERSE_CONTROLS; + ok(!pRtlIsTextUnicode(unicode, sizeof(unicode), &flags), "Test should not pass on Unicode string lacking control characters.\n"); + ok(flags == 0, "Expected flags 0x0, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_REVERSE_CONTROLS; + ok(!pRtlIsTextUnicode(be_unicode, sizeof(unicode) + 2, &flags), + "Test should pass with byte-reversed Unicode string containing control characters.\n"); + ok(flags == IS_TEXT_UNICODE_REVERSE_CONTROLS, "Expected flags 0x40, obtained %x\n", flags); + + flags = IS_TEXT_UNICODE_REVERSE_CONTROLS; + ok(!pRtlIsTextUnicode(mixed_controls, sizeof(mixed_controls), &flags), "Test should pass on a string containing byte-reversed control characters.\n"); + ok(flags == IS_TEXT_UNICODE_REVERSE_CONTROLS, "Expected flags 0x40, obtained %x\n", flags); + + /* Test with flags for both byte-reverse and standard Unicode characters */ + flags = IS_TEXT_UNICODE_CONTROLS | IS_TEXT_UNICODE_REVERSE_CONTROLS; + ok(!pRtlIsTextUnicode(mixed_controls, sizeof(mixed_controls), &flags), "Test should pass on string containing both byte-reversed and standard control characters.\n"); + ok(flags == (IS_TEXT_UNICODE_CONTROLS | IS_TEXT_UNICODE_REVERSE_CONTROLS), "Expected flags 0x44, obtained %x\n", flags); + HeapFree(GetProcessHeap(), 0, be_unicode); + HeapFree(GetProcessHeap(), 0, be_unicode_no_controls); } static const WCHAR szGuid[] = { '{','0','1','0','2','0','3','0','4','-', diff --git a/rostests/winetests/ntdll/string.c b/rostests/winetests/ntdll/string.c index e9bf5e10704..00adf104732 100755 --- a/rostests/winetests/ntdll/string.c +++ b/rostests/winetests/ntdll/string.c @@ -591,20 +591,23 @@ static void one_i64toa_test(int test_num, const ulonglong2str_t *ulonglong2str) dest_str[LARGE_STRI_BUFFER_LENGTH] = '\0'; result = p_i64toa(ulonglong2str->value, dest_str, ulonglong2str->base); ok(result == dest_str, - "(test %d): _i64toa(%Lu, [out], %d) has result %p, expected: %p\n", - test_num, ulonglong2str->value, ulonglong2str->base, result, dest_str); + "(test %d): _i64toa(%08x%08x, [out], %d) has result %p, expected: %p\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, result, dest_str); if (ulonglong2str->mask & 0x04) { if (memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) != 0) { if (memcmp(dest_str, ulonglong2str[1].Buffer, LARGE_STRI_BUFFER_LENGTH) != 0) { ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0, - "(test %d): _i64toa(%Lu, [out], %d) assigns string \"%s\", expected: \"%s\"\n", - test_num, ulonglong2str->value, ulonglong2str->base, dest_str, ulonglong2str->Buffer); + "(test %d): _i64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, dest_str, ulonglong2str->Buffer); } /* if */ } /* if */ } else { ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0, - "(test %d): _i64toa(%Lu, [out], %d) assigns string \"%s\", expected: \"%s\"\n", - test_num, ulonglong2str->value, ulonglong2str->base, dest_str, ulonglong2str->Buffer); + "(test %d): _i64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, dest_str, ulonglong2str->Buffer); } /* if */ } @@ -618,11 +621,13 @@ static void one_ui64toa_test(int test_num, const ulonglong2str_t *ulonglong2str) dest_str[LARGE_STRI_BUFFER_LENGTH] = '\0'; result = p_ui64toa(ulonglong2str->value, dest_str, ulonglong2str->base); ok(result == dest_str, - "(test %d): _ui64toa(%Lu, [out], %d) has result %p, expected: %p\n", - test_num, ulonglong2str->value, ulonglong2str->base, result, dest_str); + "(test %d): _ui64toa(%08x%08x, [out], %d) has result %p, expected: %p\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, result, dest_str); ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0, - "(test %d): _ui64toa(%Lu, [out], %d) assigns string \"%s\", expected: \"%s\"\n", - test_num, ulonglong2str->value, ulonglong2str->base, dest_str, ulonglong2str->Buffer); + "(test %d): _ui64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n", + test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value, + ulonglong2str->base, dest_str, ulonglong2str->Buffer); } @@ -893,6 +898,31 @@ static void test_wtoi(void) } /* for */ } +static void test_atoi(void) +{ + int test_num; + int result; + + for (test_num = 0; test_num < NB_STR2LONG; test_num++) { + result = patoi(str2long[test_num].str); + ok(result == str2long[test_num].value, + "(test %d): call failed: _atoi(\"%s\") has result %d, expected: %d\n", + test_num, str2long[test_num].str, result, str2long[test_num].value); + } +} + +static void test_atol(void) +{ + int test_num; + int result; + + for (test_num = 0; test_num < NB_STR2LONG; test_num++) { + result = patol(str2long[test_num].str); + ok(result == str2long[test_num].value, + "(test %d): call failed: _atol(\"%s\") has result %d, expected: %d\n", + test_num, str2long[test_num].str, result, str2long[test_num].value); + } +} static void test_wtol(void) { @@ -914,6 +944,7 @@ static void test_wtol(void) typedef struct { const char *str; LONGLONG value; + int overflow; } str2longlong_t; static const str2longlong_t str2longlong[] = { @@ -968,8 +999,8 @@ static const str2longlong_t str2longlong[] = { { "00x12345", 0 }, { "0xx12345", 0 }, { "1x34", 1 }, - { "-99999999999999999999", -ULL(0x6bc75e2d,0x630fffff) }, /* Big negative integer */ - { "-9223372036854775809", ULL(0x7fffffff,0xffffffff) }, /* Too small to fit in 64 bits */ + { "-99999999999999999999", -ULL(0x6bc75e2d,0x630fffff), -1 }, /* Big negative integer */ + { "-9223372036854775809", ULL(0x7fffffff,0xffffffff), -1 }, /* Too small to fit in 64 bits */ { "-9223372036854775808", ULL(0x80000000,0x00000000) }, /* Smallest negative 64 bit integer */ { "-9223372036854775807", -ULL(0x7fffffff,0xffffffff) }, { "-9999999999", -ULL(0x00000002,0x540be3ff) }, @@ -989,12 +1020,12 @@ static const str2longlong_t str2longlong[] = { { "9999999999", ULL(0x00000002,0x540be3ff) }, { "9223372036854775806", ULL(0x7fffffff,0xfffffffe) }, { "9223372036854775807", ULL(0x7fffffff,0xffffffff) }, /* Largest signed positive 64 bit integer */ - { "9223372036854775808", ULL(0x80000000,0x00000000) }, /* Pos int equal to smallest neg 64 bit int */ - { "9223372036854775809", ULL(0x80000000,0x00000001) }, - { "18446744073709551614", ULL(0xffffffff,0xfffffffe) }, - { "18446744073709551615", ULL(0xffffffff,0xffffffff) }, /* Largest unsigned 64 bit integer */ - { "18446744073709551616", 0 }, /* Too big to fit in 64 bits */ - { "99999999999999999999", ULL(0x6bc75e2d,0x630fffff) }, /* Big positive integer */ + { "9223372036854775808", ULL(0x80000000,0x00000000), 1 }, /* Pos int equal to smallest neg 64 bit int */ + { "9223372036854775809", ULL(0x80000000,0x00000001), 1 }, + { "18446744073709551614", ULL(0xffffffff,0xfffffffe), 1 }, + { "18446744073709551615", ULL(0xffffffff,0xffffffff), 1 }, /* Largest unsigned 64 bit integer */ + { "18446744073709551616", 0, 1 }, /* Too big to fit in 64 bits */ + { "99999999999999999999", ULL(0x6bc75e2d,0x630fffff), 1 }, /* Big positive integer */ { "056789", 56789 }, /* Leading zero and still decimal */ { "b1011101100", 0 }, /* Binary (b-notation) */ { "-b1011101100", 0 }, /* Negative Binary (b-notation) */ @@ -1041,11 +1072,19 @@ static void test_atoi64(void) for (test_num = 0; test_num < NB_STR2LONGLONG; test_num++) { result = p_atoi64(str2longlong[test_num].str); + if (str2longlong[test_num].overflow) + ok(result == str2longlong[test_num].value || + (result == (str2longlong[test_num].overflow == -1) ? + ULL(0x80000000,0x00000000) : ULL(0x7fffffff,0xffffffff)), + "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n", + test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result, + (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value); + else ok(result == str2longlong[test_num].value, "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n", test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result, (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value); - } /* for */ +} } @@ -1058,12 +1097,20 @@ static void test_wtoi64(void) for (test_num = 0; test_num < NB_STR2LONGLONG; test_num++) { pRtlCreateUnicodeStringFromAsciiz(&uni, str2longlong[test_num].str); result = p_wtoi64(uni.Buffer); + if (str2longlong[test_num].overflow) + ok(result == str2longlong[test_num].value || + (result == (str2longlong[test_num].overflow == -1) ? + ULL(0x80000000,0x00000000) : ULL(0x7fffffff,0xffffffff)), + "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n", + test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result, + (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value); + else ok(result == str2longlong[test_num].value, - "(test %d): call failed: _wtoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n", + "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n", test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result, (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value); pRtlFreeUnicodeString(&uni); - } /* for */ +} } static void test_wcsfuncs(void) @@ -1095,4 +1142,8 @@ START_TEST(string) test_wtoi64(); if (p_wcschr && p_wcsrchr) test_wcsfuncs(); + if (patoi) + test_atoi(); + if (patol) + test_atol(); } diff --git a/rostests/winetests/ntdsapi/ntdsapi.c b/rostests/winetests/ntdsapi/ntdsapi.c new file mode 100644 index 00000000000..8290ed2cbf1 --- /dev/null +++ b/rostests/winetests/ntdsapi/ntdsapi.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008 Robert Shearman (for CodeWeavers) + * + * 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 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" +#include "rpc.h" +#include "rpcdce.h" +#include "ntdsapi.h" + +#include "wine/test.h" + +static void test_DsMakeSpn(void) +{ + DWORD ret; + WCHAR spn[256]; + DWORD spn_length; + static const WCHAR wszServiceClass[] = {'c','l','a','s','s',0}; + static const WCHAR wszServiceHost[] = {'h','o','s','t',0}; + static const WCHAR wszInstanceName[] = {'i','n','s','t','a','n','c','e',0}; + static const WCHAR wszReferrer[] = {'r','e','f','e','r','r','e','r',0}; + static const WCHAR wszSpn1[] = {'c','l','a','s','s','/','h','o','s','t',0}; + static const WCHAR wszSpn2[] = {'c','l','a','s','s','/','i','n','s','t','a','n','c','e','/','h','o','s','t',0}; + static const WCHAR wszSpn3[] = {'c','l','a','s','s','/','i','n','s','t','a','n','c','e',':','5','5','5','/','h','o','s','t',0}; + static const WCHAR wszSpn4[] = {'c','l','a','s','s','/','i','n','s','t','a','n','c','e',':','5','5','5','/','h','o','s','t',0}; + static const WCHAR wszSpn5[] = {'c','l','a','s','s','/','h','o','s','t',':','5','5','5',0}; + + spn[0] = '\0'; + + spn_length = sizeof(spn)/sizeof(spn[0]); + ret = DsMakeSpnW(NULL, NULL, NULL, 0, NULL, &spn_length, spn); + ok(ret == ERROR_INVALID_PARAMETER, "DsMakeSpnW should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret); + + spn_length = sizeof(spn)/sizeof(spn[0]); + ret = DsMakeSpnW(NULL, wszServiceHost, NULL, 0, NULL, &spn_length, spn); + ok(ret == ERROR_INVALID_PARAMETER, "DsMakeSpnW should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret); + + spn_length = sizeof(spn)/sizeof(spn[0]); + ret = DsMakeSpnW(wszServiceClass, wszServiceHost, NULL, 0, NULL, &spn_length, spn); + ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret); + ok(!lstrcmpW(spn, wszSpn1), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn)); + ok(spn_length == lstrlenW(wszSpn1) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn1) + 1, spn_length); + + spn_length = sizeof(spn)/sizeof(spn[0]); + ret = DsMakeSpnW(wszServiceClass, wszServiceHost, wszInstanceName, 0, NULL, &spn_length, spn); + ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret); + ok(!lstrcmpW(spn, wszSpn2), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn)); + ok(spn_length == lstrlenW(wszSpn2) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn2) + 1, spn_length); + + spn_length = sizeof(spn)/sizeof(spn[0]); + ret = DsMakeSpnW(wszServiceClass, wszServiceHost, wszInstanceName, 555, NULL, &spn_length, spn); + ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret); + ok(!lstrcmpW(spn, wszSpn3), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn)); + ok(spn_length == lstrlenW(wszSpn3) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn3) + 1, spn_length); + + spn_length = sizeof(spn)/sizeof(spn[0]); + ret = DsMakeSpnW(wszServiceClass, wszServiceHost, wszInstanceName, 555, wszReferrer, &spn_length, spn); + ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret); + ok(!lstrcmpW(spn, wszSpn4), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn)); + ok(spn_length == lstrlenW(wszSpn4) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn4) + 1, spn_length); + + spn_length = sizeof(spn)/sizeof(spn[0]); + ret = DsMakeSpnW(wszServiceClass, wszServiceHost, NULL, 555, wszReferrer, &spn_length, spn); + ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret); + ok(!lstrcmpW(spn, wszSpn5), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn)); + ok(spn_length == lstrlenW(wszSpn5) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn5) + 1, spn_length); +} + +START_TEST( ntdsapi ) +{ + test_DsMakeSpn(); +} diff --git a/rostests/winetests/ntdsapi/ntdsapi.rbuild b/rostests/winetests/ntdsapi/ntdsapi.rbuild new file mode 100644 index 00000000000..ce6c229164c --- /dev/null +++ b/rostests/winetests/ntdsapi/ntdsapi.rbuild @@ -0,0 +1,9 @@ + + . + + ntdsapi.c + testlist.c + wine + ntdsapi + ntdll + diff --git a/rostests/winetests/ntdsapi/testlist.c b/rostests/winetests/ntdsapi/testlist.c new file mode 100644 index 00000000000..c21305eb764 --- /dev/null +++ b/rostests/winetests/ntdsapi/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_ntdsapi(void); + +const struct test winetest_testlist[] = +{ + { "ntdsapi", func_ntdsapi }, + { 0, 0 } +}; diff --git a/rostests/winetests/ntprint/ntprint.c b/rostests/winetests/ntprint/ntprint.c new file mode 100644 index 00000000000..fca7b8d4848 --- /dev/null +++ b/rostests/winetests/ntprint/ntprint.c @@ -0,0 +1,230 @@ +/* + * Unit test suite for the Spooler Setup API (Printing) + * + * Copyright 2007 Detlef Riekenberg + * + * 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 + * + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wingdi.h" +#include "wine/test.h" + + +/* ##### */ + +static HMODULE hdll; +static HANDLE (WINAPI *pPSetupCreateMonitorInfo)(LPVOID, LPVOID, LPVOID); +static VOID (WINAPI *pPSetupDestroyMonitorInfo)(HANDLE); +static BOOL (WINAPI *pPSetupEnumMonitor)(HANDLE, DWORD, LPWSTR, LPDWORD); + +/* ########################### */ + +static LPCSTR load_functions(void) +{ + LPCSTR ptr; + + ptr = "ntprint.dll"; + hdll = LoadLibraryA(ptr); + if (!hdll) return ptr; + + ptr = "PSetupCreateMonitorInfo"; + pPSetupCreateMonitorInfo = (VOID *) GetProcAddress(hdll, ptr); + if (!pPSetupCreateMonitorInfo) return ptr; + + ptr = "PSetupDestroyMonitorInfo"; + pPSetupDestroyMonitorInfo = (VOID *) GetProcAddress(hdll, ptr); + if (!pPSetupDestroyMonitorInfo) return ptr; + + ptr = "PSetupEnumMonitor"; + pPSetupEnumMonitor = (VOID *) GetProcAddress(hdll, ptr); + if (!pPSetupEnumMonitor) return ptr; + + return NULL; +} + +/* ########################### */ + +static void test_PSetupCreateMonitorInfo(VOID) +{ + HANDLE mi; + BYTE buffer[1024] ; + + SetLastError(0xdeadbeef); + mi = pPSetupCreateMonitorInfo(NULL, NULL, NULL); + ok( mi != NULL, "got %p with %u (expected '!= NULL')\n", mi, GetLastError()); + if (mi) pPSetupDestroyMonitorInfo(mi); + + + memset(buffer, 0, sizeof(buffer)); + SetLastError(0xdeadbeef); + mi = pPSetupCreateMonitorInfo(buffer, NULL, NULL); + ok( mi != NULL, "got %p with %u (expected '!= NULL')\n", mi, GetLastError()); + if (mi) pPSetupDestroyMonitorInfo(mi); + +} + +/* ########################### */ + +static void test_PSetupDestroyMonitorInfo(VOID) +{ + HANDLE mi; + + + SetLastError(0xdeadbeef); + pPSetupDestroyMonitorInfo(NULL); + /* lasterror is returned */ + trace("returned with %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + mi = pPSetupCreateMonitorInfo(NULL, NULL, NULL); + ok( mi != NULL, "got %p with %u (expected '!= NULL')\n", mi, GetLastError()); + + if (!mi) return; + + SetLastError(0xdeadbeef); + pPSetupDestroyMonitorInfo(mi); + /* lasterror is returned */ + trace("returned with %u\n", GetLastError()); + + /* Try to destroy the handle twice crash with native ntprint.dll */ + if (0) { + SetLastError(0xdeadbeef); + pPSetupDestroyMonitorInfo(mi); + trace(" with %u\n", GetLastError()); + } + +} + +/* ########################### */ + +static void test_PSetupEnumMonitor(VOID) +{ + HANDLE mi; + WCHAR buffer[MAX_PATH+2]; + DWORD minsize = 0; + DWORD size; + DWORD res; + DWORD index=0; + + SetLastError(0xdeadbeef); + mi = pPSetupCreateMonitorInfo(NULL, NULL, NULL); + if (!mi) { + skip("PSetupCreateMonitorInfo\n"); + return; + } + + minsize = 0; + SetLastError(0xdeadbeef); + res = pPSetupEnumMonitor(mi, 0, NULL, &minsize); + ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) && (minsize > 0), + "got %u with %u and %u (expected '0' with ERROR_INSUFFICIENT_BUFFER " + "and '> 0')\n", res, GetLastError(), minsize); + + + size = sizeof(buffer) / sizeof(buffer[0]); + if ((minsize + 1) > size) { + skip("overflow: %u\n", minsize); + pPSetupDestroyMonitorInfo(mi); + return; + } + + if (0) { + /* XP: ERROR_INVALID_PARAMETER, w2k: Crash */ + SetLastError(0xdeadbeef); + size = sizeof(buffer) / sizeof(buffer[0]); + res = pPSetupEnumMonitor(NULL, 0, buffer, &size); + ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER), + "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); + } + + if (0) { + /* XP: Crash, w2k: Success (how can that work?) */ + SetLastError(0xdeadbeef); + size = sizeof(buffer) / sizeof(buffer[0]); + res = pPSetupEnumMonitor(mi, 0, NULL, &size); + trace("got %u with %u and %u\n", res, GetLastError(), size); + } + + if (0) { + /* XP: ERROR_INVALID_PARAMETER, w2k: Crash */ + SetLastError(0xdeadbeef); + res = pPSetupEnumMonitor(mi, 0, buffer, NULL); + ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER), + "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); + } + + SetLastError(0xdeadbeef); + size = minsize - 1; + res = pPSetupEnumMonitor(mi, 0, buffer, &size); + ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), + "got %u with %u and %u (expected '0' with ERROR_INSUFFICIENT_BUFFER)\n", + res, GetLastError(), size); + + + SetLastError(0xdeadbeef); + size = minsize; + res = pPSetupEnumMonitor(mi, 0, buffer, &size); + ok( res, "got %u with %u and %u (expected '!= 0')\n", + res, GetLastError(), size); + + SetLastError(0xdeadbeef); + size = minsize + 1; + res = pPSetupEnumMonitor(mi, 0, buffer, &size); + ok( res, "got %u with %u and %u (expected '!= 0')\n", + res, GetLastError(), size); + + /* try max. 20 monitors */ + while (res && (index < 20)) { + SetLastError(0xdeadbeef); + buffer[0] = '\0'; + size = sizeof(buffer) / sizeof(buffer[0]); + res = pPSetupEnumMonitor(mi, index, buffer, &size); + ok( res || (GetLastError() == ERROR_NO_MORE_ITEMS), + "(%u) got %u with %u and %u (expected '!=0' or: '0' with " + "ERROR_NO_MORE_ITEMS)\n", index, res, GetLastError(), size); + + if (res) index++; + } + pPSetupDestroyMonitorInfo(mi); + +} + +/* ########################### */ + +START_TEST(ntprint) +{ + LPCSTR ptr; + + /* ntprint.dll does not exist on win9x */ + ptr = load_functions(); + if (ptr) { + skip("%s not found\n", ptr); + return; + } + + test_PSetupCreateMonitorInfo(); + test_PSetupDestroyMonitorInfo(); + test_PSetupEnumMonitor(); + +} diff --git a/rostests/winetests/ntprint/ntprint.rbuild b/rostests/winetests/ntprint/ntprint.rbuild new file mode 100644 index 00000000000..a60b8e96540 --- /dev/null +++ b/rostests/winetests/ntprint/ntprint.rbuild @@ -0,0 +1,8 @@ + + . + + ntprint.c + testlist.c + wine + ntdll + diff --git a/rostests/winetests/ntprint/testlist.c b/rostests/winetests/ntprint/testlist.c new file mode 100644 index 00000000000..25fb277033c --- /dev/null +++ b/rostests/winetests/ntprint/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_ntprint(void); + +const struct test winetest_testlist[] = +{ + { "ntprint", func_ntprint }, + { 0, 0 } +}; diff --git a/rostests/winetests/odbccp32/misc.c b/rostests/winetests/odbccp32/misc.c index ba8e5f45f87..7cf2606ab80 100644 --- a/rostests/winetests/odbccp32/misc.c +++ b/rostests/winetests/odbccp32/misc.c @@ -112,14 +112,24 @@ static void test_SQLInstallDriverManager(void) /* Length OK */ bool_ret = SQLInstallDriverManager(target_path, MAX_PATH, NULL); sql_ret = SQLInstallerErrorW(1, &error_code, NULL, 0, NULL); - ok(bool_ret, "SQLInstallDriverManager unexpectedly failed\n"); + ok(bool_ret, "SQLInstallDriverManager unexpectedly failed: %d\n", + error_code); + if (bool_ret) ok(sql_ret == SQL_NO_DATA, "Expected SQL_NO_DATA, got %d\n", sql_ret); + else + ok(sql_ret == SQL_SUCCESS_WITH_INFO, + "Expected SQL_SUCCESS_WITH_INFO, got %d\n", sql_ret); path_out = 0xcafe; bool_ret = SQLInstallDriverManager(target_path, MAX_PATH, &path_out); sql_ret = SQLInstallerErrorW(1, &error_code, NULL, 0, NULL); - ok(bool_ret, "SQLInstallDriverManager unexpectedly failed\n"); + ok(bool_ret, "SQLInstallDriverManager unexpectedly failed: %d\n", + error_code); + if (bool_ret) ok(sql_ret == SQL_NO_DATA, "Expected SQL_NO_DATA, got %d\n", sql_ret); + else + ok(sql_ret == SQL_SUCCESS_WITH_INFO, + "Expected SQL_SUCCESS_WITH_INFO, got %d\n", sql_ret); /* path_out should in practice be less than 0xcafe */ ok(path_out != 0xcafe, "Expected path_out to show the correct amount of bytes\n"); } diff --git a/rostests/winetests/odbccp32/odbccp32.rbuild b/rostests/winetests/odbccp32/odbccp32.rbuild index faad1e73436..8da1e1f38b4 100644 --- a/rostests/winetests/odbccp32/odbccp32.rbuild +++ b/rostests/winetests/odbccp32/odbccp32.rbuild @@ -3,13 +3,11 @@ . - 0x600 - 0x600 + misc.c testlist.c wine odbccp32 - kernel32 ntdll diff --git a/rostests/winetests/ole32/clipboard.c b/rostests/winetests/ole32/clipboard.c index 26278b6417c..964d02c39d4 100644 --- a/rostests/winetests/ole32/clipboard.c +++ b/rostests/winetests/ole32/clipboard.c @@ -19,8 +19,10 @@ */ #define COBJMACROS +#define NONAMELESSUNION #include +#include #include "windef.h" #include "winbase.h" @@ -37,6 +39,15 @@ (fe).lindex=-1;\ }; +static inline char *dump_fmtetc(FORMATETC *fmt) +{ + static char buf[100]; + + snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x", + fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed); + return buf; +} + typedef struct DataObjectImpl { const IDataObjectVtbl *lpVtbl; LONG ref; @@ -45,6 +56,8 @@ typedef struct DataObjectImpl { UINT fmtetc_cnt; HANDLE text; + IStream *stm; + IStorage *stg; } DataObjectImpl; typedef struct EnumFormatImpl { @@ -59,6 +72,10 @@ typedef struct EnumFormatImpl { static BOOL expect_DataObjectImpl_QueryGetData = TRUE; static ULONG DataObjectImpl_GetData_calls = 0; +static ULONG DataObjectImpl_GetDataHere_calls = 0; +static ULONG DataObjectImpl_EnumFormatEtc_calls = 0; + +static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore; static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc); @@ -68,7 +85,7 @@ static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFII if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) { IEnumFORMATETC_AddRef(iface); - *ppvObj = (LPVOID)This; + *ppvObj = This; return S_OK; } *ppvObj = NULL; @@ -99,15 +116,23 @@ static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) { EnumFormatImpl *This = (EnumFormatImpl*)iface; - ULONG count = 0; + ULONG count, i; + + trace("next: count %d cur %d\n", celt, This->cur); if(!rgelt) return E_INVALIDARG; count = min(celt, This->fmtetc_cnt-This->cur); - if(count > 0) { - memcpy(rgelt, This->fmtetc+This->cur, count*sizeof(FORMATETC)); - This->cur += count; + for(i = 0; i < count; i++, This->cur++, rgelt++) + { + *rgelt = This->fmtetc[This->cur]; + if(rgelt->ptd) + { + DWORD size = This->fmtetc[This->cur].ptd->tdSize; + rgelt->ptd = CoTaskMemAlloc(size); + memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size); + } } if(pceltFetched) *pceltFetched = count; @@ -165,7 +190,7 @@ static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID r if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) { IDataObject_AddRef(iface); - *ppvObj = (LPVOID)This; + *ppvObj = This; return S_OK; } *ppvObj = NULL; @@ -184,9 +209,15 @@ static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface) DataObjectImpl *This = (DataObjectImpl*)iface; ULONG ref = InterlockedDecrement(&This->ref); - if(!ref) { + if(!ref) + { + int i; if(This->text) GlobalFree(This->text); - if(This->fmtetc) GlobalFree(This->fmtetc); + for(i = 0; i < This->fmtetc_cnt; i++) + HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd); + HeapFree(GetProcessHeap(), 0, This->fmtetc); + if(This->stm) IStream_Release(This->stm); + if(This->stg) IStorage_Release(This->stg); HeapFree(GetProcessHeap(), 0, This); } @@ -196,29 +227,56 @@ static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface) static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium) { DataObjectImpl *This = (DataObjectImpl*)iface; + UINT i; + BOOL foundFormat = FALSE; + + trace("getdata: %s\n", dump_fmtetc(pformatetc)); DataObjectImpl_GetData_calls++; if(pformatetc->lindex != -1) - return DV_E_LINDEX; - - if(!(pformatetc->tymed & TYMED_HGLOBAL)) - return DV_E_TYMED; - - if(This->text && pformatetc->cfFormat == CF_TEXT) - U(*pmedium).hGlobal = This->text; - else return DV_E_FORMATETC; - pmedium->tymed = TYMED_HGLOBAL; + for(i = 0; i < This->fmtetc_cnt; i++) + { + if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) + { + foundFormat = TRUE; + if(This->fmtetc[i].tymed & pformatetc->tymed) + { pmedium->pUnkForRelease = (LPUNKNOWN)iface; IUnknown_AddRef(pmedium->pUnkForRelease); + + if(pformatetc->cfFormat == CF_TEXT || pformatetc->cfFormat == cf_global) + { + pmedium->tymed = TYMED_HGLOBAL; + U(*pmedium).hGlobal = This->text; + } + else if(pformatetc->cfFormat == cf_stream) + { + pmedium->tymed = TYMED_ISTREAM; + IStream_AddRef(This->stm); + U(*pmedium).pstm = This->stm; + } + else if(pformatetc->cfFormat == cf_storage || pformatetc->cfFormat == cf_another) + { + pmedium->tymed = TYMED_ISTORAGE; + IStorage_AddRef(This->stg); + U(*pmedium).pstg = This->stg; + } return S_OK; } + } + } + + return foundFormat ? DV_E_TYMED : DV_E_FORMATETC; +} static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium) { - ok(0, "unexpected call\n"); + trace("getdatahere: %s\n", dump_fmtetc(pformatetc)); + DataObjectImpl_GetDataHere_calls++; + return E_NOTIMPL; } @@ -228,6 +286,7 @@ static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC UINT i; BOOL foundFormat = FALSE; + trace("querygetdata: %s\n", dump_fmtetc(pformatetc)); if (!expect_DataObjectImpl_QueryGetData) ok(0, "unexpected call to DataObjectImpl_QueryGetData\n"); @@ -263,6 +322,8 @@ static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwD { DataObjectImpl *This = (DataObjectImpl*)iface; + DataObjectImpl_EnumFormatEtc_calls++; + if(dwDirection != DATADIR_GET) { ok(0, "unexpected direction %d\n", dwDirection); return E_NOTIMPL; @@ -315,6 +376,8 @@ static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj) obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1); strcpy(GlobalLock(obj->text), text); GlobalUnlock(obj->text); + obj->stm = NULL; + obj->stg = NULL; obj->fmtetc_cnt = 1; obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC)); @@ -324,6 +387,59 @@ static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj) return S_OK; } +const char *cmpl_stm_data = "complex stream"; +const char *cmpl_text_data = "complex text"; +const WCHAR device_name[] = {'m','y','d','e','v',0}; + +static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj) +{ + DataObjectImpl *obj; + ILockBytes *lbs; + DEVMODEW dm; + + obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl)); + obj->lpVtbl = &VT_DataObjectImpl; + obj->ref = 1; + obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(cmpl_text_data) + 1); + strcpy(GlobalLock(obj->text), cmpl_text_data); + GlobalUnlock(obj->text); + CreateStreamOnHGlobal(NULL, TRUE, &obj->stm); + IStream_Write(obj->stm, cmpl_stm_data, strlen(cmpl_stm_data), NULL); + + CreateILockBytesOnHGlobal(NULL, TRUE, &lbs); + StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg); + ILockBytes_Release(lbs); + + obj->fmtetc_cnt = 8; + /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */ + obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC)); + InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL); + InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM); + InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE); + InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL); + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; + lstrcpyW(dm.dmDeviceName, device_name); + obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra); + obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra; + obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData); + obj->fmtetc[3].ptd->tdDeviceNameOffset = 0; + obj->fmtetc[3].ptd->tdPortNameOffset = 0; + obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(device_name); + lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, device_name); + memcpy(obj->fmtetc[3].ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra); + + InitFormatEtc(obj->fmtetc[4], cf_global, TYMED_HGLOBAL); + InitFormatEtc(obj->fmtetc[5], cf_another, TYMED_HGLOBAL); + InitFormatEtc(obj->fmtetc[6], cf_another, 0xfffff); + InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff); + obj->fmtetc[7].dwAspect = DVASPECT_ICON; + + *lplpdataobj = (LPDATAOBJECT)obj; + return S_OK; +} + static void test_get_clipboard(void) { HRESULT hr; @@ -359,7 +475,10 @@ static void test_get_clipboard(void) InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); fmtetc.lindex = 256; hr = IDataObject_QueryGetData(data_obj, &fmtetc); - ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + ok(hr == DV_E_FORMATETC || broken(hr == S_OK), + "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + if (hr == S_OK) + ReleaseStgMedium(&stgmedium); InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); fmtetc.cfFormat = CF_RIFF; @@ -397,8 +516,13 @@ static void test_get_clipboard(void) InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); fmtetc.lindex = 256; hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium); - todo_wine - ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr); + if (hr == S_OK) + { + /* undo the unexpected success */ + DataObjectImpl_GetData_calls--; + ReleaseStgMedium(&stgmedium); + } InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL); fmtetc.cfFormat = CF_RIFF; @@ -415,27 +539,296 @@ static void test_get_clipboard(void) IDataObject_Release(data_obj); } +static void test_enum_fmtetc(IDataObject *src) +{ + HRESULT hr; + IDataObject *data; + IEnumFORMATETC *enum_fmt, *src_enum; + FORMATETC fmt, src_fmt; + DWORD count = 0; + + hr = OleGetClipboard(&data); + ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr); + + hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt); + ok(hr == E_NOTIMPL || + broken(hr == E_INVALIDARG), /* win98 (not win98SE) */ + "got %08x\n", hr); + + DataObjectImpl_EnumFormatEtc_calls = 0; + hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt); + ok(hr == S_OK, "got %08x\n", hr); + ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n"); + + if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum); + + while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK) + { + ok(src != NULL, "shouldn't be here\n"); + hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL); + ok(hr == S_OK, "%d: got %08x\n", count, hr); + trace("%d: %s\n", count, dump_fmtetc(&fmt)); + ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat); + ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect); + ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex); + ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed); + if(fmt.ptd) + { + ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count); + CoTaskMemFree(fmt.ptd); + CoTaskMemFree(src_fmt.ptd); + } + count++; + } + + ok(hr == S_FALSE, "%d: got %08x\n", count, hr); + + if(src) + { + hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL); + ok(hr == S_FALSE || + broken(hr == S_OK && count == 5), /* win9x and winme don't enumerate duplicated cf's */ + "%d: got %08x\n", count, hr); + IEnumFORMATETC_Release(src_enum); + } + + hr = IEnumFORMATETC_Reset(enum_fmt); + ok(hr == S_OK, "got %08x\n", hr); + + if(src) /* Exercise the enumerator a bit */ + { + IEnumFORMATETC *clone; + FORMATETC third_fmt; + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IEnumFORMATETC_Reset(enum_fmt); + ok(hr == S_OK, "got %08x\n", hr); + hr = IEnumFORMATETC_Skip(enum_fmt, 2); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IEnumFORMATETC_Clone(enum_fmt, &clone); + ok(hr == S_OK, "got %08x\n", hr); + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n"); + hr = IEnumFORMATETC_Next(clone, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n"); + IEnumFORMATETC_Release(clone); + } + + IEnumFORMATETC_Release(enum_fmt); + IDataObject_Release(data); +} + +static void test_no_cf_dataobject(void) +{ + UINT cf_dataobject = RegisterClipboardFormatA("DataObject"); + UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data"); + HANDLE h; + OpenClipboard(NULL); + + h = GetClipboardData(cf_dataobject); + ok(!h, "got %p\n", h); + h = GetClipboardData(cf_ole_priv_data); + ok(!h, "got %p\n", h); + + CloseClipboard(); +} + +static void test_cf_dataobject(IDataObject *data) +{ + UINT cf = 0; + UINT cf_dataobject = RegisterClipboardFormatA("DataObject"); + UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data"); + BOOL found_dataobject = FALSE, found_priv_data = FALSE; + + OpenClipboard(NULL); + do + { + cf = EnumClipboardFormats(cf); + if(cf == cf_dataobject) + { + HGLOBAL h = GetClipboardData(cf); + HWND *ptr = GlobalLock(h); + DWORD size = GlobalSize(h); + HWND clip_owner = GetClipboardOwner(); + + found_dataobject = TRUE; + ok(size >= sizeof(*ptr), "size %d\n", size); + if(data) + ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner); + else /* ole clipboard flushed */ + ok(*ptr == NULL, "hwnd %p\n", *ptr); + GlobalUnlock(h); + } + else if(cf == cf_ole_priv_data) + { + found_priv_data = TRUE; + if(data) + { + HGLOBAL h = GetClipboardData(cf); + DWORD *ptr = GlobalLock(h); + DWORD size = GlobalSize(h); + + if(size != ptr[1]) + win_skip("Ole Private Data in win9x format\n"); + else + { + HRESULT hr; + IEnumFORMATETC *enum_fmt; + DWORD count = 0; + FORMATETC fmt; + struct formatetcetc + { + FORMATETC fmt; + BOOL first_use_of_cf; + DWORD res[2]; + } *fmt_ptr; + struct priv_data + { + DWORD res1; + DWORD size; + DWORD res2; + DWORD count; + DWORD res3[2]; + struct formatetcetc fmts[1]; + } *priv = (struct priv_data*)ptr; + CLIPFORMAT cfs_seen[10]; + + hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt); + ok(hr == S_OK, "got %08x\n", hr); + fmt_ptr = priv->fmts; + + while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK) + { + int i; + BOOL seen_cf = FALSE; + + ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat, + "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat); + ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n", + fmt_ptr->fmt.dwAspect, fmt.dwAspect); + ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n", + fmt_ptr->fmt.lindex, fmt.lindex); + ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n", + fmt_ptr->fmt.tymed, fmt.tymed); + for(i = 0; i < count; i++) + if(fmt_ptr->fmt.cfFormat == cfs_seen[i]) + { + seen_cf = TRUE; + break; + } + cfs_seen[count] = fmt.cfFormat; + ok(fmt_ptr->first_use_of_cf == seen_cf ? FALSE : TRUE, "got %08x expected %08x\n", + fmt_ptr->first_use_of_cf, !seen_cf); + ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[1]); + ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[2]); + if(fmt.ptd) + { + DVTARGETDEVICE *target; + + ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n"); + target = (DVTARGETDEVICE*)((char*)priv + (DWORD)fmt_ptr->fmt.ptd); + ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n"); + CoTaskMemFree(fmt.ptd); + } + fmt_ptr++; + count++; + } + ok(priv->res1 == 0, "got %08x\n", priv->res1); + ok(priv->res2 == 1, "got %08x\n", priv->res2); + ok(priv->count == count, "got %08x expected %08x\n", priv->count, count); + ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]); + + /* win64 sets the lsb */ + if(sizeof(fmt_ptr->fmt.ptd) == 8) + todo_wine ok(priv->res3[1] == 1, "got %08x\n", priv->res3[1]); + else + ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]); + + GlobalUnlock(h); + IEnumFORMATETC_Release(enum_fmt); + } + } + } + else if(cf == cf_stream) + { + HGLOBAL h; + void *ptr; + DWORD size; + + DataObjectImpl_GetDataHere_calls = 0; + h = GetClipboardData(cf); + ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls); + ptr = GlobalLock(h); + size = GlobalSize(h); + ok(size == strlen(cmpl_stm_data) || + broken(size > strlen(cmpl_stm_data)), /* win9x, winme */ + "expected %d got %d\n", lstrlenA(cmpl_stm_data), size); + ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n"); + GlobalUnlock(h); + } + else if(cf == cf_global) + { + HGLOBAL h; + void *ptr; + DWORD size; + + DataObjectImpl_GetDataHere_calls = 0; + h = GetClipboardData(cf); + ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls); + ptr = GlobalLock(h); + size = GlobalSize(h); + ok(size == strlen(cmpl_text_data) + 1 || + broken(size > strlen(cmpl_text_data) + 1), /* win9x, winme */ + "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size); + ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n"); + GlobalUnlock(h); + } + } while(cf); + CloseClipboard(); + ok(found_dataobject, "didn't find cf_dataobject\n"); + ok(found_priv_data, "didn't find cf_ole_priv_data\n"); +} + static void test_set_clipboard(void) { HRESULT hr; ULONG ref; - LPDATAOBJECT data1, data2; + LPDATAOBJECT data1, data2, data_cmpl; + HGLOBAL hblob, h; + + cf_stream = RegisterClipboardFormatA("stream format"); + cf_storage = RegisterClipboardFormatA("storage format"); + cf_global = RegisterClipboardFormatA("global format"); + cf_another = RegisterClipboardFormatA("another format"); + cf_onemore = RegisterClipboardFormatA("one more format"); + hr = DataObjectImpl_CreateText("data1", &data1); ok(SUCCEEDED(hr), "Failed to create data1 object: 0x%08x\n", hr); if(FAILED(hr)) return; hr = DataObjectImpl_CreateText("data2", &data2); ok(SUCCEEDED(hr), "Failed to create data2 object: 0x%08x\n", hr); + if(FAILED(hr)) + return; + hr = DataObjectImpl_CreateComplex(&data_cmpl); + ok(SUCCEEDED(hr), "Failed to create complex data object: 0x%08x\n", hr); if(FAILED(hr)) return; hr = OleSetClipboard(data1); - todo_wine ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr); CoInitialize(NULL); hr = OleSetClipboard(data1); - todo_wine ok(hr == CO_E_NOTINITIALIZED || hr == CLIPBRD_E_CANT_SET, /* win9x */ "OleSetClipboard should have failed with " @@ -447,10 +840,15 @@ static void test_set_clipboard(void) hr = OleSetClipboard(data1); ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr); + + test_cf_dataobject(data1); + hr = OleIsCurrentClipboard(data1); ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr); hr = OleIsCurrentClipboard(data2); ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr); + hr = OleIsCurrentClipboard(NULL); + ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr); test_get_clipboard(); @@ -460,6 +858,20 @@ static void test_set_clipboard(void) ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr); hr = OleIsCurrentClipboard(data2); ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr); + hr = OleIsCurrentClipboard(NULL); + ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr); + + /* put a format directly onto the clipboard to show + OleFlushClipboard doesn't empty the clipboard */ + hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10); + OpenClipboard(NULL); + h = SetClipboardData(cf_onemore, hblob); + ok(h == hblob, "got %p\n", h); + h = GetClipboardData(cf_onemore); + ok(h == hblob || + broken(h != NULL), /* win9x */ + "got %p\n", h); + CloseClipboard(); hr = OleFlushClipboard(); ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr); @@ -467,19 +879,642 @@ static void test_set_clipboard(void) ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr); hr = OleIsCurrentClipboard(data2); ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr); + hr = OleIsCurrentClipboard(NULL); + ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr); + + /* format should survive the flush */ + OpenClipboard(NULL); + h = GetClipboardData(cf_onemore); + ok(h == hblob || + broken(h != NULL), /* win9x */ + "got %p\n", h); + CloseClipboard(); + + test_cf_dataobject(NULL); ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr); + OpenClipboard(NULL); + h = GetClipboardData(cf_onemore); + ok(h == NULL, "got %p\n", h); + CloseClipboard(); + + trace("setting complex\n"); + hr = OleSetClipboard(data_cmpl); + ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr); + test_cf_dataobject(data_cmpl); + test_enum_fmtetc(data_cmpl); + + ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr); + + test_no_cf_dataobject(); + test_enum_fmtetc(NULL); + ref = IDataObject_Release(data1); ok(ref == 0, "expected data1 ref=0, got %d\n", ref); ref = IDataObject_Release(data2); ok(ref == 0, "expected data2 ref=0, got %d\n", ref); + ref = IDataObject_Release(data_cmpl); + ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref); OleUninitialize(); } +static inline ULONG count_refs(IDataObject *d) +{ + IDataObject_AddRef(d); + return IDataObject_Release(d); +} + +static void test_consumer_refs(void) +{ + HRESULT hr; + IDataObject *src, *src2, *get1, *get2, *get3; + ULONG refs, old_refs; + FORMATETC fmt; + STGMEDIUM med; + + InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL); + + OleInitialize(NULL); + + /* First show that each clipboard state results in + a different data object */ + + hr = DataObjectImpl_CreateText("data1", &src); + ok(hr == S_OK, "got %08x\n", hr); + hr = DataObjectImpl_CreateText("data2", &src2); + ok(hr == S_OK, "got %08x\n", hr); + + hr = OleSetClipboard(src); + ok(hr == S_OK, "got %08x\n", hr); + + hr = OleGetClipboard(&get1); + ok(hr == S_OK, "got %08x\n", hr); + + hr = OleGetClipboard(&get2); + ok(hr == S_OK, "got %08x\n", hr); + + ok(get1 == get2 || + broken(get1 != get2), /* win9x, winme & nt4 */ + "data objects differ\n"); + refs = IDataObject_Release(get2); + ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs); + + OleFlushClipboard(); + + DataObjectImpl_GetData_calls = 0; + hr = IDataObject_GetData(get1, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(DataObjectImpl_GetData_calls == 0, "GetData called\n"); + ReleaseStgMedium(&med); + + hr = OleGetClipboard(&get2); + ok(hr == S_OK, "got %08x\n", hr); + + ok(get1 != get2, "data objects match\n"); + + OleSetClipboard(NULL); + + hr = OleGetClipboard(&get3); + ok(hr == S_OK, "got %08x\n", hr); + + ok(get1 != get3, "data objects match\n"); + ok(get2 != get3, "data objects match\n"); + + IDataObject_Release(get3); + IDataObject_Release(get2); + IDataObject_Release(get1); + + /* Now call GetData before the flush and show that this + takes a ref on our src data obj. */ + + hr = OleSetClipboard(src); + ok(hr == S_OK, "got %08x\n", hr); + + old_refs = count_refs(src); + + hr = OleGetClipboard(&get1); + ok(hr == S_OK, "got %08x\n", hr); + + refs = count_refs(src); + ok(refs == old_refs, "%d %d\n", refs, old_refs); + + DataObjectImpl_GetData_calls = 0; + hr = IDataObject_GetData(get1, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n"); + ReleaseStgMedium(&med); + refs = count_refs(src); + ok(refs == old_refs + 1, "%d %d\n", refs, old_refs); + + OleFlushClipboard(); + + DataObjectImpl_GetData_calls = 0; + hr = IDataObject_GetData(get1, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n"); + ReleaseStgMedium(&med); + + refs = count_refs(src); + ok(refs == 2, "%d\n", refs); + + IDataObject_Release(get1); + + refs = count_refs(src); + ok(refs == 1, "%d\n", refs); + + /* Now set a second src object before the call to GetData + and show that GetData calls that second src. */ + + hr = OleSetClipboard(src); + ok(hr == S_OK, "got %08x\n", hr); + + old_refs = count_refs(src); + + hr = OleGetClipboard(&get1); + ok(hr == S_OK, "got %08x\n", hr); + + refs = count_refs(src); + ok(refs == old_refs, "%d %d\n", refs, old_refs); + + hr = OleSetClipboard(src2); + ok(hr == S_OK, "got %08x\n", hr); + + old_refs = count_refs(src2); + + DataObjectImpl_GetData_calls = 0; + hr = IDataObject_GetData(get1, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n"); + ReleaseStgMedium(&med); + + refs = count_refs(src); + ok(refs == 1, "%d\n", refs); + refs = count_refs(src2); + ok(refs == old_refs + 1, "%d %d\n", refs, old_refs); + + OleSetClipboard(NULL); + + refs = count_refs(src2); + ok(refs == 2, "%d\n", refs); + + IDataObject_Release(get1); + + IDataObject_Release(src2); + IDataObject_Release(src); + + OleUninitialize(); +} + +static void test_flushed_getdata(void) +{ + HRESULT hr; + IDataObject *src, *get; + FORMATETC fmt; + STGMEDIUM med; + STATSTG stat; + DEVMODEW dm; + + OleInitialize(NULL); + + hr = DataObjectImpl_CreateComplex(&src); + ok(hr == S_OK, "got %08x\n", hr); + + hr = OleSetClipboard(src); + ok(hr == S_OK, "got %08x\n", hr); + + hr = OleFlushClipboard(); + ok(hr == S_OK, "got %08x\n", hr); + + hr = OleGetClipboard(&get); + ok(hr == S_OK, "got %08x\n", hr); + + /* global format -> global & stream */ + + InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + InitFormatEtc(fmt, CF_TEXT, TYMED_ISTREAM); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == E_FAIL, "got %08x\n", hr); + + InitFormatEtc(fmt, CF_TEXT, 0xffff); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + /* stream format -> global & stream */ + + InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == E_FAIL, "got %08x\n", hr); + + InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + InitFormatEtc(fmt, cf_stream, 0xffff); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + /* storage format -> global, stream & storage */ + + InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); + hr = IStorage_Stat(med.u.pstg, &stat, STATFLAG_NONAME); + ok(hr == S_OK, "got %08x\n", hr); + ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode); + ReleaseStgMedium(&med); + + InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + InitFormatEtc(fmt, cf_storage, 0xffff); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + /* complex format with target device */ + + InitFormatEtc(fmt, cf_another, 0xffff); + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == DV_E_FORMATETC || + broken(hr == S_OK), /* win9x, winme & nt4 */ + "got %08x\n", hr); + if(hr == S_OK) ReleaseStgMedium(&med); + + InitFormatEtc(fmt, cf_another, 0xffff); + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; + lstrcpyW(dm.dmDeviceName, device_name); + fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra); + fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra; + fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData); + fmt.ptd->tdDeviceNameOffset = 0; + fmt.ptd->tdPortNameOffset = 0; + fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name); + lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name); + memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra); + + hr = IDataObject_GetData(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + + HeapFree(GetProcessHeap(), 0, fmt.ptd); + + + IDataObject_Release(get); + IDataObject_Release(src); + OleUninitialize(); +} + +static HGLOBAL create_text(void) +{ + HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5); + char *p = GlobalLock(h); + strcpy(p, "test"); + GlobalUnlock(h); + return h; +} + +static HENHMETAFILE create_emf(void) +{ + const RECT rect = {0, 0, 100, 100}; + HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0"); + ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL); + return CloseEnhMetaFile(hdc); +} + +static void test_nonole_clipboard(void) +{ + HRESULT hr; + BOOL r; + IDataObject *get; + IEnumFORMATETC *enum_fmt; + FORMATETC fmt; + HGLOBAL h, hblob, htext; + HENHMETAFILE emf; + + r = OpenClipboard(NULL); + ok(r, "gle %d\n", GetLastError()); + r = EmptyClipboard(); + ok(r, "gle %d\n", GetLastError()); + r = CloseClipboard(); + ok(r, "gle %d\n", GetLastError()); + + OleInitialize(NULL); + + /* empty clipboard */ + hr = OleGetClipboard(&get); + ok(hr == S_OK, "got %08x\n", hr); + hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_FALSE, "got %08x\n", hr); + IEnumFORMATETC_Release(enum_fmt); + + IDataObject_Release(get); + + /* set a user defined clipboard type */ + + htext = create_text(); + hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10); + emf = create_emf(); + + r = OpenClipboard(NULL); + ok(r, "gle %d\n", GetLastError()); + h = SetClipboardData(CF_TEXT, htext); + ok(h == htext, "got %p\n", h); + h = SetClipboardData(cf_onemore, hblob); + ok(h == hblob, "got %p\n", h); + h = SetClipboardData(CF_ENHMETAFILE, emf); + ok(h == emf, "got %p\n", h); + r = CloseClipboard(); + ok(r, "gle %d\n", GetLastError()); + + hr = OleGetClipboard(&get); + ok(hr == S_OK, "got %08x\n", hr); + hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat); + ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); + ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); + ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); + ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat); + ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); + ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); + ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); + ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat); + ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); + ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); + ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); + ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */ + + todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat); + if(fmt.cfFormat == CF_LOCALE) + { + ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); + ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); + ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); + ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + } + + ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat); + ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); + ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); + ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); + ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + ok(fmt.cfFormat == CF_UNICODETEXT || + broken(fmt.cfFormat == CF_METAFILEPICT), /* win9x and winme don't have CF_UNICODETEXT */ + "cf %04x\n", fmt.cfFormat); + if(fmt.cfFormat == CF_UNICODETEXT) + { + ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); + ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); + ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); + ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_OK, "got %08x\n", hr); + } + ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat); + ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd); + ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect); + ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex); + ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed); + + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + ok(hr == S_FALSE, "got %08x\n", hr); + IEnumFORMATETC_Release(enum_fmt); + + IDataObject_Release(get); + + r = OpenClipboard(NULL); + ok(r, "gle %d\n", GetLastError()); + r = EmptyClipboard(); + ok(r, "gle %d\n", GetLastError()); + r = CloseClipboard(); + ok(r, "gle %d\n", GetLastError()); + + OleUninitialize(); +} + +static void test_getdatahere(void) +{ + HRESULT hr; + IDataObject *src, *get; + FORMATETC fmt; + STGMEDIUM med; + + OleInitialize(NULL); + + hr = DataObjectImpl_CreateComplex(&src); + ok(hr == S_OK, "got %08x\n", hr); + + hr = OleSetClipboard(src); + ok(hr == S_OK, "got %08x\n", hr); + + hr = OleGetClipboard(&get); + ok(hr == S_OK, "got %08x\n", hr); + + /* global format -> global & stream */ + + DataObjectImpl_GetData_calls = 0; + DataObjectImpl_GetDataHere_calls = 0; + + InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_HGLOBAL; + U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 1, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); + + InitFormatEtc(fmt, CF_TEXT, 0); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_HGLOBAL; + U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 2, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_HGLOBAL; + U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 1); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == E_FAIL, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 3, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_ISTREAM; + CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 4, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_ISTORAGE; + StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == E_FAIL, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 5, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls); + + InitFormatEtc(fmt, cf_stream, 0); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_HGLOBAL; + U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 7, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_ISTREAM; + CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 8, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_ISTORAGE; + StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == E_FAIL, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 9, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls); + + InitFormatEtc(fmt, cf_storage, 0); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_HGLOBAL; + U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 3000); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 11, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_ISTREAM; + CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 12, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls); + + med.pUnkForRelease = NULL; + med.tymed = TYMED_ISTORAGE; + StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg); + hr = IDataObject_GetDataHere(get, &fmt, &med); + ok(hr == S_OK, "got %08x\n", hr); + ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed); + ReleaseStgMedium(&med); + ok(DataObjectImpl_GetDataHere_calls == 13, "called %d\n", DataObjectImpl_GetDataHere_calls); + ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls); + + + IDataObject_Release(get); + IDataObject_Release(src); + + OleUninitialize(); + +} START_TEST(clipboard) { test_set_clipboard(); + test_consumer_refs(); + test_flushed_getdata(); + test_nonole_clipboard(); + test_getdatahere(); } diff --git a/rostests/winetests/ole32/compobj.c b/rostests/winetests/ole32/compobj.c index b2aaa226eb5..7363f30f735 100644 --- a/rostests/winetests/ole32/compobj.c +++ b/rostests/winetests/ole32/compobj.c @@ -29,29 +29,29 @@ #include "shlguid.h" #include "urlmon.h" /* for CLSID_FileProtocol */ +#include "initguid.h" +#include "ctxtcall.h" + #include "wine/test.h" /* functions that are not present on all versions of Windows */ HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit); HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv); +HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown **ppOldObject); +HRESULT (WINAPI * pCoGetTreatAsClass)(REFCLSID clsidOld, LPCLSID pClsidNew); #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr) #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks) #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks) static const CLSID CLSID_non_existent = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } }; -static const CLSID CLSID_CDeviceMoniker = { 0x4315d437, 0x5b8c, 0x11d0, { 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86 } }; -static WCHAR devicedotone[] = {'d','e','v','i','c','e','.','1',0}; +static const CLSID CLSID_StdFont = { 0x0be35203, 0x8f91, 0x11ce, { 0x9d, 0xe3, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51 } }; +static WCHAR stdfont[] = {'S','t','d','F','o','n','t',0}; static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0}; -static WCHAR wszCLSID_CDeviceMoniker[] = +static WCHAR wszCLSID_StdFont[] = { - '{', - '4','3','1','5','d','4','3','7','-', - '5','b','8','c','-', - '1','1','d','0','-', - 'b','d','3','b','-', - '0','0','a','0','c','9','1','1','c','e','8','6', - '}',0 + '{','0','b','e','3','5','2','0','3','-','8','f','9','1','-','1','1','c','e','-', + '9','d','e','3','-','0','0','a','a','0','0','4','b','b','8','5','1','}',0 }; static const IID IID_IWineTest = @@ -90,7 +90,7 @@ static HRESULT WINAPI Test_IClassFactory_QueryInterface( if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IClassFactory)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IClassFactory_AddRef(iface); return S_OK; } @@ -143,11 +143,11 @@ static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl }; static void test_ProgIDFromCLSID(void) { LPWSTR progid; - HRESULT hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, &progid); + HRESULT hr = ProgIDFromCLSID(&CLSID_StdFont, &progid); ok(hr == S_OK, "ProgIDFromCLSID failed with error 0x%08x\n", hr); if (hr == S_OK) { - ok(!lstrcmpiW(progid, devicedotone), "Didn't get expected prog ID\n"); + ok(!lstrcmpiW(progid, stdfont), "Didn't get expected prog ID\n"); CoTaskMemFree(progid); } @@ -156,20 +156,20 @@ static void test_ProgIDFromCLSID(void) ok(hr == REGDB_E_CLASSNOTREG, "ProgIDFromCLSID returned %08x\n", hr); ok(progid == NULL, "ProgIDFromCLSID returns with progid %p\n", progid); - hr = ProgIDFromCLSID(&CLSID_CDeviceMoniker, NULL); + hr = ProgIDFromCLSID(&CLSID_StdFont, NULL); ok(hr == E_INVALIDARG, "ProgIDFromCLSID should return E_INVALIDARG instead of 0x%08x\n", hr); } static void test_CLSIDFromProgID(void) { CLSID clsid; - HRESULT hr = CLSIDFromProgID(devicedotone, &clsid); + HRESULT hr = CLSIDFromProgID(stdfont, &clsid); ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08x\n", hr); - ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n"); + ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n"); - hr = CLSIDFromString(devicedotone, &clsid); + hr = CLSIDFromString(stdfont, &clsid); ok_ole_success(hr, "CLSIDFromString"); - ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n"); + ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n"); /* test some failure cases */ @@ -188,9 +188,9 @@ static void test_CLSIDFromProgID(void) static void test_CLSIDFromString(void) { CLSID clsid; - HRESULT hr = CLSIDFromString(wszCLSID_CDeviceMoniker, &clsid); + HRESULT hr = CLSIDFromString(wszCLSID_StdFont, &clsid); ok_ole_success(hr, "CLSIDFromString"); - ok(IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker), "clsid wasn't equal to CLSID_CDeviceMoniker\n"); + ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n"); hr = CLSIDFromString(NULL, &clsid); ok_ole_success(hr, "CLSIDFromString"); @@ -202,27 +202,52 @@ static void test_StringFromGUID2(void) WCHAR str[50]; int len; /* Test corner cases for buffer size */ - len = StringFromGUID2(&CLSID_CDeviceMoniker,str,50); + len = StringFromGUID2(&CLSID_StdFont,str,50); ok(len == 39, "len: %d (expected 39)\n", len); - ok(!lstrcmpiW(str, wszCLSID_CDeviceMoniker),"string wan't equal for CLSID_CDeviceMoniker\n"); + ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n"); memset(str,0,sizeof str); - len = StringFromGUID2(&CLSID_CDeviceMoniker,str,39); + len = StringFromGUID2(&CLSID_StdFont,str,39); ok(len == 39, "len: %d (expected 39)\n", len); - ok(!lstrcmpiW(str, wszCLSID_CDeviceMoniker),"string wan't equal for CLSID_CDeviceMoniker\n"); + ok(!lstrcmpiW(str, wszCLSID_StdFont),"string wasn't equal for CLSID_StdFont\n"); - len = StringFromGUID2(&CLSID_CDeviceMoniker,str,38); + len = StringFromGUID2(&CLSID_StdFont,str,38); ok(len == 0, "len: %d (expected 0)\n", len); - len = StringFromGUID2(&CLSID_CDeviceMoniker,str,30); + len = StringFromGUID2(&CLSID_StdFont,str,30); ok(len == 0, "len: %d (expected 0)\n", len); } +struct info +{ + HANDLE wait, stop; +}; + +static DWORD CALLBACK ole_initialize_thread(LPVOID pv) +{ + HRESULT hr; + struct info *info = pv; + + hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED); + + SetEvent(info->wait); + WaitForSingleObject(info->stop, INFINITE); + + CoUninitialize(); + return hr; +} + static void test_CoCreateInstance(void) { - REFCLSID rclsid = &CLSID_MyComputer; - IUnknown *pUnk = (IUnknown *)0xdeadbeef; - HRESULT hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); + HRESULT hr; + HANDLE thread; + DWORD tid, exitcode; + IUnknown *pUnk; + struct info info; + REFCLSID rclsid = &CLSID_InternetZoneManager; + + pUnk = (IUnknown *)0xdeadbeef; + hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr); ok(pUnk == NULL, "CoCreateInstance should have changed the passed in pointer to NULL, instead of %p\n", pUnk); @@ -234,17 +259,85 @@ static void test_CoCreateInstance(void) hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr); + + /* show that COM doesn't have to be initialized for multi-threaded apartments if another + thread has already done so */ + + info.wait = CreateEvent(NULL, TRUE, FALSE, NULL); + ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError()); + + info.stop = CreateEvent(NULL, TRUE, FALSE, NULL); + ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError()); + + thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid); + ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError()); + + WaitForSingleObject(info.wait, INFINITE); + + pUnk = (IUnknown *)0xdeadbeef; + hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); + ok(hr == S_OK, "CoCreateInstance should have returned S_OK instead of 0x%08x\n", hr); + if (pUnk) IUnknown_Release(pUnk); + + SetEvent(info.stop); + WaitForSingleObject(thread, INFINITE); + + GetExitCodeThread(thread, &exitcode); + hr = exitcode; + ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr); + + CloseHandle(thread); + CloseHandle(info.wait); + CloseHandle(info.stop); } static void test_CoGetClassObject(void) { - IUnknown *pUnk = (IUnknown *)0xdeadbeef; - HRESULT hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk); + HRESULT hr; + HANDLE thread; + DWORD tid, exitcode; + IUnknown *pUnk; + struct info info; + REFCLSID rclsid = &CLSID_InternetZoneManager; + + hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk); ok(hr == CO_E_NOTINITIALIZED, "CoGetClassObject should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr); ok(pUnk == NULL, "CoGetClassObject should have changed the passed in pointer to NULL, instead of %p\n", pUnk); - hr = CoGetClassObject(&CLSID_MyComputer, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL); - ok(hr == E_INVALIDARG, "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr); + hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, NULL); + ok(hr == E_INVALIDARG || + broken(hr == CO_E_NOTINITIALIZED), /* win9x */ + "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr); + + /* show that COM doesn't have to be initialized for multi-threaded apartments if another + thread has already done so */ + + info.wait = CreateEvent(NULL, TRUE, FALSE, NULL); + ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError()); + + info.stop = CreateEvent(NULL, TRUE, FALSE, NULL); + ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError()); + + thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid); + ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError()); + + WaitForSingleObject(info.wait, INFINITE); + + pUnk = (IUnknown *)0xdeadbeef; + hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk); + ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr); + if (pUnk) IUnknown_Release(pUnk); + + SetEvent(info.stop); + WaitForSingleObject(thread, INFINITE); + + GetExitCodeThread(thread, &exitcode); + hr = exitcode; + ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr); + + CloseHandle(thread); + CloseHandle(info.wait); + CloseHandle(info.stop); } static ATOM register_dummy_class(void) @@ -286,7 +379,7 @@ static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IClassFactory)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IMessageFilter_AddRef(iface); return S_OK; } @@ -397,7 +490,7 @@ static HRESULT WINAPI Test_IUnknown_QueryInterface( if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IWineTest)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IUnknown_AddRef(iface); return S_OK; } @@ -512,7 +605,7 @@ static void test_CoRegisterPSClsid(void) hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); ok_ole_success(hr, "CreateStreamOnHGlobal"); - hr = CoMarshalInterface(stream, &IID_IWineTest, (IUnknown *)&Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + hr = CoMarshalInterface(stream, &IID_IWineTest, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); ok(hr == E_NOTIMPL, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr); IStream_Release(stream); @@ -890,7 +983,7 @@ static void test_registered_object_thread_affinity(void) ok(hr == S_OK, "CoGetClassObject on local server object registered in same " "thread should return S_OK instead of 0x%08x\n", hr); - thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)cookie, 0, &tid); + thread = CreateThread(NULL, 0, revoke_class_object_thread, (LPVOID)(DWORD_PTR)cookie, 0, &tid); ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError()); WaitForSingleObject(thread, INFINITE); GetExitCodeThread(thread, &exitcode); @@ -934,17 +1027,20 @@ static void test_CoFreeUnusedLibraries(void) ok(!is_module_loaded("urlmon.dll"), "urlmon.dll shouldn't be loaded\n"); - hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); + hr = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void **)&pUnk); if (hr == REGDB_E_CLASSNOTREG) { trace("IE not installed so can't run CoFreeUnusedLibraries test\n"); + CoUninitialize(); return; } ok_ole_success(hr, "CoCreateInstance"); ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n"); - ok(pUnk != NULL, "Expected a valid pointer\n"); + ok(pUnk != NULL || + broken(pUnk == NULL), /* win9x */ + "Expected a valid pointer\n"); if (pUnk) IUnknown_Release(pUnk); @@ -968,6 +1064,7 @@ static void test_CoGetObjectContext(void) HRESULT hr; ULONG refs; IComThreadingInfo *pComThreadingInfo; + IContextCallback *pContextCallback; APTTYPE apttype; THDTYPE thdtype; @@ -997,6 +1094,15 @@ static void test_CoGetObjectContext(void) refs = IComThreadingInfo_Release(pComThreadingInfo); ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs); + hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback); + ok_ole_success(hr, "CoGetObjectContext(ContextCallback)"); + + if (hr == S_OK) + { + refs = IContextCallback_Release(pContextCallback); + ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs); + } + CoUninitialize(); pCoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -1015,13 +1121,161 @@ static void test_CoGetObjectContext(void) refs = IComThreadingInfo_Release(pComThreadingInfo); ok(refs == 0, "pComThreadingInfo should have 0 refs instead of %d refs\n", refs); + hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback); + ok_ole_success(hr, "CoGetObjectContext(ContextCallback)"); + + if (hr == S_OK) + { + refs = IContextCallback_Release(pContextCallback); + ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs); + } + CoUninitialize(); } +typedef struct { + const IUnknownVtbl *lpVtbl; + LONG refs; +} Test_CallContext; + +static HRESULT WINAPI Test_CallContext_QueryInterface( + IUnknown *iface, + REFIID riid, + LPVOID *ppvObj) +{ + if (ppvObj == NULL) return E_POINTER; + + if (IsEqualGUID(riid, &IID_IUnknown)) + { + *ppvObj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + *ppvObj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI Test_CallContext_AddRef(IUnknown *iface) +{ + Test_CallContext *This = (Test_CallContext*)iface; + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI Test_CallContext_Release(IUnknown *iface) +{ + Test_CallContext *This = (Test_CallContext*)iface; + ULONG refs = InterlockedDecrement(&This->refs); + if (!refs) + HeapFree(GetProcessHeap(), 0, This); + return refs; +} + +static const IUnknownVtbl TestCallContext_Vtbl = +{ + Test_CallContext_QueryInterface, + Test_CallContext_AddRef, + Test_CallContext_Release +}; + +static void test_CoGetCallContext(void) +{ + HRESULT hr; + ULONG refs; + IUnknown *pUnk; + IUnknown *test_object; + + if (!pCoSwitchCallContext) + { + skip("CoSwitchCallContext not present\n"); + return; + } + + CoInitialize(NULL); + + test_object = HeapAlloc(GetProcessHeap(), 0, sizeof(Test_CallContext)); + ((Test_CallContext*)test_object)->lpVtbl = &TestCallContext_Vtbl; + ((Test_CallContext*)test_object)->refs = 1; + + hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk); + ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr); + + pUnk = (IUnknown*)0xdeadbeef; + hr = pCoSwitchCallContext(test_object, &pUnk); + ok_ole_success(hr, "CoSwitchCallContext"); + ok(pUnk == NULL, "expected NULL, got %p\n", pUnk); + refs = IUnknown_AddRef(test_object); + ok(refs == 2, "Expected refcount 2, got %d\n", refs); + IUnknown_Release(test_object); + + pUnk = (IUnknown*)0xdeadbeef; + hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk); + ok_ole_success(hr, "CoGetCallContext"); + ok(pUnk == test_object, "expected %p, got %p\n", test_object, pUnk); + refs = IUnknown_AddRef(test_object); + ok(refs == 3, "Expected refcount 3, got %d\n", refs); + IUnknown_Release(test_object); + IUnknown_Release(pUnk); + + pUnk = (IUnknown*)0xdeadbeef; + hr = pCoSwitchCallContext(NULL, &pUnk); + ok_ole_success(hr, "CoSwitchCallContext"); + ok(pUnk == test_object, "expected %p, got %p\n", test_object, pUnk); + refs = IUnknown_AddRef(test_object); + ok(refs == 2, "Expected refcount 2, got %d\n", refs); + IUnknown_Release(test_object); + + hr = CoGetCallContext(&IID_IUnknown, (void**)&pUnk); + ok(hr == RPC_E_CALL_COMPLETE, "Expected RPC_E_CALL_COMPLETE, got 0x%08x\n", hr); + + IUnknown_Release(test_object); + + CoUninitialize(); +} + +static void test_CoGetTreatAsClass(void) +{ + HRESULT hr; + CLSID out; + static GUID deadbeef = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}}; + + if (!pCoGetTreatAsClass) + { + win_skip("CoGetTreatAsClass not present\n"); + return; + } + hr = pCoGetTreatAsClass(&deadbeef,&out); + ok (hr == S_FALSE, "expected S_FALSE got %x\n",hr); + ok (IsEqualGUID(&out,&deadbeef), "expected to get same clsid back\n"); +} + +static void test_CoInitializeEx(void) +{ + HRESULT hr; + + hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr); + + /* Calling OleInitialize for the first time should yield S_OK even with + * apartment already initialized by previous CoInitialize(Ex) calls. */ + hr = OleInitialize(NULL); + todo_wine ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr); + + /* Subsequent calls to OleInitialize should return S_FALSE */ + hr = OleInitialize(NULL); + ok(hr == S_FALSE, "Expected S_FALSE, hr = 0x%08x\n", hr); + + /* Cleanup */ + CoUninitialize(); + OleUninitialize(); +} + START_TEST(compobj) { HMODULE hOle32 = GetModuleHandle("ole32"); pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext"); + pCoSwitchCallContext = (void*)GetProcAddress(hOle32, "CoSwitchCallContext"); + pCoGetTreatAsClass = (void*)GetProcAddress(hOle32,"CoGetTreatAsClass"); if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) { trace("You need DCOM95 installed to run this test\n"); @@ -1046,4 +1300,7 @@ START_TEST(compobj) test_registered_object_thread_affinity(); test_CoFreeUnusedLibraries(); test_CoGetObjectContext(); + test_CoGetCallContext(); + test_CoGetTreatAsClass(); + test_CoInitializeEx(); } diff --git a/rostests/winetests/ole32/defaulthandler.c b/rostests/winetests/ole32/defaulthandler.c new file mode 100644 index 00000000000..a6469b709e5 --- /dev/null +++ b/rostests/winetests/ole32/defaulthandler.c @@ -0,0 +1,110 @@ +/* + * Default Handler Tests + * + * Copyright 2008 Huw Davies + * + * 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 + */ + +#define COBJMACROS +#define CONST_VTABLE + +#include + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wine/test.h" + + +static HRESULT create_storage(IStorage **stg) +{ + HRESULT hr; + ILockBytes *lock_bytes; + + hr = CreateILockBytesOnHGlobal(NULL, TRUE, &lock_bytes); + if(SUCCEEDED(hr)) + { + hr = StgCreateDocfileOnILockBytes(lock_bytes, + STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, stg); + ILockBytes_Release(lock_bytes); + } + return hr; +} + +typedef struct +{ + DWORD version; + DWORD flags; + DWORD link_update_opt; + DWORD res; + DWORD moniker_size; +} ole_stream_header_t; + +static void test_olestream(void) +{ + HRESULT hr; + const CLSID non_existent_class = {0xa5f1772f, 0x3772, 0x490f, {0x9e, 0xc6, 0x77, 0x13, 0xe8, 0xb3, 0x4b, 0x5d}}; + IOleObject *ole_obj; + IPersistStorage *persist; + IStorage *stg; + IStream *stm; + static const WCHAR olestream[] = {1,'O','l','e',0}; + ULONG read; + ole_stream_header_t header; + + hr = create_storage(&stg); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IStorage_OpenStream(stg, olestream, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, 0, &stm); + ok(hr == STG_E_FILENOTFOUND, "got %08x\n", hr); + + hr = OleCreateDefaultHandler(&non_existent_class, 0, &IID_IOleObject, (void**)&ole_obj); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IOleObject_QueryInterface(ole_obj, &IID_IPersistStorage, (void**)&persist); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IPersistStorage_InitNew(persist, stg); + ok(hr == S_OK, "got %08x\n", hr); + + hr = IStorage_OpenStream(stg, olestream, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, 0, &stm); + ok(hr == S_OK, "got %08x\n", hr); + hr = IStream_Read(stm, &header, sizeof(header), &read); + ok(hr == S_OK, "got %08x\n", hr); + ok(read == sizeof(header), "read %d\n", read); + ok(header.version == 0x02000001, "got version %08x\n", header.version); + ok(header.flags == 0x0, "got flags %08x\n", header.flags); + ok(header.link_update_opt == 0x0, "got link update option %08x\n", header.link_update_opt); + ok(header.res == 0x0, "got reserved %08x\n", header.res); + ok(header.moniker_size == 0x0, "got moniker size %08x\n", header.moniker_size); + + IStream_Release(stm); + + IPersistStorage_Release(persist); + IOleObject_Release(ole_obj); + + IStorage_Release(stg); +} + +START_TEST(defaulthandler) +{ + OleInitialize(NULL); + + test_olestream(); + + OleUninitialize(); +} diff --git a/rostests/winetests/ole32/dragdrop.c b/rostests/winetests/ole32/dragdrop.c index 15610661c29..b28a8313e1a 100644 --- a/rostests/winetests/ole32/dragdrop.c +++ b/rostests/winetests/ole32/dragdrop.c @@ -31,9 +31,6 @@ #include "wine/test.h" -/* functions that are not present on all versions of Windows */ -HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit); - static int droptarget_addref_called; static int droptarget_release_called; @@ -108,16 +105,42 @@ static const IDropTargetVtbl DropTarget_VTbl = static IDropTarget DropTarget = { &DropTarget_VTbl }; +static ATOM register_dummy_class(void) +{ + WNDCLASS wc = + { + 0, + DefWindowProc, + 0, + 0, + GetModuleHandle(NULL), + NULL, + LoadCursor(NULL, IDC_ARROW), + (HBRUSH)(COLOR_BTNFACE+1), + NULL, + TEXT("WineOleTestClass"), + }; + + return RegisterClass(&wc); +} + START_TEST(dragdrop) { HRESULT hr; + HWND hwnd; - hr = RegisterDragDrop(GetDesktopWindow(), &DropTarget); - ok(hr == E_OUTOFMEMORY, "RegisterDragDrop without OLE initialized should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr); + hwnd = CreateWindow(MAKEINTATOM(register_dummy_class()), "Test", 0, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, + NULL, NULL, NULL); + + hr = RegisterDragDrop(hwnd, &DropTarget); + ok(hr == E_OUTOFMEMORY || + broken(hr == CO_E_NOTINITIALIZED), /* NT4 */ + "RegisterDragDrop without OLE initialized should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr); OleInitialize(NULL); - hr = RegisterDragDrop(GetDesktopWindow(), NULL); + hr = RegisterDragDrop(hwnd, NULL); ok(hr == E_INVALIDARG, "RegisterDragDrop with NULL IDropTarget * should return E_INVALIDARG instead of 0x%08x\n", hr); hr = RegisterDragDrop(NULL, &DropTarget); @@ -127,21 +150,25 @@ START_TEST(dragdrop) ok(hr == DRAGDROP_E_INVALIDHWND, "RegisterDragDrop with garbage hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr); ok(droptarget_addref_called == 0, "DropTarget_AddRef shouldn't have been called\n"); - hr = RegisterDragDrop(GetDesktopWindow(), &DropTarget); + hr = RegisterDragDrop(hwnd, &DropTarget); ok_ole_success(hr, "RegisterDragDrop"); ok(droptarget_addref_called == 1, "DropTarget_AddRef should have been called once, not %d times\n", droptarget_addref_called); - hr = RegisterDragDrop(GetDesktopWindow(), &DropTarget); + hr = RegisterDragDrop(hwnd, &DropTarget); ok(hr == DRAGDROP_E_ALREADYREGISTERED, "RegisterDragDrop with already registered hwnd should return DRAGDROP_E_ALREADYREGISTERED instead of 0x%08x\n", hr); ok(droptarget_release_called == 0, "DropTarget_Release shouldn't have been called\n"); OleUninitialize(); ok(droptarget_release_called == 0, "DropTarget_Release shouldn't have been called\n"); - hr = RevokeDragDrop(GetDesktopWindow()); + hr = RevokeDragDrop(hwnd); ok_ole_success(hr, "RevokeDragDrop"); - ok(droptarget_release_called == 1, "DropTarget_Release should have been called once, not %d times\n", droptarget_release_called); + ok(droptarget_release_called == 1 || + broken(droptarget_release_called == 0), /* NT4 */ + "DropTarget_Release should have been called once, not %d times\n", droptarget_release_called); hr = RevokeDragDrop(NULL); ok(hr == DRAGDROP_E_INVALIDHWND, "RevokeDragDrop with NULL hwnd should return DRAGDROP_E_INVALIDHWND instead of 0x%08x\n", hr); + + DestroyWindow(hwnd); } diff --git a/rostests/winetests/ole32/hglobalstream.c b/rostests/winetests/ole32/hglobalstream.c index eb98a18c44a..cae13ed2ea9 100644 --- a/rostests/winetests/ole32/hglobalstream.c +++ b/rostests/winetests/ole32/hglobalstream.c @@ -92,7 +92,8 @@ static void test_streamonhglobal(IStream *pStream) ull.u.HighPart = -1; ull.u.LowPart = -1; hr = IStream_SetSize(pStream, ull); - ok(hr == E_OUTOFMEMORY, "IStream_SetSize with large size should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr); + ok(hr == E_OUTOFMEMORY || broken(hr == S_OK), /* win9x */ + "IStream_SetSize with large size should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr); } static HRESULT WINAPI TestStream_QueryInterface(IStream *iface, REFIID riid, void **ppv) @@ -261,18 +262,19 @@ static void test_copyto(void) static void test_freed_hglobal(void) { + static const char teststring[] = "this is a test string"; HRESULT hr; IStream *pStream; HGLOBAL hglobal; char *p; - char buffer[10]; + char buffer[sizeof(teststring) + 8]; ULARGE_INTEGER ull; ULONG read, written; - hglobal = GlobalAlloc(GMEM_DDESHARE|GMEM_NODISCARD|GMEM_MOVEABLE, strlen("Rob") + 1); + hglobal = GlobalAlloc(GMEM_DDESHARE|GMEM_NODISCARD|GMEM_MOVEABLE, strlen(teststring) + 1); ok(hglobal != NULL, "GlobalAlloc failed with error %d\n", GetLastError()); p = GlobalLock(hglobal); - strcpy(p, "Rob"); + strcpy(p, teststring); GlobalUnlock(hglobal); hr = CreateStreamOnHGlobal(hglobal, FALSE, &pStream); @@ -280,8 +282,10 @@ static void test_freed_hglobal(void) hr = IStream_Read(pStream, buffer, sizeof(buffer), &read); ok_ole_success(hr, "IStream_Read"); - ok(!strcmp(buffer, "Rob"), "buffer data %s differs\n", buffer); - ok(read == strlen("Rob") + 1, "read should be 4 instead of %d\n", read); + ok(!strcmp(buffer, teststring), "buffer data %s differs\n", buffer); + ok(read == sizeof(teststring) || + broken(read == ((sizeof(teststring) + 3) & ~3)), /* win9x rounds the size */ + "read should be sizeof(teststring) instead of %d\n", read); GlobalFree(hglobal); diff --git a/rostests/winetests/ole32/marshal.c b/rostests/winetests/ole32/marshal.c index fade8b075a1..ec0fc6ce043 100644 --- a/rostests/winetests/ole32/marshal.c +++ b/rostests/winetests/ole32/marshal.c @@ -27,12 +27,16 @@ #include "windef.h" #include "winbase.h" +#include "initguid.h" #include "objbase.h" +#include "olectl.h" #include "shlguid.h" #include "shobjidl.h" #include "wine/test.h" +DEFINE_GUID(CLSID_StdGlobalInterfaceTable,0x00000323,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); + /* functions that are not present on all versions of Windows */ HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit); @@ -110,7 +114,7 @@ static HRESULT WINAPI Test_IUnknown_QueryInterface( if (IsEqualGUID(riid, &IID_IUnknown)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IUnknown_AddRef(iface); return S_OK; } @@ -153,7 +157,7 @@ static HRESULT WINAPI Test_IClassFactory_QueryInterface( /* the only other interface Wine is currently able to marshal (for testing two proxies) */ IsEqualGUID(riid, &IID_IRemUnknown)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IClassFactory_AddRef(iface); return S_OK; } @@ -216,7 +220,7 @@ struct host_object_data static DWORD CALLBACK host_object_proc(LPVOID p) { - struct host_object_data *data = (struct host_object_data *)p; + struct host_object_data *data = p; HRESULT hr; MSG msg; @@ -829,7 +833,7 @@ struct ncu_params /* helper for test_no_couninitialize_server */ static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p) { - struct ncu_params *ncu_params = (struct ncu_params *)p; + struct ncu_params *ncu_params = p; HRESULT hr; pCoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -895,7 +899,7 @@ static void test_no_couninitialize_server(void) /* STA -> STA call during DLL_THREAD_DETACH */ static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p) { - struct ncu_params *ncu_params = (struct ncu_params *)p; + struct ncu_params *ncu_params = p; HRESULT hr; IUnknown *pProxy = NULL; @@ -1366,7 +1370,7 @@ static void test_hresult_marshaling(void) /* helper for test_proxy_used_in_wrong_thread */ static DWORD CALLBACK bad_thread_proc(LPVOID p) { - IClassFactory * cf = (IClassFactory *)p; + IClassFactory * cf = p; HRESULT hr; IUnknown * proxy = NULL; @@ -1443,7 +1447,7 @@ static void test_proxy_used_in_wrong_thread(void) IClassFactory_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream); /* create a thread that we can misbehave in */ - thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2); + thread = CreateThread(NULL, 0, bad_thread_proc, pProxy, 0, &tid2); WaitForSingleObject(thread, INFINITE); CloseHandle(thread); @@ -1464,7 +1468,7 @@ static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IClassFactory)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IClassFactory_AddRef(iface); return S_OK; } @@ -1675,7 +1679,7 @@ static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, v if (IsEqualIID(riid, &IID_IUnknown)) { IUnknown_AddRef(iface); - *ppv = (LPVOID)iface; + *ppv = iface; return S_OK; } *ppv = NULL; @@ -2036,6 +2040,19 @@ static void test_WM_QUIT_handling(void) } } +static SIZE_T round_global_size(SIZE_T size) +{ + static SIZE_T global_size_alignment = -1; + if (global_size_alignment == -1) + { + void *p = GlobalAlloc(GMEM_FIXED, 1); + global_size_alignment = GlobalSize(p); + GlobalFree(p); + } + + return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1)); +} + static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void *ptr, DWORD mshlflags) { HGLOBAL hglobal; @@ -2048,24 +2065,32 @@ static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void * size = GlobalSize(hglobal); - marshal_data = (char *)GlobalLock(hglobal); + marshal_data = GlobalLock(hglobal); if (mshctx == MSHCTX_INPROC) { - DWORD expected_size = sizeof(DWORD) + sizeof(void *) + sizeof(DWORD) + sizeof(GUID); - ok(size == expected_size, "size should have been %d instead of %d\n", expected_size, size); + DWORD expected_size = round_global_size(3*sizeof(DWORD) + sizeof(GUID)); + ok(size == expected_size || + broken(size == round_global_size(2*sizeof(DWORD))) /* Win9x & NT4 */, + "size should have been %d instead of %d\n", expected_size, size); ok(*(DWORD *)marshal_data == mshlflags, "expected 0x%x, but got 0x%x for mshctx\n", mshlflags, *(DWORD *)marshal_data); marshal_data += sizeof(DWORD); ok(*(void **)marshal_data == ptr, "expected %p, but got %p for mshctx\n", ptr, *(void **)marshal_data); marshal_data += sizeof(void *); + if (sizeof(void*) == 4 && size >= 3*sizeof(DWORD)) + { ok(*(DWORD *)marshal_data == 0, "expected 0x0, but got 0x%x\n", *(DWORD *)marshal_data); marshal_data += sizeof(DWORD); + } + if (size >= 3*sizeof(DWORD) + sizeof(GUID)) + { trace("got guid data: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", ((GUID *)marshal_data)->Data1, ((GUID *)marshal_data)->Data2, ((GUID *)marshal_data)->Data3, ((GUID *)marshal_data)->Data4[0], ((GUID *)marshal_data)->Data4[1], ((GUID *)marshal_data)->Data4[2], ((GUID *)marshal_data)->Data4[3], ((GUID *)marshal_data)->Data4[4], ((GUID *)marshal_data)->Data4[5], ((GUID *)marshal_data)->Data4[6], ((GUID *)marshal_data)->Data4[7]); } + } else { ok(size > sizeof(DWORD), "size should have been > sizeof(DWORD), not %d\n", size); @@ -2098,7 +2123,7 @@ static void test_freethreadedmarshaler(void) /* inproc normal marshaling */ hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, - (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); ok_ole_success(hr, IMarshal_MarshalInterface); ok_more_than_one_lock(); @@ -2120,7 +2145,7 @@ static void test_freethreadedmarshaler(void) /* local normal marshaling */ IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL); - hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL); + hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL); ok_ole_success(hr, IMarshal_MarshalInterface); ok_more_than_one_lock(); @@ -2186,7 +2211,7 @@ static void test_freethreadedmarshaler(void) IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL); hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, - (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); ok_ole_success(hr, IMarshal_MarshalInterface); ok_more_than_one_lock(); @@ -2215,11 +2240,9 @@ static void test_freethreadedmarshaler(void) IMarshal_Release(pFTMarshal); } -static void test_inproc_handler(void) +static void reg_unreg_wine_test_class(BOOL Register) { HRESULT hr; - IUnknown *pObject; - IUnknown *pObject2; char buffer[256]; LPOLESTR pszClsid; HKEY hkey; @@ -2232,11 +2255,29 @@ static void test_inproc_handler(void) WideCharToMultiByte(CP_ACP, 0, pszClsid, -1, buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), NULL, NULL); CoTaskMemFree(pszClsid); strcat(buffer, "\\InprocHandler32"); + if (Register) + { error = RegCreateKeyEx(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, &dwDisposition); ok(error == ERROR_SUCCESS, "RegCreateKeyEx failed with error %d\n", error); error = RegSetValueEx(hkey, NULL, 0, REG_SZ, (const unsigned char *)"ole32.dll", strlen("ole32.dll") + 1); ok(error == ERROR_SUCCESS, "RegSetValueEx failed with error %d\n", error); RegCloseKey(hkey); + } + else + { + RegDeleteKey(HKEY_CLASSES_ROOT, buffer); + *strrchr(buffer, '\\') = '\0'; + RegDeleteKey(HKEY_CLASSES_ROOT, buffer); + } +} + +static void test_inproc_handler(void) +{ + HRESULT hr; + IUnknown *pObject; + IUnknown *pObject2; + + reg_unreg_wine_test_class(TRUE); hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pObject); todo_wine @@ -2255,9 +2296,7 @@ static void test_inproc_handler(void) IUnknown_Release(pObject); } - RegDeleteKey(HKEY_CLASSES_ROOT, buffer); - *strrchr(buffer, '\\') = '\0'; - RegDeleteKey(HKEY_CLASSES_ROOT, buffer); + reg_unreg_wine_test_class(FALSE); } static HRESULT WINAPI Test_SMI_QueryInterface( @@ -2270,7 +2309,7 @@ static HRESULT WINAPI Test_SMI_QueryInterface( if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IStdMarshalInfo)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IClassFactory_AddRef(iface); return S_OK; } @@ -2320,6 +2359,7 @@ static void test_handler_marshaling(void) HANDLE thread; static const LARGE_INTEGER ullZero; + reg_unreg_wine_test_class(TRUE); cLocks = 0; hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); @@ -2333,6 +2373,8 @@ static void test_handler_marshaling(void) ok_ole_success(hr, "CoUnmarshalInterface"); IStream_Release(pStream); + if(hr == S_OK) + { ok_more_than_one_lock(); hr = IUnknown_QueryInterface(pProxy, &IID_IWineTest, (void **)&pObject); @@ -2347,8 +2389,10 @@ static void test_handler_marshaling(void) IUnknown_Release(pProxy); ok_no_locks(); + } end_host_object(tid, thread); + reg_unreg_wine_test_class(FALSE); /* FIXME: test IPersist interface has the same effect as IStdMarshalInfo */ } @@ -2427,7 +2471,7 @@ static void test_client_security(void) CoTaskMemFree(pServerPrincName); - hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pUnknown1, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities); + hr = IClientSecurity_QueryBlanket(pCliSec, pUnknown1, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities); todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket(IUnknown)"); CoTaskMemFree(pServerPrincName); @@ -2469,7 +2513,7 @@ static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface( if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IClassFactory)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IClassFactory_AddRef(iface); return S_OK; } @@ -2544,7 +2588,7 @@ static void test_register_local_server(void) do { - wait = MsgWaitForMultipleObjects(1, &quit_event, FALSE, INFINITE, QS_ALLINPUT); + wait = MsgWaitForMultipleObjects(1, &quit_event, FALSE, 30000, QS_ALLINPUT); if (wait == WAIT_OBJECT_0+1) { MSG msg; @@ -2559,6 +2603,7 @@ static void test_register_local_server(void) } while (wait == WAIT_OBJECT_0+1); + ok( wait == WAIT_OBJECT_0, "quit event wait timed out\n" ); hr = CoRevokeClassObject(cookie); ok_ole_success(hr, CoRevokeClassObject); } @@ -2684,14 +2729,17 @@ struct git_params static DWORD CALLBACK get_global_interface_proc(LPVOID pv) { HRESULT hr; - struct git_params *params = (struct git_params *)pv; + struct git_params *params = pv; IClassFactory *cf; hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf); ok(hr == CO_E_NOTINITIALIZED || - hr == E_UNEXPECTED, /* win2k */ + broken(hr == E_UNEXPECTED) /* win2k */ || + broken(hr == S_OK) /* NT 4 */, "IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED or E_UNEXPECTED instead of 0x%08x\n", hr); + if (hr == S_OK) + IClassFactory_Release(cf); CoInitialize(NULL); diff --git a/rostests/winetests/ole32/moniker.c b/rostests/winetests/ole32/moniker.c index b15cce43e5e..228600c5945 100644 --- a/rostests/winetests/ole32/moniker.c +++ b/rostests/winetests/ole32/moniker.c @@ -82,6 +82,19 @@ static void UnlockModule(void) InterlockedDecrement(&cLocks); } +static SIZE_T round_global_size(SIZE_T size) +{ + static SIZE_T global_size_alignment = -1; + if (global_size_alignment == -1) + { + void *p = GlobalAlloc(GMEM_FIXED, 1); + global_size_alignment = GlobalSize(p); + GlobalFree(p); + } + + return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1)); +} + static HRESULT WINAPI Test_IClassFactory_QueryInterface( LPCLASSFACTORY iface, REFIID riid, @@ -92,7 +105,7 @@ static HRESULT WINAPI Test_IClassFactory_QueryInterface( if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IClassFactory)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IClassFactory_AddRef(iface); return S_OK; } @@ -151,7 +164,7 @@ static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, v if (IsEqualIID(riid, &IID_IUnknown)) { IUnknown_AddRef(iface); - *ppv = (LPVOID)iface; + *ppv = iface; return S_OK; } *ppv = NULL; @@ -364,7 +377,7 @@ Moniker_GetDisplayName(IMoniker* iface, IBindCtx* pbc, { static const WCHAR wszDisplayName[] = {'*','*','G','e','m','m','a',0}; CHECK_EXPECTED_METHOD("Moniker_GetDisplayName"); - *ppszDisplayName = (LPOLESTR)CoTaskMemAlloc(sizeof(wszDisplayName)); + *ppszDisplayName = CoTaskMemAlloc(sizeof(wszDisplayName)); memcpy(*ppszDisplayName, wszDisplayName, sizeof(wszDisplayName)); return S_OK; } @@ -571,26 +584,18 @@ static void test_ROT(void) /* try with our own moniker that doesn't support IROTData */ hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown*)&Test_ClassFactory, &MonikerNoROTData, &dwCookie); - todo_wine { /* only fails because of lack of IMoniker marshaling */ ok_ole_success(hr, IRunningObjectTable_Register); - } ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); - todo_wine { /* only fails because of lack of IMoniker marshaling */ ok_more_than_one_lock(); - } expected_method_list = methods_isrunning_no_ROTData; hr = IRunningObjectTable_IsRunning(pROT, &MonikerNoROTData); - todo_wine { /* only fails because of lack of IMoniker marshaling */ ok_ole_success(hr, IRunningObjectTable_IsRunning); - } ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); hr = IRunningObjectTable_Revoke(pROT, dwCookie); - todo_wine { /* only fails because of lack of IMoniker marshaling */ ok_ole_success(hr, IRunningObjectTable_Revoke); - } ok_no_locks(); @@ -598,26 +603,18 @@ static void test_ROT(void) /* try with our own moniker */ hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown*)&Test_ClassFactory, &Moniker, &dwCookie); - todo_wine { /* only fails because of lack of IMoniker marshaling */ ok_ole_success(hr, IRunningObjectTable_Register); - } ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); - todo_wine { /* only fails because of lack of IMoniker marshaling */ ok_more_than_one_lock(); - } expected_method_list = methods_isrunning; hr = IRunningObjectTable_IsRunning(pROT, &Moniker); - todo_wine { /* only fails because of lack of IMoniker marshaling */ ok_ole_success(hr, IRunningObjectTable_IsRunning); - } ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); hr = IRunningObjectTable_Revoke(pROT, dwCookie); - todo_wine { /* only fails because of lack of IMoniker marshaling */ ok_ole_success(hr, IRunningObjectTable_Revoke); - } ok_no_locks(); @@ -655,7 +652,9 @@ static void test_ROT(void) ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT, (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie); todo_wine { - ok(hr == CO_E_WRONG_SERVER_IDENTITY, "IRunningObjectTable_Register should have returned CO_E_WRONG_SERVER_IDENTITY instead of 0x%08x\n", hr); + ok(hr == CO_E_WRONG_SERVER_IDENTITY || + broken(hr == S_OK) /* Win9x */, + "IRunningObjectTable_Register should have returned CO_E_WRONG_SERVER_IDENTITY instead of 0x%08x\n", hr); } if (hr == S_OK) IRunningObjectTable_Revoke(pROT, dwCookie); @@ -921,6 +920,7 @@ static void test_MkParseDisplayName(void) hr = IMoniker_BindToObject(pmk, pbc, NULL, &IID_IUnknown, (LPVOID*)&object); ok_ole_success(hr, IMoniker_BindToObject); + if (SUCCEEDED(hr)) IUnknown_Release(object); IMoniker_Release(pmk); } @@ -1220,12 +1220,12 @@ static void test_moniker( moniker_data = GlobalLock(hglobal); /* first check we have the right amount of data */ - ok(moniker_size == sizeof_expected_moniker_saved_data, + ok(moniker_size == round_global_size(sizeof_expected_moniker_saved_data), "%s: Size of saved data differs (expected %d, actual %d)\n", - testname, sizeof_expected_moniker_saved_data, moniker_size); + testname, (DWORD)round_global_size(sizeof_expected_moniker_saved_data), moniker_size); /* then do a byte-by-byte comparison */ - for (i = 0; i < min(moniker_size, sizeof_expected_moniker_saved_data); i++) + for (i = 0; i < min(moniker_size, round_global_size(sizeof_expected_moniker_saved_data)); i++) { if (expected_moniker_saved_data[i] != moniker_data[i]) { @@ -1266,14 +1266,14 @@ static void test_moniker( moniker_data = GlobalLock(hglobal); /* first check we have the right amount of data */ - ok(moniker_size == sizeof_expected_moniker_marshal_data, + ok(moniker_size == round_global_size(sizeof_expected_moniker_marshal_data), "%s: Size of marshaled data differs (expected %d, actual %d)\n", - testname, sizeof_expected_moniker_marshal_data, moniker_size); + testname, (DWORD)round_global_size(sizeof_expected_moniker_marshal_data), moniker_size); /* then do a byte-by-byte comparison */ if (expected_moniker_marshal_data) { - for (i = 0; i < min(moniker_size, sizeof_expected_moniker_marshal_data); i++) + for (i = 0; i < min(moniker_size, round_global_size(sizeof_expected_moniker_marshal_data)); i++) { if (expected_moniker_marshal_data[i] != moniker_data[i]) { @@ -1348,6 +1348,9 @@ static void test_class_moniker(void) ok_ole_success(hr, CreateBindCtx); /* IsRunning test */ + hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL); + ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08x\n", hr); + hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL); ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08x\n", hr); @@ -1477,6 +1480,10 @@ static void test_item_moniker(void) ok_ole_success(hr, CreateBindCtx); /* IsRunning test */ + hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL); + todo_wine + ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr); + hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL); ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr); @@ -1609,6 +1616,10 @@ static void test_generic_composite_moniker(void) ok_ole_success(hr, CreateBindCtx); /* IsRunning test */ + hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL); + todo_wine + ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr); + hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL); todo_wine ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr); @@ -1765,7 +1776,9 @@ static void test_bind_context(void) bind_opts.cbStruct = -1; hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts); ok_ole_success(hr, "IBindCtx_GetBindOptions"); - ok(bind_opts.cbStruct == sizeof(bind_opts), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct); + ok(bind_opts.cbStruct == sizeof(bind_opts) || + bind_opts.cbStruct == sizeof(bind_opts) + sizeof(void*), /* Vista */ + "bind_opts.cbStruct was %d\n", bind_opts.cbStruct); bind_opts.cbStruct = sizeof(BIND_OPTS); hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts); diff --git a/rostests/winetests/ole32/ole2.c b/rostests/winetests/ole32/ole2.c index 8d72b153317..fb6e25a4b92 100644 --- a/rostests/winetests/ole32/ole2.c +++ b/rostests/winetests/ole32/ole2.c @@ -44,7 +44,15 @@ static const CLSID CLSID_WineTest = {0xbc, 0x13, 0x51, 0x6e, 0x92, 0x39, 0xac, 0xe0} }; -static char const * const *expected_method_list; +#define TEST_OPTIONAL 0x1 + +struct expected_method +{ + const char *method; + unsigned int flags; +}; + +static const struct expected_method *expected_method_list; BOOL g_showRunnable = TRUE; BOOL g_isRunning = TRUE; @@ -52,15 +60,25 @@ BOOL g_isRunning = TRUE; #define CHECK_EXPECTED_METHOD(method_name) \ do { \ trace("%s\n", method_name); \ - ok(*expected_method_list != NULL, "Extra method %s called\n", method_name); \ - if (*expected_method_list) \ + ok(expected_method_list->method != NULL, "Extra method %s called\n", method_name); \ + if (expected_method_list->method) \ { \ - ok(!strcmp(*expected_method_list, method_name), "Expected %s to be called instead of %s\n", \ - *expected_method_list, method_name); \ + while (expected_method_list->flags & TEST_OPTIONAL && \ + strcmp(expected_method_list->method, method_name) != 0) \ + expected_method_list++; \ + ok(!strcmp(expected_method_list->method, method_name), "Expected %s to be called instead of %s\n", \ + expected_method_list->method, method_name); \ expected_method_list++; \ } \ } while(0) +#define CHECK_NO_EXTRA_METHODS() \ + do { \ + while (expected_method_list->flags & TEST_OPTIONAL) \ + expected_method_list++; \ + ok(!expected_method_list->method, "Method sequence starting from %s not called\n", expected_method_list->method); \ + } while (0) + static HRESULT WINAPI OleObject_QueryInterface(IOleObject *iface, REFIID riid, void **ppv) { CHECK_EXPECTED_METHOD("OleObject_QueryInterface"); @@ -68,7 +86,7 @@ static HRESULT WINAPI OleObject_QueryInterface(IOleObject *iface, REFIID riid, v *ppv = NULL; if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IOleObject)) - *ppv = (void *)iface; + *ppv = iface; else if (IsEqualIID(riid, &IID_IPersistStorage)) *ppv = &OleObjectPersistStg; else if (IsEqualIID(riid, &IID_IOleCache)) @@ -660,102 +678,122 @@ static void test_OleCreate(IStorage *pStorage) HRESULT hr; IOleObject *pObject; FORMATETC formatetc; - static const char *methods_olerender_none[] = + static const struct expected_method methods_olerender_none[] = { - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_QueryInterface", - "OleObjectPersistStg_AddRef", - "OleObjectPersistStg_InitNew", - "OleObjectPersistStg_Release", - "OleObject_Release", - NULL + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", TEST_OPTIONAL }, + { "OleObject_Release", TEST_OPTIONAL }, + { "OleObject_QueryInterface", TEST_OPTIONAL }, + { "OleObjectPersistStg_AddRef", 0 }, + { "OleObjectPersistStg_InitNew", 0 }, + { "OleObjectPersistStg_Release", 0 }, + { "OleObject_Release", 0 }, + { "OleObject_Release", TEST_OPTIONAL }, + { NULL, 0 } }; - static const char *methods_olerender_draw[] = + static const struct expected_method methods_olerender_draw[] = { - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_QueryInterface", - "OleObjectPersistStg_AddRef", - "OleObjectPersistStg_InitNew", - "OleObjectPersistStg_Release", - "OleObject_QueryInterface", - "OleObjectRunnable_AddRef", - "OleObjectRunnable_Run", - "OleObjectRunnable_Release", - "OleObject_QueryInterface", - "OleObjectCache_AddRef", - "OleObjectCache_Cache", - "OleObjectCache_Release", - "OleObject_Release", - NULL + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", TEST_OPTIONAL /* NT4 only */ }, + { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ }, + { "OleObject_QueryInterface", TEST_OPTIONAL /* NT4 only */ }, + { "OleObjectPersistStg_AddRef", 0 }, + { "OleObjectPersistStg_InitNew", 0 }, + { "OleObjectPersistStg_Release", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObjectRunnable_AddRef", 0 }, + { "OleObjectRunnable_Run", 0 }, + { "OleObjectRunnable_Release", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObjectCache_AddRef", 0 }, + { "OleObjectCache_Cache", 0 }, + { "OleObjectCache_Release", 0 }, + { "OleObject_Release", 0 }, + { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ }, + { NULL, 0 } }; - static const char *methods_olerender_format[] = + static const struct expected_method methods_olerender_format[] = { - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_GetMiscStatus", - "OleObject_QueryInterface", - "OleObjectPersistStg_AddRef", - "OleObjectPersistStg_InitNew", - "OleObjectPersistStg_Release", - "OleObject_SetClientSite", - "OleObject_Release", - "OleObject_QueryInterface", - "OleObjectRunnable_AddRef", - "OleObjectRunnable_Run", - "OleObjectRunnable_Release", - "OleObject_QueryInterface", - "OleObjectCache_AddRef", - "OleObjectCache_Cache", - "OleObjectCache_Release", - "OleObject_Release", - NULL + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_GetMiscStatus", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObjectPersistStg_AddRef", 0 }, + { "OleObjectPersistStg_InitNew", 0 }, + { "OleObjectPersistStg_Release", 0 }, + { "OleObject_SetClientSite", 0 }, + { "OleObject_Release", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObjectRunnable_AddRef", 0 }, + { "OleObjectRunnable_Run", 0 }, + { "OleObjectRunnable_Release", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObjectCache_AddRef", 0 }, + { "OleObjectCache_Cache", 0 }, + { "OleObjectCache_Release", 0 }, + { "OleObject_Release", 0 }, + { NULL, 0 } }; - static const char *methods_olerender_asis[] = + static const struct expected_method methods_olerender_asis[] = { - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_QueryInterface", - "OleObjectPersistStg_AddRef", - "OleObjectPersistStg_InitNew", - "OleObjectPersistStg_Release", - "OleObject_Release", - NULL + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", TEST_OPTIONAL /* NT4 only */ }, + { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ }, + { "OleObject_QueryInterface", TEST_OPTIONAL /* NT4 only */ }, + { "OleObjectPersistStg_AddRef", 0 }, + { "OleObjectPersistStg_InitNew", 0 }, + { "OleObjectPersistStg_Release", 0 }, + { "OleObject_Release", 0 }, + { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ }, + { NULL, 0 } }; - static const char *methods_olerender_draw_no_runnable[] = + static const struct expected_method methods_olerender_draw_no_runnable[] = { - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_QueryInterface", - "OleObjectPersistStg_AddRef", - "OleObjectPersistStg_InitNew", - "OleObjectPersistStg_Release", - "OleObject_QueryInterface", - "OleObject_QueryInterface", - "OleObjectCache_AddRef", - "OleObjectCache_Cache", - "OleObjectCache_Release", - "OleObject_Release", - NULL + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", TEST_OPTIONAL /* NT4 only */ }, + { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ }, + { "OleObject_QueryInterface", TEST_OPTIONAL /* NT4 only */ }, + { "OleObjectPersistStg_AddRef", 0 }, + { "OleObjectPersistStg_InitNew", 0 }, + { "OleObjectPersistStg_Release", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObjectCache_AddRef", 0 }, + { "OleObjectCache_Cache", 0 }, + { "OleObjectCache_Release", 0 }, + { "OleObject_Release", 0 }, + { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ }, + { NULL, 0 }, }; - static const char *methods_olerender_draw_no_cache[] = + static const struct expected_method methods_olerender_draw_no_cache[] = { - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_QueryInterface", - "OleObjectPersistStg_AddRef", - "OleObjectPersistStg_InitNew", - "OleObjectPersistStg_Release", - "OleObject_QueryInterface", - "OleObjectRunnable_AddRef", - "OleObjectRunnable_Run", - "OleObjectRunnable_Release", - "OleObject_QueryInterface", - "OleObject_Release", - NULL + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", TEST_OPTIONAL /* NT4 only */ }, + { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ }, + { "OleObject_QueryInterface", TEST_OPTIONAL /* NT4 only */ }, + { "OleObjectPersistStg_AddRef", 0 }, + { "OleObjectPersistStg_InitNew", 0 }, + { "OleObjectPersistStg_Release", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObjectRunnable_AddRef", 0 }, + { "OleObjectRunnable_Run", 0 }, + { "OleObjectRunnable_Release", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_Release", 0 }, + { "OleObject_Release", TEST_OPTIONAL /* NT4 only */ }, + { NULL, 0 } }; runnable = &OleObjectRunnable; @@ -765,14 +803,14 @@ static void test_OleCreate(IStorage *pStorage) hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_NONE, NULL, NULL, pStorage, (void **)&pObject); ok_ole_success(hr, "OleCreate"); IOleObject_Release(pObject); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); expected_method_list = methods_olerender_draw; trace("OleCreate with OLERENDER_DRAW:\n"); hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_DRAW, NULL, NULL, pStorage, (void **)&pObject); ok_ole_success(hr, "OleCreate"); IOleObject_Release(pObject); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); formatetc.cfFormat = CF_TEXT; formatetc.ptd = NULL; @@ -782,34 +820,38 @@ static void test_OleCreate(IStorage *pStorage) expected_method_list = methods_olerender_format; trace("OleCreate with OLERENDER_FORMAT:\n"); hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_FORMAT, &formatetc, (IOleClientSite *)0xdeadbeef, pStorage, (void **)&pObject); - ok_ole_success(hr, "OleCreate"); + ok(hr == S_OK || + broken(hr == E_INVALIDARG), /* win2k */ + "OleCreate failed with error 0x%08x\n", hr); if (pObject) + { IOleObject_Release(pObject); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); + } expected_method_list = methods_olerender_asis; trace("OleCreate with OLERENDER_ASIS:\n"); hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_ASIS, NULL, NULL, pStorage, (void **)&pObject); ok_ole_success(hr, "OleCreate"); IOleObject_Release(pObject); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); runnable = NULL; expected_method_list = methods_olerender_draw_no_runnable; - trace("OleCreate with OLERENDER_DRAW (no IOlObjectRunnable):\n"); + trace("OleCreate with OLERENDER_DRAW (no IRunnableObject):\n"); hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_DRAW, NULL, NULL, pStorage, (void **)&pObject); ok_ole_success(hr, "OleCreate"); IOleObject_Release(pObject); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); runnable = &OleObjectRunnable; cache = NULL; expected_method_list = methods_olerender_draw_no_cache; - trace("OleCreate with OLERENDER_DRAW (no IOlObjectRunnable):\n"); + trace("OleCreate with OLERENDER_DRAW (no IOleCache):\n"); hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_DRAW, NULL, NULL, pStorage, (void **)&pObject); ok_ole_success(hr, "OleCreate"); IOleObject_Release(pObject); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); trace("end\n"); } @@ -818,31 +860,35 @@ static void test_OleLoad(IStorage *pStorage) HRESULT hr; IOleObject *pObject; - static const char *methods_oleload[] = + static const struct expected_method methods_oleload[] = { - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_QueryInterface", - "OleObject_AddRef", - "OleObject_GetMiscStatus", - "OleObject_QueryInterface", - "OleObjectPersistStg_AddRef", - "OleObjectPersistStg_Load", - "OleObjectPersistStg_Release", - "OleObject_SetClientSite", - "OleObject_Release", - "OleObject_QueryInterface", - "OleObject_Release", - NULL + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_AddRef", 0 }, + { "OleObject_GetMiscStatus", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObjectPersistStg_AddRef", 0 }, + { "OleObjectPersistStg_Load", 0 }, + { "OleObjectPersistStg_Release", 0 }, + { "OleObject_SetClientSite", 0 }, + { "OleObject_Release", 0 }, + { "OleObject_QueryInterface", 0 }, + { "OleObject_Release", 0 }, + { NULL, 0 } }; expected_method_list = methods_oleload; trace("OleLoad:\n"); hr = OleLoad(pStorage, &IID_IOleObject, (IOleClientSite *)0xdeadbeef, (void **)&pObject); - ok_ole_success(hr, "OleLoad"); + ok(hr == S_OK || + broken(hr == E_INVALIDARG), /* win98 and win2k */ + "OleLoad failed with error 0x%08x\n", hr); if (pObject) + { IOleObject_Release(pObject); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); +} } static BOOL STDMETHODCALLTYPE draw_continue(ULONG_PTR param) @@ -1066,27 +1112,27 @@ static void test_data_cache(void) WCHAR wszPath[MAX_PATH]; static const WCHAR wszShell32[] = {'\\','s','h','e','l','l','3','2','.','d','l','l',0}; - static const char *methods_cacheinitnew[] = + static const struct expected_method methods_cacheinitnew[] = { - "AdviseSink_OnViewChange", - "AdviseSink_OnViewChange", - "draw_continue", - "DataObject_DAdvise", - "DataObject_DAdvise", - "DataObject_DUnadvise", - "DataObject_DUnadvise", - NULL + { "AdviseSink_OnViewChange", 0 }, + { "AdviseSink_OnViewChange", 0 }, + { "draw_continue", 0 }, + { "DataObject_DAdvise", 0 }, + { "DataObject_DAdvise", 0 }, + { "DataObject_DUnadvise", 0 }, + { "DataObject_DUnadvise", 0 }, + { NULL, 0 } }; - static const char *methods_cacheload[] = + static const struct expected_method methods_cacheload[] = { - "AdviseSink_OnViewChange", - "draw_continue", - "draw_continue", - "draw_continue", - "DataObject_GetData", - "DataObject_GetData", - "DataObject_GetData", - NULL + { "AdviseSink_OnViewChange", 0 }, + { "draw_continue", 0 }, + { "draw_continue", 0 }, + { "draw_continue", 0 }, + { "DataObject_GetData", 0 }, + { "DataObject_GetData", 0 }, + { "DataObject_GetData", 0 }, + { NULL, 0 } }; GetSystemDirectory(szSystemDir, sizeof(szSystemDir)/sizeof(szSystemDir[0])); @@ -1159,7 +1205,8 @@ static void test_data_cache(void) ok(hr == S_OK, "IOleCache_Cache cfFormat = %d, tymed = %d should have returned S_OK instead of 0x%08x\n", fmtetc.cfFormat, fmtetc.tymed, hr); else if (fmtetc.tymed == TYMED_HGLOBAL) - ok(hr == CACHE_S_FORMATETC_NOTSUPPORTED, + ok(hr == CACHE_S_FORMATETC_NOTSUPPORTED || + broken(hr == S_OK && fmtetc.cfFormat == CF_BITMAP) /* Win9x & NT4 */, "IOleCache_Cache cfFormat = %d, tymed = %d should have returned CACHE_S_FORMATETC_NOTSUPPORTED instead of 0x%08x\n", fmtetc.cfFormat, fmtetc.tymed, hr); else @@ -1243,7 +1290,7 @@ static void test_data_cache(void) IOleCacheControl_Release(pOleCacheControl); todo_wine { - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); } /* Test with loaded data */ @@ -1315,7 +1362,7 @@ static void test_data_cache(void) IOleCache_Release(pOleCache); todo_wine { - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); } IStorage_Release(pStorage); @@ -1376,7 +1423,6 @@ static void test_default_handler(void) hr); hr = IOleObject_GetMiscStatus(pObject, DVASPECT_CONTENT, &dwStatus); - todo_wine ok(hr == REGDB_E_CLASSNOTREG, "IOleObject_GetMiscStatus should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr); hr = IOleObject_GetUserClassID(pObject, &clsid); @@ -1473,38 +1519,38 @@ static void test_default_handler(void) IOleObject_Release(pObject); } -void test_runnable(void) +static void test_runnable(void) { - static const char *methods_query_runnable[] = + static const struct expected_method methods_query_runnable[] = { - "OleObject_QueryInterface", - "OleObjectRunnable_AddRef", - "OleObjectRunnable_IsRunning", - "OleObjectRunnable_Release", - NULL + { "OleObject_QueryInterface", 0 }, + { "OleObjectRunnable_AddRef", 0 }, + { "OleObjectRunnable_IsRunning", 0 }, + { "OleObjectRunnable_Release", 0 }, + { NULL, 0 } }; - static const char *methods_no_runnable[] = + static const struct expected_method methods_no_runnable[] = { - "OleObject_QueryInterface", - NULL + { "OleObject_QueryInterface", 0 }, + { NULL, 0 } }; - IOleObject *object = (IOleObject *)&OleObject; + IOleObject *object = &OleObject; expected_method_list = methods_query_runnable; ok(OleIsRunning(object), "Object should be running\n"); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); g_isRunning = FALSE; expected_method_list = methods_query_runnable; ok(OleIsRunning(object) == FALSE, "Object should not be running\n"); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); g_showRunnable = FALSE; /* QueryInterface(IID_IRunnableObject, ...) will fail */ expected_method_list = methods_no_runnable; ok(OleIsRunning(object), "Object without IRunnableObject should be running\n"); - ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); + CHECK_NO_EXTRA_METHODS(); g_isRunning = TRUE; g_showRunnable = TRUE; diff --git a/rostests/winetests/ole32/ole32.rbuild b/rostests/winetests/ole32/ole32.rbuild index 4438cdf49bb..828e63d45eb 100644 --- a/rostests/winetests/ole32/ole32.rbuild +++ b/rostests/winetests/ole32/ole32.rbuild @@ -3,10 +3,10 @@ . - 0x600 - 0x600 + clipboard.c compobj.c + defaulthandler.c dragdrop.c errorinfo.c hglobalstream.c @@ -24,7 +24,6 @@ user32 gdi32 advapi32 - kernel32 uuid ntdll diff --git a/rostests/winetests/ole32/propvariant.c b/rostests/winetests/ole32/propvariant.c index f1cbc76ecdc..24d2a63132a 100644 --- a/rostests/winetests/ole32/propvariant.c +++ b/rostests/winetests/ole32/propvariant.c @@ -23,13 +23,14 @@ #include "wine/test.h" /* invalid in all versions */ -#define PROP_INV 255 +#define PROP_INV 0x7f /* valid in v0 and above (NT4+) */ #define PROP_V0 0 /* valid in v1 and above (Win2k+) */ #define PROP_V1 1 /* valid in v1a and above (WinXP+) */ #define PROP_V1A 2 +#define PROP_TODO 0x80 struct valid_mapping { @@ -41,28 +42,28 @@ struct valid_mapping { { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_EMPTY */ { PROP_V0 , PROP_INV, PROP_INV, PROP_INV }, /* VT_NULL */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_I2 */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_I4 */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_R4 */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_R8 */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_CY */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_DATE */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_BSTR */ - { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 }, /* VT_DISPATCH */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_ERROR */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_BOOL */ - { PROP_V1 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_VARIANT */ - { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 }, /* VT_UNKNOWN */ - { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 }, /* VT_DECIMAL */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_I2 */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_I4 */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_R4 */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_R8 */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_CY */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_DATE */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_BSTR */ + { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_DISPATCH */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_ERROR */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_BOOL */ + { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_VARIANT */ + { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_UNKNOWN */ + { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_DECIMAL */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 15 */ - { PROP_V1 , PROP_V1 , PROP_V1 , PROP_V1 }, /* VT_I1 */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_UI1 */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_UI2 */ - { PROP_V0 , PROP_V1 , PROP_V0 , PROP_V1 }, /* VT_UI4 */ - { PROP_V0 , PROP_V1A, PROP_V0 , PROP_V1A }, /* VT_I8 */ - { PROP_V0 , PROP_V1A, PROP_V0 , PROP_V1A }, /* VT_UI8 */ - { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 }, /* VT_INT */ - { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 }, /* VT_UINT */ + { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO }, /* VT_I1 */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI1 */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI2 */ + { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO }, /* VT_UI4 */ + { PROP_V0 , PROP_V1A | PROP_TODO, PROP_V0 , PROP_V1A | PROP_TODO }, /* VT_I8 */ + { PROP_V0 , PROP_V1A | PROP_TODO, PROP_V0 , PROP_V1A | PROP_TODO }, /* VT_UI8 */ + { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_INT */ + { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_UINT */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_VOID */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_HRESULT */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_PTR */ @@ -75,7 +76,7 @@ struct valid_mapping { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 33 */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 34 */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 35 */ - { PROP_V1 , PROP_V1 , PROP_INV, PROP_V1 }, /* VT_RECORD */ + { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO }, /* VT_RECORD */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_INT_PTR */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* VT_UINT_PTR */ { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 39 */ @@ -126,74 +127,83 @@ static const char* wine_vtypes[VT_CLSID+1] = "VT_STREAMED_OBJECT","VT_STORED_OBJECT","VT_BLOB_OBJECT","VT_CF","VT_CLSID" }; + +static void expect(HRESULT hr, VARTYPE vt) +{ + int idx = vt & VT_TYPEMASK; + BYTE flags; + const char *modifier; + + if(vt & VT_BYREF) + { + flags = valid_types[idx].byref; + modifier = "byref"; + } + else if(vt & VT_ARRAY) + { + flags = valid_types[idx].with_array; + modifier = "array"; + } + else if(vt & VT_VECTOR) + { + flags = valid_types[idx].with_vector; + modifier = "vector"; + } + else + { + flags = valid_types[idx].simple; + modifier = "simple"; + } + + if(flags == PROP_INV) + ok(hr == STG_E_INVALIDPARAMETER, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr); + else if(flags == PROP_V0) + ok(hr == S_OK, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr); + else if(flags & PROP_TODO) + { + todo_wine + { + if(hr != S_OK) + win_skip("%s (%s): unsupported\n", wine_vtypes[idx], modifier); + else ok(hr == S_OK, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr); + } + } + else + { + if(hr != S_OK) + win_skip("%s (%s): unsupported\n", wine_vtypes[idx], modifier); + else ok(hr == S_OK, "%s (%s): got %08x\n", wine_vtypes[idx], modifier, hr); + } +} + static void test_validtypes(void) { PROPVARIANT propvar; HRESULT hr; unsigned int i; - BYTE version; memset(&propvar, 0, sizeof(propvar)); - /* detect version */ - propvar.vt = VT_I2 | VT_ARRAY; - hr = PropVariantClear(&propvar); - if (hr == S_OK) - { - propvar.vt = VT_I8 | VT_ARRAY; - hr = PropVariantClear(&propvar); - if (hr == S_OK) - { - version = PROP_V1A; - trace("detected prop variant v1a\n"); - } - else - { - version = PROP_V1; - trace("detected prop variant v1\n"); - } - } - else - { - version = PROP_V0; - trace("detected prop variant v0\n"); - } - for (i = 0; i < sizeof(valid_types)/sizeof(valid_types[0]); i++) { - BOOL expected_result; + VARTYPE vt; - propvar.vt = i; + vt = propvar.vt = i; hr = PropVariantClear(&propvar); - expected_result = (valid_types[i].simple <= version ? TRUE : FALSE); - ok(expected_result == !(hr == STG_E_INVALIDPARAMETER), - "PropVariantClear(%s) should have returned 0x%08x, but returned 0x%08x\n", - wine_vtypes[i], - expected_result ? S_OK : STG_E_INVALIDPARAMETER, hr); + expect(hr, vt); - propvar.vt = i | VT_ARRAY; + vt = propvar.vt = i | VT_ARRAY; hr = PropVariantClear(&propvar); - expected_result = (valid_types[i].with_array <= version ? TRUE : FALSE); - ok(expected_result == !(hr == STG_E_INVALIDPARAMETER), - "PropVariantClear(%s|VT_ARRAY) should have returned 0x%08x, but returned 0x%08x\n", - wine_vtypes[i], - expected_result ? S_OK : STG_E_INVALIDPARAMETER, hr); + expect(hr, vt); - propvar.vt = i | VT_VECTOR; + vt = propvar.vt = i | VT_VECTOR; hr = PropVariantClear(&propvar); - expected_result = (valid_types[i].with_vector <= version ? TRUE : FALSE); - ok(expected_result == !(hr == STG_E_INVALIDPARAMETER), - "PropVariantClear(%s|VT_VECTOR) should have returned 0x%08x, but returned 0x%08x\n", - wine_vtypes[i], - expected_result ? S_OK : STG_E_INVALIDPARAMETER, hr); + expect(hr, vt); - propvar.vt = i | VT_BYREF; + vt = propvar.vt = i | VT_BYREF; hr = PropVariantClear(&propvar); - expected_result = (valid_types[i].byref <= version ? TRUE : FALSE); - ok(expected_result == !(hr == STG_E_INVALIDPARAMETER), - "PropVariantClear(%s|VT_BYREF) should have returned 0x%08x, but returned 0x%08x\n", - wine_vtypes[i], - expected_result ? S_OK : STG_E_INVALIDPARAMETER, hr); + expect(hr, vt); + } } diff --git a/rostests/winetests/ole32/stg_prop.c b/rostests/winetests/ole32/stg_prop.c index 5a007e48105..82609462dc1 100644 --- a/rostests/winetests/ole32/stg_prop.c +++ b/rostests/winetests/ole32/stg_prop.c @@ -19,6 +19,12 @@ #define COBJMACROS #include "objbase.h" #include "wine/test.h" +#include "initguid.h" + +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +DEFINE_GUID(FMTID_SummaryInformation,0xF29F85E0,0x4FF9,0x1068,0xAB,0x91,0x08,0x00,0x2B,0x27,0xB3,0xD9); +DEFINE_GUID(FMTID_DocSummaryInformation,0xD5CDD502,0x2E9C,0x101B,0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE); +DEFINE_GUID(FMTID_UserDefinedProperties,0xD5CDD505,0x2E9C,0x101B,0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE); #ifndef PID_BEHAVIOR #define PID_BEHAVIOR 0x80000003 @@ -94,7 +100,7 @@ static void testProps(void) /* test setting one by name with an invalid propidNameFirst */ spec.ulKind = PRSPEC_LPWSTR; - U(spec).lpwstr = (LPOLESTR)propName; + U(spec).lpwstr = propName; hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, PID_DICTIONARY); ok(hr == STG_E_INVALIDPARAMETER, @@ -117,7 +123,7 @@ static void testProps(void) /* set one by name */ spec.ulKind = PRSPEC_LPWSTR; - U(spec).lpwstr = (LPOLESTR)propName; + U(spec).lpwstr = propName; U(var).lVal = 2; hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, PID_FIRST_USABLE); @@ -154,15 +160,15 @@ static void testProps(void) hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var); ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr); ok(var.vt == VT_I4 && U(var).lVal == 1, - "Didn't get expected type or value for property (got type %d, value %ld)\n", + "Didn't get expected type or value for property (got type %d, value %d)\n", var.vt, U(var).lVal); /* read by name */ spec.ulKind = PRSPEC_LPWSTR; - U(spec).lpwstr = (LPOLESTR)propName; + U(spec).lpwstr = propName; hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var); ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr); ok(var.vt == VT_I4 && U(var).lVal == 2, - "Didn't get expected type or value for property (got type %d, value %ld)\n", + "Didn't get expected type or value for property (got type %d, value %d)\n", var.vt, U(var).lVal); /* read string value */ spec.ulKind = PRSPEC_PROPID; @@ -231,7 +237,7 @@ static void testProps(void) ok(hr == S_OK, "Commit failed: 0x%08x\n", hr); /* set it to a string value */ var.vt = VT_LPSTR; - U(var).pszVal = (LPSTR)val; + U(var).pszVal = val; hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0); ok(hr == S_OK, "WriteMultiple failed: 0x%08x\n", hr); /* revert it */ @@ -263,11 +269,11 @@ static void testProps(void) /* check properties again */ spec.ulKind = PRSPEC_LPWSTR; - U(spec).lpwstr = (LPOLESTR)propName; + U(spec).lpwstr = propName; hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var); ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr); ok(var.vt == VT_I4 && U(var).lVal == 2, - "Didn't get expected type or value for property (got type %d, value %ld)\n", + "Didn't get expected type or value for property (got type %d, value %d)\n", var.vt, U(var).lVal); spec.ulKind = PRSPEC_PROPID; U(spec).propid = PIDSI_AUTHOR; @@ -402,8 +408,7 @@ static void testCodepage(void) /* check code page before it's been explicitly set */ hr = IPropertyStorage_ReadMultiple(propertyStorage, 1, &spec, &var); ok(hr == S_OK, "ReadMultiple failed: 0x%08x\n", hr); - ok(var.vt == VT_I2 && U(var).iVal == 1252, - "Didn't get expected type or value for property\n"); + ok(var.vt == VT_I2, "Didn't get expected type for property (%u)\n", var.vt); /* Set code page to Unicode */ U(var).iVal = 1200; hr = IPropertyStorage_WriteMultiple(propertyStorage, 1, &spec, &var, 0); diff --git a/rostests/winetests/ole32/storage32.c b/rostests/winetests/ole32/storage32.c index 7dc633c9fb7..da2d0aa5a6e 100644 --- a/rostests/winetests/ole32/storage32.c +++ b/rostests/winetests/ole32/storage32.c @@ -262,7 +262,8 @@ static void test_storage_stream(void) r = IStorage_CreateStream(stg, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm ); ok(r==STG_E_INVALIDNAME, "IStorage->CreateStream wrong error\n"); r = IStorage_CreateStream(stg, longname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm ); - ok(r==STG_E_INVALIDNAME, "IStorage->CreateStream wrong error, got %d GetLastError()=%d\n", r, GetLastError()); + ok(r==STG_E_INVALIDNAME || broken(r==S_OK) /* nt4 */, + "IStorage->CreateStream wrong error, got %d GetLastError()=%d\n", r, GetLastError()); r = IStorage_CreateStream(stg, stmname, STGM_READWRITE, 0, 0, &stm ); ok(r==STG_E_INVALIDFLAG, "IStorage->CreateStream wrong error\n"); r = IStorage_CreateStream(stg, stmname, STGM_READ, 0, 0, &stm ); @@ -802,6 +803,56 @@ static void test_storage_refcount(void) DeleteFileW(filename); } +static void test_writeclassstg(void) +{ + static const WCHAR szPrefix[] = { 's','t','g',0 }; + static const WCHAR szDot[] = { '.',0 }; + WCHAR filename[MAX_PATH]; + IStorage *stg = NULL; + HRESULT r; + CLSID temp_cls; + + if(!GetTempFileNameW(szDot, szPrefix, 0, filename)) + return; + + DeleteFileW(filename); + + /* create the file */ + r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | + STGM_READWRITE, 0, &stg); + ok(r==S_OK, "StgCreateDocfile failed\n"); + + r = ReadClassStg( NULL, NULL ); + ok(r == E_INVALIDARG, "ReadClassStg should return E_INVALIDARG instead of 0x%08X\n", r); + + r = ReadClassStg( stg, NULL ); + ok(r == E_INVALIDARG, "ReadClassStg should return E_INVALIDARG instead of 0x%08X\n", r); + + temp_cls.Data1 = 0xdeadbeef; + r = ReadClassStg( stg, &temp_cls ); + ok(r == S_OK, "ReadClassStg failed with 0x%08X\n", r); + + ok(IsEqualCLSID(&temp_cls, &CLSID_NULL), "ReadClassStg returned wrong clsid\n"); + + r = WriteClassStg( NULL, NULL ); + ok(r == E_INVALIDARG, "WriteClassStg should return E_INVALIDARG instead of 0x%08X\n", r); + + r = WriteClassStg( stg, NULL ); + ok(r == STG_E_INVALIDPOINTER, "WriteClassStg should return STG_E_INVALIDPOINTER instead of 0x%08X\n", r); + + r = WriteClassStg( stg, &test_stg_cls ); + ok( r == S_OK, "WriteClassStg failed with 0x%08X\n", r); + + r = ReadClassStg( stg, &temp_cls ); + ok( r == S_OK, "ReadClassStg failed with 0x%08X\n", r); + ok(IsEqualCLSID(&temp_cls, &test_stg_cls), "ReadClassStg returned wrong clsid\n"); + + r = IStorage_Release( stg ); + ok (r == 0, "storage not released\n"); + + DeleteFileW(filename); +} + static void test_streamenum(void) { static const WCHAR szPrefix[] = { 's','t','g',0 }; @@ -999,6 +1050,223 @@ static void test_ReadClassStm(void) ok(IsEqualCLSID(&clsid, &test_stg_cls), "clsid should have been set to CLSID_WineTest\n"); } +struct access_res +{ + BOOL gothandle; + DWORD lasterr; + BOOL ignore; +}; + +static const struct access_res create[16] = +{ + { TRUE, ERROR_SUCCESS, TRUE }, + { TRUE, ERROR_SUCCESS, TRUE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, TRUE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, TRUE } +}; + +static const struct access_res create_commit[16] = +{ + { TRUE, ERROR_SUCCESS, TRUE }, + { TRUE, ERROR_SUCCESS, TRUE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, TRUE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { FALSE, ERROR_SHARING_VIOLATION, FALSE }, + { TRUE, ERROR_SUCCESS, TRUE } +}; + +static const struct access_res create_close[16] = +{ + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS, FALSE }, + { TRUE, ERROR_SUCCESS } +}; + +static void _test_file_access(LPCSTR file, const struct access_res *ares, DWORD line) +{ + DWORD access = 0, share = 0; + DWORD lasterr; + HANDLE hfile; + int i, j, idx = 0; + + for (i = 0; i < 4; i++) + { + if (i == 0) access = 0; + if (i == 1) access = GENERIC_READ; + if (i == 2) access = GENERIC_WRITE; + if (i == 3) access = GENERIC_READ | GENERIC_WRITE; + + for (j = 0; j < 4; j++) + { + if (ares[idx].ignore) + continue; + + if (j == 0) share = 0; + if (j == 1) share = FILE_SHARE_READ; + if (j == 2) share = FILE_SHARE_WRITE; + if (j == 3) share = FILE_SHARE_READ | FILE_SHARE_WRITE; + + SetLastError(0xdeadbeef); + hfile = CreateFileA(file, access, share, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + lasterr = GetLastError(); + + ok((hfile != INVALID_HANDLE_VALUE) == ares[idx].gothandle, + "(%d, handle, %d): Expected %d, got %d\n", + line, idx, ares[idx].gothandle, + (hfile != INVALID_HANDLE_VALUE)); + + ok(lasterr == ares[idx].lasterr || + broken(lasterr == 0xdeadbeef) /* win9x */, + "(%d, lasterr, %d): Expected %d, got %d\n", + line, idx, ares[idx].lasterr, lasterr); + + CloseHandle(hfile); + idx++; + } + } +} + +#define test_file_access(file, ares) _test_file_access(file, ares, __LINE__) + +static void test_access(void) +{ + IStorage *stg; + HRESULT hr; + + static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0}; + + /* STGM_TRANSACTED */ + + hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | + STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, &stg); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create); + + hr = IStorage_Commit(stg, STGC_DEFAULT); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create_commit); + + IStorage_Release(stg); + + test_file_access("winetest", create_close); + + DeleteFileA("winetest"); + + /* STGM_DIRECT */ + + hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | + STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &stg); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create); + + hr = IStorage_Commit(stg, STGC_DEFAULT); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create_commit); + + IStorage_Release(stg); + + test_file_access("winetest", create_close); + + DeleteFileA("winetest"); + + /* STGM_SHARE_DENY_NONE */ + + hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | + STGM_SHARE_DENY_NONE | STGM_TRANSACTED, 0, &stg); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create); + + hr = IStorage_Commit(stg, STGC_DEFAULT); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create_commit); + + IStorage_Release(stg); + + test_file_access("winetest", create_close); + + DeleteFileA("winetest"); + + /* STGM_SHARE_DENY_READ */ + + hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | + STGM_SHARE_DENY_READ | STGM_TRANSACTED, 0, &stg); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create); + + hr = IStorage_Commit(stg, STGC_DEFAULT); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create_commit); + + IStorage_Release(stg); + + test_file_access("winetest", create_close); + + DeleteFileA("winetest"); + + /* STGM_SHARE_DENY_WRITE */ + + hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE | + STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create); + + hr = IStorage_Commit(stg, STGC_DEFAULT); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + test_file_access("winetest", create_commit); + + IStorage_Release(stg); + + test_file_access("winetest", create_close); + + DeleteFileA("winetest"); +} + START_TEST(storage32) { test_hglobal_storage_stat(); @@ -1010,4 +1278,6 @@ START_TEST(storage32) test_streamenum(); test_transact(); test_ReadClassStm(); + test_access(); + test_writeclassstg(); } diff --git a/rostests/winetests/ole32/testlist.c b/rostests/winetests/ole32/testlist.c index 0d19af299c6..65c40d2c5ad 100644 --- a/rostests/winetests/ole32/testlist.c +++ b/rostests/winetests/ole32/testlist.c @@ -8,6 +8,7 @@ extern void func_clipboard(void); extern void func_compobj(void); +extern void func_defaulthandler(void); extern void func_dragdrop(void); extern void func_errorinfo(void); extern void func_hglobalstream(void); @@ -23,6 +24,7 @@ const struct test winetest_testlist[] = { { "clipboard", func_clipboard }, { "compobj", func_compobj }, + { "defaulthandler", func_defaulthandler }, { "dragdrop", func_dragdrop }, { "errorinfo", func_errorinfo }, { "hglobalstream", func_hglobalstream }, diff --git a/rostests/winetests/ole32/usrmarshal.c b/rostests/winetests/ole32/usrmarshal.c index 60e85cf5544..3411cc283b1 100644 --- a/rostests/winetests/ole32/usrmarshal.c +++ b/rostests/winetests/ole32/usrmarshal.c @@ -34,6 +34,48 @@ unsigned char * __RPC_USER HMETAFILE_UserMarshal(ULONG *, unsigned char *, HMETA unsigned char * __RPC_USER HMETAFILE_UserUnmarshal(ULONG *, unsigned char *, HMETAFILE *); void __RPC_USER HMETAFILE_UserFree(ULONG *, HMETAFILE *); +ULONG __RPC_USER HENHMETAFILE_UserSize(ULONG *, ULONG, HENHMETAFILE *); +unsigned char * __RPC_USER HENHMETAFILE_UserMarshal (ULONG *, unsigned char *, HENHMETAFILE *); +unsigned char * __RPC_USER HENHMETAFILE_UserUnmarshal(ULONG *, unsigned char *, HENHMETAFILE *); +void __RPC_USER HENHMETAFILE_UserFree(ULONG *, HENHMETAFILE *); + +ULONG __RPC_USER HMETAFILEPICT_UserSize(ULONG *, ULONG, HMETAFILEPICT *); +unsigned char * __RPC_USER HMETAFILEPICT_UserMarshal (ULONG *, unsigned char *, HMETAFILEPICT *); +unsigned char * __RPC_USER HMETAFILEPICT_UserUnmarshal(ULONG *, unsigned char *, HMETAFILEPICT *); +void __RPC_USER HMETAFILEPICT_UserFree(ULONG *, HMETAFILEPICT *); + +static void * WINAPI user_allocate(SIZE_T size) +{ + return CoTaskMemAlloc(size); +} + +static void WINAPI user_free(void *p) +{ + CoTaskMemFree(p); +} + +static void init_user_marshal_cb(USER_MARSHAL_CB *umcb, + PMIDL_STUB_MESSAGE stub_msg, + PRPC_MESSAGE rpc_msg, unsigned char *buffer, + unsigned int size, MSHCTX context) +{ + memset(rpc_msg, 0, sizeof(*rpc_msg)); + rpc_msg->Buffer = buffer; + rpc_msg->BufferLength = size; + + memset(stub_msg, 0, sizeof(*stub_msg)); + stub_msg->RpcMsg = rpc_msg; + stub_msg->Buffer = buffer; + stub_msg->pfnAllocate = user_allocate; + stub_msg->pfnFree = user_free; + + memset(umcb, 0, sizeof(*umcb)); + umcb->Flags = MAKELONG(context, NDR_LOCAL_DATA_REPRESENTATION); + umcb->pStubMsg = stub_msg; + umcb->Signature = USER_MARSHAL_CB_SIGNATURE; + umcb->CBType = buffer ? USER_MARSHAL_CB_UNMARSHALL : USER_MARSHAL_CB_BUFFER_SIZE; +} + static const char cf_marshaled[] = { 0x9, 0x0, 0x0, 0x0, @@ -48,137 +90,166 @@ static const char cf_marshaled[] = static void test_marshal_CLIPFORMAT(void) { + USER_MARSHAL_CB umcb; + MIDL_STUB_MESSAGE stub_msg; + RPC_MESSAGE rpc_msg; unsigned char *buffer; - ULONG size; - ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); - wireCLIPFORMAT wirecf; + ULONG i, size; CLIPFORMAT cf = RegisterClipboardFormatA("MyFormat"); CLIPFORMAT cf2; - size = CLIPFORMAT_UserSize(&flags, 0, &cf); - ok(size == sizeof(*wirecf) + sizeof(cf_marshaled), "Wrong size %d\n", size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = CLIPFORMAT_UserSize(&umcb.Flags, 0, &cf); + ok(size == 8 + sizeof(cf_marshaled) || + broken(size == 12 + sizeof(cf_marshaled)) || /* win64 adds 4 extra (unused) bytes */ + broken(size == 8 + sizeof(cf_marshaled) - 2), /* win9x and winnt don't include the '\0' */ + "CLIPFORMAT: Wrong size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - CLIPFORMAT_UserMarshal(&flags, buffer, &cf); - wirecf = (wireCLIPFORMAT)buffer; - ok(wirecf->fContext == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08lx\n", wirecf->fContext); - ok(wirecf->u.dwValue == cf, "Marshaled value should be 0x%04x instead of 0x%04x\n", cf, wirecf->u.dwValue); - ok(!memcmp(wirecf+1, cf_marshaled, sizeof(cf_marshaled)), "Marshaled data differs\n"); + memset( buffer, 0xcc, size ); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + CLIPFORMAT_UserMarshal(&umcb.Flags, buffer, &cf); + ok(*(LONG *)(buffer + 0) == WDT_REMOTE_CALL, "CLIPFORMAT: Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(LONG *)(buffer + 0)); + ok(*(DWORD *)(buffer + 4) == cf, "CLIPFORMAT: Marshaled value should be 0x%04x instead of 0x%04x\n", cf, *(DWORD *)(buffer + 4)); + ok(!memcmp(buffer + 8, cf_marshaled, min( sizeof(cf_marshaled), size-8 )), "Marshaled data differs\n"); + if (size > sizeof(cf_marshaled) + 8) /* make sure the extra bytes are not used */ + for (i = sizeof(cf_marshaled) + 8; i < size; i++) + ok( buffer[i] == 0xcc, "buffer offset %u has been set to %x\n", i, buffer[i] ); - CLIPFORMAT_UserUnmarshal(&flags, buffer, &cf2); - ok(cf == cf2, "Didn't unmarshal properly\n"); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + CLIPFORMAT_UserUnmarshal(&umcb.Flags, buffer, &cf2); + ok(cf == cf2, "CLIPFORMAT: Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); - CLIPFORMAT_UserFree(&flags, &cf2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + CLIPFORMAT_UserFree(&umcb.Flags, &cf2); } static void test_marshal_HWND(void) { + USER_MARSHAL_CB umcb; + MIDL_STUB_MESSAGE stub_msg; + RPC_MESSAGE rpc_msg; unsigned char *buffer; ULONG size; - ULONG flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION); HWND hwnd = GetDesktopWindow(); HWND hwnd2; wireHWND wirehwnd; - size = HWND_UserSize(&flags, 0, &hwnd); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = HWND_UserSize(&umcb.Flags, 0, &hwnd); ok(size == sizeof(*wirehwnd), "Wrong size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - HWND_UserMarshal(&flags, buffer, &hwnd); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HWND_UserMarshal(&umcb.Flags, buffer, &hwnd); wirehwnd = (wireHWND)buffer; - ok(wirehwnd->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08lx\n", wirehwnd->fContext); + ok(wirehwnd->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08x\n", wirehwnd->fContext); ok(wirehwnd->u.hInproc == (LONG_PTR)hwnd, "Marshaled value should be %p instead of %p\n", hwnd, (HANDLE)wirehwnd->u.hRemote); - HWND_UserUnmarshal(&flags, buffer, &hwnd2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HWND_UserUnmarshal(&umcb.Flags, buffer, &hwnd2); ok(hwnd == hwnd2, "Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); - HWND_UserFree(&flags, &hwnd2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + HWND_UserFree(&umcb.Flags, &hwnd2); } static void test_marshal_HGLOBAL(void) { + USER_MARSHAL_CB umcb; + MIDL_STUB_MESSAGE stub_msg; + RPC_MESSAGE rpc_msg; unsigned char *buffer; ULONG size; - ULONG flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION); HGLOBAL hglobal; HGLOBAL hglobal2; unsigned char *wirehglobal; int i; hglobal = NULL; - flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION); - size = HGLOBAL_UserSize(&flags, 0, &hglobal); - /* native is poorly programmed and allocates 4 bytes more than it needs to + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = HGLOBAL_UserSize(&umcb.Flags, 0, &hglobal); + /* native is poorly programmed and allocates 4/8 bytes more than it needs to * here - Wine doesn't have to emulate that */ - ok((size == 8) || (size == 12), "Size should be 12, instead of %d\n", size); + ok((size == 8) || broken(size == 12) || broken(size == 16), "Size should be 8, instead of %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - HGLOBAL_UserMarshal(&flags, buffer, &hglobal); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HGLOBAL_UserMarshal(&umcb.Flags, buffer, &hglobal); wirehglobal = buffer; ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)wirehglobal); wirehglobal += sizeof(ULONG); - ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+4 should be HGLOBAL\n"); - HGLOBAL_UserUnmarshal(&flags, buffer, &hglobal2); + ok(*(ULONG *)wirehglobal == 0, "buffer+4 should be HGLOBAL\n"); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2); ok(hglobal2 == hglobal, "Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); - HGLOBAL_UserFree(&flags, &hglobal2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + HGLOBAL_UserFree(&umcb.Flags, &hglobal2); hglobal = GlobalAlloc(0, 4); buffer = GlobalLock(hglobal); for (i = 0; i < 4; i++) buffer[i] = i; GlobalUnlock(hglobal); - flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION); - size = HGLOBAL_UserSize(&flags, 0, &hglobal); - /* native is poorly programmed and allocates 4 bytes more than it needs to + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = HGLOBAL_UserSize(&umcb.Flags, 0, &hglobal); + /* native is poorly programmed and allocates 4/8 bytes more than it needs to * here - Wine doesn't have to emulate that */ - ok((size == 24) || (size == 28), "Size should be 24 or 28, instead of %d\n", size); + ok((size == 24) || broken(size == 28) || broken(size == 32), "Size should be 24, instead of %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - HGLOBAL_UserMarshal(&flags, buffer, &hglobal); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HGLOBAL_UserMarshal(&umcb.Flags, buffer, &hglobal); wirehglobal = buffer; ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)wirehglobal); wirehglobal += sizeof(ULONG); - ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+0x4 should be HGLOBAL\n"); + ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0x4 should be HGLOBAL\n"); wirehglobal += sizeof(ULONG); - ok(*(ULONG *)wirehglobal == 4, "buffer+0x8 should be size of HGLOBAL\n"); + ok(*(ULONG *)wirehglobal == 4, "buffer+0x8 should be size of HGLOBAL instead of %d\n", *(ULONG *)wirehglobal); wirehglobal += sizeof(ULONG); - ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+0xc should be HGLOBAL\n"); + ok(*(ULONG *)wirehglobal == (ULONG)(ULONG_PTR)hglobal, "buffer+0xc should be HGLOBAL\n"); wirehglobal += sizeof(ULONG); - ok(*(ULONG *)wirehglobal == 4, "buffer+0x10 should be size of HGLOBAL\n"); + ok(*(ULONG *)wirehglobal == 4, "buffer+0x10 should be size of HGLOBAL instead of %d\n", *(ULONG *)wirehglobal); wirehglobal += sizeof(ULONG); for (i = 0; i < 4; i++) ok(wirehglobal[i] == i, "buffer+0x%x should be %d\n", 0x10 + i, i); - HGLOBAL_UserUnmarshal(&flags, buffer, &hglobal2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HGLOBAL_UserUnmarshal(&umcb.Flags, buffer, &hglobal2); ok(hglobal2 != NULL, "Didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); - HGLOBAL_UserFree(&flags, &hglobal2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + HGLOBAL_UserFree(&umcb.Flags, &hglobal2); GlobalFree(hglobal); } static HENHMETAFILE create_emf(void) { - RECT rect = {0, 0, 100, 100}; + const RECT rect = {0, 0, 100, 100}; HDC hdc = CreateEnhMetaFile(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0"); - ExtTextOut(hdc, 0, 0, ETO_OPAQUE, NULL, "Test String", strlen("Test String"), NULL); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL); return CloseEnhMetaFile(hdc); } static void test_marshal_HENHMETAFILE(void) { + USER_MARSHAL_CB umcb; + MIDL_STUB_MESSAGE stub_msg; + RPC_MESSAGE rpc_msg; unsigned char *buffer; ULONG size; - ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); HENHMETAFILE hemf; HENHMETAFILE hemf2 = NULL; unsigned char *wirehemf; hemf = create_emf(); - size = HENHMETAFILE_UserSize(&flags, 0, &hemf); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf); ok(size > 20, "size should be at least 20 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - HENHMETAFILE_UserMarshal(&flags, buffer, &hemf); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf); wirehemf = buffer; ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf); wirehemf += sizeof(DWORD); @@ -193,29 +264,35 @@ static void test_marshal_HENHMETAFILE(void) /* ... rest of data not tested - refer to tests for GetEnhMetaFileBits * at this point */ - HENHMETAFILE_UserUnmarshal(&flags, buffer, &hemf2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2); ok(hemf2 != NULL, "HENHMETAFILE didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); - HENHMETAFILE_UserFree(&flags, &hemf2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + HENHMETAFILE_UserFree(&umcb.Flags, &hemf2); DeleteEnhMetaFile(hemf); /* test NULL emf */ hemf = NULL; - size = HENHMETAFILE_UserSize(&flags, 0, &hemf); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = HENHMETAFILE_UserSize(&umcb.Flags, 0, &hemf); ok(size == 8, "size should be 8 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - HENHMETAFILE_UserMarshal(&flags, buffer, &hemf); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HENHMETAFILE_UserMarshal(&umcb.Flags, buffer, &hemf); wirehemf = buffer; ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehemf); wirehemf += sizeof(DWORD); ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08x\n", *(DWORD *)wirehemf); wirehemf += sizeof(DWORD); - HENHMETAFILE_UserUnmarshal(&flags, buffer, &hemf2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HENHMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hemf2); ok(hemf2 == NULL, "NULL HENHMETAFILE didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); - HENHMETAFILE_UserFree(&flags, &hemf2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + HENHMETAFILE_UserFree(&umcb.Flags, &hemf2); } static HMETAFILE create_mf(void) @@ -228,19 +305,23 @@ static HMETAFILE create_mf(void) static void test_marshal_HMETAFILE(void) { + USER_MARSHAL_CB umcb; + MIDL_STUB_MESSAGE stub_msg; + RPC_MESSAGE rpc_msg; unsigned char *buffer; ULONG size; - ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); HMETAFILE hmf; HMETAFILE hmf2 = NULL; unsigned char *wirehmf; hmf = create_mf(); - size = HMETAFILE_UserSize(&flags, 0, &hmf); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf); ok(size > 20, "size should be at least 20 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - HMETAFILE_UserMarshal(&flags, buffer, &hmf); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf); wirehmf = buffer; ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf); wirehmf += sizeof(DWORD); @@ -255,29 +336,32 @@ static void test_marshal_HMETAFILE(void) /* ... rest of data not tested - refer to tests for GetMetaFileBits * at this point */ - HMETAFILE_UserUnmarshal(&flags, buffer, &hmf2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2); ok(hmf2 != NULL, "HMETAFILE didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); - HMETAFILE_UserFree(&flags, &hmf2); + HMETAFILE_UserFree(&umcb.Flags, &hmf2); DeleteMetaFile(hmf); /* test NULL emf */ hmf = NULL; - size = HMETAFILE_UserSize(&flags, 0, &hmf); + size = HMETAFILE_UserSize(&umcb.Flags, 0, &hmf); ok(size == 8, "size should be 8 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - HMETAFILE_UserMarshal(&flags, buffer, &hmf); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HMETAFILE_UserMarshal(&umcb.Flags, buffer, &hmf); wirehmf = buffer; ok(*(DWORD *)wirehmf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmf); wirehmf += sizeof(DWORD); ok(*(DWORD *)wirehmf == (DWORD)(DWORD_PTR)hmf, "wirestgm + 0x4 should be hmf instead of 0x%08x\n", *(DWORD *)wirehmf); wirehmf += sizeof(DWORD); - HMETAFILE_UserUnmarshal(&flags, buffer, &hmf2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HMETAFILE_UserUnmarshal(&umcb.Flags, buffer, &hmf2); ok(hmf2 == NULL, "NULL HMETAFILE didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); - HMETAFILE_UserFree(&flags, &hmf2); + HMETAFILE_UserFree(&umcb.Flags, &hmf2); } #define USER_MARSHAL_PTR_PREFIX \ @@ -286,9 +370,11 @@ static void test_marshal_HMETAFILE(void) static void test_marshal_HMETAFILEPICT(void) { + USER_MARSHAL_CB umcb; + MIDL_STUB_MESSAGE stub_msg; + RPC_MESSAGE rpc_msg; unsigned char *buffer, *buffer_end; ULONG size; - ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); HMETAFILEPICT hmfp; HMETAFILEPICT hmfp2 = NULL; METAFILEPICT *pmfp; @@ -302,11 +388,13 @@ static void test_marshal_HMETAFILEPICT(void) pmfp->hMF = create_mf(); GlobalUnlock(hmfp); - size = HMETAFILEPICT_UserSize(&flags, 0, &hmfp); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp); ok(size > 20, "size should be at least 20 bytes, not %d\n", size); trace("size is %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - buffer_end = HMETAFILEPICT_UserMarshal(&flags, buffer, &hmfp); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + buffer_end = HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp); wirehmfp = buffer; ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp); wirehmfp += sizeof(DWORD); @@ -337,10 +425,12 @@ static void test_marshal_HMETAFILEPICT(void) /* ... rest of data not tested - refer to tests for GetMetaFileBits * at this point */ - HMETAFILEPICT_UserUnmarshal(&flags, buffer, &hmfp2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2); ok(hmfp2 != NULL, "HMETAFILEPICT didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); - HMETAFILEPICT_UserFree(&flags, &hmfp2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2); pmfp = GlobalLock(hmfp); DeleteMetaFile(pmfp->hMF); GlobalUnlock(hmfp); @@ -349,10 +439,12 @@ static void test_marshal_HMETAFILEPICT(void) /* test NULL emf */ hmfp = NULL; - size = HMETAFILEPICT_UserSize(&flags, 0, &hmfp); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = HMETAFILEPICT_UserSize(&umcb.Flags, 0, &hmfp); ok(size == 8, "size should be 8 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); - HMETAFILEPICT_UserMarshal(&flags, buffer, &hmfp); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HMETAFILEPICT_UserMarshal(&umcb.Flags, buffer, &hmfp); wirehmfp = buffer; ok(*(DWORD *)wirehmfp == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08x\n", *(DWORD *)wirehmfp); wirehmfp += sizeof(DWORD); @@ -360,10 +452,12 @@ static void test_marshal_HMETAFILEPICT(void) wirehmfp += sizeof(DWORD); hmfp2 = NULL; - HMETAFILEPICT_UserUnmarshal(&flags, buffer, &hmfp2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); + HMETAFILEPICT_UserUnmarshal(&umcb.Flags, buffer, &hmfp2); ok(hmfp2 == NULL, "NULL HMETAFILE didn't unmarshal\n"); HeapFree(GetProcessHeap(), 0, buffer); - HMETAFILEPICT_UserFree(&flags, &hmfp2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2); } static HRESULT WINAPI Test_IUnknown_QueryInterface( @@ -375,7 +469,7 @@ static HRESULT WINAPI Test_IUnknown_QueryInterface( if (IsEqualGUID(riid, &IID_IUnknown)) { - *ppvObj = (LPVOID)iface; + *ppvObj = iface; IUnknown_AddRef(iface); return S_OK; } @@ -410,27 +504,21 @@ void __RPC_USER WdtpInterfacePointer_UserFree(IUnknown *); static void test_marshal_WdtpInterfacePointer(void) { + USER_MARSHAL_CB umcb; + MIDL_STUB_MESSAGE stub_msg; + RPC_MESSAGE rpc_msg; unsigned char *buffer, *buffer_end; ULONG size; - MIDL_STUB_MESSAGE stubmsg; - USER_MARSHAL_CB umcb; IUnknown *unk; IUnknown *unk2; unsigned char *wireip; const IID *iid; - memset(&stubmsg, 0xcc, sizeof(stubmsg)); - stubmsg.dwDestContext = MSHCTX_INPROC; - stubmsg.pvDestContext = NULL; - - memset(&umcb, 0xcc, sizeof(umcb)); - umcb.Flags = MAKELONG(MSHCTX_INPROC, NDR_LOCAL_DATA_REPRESENTATION); - umcb.pStubMsg = &stubmsg; - /* shows that the WdtpInterfacePointer functions don't marshal anything for * NULL pointers, so code using these functions must handle that case * itself */ unk = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 0, unk, &IID_IUnknown); ok(size == 0, "size should be 0 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); @@ -439,11 +527,13 @@ static void test_marshal_WdtpInterfacePointer(void) HeapFree(GetProcessHeap(), 0, buffer); unk = &Test_Unknown; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); size = WdtpInterfacePointer_UserSize(&umcb.Flags, umcb.Flags, 0, unk, &IID_IUnknown); todo_wine ok(size > 28, "size should be > 28 bytes, not %d\n", size); trace("WdtpInterfacePointer_UserSize returned %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, umcb.Flags, buffer, unk, &IID_IUnknown); wireip = buffer; if (size >= 28) @@ -471,10 +561,12 @@ static void test_marshal_WdtpInterfacePointer(void) } unk2 = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_INPROC); WdtpInterfacePointer_UserUnmarshal(&umcb.Flags, buffer, &unk2, &IID_IUnknown); todo_wine ok(unk2 != NULL, "IUnknown object didn't unmarshal properly\n"); HeapFree(GetProcessHeap(), 0, buffer); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC); WdtpInterfacePointer_UserFree(unk2); } diff --git a/rostests/winetests/oleacc/main.c b/rostests/winetests/oleacc/main.c new file mode 100644 index 00000000000..db7ee9e5dfb --- /dev/null +++ b/rostests/winetests/oleacc/main.c @@ -0,0 +1,141 @@ +/* + * oleacc tests + * + * Copyright 2008 Nikolay Sivov + * + * 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 + */ + +#include +#include "wine/test.h" + +static void test_getroletext(void) +{ + INT ret, role; + CHAR buf[2], *buff; + WCHAR bufW[2], *buffW; + + /* wrong role number */ + ret = GetRoleTextA(-1, NULL, 0); + ok(ret == 0, "GetRoleTextA doesn't return zero on wrong role number, got %d\n", ret); + buf[0] = '*'; + ret = GetRoleTextA(-1, buf, 2); + ok(ret == 0, "GetRoleTextA doesn't return zero on wrong role number, got %d\n", ret); + ok(buf[0] == '*' || + broken(buf[0] == 0), /* Win98 and WinMe */ + "GetRoleTextA modified buffer on wrong role number\n"); + buf[0] = '*'; + ret = GetRoleTextA(-1, buf, 0); + ok(ret == 0, "GetRoleTextA doesn't return zero on wrong role number, got %d\n", ret); + ok(buf[0] == '*', "GetRoleTextA modified buffer on wrong role number\n"); + + ret = GetRoleTextW(-1, NULL, 0); + ok(ret == 0, "GetRoleTextW doesn't return zero on wrong role number, got %d\n", ret); + bufW[0] = '*'; + ret = GetRoleTextW(-1, bufW, 2); + ok(ret == 0, "GetRoleTextW doesn't return zero on wrong role number, got %d\n", ret); + ok(bufW[0] == '\0' || + broken(bufW[0] == '*'), /* Win98 and WinMe */ + "GetRoleTextW doesn't return NULL char on wrong role number\n"); + bufW[0] = '*'; + ret = GetRoleTextW(-1, bufW, 0); + ok(ret == 0, "GetRoleTextW doesn't return zero on wrong role number, got %d\n", ret); + + /* zero role number - not documented */ + ret = GetRoleTextA(0, NULL, 0); + ok(ret > 0, "GetRoleTextA doesn't return (>0) for zero role number, got %d\n", ret); + ret = GetRoleTextW(0, NULL, 0); + ok(ret > 0, "GetRoleTextW doesn't return (>0) for zero role number, got %d\n", ret); + + /* NULL buffer, return length */ + ret = GetRoleTextA(ROLE_SYSTEM_TITLEBAR, NULL, 0); + ok(ret > 0, "GetRoleTextA doesn't return length on NULL buffer, got %d\n", ret); + ret = GetRoleTextA(ROLE_SYSTEM_TITLEBAR, NULL, 1); + ok(ret > 0, "GetRoleTextA doesn't return length on NULL buffer, got %d\n", ret); + ret = GetRoleTextW(ROLE_SYSTEM_TITLEBAR, NULL, 0); + ok(ret > 0, "GetRoleTextW doesn't return length on NULL buffer, got %d\n", ret); + ret = GetRoleTextW(ROLE_SYSTEM_TITLEBAR, NULL, 1); + ok(ret > 0, "GetRoleTextW doesn't return length on NULL buffer, got %d\n", ret); + + /* use a smaller buffer */ + buf[0] = '*'; + ret = GetRoleTextA(ROLE_SYSTEM_TITLEBAR, buf, 1); + ok(ret == 0, "GetRoleTextA returned wrong length\n"); + ok(buf[0] == '\0', "GetRoleTextA returned not zero-length buffer\n"); + buf[1] = '*'; + ret = GetRoleTextA(ROLE_SYSTEM_TITLEBAR, buf, 2); + ok(ret == 1 || + ret == 0, /* Vista and W2K8 */ + "GetRoleTextA returned wrong length, got %d, expected 0 or 1\n", ret); + if (ret == 1) + ok(buf[1] == '\0', "GetRoleTextA returned not zero-length buffer : (%c)\n", buf[1]); + + bufW[0] = '*'; + ret = GetRoleTextW(ROLE_SYSTEM_TITLEBAR, bufW, 1); + ok(ret == 0, "GetRoleTextW returned wrong length, got %d, expected 1\n", ret); + ok(bufW[0] == '\0', "GetRoleTextW returned not zero-length buffer\n"); + bufW[1] = '*'; + ret = GetRoleTextW(ROLE_SYSTEM_TITLEBAR, bufW, 2); + ok(ret == 1, "GetRoleTextW returned wrong length, got %d, expected 1\n", ret); + ok(bufW[1] == '\0', "GetRoleTextW returned not zero-length buffer\n"); + + /* use bigger buffer */ + ret = GetRoleTextA(ROLE_SYSTEM_TITLEBAR, NULL, 0); + buff = HeapAlloc(GetProcessHeap(), 0, 2*ret); + buff[2*ret-1] = '*'; + ret = GetRoleTextA(ROLE_SYSTEM_TITLEBAR, buff, 2*ret); + ok(buff[2*ret-1] == '*', "GetRoleTextA shouldn't modify this part of buffer\n"); + HeapFree(GetProcessHeap(), 0, buff); + + ret = GetRoleTextW(ROLE_SYSTEM_TITLEBAR, NULL, 0); + buffW = HeapAlloc(GetProcessHeap(), 0, 2*ret*sizeof(WCHAR)); + buffW[2*ret-1] = '*'; + ret = GetRoleTextW(ROLE_SYSTEM_TITLEBAR, buffW, 2*ret); + ok(buffW[2*ret-1] == '*', "GetRoleTextW shouldn't modify this part of buffer\n"); + HeapFree(GetProcessHeap(), 0, buffW); + + /* check returned length for all roles */ + for(role = 0; role <= ROLE_SYSTEM_OUTLINEBUTTON; role++){ + CHAR buff2[100]; + WCHAR buff2W[100]; + + /* NT4 and W2K don't clear the buffer on a nonexistent role in the A-call */ + memset(buff2, 0, sizeof(buff2)); + + ret = GetRoleTextA(role, NULL, 0); + /* Win98 up to W2K miss some of the roles */ + if (role >= ROLE_SYSTEM_SPLITBUTTON) + ok(ret > 0 || broken(ret == 0), "Expected the role %d to be present\n", role); + else + ok(ret > 0, "Expected the role to be present\n"); + + GetRoleTextA(role, buff2, sizeof(buff2)); + ok(ret == lstrlenA(buff2), + "GetRoleTextA: returned length doesn't match returned buffer for role %d\n", role); + + /* Win98 and WinMe don't clear the buffer on a nonexistent role in the W-call */ + memset(buff2W, 0, sizeof(buff2W)); + + ret = GetRoleTextW(role, NULL, 0); + GetRoleTextW(role, buff2W, sizeof(buff2W)/sizeof(WCHAR)); + ok(ret == lstrlenW(buff2W), + "GetRoleTextW: returned length doesn't match returned buffer for role %d\n", role); + } +} + +START_TEST(main) +{ + test_getroletext(); +} diff --git a/rostests/winetests/oleacc/oleacc.rbuild b/rostests/winetests/oleacc/oleacc.rbuild new file mode 100644 index 00000000000..4a67b292704 --- /dev/null +++ b/rostests/winetests/oleacc/oleacc.rbuild @@ -0,0 +1,9 @@ + + . + + main.c + testlist.c + wine + oleacc + ntdll + diff --git a/rostests/winetests/oleacc/testlist.c b/rostests/winetests/oleacc/testlist.c new file mode 100644 index 00000000000..6f0c3974819 --- /dev/null +++ b/rostests/winetests/oleacc/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_main(void); + +const struct test winetest_testlist[] = +{ + { "main", func_main }, + { 0, 0 } +}; diff --git a/rostests/winetests/oleaut32/oleaut32.rbuild b/rostests/winetests/oleaut32/oleaut32.rbuild index f03c556d3c4..e24a24b8bf0 100644 --- a/rostests/winetests/oleaut32/oleaut32.rbuild +++ b/rostests/winetests/oleaut32/oleaut32.rbuild @@ -3,19 +3,19 @@ . - 0x600 - 0x600 + include/reactos/wine + . + wine oleaut32 ole32 - shlwapi rpcrt4 user32 gdi32 advapi32 - kernel32 uuid ntdll + tmarshal_interface olefont.c olepicture.c safearray.c @@ -27,5 +27,24 @@ vartype.c tmarshal.rc testlist.c + tmarshal_header + tmarshal + test_tlb + + + stdole2 + tmarshal.idl + + + stdole2 + tmarshal.idl + + + stdole2 + test_tlb.idl + + + stdole2 + tmarshal.idl diff --git a/rostests/winetests/oleaut32/olefont.c b/rostests/winetests/oleaut32/olefont.c index 1e6678b3499..adcb5cba94c 100644 --- a/rostests/winetests/oleaut32/olefont.c +++ b/rostests/winetests/oleaut32/olefont.c @@ -24,7 +24,6 @@ #include #include #include -#include #define COBJMACROS @@ -36,10 +35,13 @@ #include #include #include +#include #include #include #include +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + static WCHAR MSSansSerif_font[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0}; static WCHAR system_font[] = { 'S','y','s','t','e','m',0 }; static WCHAR arial_font[] = { 'A','r','i','a','l',0 }; @@ -135,13 +137,15 @@ static void test_QueryInterface(void) /* Test if QueryInterface increments ref counter for IFONTs */ ret = IFont_AddRef(font); - ok(ret == 3, "IFont_QI expected ref value 3 but instead got %12u\n",ret); + ok(ret == 3 || + broken(ret == 1), /* win95 */ + "IFont_QI expected ref value 3 but instead got %d\n",ret); IFont_Release(font); ok(hres == S_OK,"IFont_QI does not return S_OK, but 0x%08x\n", hres); ok(pvObj != NULL,"IFont_QI does return NULL, instead of a ptr\n"); - /* Orignial ref and QueryInterface ref both have to be released */ + /* Original ref and QueryInterface ref both have to be released */ IFont_Release(font); IFont_Release(font); } @@ -171,6 +175,7 @@ static void test_type_info(void) ok(hres == S_OK, "GetNames returned 0x%08x instead of S_OK.\n", hres); ok(n == 1, "GetNames returned %d names instead of 1.\n", n); ok(!lstrcmpiW(names[0],name_Name), "DISPID_FONT_NAME doesn't get 'Names'.\n"); + SysFreeString(names[0]); ITypeInfo_Release(pTInfo); @@ -768,8 +773,9 @@ static void test_AddRefHfont(void) /* Decrement reference for destroyed hfnt1 */ hres = IFont_ReleaseHfont(ifnt2,hfnt1); - ok(hres == S_OK, - "IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n", + ok(hres == S_OK || + hres == S_FALSE, /* <= win2k */ + "IFont_AddRefHfont: (Release ref) Expected S_OK or S_FALSE but got 0x%08x\n", hres); /* Shows that releasing all IFONT's does clear the HFONT cache. */ @@ -802,7 +808,7 @@ START_TEST(olefont) pOleCreateFontIndirect = (void*)GetProcAddress(hOleaut32, "OleCreateFontIndirect"); if (!pOleCreateFontIndirect) { - skip("OleCreateFontIndirect not available\n"); + win_skip("OleCreateFontIndirect not available\n"); return; } @@ -811,6 +817,8 @@ START_TEST(olefont) /* Test various size operations and conversions. */ /* Add more as needed. */ + if (0) /* FIXME: failing tests */ + { test_ifont_sizes(180000, 0, 72, 2540, -18, "default"); test_ifont_sizes(180000, 0, 144, 2540, -36, "ratio1"); /* change ratio */ test_ifont_sizes(180000, 0, 72, 1270, -36, "ratio2"); /* 2nd part of ratio */ @@ -818,6 +826,7 @@ START_TEST(olefont) /* These depend on details of how IFont rounds sizes internally. */ test_ifont_sizes(0, 0, 72, 2540, 0, "zero size"); /* zero size */ test_ifont_sizes(186000, 0, 72, 2540, -19, "rounding"); /* test rounding */ + } test_font_events_disp(); test_GetIDsOfNames(); diff --git a/rostests/winetests/oleaut32/olepicture.c b/rostests/winetests/oleaut32/olepicture.c index c0d0de9d969..2dc1b05cf92 100644 --- a/rostests/winetests/oleaut32/olepicture.c +++ b/rostests/winetests/oleaut32/olepicture.c @@ -23,9 +23,9 @@ #include #include #include -#include #define COBJMACROS +#define NONAMELESSUNION #include "wine/test.h" #include @@ -121,6 +121,53 @@ static const unsigned char apmdata[] = { 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00 }; +/* MF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */ +static const unsigned char metafile[] = { + 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a, + 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00, + 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + +/* EMF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */ +static const unsigned char enhmetafile[] = { + 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff, + 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00, + 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00, + 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41, + 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00 +}; + + struct NoStatStreamImpl { const IStreamVtbl *lpVtbl; @@ -277,6 +324,7 @@ static void test_empty_image(void) { ULARGE_INTEGER newpos1; LARGE_INTEGER seekto; short type; + DWORD attr; /* Empty image. Happens occasionally in VB programs. */ hglob = GlobalAlloc (0, 8); @@ -300,6 +348,11 @@ static void test_empty_image(void) { ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres); ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type); + attr = 0xdeadbeef; + hres = IPicture_get_Attributes (pic, &attr); + ok (hres == S_OK,"empty picture get attributes failed with hres 0x%08x\n", hres); + ok (attr == 0,"attr is %d, but should be 0\n", attr); + hres = IPicture_get_Handle (pic, &handle); ok (hres == S_OK,"empty picture get handle failed with hres 0x%08x\n", hres); ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle); @@ -424,7 +477,7 @@ static void test_OleCreatePictureIndirect(void) if(!pOleCreatePictureIndirect) { - skip("Skipping OleCreatePictureIndirect tests\n"); + win_skip("Skipping OleCreatePictureIndirect tests\n"); return; } @@ -442,7 +495,7 @@ static void test_OleCreatePictureIndirect(void) IPicture_Release(pict); } -static void test_apm() +static void test_apm(void) { OLE_HANDLE handle; LPSTREAM stream; @@ -480,6 +533,173 @@ static void test_apm() IStream_Release(stream); } +static void test_metafile(void) +{ + LPSTREAM stream; + IPicture *pict; + HGLOBAL hglob; + LPBYTE *data; + + hglob = GlobalAlloc (0, sizeof(metafile)); + data = GlobalLock(hglob); + memcpy(data, metafile, sizeof(metafile)); + + ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream)); + /* Windows does not load simple metafiles */ + ole_expect(OleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL); + + IStream_Release(stream); +} + +static void test_enhmetafile(void) +{ + OLE_HANDLE handle; + LPSTREAM stream; + IPicture *pict; + HGLOBAL hglob; + LPBYTE *data; + LONG cxy; + BOOL keep; + short type; + + hglob = GlobalAlloc (0, sizeof(enhmetafile)); + data = GlobalLock(hglob); + memcpy(data, enhmetafile, sizeof(enhmetafile)); + + ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream)); + ole_check(OleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict)); + + ole_check(IPicture_get_Handle(pict, &handle)); + ok(handle != 0, "handle is null\n"); + + ole_check(IPicture_get_Type(pict, &type)); + expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d"); + + ole_check(IPicture_get_Height(pict, &cxy)); + expect_eq(cxy, -23, LONG, "%d"); + + ole_check(IPicture_get_Width(pict, &cxy)); + expect_eq(cxy, -25, LONG, "%d"); + + ole_check(IPicture_get_KeepOriginalFormat(pict, &keep)); + todo_wine expect_eq(keep, FALSE, LONG, "%d"); + + IPicture_Release(pict); + IStream_Release(stream); +} + +static void test_Render(void) +{ + IPicture *pic; + HRESULT hres; + short type; + PICTDESC desc; + HDC hdc = GetDC(0); + + /* test IPicture::Render return code on uninitialized picture */ + OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic); + hres = IPicture_get_Type(pic, &type); + ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres); + ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type); + /* zero dimensions */ + hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + /* nonzero dimensions, PICTYPE_UNINITIALIZED */ + hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL); + ole_expect(hres, S_OK); + IPicture_Release(pic); + + desc.cbSizeofstruct = sizeof(PICTDESC); + desc.picType = PICTYPE_ICON; + desc.u.icon.hicon = LoadIcon(NULL, IDI_APPLICATION); + if(!desc.u.icon.hicon){ + win_skip("LoadIcon failed. Skipping...\n"); + ReleaseDC(NULL, hdc); + return; + } + + OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (VOID**)&pic); + /* zero dimensions, PICTYPE_ICON */ + hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL); + ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); + IPicture_Release(pic); + + ReleaseDC(NULL, hdc); +} + +static void test_get_Attributes(void) +{ + IPicture *pic; + HRESULT hres; + short type; + DWORD attr; + + OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic); + hres = IPicture_get_Type(pic, &type); + ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres); + ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type); + + hres = IPicture_get_Attributes(pic, NULL); + ole_expect(hres, E_POINTER); + + attr = 0xdeadbeef; + hres = IPicture_get_Attributes(pic, &attr); + ole_expect(hres, S_OK); + ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr); + + IPicture_Release(pic); +} + +static void test_get_Handle(void) +{ + IPicture *pic; + HRESULT hres; + + OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic); + + hres = IPicture_get_Handle(pic, NULL); + ole_expect(hres, E_POINTER); + + IPicture_Release(pic); +} + +static void test_get_Type(void) +{ + IPicture *pic; + HRESULT hres; + + OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic); + + hres = IPicture_get_Type(pic, NULL); + ole_expect(hres, E_POINTER); + + IPicture_Release(pic); +} + START_TEST(olepicture) { hOleaut32 = GetModuleHandleA("oleaut32.dll"); @@ -487,7 +707,7 @@ START_TEST(olepicture) pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect"); if (!pOleLoadPicture) { - skip("OleLoadPicture is not available\n"); + win_skip("OleLoadPicture is not available\n"); return; } @@ -501,9 +721,15 @@ START_TEST(olepicture) test_empty_image(); test_empty_image_2(); test_apm(); + test_metafile(); + test_enhmetafile(); test_Invoke(); test_OleCreatePictureIndirect(); + test_Render(); + test_get_Attributes(); + test_get_Handle(); + test_get_Type(); } @@ -534,11 +760,11 @@ static HRESULT WINAPI NoStatStreamImpl_QueryInterface( *ppvObject = 0; if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) { - *ppvObject = (IStream*)This; + *ppvObject = This; } else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0) { - *ppvObject = (IStream*)This; + *ppvObject = This; } if ((*ppvObject)==0) diff --git a/rostests/winetests/oleaut32/safearray.c b/rostests/winetests/oleaut32/safearray.c index 1857ab5a5ca..f7bd66f3942 100644 --- a/rostests/winetests/oleaut32/safearray.c +++ b/rostests/winetests/oleaut32/safearray.c @@ -23,7 +23,6 @@ #include #include #include -#include #define COBJMACROS #include "wine/test.h" @@ -147,7 +146,7 @@ static const IRecordInfoVtbl IRecordInfoImpl_VTable = (PVOID)IRecordInfoImpl_Dummy, (PVOID)IRecordInfoImpl_Dummy, (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_GetSize, + IRecordInfoImpl_GetSize, (PVOID)IRecordInfoImpl_Dummy, (PVOID)IRecordInfoImpl_Dummy, (PVOID)IRecordInfoImpl_Dummy, @@ -276,7 +275,7 @@ static struct { static void test_safearray(void) { SAFEARRAY *a, b, *c; - unsigned int i; + unsigned int i, diff; LONG indices[2]; HRESULT hres; SAFEARRAYBOUND bound, bounds[2]; @@ -355,15 +354,24 @@ static void test_safearray(void) SafeArrayPtrOfIndex(a, indices, (void **)&ptr1); ok(*(WORD *)ptr1 == 0x55aa, "Data not preserved when resizing array\n"); + hres = SafeArrayDestroy(a); + ok(hres == S_OK,"SAD faild with hres %x\n", hres); + bounds[0].cElements = 0; bounds[0].lLbound = 1; bounds[1].cElements = 2; bounds[1].lLbound = 23; a = SafeArrayCreate(VT_I4,2,bounds); ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n"); + + hres = SafeArrayDestroy(a); + ok(hres == S_OK,"SAD faild with hres %x\n", hres); bounds[0].cElements = 1; bounds[0].lLbound = 1; bounds[1].cElements = 0; bounds[1].lLbound = 23; a = SafeArrayCreate(VT_I4,2,bounds); ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n"); + hres = SafeArrayDestroy(a); + ok(hres == S_OK,"SAD faild with hres %x\n", hres); + bounds[0].cElements = 42; bounds[0].lLbound = 1; bounds[1].cElements = 2; bounds[1].lLbound = 23; a = SafeArrayCreate(VT_I4,2,bounds); @@ -426,23 +434,29 @@ static void test_safearray(void) indices[1] = 23; hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2); ok(S_OK == hres,"SAPOI failed [1,23], hres 0x%x\n",hres); - ok(ptr2 - ptr1 == 8,"ptr difference is not 8, but %d (%p vs %p)\n", ptr2-ptr1, ptr2, ptr1); + diff = ptr2 - ptr1; + ok(diff == 8,"ptr difference is not 8, but %d (%p vs %p)\n", diff, ptr2, ptr1); indices[0] = 3; indices[1] = 24; hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2); ok(S_OK == hres,"SAPOI failed [5,24], hres 0x%x\n",hres); - ok(ptr2 - ptr1 == 176,"ptr difference is not 176, but %d (%p vs %p)\n", ptr2-ptr1, ptr2, ptr1); + diff = ptr2 - ptr1; + ok(diff == 176,"ptr difference is not 176, but %d (%p vs %p)\n", diff, ptr2, ptr1); indices[0] = 20; indices[1] = 23; hres = SafeArrayPtrOfIndex(a, indices, (void**)&ptr2); ok(S_OK == hres,"SAPOI failed [20,23], hres 0x%x\n",hres); - ok(ptr2 - ptr1 == 76,"ptr difference is not 76, but %d (%p vs %p)\n", ptr2-ptr1, ptr2, ptr1); + diff = ptr2 - ptr1; + ok(diff == 76,"ptr difference is not 76, but %d (%p vs %p)\n", diff, ptr2, ptr1); hres = SafeArrayUnaccessData(a); ok(S_OK == hres, "SAUAD failed with 0x%x\n", hres); + hres = SafeArrayDestroy(a); + ok(hres == S_OK,"SAD faild with hres %x\n", hres); + for (i=0;i VT_BSTR failed with %x\n",hres); ok(V_VT(&v) == VT_BSTR,"CTE VT_ARRAY|VT_UI1 -> VT_BSTR did not return VT_BSTR, but %d.v\n",V_VT(&v)); ok(V_BSTR(&v)[0] == 0x6548,"First letter are not 'He', but %x\n", V_BSTR(&v)[0]); + VariantClear(&v); /* check locking functions */ a = SafeArrayCreate(VT_I4, 1, &bound); @@ -560,7 +570,6 @@ static void test_safearray(void) hres = SafeArrayDestroyDescriptor(a); ok(hres == S_OK,"SADD with data in array failed with hres %x\n",hres); - /* IID functions */ /* init a small stack safearray */ if (pSafeArraySetIID) { @@ -574,6 +583,9 @@ static void test_safearray(void) ok((a->fFeatures & FADF_HAVEIID) == 0,"newly allocated descriptor with SAAD should not have FADF_HAVEIID\n"); hres = pSafeArraySetIID(a,&iid); ok(hres == E_INVALIDARG,"SafeArraySetIID of newly allocated descriptor with SAAD should return E_INVALIDARG, but %x\n",hres); + + hres = SafeArrayDestroyDescriptor(a); + ok(hres == S_OK,"SADD failed with hres %x\n",hres); } if (!pSafeArrayAllocDescriptorEx) @@ -692,6 +704,9 @@ static void test_SafeArrayAllocDestroyDescriptor(void) hres = SafeArrayAllocData(sa); ok(hres == S_OK, "SafeArrayAllocData gave hres 0x%x\n", hres); + + hres = SafeArrayDestroy(sa); + ok(hres == S_OK,"SafeArrayDestroy failed with hres %x\n",hres); } static void test_SafeArrayCreateLockDestroy(void) @@ -808,7 +823,7 @@ static void test_SafeArrayCreateLockDestroy(void) ok(hres == S_OK, "Unlock VARTYPE %d (@%d dims) hres 0x%x\n", vt, dimension, hres); - hres = SafeArrayDestroyDescriptor(sa); + hres = SafeArrayDestroy(sa); ok(hres == S_OK, "destroy VARTYPE %d (@%d dims) hres 0x%x\n", vt, dimension, hres); } @@ -829,6 +844,9 @@ static void test_VectorCreateLockDestroy(void) sa = pSafeArrayCreateVector(VT_UI1, 0, 0); ok(sa != NULL, "SACV with 0 elements failed.\n"); + hres = SafeArrayDestroy(sa); + ok(hres == S_OK, "SafeArrayDestroy failed with hres %x\n",hres); + /* Test all VARTYPES in different lengths */ for (element = 1; element <= 101; element += 10) { @@ -861,7 +879,7 @@ static void test_VectorCreateLockDestroy(void) ok(hres == S_OK, "Unlock VARTYPE %d (@%d elements) failed; hres 0x%x\n", vt, element, hres); - hres = SafeArrayDestroyDescriptor(sa); + hres = SafeArrayDestroy(sa); ok(hres == S_OK, "destroy VARTYPE %d (@%d elements) failed; hres 0x%x\n", vt, element, hres); } @@ -1085,6 +1103,8 @@ static void test_SafeArrayGetPutElement_BSTR(void) if (hres == S_OK) ok(SysStringLen(value) == SysStringLen(gotvalue), "Got len %d instead of %d\n", SysStringLen(gotvalue), SysStringLen(value)); SafeArrayDestroy(sa); + SysFreeString(value); + SysFreeString(gotvalue); } static int tunk_xref = 0; @@ -1254,7 +1274,7 @@ static void test_SafeArrayCopyData(void) /* Fill the source array with some data; it doesn't matter what */ for (dimension = 0; dimension < size; dimension++) { - int* data = (int*)sa->pvData; + int* data = sa->pvData; data[dimension] = dimension; } @@ -1400,7 +1420,7 @@ static void test_SafeArrayCreateEx(void) /* Win32 doesn't care if GetSize fails */ fail_GetSize = TRUE; - sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, (LPVOID)iRec); + sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, iRec); ok(sa != NULL, "CreateEx (Fail Size) failed\n"); ok(iRec->ref == START_REF_COUNT + 1, "Wrong iRec refcount %d\n", iRec->ref); ok(iRec->sizeCalled == 1, "GetSize called %d times\n", iRec->sizeCalled); @@ -1417,7 +1437,7 @@ static void test_SafeArrayCreateEx(void) iRec->ref = START_REF_COUNT; iRec->sizeCalled = 0; iRec->clearCalled = 0; - sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, (LPVOID)iRec); + sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, iRec); ok(sa != NULL, "CreateEx (Rec) failed\n"); ok(iRec->ref == START_REF_COUNT + 1, "Wrong iRec refcount %d\n", iRec->ref); ok(iRec->sizeCalled == 1, "GetSize called %d times\n", iRec->sizeCalled); @@ -1603,6 +1623,7 @@ static void test_SafeArrayChangeTypeEx(void) hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_BSTR); ok(hres != S_OK, "CTE VT_ARRAY|VT %d->BSTR succeeded\n", vt); VariantClear(&v2); + VariantClear(&v); } /* Can't change an array of one type into array of another type , even @@ -1630,6 +1651,7 @@ static void test_SafeArrayChangeTypeEx(void) V_ARRAY(&v) = sa; hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_ARRAY|VT_UI1); ok(hres == S_OK, "CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_UI1 returned %x\n", hres); + SafeArrayDestroy(sa); } /* NULL/EMPTY */ diff --git a/rostests/winetests/oleaut32/tmarshal.c b/rostests/winetests/oleaut32/tmarshal.c index c96fb33d618..044350f1fe8 100644 --- a/rostests/winetests/oleaut32/tmarshal.c +++ b/rostests/winetests/oleaut32/tmarshal.c @@ -18,93 +18,31 @@ */ #define COBJMACROS +#define CONST_VTABLE #include #include #include -#include +#include "wine/test.h" #include "tmarshal.h" #include "tmarshal_dispids.h" #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", (unsigned long int)hr) -/* Debugging functions from wine/libs/wine/debug.c */ +/* ULL suffix is not portable */ +#define ULL_CONST(dw1, dw2) ((((ULONGLONG)dw1) << 32) | (ULONGLONG)dw2) -/* allocate some tmp string space */ -/* FIXME: this is not 100% thread-safe */ -static char *get_tmp_space( int size ) -{ - static char *list[32]; - static long pos; - char *ret; - int idx; - - idx = ++pos % (sizeof(list)/sizeof(list[0])); - if ((ret = realloc( list[idx], size ))) list[idx] = ret; - return ret; -} - -/* default implementation of wine_dbgstr_wn */ -static const char *default_dbgstr_wn( const WCHAR *str, int n ) -{ - char *dst, *res; - - if (!HIWORD(str)) - { - if (!str) return "(null)"; - res = get_tmp_space( 6 ); - sprintf( res, "#%04x", LOWORD(str) ); - return res; - } - if (n == -1) n = lstrlenW(str); - if (n < 0) n = 0; - else if (n > 200) n = 200; - dst = res = get_tmp_space( n * 5 + 7 ); - *dst++ = 'L'; - *dst++ = '"'; - while (n-- > 0) - { - WCHAR c = *str++; - switch (c) - { - case '\n': *dst++ = '\\'; *dst++ = 'n'; break; - case '\r': *dst++ = '\\'; *dst++ = 'r'; break; - case '\t': *dst++ = '\\'; *dst++ = 't'; break; - case '"': *dst++ = '\\'; *dst++ = '"'; break; - case '\\': *dst++ = '\\'; *dst++ = '\\'; break; - default: - if (c >= ' ' && c <= 126) - *dst++ = (char)c; - else - { - *dst++ = '\\'; - sprintf(dst,"%04x",c); - dst+=4; - } - } - } - *dst++ = '"'; - if (*str) - { - *dst++ = '.'; - *dst++ = '.'; - *dst++ = '.'; - } - *dst = 0; - return res; -} - -const char *wine_dbgstr_wn( const WCHAR *s, int n ) -{ - return default_dbgstr_wn(s, n); -} - -const char *wine_dbgstr_w( const WCHAR *s ) -{ - return default_dbgstr_wn( s, -1 ); -} +const MYSTRUCT MYSTRUCT_BYVAL = {0x12345678, ULL_CONST(0xdeadbeef, 0x98765432)}; +const MYSTRUCT MYSTRUCT_BYPTR = {0x91827364, ULL_CONST(0x88776655, 0x44332211)}; +const MYSTRUCT MYSTRUCT_ARRAY[5] = { + {0x1a1b1c1d, ULL_CONST(0x1e1f1011, 0x12131415)}, + {0x2a2b2c2d, ULL_CONST(0x2e2f2021, 0x22232425)}, + {0x3a3b3c3d, ULL_CONST(0x3e3f3031, 0x32333435)}, + {0x4a4b4c4d, ULL_CONST(0x4e4f4041, 0x42434445)}, + {0x5a5b5c5d, ULL_CONST(0x5e5f5051, 0x52535455)}, +}; #define RELEASEMARSHALDATA WM_USER @@ -121,7 +59,7 @@ struct host_object_data static DWORD CALLBACK host_object_proc(LPVOID p) { - struct host_object_data *data = (struct host_object_data *)p; + struct host_object_data *data = p; HRESULT hr; MSG msg; @@ -210,6 +148,72 @@ static void end_host_object(DWORD tid, HANDLE thread) CloseHandle(thread); } +static ItestDual TestDual, TestDualDisp; + +static HRESULT WINAPI TestDual_QueryInterface(ItestDual *iface, REFIID riid, void **ppvObject) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch)) { + *ppvObject = &TestDualDisp; + return S_OK; + }else if(IsEqualGUID(riid, &IID_ItestDual)) { + *ppvObject = &TestDual; + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI TestDual_AddRef(ItestDual *iface) +{ + return 2; +} + +static ULONG WINAPI TestDual_Release(ItestDual *iface) +{ + return 1; +} + +static HRESULT WINAPI TestDual_GetTypeInfoCount(ItestDual *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI TestDual_GetTypeInfo(ItestDual *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI TestDual_GetIDsOfNames(ItestDual *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI TestDual_Invoke(ItestDual *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, + UINT *puArgErr) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static ItestDualVtbl TestDualVtbl = { + TestDual_QueryInterface, + TestDual_AddRef, + TestDual_Release, + TestDual_GetTypeInfoCount, + TestDual_GetTypeInfo, + TestDual_GetIDsOfNames, + TestDual_Invoke +}; + +static ItestDual TestDual = { &TestDualVtbl }; +static ItestDual TestDualDisp = { &TestDualVtbl }; + typedef struct Widget { const IWidgetVtbl *lpVtbl; @@ -217,7 +221,7 @@ typedef struct Widget IUnknown *pDispatchUnknown; } Widget; -HRESULT WINAPI Widget_QueryInterface( +static HRESULT WINAPI Widget_QueryInterface( IWidget *iface, /* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) @@ -235,7 +239,7 @@ HRESULT WINAPI Widget_QueryInterface( } } -ULONG WINAPI Widget_AddRef( +static ULONG WINAPI Widget_AddRef( IWidget *iface) { Widget *This = (Widget *)iface; @@ -243,7 +247,7 @@ ULONG WINAPI Widget_AddRef( return InterlockedIncrement(&This->refs); } -ULONG WINAPI Widget_Release( +static ULONG WINAPI Widget_Release( IWidget *iface) { Widget *This = (Widget *)iface; @@ -259,7 +263,7 @@ ULONG WINAPI Widget_Release( return refs; } -HRESULT WINAPI Widget_GetTypeInfoCount( +static HRESULT WINAPI Widget_GetTypeInfoCount( IWidget *iface, /* [out] */ UINT __RPC_FAR *pctinfo) { @@ -274,7 +278,7 @@ HRESULT WINAPI Widget_GetTypeInfoCount( return hr; } -HRESULT WINAPI Widget_GetTypeInfo( +static HRESULT WINAPI Widget_GetTypeInfo( IWidget __RPC_FAR * iface, /* [in] */ UINT iTInfo, /* [in] */ LCID lcid, @@ -291,7 +295,7 @@ HRESULT WINAPI Widget_GetTypeInfo( return hr; } -HRESULT WINAPI Widget_GetIDsOfNames( +static HRESULT WINAPI Widget_GetIDsOfNames( IWidget __RPC_FAR * iface, /* [in] */ REFIID riid, /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, @@ -310,7 +314,7 @@ HRESULT WINAPI Widget_GetIDsOfNames( return hr; } -HRESULT WINAPI Widget_Invoke( +static HRESULT WINAPI Widget_Invoke( IWidget __RPC_FAR * iface, /* [in] */ DISPID dispIdMember, /* [in] */ REFIID riid, @@ -332,7 +336,7 @@ HRESULT WINAPI Widget_Invoke( return hr; } -HRESULT WINAPI Widget_put_Name( +static HRESULT WINAPI Widget_put_Name( IWidget __RPC_FAR * iface, /* [in] */ BSTR name) { @@ -340,7 +344,7 @@ HRESULT WINAPI Widget_put_Name( return S_OK; } -HRESULT WINAPI Widget_get_Name( +static HRESULT WINAPI Widget_get_Name( IWidget __RPC_FAR * iface, /* [out] */ BSTR __RPC_FAR *name) { @@ -350,7 +354,7 @@ HRESULT WINAPI Widget_get_Name( return S_OK; } -HRESULT WINAPI Widget_DoSomething( +static HRESULT WINAPI Widget_DoSomething( IWidget __RPC_FAR * iface, /* [in] */ double number, /* [out] */ BSTR *str1, @@ -369,7 +373,7 @@ HRESULT WINAPI Widget_DoSomething( return S_FALSE; } -HRESULT WINAPI Widget_get_State( +static HRESULT WINAPI Widget_get_State( IWidget __RPC_FAR * iface, /* [retval][out] */ STATE __RPC_FAR *state) { @@ -378,7 +382,7 @@ HRESULT WINAPI Widget_get_State( return S_OK; } -HRESULT WINAPI Widget_put_State( +static HRESULT WINAPI Widget_put_State( IWidget __RPC_FAR * iface, /* [in] */ STATE state) { @@ -386,7 +390,7 @@ HRESULT WINAPI Widget_put_State( return S_OK; } -HRESULT WINAPI Widget_Map( +static HRESULT WINAPI Widget_Map( IWidget * iface, BSTR bstrId, BSTR *sValue) @@ -396,7 +400,7 @@ HRESULT WINAPI Widget_Map( return S_OK; } -HRESULT WINAPI Widget_SetOleColor( +static HRESULT WINAPI Widget_SetOleColor( IWidget * iface, OLE_COLOR val) { @@ -404,7 +408,7 @@ HRESULT WINAPI Widget_SetOleColor( return S_OK; } -HRESULT WINAPI Widget_GetOleColor( +static HRESULT WINAPI Widget_GetOleColor( IWidget * iface, OLE_COLOR *pVal) { @@ -413,7 +417,7 @@ HRESULT WINAPI Widget_GetOleColor( return S_FALSE; } -HRESULT WINAPI Widget_Clone( +static HRESULT WINAPI Widget_Clone( IWidget *iface, IWidget **ppVal) { @@ -421,7 +425,7 @@ HRESULT WINAPI Widget_Clone( return Widget_QueryInterface(iface, &IID_IWidget, (void **)ppVal); } -HRESULT WINAPI Widget_CloneDispatch( +static HRESULT WINAPI Widget_CloneDispatch( IWidget *iface, IDispatch **ppVal) { @@ -429,7 +433,7 @@ HRESULT WINAPI Widget_CloneDispatch( return Widget_QueryInterface(iface, &IID_IWidget, (void **)ppVal); } -HRESULT WINAPI Widget_CloneCoclass( +static HRESULT WINAPI Widget_CloneCoclass( IWidget *iface, ApplicationObject2 **ppVal) { @@ -437,7 +441,7 @@ HRESULT WINAPI Widget_CloneCoclass( return S_OK; } -HRESULT WINAPI Widget_Value( +static HRESULT WINAPI Widget_Value( IWidget __RPC_FAR * iface, VARIANT *value, VARIANT *retval) @@ -450,7 +454,7 @@ HRESULT WINAPI Widget_Value( return S_OK; } -HRESULT WINAPI Widget_Array( +static HRESULT WINAPI Widget_Array( IWidget * iface, SAFEARRAY * values) { @@ -458,7 +462,7 @@ HRESULT WINAPI Widget_Array( return S_OK; } -HRESULT WINAPI Widget_VariantArrayPtr( +static HRESULT WINAPI Widget_VariantArrayPtr( IWidget * iface, SAFEARRAY ** values) { @@ -466,7 +470,7 @@ HRESULT WINAPI Widget_VariantArrayPtr( return S_OK; } -void WINAPI Widget_Variant( +static HRESULT WINAPI Widget_Variant( IWidget __RPC_FAR * iface, VARIANT var) { @@ -474,9 +478,10 @@ void WINAPI Widget_Variant( ok(V_VT(&var) == VT_CY, "V_VT(&var) was %d\n", V_VT(&var)); ok(S(V_CY(&var)).Hi == 0xdababe, "V_CY(&var).Hi was 0x%x\n", S(V_CY(&var)).Hi); ok(S(V_CY(&var)).Lo == 0xdeadbeef, "V_CY(&var).Lo was 0x%x\n", S(V_CY(&var)).Lo); + return S_OK; } -void WINAPI Widget_VarArg( +static HRESULT WINAPI Widget_VarArg( IWidget * iface, int numexpect, SAFEARRAY * values) @@ -506,16 +511,31 @@ void WINAPI Widget_VarArg( hr = SafeArrayUnaccessData(values); ok(hr == S_OK, "SafeArrayUnaccessData failed with %x\n", hr); + + return S_OK; } -HRESULT WINAPI Widget_Error( +static HRESULT WINAPI Widget_StructArgs( + IWidget * iface, + MYSTRUCT byval, + MYSTRUCT *byptr, + MYSTRUCT arr[5]) +{ + ok(memcmp(&byval, &MYSTRUCT_BYVAL, sizeof(MYSTRUCT))==0, "Struct parameter passed by value corrupted\n"); + ok(memcmp(byptr, &MYSTRUCT_BYPTR, sizeof(MYSTRUCT))==0, "Struct parameter passed by pointer corrupted\n"); + ok(memcmp(arr, MYSTRUCT_ARRAY, sizeof(MYSTRUCT_ARRAY))==0, "Array of structs corrupted\n"); + return S_OK; +} + + +static HRESULT WINAPI Widget_Error( IWidget __RPC_FAR * iface) { trace("Error()\n"); return E_NOTIMPL; } -HRESULT WINAPI Widget_CloneInterface( +static HRESULT WINAPI Widget_CloneInterface( IWidget __RPC_FAR * iface, ISomethingFromDispatch **ppVal) { @@ -524,6 +544,40 @@ HRESULT WINAPI Widget_CloneInterface( return S_OK; } +static HRESULT WINAPI Widget_put_prop_with_lcid( + IWidget* iface, LONG lcid, INT i) +{ + trace("put_prop_with_lcid(%08x, %x)\n", lcid, i); + ok(lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), "got lcid %08x\n", lcid); + ok(i == 0xcafe, "got %08x\n", i); + return S_OK; +} + +static HRESULT WINAPI Widget_get_prop_with_lcid( + IWidget* iface, LONG lcid, INT *i) +{ + trace("get_prop_with_lcid(%08x, %p)\n", lcid, i); + ok(lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), "got lcid %08x\n", lcid); + *i = lcid; + return S_OK; +} + +static HRESULT WINAPI Widget_get_prop_int( + IWidget* iface, INT *i) +{ + trace("get_prop_int(%p)\n", i); + *i = -13; + return S_OK; +} + +static HRESULT WINAPI Widget_get_prop_uint( + IWidget* iface, UINT *i) +{ + trace("get_prop_uint(%p)\n", i); + *i = 42; + return S_OK; +} + static const struct IWidgetVtbl Widget_VTable = { Widget_QueryInterface, @@ -549,10 +603,86 @@ static const struct IWidgetVtbl Widget_VTable = Widget_VariantArrayPtr, Widget_Variant, Widget_VarArg, + Widget_StructArgs, Widget_Error, - Widget_CloneInterface + Widget_CloneInterface, + Widget_put_prop_with_lcid, + Widget_get_prop_with_lcid, + Widget_get_prop_int, + Widget_get_prop_uint }; +static HRESULT WINAPI StaticWidget_QueryInterface(IStaticWidget *iface, REFIID riid, void **ppvObject) +{ + if (IsEqualIID(riid, &IID_IStaticWidget) || IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch)) + { + IStaticWidget_AddRef(iface); + *ppvObject = iface; + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI StaticWidget_AddRef(IStaticWidget *iface) +{ + return 2; +} + +static ULONG WINAPI StaticWidget_Release(IStaticWidget *iface) +{ + return 1; +} + +static HRESULT WINAPI StaticWidget_GetTypeInfoCount(IStaticWidget *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI StaticWidget_GetTypeInfo(IStaticWidget *iface, UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI StaticWidget_GetIDsOfNames(IStaticWidget *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI StaticWidget_Invoke(IStaticWidget *iface, DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, + UINT *puArgErr) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI StaticWidget_TestDual(IStaticWidget *iface, ItestDual *p) +{ + trace("TestDual()\n"); + todo_wine + ok(p == &TestDual, "wrong ItestDual\n"); + return S_OK; +} + +static const IStaticWidgetVtbl StaticWidgetVtbl = { + StaticWidget_QueryInterface, + StaticWidget_AddRef, + StaticWidget_Release, + StaticWidget_GetTypeInfoCount, + StaticWidget_GetTypeInfo, + StaticWidget_GetIDsOfNames, + StaticWidget_Invoke, + StaticWidget_TestDual +}; + +static IStaticWidget StaticWidget = { &StaticWidgetVtbl }; typedef struct KindaEnum { @@ -563,10 +693,12 @@ typedef struct KindaEnum static HRESULT register_current_module_typelib(void) { WCHAR path[MAX_PATH]; + CHAR pathA[MAX_PATH]; HRESULT hr; ITypeLib *typelib; - GetModuleFileNameW(NULL, path, MAX_PATH); + GetModuleFileNameA(NULL, pathA, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH); hr = LoadTypeLib(path, &typelib); if (SUCCEEDED(hr)) @@ -577,30 +709,44 @@ static HRESULT register_current_module_typelib(void) return hr; } -static IWidget *Widget_Create(void) +static ITypeInfo *get_type_info(REFIID riid) { - Widget *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - HRESULT hr; + ITypeInfo *pTypeInfo; ITypeLib *pTypeLib; - - This->lpVtbl = &Widget_VTable; - This->refs = 1; + HRESULT hr; hr = LoadRegTypeLib(&LIBID_TestTypelib, 1, 0, LOCALE_NEUTRAL, &pTypeLib); ok_ole_success(hr, LoadRegTypeLib); - if (SUCCEEDED(hr)) + if (FAILED(hr)) + return NULL; + + hr = ITypeLib_GetTypeInfoOfGuid(pTypeLib, riid, &pTypeInfo); + ITypeLib_Release(pTypeLib); + ok_ole_success(hr, ITypeLib_GetTypeInfoOfGuid); + if (FAILED(hr)) + return NULL; + + return pTypeInfo; +} + +static IWidget *Widget_Create(void) { + Widget *This; ITypeInfo *pTypeInfo; - hr = ITypeLib_GetTypeInfoOfGuid(pTypeLib, &IID_IWidget, &pTypeInfo); - ok_ole_success(hr, ITypeLib_GetTypeInfoOfGuid); - if (SUCCEEDED(hr)) - { + HRESULT hr = E_FAIL; + + pTypeInfo = get_type_info(&IID_IWidget); + if(!pTypeInfo) + return NULL; + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + This->lpVtbl = &Widget_VTable; + This->refs = 1; This->pDispatchUnknown = NULL; + hr = CreateStdDispatch((IUnknown *)&This->lpVtbl, This, pTypeInfo, &This->pDispatchUnknown); ok_ole_success(hr, CreateStdDispatch); ITypeInfo_Release(pTypeInfo); - } - } if (SUCCEEDED(hr)) return (IWidget *)&This->lpVtbl; @@ -611,7 +757,7 @@ static IWidget *Widget_Create(void) } } -HRESULT WINAPI KindaEnum_QueryInterface( +static HRESULT WINAPI KindaEnum_QueryInterface( IKindaEnumWidget *iface, /* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) @@ -629,7 +775,7 @@ HRESULT WINAPI KindaEnum_QueryInterface( } } -ULONG WINAPI KindaEnum_AddRef( +static ULONG WINAPI KindaEnum_AddRef( IKindaEnumWidget *iface) { KindaEnum *This = (KindaEnum *)iface; @@ -637,7 +783,7 @@ ULONG WINAPI KindaEnum_AddRef( return InterlockedIncrement(&This->refs); } -ULONG WINAPI KindaEnum_Release( +static ULONG WINAPI KindaEnum_Release( IKindaEnumWidget *iface) { KindaEnum *This = (KindaEnum *)iface; @@ -652,7 +798,7 @@ ULONG WINAPI KindaEnum_Release( return refs; } -HRESULT WINAPI KindaEnum_Next( +static HRESULT WINAPI KindaEnum_Next( IKindaEnumWidget *iface, /* [out] */ IWidget __RPC_FAR *__RPC_FAR *widget) { @@ -663,20 +809,20 @@ HRESULT WINAPI KindaEnum_Next( return E_OUTOFMEMORY; } -HRESULT WINAPI KindaEnum_Count( +static HRESULT WINAPI KindaEnum_Count( IKindaEnumWidget *iface, - /* [out] */ unsigned long __RPC_FAR *count) + /* [out] */ ULONG __RPC_FAR *count) { return E_NOTIMPL; } -HRESULT WINAPI KindaEnum_Reset( +static HRESULT WINAPI KindaEnum_Reset( IKindaEnumWidget *iface) { return E_NOTIMPL; } -HRESULT WINAPI KindaEnum_Clone( +static HRESULT WINAPI KindaEnum_Clone( IKindaEnumWidget *iface, /* [out] */ IKindaEnumWidget __RPC_FAR *__RPC_FAR *ppenum) { @@ -778,12 +924,15 @@ static void test_typelibmarshal(void) DWORD tid; BSTR bstr; ITypeInfo *pTypeInfo; + MYSTRUCT mystruct; + MYSTRUCT mystructArray[5]; ok(pKEW != NULL, "Widget creation failed\n"); hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); ok_ole_success(hr, CreateStreamOnHGlobal); tid = start_host_object(pStream, &IID_IKindaEnumWidget, (IUnknown *)pKEW, MSHLFLAGS_NORMAL, &thread); + IKindaEnumWidget_Release(pKEW); IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); hr = CoUnmarshalInterface(pStream, &IID_IKindaEnumWidget, (void **)&pKEW); @@ -916,6 +1065,14 @@ static void test_typelibmarshal(void) ok_ole_success(hr, IDispatch_Invoke); VariantClear(&varresult); + /* call StructArgs (direct) */ + mystruct = MYSTRUCT_BYPTR; + memcpy(mystructArray, MYSTRUCT_ARRAY, sizeof(mystructArray)); + hr = IWidget_StructArgs(pWidget, MYSTRUCT_BYVAL, &mystruct, mystructArray); + todo_wine { + ok_ole_success(hr, IWidget_StructArgs); + } + /* call Clone */ dispparams.cNamedArgs = 0; dispparams.cArgs = 0; @@ -1129,6 +1286,59 @@ static void test_typelibmarshal(void) hr = IDispatch_Invoke(pDispatch, DISPID_TM_STATE, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL); ok(hr == DISP_E_NOTACOLLECTION, "IDispatch_Invoke should have returned DISP_E_NOTACOLLECTION instead of 0x%08x\n", hr); + /* test propput with lcid */ + + /* the lcid passed to the function is the first lcid in the typelib header. + Since we don't explicitly set an lcid in the idl, it'll default to US English. */ + VariantInit(&vararg[0]); + V_VT(&vararg[0]) = VT_I4; + V_I4(&vararg[0]) = 0xcafe; + dispparams.cNamedArgs = 1; + dispparams.rgdispidNamedArgs = &dispidNamed; + dispparams.cArgs = 1; + dispparams.rgvarg = vararg; + VariantInit(&varresult); + hr = IDispatch_Invoke(pDispatch, DISPID_TM_PROP_WITH_LCID, &IID_NULL, 0x40c, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL); +todo_wine + ok_ole_success(hr, ITypeInfo_Invoke); + VariantClear(&varresult); + + /* test propget with lcid */ + dispparams.cNamedArgs = 0; + dispparams.cArgs = 0; + dispparams.rgvarg = NULL; + dispparams.rgdispidNamedArgs = NULL; + hr = IDispatch_Invoke(pDispatch, DISPID_TM_PROP_WITH_LCID, &IID_NULL, 0x40c, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL); +todo_wine +{ + ok_ole_success(hr, ITypeInfo_Invoke); + ok(V_VT(&varresult) == VT_I4, "got %x\n", V_VT(&varresult)); + ok(V_I4(&varresult) == 0x409, "got %x\n", V_I4(&varresult)); +} + VariantClear(&varresult); + + /* test propget of INT value */ + dispparams.cNamedArgs = 0; + dispparams.cArgs = 0; + dispparams.rgvarg = NULL; + dispparams.rgdispidNamedArgs = NULL; + hr = IDispatch_Invoke(pDispatch, DISPID_TM_PROP_INT, &IID_NULL, 0x40c, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL); + ok_ole_success(hr, ITypeInfo_Invoke); + ok(V_VT(&varresult) == VT_I4, "got %x\n", V_VT(&varresult)); + ok(V_I4(&varresult) == -13, "got %x\n", V_I4(&varresult)); + VariantClear(&varresult); + + /* test propget of INT value */ + dispparams.cNamedArgs = 0; + dispparams.cArgs = 0; + dispparams.rgvarg = NULL; + dispparams.rgdispidNamedArgs = NULL; + hr = IDispatch_Invoke(pDispatch, DISPID_TM_PROP_UINT, &IID_NULL, 0x40c, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL); + ok_ole_success(hr, ITypeInfo_Invoke); + ok(V_VT(&varresult) == VT_UI4, "got %x\n", V_VT(&varresult)); + ok(V_UI4(&varresult) == 42, "got %x\n", V_UI4(&varresult)); + VariantClear(&varresult); + IDispatch_Release(pDispatch); IWidget_Release(pWidget); @@ -1157,9 +1367,40 @@ static void test_DispCallFunc(void) V_VT(&varref) = VT_ERROR; V_ERROR(&varref) = DISP_E_PARAMNOTFOUND; VariantInit(&varresult); - hr = DispCallFunc(pWidget, 36, CC_STDCALL, VT_UI4, 4, rgvt, rgpvarg, &varresult); + hr = DispCallFunc(pWidget, 9*sizeof(void*), CC_STDCALL, VT_UI4, 4, rgvt, rgpvarg, &varresult); ok_ole_success(hr, DispCallFunc); VariantClear(&varresult); + VariantClear(&vararg[1]); + VariantClear(&vararg[2]); + IWidget_Release(pWidget); +} + +static void test_StaticWidget(void) +{ + ITypeInfo *type_info; + DISPPARAMS dispparams; + VARIANTARG vararg[4]; + EXCEPINFO excepinfo; + VARIANT varresult; + HRESULT hr; + + type_info = get_type_info(&IID_IStaticWidget); + + /* call TestDual */ + dispparams.cNamedArgs = 0; + dispparams.cArgs = 1; + dispparams.rgdispidNamedArgs = NULL; + dispparams.rgvarg = vararg; + V_VT(vararg) = VT_DISPATCH; + V_DISPATCH(vararg) = (IDispatch*)&TestDualDisp; + VariantInit(&varresult); + hr = ITypeInfo_Invoke(type_info, &StaticWidget, DISPID_TM_TESTDUAL, DISPATCH_METHOD, + &dispparams, &varresult, &excepinfo, NULL); + ok_ole_success(hr, IDispatch_Invoke); + ok(V_VT(&varresult) == VT_EMPTY, "vt %x\n", V_VT(&varresult)); + VariantClear(&varresult); + + ITypeInfo_Release(type_info); } START_TEST(tmarshal) @@ -1173,6 +1414,11 @@ START_TEST(tmarshal) test_typelibmarshal(); test_DispCallFunc(); + test_StaticWidget(); + + hr = UnRegisterTypeLib(&LIBID_TestTypelib, 1, 0, LOCALE_NEUTRAL, + sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32); + ok_ole_success(hr, UnRegisterTypeLib); CoUninitialize(); } diff --git a/rostests/winetests/oleaut32/tmarshal.idl b/rostests/winetests/oleaut32/tmarshal.idl index 9b94843b46e..f9b18b81f9f 100644 --- a/rostests/winetests/oleaut32/tmarshal.idl +++ b/rostests/winetests/oleaut32/tmarshal.idl @@ -35,6 +35,12 @@ library TestTypelib STATE_WIDGETIFIED } STATE; + typedef struct tagMYSTRUCT + { + INT field1; + ULONGLONG field2; + } MYSTRUCT; + coclass ApplicationObject2; [ @@ -46,6 +52,17 @@ library TestTypelib HRESULT anotherfn(void); } + [ + odl, + oleautomation, + dual, + uuid(3f7e06fe-0bce-46f0-8b7d-3a68393c7967) + ] + interface ItestDual : IDispatch + { + HRESULT test(); + } + [ odl, uuid(a1f8cae3-c947-4c5f-b57d-c87b9b5f3586), @@ -95,10 +112,13 @@ library TestTypelib HRESULT VariantArrayPtr([in] SAFEARRAY(VARIANT) *values); [id(DISPID_TM_VARIANT)] - void Variant([in] VARIANT var); + HRESULT Variant([in] VARIANT var); [vararg, id(DISPID_TM_VARARG)] - void VarArg([in] int numexpect, [in] SAFEARRAY(VARIANT) values); + HRESULT VarArg([in] int numexpect, [in] SAFEARRAY(VARIANT) values); + + [id(DISPID_TM_STRUCTARGS)] + HRESULT StructArgs([in] MYSTRUCT byval, [in] MYSTRUCT *byptr, [in] MYSTRUCT arr[5]); [id(DISPID_TM_ERROR)] HRESULT Error(); @@ -106,6 +126,29 @@ library TestTypelib [propget, id(DISPID_TM_CLONEINTERFACE)] HRESULT CloneInterface([out, retval] ISomethingFromDispatch **ppVal); + [id(DISPID_TM_PROP_WITH_LCID), propput] + HRESULT prop_with_lcid([in,lcid] long lcid, [in] INT i); + + [id(DISPID_TM_PROP_WITH_LCID), propget] + HRESULT prop_with_lcid([in,lcid] long lcid, [out,retval] INT *i); + + [id(DISPID_TM_PROP_INT), propget] + HRESULT prop_int([out,retval] INT *i); + + [id(DISPID_TM_PROP_UINT), propget] + HRESULT prop_uint([out,retval] UINT *i); + } + + [ + odl, + uuid(a1f8cae3-c947-3c5f-a57c-c88b9b6f3586), + oleautomation, + dual + ] + interface IStaticWidget : IDispatch + { + [id(DISPID_TM_TESTDUAL)] + HRESULT TestDual([in] ItestDual *p); } [ diff --git a/rostests/winetests/oleaut32/tmarshal.rc b/rostests/winetests/oleaut32/tmarshal.rc index aabf61181b9..707895f2bb5 100644 --- a/rostests/winetests/oleaut32/tmarshal.rc +++ b/rostests/winetests/oleaut32/tmarshal.rc @@ -27,4 +27,8 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #include "wine/wine_common_ver.rc" +/* @makedep: tmarshal.tlb */ 1 TYPELIB LOADONCALL DISCARDABLE tmarshal.tlb + +/* @makedep: test_tlb.tlb */ +2 TYPELIB LOADONCALL DISCARDABLE test_tlb.tlb diff --git a/rostests/winetests/oleaut32/tmarshal_dispids.h b/rostests/winetests/oleaut32/tmarshal_dispids.h index 4bf47cdf629..08d77360f80 100644 --- a/rostests/winetests/oleaut32/tmarshal_dispids.h +++ b/rostests/winetests/oleaut32/tmarshal_dispids.h @@ -32,5 +32,10 @@ #define DISPID_TM_VARARG 13 #define DISPID_TM_ERROR 14 #define DISPID_TM_CLONEINTERFACE 15 +#define DISPID_TM_TESTDUAL 16 +#define DISPID_TM_STRUCTARGS 17 +#define DISPID_TM_PROP_WITH_LCID 18 +#define DISPID_TM_PROP_INT 19 +#define DISPID_TM_PROP_UINT 20 #define DISPID_NOA_BSTRRET 1 diff --git a/rostests/winetests/oleaut32/typelib.c b/rostests/winetests/oleaut32/typelib.c index e022b8263de..0d523f0efd9 100644 --- a/rostests/winetests/oleaut32/typelib.c +++ b/rostests/winetests/oleaut32/typelib.c @@ -33,14 +33,14 @@ #include "tmarshal.h" #define expect_eq(expr, value, type, format) { type _ret = (expr); ok((value) == _ret, #expr " expected " format " got " format "\n", value, _ret); } -#define expect_int(expr, value) expect_eq(expr, (int)value, int, "%d") -#define expect_hex(expr, value) expect_eq(expr, (int)value, int, "0x%x") +#define expect_int(expr, value) expect_eq(expr, (int)(value), int, "%d") +#define expect_hex(expr, value) expect_eq(expr, (int)(value), int, "0x%x") #define expect_null(expr) expect_eq(expr, NULL, const void *, "%p") -#define expect_wstr_utf8val(expr, value) \ +#define expect_wstr_acpval(expr, value) \ { \ CHAR buf[260]; \ - expect_eq(!WideCharToMultiByte(CP_UTF8, 0, (expr), -1, buf, 260, NULL, NULL), 0, int, "%d"); \ + expect_eq(!WideCharToMultiByte(CP_ACP, 0, (expr), -1, buf, 260, NULL, NULL), 0, int, "%d"); \ ok(lstrcmp(value, buf) == 0, #expr " expected \"%s\" got \"%s\"\n", value, buf); \ } @@ -399,7 +399,7 @@ static void test_CreateDispTypeInfo(void) ok(pFuncDesc->invkind == methdata[1].wFlags, "invkind %d\n", pFuncDesc->invkind); ok(pFuncDesc->callconv == methdata[1].cc, "callconv %d\n", pFuncDesc->callconv); ok(pFuncDesc->cParams == methdata[1].cArgs, "cParams %d\n", pFuncDesc->cParams); - ok(pFuncDesc->oVft == 4, "oVft %d\n", pFuncDesc->oVft); + ok(pFuncDesc->oVft == sizeof(void *), "oVft %d\n", pFuncDesc->oVft); ok(pFuncDesc->wFuncFlags == 0, "oVft %d\n", pFuncDesc->wFuncFlags); ok(pFuncDesc->elemdescFunc.tdesc.vt == VT_I4, "ret vt %x\n", pFuncDesc->elemdescFunc.tdesc.vt); ITypeInfo_ReleaseFuncDesc(pTI2, pFuncDesc); @@ -410,7 +410,7 @@ static void test_CreateDispTypeInfo(void) ok(pFuncDesc->invkind == methdata[2].wFlags, "invkind %d\n", pFuncDesc->invkind); ok(pFuncDesc->callconv == methdata[2].cc, "callconv %d\n", pFuncDesc->callconv); ok(pFuncDesc->cParams == methdata[2].cArgs, "cParams %d\n", pFuncDesc->cParams); - ok(pFuncDesc->oVft == 12, "oVft %d\n", pFuncDesc->oVft); + ok(pFuncDesc->oVft == 3 * sizeof(void *), "oVft %d\n", pFuncDesc->oVft); ok(pFuncDesc->wFuncFlags == 0, "oVft %d\n", pFuncDesc->wFuncFlags); ok(pFuncDesc->elemdescFunc.tdesc.vt == VT_HRESULT, "ret vt %x\n", pFuncDesc->elemdescFunc.tdesc.vt); ok(pFuncDesc->lprgelemdescParam[0].tdesc.vt == VT_I4, "parm 0 vt %x\n", pFuncDesc->lprgelemdescParam[0].tdesc.vt); @@ -423,7 +423,7 @@ static void test_CreateDispTypeInfo(void) ok(pFuncDesc->invkind == methdata[3].wFlags, "invkind %d\n", pFuncDesc->invkind); ok(pFuncDesc->callconv == methdata[3].cc, "callconv %d\n", pFuncDesc->callconv); ok(pFuncDesc->cParams == methdata[3].cArgs, "cParams %d\n", pFuncDesc->cParams); - ok(pFuncDesc->oVft == 16, "oVft %d\n", pFuncDesc->oVft); + ok(pFuncDesc->oVft == 4 * sizeof(void *), "oVft %d\n", pFuncDesc->oVft); ok(pFuncDesc->wFuncFlags == 0, "oVft %d\n", pFuncDesc->wFuncFlags); ok(pFuncDesc->elemdescFunc.tdesc.vt == VT_I4, "ret vt %x\n", pFuncDesc->elemdescFunc.tdesc.vt); ITypeInfo_ReleaseFuncDesc(pTI2, pFuncDesc); @@ -513,6 +513,70 @@ static void test_TypeInfo(void) ITypeLib_Release(pTypeLib); } +/* RegDeleteTreeW from dlls/advapi32/registry.c */ +static LSTATUS myRegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey) +{ + LONG ret; + DWORD dwMaxSubkeyLen, dwMaxValueLen; + DWORD dwMaxLen, dwSize; + WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; + HKEY hSubKey = hKey; + + if(lpszSubKey) + { + ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + if (ret) return ret; + } + + ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, + &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL); + if (ret) goto cleanup; + + dwMaxSubkeyLen++; + dwMaxValueLen++; + dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen); + if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR)) + { + /* Name too big: alloc a buffer for it */ + if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR)))) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + } + + /* Recursively delete all the subkeys */ + while (TRUE) + { + dwSize = dwMaxLen; + if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, + NULL, NULL, NULL)) break; + + ret = myRegDeleteTreeW(hSubKey, lpszName); + if (ret) goto cleanup; + } + + if (lpszSubKey) + ret = RegDeleteKeyW(hKey, lpszSubKey); + else + while (TRUE) + { + dwSize = dwMaxLen; + if (RegEnumValueW(hKey, 0, lpszName, &dwSize, + NULL, NULL, NULL, NULL)) break; + + ret = RegDeleteValueW(hKey, lpszName); + if (ret) goto cleanup; + } + +cleanup: + if (lpszName != szNameBuf) + HeapFree(GetProcessHeap(), 0, lpszName); + if(lpszSubKey) + RegCloseKey(hSubKey); + return ret; +} + static BOOL do_typelib_reg_key(GUID *uid, WORD maj, WORD min, LPCWSTR base, BOOL remove) { static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0}; @@ -521,20 +585,29 @@ static BOOL do_typelib_reg_key(GUID *uid, WORD maj, WORD min, LPCWSTR base, BOOL WCHAR buf[128]; HKEY hkey; BOOL ret = TRUE; + DWORD res; memcpy(buf, typelibW, sizeof(typelibW)); StringFromGUID2(uid, buf + lstrlenW(buf), 40); if (remove) { - ok(SHDeleteKeyW(HKEY_CLASSES_ROOT, buf) == ERROR_SUCCESS, "SHDeleteKey failed\n"); + ok(myRegDeleteTreeW(HKEY_CLASSES_ROOT, buf) == ERROR_SUCCESS, "SHDeleteKey failed\n"); return TRUE; } wsprintfW(buf + lstrlenW(buf), formatW, maj, min ); - if (RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0, - KEY_WRITE, NULL, &hkey, NULL) != ERROR_SUCCESS) + SetLastError(0xdeadbeef); + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0, + KEY_WRITE, NULL, &hkey, NULL); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("W-calls are not implemented\n"); + return FALSE; + } + + if (res != ERROR_SUCCESS) { trace("RegCreateKeyExW failed\n"); return FALSE; @@ -565,6 +638,10 @@ static void test_QueryPathOfRegTypeLib(void) { 3, 22, S_OK, {'f','a','k','e','_','3','_','3','7','.','d','l','l',0 } }, { 3, 37, S_OK, {'f','a','k','e','_','3','_','3','7','.','d','l','l',0 } }, { 3, 40, S_OK, {'f','a','k','e','_','3','_','3','7','.','d','l','l',0 } }, + { 0xffff, 0xffff, S_OK, {'f','a','k','e','_','5','_','3','7','.','d','l','l',0 } }, + { 0xffff, 0, TYPE_E_LIBNOTREGISTERED, { 0 } }, + { 3, 0xffff, TYPE_E_LIBNOTREGISTERED, { 0 } }, + { 5, 0xffff, TYPE_E_LIBNOTREGISTERED, { 0 } }, { 4, 0, TYPE_E_LIBNOTREGISTERED, { 0 } } }; static const WCHAR base[] = {'f','a','k','e',0}; @@ -576,7 +653,7 @@ static void test_QueryPathOfRegTypeLib(void) BSTR path; status = UuidCreate(&uid); - ok(!status, "UuidCreate error %08lx\n", status); + ok(!status || status == RPC_S_UUID_LOCAL_ONLY, "UuidCreate error %08x\n", status); StringFromGUID2(&uid, uid_str, 40); /*trace("GUID: %s\n", wine_dbgstr_w(uid_str));*/ @@ -584,6 +661,7 @@ static void test_QueryPathOfRegTypeLib(void) if (!do_typelib_reg_key(&uid, 3, 0, base, 0)) return; if (!do_typelib_reg_key(&uid, 3, 1, base, 0)) return; if (!do_typelib_reg_key(&uid, 3, 37, base, 0)) return; + if (!do_typelib_reg_key(&uid, 5, 37, base, 0)) return; for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { @@ -608,11 +686,13 @@ static void test_inheritance(void) HREFTYPE href; FUNCDESC *pFD; WCHAR path[MAX_PATH]; + CHAR pathA[MAX_PATH]; static const WCHAR tl_path[] = {'.','\\','m','i','d','l','_','t','m','a','r','s','h','a','l','.','t','l','b',0}; BOOL use_midl_tlb = 0; - GetModuleFileNameW(NULL, path, MAX_PATH); + GetModuleFileNameA(NULL, pathA, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH); if(use_midl_tlb) memcpy(path, tl_path, sizeof(tl_path)); @@ -628,7 +708,7 @@ static void test_inheritance(void) hr = ITypeInfo_GetTypeAttr(pTI, &pTA); ok(hr == S_OK, "hr %08x\n", hr); ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); - ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->cbSizeVft == 7 * sizeof(void *), "sizevft %d\n", pTA->cbSizeVft); ok(pTA->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "typeflags %x\n", pTA->wTypeFlags); if(use_midl_tlb) { ok(pTA->cFuncs == 6, "cfuncs %d\n", pTA->cFuncs); @@ -650,7 +730,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetFuncDesc(pTI, 5, &pFD); ok(hr == S_OK, "hr %08x\n", hr); ok(pFD->memid == 0x60020000, "memid %08x\n", pFD->memid); - ok(pFD->oVft == 20, "oVft %d\n", pFD->oVft); + ok(pFD->oVft == 5 * sizeof(void *), "oVft %d\n", pFD->oVft); ITypeInfo_ReleaseFuncDesc(pTI, pFD); } ITypeInfo_Release(pTI); @@ -663,7 +743,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetTypeAttr(pTI, &pTA); ok(hr == S_OK, "hr %08x\n", hr); ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); - ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->cbSizeVft == 7 * sizeof(void *), "sizevft %d\n", pTA->cbSizeVft); ok(pTA->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "typeflags %x\n", pTA->wTypeFlags); ok(pTA->cFuncs == 1, "cfuncs %d\n", pTA->cFuncs); ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); @@ -692,15 +772,17 @@ if(use_midl_tlb) { hr = ITypeInfo_GetTypeAttr(pTI, &pTA); ok(hr == S_OK, "hr %08x\n", hr); + if (hr == S_OK) + { ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); - ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->cbSizeVft == 7 * sizeof(void *), "sizevft %d\n", pTA->cbSizeVft); if(use_midl_tlb) { ok(pTA->wTypeFlags == TYPEFLAG_FDUAL, "typeflags %x\n", pTA->wTypeFlags); } ok(pTA->cFuncs == 8, "cfuncs %d\n", pTA->cFuncs); ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); ITypeInfo_ReleaseTypeAttr(pTI, pTA); - + } hr = ITypeInfo_GetRefTypeOfImplType(pTI, 0, &href); ok(hr == S_OK, "hr %08x\n", hr); hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p); @@ -724,7 +806,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetTypeAttr(pTI, &pTA); ok(hr == S_OK, "hr %08x\n", hr); ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); - ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->cbSizeVft == 7 * sizeof(void *), "sizevft %d\n", pTA->cbSizeVft); ok(pTA->wTypeFlags == (TYPEFLAG_FDISPATCHABLE|TYPEFLAG_FDUAL), "typeflags %x\n", pTA->wTypeFlags); ok(pTA->cFuncs == 10, "cfuncs %d\n", pTA->cFuncs); ok(pTA->cImplTypes == 1, "cimpltypes %d\n", pTA->cImplTypes); @@ -752,7 +834,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetTypeAttr(pTI, &pTA); ok(hr == S_OK, "hr %08x\n", hr); ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); - ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->cbSizeVft == 7 * sizeof(void *), "sizevft %d\n", pTA->cbSizeVft); ok(pTA->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "typeflags %x\n", pTA->wTypeFlags); if(use_midl_tlb) { ok(pTA->cFuncs == 3, "cfuncs %d\n", pTA->cFuncs); @@ -776,7 +858,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetFuncDesc(pTI, 2, &pFD); ok(hr == S_OK, "hr %08x\n", hr); ok(pFD->memid == 0x60010000, "memid %08x\n", pFD->memid); - ok(pFD->oVft == 8, "oVft %d\n", pFD->oVft); + ok(pFD->oVft == 2 * sizeof(void *), "oVft %d\n", pFD->oVft); ITypeInfo_ReleaseFuncDesc(pTI, pFD); } ITypeInfo_Release(pTI); @@ -788,7 +870,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetTypeAttr(pTI, &pTA); ok(hr == S_OK, "hr %08x\n", hr); ok(pTA->typekind == TKIND_DISPATCH, "kind %04x\n", pTA->typekind); - ok(pTA->cbSizeVft == 28, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->cbSizeVft == 7 * sizeof(void *), "sizevft %d\n", pTA->cbSizeVft); ok(pTA->wTypeFlags == TYPEFLAG_FDISPATCHABLE, "typeflags %x\n", pTA->wTypeFlags); if(use_midl_tlb) { ok(pTA->cFuncs == 10, "cfuncs %d\n", pTA->cFuncs); @@ -810,7 +892,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetFuncDesc(pTI, 9, &pFD); ok(hr == S_OK, "hr %08x\n", hr); ok(pFD->memid == 0x1236, "memid %08x\n", pFD->memid); - ok(pFD->oVft == 36, "oVft %d\n", pFD->oVft); + ok(pFD->oVft == 9 * sizeof(void *), "oVft %d\n", pFD->oVft); ITypeInfo_ReleaseFuncDesc(pTI, pFD); } ITypeInfo_Release(pTI); @@ -823,7 +905,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetTypeAttr(pTI, &pTA); ok(hr == S_OK, "hr %08x\n", hr); ok(pTA->typekind == TKIND_INTERFACE, "kind %04x\n", pTA->typekind); - ok(pTA->cbSizeVft == 24, "sizevft %d\n", pTA->cbSizeVft); + ok(pTA->cbSizeVft == 6 * sizeof(void *), "sizevft %d\n", pTA->cbSizeVft); ok(pTA->wTypeFlags == 0, "typeflags %x\n", pTA->wTypeFlags); if(use_midl_tlb) { ok(pTA->cFuncs == 1, "cfuncs %d\n", pTA->cFuncs); @@ -836,7 +918,7 @@ if(use_midl_tlb) { hr = ITypeInfo_GetFuncDesc(pTI, 0, &pFD); ok(hr == S_OK, "hr %08x\n", hr); ok(pFD->memid == 0x60020000, "memid %08x\n", pFD->memid); - ok(pFD->oVft == 20, "oVft %d\n", pFD->oVft); + ok(pFD->oVft == 5 * sizeof(void *), "oVft %d\n", pFD->oVft); ITypeInfo_ReleaseFuncDesc(pTI, pFD); } ITypeInfo_Release(pTI); @@ -1008,7 +1090,7 @@ typedef struct _function_info CALLCONV callconv; short cParams; short cParamsOpt; - short oVft; + short vtbl_index; short cScodes; WORD wFuncFlags; element_info ret_type; @@ -1033,7 +1115,7 @@ static const interface_info info[] = { { "IDualIface", /*kind*/ TKIND_DISPATCH, /*flags*/ 0x1040, /*align*/ 4, /*size*/ 4, - /*#vtbl*/ 28, /*#func*/ 8, + /*#vtbl*/ 7, /*#func*/ 8, { { 0x60000000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, @@ -1053,7 +1135,7 @@ static const interface_info info[] = { }, { 0x60000001, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, - /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 4, /*#scodes*/ 0, /*flags*/ 0x1, + /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 1, /*#scodes*/ 0, /*flags*/ 0x1, {19, 0}, /* ret */ { /* params */ {-1, -1} @@ -1065,7 +1147,7 @@ static const interface_info info[] = { }, { 0x60000002, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, - /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 8, /*#scodes*/ 0, /*flags*/ 0x1, + /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 2, /*#scodes*/ 0, /*flags*/ 0x1, {19, 0}, /* ret */ { /* params */ {-1, -1} @@ -1077,7 +1159,7 @@ static const interface_info info[] = { }, { 0x60010000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, - /*#param*/ 1, /*#opt*/ 0, /*vtbl*/ 12, /*#scodes*/ 0, /*flags*/ 0x1, + /*#param*/ 1, /*#opt*/ 0, /*vtbl*/ 3, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ {26, 2}, @@ -1091,7 +1173,7 @@ static const interface_info info[] = { }, { 0x60010001, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, - /*#param*/ 3, /*#opt*/ 0, /*vtbl*/ 16, /*#scodes*/ 0, /*flags*/ 0x1, + /*#param*/ 3, /*#opt*/ 0, /*vtbl*/ 4, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ {23, 1}, @@ -1109,7 +1191,7 @@ static const interface_info info[] = { }, { 0x60010002, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, - /*#param*/ 5, /*#opt*/ 0, /*vtbl*/ 20, /*#scodes*/ 0, /*flags*/ 0x1, + /*#param*/ 5, /*#opt*/ 0, /*vtbl*/ 5, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ {26, 1}, @@ -1131,7 +1213,7 @@ static const interface_info info[] = { }, { 0x60010003, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, - /*#param*/ 8, /*#opt*/ 0, /*vtbl*/ 24, /*#scodes*/ 0, /*flags*/ 0x1, + /*#param*/ 8, /*#opt*/ 0, /*vtbl*/ 6, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ {3, 1}, @@ -1159,7 +1241,7 @@ static const interface_info info[] = { }, { 0x60020000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, - /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 28, /*#scodes*/ 0, /*flags*/ 0x0, + /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 7, /*#scodes*/ 0, /*flags*/ 0x0, {24, 0}, /* ret */ { /* params */ {-1, -1} @@ -1174,11 +1256,11 @@ static const interface_info info[] = { { "ISimpleIface", /*kind*/ TKIND_INTERFACE, /*flags*/ 0x1000, /*align*/ 4, /*size*/ 4, - /*#vtbl*/ 32, /*#func*/ 1, + /*#vtbl*/ 8, /*#func*/ 1, { { 0x60020000, /*func*/ FUNC_PUREVIRTUAL, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, - /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 28, /*#scodes*/ 0, /*flags*/ 0x0, + /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 7, /*#scodes*/ 0, /*flags*/ 0x0, {25, 0}, /* ret */ { /* params */ {-1, -1} @@ -1204,7 +1286,7 @@ static void test_dump_typelib(const char *name) int ifcount = sizeof(info)/sizeof(info[0]); int iface, func; - MultiByteToWideChar(CP_UTF8, 0, name, -1, wszName, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, name, -1, wszName, MAX_PATH); ole_check(LoadTypeLibEx(wszName, REGKIND_NONE, &typelib)); expect_eq(ITypeLib_GetTypeInfoCount(typelib), ifcount, UINT, "%d"); for (iface = 0; iface < ifcount; iface++) @@ -1217,7 +1299,7 @@ static void test_dump_typelib(const char *name) trace("Interface %s\n", if_info->name); ole_check(ITypeLib_GetTypeInfo(typelib, iface, &typeinfo)); ole_check(ITypeLib_GetDocumentation(typelib, iface, &bstrIfName, NULL, NULL, NULL)); - expect_wstr_utf8val(bstrIfName, if_info->name); + expect_wstr_acpval(bstrIfName, if_info->name); SysFreeString(bstrIfName); ole_check(ITypeInfo_GetTypeAttr(typeinfo, &typeattr)); @@ -1225,7 +1307,7 @@ static void test_dump_typelib(const char *name) expect_hex(typeattr->wTypeFlags, if_info->wTypeFlags); expect_int(typeattr->cbAlignment, if_info->cbAlignment); expect_int(typeattr->cbSizeInstance, if_info->cbSizeInstance); - expect_int(typeattr->cbSizeVft, if_info->cbSizeVft); + expect_int(typeattr->cbSizeVft, if_info->cbSizeVft * sizeof(void*)); expect_int(typeattr->cFuncs, if_info->cFuncs); for (func = 0; func < typeattr->cFuncs; func++) @@ -1244,13 +1326,15 @@ static void test_dump_typelib(const char *name) expect_int(desc->callconv, fn_info->callconv); expect_int(desc->cParams, fn_info->cParams); expect_int(desc->cParamsOpt, fn_info->cParamsOpt); - expect_int(desc->oVft, fn_info->oVft); + ok( desc->oVft == fn_info->vtbl_index * sizeof(void*) || + broken(desc->oVft == fn_info->vtbl_index * 4), /* xp64 */ + "desc->oVft got %u\n", desc->oVft ); expect_int(desc->cScodes, fn_info->cScodes); expect_int(desc->wFuncFlags, fn_info->wFuncFlags); ole_check(ITypeInfo_GetNames(typeinfo, desc->memid, namesTab, 256, &cNames)); for (i = 0; i < cNames; i++) { - expect_wstr_utf8val(namesTab[i], fn_info->names[i]); + expect_wstr_acpval(namesTab[i], fn_info->names[i]); SysFreeString(namesTab[i]); } expect_null(fn_info->names[cNames]); @@ -1273,13 +1357,96 @@ static void test_dump_typelib(const char *name) #endif +static const char *create_test_typelib(void) +{ + static char filename[MAX_PATH]; + HANDLE file; + HRSRC res; + void *ptr; + DWORD written; + + GetTempFileNameA( ".", "tlb", 0, filename ); + file = CreateFile( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "file creation failed\n" ); + if (file == INVALID_HANDLE_VALUE) return NULL; + res = FindResource( GetModuleHandle(0), MAKEINTRESOURCE(2), "TYPELIB" ); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandle(0), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandle(0), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandle(0), res ), "couldn't write resource\n" ); + CloseHandle( file ); + return filename; +} + +static void test_create_typelib_lcid(LCID lcid) +{ + char filename[MAX_PATH]; + WCHAR name[MAX_PATH]; + HRESULT hr; + ICreateTypeLib2 *tl; + HANDLE file; + DWORD msft_header[5]; /* five is enough for now */ + DWORD read; + + GetTempFileNameA( ".", "tlb", 0, filename ); + MultiByteToWideChar(CP_ACP, 0, filename, -1, name, MAX_PATH); + + hr = CreateTypeLib2(SYS_WIN32, name, &tl); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeLib2_SetLcid(tl, lcid); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeLib2_SaveAllChanges(tl); + ICreateTypeLib2_Release(tl); + + file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "file creation failed\n" ); + + ReadFile( file, msft_header, sizeof(msft_header), &read, NULL ); + ok(read == sizeof(msft_header), "read %d\n", read); + CloseHandle( file ); + + ok(msft_header[0] == 0x5446534d, "got %08x\n", msft_header[0]); + ok(msft_header[1] == 0x00010002, "got %08x\n", msft_header[1]); + ok(msft_header[2] == 0xffffffff, "got %08x\n", msft_header[2]); + ok(msft_header[3] == (lcid ? lcid : 0x409), "got %08x (lcid %08x)\n", msft_header[3], lcid); + ok(msft_header[4] == lcid, "got %08x (lcid %08x)\n", msft_header[4], lcid); + + DeleteFileA(filename); +} + +static void test_create_typelibs(void) +{ + test_create_typelib_lcid(LOCALE_SYSTEM_DEFAULT); + test_create_typelib_lcid(LOCALE_USER_DEFAULT); + test_create_typelib_lcid(LOCALE_NEUTRAL); + + test_create_typelib_lcid(0x009); + test_create_typelib_lcid(0x409); + test_create_typelib_lcid(0x809); + + test_create_typelib_lcid(0x007); + test_create_typelib_lcid(0x407); +} + START_TEST(typelib) { + const char *filename; + ref_count_test(wszStdOle2); test_TypeComp(); test_CreateDispTypeInfo(); test_TypeInfo(); test_QueryPathOfRegTypeLib(); test_inheritance(); - test_dump_typelib("test_tlb.tlb"); + + if ((filename = create_test_typelib())) + { + test_dump_typelib( filename ); + DeleteFile( filename ); +} + + test_create_typelibs(); + } diff --git a/rostests/winetests/oleaut32/usrmarshal.c b/rostests/winetests/oleaut32/usrmarshal.c index 633a382fba1..1d61f4972be 100644 --- a/rostests/winetests/oleaut32/usrmarshal.c +++ b/rostests/winetests/oleaut32/usrmarshal.c @@ -35,10 +35,8 @@ # define V_U2(A) (*(A)) #endif -/* doesn't work on Windows due to needing more of the - * MIDL_STUB_MESSAGE structure to be filled out */ -#define LPSAFEARRAY_UNMARSHAL_WORKS 0 -#define BSTR_UNMARSHAL_WORKS 0 +#define LPSAFEARRAY_UNMARSHAL_WORKS 1 +#define BSTR_UNMARSHAL_WORKS 1 #define VARIANT_UNMARSHAL_WORKS 1 static inline SF_TYPE get_union_type(SAFEARRAY *psa) @@ -120,7 +118,7 @@ static void check_safearray(void *buffer, LPSAFEARRAY lpsa) if(!lpsa) { - ok(*(void **)wiresa == NULL, "wiresa + 0x0 should be NULL instead of 0x%08x\n", *(DWORD *)wiresa); + ok(*(DWORD *)wiresa == 0, "wiresa + 0x0 should be NULL instead of 0x%08x\n", *(DWORD *)wiresa); return; } @@ -136,51 +134,80 @@ static void check_safearray(void *buffer, LPSAFEARRAY lpsa) wiresa += sizeof(DWORD); ok(*(WORD *)wiresa == lpsa->cDims, "wiresa + 0x8 should be lpsa->cDims instead of 0x%04x\n", *(WORD *)wiresa); wiresa += sizeof(WORD); - ok(*(WORD *)wiresa == lpsa->fFeatures, "wiresa + 0xc should be lpsa->fFeatures instead of 0x%08x\n", *(WORD *)wiresa); + ok(*(WORD *)wiresa == lpsa->fFeatures, "wiresa + 0xa should be lpsa->fFeatures instead of 0x%08x\n", *(WORD *)wiresa); wiresa += sizeof(WORD); - ok(*(DWORD *)wiresa == lpsa->cbElements, "wiresa + 0x10 should be lpsa->cbElements instead of 0x%08x\n", *(DWORD *)wiresa); + ok(*(DWORD *)wiresa == lpsa->cbElements, "wiresa + 0xc should be lpsa->cbElements instead of 0x%08x\n", *(DWORD *)wiresa); wiresa += sizeof(DWORD); - ok(*(WORD *)wiresa == lpsa->cLocks, "wiresa + 0x16 should be lpsa->cLocks instead of 0x%04x\n", *(WORD *)wiresa); + ok(*(WORD *)wiresa == lpsa->cLocks, "wiresa + 0x10 should be lpsa->cLocks instead of 0x%04x\n", *(WORD *)wiresa); wiresa += sizeof(WORD); - ok(*(WORD *)wiresa == vt, "wiresa + 0x14 should be %04x instead of 0x%04x\n", vt, *(WORD *)wiresa); + ok(*(WORD *)wiresa == vt, "wiresa + 0x12 should be %04x instead of 0x%04x\n", vt, *(WORD *)wiresa); wiresa += sizeof(WORD); - ok(*(DWORD *)wiresa == sftype, "wiresa + 0x18 should be %08x instead of 0x%08x\n", (DWORD)sftype, *(DWORD *)wiresa); + ok(*(DWORD *)wiresa == sftype, "wiresa + 0x14 should be %08x instead of 0x%08x\n", (DWORD)sftype, *(DWORD *)wiresa); wiresa += sizeof(DWORD); - ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x1c should be %u instead of %u\n", cell_count, *(DWORD *)wiresa); + ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x18 should be %u instead of %u\n", cell_count, *(DWORD *)wiresa); + wiresa += sizeof(DWORD); + ok(*(DWORD *)wiresa, "wiresa + 0x1c should be non-zero instead of 0x%08x\n", *(DWORD *)wiresa); wiresa += sizeof(DWORD); - ok(*(DWORD_PTR *)wiresa == (DWORD_PTR)lpsa->pvData, "wiresa + 0x20 should be lpsa->pvData instead of 0x%08lx\n", *(DWORD_PTR *)wiresa); - wiresa += sizeof(DWORD_PTR); if(sftype == SF_HAVEIID) { GUID guid; SafeArrayGetIID(lpsa, &guid); - ok(IsEqualGUID(&guid, (GUID*)wiresa), "guid mismatch\n"); + ok(IsEqualGUID(&guid, wiresa), "guid mismatch\n"); wiresa += sizeof(GUID); } ok(!memcmp(wiresa, lpsa->rgsabound, sizeof(lpsa->rgsabound[0]) * lpsa->cDims), "bounds mismatch\n"); wiresa += sizeof(lpsa->rgsabound[0]) * lpsa->cDims; - ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x2c should be %u instead of %u\n", cell_count, *(DWORD*)wiresa); + ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x28 should be %u instead of %u\n", cell_count, *(DWORD*)wiresa); wiresa += sizeof(DWORD); /* elements are now pointed to by wiresa */ } +static void * WINAPI user_allocate(SIZE_T size) +{ + return CoTaskMemAlloc(size); +} + +static void WINAPI user_free(void *p) +{ + CoTaskMemFree(p); +} + +static void init_user_marshal_cb(USER_MARSHAL_CB *umcb, + PMIDL_STUB_MESSAGE stub_msg, + PRPC_MESSAGE rpc_msg, unsigned char *buffer, + unsigned int size, MSHCTX context) +{ + memset(rpc_msg, 0, sizeof(*rpc_msg)); + rpc_msg->Buffer = buffer; + rpc_msg->BufferLength = size; + + memset(stub_msg, 0, sizeof(*stub_msg)); + stub_msg->RpcMsg = rpc_msg; + stub_msg->Buffer = buffer; + stub_msg->pfnAllocate = user_allocate; + stub_msg->pfnFree = user_free; + + memset(umcb, 0, sizeof(*umcb)); + umcb->Flags = MAKELONG(context, NDR_LOCAL_DATA_REPRESENTATION); + umcb->pStubMsg = stub_msg; + umcb->Signature = USER_MARSHAL_CB_SIGNATURE; + umcb->CBType = buffer ? USER_MARSHAL_CB_UNMARSHALL : USER_MARSHAL_CB_BUFFER_SIZE; +} + static void test_marshal_LPSAFEARRAY(void) { unsigned char *buffer; - unsigned long size; + ULONG size, expected; LPSAFEARRAY lpsa; LPSAFEARRAY lpsa2 = NULL; SAFEARRAYBOUND sab; - MIDL_STUB_MESSAGE stubMsg = { 0 }; - USER_MARSHAL_CB umcb = { 0 }; + RPC_MESSAGE rpc_msg; + MIDL_STUB_MESSAGE stub_msg; + USER_MARSHAL_CB umcb; HRESULT hr; VARTYPE vt; - umcb.Flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); - umcb.pReserve = NULL; - umcb.pStubMsg = &stubMsg; - sab.lLbound = 5; sab.cElements = 10; @@ -188,11 +215,19 @@ static void test_marshal_LPSAFEARRAY(void) *(DWORD *)lpsa->pvData = 0xcafebabe; lpsa->cLocks = 7; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa); - ok(size == 68, "size should be 68 bytes, not %ld\n", size); + expected = (44 + 1 + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1); + expected += sab.cElements * sizeof(USHORT); + ok(size == expected || size == expected + 12, /* win64 */ + "size should be %u bytes, not %u\n", expected, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa); - ok(size == 64, "size should be 64 bytes, not %ld\n", size); + expected = 44 + sab.cElements * sizeof(USHORT); + ok(size == expected || size == expected + 12, /* win64 */ + "size should be %u bytes, not %u\n", expected, size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa); check_safearray(buffer, lpsa); @@ -200,29 +235,36 @@ static void test_marshal_LPSAFEARRAY(void) if (LPSAFEARRAY_UNMARSHAL_WORKS) { VARTYPE vt, vt2; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2); ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal\n"); SafeArrayGetVartype(lpsa, &vt); SafeArrayGetVartype(lpsa2, &vt2); ok(vt == vt2, "vts differ %x %x\n", vt, vt2); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2); } HeapFree(GetProcessHeap(), 0, buffer); + lpsa->cLocks = 0; SafeArrayDestroy(lpsa); /* test NULL safe array */ lpsa = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa); - ok(size == 4, "size should be 4 bytes, not %ld\n", size); + ok(size == 4, "size should be 4 bytes, not %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa); check_safearray(buffer, lpsa); if (LPSAFEARRAY_UNMARSHAL_WORKS) { + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2); ok(lpsa2 == NULL, "NULL LPSAFEARRAY didn't unmarshal\n"); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2); } HeapFree(GetProcessHeap(), 0, buffer); @@ -234,16 +276,26 @@ static void test_marshal_LPSAFEARRAY(void) *(double *)lpsa->pvData = 3.1415; lpsa->cLocks = 7; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa); - ok(size == 128, "size should be 128 bytes, not %ld\n", size); + expected = (44 + 1 + (sizeof(double) - 1)) & ~(sizeof(double) - 1); + expected += sab.cElements * sizeof(double); + ok(size == expected || size == expected + 16, /* win64 */ + "size should be %u bytes, not %u\n", expected, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + expected = (44 + (sizeof(double) - 1)) & ~(sizeof(double) - 1); + expected += sab.cElements * sizeof(double); size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa); - ok(size == 128, "size should be 128 bytes, not %ld\n", size); + ok(size == expected || size == expected + 8, /* win64 */ + "size should be %u bytes, not %u\n", expected, size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa); check_safearray(buffer, lpsa); HeapFree(GetProcessHeap(), 0, buffer); + lpsa->cLocks = 0; SafeArrayDestroy(lpsa); /* VARTYPE-less arrays can be marshaled if cbElements is 1,2,4 or 8 as type SF_In */ @@ -258,9 +310,14 @@ static void test_marshal_LPSAFEARRAY(void) hr = SafeArrayGetVartype(lpsa, &vt); ok(hr == E_INVALIDARG, "ret %08x\n", hr); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa); - ok(size == 432, "size %ld\n", size); + expected = (44 + lpsa->cbElements - 1) & ~(lpsa->cbElements - 1); + expected += lpsa->cbElements * lpsa->rgsabound[0].cElements; + ok(size == expected || size == expected + 8, /* win64 */ + "size should be %u bytes, not %u\n", expected, size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa); check_safearray(buffer, lpsa); HeapFree(GetProcessHeap(), 0, buffer); @@ -270,7 +327,7 @@ static void test_marshal_LPSAFEARRAY(void) /* VARTYPE-less arrays with FADF_VARIANT */ hr = SafeArrayAllocDescriptor(1, &lpsa); ok(hr == S_OK, "saad failed %08x\n", hr); - lpsa->cbElements = 16; + lpsa->cbElements = sizeof(VARIANT); lpsa->fFeatures = FADF_VARIANT; lpsa->rgsabound[0].lLbound = 2; lpsa->rgsabound[0].cElements = 48; @@ -280,11 +337,16 @@ static void test_marshal_LPSAFEARRAY(void) hr = SafeArrayGetVartype(lpsa, &vt); ok(hr == E_INVALIDARG, "ret %08x\n", hr); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa); + expected = 44 + 28 * lpsa->rgsabound[0].cElements; todo_wine - ok(size == 1388, "size %ld\n", size); + ok(size == expected || size == expected + 8, /* win64 */ + "size should be %u bytes, not %u\n", expected, size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa); + lpsa->cbElements = 16; /* VARIANT wire size */ check_safearray(buffer, lpsa); HeapFree(GetProcessHeap(), 0, buffer); SafeArrayDestroyData(lpsa); @@ -314,30 +376,31 @@ static void check_bstr(void *buffer, BSTR b) static void test_marshal_BSTR(void) { - unsigned long size; - MIDL_STUB_MESSAGE stubMsg = { 0 }; - USER_MARSHAL_CB umcb = { 0 }; + ULONG size; + RPC_MESSAGE rpc_msg; + MIDL_STUB_MESSAGE stub_msg; + USER_MARSHAL_CB umcb; unsigned char *buffer, *next; BSTR b, b2; WCHAR str[] = {'m','a','r','s','h','a','l',' ','t','e','s','t','1',0}; DWORD len; - umcb.Flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION); - umcb.pReserve = NULL; - umcb.pStubMsg = &stubMsg; - b = SysAllocString(str); len = SysStringLen(b); ok(len == 13, "get %d\n", len); /* BSTRs are DWORD aligned */ - size = BSTR_UserSize(&umcb.Flags, 1, &b); - ok(size == 42, "size %ld\n", size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); + size = BSTR_UserSize(&umcb.Flags, 1, &b); + ok(size == 42, "size %d\n", size); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = BSTR_UserSize(&umcb.Flags, 0, &b); - ok(size == 38, "size %ld\n", size); + ok(size == 38, "size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); next = BSTR_UserMarshal(&umcb.Flags, buffer, &b); ok(next == buffer + size, "got %p expect %p\n", next, buffer + size); check_bstr(buffer, b); @@ -345,10 +408,12 @@ static void test_marshal_BSTR(void) if (BSTR_UNMARSHAL_WORKS) { b2 = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2); ok(next == buffer + size, "got %p expect %p\n", next, buffer + size); ok(b2 != NULL, "BSTR didn't unmarshal\n"); ok(!memcmp(b, b2, (len + 1) * 2), "strings differ\n"); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); BSTR_UserFree(&umcb.Flags, &b2); } @@ -356,10 +421,12 @@ static void test_marshal_BSTR(void) SysFreeString(b); b = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = BSTR_UserSize(&umcb.Flags, 0, &b); - ok(size == 12, "size %ld\n", size); + ok(size == 12, "size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); next = BSTR_UserMarshal(&umcb.Flags, buffer, &b); ok(next == buffer + size, "got %p expect %p\n", next, buffer + size); @@ -367,9 +434,11 @@ static void test_marshal_BSTR(void) if (BSTR_UNMARSHAL_WORKS) { b2 = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2); ok(next == buffer + size, "got %p expect %p\n", next, buffer + size); ok(b2 == NULL, "NULL BSTR didn't unmarshal\n"); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); BSTR_UserFree(&umcb.Flags, &b2); } HeapFree(GetProcessHeap(), 0, buffer); @@ -381,11 +450,13 @@ static void test_marshal_BSTR(void) len = SysStringByteLen(b); ok(len == 3, "get %d\n", len); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = BSTR_UserSize(&umcb.Flags, 0, &b); - ok(size == 16, "size %ld\n", size); + ok(size == 16, "size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); memset(buffer, 0xcc, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); next = BSTR_UserMarshal(&umcb.Flags, buffer, &b); ok(next == buffer + size, "got %p expect %p\n", next, buffer + size); check_bstr(buffer, b); @@ -394,10 +465,12 @@ static void test_marshal_BSTR(void) if (BSTR_UNMARSHAL_WORKS) { b2 = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2); ok(next == buffer + size, "got %p expect %p\n", next, buffer + size); ok(b2 != NULL, "BSTR didn't unmarshal\n"); ok(!memcmp(b, b2, len), "strings differ\n"); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); BSTR_UserFree(&umcb.Flags, &b2); } HeapFree(GetProcessHeap(), 0, buffer); @@ -409,10 +482,12 @@ static void test_marshal_BSTR(void) len = SysStringByteLen(b); ok(len == 0, "get %d\n", len); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); size = BSTR_UserSize(&umcb.Flags, 0, &b); - ok(size == 12, "size %ld\n", size); + ok(size == 12, "size %d\n", size); buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); next = BSTR_UserMarshal(&umcb.Flags, buffer, &b); ok(next == buffer + size, "got %p expect %p\n", next, buffer + size); check_bstr(buffer, b); @@ -420,11 +495,13 @@ static void test_marshal_BSTR(void) if (BSTR_UNMARSHAL_WORKS) { b2 = NULL; + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE); next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2); ok(next == buffer + size, "got %p expect %p\n", next, buffer + size); ok(b2 != NULL, "NULL LPSAFEARRAY didn't unmarshal\n"); len = SysStringByteLen(b2); ok(len == 0, "byte len %d\n", len); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE); BSTR_UserFree(&umcb.Flags, &b2); } HeapFree(GetProcessHeap(), 0, buffer); @@ -442,7 +519,7 @@ static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, v if (IsEqualIID(riid, &IID_IUnknown)) { IUnknown_AddRef(iface); - *ppv = (LPVOID)iface; + *ppv = iface; return S_OK; } *ppv = NULL; @@ -470,12 +547,12 @@ static const IUnknownVtbl HeapUnknown_Vtbl = HeapUnknown_Release }; -static void check_variant_header(DWORD *wirev, VARIANT *v, unsigned long size) +static void check_variant_header(DWORD *wirev, VARIANT *v, ULONG size) { WORD *wp; DWORD switch_is; - ok(*wirev == (size + 7) >> 3, "wv[0] %08x, expected %08lx\n", *wirev, (size + 7) >> 3); + ok(*wirev == (size + 7) >> 3, "wv[0] %08x, expected %08x\n", *wirev, (size + 7) >> 3); wirev++; ok(*wirev == 0, "wv[1] %08x\n", *wirev); wirev++; @@ -495,6 +572,15 @@ static void check_variant_header(DWORD *wirev, VARIANT *v, unsigned long size) ok(*wirev == switch_is, "switch_is %08x expected %08x\n", *wirev, switch_is); } +/* Win9x and WinME don't always align as needed. Variants have + * an alignment of 8. + */ +static void *alloc_aligned(SIZE_T size, void **buf) +{ + *buf = HeapAlloc(GetProcessHeap(), 0, size + 7); + return (void *)(((UINT_PTR)*buf + 7) & ~7); +} + static void test_marshal_VARIANT(void) { VARIANT v, v2; @@ -502,6 +588,7 @@ static void test_marshal_VARIANT(void) RPC_MESSAGE rpcMsg = { 0 }; USER_MARSHAL_CB umcb = { 0 }; unsigned char *buffer, *next; + void *oldbuffer; ULONG ul; short s; double d; @@ -512,6 +599,7 @@ static void test_marshal_VARIANT(void) LPSAFEARRAY lpsa; DECIMAL dec, dec2; HeapUnknown *heap_unknown; + DWORD expected; stubMsg.RpcMsg = &rpcMsg; @@ -526,6 +614,13 @@ static void test_marshal_VARIANT(void) V_VT(&v) = VT_I1; V_I1(&v) = 0x12; + /* check_variant_header tests wReserved[123], so initialize to unique values. + * (Could probably also do this by setting the variant to a known DECIMAL.) + */ + V_U2(&v).wReserved1 = 0x1234; + V_U2(&v).wReserved2 = 0x5678; + V_U2(&v).wReserved3 = 0x9abc; + /* Variants have an alignment of 8 */ rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 1, &v); ok(stubMsg.BufferLength == 29, "size %d\n", stubMsg.BufferLength); @@ -533,7 +628,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 21, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -553,7 +648,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** I2 ***/ VariantInit(&v); @@ -563,7 +658,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 22, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -583,7 +678,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** I2 BYREF ***/ VariantInit(&v); @@ -594,7 +689,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 26, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -607,16 +702,20 @@ static void test_marshal_VARIANT(void) ok(*(short*)wirev == s, "wv[6] %08x\n", *wirev); if (VARIANT_UNMARSHAL_WORKS) { + void *mem; VariantInit(&v2); + V_VT(&v2) = VT_I2 | VT_BYREF; + V_BYREF(&v2) = mem = CoTaskMemAlloc(sizeof(V_I2(&v2))); stubMsg.Buffer = buffer; next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2)); + ok(V_BYREF(&v2) == mem, "didn't reuse existing memory\n"); ok(*V_I2REF(&v) == *V_I2REF(&v2), "got i2 ref %x expect ui4 ref %x\n", *V_I2REF(&v), *V_I2REF(&v2)); VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** I4 ***/ VariantInit(&v); @@ -626,7 +725,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 24, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -647,8 +746,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** UI4 ***/ VariantInit(&v); @@ -658,7 +756,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 24, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -678,8 +776,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** UI4 BYREF ***/ VariantInit(&v); @@ -690,7 +787,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 28, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -713,7 +810,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** R4 ***/ VariantInit(&v); @@ -723,7 +820,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 24, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -743,7 +840,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** R8 ***/ VariantInit(&v); @@ -753,7 +850,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 32, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; memset(buffer, 0xcc, stubMsg.BufferLength); next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); @@ -776,7 +873,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** R8 BYREF ***/ VariantInit(&v); @@ -787,7 +884,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 32, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -809,7 +906,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** VARIANT_BOOL ***/ VariantInit(&v); @@ -819,7 +916,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 22, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -839,10 +936,11 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** DECIMAL ***/ VarDecFromI4(0x12345678, &dec); + dec.wReserved = 0xfedc; /* Also initialize reserved field, as we check it later */ VariantInit(&v); V_DECIMAL(&v) = dec; V_VT(&v) = VT_DECIMAL; @@ -850,7 +948,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 40, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; memset(buffer, 0xcc, stubMsg.BufferLength); next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); @@ -876,7 +974,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** DECIMAL BYREF ***/ VariantInit(&v); @@ -886,7 +984,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 40, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -900,6 +998,13 @@ static void test_marshal_VARIANT(void) if (VARIANT_UNMARSHAL_WORKS) { VariantInit(&v2); + /* check_variant_header tests wReserved[123], so initialize to unique values. + * (Could probably also do this by setting the variant to a known DECIMAL.) + */ + V_U2(&v2).wReserved1 = 0x0123; + V_U2(&v2).wReserved2 = 0x4567; + V_U2(&v2).wReserved3 = 0x89ab; + stubMsg.Buffer = buffer; next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -908,7 +1013,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** EMPTY ***/ VariantInit(&v); @@ -917,7 +1022,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 20, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -934,7 +1039,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** NULL ***/ VariantInit(&v); @@ -943,7 +1048,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 20, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -960,7 +1065,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** BSTR ***/ b = SysAllocString(str); @@ -970,7 +1075,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 60, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -993,7 +1098,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** BSTR BYREF ***/ VariantInit(&v); @@ -1002,7 +1107,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 64, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); @@ -1027,7 +1132,7 @@ static void test_marshal_VARIANT(void) VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); SysFreeString(b); /*** ARRAY ***/ @@ -1037,21 +1142,22 @@ static void test_marshal_VARIANT(void) lpsa = SafeArrayCreate(VT_R8, 1, &sab); *(DWORD *)lpsa->pvData = 0xcafebabe; *((DWORD *)lpsa->pvData + 1) = 0xdeadbeef; - lpsa->cLocks = 7; VariantInit(&v); V_VT(&v) = VT_UI4 | VT_ARRAY; V_ARRAY(&v) = lpsa; rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); - ok(stubMsg.BufferLength == 152, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + expected = 152; + ok(stubMsg.BufferLength == expected || stubMsg.BufferLength == expected + 8, /* win64 */ + "size %u instead of %u\n", stubMsg.BufferLength, expected); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); - ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); + ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected); wirev = (DWORD*)buffer; - check_variant_header(wirev, &v, stubMsg.BufferLength); + check_variant_header(wirev, &v, expected); wirev += 5; ok(*wirev, "wv[5] %08x\n", *wirev); /* win2k: this is lpsa. winxp: this is (char*)lpsa + 1 */ wirev++; @@ -1063,7 +1169,7 @@ static void test_marshal_VARIANT(void) VariantInit(&v2); stubMsg.Buffer = buffer; next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2); - ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); + ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected); ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2)); ok(SafeArrayGetDim(V_ARRAY(&v)) == SafeArrayGetDim(V_ARRAY(&v)), "array dims differ\n"); SafeArrayGetLBound(V_ARRAY(&v), 1, &bound); @@ -1077,7 +1183,7 @@ static void test_marshal_VARIANT(void) ok(vt == vt2, "array vts differ %x %x\n", vt, vt2); VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** ARRAY BYREF ***/ VariantInit(&v); @@ -1085,14 +1191,16 @@ static void test_marshal_VARIANT(void) V_ARRAYREF(&v) = &lpsa; rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); - ok(stubMsg.BufferLength == 152, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + expected = 152; + ok(stubMsg.BufferLength == expected || stubMsg.BufferLength == expected + 16, /* win64 */ + "size %u instead of %u\n", stubMsg.BufferLength, expected); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); - ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); + ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected); wirev = (DWORD*)buffer; - check_variant_header(wirev, &v, stubMsg.BufferLength); + check_variant_header(wirev, &v, expected); wirev += 5; ok(*wirev == 4, "wv[5] %08x\n", *wirev); wirev++; @@ -1106,7 +1214,7 @@ static void test_marshal_VARIANT(void) VariantInit(&v2); stubMsg.Buffer = buffer; next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2); - ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength); + ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected); ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2)); ok(SafeArrayGetDim(*V_ARRAYREF(&v)) == SafeArrayGetDim(*V_ARRAYREF(&v)), "array dims differ\n"); SafeArrayGetLBound(*V_ARRAYREF(&v), 1, &bound); @@ -1120,7 +1228,7 @@ static void test_marshal_VARIANT(void) ok(vt == vt2, "array vts differ %x %x\n", vt, vt2); VARIANT_UserFree(&umcb.Flags, &v2); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); SafeArrayDestroy(lpsa); /*** VARIANT BYREF ***/ @@ -1133,7 +1241,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength == 64, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; memset(buffer, 0xcc, stubMsg.BufferLength); next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); @@ -1142,7 +1250,7 @@ static void test_marshal_VARIANT(void) check_variant_header(wirev, &v, stubMsg.BufferLength); wirev += 5; - ok(*wirev == 16, "wv[5] %08x\n", *wirev); + ok(*wirev == sizeof(VARIANT), "wv[5] %08x\n", *wirev); wirev++; ok(*wirev == ('U' | 's' << 8 | 'e' << 16 | 'r' << 24), "wv[6] %08x\n", *wirev); /* 'User' */ wirev++; @@ -1166,7 +1274,7 @@ static void test_marshal_VARIANT(void) ok(V_R8(V_VARIANTREF(&v)) == V_R8(V_VARIANTREF(&v3)), "r8s differ\n"); VARIANT_UserFree(&umcb.Flags, &v3); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** UNKNOWN ***/ heap_unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*heap_unknown)); @@ -1179,7 +1287,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength > 32, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; memset(buffer, 0xcc, stubMsg.BufferLength); next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); @@ -1209,14 +1317,12 @@ static void test_marshal_VARIANT(void) stubMsg.Buffer = buffer; next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3); ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3)); - ok(V_VT(V_VARIANTREF(&v)) == V_VT(V_VARIANTREF(&v3)), "vts differ %x %x\n", - V_VT(V_VARIANTREF(&v)), V_VT(V_VARIANTREF(&v3))); - ok(V_R8(V_VARIANTREF(&v)) == V_R8(V_VARIANTREF(&v3)), "r8s differ\n"); + ok(V_UNKNOWN(&v) == V_UNKNOWN(&v3), "got %p expect %p\n", V_UNKNOWN(&v), V_UNKNOWN(&v3)); VARIANT_UserFree(&umcb.Flags, &v3); ok(heap_unknown->refs == 1, "%d refcounts of IUnknown leaked\n", heap_unknown->refs - 1); IUnknown_Release((IUnknown *)heap_unknown); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); /*** UNKNOWN BYREF ***/ heap_unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*heap_unknown)); @@ -1229,7 +1335,7 @@ static void test_marshal_VARIANT(void) rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v); ok(stubMsg.BufferLength > 36, "size %d\n", stubMsg.BufferLength); - buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = HeapAlloc(GetProcessHeap(), 0, stubMsg.BufferLength); + buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer); stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength; memset(buffer, 0xcc, stubMsg.BufferLength); next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v); @@ -1266,7 +1372,7 @@ static void test_marshal_VARIANT(void) ok(heap_unknown->refs == 1, "%d refcounts of IUnknown leaked\n", heap_unknown->refs - 1); IUnknown_Release((IUnknown *)heap_unknown); } - HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, oldbuffer); } diff --git a/rostests/winetests/oleaut32/varformat.c b/rostests/winetests/oleaut32/varformat.c index f7c7c28bd8d..6833a278ed9 100644 --- a/rostests/winetests/oleaut32/varformat.c +++ b/rostests/winetests/oleaut32/varformat.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "windef.h" #include "winbase.h" @@ -42,6 +41,7 @@ static HMODULE hOleaut32; static HRESULT (WINAPI *pVarFormatNumber)(LPVARIANT,int,int,int,int,ULONG,BSTR*); static HRESULT (WINAPI *pVarFormat)(LPVARIANT,LPOLESTR,int,int,ULONG,BSTR*); +static HRESULT (WINAPI *pVarWeekdayName)(int,int,int,ULONG,BSTR*); /* Have I8/UI8 data type? */ #define HAVE_OLEAUT32_I8 HAVE_FUNC(VarI8FromI1) @@ -63,9 +63,11 @@ static inline int strcmpW( const WCHAR *str1, const WCHAR *str2 ) VariantInit(&v); V_VT(&v) = vt; val(&v) = 1; \ hres = pVarFormatNumber(&v,2,0,0,0,0,&str); \ ok(hres == S_OK, "VarFormatNumber (vt %d): returned %8x\n", vt, hres); \ - if (hres == S_OK) \ + if (hres == S_OK) { \ ok(str && strcmpW(str,szResult1) == 0, \ - "VarFormatNumber (vt %d): string different\n", vt) + "VarFormatNumber (vt %d): string different\n", vt); \ + SysFreeString(str); \ + } static void test_VarFormatNumber(void) { @@ -125,7 +127,7 @@ static void test_VarFormatNumber(void) static const char *szVarFmtFail = "VT %d|0x%04x Format %s: expected 0x%08x, '%s', got 0x%08x, '%s'\n"; #define VARFMT(vt,v,val,fmt,ret,str) do { \ - if (out) SysFreeString(out); out = NULL; \ + out = NULL; \ V_VT(&in) = (vt); v(&in) = val; \ if (fmt) MultiByteToWideChar(CP_ACP, 0, fmt, -1, buffW, sizeof(buffW)/sizeof(WCHAR)); \ hres = pVarFormat(&in,fmt ? buffW : NULL,fd,fw,flags,&out); \ @@ -134,6 +136,7 @@ static const char *szVarFmtFail = "VT %d|0x%04x Format %s: expected 0x%08x, '%s' ok(hres == ret && (FAILED(ret) || !strcmp(buff, str)), \ szVarFmtFail, \ (vt)&VT_TYPEMASK,(vt)&~VT_TYPEMASK,fmt?fmt:"",ret,str,hres,buff); \ + SysFreeString(out); \ } while(0) typedef struct tagFMTRES @@ -227,6 +230,7 @@ static const FMTDATERES VarFormat_date_results[] = static void test_VarFormat(void) { static const WCHAR szTesting[] = { 't','e','s','t','i','n','g','\0' }; + static const WCHAR szNum[] = { '3','9','6','9','7','.','1','1','\0' }; size_t i; WCHAR buffW[256]; char buff[256]; @@ -312,6 +316,10 @@ static void test_VarFormat(void) VARFMT(VT_BSTR,V_BSTR,bstrin,"<&&",S_OK,"testing"); VARFMT(VT_BSTR,V_BSTR,bstrin,"<&>&",S_OK,"testing"); SysFreeString(bstrin); + bstrin = SysAllocString(szNum); + todo_wine VARFMT(VT_BSTR,V_BSTR,bstrin,"hh:mm",S_OK,"02:38"); + todo_wine VARFMT(VT_BSTR,V_BSTR,bstrin,"mm-dd-yy",S_OK,"09-06-08"); + SysFreeString(bstrin); /* Numeric values are converted to strings then output */ VARFMT(VT_I1,V_I1,1,"<&>&",S_OK,"1"); @@ -320,9 +328,12 @@ static void test_VarFormat(void) VARFMT(VT_I4,V_I4,1,"000###",S_OK,"000001"); VARFMT(VT_I4,V_I4,1,"#00##00#0",S_OK,"00000001"); VARFMT(VT_I4,V_I4,1,"1#####0000",S_OK,"10001"); - todo_wine { VARFMT(VT_I4,V_I4,100000,"#,###,###,###",S_OK,"100,000"); - } + VARFMT(VT_I4,V_I4,1,"0,000,000,000",S_OK,"0,000,000,001"); + VARFMT(VT_I4,V_I4,123456789,"#,#.#",S_OK,"123,456,789."); + VARFMT(VT_I4,V_I4,123456789,"###, ###, ###",S_OK,"123, 456, 789"); + VARFMT(VT_I4,V_I4,1,"#;-#",S_OK,"1"); + VARFMT(VT_I4,V_I4,-1,"#;-#",S_OK,"-1"); VARFMT(VT_R8,V_R8,1.23456789,"0#.0#0#0#0#0",S_OK,"01.234567890"); VARFMT(VT_R8,V_R8,1.2,"0#.0#0#0#0#0",S_OK,"01.200000000"); VARFMT(VT_R8,V_R8,9.87654321,"#0.#0#0#0#0#",S_OK,"9.87654321"); @@ -364,6 +375,14 @@ static void test_VarFormat(void) VARFMT(VT_R8,V_R8,1.0001e-27,"##00.0000e-0",S_OK,"1000.1000e-30"); VARFMT(VT_R8,V_R8,47.11,".0000E+0",S_OK,".4711E+2"); VARFMT(VT_R8,V_R8,3.0401e-13,"#####.####e-0%",S_OK,"30401.e-15%"); + VARFMT(VT_R8,V_R8,1.57,"0.00",S_OK,"1.57"); + VARFMT(VT_R8,V_R8,-1.57,"0.00",S_OK,"-1.57"); + VARFMT(VT_R8,V_R8,-1.57,"#.##",S_OK,"-1.57"); + VARFMT(VT_R8,V_R8,-0.1,".#",S_OK,"-.1"); + VARFMT(VT_R8,V_R8,0.099,"#.#",S_OK,".1"); + VARFMT(VT_R8,V_R8,0.0999,"#.##",S_OK,".1"); + /* for large negative exponents, wine truncates instead of rounding */ + todo_wine VARFMT(VT_R8,V_R8,0.099,"#.##",S_OK,".1"); /* 'out' is not cleared */ @@ -392,10 +411,120 @@ static void test_VarFormat(void) VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,""); } +static const char *szVarWdnFail = + "VarWeekdayName (%d, %d, %d, %d, %x): returned %8x, expected %8x\n"; +#define VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, ret, buff, out, freeOut) \ +do { \ + hres = pVarWeekdayName(iWeekday, fAbbrev, iFirstDay, dwFlags, &out); \ + if (SUCCEEDED(hres)) { \ + WideCharToMultiByte(CP_ACP, 0, out, -1, buff, sizeof(buff), 0, 0); \ + if (freeOut) SysFreeString(out); \ + } else { \ + buff[0] = '\0'; \ + } \ + ok(hres == ret, \ + szVarWdnFail, \ + iWeekday, fAbbrev, iFirstDay, dwFlags, &out, hres, ret \ + ); \ +} while(0) + +#define VARWDN_F(iWeekday, fAbbrev, iFirstDay, dwFlags, ret) \ + VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, ret, buff, out, 1) + +#define VARWDN_O(iWeekday, fAbbrev, iFirstDay, dwFlags) \ + VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, S_OK, buff, out, 0) + +static void test_VarWeekdayName(void) +{ + char buff[256]; + BSTR out = NULL; + HRESULT hres; + int iWeekday, fAbbrev, iFirstDay; + BSTR dayNames[7][2]; /* Monday-Sunday, full/abbr */ + DWORD defaultFirstDay; + int firstDay; + int day; + int size; + DWORD localeValue; + + CHECKPTR(VarWeekdayName); + + SetLastError(0xdeadbeef); + GetLocaleInfoW(LOCALE_USER_DEFAULT, 0, NULL, 0); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetLocaleInfoW is not implemented\n"); + return; + } + + /* Initialize days' names */ + for (day = 0; day <= 6; ++day) + { + for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev) + { + localeValue = fAbbrev ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1; + localeValue += day; + size = GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue, NULL, 0); + dayNames[day][fAbbrev] = SysAllocStringLen(NULL, size - 1); + GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue, + dayNames[day][fAbbrev], size); + } + } + + /* Get the user's first day of week. 0=Monday, .. */ + GetLocaleInfoW( + LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK | LOCALE_RETURN_NUMBER, + (LPWSTR)&defaultFirstDay, sizeof(defaultFirstDay) / sizeof(WCHAR)); + + /* Check invalid arguments */ + VARWDN_F(0, 0, 4, 0, E_INVALIDARG); + VARWDN_F(8, 0, 4, 0, E_INVALIDARG); + VARWDN_F(4, 0, -1, 0, E_INVALIDARG); + VARWDN_F(4, 0, 8, 0, E_INVALIDARG); + + hres = pVarWeekdayName(1, 0, 0, 0, NULL); + ok(E_INVALIDARG == hres, + "Null pointer: expected E_INVALIDARG, got 0x%08x\n", hres); + + /* Check all combinations */ + for (iWeekday = 1; iWeekday <= 7; ++iWeekday) + { + for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev) + { + /* 0 = Default, 1 = Sunday, 2 = Monday, .. */ + for (iFirstDay = 0; iFirstDay <= 7; ++iFirstDay) + { + VARWDN_O(iWeekday, fAbbrev, iFirstDay, 0); + if (iFirstDay == 0) + firstDay = defaultFirstDay; + else + /* Translate from 0=Sunday to 0=Monday in the modulo 7 space */ + firstDay = iFirstDay - 2; + day = (7 + iWeekday - 1 + firstDay) % 7; + ok(VARCMP_EQ == VarBstrCmp(out, dayNames[day][fAbbrev], + LOCALE_USER_DEFAULT, 0), + "VarWeekdayName(%d,%d,%d): got wrong dayname: '%s'\n", + iWeekday, fAbbrev, iFirstDay, buff); + SysFreeString(out); + } + } + } + + /* Cleanup */ + for (day = 0; day <= 6; ++day) + { + for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev) + { + SysFreeString(dayNames[day][fAbbrev]); + } + } +} + START_TEST(varformat) { hOleaut32 = GetModuleHandleA("oleaut32.dll"); test_VarFormatNumber(); test_VarFormat(); + test_VarWeekdayName(); } diff --git a/rostests/winetests/oleaut32/vartest.c b/rostests/winetests/oleaut32/vartest.c index fd95361b4e8..d6aa979cd35 100644 --- a/rostests/winetests/oleaut32/vartest.c +++ b/rostests/winetests/oleaut32/vartest.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "windef.h" #include "winbase.h" @@ -47,6 +46,11 @@ static INT (WINAPI *pVariantTimeToSystemTime)(double,LPSYSTEMTIME); static INT (WINAPI *pDosDateTimeToVariantTime)(USHORT,USHORT,double*); static INT (WINAPI *pVariantTimeToDosDateTime)(double,USHORT*,USHORT *); +static const WCHAR sz12[] = {'1','2','\0'}; +/* the strings are localized */ +static WCHAR sz12_false[32]; +static WCHAR sz12_true[32]; + /* Get a conversion function ptr, return if function not available */ #define CHECKPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func); \ if (!p##func) { trace("function " # func " not available, not testing it\n"); return; } @@ -96,6 +100,24 @@ static int IS_ANCIENT = 0; static void init(void) { + BSTR bstr; + HRESULT res; + + res = VarBstrFromBool(VARIANT_TRUE, LANG_USER_DEFAULT, VAR_LOCALBOOL, &bstr); + ok(SUCCEEDED(res) && (lstrlenW(bstr) > 0), + "Expected localized string for 'True'\n"); + /* lstrcpyW / lstrcatW do not work on win95 */ + memcpy(sz12_true, sz12, sizeof(sz12)); + if (bstr) memcpy(&sz12_true[2], bstr, SysStringByteLen(bstr) + sizeof(WCHAR)); + SysFreeString(bstr); + + res = VarBstrFromBool(VARIANT_FALSE, LANG_USER_DEFAULT, VAR_LOCALBOOL, &bstr); + ok(SUCCEEDED(res) && (lstrlenW(bstr) > 0), + "Expected localized string for 'False'\n"); + memcpy(sz12_false, sz12, sizeof(sz12)); + if (bstr) memcpy(&sz12_false[2], bstr, SysStringByteLen(bstr) + sizeof(WCHAR)); + SysFreeString(bstr); + hOleaut32 = GetModuleHandle("oleaut32.dll"); /* Is a given function exported from oleaut32? */ @@ -298,6 +320,7 @@ static void test_var_call1( int line, HRESULT (WINAPI *func)(LPVARIANT,LPVARIANT "got %s expected %s\n", variantstr(&result), variantstr(expected) ); ok_(__FILE__,line)( is_expected_variant( arg, &old_arg ), "Modified argument %s / %s\n", variantstr(&old_arg), variantstr(arg)); + VariantClear( &result ); } static void test_var_call2( int line, HRESULT (WINAPI *func)(LPVARIANT,LPVARIANT,LPVARIANT), @@ -317,6 +340,7 @@ static void test_var_call2( int line, HRESULT (WINAPI *func)(LPVARIANT,LPVARIANT variantstr(&old_left), variantstr(left)); ok_(__FILE__,line)( is_expected_variant( right, &old_right ), "Modified right argument %s / %s\n", variantstr(&old_right), variantstr(right)); + VariantClear( &result ); } @@ -621,11 +645,14 @@ static void test_VariantCopy(void) "Copy(bad src): expected 0x%X, got 0x%X for src vt %d|0x%X\n", hExpected, hres, vt, ExtraFlags[i]); if (hres == S_OK) + { ok(V_VT(&vDst) == (vt|ExtraFlags[i]), "Copy(bad src): expected vt = %d, got %d\n", vt | ExtraFlags[i], V_VT(&vDst)); + VariantClear(&vDst); } } + } /* Test that copying a NULL BSTR results in an empty BSTR */ memset(&vDst, 0, sizeof(vDst)); @@ -642,6 +669,7 @@ static void test_VariantCopy(void) { ok(*V_BSTR(&vDst) == 0, "Copy(NULL BSTR): result not empty\n"); } + VariantClear(&vDst); } } @@ -813,6 +841,7 @@ static void test_VariantCopyInd(void) vt, ExtraFlags[i] & ~VT_BYREF, V_VT(&vDst) & VT_TYPEMASK, V_VT(&vDst) & ~VT_TYPEMASK); } + VariantClear(&vDst); } } } @@ -1050,7 +1079,7 @@ static void test_VarParseNumFromStr(void) EXPECT(1,NUMPRS_HEX_OCT,0,1,0,0); EXPECT2(0,FAILDIG); - /* Doesn't recognise hex in .asm sytax */ + /* Doesn't recognise hex in .asm syntax */ CONVERT("0h", NUMPRS_HEX_OCT); EXPECT(1,NUMPRS_HEX_OCT,0,1,0,0); EXPECT2(0,FAILDIG); @@ -1060,7 +1089,7 @@ static void test_VarParseNumFromStr(void) EXPECT(1,NUMPRS_HEX_OCT,0,1,0,0); EXPECT2(0,FAILDIG); - /* Doesn't recognise hex format humbers at all! */ + /* Doesn't recognise hex format numbers at all! */ CONVERT("0x0", NUMPRS_HEX_OCT); EXPECT(1,NUMPRS_HEX_OCT,0,1,0,0); EXPECT2(0,FAILDIG); @@ -2001,7 +2030,6 @@ static HRESULT (WINAPI *pVarSub)(LPVARIANT,LPVARIANT,LPVARIANT); static void test_VarSub(void) { - static const WCHAR sz12[] = {'1','2','\0'}; VARIANT left, right, exp, result, cy, dec; VARTYPE i; BSTR lbstr, rbstr; @@ -2078,7 +2106,12 @@ static void test_VarSub(void) leftvt == VT_RECORD || rightvt == VT_RECORD) { if (leftvt == VT_RECORD && rightvt == VT_I8) + { + if (HAVE_OLEAUT32_I8) expectedhres = DISP_E_TYPEMISMATCH; + else + expectedhres = DISP_E_BADVARTYPE; + } else if (leftvt < VT_UI1 && rightvt == VT_RECORD) expectedhres = DISP_E_TYPEMISMATCH; else if (leftvt >= VT_UI1 && rightvt == VT_RECORD) @@ -2726,6 +2759,9 @@ static void test_VarMod(void) hres = pVarMod(&v1,&v2,&vDst); ok(hres == DISP_E_BADVARTYPE && V_VT(&vDst) == VT_EMPTY, "VarMod: expected 0x%x,%d, got 0x%X,%d\n", DISP_E_BADVARTYPE, VT_EMPTY, hres, V_VT(&vDst)); + + SysFreeString(strNum0); + SysFreeString(strNum1); } static HRESULT (WINAPI *pVarFix)(LPVARIANT,LPVARIANT); @@ -2824,7 +2860,7 @@ static void test_VarFix(void) S1(U1(*pdec)).Mid32 = 0; S1(U1(*pdec)).Lo32 = 1; hres = pVarFix(&v,&vDst); - ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL && !memcmp(&v, &vDst, sizeof(v)), + ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL && !memcmp(&V_DECIMAL(&v), &V_DECIMAL(&vDst), sizeof(DECIMAL)), "VarFix: expected 0x0,%d,identical, got 0x%X,%d\n", VT_DECIMAL, hres, V_VT(&vDst)); @@ -2939,7 +2975,7 @@ static void test_VarInt(void) S1(U1(*pdec)).Mid32 = 0; S1(U1(*pdec)).Lo32 = 1; hres = pVarInt(&v,&vDst); - ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL && !memcmp(&v, &vDst, sizeof(v)), + ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL && !memcmp(&V_DECIMAL(&v), &V_DECIMAL(&vDst), sizeof(DECIMAL)), "VarInt: expected 0x0,%d,identical, got 0x%X,%d\n", VT_DECIMAL, hres, V_VT(&vDst)); @@ -3104,8 +3140,8 @@ static void test_Round( int line, VARIANT *arg, int deci, VARIANT *expected ) static void test_VarRound(void) { - static WCHAR szNumMin[] = {'-','1','.','4','5','\0' }; - static WCHAR szNum[] = {'1','.','4','5','\0' }; + static WCHAR szNumMin[] = {'-','1','.','4','4','9','\0' }; + static WCHAR szNum[] = {'1','.','4','5','1','\0' }; HRESULT hres; VARIANT v, exp, vDst; CY *pcy = &V_CY(&v); @@ -3140,7 +3176,7 @@ static void test_VarRound(void) /* floating point numbers aren't exactly equal and we can't just * compare the first few digits. */ VARROUND(DATE,1.451,1,DATE,1.5); - VARROUND(DATE,-1.45,1,DATE,-1.4); + VARROUND(DATE,-1.449,1,DATE,-1.4); /* replace the decimal separator */ GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buff, sizeof(buff)/sizeof(char)); @@ -3148,7 +3184,7 @@ static void test_VarRound(void) szNumMin[2] = buff[0]; szNum[1] = buff[0]; VARROUND(BSTR,(BSTR)szNumMin,1,R8,-1.40); - if (0) { VARROUND(BSTR,(BSTR)szNum,1,R8,1.50); } + VARROUND(BSTR,(BSTR)szNum,1,R8,1.50); } else { skip("Skipping VarRound(BSTR) as decimal separator is '%s'\n", buff); } @@ -3381,9 +3417,11 @@ static void test_VarXor(void) VARXOR(EMPTY,0,R8,1,I4,1); rbstr = SysAllocString(szFalse); VARXOR(EMPTY,0,BSTR,rbstr,I2,0); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(EMPTY,0,BSTR,rbstr,I2,-1); VARXORCY(EMPTY,0,10000,I4,1); + SysFreeString(rbstr); /* NULL OR 0 = NULL. NULL OR n = n */ VARXOR(NULL,0,NULL,0,NULL,0); @@ -3419,8 +3457,10 @@ static void test_VarXor(void) VARXOR(NULL,0,R8,1,NULL,0); rbstr = SysAllocString(szFalse); VARXOR(NULL,0,BSTR,rbstr,NULL,0); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(NULL,0,BSTR,rbstr,NULL,0); + SysFreeString(rbstr); VARXORCY(NULL,0,10000,NULL,0); VARXORCY(NULL,0,0,NULL,0); @@ -3477,9 +3517,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(BOOL,VARIANT_FALSE,BSTR,rbstr,BOOL,VARIANT_FALSE); VARXOR(BOOL,VARIANT_TRUE,BSTR,rbstr,BOOL,VARIANT_TRUE); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(BOOL,VARIANT_FALSE,BSTR,rbstr,BOOL,VARIANT_TRUE); VARXOR(BOOL,VARIANT_TRUE,BSTR,rbstr,BOOL,VARIANT_FALSE); + SysFreeString(rbstr); VARXORCY(BOOL,VARIANT_TRUE,10000,I4,-2); VARXORCY(BOOL,VARIANT_TRUE,0,I4,-1); VARXORCY(BOOL,VARIANT_FALSE,0,I4,0); @@ -3528,9 +3570,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(I1,0,BSTR,rbstr,I4,0); VARXOR(I1,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(I1,0,BSTR,rbstr,I4,-1); VARXOR(I1,-1,BSTR,rbstr,I4,0); + SysFreeString(rbstr); VARXORCY(I1,-1,10000,I4,-2); VARXORCY(I1,-1,0,I4,-1); VARXORCY(I1,0,0,I4,0); @@ -3576,9 +3620,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(UI1,0,BSTR,rbstr,I2,0); VARXOR(UI1,255,BSTR,rbstr,I2,255); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(UI1,0,BSTR,rbstr,I2,-1); VARXOR(UI1,255,BSTR,rbstr,I2,-256); + SysFreeString(rbstr); VARXORCY(UI1,255,10000,I4,254); VARXORCY(UI1,255,0,I4,255); VARXORCY(UI1,0,0,I4,0); @@ -3621,9 +3667,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(I2,0,BSTR,rbstr,I2,0); VARXOR(I2,-1,BSTR,rbstr,I2,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(I2,0,BSTR,rbstr,I2,-1); VARXOR(I2,-1,BSTR,rbstr,I2,0); + SysFreeString(rbstr); VARXORCY(I2,-1,10000,I4,-2); VARXORCY(I2,-1,0,I4,-1); VARXORCY(I2,0,0,I4,0); @@ -3663,9 +3711,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(UI2,0,BSTR,rbstr,I4,0); VARXOR(UI2,65535,BSTR,rbstr,I4,65535); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(UI2,0,BSTR,rbstr,I4,-1); VARXOR(UI2,65535,BSTR,rbstr,I4,-65536); + SysFreeString(rbstr); VARXORCY(UI2,65535,10000,I4,65534); VARXORCY(UI2,65535,0,I4,65535); VARXORCY(UI2,0,0,I4,0); @@ -3702,9 +3752,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(I4,0,BSTR,rbstr,I4,0); VARXOR(I4,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(I4,0,BSTR,rbstr,I4,-1); VARXOR(I4,-1,BSTR,rbstr,I4,0); + SysFreeString(rbstr); VARXORCY(I4,-1,10000,I4,-2); VARXORCY(I4,-1,0,I4,-1); VARXORCY(I4,0,0,I4,0); @@ -3738,9 +3790,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(UI4,0,BSTR,rbstr,I4,0); VARXOR(UI4,0xffffffff,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(UI4,0,BSTR,rbstr,I4,-1); VARXOR(UI4,0xffffffff,BSTR,rbstr,I4,0); + SysFreeString(rbstr); VARXORCY(UI4,0xffffffff,10000,I4,-2); VARXORCY(UI4,0xffffffff,0,I4,-1); VARXORCY(UI4,0,0,I4,0); @@ -3771,9 +3825,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(R4,0,BSTR,rbstr,I4,0); VARXOR(R4,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(R4,0,BSTR,rbstr,I4,-1); VARXOR(R4,-1,BSTR,rbstr,I4,0); + SysFreeString(rbstr); VARXORCY(R4,-1,10000,I4,-2); VARXORCY(R4,-1,0,I4,-1); VARXORCY(R4,0,0,I4,0); @@ -3801,9 +3857,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(R8,0,BSTR,rbstr,I4,0); VARXOR(R8,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(R8,0,BSTR,rbstr,I4,-1); VARXOR(R8,-1,BSTR,rbstr,I4,0); + SysFreeString(rbstr); VARXORCY(R8,-1,10000,I4,-2); VARXORCY(R8,-1,0,I4,-1); VARXORCY(R8,0,0,I4,0); @@ -3828,9 +3886,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(DATE,0,BSTR,rbstr,I4,0); VARXOR(DATE,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(DATE,0,BSTR,rbstr,I4,-1); VARXOR(DATE,-1,BSTR,rbstr,I4,0); + SysFreeString(rbstr); VARXORCY(DATE,-1,10000,I4,-2); VARXORCY(DATE,-1,0,I4,-1); VARXORCY(DATE,0,0,I4,0); @@ -3847,9 +3907,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(I8,0,BSTR,rbstr,I8,0); VARXOR(I8,-1,BSTR,rbstr,I8,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(I8,0,BSTR,rbstr,I8,-1); VARXOR(I8,-1,BSTR,rbstr,I8,0); + SysFreeString(rbstr); VARXORCY(I8,-1,10000,I8,-2); VARXORCY(I8,-1,0,I8,-1); VARXORCY(I8,0,0,I8,0); @@ -3866,9 +3928,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(UI8,0,BSTR,rbstr,I4,0); VARXOR(UI8,0xffff,BSTR,rbstr,I4,0xffff); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(UI8,0,BSTR,rbstr,I4,-1); VARXOR(UI8,0xffff,BSTR,rbstr,I4,-65536); + SysFreeString(rbstr); VARXORCY(UI8,0xffff,10000,I4,65534); VARXORCY(UI8,0xffff,0,I4,0xffff); VARXORCY(UI8,0,0,I4,0); @@ -3883,9 +3947,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(INT,0,BSTR,rbstr,I4,0); VARXOR(INT,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(INT,0,BSTR,rbstr,I4,-1); VARXOR(INT,-1,BSTR,rbstr,I4,0); + SysFreeString(rbstr); VARXORCY(INT,-1,10000,I4,-2); VARXORCY(INT,-1,0,I4,-1); VARXORCY(INT,0,0,I4,0); @@ -3896,9 +3962,11 @@ static void test_VarXor(void) rbstr = SysAllocString(szFalse); VARXOR(UINT,0,BSTR,rbstr,I4,0); VARXOR(UINT,0xffff,BSTR,rbstr,I4,0xffff); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(UINT,0,BSTR,rbstr,I4,-1); VARXOR(UINT,0xffff,BSTR,rbstr,I4,-65536); + SysFreeString(rbstr); VARXORCY(UINT,0xffff,10000,I4,65534); VARXORCY(UINT,0xffff,0,I4,0xffff); VARXORCY(UINT,0,0,I4,0); @@ -3906,13 +3974,18 @@ static void test_VarXor(void) lbstr = SysAllocString(szFalse); rbstr = SysAllocString(szFalse); VARXOR(BSTR,lbstr,BSTR,rbstr,BOOL,0); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VARXOR(BSTR,lbstr,BSTR,rbstr,BOOL,VARIANT_TRUE); + SysFreeString(lbstr); lbstr = SysAllocString(szTrue); VARXOR(BSTR,lbstr,BSTR,rbstr,BOOL,VARIANT_FALSE); VARXORCY(BSTR,lbstr,10000,I4,-2); + SysFreeString(lbstr); lbstr = SysAllocString(szFalse); VARXORCY(BSTR,lbstr,10000,I4,1); + SysFreeString(lbstr); + SysFreeString(rbstr); } static HRESULT (WINAPI *pVarOr)(LPVARIANT,LPVARIANT,LPVARIANT); @@ -4080,8 +4153,10 @@ static void test_VarOr(void) VAROR(EMPTY,0,R8,1,I4,1); rbstr = SysAllocString(szFalse); VAROR(EMPTY,0,BSTR,rbstr,I2,0); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(EMPTY,0,BSTR,rbstr,I2,-1); + SysFreeString(rbstr); VARORCY(EMPTY,0,10000,I4,1); /* NULL OR 0 = NULL. NULL OR n = n */ @@ -4118,8 +4193,10 @@ static void test_VarOr(void) VAROR(NULL,0,R8,1,I4,1); rbstr = SysAllocString(szFalse); VAROR(NULL,0,BSTR,rbstr,NULL,0); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(NULL,0,BSTR,rbstr,BOOL,VARIANT_TRUE); + SysFreeString(rbstr); VARORCY(NULL,0,10000,I4,1); VARORCY(NULL,0,0,NULL,0); @@ -4176,9 +4253,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(BOOL,VARIANT_FALSE,BSTR,rbstr,BOOL,VARIANT_FALSE); VAROR(BOOL,VARIANT_TRUE,BSTR,rbstr,BOOL,VARIANT_TRUE); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(BOOL,VARIANT_FALSE,BSTR,rbstr,BOOL,VARIANT_TRUE); VAROR(BOOL,VARIANT_TRUE,BSTR,rbstr,BOOL,VARIANT_TRUE); + SysFreeString(rbstr); VARORCY(BOOL,VARIANT_TRUE,10000,I4,-1); VARORCY(BOOL,VARIANT_TRUE,0,I4,-1); VARORCY(BOOL,VARIANT_FALSE,0,I4,0); @@ -4227,9 +4306,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(I1,0,BSTR,rbstr,I4,0); VAROR(I1,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(I1,0,BSTR,rbstr,I4,-1); VAROR(I1,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(I1,-1,10000,I4,-1); VARORCY(I1,-1,0,I4,-1); VARORCY(I1,0,0,I4,0); @@ -4275,9 +4356,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(UI1,0,BSTR,rbstr,I2,0); VAROR(UI1,255,BSTR,rbstr,I2,255); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(UI1,0,BSTR,rbstr,I2,-1); VAROR(UI1,255,BSTR,rbstr,I2,-1); + SysFreeString(rbstr); VARORCY(UI1,255,10000,I4,255); VARORCY(UI1,255,0,I4,255); VARORCY(UI1,0,0,I4,0); @@ -4320,9 +4403,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(I2,0,BSTR,rbstr,I2,0); VAROR(I2,-1,BSTR,rbstr,I2,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(I2,0,BSTR,rbstr,I2,-1); VAROR(I2,-1,BSTR,rbstr,I2,-1); + SysFreeString(rbstr); VARORCY(I2,-1,10000,I4,-1); VARORCY(I2,-1,0,I4,-1); VARORCY(I2,0,0,I4,0); @@ -4362,9 +4447,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(UI2,0,BSTR,rbstr,I4,0); VAROR(UI2,65535,BSTR,rbstr,I4,65535); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(UI2,0,BSTR,rbstr,I4,-1); VAROR(UI2,65535,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(UI2,65535,10000,I4,65535); VARORCY(UI2,65535,0,I4,65535); VARORCY(UI2,0,0,I4,0); @@ -4401,9 +4488,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(I4,0,BSTR,rbstr,I4,0); VAROR(I4,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(I4,0,BSTR,rbstr,I4,-1); VAROR(I4,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(I4,-1,10000,I4,-1); VARORCY(I4,-1,0,I4,-1); VARORCY(I4,0,0,I4,0); @@ -4437,9 +4526,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(UI4,0,BSTR,rbstr,I4,0); VAROR(UI4,0xffffffff,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(UI4,0,BSTR,rbstr,I4,-1); VAROR(UI4,0xffffffff,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(UI4,0xffffffff,10000,I4,-1); VARORCY(UI4,0xffffffff,0,I4,-1); VARORCY(UI4,0,0,I4,0); @@ -4470,9 +4561,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(R4,0,BSTR,rbstr,I4,0); VAROR(R4,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(R4,0,BSTR,rbstr,I4,-1); VAROR(R4,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(R4,-1,10000,I4,-1); VARORCY(R4,-1,0,I4,-1); VARORCY(R4,0,0,I4,0); @@ -4500,9 +4593,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(R8,0,BSTR,rbstr,I4,0); VAROR(R8,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(R8,0,BSTR,rbstr,I4,-1); VAROR(R8,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(R8,-1,10000,I4,-1); VARORCY(R8,-1,0,I4,-1); VARORCY(R8,0,0,I4,0); @@ -4527,9 +4622,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(DATE,0,BSTR,rbstr,I4,0); VAROR(DATE,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(DATE,0,BSTR,rbstr,I4,-1); VAROR(DATE,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(DATE,-1,10000,I4,-1); VARORCY(DATE,-1,0,I4,-1); VARORCY(DATE,0,0,I4,0); @@ -4551,9 +4648,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(I8,0,BSTR,rbstr,I8,0); VAROR(I8,-1,BSTR,rbstr,I8,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(I8,0,BSTR,rbstr,I8,-1); VAROR(I8,-1,BSTR,rbstr,I8,-1); + SysFreeString(rbstr); VARORCY(I8,-1,10000,I8,-1); VARORCY(I8,-1,0,I8,-1); VARORCY(I8,0,0,I8,0); @@ -4570,9 +4669,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(UI8,0,BSTR,rbstr,I4,0); VAROR(UI8,0xffff,BSTR,rbstr,I4,0xffff); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(UI8,0,BSTR,rbstr,I4,-1); VAROR(UI8,0xffff,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(UI8,0xffff,10000,I4,0xffff); VARORCY(UI8,0xffff,0,I4,0xffff); VARORCY(UI8,0,0,I4,0); @@ -4587,9 +4688,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(INT,0,BSTR,rbstr,I4,0); VAROR(INT,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(INT,0,BSTR,rbstr,I4,-1); VAROR(INT,-1,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(INT,-1,10000,I4,-1); VARORCY(INT,-1,0,I4,-1); VARORCY(INT,0,0,I4,0); @@ -4600,9 +4703,11 @@ static void test_VarOr(void) rbstr = SysAllocString(szFalse); VAROR(UINT,0,BSTR,rbstr,I4,0); VAROR(UINT,0xffff,BSTR,rbstr,I4,0xffff); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(UINT,0,BSTR,rbstr,I4,-1); VAROR(UINT,0xffff,BSTR,rbstr,I4,-1); + SysFreeString(rbstr); VARORCY(UINT,0xffff,10000,I4,0xffff); VARORCY(UINT,0xffff,0,I4,0xffff); VARORCY(UINT,0,0,I4,0); @@ -4610,13 +4715,18 @@ static void test_VarOr(void) lbstr = SysAllocString(szFalse); rbstr = SysAllocString(szFalse); VAROR(BSTR,lbstr,BSTR,rbstr,BOOL,0); + SysFreeString(rbstr); rbstr = SysAllocString(szTrue); VAROR(BSTR,lbstr,BSTR,rbstr,BOOL,VARIANT_TRUE); + SysFreeString(lbstr); lbstr = SysAllocString(szTrue); VAROR(BSTR,lbstr,BSTR,rbstr,BOOL,VARIANT_TRUE); VARORCY(BSTR,lbstr,10000,I4,-1); + SysFreeString(lbstr); lbstr = SysAllocString(szFalse); VARORCY(BSTR,lbstr,10000,I4,1); + SysFreeString(lbstr); + SysFreeString(rbstr); } static HRESULT (WINAPI *pVarEqv)(LPVARIANT,LPVARIANT,LPVARIANT); @@ -4768,7 +4878,6 @@ static HRESULT (WINAPI *pVarMul)(LPVARIANT,LPVARIANT,LPVARIANT); static void test_VarMul(void) { - static const WCHAR sz12[] = {'1','2','\0'}; VARIANT left, right, exp, result, cy, dec; VARTYPE i; BSTR lbstr, rbstr; @@ -4940,7 +5049,6 @@ static HRESULT (WINAPI *pVarAdd)(LPVARIANT,LPVARIANT,LPVARIANT); static void test_VarAdd(void) { - static const WCHAR sz12[] = {'1','2','\0'}; VARIANT left, right, exp, result, cy, dec; VARTYPE i; BSTR lbstr, rbstr; @@ -5049,6 +5157,8 @@ static void test_VarAdd(void) leftvt, ExtraFlags[i], rightvt, ExtraFlags[i], resvt, hres, V_VT(&result)); } + /* Note, we don't clear left/right deliberately here */ + VariantClear(&result); } } } @@ -5090,6 +5200,7 @@ static void test_VarAdd(void) ok(hres == S_OK && V_VT(&result) == VT_BSTR, "VarAdd: expected coerced type VT_BSTR, got %s!\n", vtstr(V_VT(&result))); hres = VarR8FromStr(V_BSTR(&result), 0, 0, &r); ok(hres == S_OK && EQ_DOUBLE(r, 1212), "VarAdd: BSTR value %f, expected %f\n", r, (double)1212); + VariantClear(&result); /* Manuly test some VT_CY and VT_DECIMAL variants */ V_VT(&cy) = VT_CY; @@ -5114,6 +5225,7 @@ static void test_VarAdd(void) ok(hres == S_OK && V_VT(&result) == VT_DECIMAL, "VarAdd: expected coerced type VT_DECIMAL, got %s!\n", vtstr(V_VT(&result))); hres = VarR8FromDec(&V_DECIMAL(&result), &r); ok(hres == S_OK && EQ_DOUBLE(r, -15.2), "VarAdd: DECIMAL value %f, expected %f\n", r, (double)-15.2); + VariantClear(&result); SysFreeString(lbstr); SysFreeString(rbstr); @@ -5122,15 +5234,14 @@ static void test_VarAdd(void) static void test_VarCat(void) { LCID lcid; - VARIANT left, right, result, expected; - static const WCHAR sz12[] = {'1','2','\0'}; + VARIANT left, right, result, expected, expected_broken; static const WCHAR sz34[] = {'3','4','\0'}; static const WCHAR sz1234[] = {'1','2','3','4','\0'}; static const WCHAR date_sz12[] = {'9','/','3','0','/','1','9','8','0','1','2','\0'}; + static const WCHAR date_sz12_broken[] = {'9','/','3','0','/','8','0','1','2','\0'}; static const WCHAR sz12_date[] = {'1','2','9','/','3','0','/','1','9','8','0','\0'}; + static const WCHAR sz12_date_broken[] = {'1','2','9','/','3','0','/','8','0','\0'}; static const WCHAR sz_empty[] = {'\0'}; - static const WCHAR sz12_true[] = {'1','2','T','r','u','e','\0'}; - static const WCHAR sz12_false[] = {'1','2','F','a','l','s','e','\0'}; TCHAR orig_date_format[128]; VARTYPE leftvt, rightvt, resultvt; HRESULT hres; @@ -5230,18 +5341,27 @@ static void test_VarCat(void) V_VT(&left) = leftvt; V_VT(&right) = rightvt; - if (leftvt == VT_BSTR) - V_BSTR(&left) = SysAllocString(sz_empty); - if (rightvt == VT_BSTR) - V_BSTR(&right) = SysAllocString(sz_empty); - if (leftvt == VT_DATE) - V_DATE(&left) = 0.0; - if (rightvt == VT_DATE) - V_DATE(&right) = 0.0; - if (leftvt == VT_DECIMAL) - VarDecFromR8(0.0, &V_DECIMAL(&left)); - if (rightvt == VT_DECIMAL) - VarDecFromR8(0.0, &V_DECIMAL(&right)); + switch (leftvt) { + case VT_BSTR: + V_BSTR(&left) = SysAllocString(sz_empty); break; + case VT_DATE: + V_DATE(&left) = 0.0; break; + case VT_DECIMAL: + VarDecFromR8(0.0, &V_DECIMAL(&left)); break; + default: + V_I8(&left) = 0; + } + + switch (rightvt) { + case VT_BSTR: + V_BSTR(&right) = SysAllocString(sz_empty); break; + case VT_DATE: + V_DATE(&right) = 0.0; break; + case VT_DECIMAL: + VarDecFromR8(0.0, &V_DECIMAL(&right)); break; + default: + V_I8(&right) = 0; + } hres = VarCat(&left, &right, &result); @@ -5261,7 +5381,7 @@ static void test_VarCat(void) } } - /* Runnning single comparison tests to compare outputs */ + /* Running single comparison tests to compare outputs */ /* Test concat strings */ V_VT(&left) = VT_BSTR; @@ -5314,8 +5434,9 @@ static void test_VarCat(void) V_BSTR(&expected) = SysAllocString(sz12_true); hres = VarCat(&left,&right,&result); ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres); - ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, - "VarCat: VT_INT concat with VT_BOOL (TRUE) returned incorrect result\n"); + hres = VarCmp(&result,&expected,lcid,0); + ok(hres == VARCMP_EQ, "Expected VARCMP_EQ, got %08x for %s, %s\n", + hres, variantstr(&result), variantstr(&expected)); VariantClear(&left); VariantClear(&right); @@ -5330,8 +5451,9 @@ static void test_VarCat(void) V_BSTR(&expected) = SysAllocString(sz12_false); hres = VarCat(&left,&right,&result); ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres); - ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, - "VarCat: VT_INT concat with VT_BOOL (FALSE) returned inncorrect result\n"); + hres = VarCmp(&result,&expected,lcid,0); + ok(hres == VARCMP_EQ, "Expected VARCMP_EQ, got %08x for %s, %s\n", + hres, variantstr(&result), variantstr(&expected)); VariantClear(&left); VariantClear(&right); @@ -5348,7 +5470,7 @@ static void test_VarCat(void) hres = VarCat(&left,&right,&result); ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres); ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, - "VarCat: NUMBER concat with NUMBER returned inncorrect result\n"); + "VarCat: NUMBER concat with NUMBER returned incorrect result\n"); VariantClear(&left); VariantClear(&right); @@ -5362,7 +5484,7 @@ static void test_VarCat(void) hres = VarCat(&left,&right,&result); ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres); ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, - "VarCat: NUMBER concat with VT_BSTR, inncorrect result\n"); + "VarCat: NUMBER concat with VT_BSTR, incorrect result\n"); VariantClear(&left); VariantClear(&right); @@ -5375,44 +5497,53 @@ static void test_VarCat(void) hres = VarCat(&left,&right,&result); ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres); ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, - "VarCat: VT_BSTR concat with NUMBER, inncorrect result\n"); + "VarCat: VT_BSTR concat with NUMBER, incorrect result\n"); VariantClear(&left); VariantClear(&right); VariantClear(&result); + VariantClear(&expected); /* Test concat dates with strings */ V_VT(&left) = VT_BSTR; V_VT(&right) = VT_DATE; V_VT(&expected) = VT_BSTR; + V_VT(&expected_broken) = VT_BSTR; V_BSTR(&left) = SysAllocString(sz12); V_DATE(&right) = 29494.0; V_BSTR(&expected)= SysAllocString(sz12_date); + V_BSTR(&expected_broken)= SysAllocString(sz12_date_broken); hres = VarCat(&left,&right,&result); ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres); - ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, - "VarCat: VT_BSTR concat with VT_DATE returned inncorrect result\n"); + ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ || + broken(VarCmp(&result,&expected_broken,lcid,0) == VARCMP_EQ), /* Some W98 and NT4 (intermittent) */ + "VarCat: VT_BSTR concat with VT_DATE returned incorrect result\n"); VariantClear(&left); VariantClear(&right); VariantClear(&result); VariantClear(&expected); + VariantClear(&expected_broken); V_VT(&left) = VT_DATE; V_VT(&right) = VT_BSTR; V_VT(&expected) = VT_BSTR; + V_VT(&expected_broken) = VT_BSTR; V_DATE(&left) = 29494.0; V_BSTR(&right) = SysAllocString(sz12); V_BSTR(&expected)= SysAllocString(date_sz12); + V_BSTR(&expected_broken)= SysAllocString(date_sz12_broken); hres = VarCat(&left,&right,&result); ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres); - ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, - "VarCat: VT_DATE concat with VT_BSTR returned inncorrect result\n"); + ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ || + broken(VarCmp(&result,&expected_broken,lcid,0) == VARCMP_EQ), /* Some W98 and NT4 (intermittent) */ + "VarCat: VT_DATE concat with VT_BSTR returned incorrect result\n"); VariantClear(&left); VariantClear(&right); VariantClear(&result); VariantClear(&expected); + VariantClear(&expected_broken); /* Test of both expressions are empty */ V_VT(&left) = VT_BSTR; @@ -6273,7 +6404,7 @@ static void test_VarCmp(void) } } - /* VARCMP{,EX} run each 4 tests with a permutation of all posible + /* VARCMP{,EX} run each 4 tests with a permutation of all possible input variants with (1) and without (0) VT_RESERVED set. The order of the permutations is (0,0); (1,0); (0,1); (1,1) */ VARCMP(INT,4711,I2,4711,VARCMP_EQ); @@ -6859,11 +6990,20 @@ static void test_VarPow(void) "VARPOW: CY value %f, expected %f\n", V_R8(&result), 4.0); hres = pVarPow(&cy, &right, &result); + if (hres == S_OK) + { ok(hres == S_OK && V_VT(&result) == VT_R8, "VARPOW: expected coerced hres 0x%X type VT_R8, got hres 0x%X type %s!\n", S_OK, hres, vtstr(V_VT(&result))); ok(hres == S_OK && EQ_DOUBLE(V_R8(&result), 4.0), "VARPOW: CY value %f, expected %f\n", V_R8(&result), 4.0); + } + else + { + ok(hres == DISP_E_BADVARTYPE && V_VT(&result) == VT_EMPTY, + "VARPOW: expected coerced hres 0x%X type VT_EMPTY, got hres 0x%X type %s!\n", + DISP_E_BADVARTYPE, hres, vtstr(V_VT(&result))); + } hres = pVarPow(&left, &cy, &result); ok(hres == S_OK && V_VT(&result) == VT_R8, @@ -6887,11 +7027,20 @@ static void test_VarPow(void) "VARPOW: DECIMAL value %f, expected %f\n", V_R8(&result), 4.0); hres = pVarPow(&dec, &right, &result); + if (hres == S_OK) + { ok(hres == S_OK && V_VT(&result) == VT_R8, "VARPOW: expected coerced hres 0x%X type VT_R8, got hres 0x%X type %s!\n", S_OK, hres, vtstr(V_VT(&result))); ok(hres == S_OK && EQ_DOUBLE(V_R8(&result), 4.0), "VARPOW: DECIMAL value %f, expected %f\n", V_R8(&result), 4.0); + } + else + { + ok(hres == DISP_E_BADVARTYPE && V_VT(&result) == VT_EMPTY, + "VARPOW: expected coerced hres 0x%X type VT_EMPTY, got hres 0x%X type %s!\n", + DISP_E_BADVARTYPE, hres, vtstr(V_VT(&result))); + } SysFreeString(num2_str); SysFreeString(num3_str); diff --git a/rostests/winetests/oleaut32/vartype.c b/rostests/winetests/oleaut32/vartype.c index 2292036027f..419e0273d0a 100644 --- a/rostests/winetests/oleaut32/vartype.c +++ b/rostests/winetests/oleaut32/vartype.c @@ -46,7 +46,7 @@ static HMODULE hOleaut32; /* Get a conversion function ptr, return if function not available */ #define CHECKPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func); \ if (!p##func) { \ - skip("function " # func " not available, not testing it\n"); return; } + win_skip("function " # func " not available, not testing it\n"); return; } /* Is a given function exported from oleaut32? */ #define HAVE_FUNC(func) ((void*)GetProcAddress(hOleaut32, #func) != NULL) @@ -498,6 +498,7 @@ static HRESULT (WINAPI *pVarBoolFromUI8)(ULONG64,VARIANT_BOOL*); static HRESULT (WINAPI *pVarBstrFromR4)(FLOAT,LCID,ULONG,BSTR*); static HRESULT (WINAPI *pVarBstrFromDate)(DATE,LCID,ULONG,BSTR*); +static HRESULT (WINAPI *pVarBstrFromCy)(CY,LCID,ULONG,BSTR*); static HRESULT (WINAPI *pVarBstrFromDec)(DECIMAL*,LCID,ULONG,BSTR*); static HRESULT (WINAPI *pVarBstrCmp)(BSTR,BSTR,LCID,ULONG); @@ -553,7 +554,7 @@ static HRESULT WINAPI DummyDispatch_QueryInterface(LPDISPATCH iface, } if (*ppvObject) { - DummyDispatch_AddRef((IDispatch*)*ppvObject); + DummyDispatch_AddRef(*ppvObject); return S_OK; } } @@ -1097,7 +1098,7 @@ static void test_VarUI1FromDisp(void) dispatch.vt = VT_UI1; dispatch.bFailInvoke = FALSE; - hres = VarUI1FromDisp((IDispatch*)&dispatch, in, &out); + hres = pVarUI1FromDisp((IDispatch*)&dispatch, in, &out); trace("0x%08x\n", hres); hres = VariantChangeTypeEx(&vDst, &vSrc, in, 0, VT_UI1); @@ -1105,7 +1106,7 @@ static void test_VarUI1FromDisp(void) dispatch.bFailInvoke = TRUE; - hres = VarUI1FromDisp((IDispatch*)&dispatch, in, &out); + hres = pVarUI1FromDisp((IDispatch*)&dispatch, in, &out); trace("0x%08x\n", hres); hres = VariantChangeTypeEx(&vDst, &vSrc, in, 0, VT_UI1); @@ -2348,7 +2349,7 @@ static void test_VarI8Copy(void) if (!HAVE_OLEAUT32_I8) { - skip("I8 and UI8 data types are not available\n"); + win_skip("I8 and UI8 data types are not available\n"); return; } @@ -2378,7 +2379,7 @@ static void test_VarI8ChangeTypeEx(void) if (!HAVE_OLEAUT32_I8) { - skip("I8 and UI8 data types are not available\n"); + win_skip("I8 and UI8 data types are not available\n"); return; } @@ -2610,7 +2611,7 @@ static void test_VarUI8Copy(void) if (!HAVE_OLEAUT32_I8) { - skip("I8 and UI8 data types are not available\n"); + win_skip("I8 and UI8 data types are not available\n"); return; } @@ -2640,7 +2641,7 @@ static void test_VarUI8ChangeTypeEx(void) if (!HAVE_OLEAUT32_I8) { - skip("I8 and UI8 data types are not available\n"); + win_skip("I8 and UI8 data types are not available\n"); return; } @@ -3322,7 +3323,7 @@ static void test_VarDateFromStr(void) CHECKPTR(VarDateFromStr); CHECKPTR(SystemTimeToVariantTime); - /* Some date formats are relative, so we need to find the cuurent year */ + /* Some date formats are relative, so we need to find the current year */ GetSystemTime(&st); st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; DFS(NULL); EXPECT_MISMATCH; @@ -3433,6 +3434,11 @@ static void test_VarDateFromStr(void) DFS("1/2/1970"); EXPECT_DBL(25570.0); DFS("1-2-1970"); EXPECT_DBL(25570.0); /* Native fails "1999 January 3, 9AM". I consider that a bug in native */ + + /* test a none english data string */ + DFS("02.01.1970 00:00:00"); EXPECT_MISMATCH; + lcid = MAKELCID(MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN),SORT_DEFAULT); + DFS("02.01.1970 00:00:00"); todo_wine EXPECT_DBL(25570.0); } static void test_VarDateCopy(void) @@ -4407,9 +4413,104 @@ static void test_VarDecCmp(void) MATHVARS1; CHECKPTR(VarDecCmp); + SETDEC(l,0,0,0,1); SETDEC(out,0,0,0,1); MATH1(VarDecCmp); EXPECT_EQ; SETDEC(l,0,0,0,1); SETDEC(out,0,0,0,0); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,0,1); SETDEC(out,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(l,0,0,0,1); SETDEC(out,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,0,1); SETDEC(out,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,0,1); SETDEC(out,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(l,0,DECIMAL_NEG,0,1); SETDEC(out,0,0,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,DECIMAL_NEG,0,1); SETDEC(out,0,0,0,0); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,DECIMAL_NEG,0,1); SETDEC(out,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(l,0,DECIMAL_NEG,0,1); SETDEC(out,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(l,0,DECIMAL_NEG,0,1); SETDEC(out,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,DECIMAL_NEG,0,1); SETDEC(out,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,0,0); SETDEC(out,0,0,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,0,0,0); SETDEC(out,0,0,0,0); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(l,0,0,0,0); SETDEC(out,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(l,0,0,0,0); SETDEC(out,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,0,0); SETDEC(out,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(l,0,0,0,0); SETDEC(out,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(l,0,DECIMAL_NEG,0,0); SETDEC(out,0,0,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,DECIMAL_NEG,0,0); SETDEC(out,0,0,0,0); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(l,0,DECIMAL_NEG,0,0); SETDEC(out,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(l,0,DECIMAL_NEG,0,0); SETDEC(out,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,DECIMAL_NEG,0,0); SETDEC(out,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(l,0,DECIMAL_NEG,0,0); SETDEC(out,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(l,0,0,-1,-1); SETDEC(out,0,0,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,-1,-1); SETDEC(out,0,0,0,0); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,-1,-1); SETDEC(out,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_EQ; + + SETDEC(l,0,0,-1,-1); SETDEC(out,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,-1,-1); SETDEC(out,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(l,0,0,-1,-1); SETDEC(out,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(l,0,DECIMAL_NEG,-1,-1); SETDEC(out,0,0,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,DECIMAL_NEG,-1,-1); SETDEC(out,0,0,0,0); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,DECIMAL_NEG,-1,-1); SETDEC(out,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(l,0,DECIMAL_NEG,-1,-1); SETDEC(out,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,DECIMAL_NEG,-1,-1); SETDEC(out,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(l,0,DECIMAL_NEG,-1,-1); SETDEC(out,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_EQ; + + + SETDEC(out,0,0,0,1); SETDEC(l,0,0,0,1); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(out,0,0,0,1); SETDEC(l,0,0,0,0); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,0,0,1); SETDEC(l,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(out,0,0,0,1); SETDEC(l,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,0,0,1); SETDEC(l,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,0,0,1); SETDEC(l,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(out,0,DECIMAL_NEG,0,1); SETDEC(l,0,0,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,DECIMAL_NEG,0,1); SETDEC(l,0,0,0,0); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,DECIMAL_NEG,0,1); SETDEC(l,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(out,0,DECIMAL_NEG,0,1); SETDEC(l,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(out,0,DECIMAL_NEG,0,1); SETDEC(l,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,DECIMAL_NEG,0,1); SETDEC(l,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(out,0,0,0,0); SETDEC(l,0,0,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,0,0,0); SETDEC(l,0,0,0,0); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(out,0,0,0,0); SETDEC(l,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(out,0,0,0,0); SETDEC(l,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,0,0,0); SETDEC(l,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(out,0,0,0,0); SETDEC(l,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(out,0,DECIMAL_NEG,0,0); SETDEC(l,0,0,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,DECIMAL_NEG,0,0); SETDEC(l,0,0,0,0); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(out,0,DECIMAL_NEG,0,0); SETDEC(l,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(out,0,DECIMAL_NEG,0,0); SETDEC(l,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,DECIMAL_NEG,0,0); SETDEC(l,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_EQ; + SETDEC(out,0,DECIMAL_NEG,0,0); SETDEC(l,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(out,0,0,-1,-1); SETDEC(l,0,0,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,0,-1,-1); SETDEC(l,0,0,0,0); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,0,-1,-1); SETDEC(l,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_EQ; + + SETDEC(out,0,0,-1,-1); SETDEC(l,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,0,-1,-1); SETDEC(l,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_LT; + SETDEC(out,0,0,-1,-1); SETDEC(l,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_LT; + + SETDEC(out,0,DECIMAL_NEG,-1,-1); SETDEC(l,0,0,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,DECIMAL_NEG,-1,-1); SETDEC(l,0,0,0,0); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,DECIMAL_NEG,-1,-1); SETDEC(l,0,0,-1,-1); MATH1(VarDecCmp); EXPECT_GT; + + SETDEC(out,0,DECIMAL_NEG,-1,-1); SETDEC(l,0,DECIMAL_NEG,0,1); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,DECIMAL_NEG,-1,-1); SETDEC(l,0,DECIMAL_NEG,0,0); MATH1(VarDecCmp); EXPECT_GT; + SETDEC(out,0,DECIMAL_NEG,-1,-1); SETDEC(l,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_EQ; + } /* @@ -4800,9 +4901,71 @@ static void test_VarBstrFromDate(void) BSTR_DATE(2958465.0, "12/31/9999"); } +#define BSTR_CY(l, a, b, e) \ + S(l).Lo = b; S(l).Hi = a; \ + hres = pVarBstrFromCy(l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);\ + ok(hres == S_OK, "got hres 0x%08x\n", hres);\ + if (hres== S_OK && bstr)\ + {\ + ok(lstrcmpW(bstr, e) == 0, "invalid number (got %s)\n", wtoascii(bstr));\ + } + +static void test_VarBstrFromCy(void) +{ + LCID lcid; + HRESULT hres; + BSTR bstr = NULL; + CY l; + + static const WCHAR szZero[] = {'0', '\0'}; + static const WCHAR szOne[] = {'1', '\0'}; + static const WCHAR szOnePointFive[] = {'1','.','5','\0'}; + static const WCHAR szMinusOnePointFive[] = {'-','1','.','5','\0'}; + static const WCHAR szBigNum1[] = {'4','2','9','4','9','6','.','7','2','9','5','\0'}; /* (1 << 32) - 1 / 1000 */ + static const WCHAR szBigNum2[] = {'4','2','9','4','9','6','.','7','2','9','6','\0'}; /* (1 << 32) / 1000 */ + static const WCHAR szBigNum3[] = {'9','2','2','3','3','7','2','0','3','6','8','5','4','7','7','.','5','8','0','7','\0'}; /* ((1 << 63) - 1)/10000 */ + + static const WCHAR szSmallNumber_English[] = {'0','.','0','0','0','9','\0'}; + static const WCHAR szSmallNumber_Spanish[] = {'0',',','0','0','0','9','\0'}; + + CHECKPTR(VarBstrFromCy); + lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT); + + /* check zero */ + BSTR_CY(l, 0,0, szZero); + + /* check one */ + BSTR_CY(l, 0, 10000, szOne); + + /* check one point five */ + BSTR_CY(l, 0, 15000, szOnePointFive); + + /* check minus one point five */ + BSTR_CY(l, 0xffffffff, ((15000)^0xffffffff)+1, szMinusOnePointFive); + + /* check bignum (1) */ + BSTR_CY(l, 0, 0xffffffff, szBigNum1); + + /* check bignum (2) */ + BSTR_CY(l, 1,0, szBigNum2); + + /* check bignum (3) */ + BSTR_CY(l, 0x7fffffff,0xffffffff, szBigNum3); + + /* check leading zeros and decimal sep. for English locale */ + BSTR_CY(l, 0,9, szSmallNumber_English); + + lcid = MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT); + + /* check leading zeros and decimal sep. for Spanish locale */ + BSTR_CY(l, 0,9, szSmallNumber_Spanish); +} + +#undef BSTR_CY + #define BSTR_DEC(l, a, b, c, d, e) \ SETDEC(l, a,b,c,d);\ - hres = VarBstrFromDec(&l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);\ + hres = pVarBstrFromDec(&l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);\ ok(hres == S_OK, "got hres 0x%08x\n", hres);\ if (hres== S_OK && bstr)\ {\ @@ -4811,7 +4974,7 @@ static void test_VarBstrFromDate(void) #define BSTR_DEC64(l, a, b, c, x, d, e) \ SETDEC64(l, a,b,c,x,d);\ - hres = VarBstrFromDec(&l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);\ + hres = pVarBstrFromDec(&l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);\ ok(hres == S_OK, "got hres 0x%08x\n", hres);\ if (hres== S_OK && bstr)\ {\ @@ -4920,6 +5083,8 @@ static void test_VarBstrCmp(void) static const WCHAR s2[] = { 'a',0,'b' }; static const char sb1[] = {1,0,1}; static const char sb2[] = {1,0,2}; + static const char sbchr0[] = {0,0}; + static const char sbchr00[] = {0,0,0}; BSTR bstr, bstrempty, bstr2; CHECKPTR(VarBstrCmp); @@ -4928,12 +5093,12 @@ static void test_VarBstrCmp(void) bstr = SysAllocString(sz); bstrempty = SysAllocString(szempty); - /* NULL handling. Yepp, MSDN is totaly wrong here */ + /* NULL handling. Yepp, MSDN is totally wrong here */ VARBSTRCMP(NULL,NULL,0,VARCMP_EQ); VARBSTRCMP(bstr,NULL,0,VARCMP_GT); VARBSTRCMP(NULL,bstr,0,VARCMP_LT); - /* NULL and empty string comparisions */ + /* NULL and empty string comparisons */ VARBSTRCMP(bstrempty,NULL,0,VARCMP_EQ); VARBSTRCMP(NULL,bstrempty,0,VARCMP_EQ); @@ -4958,6 +5123,15 @@ static void test_VarBstrCmp(void) SysFreeString(bstr); + bstr = SysAllocStringByteLen(sbchr0, sizeof(sbchr0)); + bstr2 = SysAllocStringByteLen(sbchr0, sizeof(sbchr00)); + VARBSTRCMP(bstr,bstrempty,0,VARCMP_GT); + VARBSTRCMP(bstrempty,bstr,0,VARCMP_LT); + VARBSTRCMP(bstr2,bstrempty,0,VARCMP_GT); + VARBSTRCMP(bstr2,bstr,0,VARCMP_EQ); + SysFreeString(bstr2); + SysFreeString(bstr); + /* When (LCID == 0) it should be a binary comparison * so these two strings could not match. */ @@ -4967,6 +5141,15 @@ static void test_VarBstrCmp(void) VARBSTRCMP(bstr,bstr2,0,VARCMP_LT); SysFreeString(bstr2); SysFreeString(bstr); + + bstr = SysAllocStringByteLen(sbchr0, sizeof(sbchr0)); + bstr2 = SysAllocStringByteLen(sbchr0, sizeof(sbchr00)); + VARBSTRCMP(bstr,bstrempty,0,VARCMP_GT); + VARBSTRCMP(bstrempty,bstr,0,VARCMP_LT); + VARBSTRCMP(bstr2,bstrempty,0,VARCMP_GT); + VARBSTRCMP(bstr2,bstr,0,VARCMP_GT); + SysFreeString(bstr2); + SysFreeString(bstr); } /* Get the internal representation of a BSTR */ @@ -4997,7 +5180,7 @@ static void test_SysStringByteLen(void) BSTR str = GetBSTR(&bstr); bstr.dwLen = 0; - ok (SysStringByteLen(str) == 0, "Expected dwLen 0, got %d\n", SysStringLen(str)); + ok (SysStringByteLen(str) == 0, "Expected dwLen 0, got %d\n", SysStringByteLen(str)); bstr.dwLen = 2; ok (SysStringByteLen(str) == 2, "Expected dwLen 2, got %d\n", SysStringByteLen(str)); } @@ -5139,7 +5322,8 @@ static void test_SysReAllocString(void) changed = SysReAllocString(&str, szSmaller); ok (changed == 1, "Expected 1, got %d\n", changed); - ok (str == oldstr, "Created new string\n"); + /* Vista creates a new string, but older versions reuse the existing string. */ + /*ok (str == oldstr, "Created new string\n");*/ bstr = Get(str); ok (bstr->dwLen == 2, "Expected 2, got %d\n", bstr->dwLen); ok (!lstrcmpW(bstr->szString, szSmaller), "String different\n"); @@ -5178,7 +5362,8 @@ static void test_SysReAllocStringLen(void) changed = SysReAllocStringLen(&str, szSmaller, 1); ok (changed == 1, "Expected 1, got %d\n", changed); - ok (str == oldstr, "Created new string\n"); + /* Vista creates a new string, but older versions reuse the existing string. */ + /*ok (str == oldstr, "Created new string\n");*/ bstr = Get(str); ok (bstr->dwLen == 2, "Expected 2, got %d\n", bstr->dwLen); ok (!lstrcmpW(bstr->szString, szSmaller), "String different\n"); @@ -5387,12 +5572,12 @@ static void test_IUnknownChangeTypeEx(void) /* =>IDispatch */ u.ref = 1; V_VT(&vSrc) = VT_UNKNOWN; - V_UNKNOWN(&vSrc) = (IUnknown*)pu; + V_UNKNOWN(&vSrc) = pu; VariantInit(&vDst); hres = VariantChangeTypeEx(&vDst, &vSrc, lcid, 0, VT_UNKNOWN); /* Note vSrc is not cleared, as final refcount is 2 */ ok(hres == S_OK && u.ref == 2 && - V_VT(&vDst) == VT_UNKNOWN && V_UNKNOWN(&vDst) == (IUnknown*)pu, + V_VT(&vDst) == VT_UNKNOWN && V_UNKNOWN(&vDst) == pu, "change unk(src,dst): expected 0x%08x,%d,%d,%p, got 0x%08x,%d,%d,%p\n", S_OK, 2, VT_UNKNOWN, pu, hres, u.ref, V_VT(&vDst), V_UNKNOWN(&vDst)); @@ -5402,7 +5587,7 @@ static void test_IUnknownChangeTypeEx(void) HRESULT hExpected = DISP_E_BADVARTYPE; V_VT(&vSrc) = VT_UNKNOWN; - V_UNKNOWN(&vSrc) = (IUnknown*)pu; + V_UNKNOWN(&vSrc) = pu; VariantInit(&vDst); if (vt == VT_UNKNOWN || vt == VT_DISPATCH || vt == VT_EMPTY || vt == VT_NULL) @@ -5703,21 +5888,13 @@ static void test_UintChangeTypeEx(void) static void test_ClearCustData(void) { - WCHAR buff[sizeof(CUSTDATAITEM) * NUM_CUST_ITEMS / sizeof(WCHAR)]; CUSTDATA ci; unsigned i; CHECKPTR(ClearCustData); - memset(buff, 0, sizeof(buff)); - ci.cCustData = NUM_CUST_ITEMS; - /* This is a bit tricky. We use SysAllocStringByteLen to allocate the - * array, since native uses an internal IMalloc interface for allocating - * its memory, while Wine uses HeapAlloc(). Doing this ensures we allocate - * using the correct function whether with native or builtin. - */ - ci.prgCustData = (LPCUSTDATAITEM)SysAllocStringByteLen((LPCSTR)buff, sizeof(buff)); + ci.prgCustData = CoTaskMemAlloc( sizeof(CUSTDATAITEM) * NUM_CUST_ITEMS ); for (i = 0; i < NUM_CUST_ITEMS; i++) VariantInit(&ci.prgCustData[i].varValue); pClearCustData(&ci); @@ -5729,8 +5906,8 @@ static void test_NullByRef(void) VARIANT v1, v2; HRESULT hRes; - VariantClear(&v1); - VariantClear(&v2); + VariantInit(&v1); + VariantInit(&v2); V_VT(&v1) = VT_BYREF|VT_VARIANT; V_BYREF(&v1) = 0; @@ -5763,8 +5940,8 @@ static void test_ChangeType_keep_dst(void) HRESULT hres; bstr = SysAllocString(testW); - VariantClear(&v1); - VariantClear(&v2); + VariantInit(&v1); + VariantInit(&v2); V_VT(&v1) = VT_BSTR; V_BSTR(&v1) = bstr; hres = VariantChangeTypeEx(&v1, &v1, 0, 0, VT_INT); @@ -6042,6 +6219,7 @@ START_TEST(vartype) test_VarBstrFromR4(); test_VarBstrFromDate(); + test_VarBstrFromCy(); test_VarBstrFromDec(); test_VarBstrCmp(); test_SysStringLen(); diff --git a/rostests/winetests/pdh/pdh.c b/rostests/winetests/pdh/pdh.c new file mode 100644 index 00000000000..cd03bcb4fe3 --- /dev/null +++ b/rostests/winetests/pdh/pdh.c @@ -0,0 +1,978 @@ +/* + * Tests for pdh.dll (Performance Data Helper) + * + * Copyright 2007 Hans Leidekker + * + * 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 + */ + +#include + +#include "windows.h" + +#include "pdh.h" +#include "pdhmsg.h" + +#include "wine/test.h" + +static HMODULE pdh; + +static PDH_STATUS (WINAPI *pPdhAddEnglishCounterA)(PDH_HQUERY, LPCSTR, DWORD_PTR, PDH_HCOUNTER *); +static PDH_STATUS (WINAPI *pPdhAddEnglishCounterW)(PDH_HQUERY, LPCWSTR, DWORD_PTR, PDH_HCOUNTER *); +static PDH_STATUS (WINAPI *pPdhCollectQueryDataWithTime)(PDH_HQUERY, LONGLONG *); +static PDH_STATUS (WINAPI *pPdhValidatePathExA)(PDH_HLOG, LPCSTR); +static PDH_STATUS (WINAPI *pPdhValidatePathExW)(PDH_HLOG, LPCWSTR); + +#define GETFUNCPTR(func) p##func = (void *)GetProcAddress( pdh, #func ); + +static void init_function_ptrs( void ) +{ + pdh = GetModuleHandle( "pdh" ); + GETFUNCPTR( PdhAddEnglishCounterA ) + GETFUNCPTR( PdhAddEnglishCounterW ) + GETFUNCPTR( PdhCollectQueryDataWithTime ) + GETFUNCPTR( PdhValidatePathExA ) + GETFUNCPTR( PdhValidatePathExW ) +} + +static const WCHAR processor_time[] = + {'%',' ','P','r','o','c','e','s','s','o','r',' ','T','i','m','e',0}; +static const WCHAR uptime[] = + {'S','y','s','t','e','m',' ','U','p',' ','T','i','m','e',0}; + +static const WCHAR system_uptime[] = + {'\\','S','y','s','t','e','m','\\','S','y','s','t','e','m',' ','U','p',' ','T','i','m','e',0}; +static const WCHAR system_downtime[] = /* does not exist */ + {'\\','S','y','s','t','e','m','\\','S','y','s','t','e','m',' ','D','o','w','n',' ','T','i','m','e',0}; +static const WCHAR percentage_processor_time[] = + {'\\','P','r','o','c','e','s','s','o','r','(','_','T','o','t','a','l',')', + '\\','%',' ','P','r','o','c','e','s','s','o','r',' ','T','i','m','e',0}; + +static void test_PdhOpenQueryA( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + + ret = PdhOpenQueryA( NULL, 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhCloseQuery( NULL ); + ok(ret == PDH_INVALID_HANDLE, "PdhCloseQuery failed 0x%08x\n", ret); + + ret = PdhCloseQuery( &query ); + ok(ret == PDH_INVALID_HANDLE, "PdhCloseQuery failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == PDH_INVALID_HANDLE, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhOpenQueryW( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + + ret = PdhOpenQueryW( NULL, 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhOpenQueryW failed 0x%08x\n", ret); + + ret = PdhOpenQueryW( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryW failed 0x%08x\n", ret); + + ret = PdhCloseQuery( NULL ); + ok(ret == PDH_INVALID_HANDLE, "PdhCloseQuery failed 0x%08x\n", ret); + + ret = PdhCloseQuery( &query ); + ok(ret == PDH_INVALID_HANDLE, "PdhCloseQuery failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == PDH_INVALID_HANDLE, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhAddCounterA( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( NULL, "\\System\\System Up Time", 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( NULL, "\\System\\System Up Time", 0, &counter ); + ok(ret == PDH_INVALID_HANDLE, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, NULL, 0, &counter ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, "\\System\\System Down Time", 0, &counter ); + ok(ret == PDH_CSTATUS_NO_COUNTER, "PdhAddCounterA failed 0x%08x\n", ret); + ok(!counter, "PdhAddCounterA failed %p\n", counter); + + ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( NULL ); + ok(ret == PDH_INVALID_HANDLE, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( counter ); + ok(ret == PDH_INVALID_HANDLE, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( query ); + ok(ret == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhRemoveCounter( NULL ); + ok(ret == PDH_INVALID_HANDLE, "PdhRemoveCounter failed 0x%08x\n", ret); + + ret = PdhRemoveCounter( counter ); + ok(ret == ERROR_SUCCESS, "PdhRemoveCounter failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhAddCounterW( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + + ret = PdhOpenQueryW( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryW failed 0x%08x\n", ret); + + ret = PdhAddCounterW( NULL, percentage_processor_time, 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddCounterW failed 0x%08x\n", ret); + + ret = PdhAddCounterW( NULL, percentage_processor_time, 0, &counter ); + ok(ret == PDH_INVALID_HANDLE, "PdhAddCounterW failed 0x%08x\n", ret); + + ret = PdhAddCounterW( query, NULL, 0, &counter ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddCounterW failed 0x%08x\n", ret); + + ret = PdhAddCounterW( query, percentage_processor_time, 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddCounterW failed 0x%08x\n", ret); + + ret = PdhAddCounterW( query, system_downtime, 0, &counter ); + ok(ret == PDH_CSTATUS_NO_COUNTER, "PdhAddCounterW failed 0x%08x\n", ret); + ok(!counter, "PdhAddCounterW failed %p\n", counter); + + ret = PdhAddCounterW( query, percentage_processor_time, 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterW failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( NULL ); + ok(ret == PDH_INVALID_HANDLE, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( counter ); + ok(ret == PDH_INVALID_HANDLE, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( query ); + ok(ret == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhRemoveCounter( NULL ); + ok(ret == PDH_INVALID_HANDLE, "PdhRemoveCounter failed 0x%08x\n", ret); + + ret = PdhRemoveCounter( counter ); + ok(ret == ERROR_SUCCESS, "PdhRemoveCounter failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhAddEnglishCounterA( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( query ); + ok(ret == PDH_NO_DATA, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterA( NULL, "\\System\\System Up Time", 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddEnglishCounterA failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterA( NULL, "\\System\\System Up Time", 0, &counter ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddEnglishCounterA failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterA( query, NULL, 0, &counter ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddEnglishCounterA failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterA( query, "\\System\\System Up Time", 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddEnglishCounterA failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterA( query, "\\System\\System Down Time", 0, &counter ); + ok(ret == PDH_CSTATUS_NO_COUNTER, "PdhAddEnglishCounterA failed 0x%08x\n", ret); + ok(!counter, "PdhAddEnglishCounterA failed %p\n", counter); + + ret = pPdhAddEnglishCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddEnglishCounterA failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( query ); + ok(ret == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhRemoveCounter( counter ); + ok(ret == ERROR_SUCCESS, "PdhRemoveCounter failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhAddEnglishCounterW( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + + ret = PdhOpenQueryW( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryW failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( query ); + ok(ret == PDH_NO_DATA, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterW( NULL, system_uptime, 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddEnglishCounterW failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterW( NULL, system_uptime, 0, &counter ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddEnglishCounterW failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterW( query, NULL, 0, &counter ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddEnglishCounterW failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterW( query, system_uptime, 0, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhAddEnglishCounterW failed 0x%08x\n", ret); + + ret = pPdhAddEnglishCounterW( query, system_downtime, 0, &counter ); + ok(ret == PDH_CSTATUS_NO_COUNTER, "PdhAddEnglishCounterW failed 0x%08x\n", ret); + ok(!counter, "PdhAddEnglishCounterA failed %p\n", counter); + + ret = pPdhAddEnglishCounterW( query, system_uptime, 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddEnglishCounterW failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( query ); + ok(ret == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhRemoveCounter( counter ); + ok(ret == ERROR_SUCCESS, "PdhRemoveCounter failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhCollectQueryDataWithTime( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + LONGLONG time; + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( query ); + ok(ret == PDH_NO_DATA, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = pPdhCollectQueryDataWithTime( NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhCollectQueryDataWithTime failed 0x%08x\n", ret); + + ret = pPdhCollectQueryDataWithTime( query, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhCollectQueryDataWithTime failed 0x%08x\n", ret); + + ret = pPdhCollectQueryDataWithTime( NULL, &time ); + ok(ret == PDH_INVALID_HANDLE, "PdhCollectQueryDataWithTime failed 0x%08x\n", ret); + + ret = pPdhCollectQueryDataWithTime( query, &time ); + ok(ret == ERROR_SUCCESS, "PdhCollectQueryDataWithTime failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhGetFormattedCounterValue( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + PDH_FMT_COUNTERVALUE value; + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( NULL, PDH_FMT_LARGE, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( NULL, PDH_FMT_LARGE, NULL, &value ); + ok(ret == PDH_INVALID_HANDLE, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE, NULL, &value ); + ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhCollectQueryData( query ); + ok(ret == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE, NULL, &value ); + ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE | PDH_FMT_NOSCALE, NULL, &value ); + ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE | PDH_FMT_NOCAP100, NULL, &value ); + ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE | PDH_FMT_1000, NULL, &value ); + ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhSetCounterScaleFactor( counter, 2 ); + ok(ret == ERROR_SUCCESS, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE, NULL, &value ); + ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhGetRawCounterValue( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + PDH_RAW_COUNTER value; + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhGetRawCounterValue( NULL, NULL, &value ); + ok(ret == PDH_INVALID_HANDLE, "PdhGetRawCounterValue failed 0x%08x\n", ret); + + ret = PdhGetRawCounterValue( counter, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetRawCounterValue failed 0x%08x\n", ret); + + ret = PdhGetRawCounterValue( counter, NULL, &value ); + ok(ret == ERROR_SUCCESS, "PdhGetRawCounterValue failed 0x%08x\n", ret); + ok(value.CStatus == ERROR_SUCCESS, "expected ERROR_SUCCESS got %x\n", value.CStatus); + + ret = PdhCollectQueryData( query ); + ok(ret == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08x\n", ret); + + ret = PdhGetRawCounterValue( counter, NULL, &value ); + ok(ret == ERROR_SUCCESS, "PdhGetRawCounterValue failed 0x%08x\n", ret); + ok(value.CStatus == ERROR_SUCCESS, "expected ERROR_SUCCESS got %x\n", value.CStatus); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhSetCounterScaleFactor( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhSetCounterScaleFactor( NULL, 8 ); + ok(ret == PDH_INVALID_HANDLE, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhSetCounterScaleFactor( NULL, 1 ); + ok(ret == PDH_INVALID_HANDLE, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhSetCounterScaleFactor( counter, 8 ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhSetCounterScaleFactor( counter, -8 ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhSetCounterScaleFactor( counter, 7 ); + ok(ret == ERROR_SUCCESS, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhSetCounterScaleFactor( counter, 0 ); + ok(ret == ERROR_SUCCESS, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhGetCounterTimeBase( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + LONGLONG base; + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhGetCounterTimeBase( NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetCounterTimeBase failed 0x%08x\n", ret); + + ret = PdhGetCounterTimeBase( NULL, &base ); + ok(ret == PDH_INVALID_HANDLE, "PdhGetCounterTimeBase failed 0x%08x\n", ret); + + ret = PdhGetCounterTimeBase( counter, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetCounterTimeBase failed 0x%08x\n", ret); + + ret = PdhGetCounterTimeBase( counter, &base ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterTimeBase failed 0x%08x\n", ret); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhGetCounterInfoA( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + PDH_COUNTER_INFO_A info; + DWORD size; + + ret = PdhOpenQueryA( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08x\n", ret); + + ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoA( NULL, 0, NULL, NULL ); + ok(ret == PDH_INVALID_HANDLE || ret == PDH_INVALID_ARGUMENT, "PdhGetCounterInfoA failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoA( counter, 0, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetCounterInfoA failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoA( counter, 0, NULL, &info ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetCounterInfoA failed 0x%08x\n", ret); + + size = sizeof(info) - 1; + ret = PdhGetCounterInfoA( counter, 0, &size, NULL ); + ok(ret == PDH_MORE_DATA || ret == PDH_INVALID_ARGUMENT, "PdhGetCounterInfoA failed 0x%08x\n", ret); + + size = sizeof(info); + ret = PdhGetCounterInfoA( counter, 0, &size, &info ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterInfoA failed 0x%08x\n", ret); + ok(size == sizeof(info), "PdhGetCounterInfoA failed %d\n", size); + + ret = PdhGetCounterInfoA( counter, 0, &size, &info ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterInfoA failed 0x%08x\n", ret); + ok(info.lScale == 0, "lScale %d\n", info.lScale); + + ret = PdhSetCounterScaleFactor( counter, 0 ); + ok(ret == ERROR_SUCCESS, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoA( counter, 0, &size, &info ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterInfoA failed 0x%08x\n", ret); + ok(info.lScale == 0, "lScale %d\n", info.lScale); + + ret = PdhSetCounterScaleFactor( counter, -5 ); + ok(ret == ERROR_SUCCESS, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoA( counter, 0, &size, &info ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterInfoA failed 0x%08x\n", ret); + ok(info.lScale == -5, "lScale %d\n", info.lScale); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhGetCounterInfoW( void ) +{ + PDH_STATUS ret; + PDH_HQUERY query; + PDH_HCOUNTER counter; + PDH_COUNTER_INFO_W info; + DWORD size; + + ret = PdhOpenQueryW( NULL, 0, &query ); + ok(ret == ERROR_SUCCESS, "PdhOpenQueryW failed 0x%08x\n", ret); + + ret = PdhAddCounterW( query, percentage_processor_time, 0, &counter ); + ok(ret == ERROR_SUCCESS, "PdhAddCounterW failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoW( NULL, 0, NULL, NULL ); + ok(ret == PDH_INVALID_HANDLE || ret == PDH_INVALID_ARGUMENT, "PdhGetCounterInfoW failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoW( counter, 0, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetCounterInfoW failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoW( counter, 0, NULL, &info ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhGetCounterInfoW failed 0x%08x\n", ret); + + size = sizeof(info) - 1; + ret = PdhGetCounterInfoW( counter, 0, &size, NULL ); + ok(ret == PDH_MORE_DATA || ret == PDH_INVALID_ARGUMENT, "PdhGetCounterInfoW failed 0x%08x\n", ret); + + size = sizeof(info); + ret = PdhGetCounterInfoW( counter, 0, &size, &info ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterInfoW failed 0x%08x\n", ret); + ok(size == sizeof(info), "PdhGetCounterInfoW failed %d\n", size); + + ret = PdhGetCounterInfoW( counter, 0, &size, &info ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterInfoW failed 0x%08x\n", ret); + ok(info.lScale == 0, "lScale %d\n", info.lScale); + + ret = PdhSetCounterScaleFactor( counter, 0 ); + ok(ret == ERROR_SUCCESS, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoW( counter, 0, &size, &info ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterInfoW failed 0x%08x\n", ret); + ok(info.lScale == 0, "lScale %d\n", info.lScale); + + ret = PdhSetCounterScaleFactor( counter, -5 ); + ok(ret == ERROR_SUCCESS, "PdhSetCounterScaleFactor failed 0x%08x\n", ret); + + ret = PdhGetCounterInfoW( counter, 0, &size, &info ); + ok(ret == ERROR_SUCCESS, "PdhGetCounterInfoW failed 0x%08x\n", ret); + ok(info.lScale == -5, "lScale %d\n", info.lScale); + + ret = PdhCloseQuery( query ); + ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", ret); +} + +static void test_PdhLookupPerfIndexByNameA( void ) +{ + PDH_STATUS ret; + DWORD index; + + ret = PdhLookupPerfIndexByNameA( NULL, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhLookupPerfIndexByNameA failed 0x%08x\n", ret); + + ret = PdhLookupPerfIndexByNameA( NULL, NULL, &index ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhLookupPerfIndexByNameA failed 0x%08x\n", ret); + + ret = PdhLookupPerfIndexByNameA( NULL, "No Counter", &index ); + ok(ret == PDH_STRING_NOT_FOUND, "PdhLookupPerfIndexByNameA failed 0x%08x\n", ret); + + ret = PdhLookupPerfIndexByNameA( NULL, "% Processor Time", NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhLookupPerfIndexByNameA failed 0x%08x\n", ret); + + ret = PdhLookupPerfIndexByNameA( NULL, "% Processor Time", &index ); + ok(ret == ERROR_SUCCESS, "PdhLookupPerfIndexByNameA failed 0x%08x\n", ret); + ok(index == 6, "PdhLookupPerfIndexByNameA failed %d\n", index); + + ret = PdhLookupPerfIndexByNameA( NULL, "System Up Time", &index ); + ok(ret == ERROR_SUCCESS, "PdhLookupPerfIndexByNameA failed 0x%08x\n", ret); + ok(index == 674, "PdhLookupPerfIndexByNameA failed %d\n", index); +} + +static void test_PdhLookupPerfIndexByNameW( void ) +{ + PDH_STATUS ret; + DWORD index; + + static const WCHAR no_counter[] = {'N','o',' ','C','o','u','n','t','e','r',0}; + + ret = PdhLookupPerfIndexByNameW( NULL, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhLookupPerfIndexByNameW failed 0x%08x\n", ret); + + ret = PdhLookupPerfIndexByNameW( NULL, NULL, &index ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhLookupPerfIndexByNameW failed 0x%08x\n", ret); + + ret = PdhLookupPerfIndexByNameW( NULL, no_counter, &index ); + ok(ret == PDH_STRING_NOT_FOUND, "PdhLookupPerfIndexByNameW failed 0x%08x\n", ret); + + ret = PdhLookupPerfIndexByNameW( NULL, processor_time, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhLookupPerfIndexByNameW failed 0x%08x\n", ret); + + ret = PdhLookupPerfIndexByNameW( NULL, processor_time, &index ); + ok(ret == ERROR_SUCCESS, "PdhLookupPerfIndexByNameW failed 0x%08x\n", ret); + ok(index == 6, "PdhLookupPerfIndexByNameW failed %d\n", index); + + ret = PdhLookupPerfIndexByNameW( NULL, uptime, &index ); + ok(ret == ERROR_SUCCESS, "PdhLookupPerfIndexByNameW failed 0x%08x\n", ret); + ok(index == 674, "PdhLookupPerfIndexByNameW failed %d\n", index); +} + +static void test_PdhLookupPerfNameByIndexA( void ) +{ + PDH_STATUS ret; + char buffer[PDH_MAX_COUNTER_NAME] = "!!"; + DWORD size; + + ret = PdhLookupPerfNameByIndexA( NULL, 0, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhLookupPerfNameByIndexA failed 0x%08x\n", ret); + + size = 0; + ret = PdhLookupPerfNameByIndexA( NULL, 6, buffer, &size ); + ok(ret == PDH_MORE_DATA || ret == PDH_INSUFFICIENT_BUFFER, "PdhLookupPerfNameByIndexA failed 0x%08x\n", ret); + + size = sizeof(buffer); + ret = PdhLookupPerfNameByIndexA( NULL, 6, buffer, &size ); + ok(ret == ERROR_SUCCESS, "PdhLookupPerfNameByIndexA failed 0x%08x\n", ret); + ok(!lstrcmpA( buffer, "% Processor Time" ), + "PdhLookupPerfNameByIndexA failed, got %s expected \'%% Processor Time\'\n", buffer); + ok(size == sizeof("% Processor Time"), "PdhLookupPerfNameByIndexA failed %d\n", size); + + size = sizeof(buffer); + ret = PdhLookupPerfNameByIndexA( NULL, 674, NULL, &size ); + ok(ret == PDH_INVALID_ARGUMENT || + ret == PDH_MORE_DATA, /* win2k3 */ + "PdhLookupPerfNameByIndexA failed 0x%08x\n", ret); + + size = sizeof(buffer); + ret = PdhLookupPerfNameByIndexA( NULL, 674, buffer, &size ); + ok(ret == ERROR_SUCCESS, "PdhLookupPerfNameByIndexA failed 0x%08x\n", ret); + ok(!lstrcmpA( buffer, "System Up Time" ), + "PdhLookupPerfNameByIndexA failed, got %s expected \'System Up Time\'\n", buffer); + ok(size == sizeof("System Up Time"), "PdhLookupPerfNameByIndexA failed %d\n", size); +} + +static void test_PdhLookupPerfNameByIndexW( void ) +{ + PDH_STATUS ret; + WCHAR buffer[PDH_MAX_COUNTER_NAME]; + DWORD size; + + ret = PdhLookupPerfNameByIndexW( NULL, 0, NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhLookupPerfNameByIndexW failed 0x%08x\n", ret); + + size = 0; + ret = PdhLookupPerfNameByIndexW( NULL, 6, buffer, &size ); + ok(ret == PDH_MORE_DATA || ret == PDH_INSUFFICIENT_BUFFER, "PdhLookupPerfNameByIndexW failed 0x%08x\n", ret); + + size = sizeof(buffer) / sizeof(WCHAR); + ret = PdhLookupPerfNameByIndexW( NULL, 6, buffer, &size ); + ok(ret == ERROR_SUCCESS, "PdhLookupPerfNameByIndexW failed 0x%08x\n", ret); + ok(size == sizeof(processor_time) / sizeof(WCHAR), "PdhLookupPerfNameByIndexW failed %d\n", size); + + size = sizeof(buffer) / sizeof(WCHAR); + ret = PdhLookupPerfNameByIndexW( NULL, 674, NULL, &size ); + ok(ret == PDH_INVALID_ARGUMENT || + ret == PDH_MORE_DATA, /* win2k3 */ + "PdhLookupPerfNameByIndexW failed 0x%08x\n", ret); + + size = sizeof(buffer) / sizeof(WCHAR); + ret = PdhLookupPerfNameByIndexW( NULL, 674, buffer, &size ); + ok(ret == ERROR_SUCCESS, "PdhLookupPerfNameByIndexW failed 0x%08x\n", ret); + ok(size == sizeof(uptime) / sizeof(WCHAR), "PdhLookupPerfNameByIndexW failed %d\n", size); +} + +static void test_PdhValidatePathA( void ) +{ + PDH_STATUS ret; + + ret = PdhValidatePathA( NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhValidatePathA failed 0x%08x\n", ret); + + ret = PdhValidatePathA( "" ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhValidatePathA failed 0x%08x\n", ret); + + ret = PdhValidatePathA( "\\System" ); + ok(ret == PDH_CSTATUS_BAD_COUNTERNAME, "PdhValidatePathA failed 0x%08x\n", ret); + + ret = PdhValidatePathA( "System Up Time" ); + ok(ret == PDH_CSTATUS_BAD_COUNTERNAME, "PdhValidatePathA failed 0x%08x\n", ret); + + ret = PdhValidatePathA( "\\System\\System Down Time" ); + ok(ret == PDH_CSTATUS_NO_COUNTER, "PdhValidatePathA failed 0x%08x\n", ret); + + ret = PdhValidatePathA( "\\System\\System Up Time" ); + ok(ret == ERROR_SUCCESS, "PdhValidatePathA failed 0x%08x\n", ret); +} + +static void test_PdhValidatePathW( void ) +{ + PDH_STATUS ret; + + static const WCHAR empty[] = {0}; + static const WCHAR system[] = {'\\','S','y','s','t','e','m',0}; + + ret = PdhValidatePathW( NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhValidatePathW failed 0x%08x\n", ret); + + ret = PdhValidatePathW( empty ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhValidatePathW failed 0x%08x\n", ret); + + ret = PdhValidatePathW( system ); + ok(ret == PDH_CSTATUS_BAD_COUNTERNAME, "PdhValidatePathW failed 0x%08x\n", ret); + + ret = PdhValidatePathW( uptime ); + ok(ret == PDH_CSTATUS_BAD_COUNTERNAME, "PdhValidatePathW failed 0x%08x\n", ret); + + ret = PdhValidatePathW( system_downtime ); + ok(ret == PDH_CSTATUS_NO_COUNTER, "PdhValidatePathW failed 0x%08x\n", ret); + + ret = PdhValidatePathW( system_uptime ); + ok(ret == ERROR_SUCCESS, "PdhValidatePathW failed 0x%08x\n", ret); +} + +static void test_PdhValidatePathExA( void ) +{ + PDH_STATUS ret; + + ret = pPdhValidatePathExA( NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhValidatePathExA failed 0x%08x\n", ret); + + ret = pPdhValidatePathExA( NULL, "" ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhValidatePathExA failed 0x%08x\n", ret); + + ret = pPdhValidatePathExA( NULL, "\\System" ); + ok(ret == PDH_CSTATUS_BAD_COUNTERNAME, "PdhValidatePathExA failed 0x%08x\n", ret); + + ret = pPdhValidatePathExA( NULL, "System Up Time" ); + ok(ret == PDH_CSTATUS_BAD_COUNTERNAME, "PdhValidatePathExA failed 0x%08x\n", ret); + + ret = pPdhValidatePathExA( NULL, "\\System\\System Down Time" ); + ok(ret == PDH_CSTATUS_NO_COUNTER, "PdhValidatePathExA failed 0x%08x\n", ret); + + ret = pPdhValidatePathExA( NULL, "\\System\\System Up Time" ); + ok(ret == ERROR_SUCCESS, "PdhValidatePathExA failed 0x%08x\n", ret); +} + +static void test_PdhValidatePathExW( void ) +{ + PDH_STATUS ret; + + static const WCHAR empty[] = {0}; + static const WCHAR system[] = {'\\','S','y','s','t','e','m',0}; + + ret = pPdhValidatePathExW( NULL, NULL ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhValidatePathExW failed 0x%08x\n", ret); + + ret = pPdhValidatePathExW( NULL, empty ); + ok(ret == PDH_INVALID_ARGUMENT, "PdhValidatePathExW failed 0x%08x\n", ret); + + ret = pPdhValidatePathExW( NULL, system ); + ok(ret == PDH_CSTATUS_BAD_COUNTERNAME, "PdhValidatePathExW failed 0x%08x\n", ret); + + ret = pPdhValidatePathExW( NULL, uptime ); + ok(ret == PDH_CSTATUS_BAD_COUNTERNAME, "PdhValidatePathExW failed 0x%08x\n", ret); + + ret = pPdhValidatePathExW( NULL, system_downtime ); + ok(ret == PDH_CSTATUS_NO_COUNTER, "PdhValidatePathExW failed 0x%08x\n", ret); + + ret = pPdhValidatePathExW( NULL, system_uptime ); + ok(ret == ERROR_SUCCESS, "PdhValidatePathExW failed 0x%08x\n", ret); +} + +static void test_PdhCollectQueryDataEx(void) +{ + PDH_STATUS status; + PDH_HQUERY query; + PDH_HCOUNTER counter; + HANDLE event; + BOOL ret; + UINT i; + + status = PdhOpenQueryA( NULL, 0, &query ); + ok(status == ERROR_SUCCESS, "PdhOpenQuery failed 0x%08x\n", status); + + event = CreateEventA( NULL, FALSE, FALSE, "winetest" ); + ok(event != NULL, "CreateEvent failed\n"); + + status = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter ); + ok(status == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08x\n", status); + + status = PdhCollectQueryDataEx( NULL, 1, event ); + ok(status == PDH_INVALID_HANDLE, "PdhCollectQueryDataEx failed 0x%08x\n", status); + + status = PdhCollectQueryDataEx( query, 1, NULL ); + ok(status == ERROR_SUCCESS, "PdhCollectQueryDataEx failed 0x%08x\n", status); + + status = PdhCollectQueryDataEx( query, 1, event ); + ok(status == ERROR_SUCCESS, "PdhCollectQueryDataEx failed 0x%08x\n", status); + + status = PdhCollectQueryData( query ); + ok(status == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08x\n", status); + + for (i = 0; i < 3; i++) + { + if (WaitForSingleObject( event, INFINITE ) == WAIT_OBJECT_0) + { + PDH_FMT_COUNTERVALUE value; + + status = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE, NULL, &value ); + ok(status == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08x\n", status); + + trace( "uptime %x%08x\n", (DWORD)(U(value).largeValue >> 32), (DWORD)U(value).largeValue ); + } + } + + ret = CloseHandle( event ); + ok(ret, "CloseHandle failed\n"); + + status = PdhCloseQuery( query ); + ok(status == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08x\n", status); +} + +static void test_PdhMakeCounterPathA(void) +{ + PDH_STATUS ret; + PDH_COUNTER_PATH_ELEMENTS_A e; + char buffer[1024]; + DWORD buflen; + + ret = PdhMakeCounterPathA(NULL, NULL, NULL, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + + buflen = 0; + ret = PdhMakeCounterPathA(NULL, NULL, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + + buflen = 0; + ret = PdhMakeCounterPathA(NULL, buffer, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + + buflen = sizeof(buffer); + memset(&e, 0, sizeof(e)); + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szMachineName = (char *)"machine"; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, ""), "expected \"machine\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szObjectName = (char *)"object"; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, ""), "expected \"machine\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szInstanceName = (char *)"instance"; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, ""), "expected \"machine\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szParentInstance = (char *)"parent"; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, ""), "expected \"machine\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.dwInstanceIndex = 1; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, ""), "expected \"machine\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szCounterName = (char *)"counter"; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == ERROR_SUCCESS, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, "\\\\machine\\object(parent/instance#1)\\counter"), + "expected \"\\\\machine\\object(parent/instance#1)\\counter\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szParentInstance = NULL; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == ERROR_SUCCESS, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, "\\\\machine\\object(instance#1)\\counter"), + "expected \"\\\\machine\\object(instance#1)\\counter\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szInstanceName = NULL; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == ERROR_SUCCESS, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, "\\\\machine\\object\\counter"), + "expected \"\\\\machine\\object\\counter\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szMachineName = NULL; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == ERROR_SUCCESS, "PdhMakeCounterPathA failed 0x%08x\n", ret); + ok(!strcmp(buffer, "\\object\\counter"), + "expected \"\\object\\counter\" got %s\n", buffer); + + buffer[0] = 0; + buflen = sizeof(buffer); + e.szObjectName = NULL; + ret = PdhMakeCounterPathA(&e, buffer, &buflen, 0); + ok(ret == PDH_INVALID_ARGUMENT, "PdhMakeCounterPathA failed 0x%08x\n", ret); +} + +START_TEST(pdh) +{ + if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH) + { + skip("non-english locale\n"); + return; + } + init_function_ptrs(); + + test_PdhOpenQueryA(); + test_PdhOpenQueryW(); + + test_PdhAddCounterA(); + test_PdhAddCounterW(); + + if (pPdhAddEnglishCounterA) test_PdhAddEnglishCounterA(); + if (pPdhAddEnglishCounterW) test_PdhAddEnglishCounterW(); + if (pPdhCollectQueryDataWithTime) test_PdhCollectQueryDataWithTime(); + + test_PdhGetFormattedCounterValue(); + test_PdhGetRawCounterValue(); + test_PdhSetCounterScaleFactor(); + test_PdhGetCounterTimeBase(); + + test_PdhGetCounterInfoA(); + test_PdhGetCounterInfoW(); + + test_PdhLookupPerfIndexByNameA(); + test_PdhLookupPerfIndexByNameW(); + + test_PdhLookupPerfNameByIndexA(); + test_PdhLookupPerfNameByIndexW(); + + test_PdhValidatePathA(); + test_PdhValidatePathW(); + + if (pPdhValidatePathExA) test_PdhValidatePathExA(); + if (pPdhValidatePathExW) test_PdhValidatePathExW(); + + test_PdhCollectQueryDataEx(); + test_PdhMakeCounterPathA(); +} diff --git a/rostests/winetests/pdh/pdh.rbuild b/rostests/winetests/pdh/pdh.rbuild new file mode 100644 index 00000000000..ee4439487d8 --- /dev/null +++ b/rostests/winetests/pdh/pdh.rbuild @@ -0,0 +1,9 @@ + + . + + pdh.c + testlist.c + wine + pdh + ntdll + diff --git a/rostests/winetests/pdh/testlist.c b/rostests/winetests/pdh/testlist.c new file mode 100644 index 00000000000..c480a0add8c --- /dev/null +++ b/rostests/winetests/pdh/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_pdh(void); + +const struct test winetest_testlist[] = +{ + { "pdh", func_pdh }, + { 0, 0 } +}; diff --git a/rostests/winetests/powrprof/powrprof.rbuild b/rostests/winetests/powrprof/powrprof.rbuild index 4d21fb5ca28..f8dea665b60 100644 --- a/rostests/winetests/powrprof/powrprof.rbuild +++ b/rostests/winetests/powrprof/powrprof.rbuild @@ -1,12 +1,11 @@ . - + powrprof ntdll advapi32 - kernel32 testlist.c pwrprof.c diff --git a/rostests/winetests/powrprof/pwrprof.c b/rostests/winetests/powrprof/pwrprof.c index 4bd1271dae7..18c6fe2ebe3 100644 --- a/rostests/winetests/powrprof/pwrprof.c +++ b/rostests/winetests/powrprof/pwrprof.c @@ -6,9 +6,10 @@ #include "winternl.h" #include "windef.h" #include "winbase.h" +#include "winreg.h" #include "powrprof.h" #include "assert.h" - +#include "winnt.h" #include "wine/unicode.h" /* LONG WINAPI RegOpenCurrentUser(REGSAM a,PHKEY b) @@ -45,10 +46,7 @@ static const WCHAR szMachPowerPoliciesSubKey[] = { 'S', 'O', 'F', 'T', 'W', 'A', static const WCHAR szTempPwrScheme[] = { '9', '9', 0 }; -ULONG DbgPrint(PCCH X,...) -{ - return (ULONG)NULL; -} +void test_ValidatePowerPolicies_Next(PGLOBAL_POWER_POLICY pGPP_original,PPOWER_POLICY pPP_original); void test_CallNtPowerInformation(void) { @@ -69,7 +67,7 @@ void test_CallNtPowerInformation(void) retval = CallNtPowerInformation(AdministratorPowerPolicy, 0, 0, &apolicy, sizeof(ADMINISTRATOR_POWER_POLICY)); ok(retval == STATUS_SUCCESS, "function expected STATUS_SUCCESS but got %d\n", (UINT)retval); retval = CallNtPowerInformation(AdministratorPowerPolicy, &apolicy, sizeof(ADMINISTRATOR_POWER_POLICY), 0, 0); - ok(retval != STATUS_PRIVILEGE_NOT_HELD, "Privileg not held!!!! more errors to expect"); + ok(retval != STATUS_PRIVILEGE_NOT_HELD, "Privileg not held!!!! more errors to expect\n"); ok(retval == STATUS_SUCCESS, "function expected STATUS_SUCCESS but got %d\n", (UINT)retval); /* LastSleepTime tests */ @@ -385,7 +383,7 @@ void test_DeletePwrScheme(void) if (RegOpenKeyW(HKEY_LOCAL_MACHINE, szMachPowerPoliciesSubKey, &hSubKey) == ERROR_SUCCESS) { if (RegDeleteKeyW(hSubKey, szTempPwrScheme) != STATUS_SUCCESS) - printf("failed to delete subkey %i (testentry)\n", g_TempPwrScheme); + printf("#1 failed to delete subkey %i (testentry)\n", g_TempPwrScheme); RegCloseKey(hSubKey); } @@ -490,22 +488,22 @@ void test_GetCurrentPowerPolicies(void) ok(ret, "function was expected to succeed, error %x\n",(UINT)GetLastError()); ret = SetActivePwrScheme(0, &gpp, 0); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); ret = SetActivePwrScheme(0, 0, &pp); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); ret = SetActivePwrScheme(0, &gpp, &pp); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); ret = SetActivePwrScheme(current_scheme, &gpp, 0); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); ret = SetActivePwrScheme(current_scheme, 0, &pp); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); ret = SetActivePwrScheme(current_scheme, &gpp, &pp); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); ret = SetActivePwrScheme(g_ActivePwrScheme, 0, 0); ok(ret, "Warning: failed to restore old active power scheme %d\n", (UINT)g_ActivePwrScheme); @@ -521,10 +519,10 @@ void test_GetCurrentPowerPolicies(void) ret = GetCurrentPowerPolicies(&gpp,&pp); ok(ret, "function was expected to succeed, error %x\n",(UINT)GetLastError()); - ok(gpp.mach.Revision == 1,"Global Mach Revision was expected to be 1 got %i",(UINT)gpp.mach.Revision); - ok(gpp.user.Revision == 1,"Global User Revision was expected to be 1 got %i",(UINT)gpp.mach.Revision); - ok(pp.mach.Revision == 1,"Mach Revision was expected to be 1 got %i",(UINT)gpp.mach.Revision); - ok(pp.user.Revision == 1,"User Revision was expected to be 1 got %i",(UINT)gpp.mach.Revision); + ok(gpp.mach.Revision == 1,"Global Mach Revision was expected to be 1 got %i\n",(UINT)gpp.mach.Revision); + ok(gpp.user.Revision == 1,"Global User Revision was expected to be 1 got %i\n",(UINT)gpp.mach.Revision); + ok(pp.mach.Revision == 1,"Mach Revision was expected to be 1 got %i\n",(UINT)gpp.mach.Revision); + ok(pp.user.Revision == 1,"User Revision was expected to be 1 got %i\n",(UINT)gpp.mach.Revision); ret = GetActivePwrScheme(&g_ActivePwrScheme); @@ -605,10 +603,10 @@ void test_IsAdminOverrideActive(void) BOOLEAN ret; ret = IsAdminOverrideActive(0); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); ret = IsAdminOverrideActive(&app); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); app.MinSleep = 0; app.MaxSleep = 0; @@ -618,7 +616,7 @@ void test_IsAdminOverrideActive(void) app.MaxSpindownTimeout = 0; ret = IsAdminOverrideActive(&app); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); app.MinSleep = 1; app.MaxSleep = 2; @@ -628,7 +626,7 @@ void test_IsAdminOverrideActive(void) app.MaxSpindownTimeout = 6; ret = IsAdminOverrideActive(&app); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); } @@ -638,7 +636,7 @@ void test_IsPwrHibernateAllowed(void) BOOLEAN ret; ret = IsPwrHibernateAllowed(); - ok(!ret, "function was expected to fail, error %x\n",(UINT)GetLastError()); + ok(!ret, "function was expected to fail\n"); */ } @@ -669,8 +667,8 @@ void test_ReadGlobalPwrPolicy(void) ret = ReadGlobalPwrPolicy(&gpp); ok(ret, "function was expected to succeed, error %x\n",(UINT)GetLastError()); - ok(gpp.mach.Revision == 1,"Global Mach Revision was expected to be 1 got %i",(UINT)gpp.mach.Revision); - ok(gpp.user.Revision == 1,"Global User Revision was expected to be 1 got %i",(UINT)gpp.mach.Revision); + ok(gpp.mach.Revision == 1,"Global Mach Revision was expected to be 1 got %i\n",(UINT)gpp.mach.Revision); + ok(gpp.user.Revision == 1,"Global User Revision was expected to be 1 got %i\n",(UINT)gpp.mach.Revision); @@ -689,9 +687,9 @@ void test_ReadProcessorPwrScheme(void) ret = ReadProcessorPwrScheme(i,&mppp); if (ret) { - ok(mppp.Revision == 1,"Main Revision was expected to be 1 got %i",(UINT)mppp.Revision); - ok(mppp.ProcessorPolicyAc.Revision == 1,"PowerAC Revision was expected to be 1 got %i",(UINT)mppp.ProcessorPolicyAc.Revision); - ok(mppp.ProcessorPolicyDc.Revision == 1,"PowerDC Revision was expected to be 1 got %i",(UINT)mppp.ProcessorPolicyDc.Revision); + ok(mppp.Revision == 1,"Main Revision was expected to be 1 got %i\n",(UINT)mppp.Revision); + ok(mppp.ProcessorPolicyAc.Revision == 1,"PowerAC Revision was expected to be 1 got %i\n",(UINT)mppp.ProcessorPolicyAc.Revision); + ok(mppp.ProcessorPolicyDc.Revision == 1,"PowerDC Revision was expected to be 1 got %i\n",(UINT)mppp.ProcessorPolicyDc.Revision); } else { @@ -739,12 +737,441 @@ void test_SetSuspendState(void) // SetSuspendState(FALSE,FALSE,FALSE) } -void test_ValidatePowerPolicies(void) + +BOOLEAN globalcompare(GLOBAL_POWER_POLICY gpp, GLOBAL_POWER_POLICY gpp_compare) +{ + //return TRUE; + int i,j; + BOOLEAN ret; + + ret = TRUE; + if (gpp.mach.BroadcastCapacityResolution != gpp_compare.mach.BroadcastCapacityResolution) + { + printf("mach.BroadcastCapacityResolution failed %i != %i\n",gpp.mach.BroadcastCapacityResolution,gpp_compare.mach.BroadcastCapacityResolution); + ret = FALSE; + } + if (gpp.mach.LidOpenWakeAc != gpp_compare.mach.LidOpenWakeAc) + { + printf("mach.LidOpenWakeAc failed %i != %i\n",gpp.mach.LidOpenWakeAc,gpp_compare.mach.LidOpenWakeAc); + ret = FALSE; + } + if (gpp.mach.LidOpenWakeDc != gpp_compare.mach.LidOpenWakeDc) + { + printf("mach.LidOpenWakeDc failed %i != %i\n",gpp.mach.LidOpenWakeDc,gpp_compare.mach.LidOpenWakeDc); + ret = FALSE; + } + if (gpp.mach.Revision != gpp_compare.mach.Revision) + { + printf("mach.Revision failed %i != %i\n",gpp.mach.Revision,gpp_compare.mach.Revision); + ret = FALSE; + } + + if (gpp.user.PowerButtonAc.Action != gpp_compare.user.PowerButtonAc.Action) + { + printf("user.PowerButtonAc.Action failed %i != %i\n",gpp.user.PowerButtonAc.Action,gpp_compare.user.PowerButtonAc.Action); + ret = FALSE; + } + if (gpp.user.PowerButtonAc.EventCode != gpp_compare.user.PowerButtonAc.EventCode) + { + printf("user.PowerButtonAc.EventCode failed %i != %i\n",gpp.user.PowerButtonAc.EventCode,gpp_compare.user.PowerButtonAc.EventCode); + ret = FALSE; + } + if (gpp.user.PowerButtonAc.Flags != gpp_compare.user.PowerButtonAc.Flags) + { + printf("user.PowerButtonAc.Flags failed %i != %i\n",gpp.user.PowerButtonAc.Flags,gpp_compare.user.PowerButtonAc.Flags); + ret = FALSE; + } + if (gpp.user.PowerButtonDc.Action != gpp_compare.user.PowerButtonDc.Action) + { + printf("user.PowerButtonDc.Action failed %i != %i\n",gpp.user.PowerButtonDc.Action,gpp_compare.user.PowerButtonDc.Action); + ret = FALSE; + } + if (gpp.user.PowerButtonDc.EventCode != gpp_compare.user.PowerButtonDc.EventCode) + { + printf("user.PowerButtonDc.EventCode failed %i != %i\n",gpp.user.PowerButtonDc.EventCode,gpp_compare.user.PowerButtonDc.EventCode); + ret = FALSE; + } + if (gpp.user.PowerButtonDc.Flags != gpp_compare.user.PowerButtonDc.Flags) + { + printf("user.PowerButtonDc.Flags failed %i != %i\n",gpp.user.PowerButtonDc.Flags,gpp_compare.user.PowerButtonDc.Flags); + ret = FALSE; + } + if (gpp.user.SleepButtonAc.Action != gpp_compare.user.SleepButtonAc.Action) + { + printf("user.SleepButtonAc.Action failed %i != %i\n",gpp.user.SleepButtonAc.Action,gpp_compare.user.SleepButtonAc.Action); + ret = FALSE; + } + if (gpp.user.SleepButtonAc.EventCode != gpp_compare.user.SleepButtonAc.EventCode) + { + printf("user.SleepButtonAc.EventCode failed %i != %i\n",gpp.user.SleepButtonAc.EventCode,gpp_compare.user.SleepButtonAc.EventCode); + ret = FALSE; + } + if (gpp.user.SleepButtonAc.Flags != gpp_compare.user.SleepButtonAc.Flags) + { + printf("user.SleepButtonAc.Flags failed %i != %i\n",gpp.user.SleepButtonAc.Flags,gpp_compare.user.SleepButtonAc.Flags); + ret = FALSE; + } + if (gpp.user.SleepButtonDc.Action != gpp_compare.user.SleepButtonDc.Action) + { + printf("user.SleepButtonDc.Action failed %i != %i\n",gpp.user.SleepButtonDc.Action,gpp_compare.user.SleepButtonDc.Action); + ret = FALSE; + } + if (gpp.user.SleepButtonDc.EventCode != gpp_compare.user.SleepButtonDc.EventCode) + { + printf("user.SleepButtonDc.EventCode failed %i != %i\n",gpp.user.SleepButtonDc.EventCode,gpp_compare.user.SleepButtonDc.EventCode); + ret = FALSE; + } + if (gpp.user.SleepButtonDc.Flags != gpp_compare.user.SleepButtonDc.Flags) + { + printf("user.SleepButtonDc.Flags failed %i != %i\n",gpp.user.SleepButtonDc.Flags,gpp_compare.user.SleepButtonDc.Flags); + ret = FALSE; + } + if (gpp.user.LidCloseAc.Action != gpp_compare.user.LidCloseAc.Action) + { + printf("user.LidCloseAc.Action failed %i != %i\n",gpp.user.LidCloseAc.Action,gpp_compare.user.LidCloseAc.Action); + ret = FALSE; + } + if (gpp.user.LidCloseAc.EventCode != gpp_compare.user.LidCloseAc.EventCode) + { + printf("user.LidCloseAc.EventCode failed %i != %i\n",gpp.user.LidCloseAc.EventCode,gpp_compare.user.LidCloseAc.EventCode); + ret = FALSE; + } + if (gpp.user.LidCloseAc.Flags != gpp_compare.user.LidCloseAc.Flags) + { + printf("user.LidCloseAc.Flags failed %i != %i\n",gpp.user.LidCloseAc.Flags,gpp_compare.user.LidCloseAc.Flags); + ret = FALSE; + } + if (gpp.user.LidCloseDc.Action != gpp_compare.user.LidCloseDc.Action) + { + printf("user.LidCloseDc.Action failed %i != %i\n",gpp.user.LidCloseDc.Action,gpp_compare.user.LidCloseDc.Action); + ret = FALSE; + } + if (gpp.user.LidCloseDc.EventCode != gpp_compare.user.LidCloseDc.EventCode) + { + printf("user.LidCloseDc.EventCode failed %i != %i\n",gpp.user.LidCloseDc.EventCode,gpp_compare.user.LidCloseDc.EventCode); + ret = FALSE; + } + if (gpp.user.LidCloseDc.Flags != gpp_compare.user.LidCloseDc.Flags) + { + printf("user.LidCloseDc.Flags failed %i != %i\n",gpp.user.LidCloseDc.Flags,gpp_compare.user.LidCloseDc.Flags); + ret = FALSE; + } + + for(i=0;imach.LidOpenWakeAc);//1 + //printf("Old: %i\n",pGPP_original->mach.LidOpenWakeDc);//1 + //printf("Old: %i,%i,%i \n",pGPP_original->user.LidCloseAc.Action,pGPP_original->user.LidCloseAc.EventCode,pGPP_original->user.LidCloseAc.Flags);//7 + //printf("Old: %i,%i,%i \n",pGPP_original->user.LidCloseDc.Action,pGPP_original->user.LidCloseDc.EventCode,pGPP_original->user.LidCloseDc.Flags);//7 + //printf("Old: %i,%i,%i \n",pGPP_original->user.PowerButtonAc.Action,pGPP_original->user.PowerButtonAc.EventCode,pGPP_original->user.PowerButtonAc.Flags);//0,0,0 + //printf("Old: %i,%i,%i \n",pGPP_original->user.PowerButtonDc.Action,pGPP_original->user.PowerButtonDc.EventCode,pGPP_original->user.PowerButtonDc.Flags);//7,0,0 + //printf("Old: %i,%i,%i \n",pGPP_original->user.SleepButtonAc.Action,pGPP_original->user.SleepButtonAc.EventCode,pGPP_original->user.SleepButtonAc.Flags);//7,0,0 + //printf("Old: %i,%i,%i \n",pGPP_original->user.SleepButtonDc.Action,pGPP_original->user.SleepButtonDc.EventCode,pGPP_original->user.SleepButtonDc.Flags);//7,0,0 + //printf("Old: %i \n",pPP_original->mach.DozeS4TimeoutAc);//0 + //printf("Old: %i \n",pPP_original->mach.DozeS4TimeoutDc);//0 + //printf("Old: %i \n",pPP_original->mach.DozeTimeoutAc);//0 + //printf("Old: %i \n",pPP_original->mach.DozeTimeoutDc);//0 + //printf("Old: %i \n",pPP_original->mach.MinSleepAc);//1 + //printf("Old: %i \n",pPP_original->mach.MinSleepDc);//1 + //printf("Old: %i \n",pPP_original->mach.MinThrottleAc);//0 + //printf("Old: %i \n",pPP_original->mach.MinThrottleDc);//0 + //printf("Old: %i,%i,%i \n",pPP_original->mach.OverThrottledAc.Action,pPP_original->mach.OverThrottledAc.EventCode,pPP_original->mach.OverThrottledAc.Flags);//0,0,0 + //printf("Old: %i,%i,%i \n",pPP_original->mach.OverThrottledDc.Action,pPP_original->mach.OverThrottledDc.EventCode,pPP_original->mach.OverThrottledDc.Flags);//0,0,0 + //printf("Old: %i \n",pPP_original->mach.ReducedLatencySleepAc);//1 + //printf("Old: %i \n",pPP_original->mach.ReducedLatencySleepDc);//1 + //printf("Old: %i \n",pPP_original->user.FanThrottleToleranceAc);//0 + //printf("Old: %i \n",pPP_original->user.FanThrottleToleranceDc);//0 + //printf("Old: %i \n",pPP_original->user.ForcedThrottleAc);//0 + //printf("Old: %i \n",pPP_original->user.ForcedThrottleDc);//0 + //printf("Old: %i,%i,%i \n",pPP_original->user.IdleAc.Action,pPP_original->user.IdleAc.EventCode,pPP_original->user.IdleAc.Flags);//0,0,0 + //printf("Old: %i,%i,%i \n",pPP_original->user.IdleDc.Action,pPP_original->user.IdleDc.EventCode,pPP_original->user.IdleDc.Flags);//0,0,0 + //printf("Old: %i \n",pPP_original->user.IdleSensitivityAc);//0 + //printf("Old: %i \n",pPP_original->user.IdleSensitivityDc);//0 + //printf("Old: %i \n",pPP_original->user.IdleTimeoutAc);//0 + //printf("Old: %i \n",pPP_original->user.IdleTimeoutDc);//0 + //printf("Old: %i \n",pPP_original->user.MaxSleepAc);//1 + //printf("Old: %i \n",pPP_original->user.MaxSleepDc);//1 + //printf("Old: %i \n",pPP_original->user.OptimizeForPowerAc);//0 + //printf("Old: %i \n",pPP_original->user.OptimizeForPowerDc);//0 + //printf("Old: %i \n",pPP_original->user.SpindownTimeoutAc);//0 + //printf("Old: %i \n",pPP_original->user.SpindownTimeoutDc);//0 + //printf("Old: %i \n",pPP_original->user.ThrottlePolicyAc);//0 + //printf("Old: %i \n",pPP_original->user.ThrottlePolicyDc);//0 + //printf("Old: %i \n",pPP_original->user.VideoTimeoutAc);//0 + //printf("Old: %i \n",pPP_original->user.VideoTimeoutDc);//0 + + pPP_original->mach.MinSleepAc=4; +pPP_original->mach.MinSleepDc=4; +pPP_original->user.MaxSleepAc=4; +pPP_original->user.MaxSleepDc=4; +pPP_original->user.OptimizeForPowerAc=1; +pPP_original->user.OptimizeForPowerDc=1; + + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ok(compare(pp,pp_compare),"Difference Found\n"); + + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemUnspecified-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemUnspecified-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemUnspecified; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemWorking; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemSleeping1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.mach.LidOpenWakeAc=4; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemSleeping2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.mach.LidOpenWakeAc=4; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemSleeping3; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.mach.LidOpenWakeAc=4; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemMaximum; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemMaximum+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeAc=PowerSystemMaximum+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pGPP_original->mach.LidOpenWakeAc=PowerSystemWorking; + + + pGPP_original->mach.LidOpenWakeDc=PowerSystemUnspecified-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemUnspecified-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemUnspecified; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemWorking; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemSleeping1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.mach.LidOpenWakeDc=4; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemSleeping2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.mach.LidOpenWakeDc=4; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemSleeping3; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.mach.LidOpenWakeDc=4; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemMaximum; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemMaximum+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->mach.LidOpenWakeDc=PowerSystemMaximum+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pGPP_original->mach.LidOpenWakeDc=PowerSystemWorking; + + pGPP_original->user.LidCloseAc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.LidCloseAc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.LidCloseAc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseAc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pGPP_original->user.LidCloseAc.Action=PowerActionWarmEject; + + + pGPP_original->user.LidCloseDc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.LidCloseDc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.LidCloseDc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.LidCloseDc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pGPP_original->user.LidCloseDc.Action=PowerActionWarmEject; + + + pGPP_original->user.PowerButtonAc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.PowerButtonAc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.PowerButtonAc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonAc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pGPP_original->user.PowerButtonAc.Action=PowerActionNone; + + + pGPP_original->user.PowerButtonDc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.PowerButtonDc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.PowerButtonDc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.PowerButtonDc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pGPP_original->user.PowerButtonDc.Action=PowerActionWarmEject; + + + pGPP_original->user.SleepButtonAc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.SleepButtonAc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.SleepButtonAc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonAc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pGPP_original->user.SleepButtonAc.Action=PowerActionWarmEject; + + + pGPP_original->user.SleepButtonDc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.SleepButtonDc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + gpp_compare.user.SleepButtonDc.Action=2; + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pGPP_original->user.SleepButtonDc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pGPP_original->user.SleepButtonDc.Action=PowerActionWarmEject; + + + pPP_original->mach.MinSleepAc=PowerSystemUnspecified-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemUnspecified-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemUnspecified; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemWorking; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemSleeping1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemSleeping2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemSleeping3; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemMaximum; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemMaximum+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepAc=PowerSystemMaximum+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->mach.MinSleepAc=PowerSystemSleeping3; + + + pPP_original->mach.MinSleepDc=PowerSystemUnspecified-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemUnspecified-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemUnspecified; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemWorking; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemSleeping1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemSleeping2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemSleeping3; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.MinSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemMaximum; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemMaximum+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.MinSleepDc=PowerSystemMaximum+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->mach.MinSleepDc=PowerSystemSleeping3; + + + pPP_original->mach.OverThrottledAc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledAc.Action=4; + pp_compare.mach.OverThrottledAc.Action=2; + pp_compare.mach.pad1[2]=2; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.OverThrottledAc.Action=2; + pp_compare.mach.pad1[2]=2; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledAc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->mach.OverThrottledAc.Action=PowerActionNone; + + + pPP_original->mach.OverThrottledDc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledDc.Action=4; + pp_compare.mach.OverThrottledDc.Action=2; + pp_compare.mach.OverThrottledAc.Action=0; + pp_compare.mach.pad1[2]=0; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.OverThrottledDc.Action=2; + pp_compare.mach.OverThrottledAc.Action=0; + pp_compare.mach.pad1[2]=0; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.OverThrottledDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.OverThrottledDc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->mach.OverThrottledDc.Action=PowerActionNone; + + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemUnspecified-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.ReducedLatencySleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemUnspecified-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.ReducedLatencySleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemUnspecified; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.ReducedLatencySleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemWorking; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.ReducedLatencySleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemSleeping1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.ReducedLatencySleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemSleeping2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.ReducedLatencySleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemSleeping3; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.ReducedLatencySleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemMaximum; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemMaximum+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepAc=PowerSystemMaximum+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->mach.ReducedLatencySleepAc=PowerSystemWorking; + + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemUnspecified-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.ReducedLatencySleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemUnspecified-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.ReducedLatencySleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemUnspecified; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.ReducedLatencySleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemWorking; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.mach.ReducedLatencySleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemSleeping1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.ReducedLatencySleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemSleeping2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.ReducedLatencySleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemSleeping3; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.mach.ReducedLatencySleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemMaximum; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemMaximum+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->mach.ReducedLatencySleepDc=PowerSystemMaximum+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %x\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->mach.ReducedLatencySleepDc=PowerSystemWorking; + + + pPP_original->user.IdleAc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleAc.Action=4; + pp_compare.user.IdleAc.Action=2; + //pp_compare.user.pad1[2]=2; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.IdleAc.Action=2; + //pp_compare.user.pad1[2]=2; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleAc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleAc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->user.IdleAc.Action=PowerActionNone; + + + + pPP_original->user.IdleDc.Action=PowerActionNone-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionNone-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionNone; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionReserved; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleDc.Action=4; + pp_compare.user.IdleDc.Action=2; +// pp_compare.user.pad1[2]=2; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionSleep; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.IdleDc.Action=2; +// pp_compare.user.pad1[2]=2; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionShutdownReset; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.IdleDc.Action=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionShutdownOff; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionWarmEject; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionWarmEject+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.IdleDc.Action=PowerActionWarmEject+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_DATA, "expected ERROR_INVALID_DATA but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->user.IdleDc.Action=PowerActionNone; + + + pPP_original->user.MaxSleepAc=PowerSystemUnspecified-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemUnspecified-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemUnspecified; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemWorking; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemSleeping1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemSleeping2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemSleeping3; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemMaximum; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemMaximum+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepAc=PowerSystemMaximum+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepAc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->user.MaxSleepAc=PowerSystemSleeping3; + + + pPP_original->user.MaxSleepDc=PowerSystemUnspecified-2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemUnspecified-1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemUnspecified; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(!ret, "function was expected to fail\n"); + ok(GetLastError() == ERROR_GEN_FAILURE, "expected ERROR_GEN_FAILURE but got %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + //pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemWorking; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemSleeping1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemSleeping2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemSleeping3; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemHibernate; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemShutdown; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemMaximum; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemMaximum+1; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + + pPP_original->user.MaxSleepDc=PowerSystemMaximum+2; + memcpy(&gpp, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&gpp_compare, pGPP_original, sizeof(GLOBAL_POWER_POLICY)); + memcpy(&pp, pPP_original, sizeof(POWER_POLICY)); + memcpy(&pp_compare, pPP_original, sizeof(POWER_POLICY)); + ret = ValidatePowerPolicies(&gpp,&pp); + ok(ret, "function was expected to succeed error %i\n",(UINT)GetLastError()); + ok(globalcompare(gpp,gpp_compare),"Difference Found\n"); + pp_compare.user.MaxSleepDc=4; + ok(compare(pp,pp_compare),"Difference Found\n"); + pPP_original->user.MaxSleepDc=PowerSystemSleeping3; + +} + void test_WriteGlobalPwrPolicy(void) { // WriteGlobalPwrPolicy(&gpp); @@ -867,6 +4848,10 @@ void test_WriteProcessorPwrScheme(void) void test_WritePwrScheme(void) { DWORD retval; + HKEY hSubKey; + LONG lSize; + LONG Err; + WCHAR szPath[MAX_PATH]; static const WCHAR szTestSchemeName[] = {'P','o','w','r','p','r','o','f',0}; static const WCHAR szTestSchemeDesc[] = {'P','o','w','r','p','r','o','f',' ','S','c','h','e','m','e',0}; @@ -876,6 +4861,15 @@ void test_WritePwrScheme(void) retval = WritePwrScheme(&g_TempPwrScheme, (LPWSTR)szTestSchemeName, (LPWSTR)szTestSchemeDesc, &g_PowerPolicy); ok(retval, "Warning: function should have succeeded\n"); + if (RegOpenKeyW(HKEY_LOCAL_MACHINE, szMachPowerPoliciesSubKey, &hSubKey) == ERROR_SUCCESS) + { + lSize = MAX_PATH * sizeof(WCHAR); + Err = RegQueryValueW(hSubKey, szTempPwrScheme, szPath, &lSize); + if (Err != STATUS_SUCCESS) + printf("#1 failed to query subkey %i (testentry)\n", g_TempPwrScheme); + RegCloseKey(hSubKey); +} + } void func_power(void) @@ -899,197 +4893,9 @@ void func_power(void) test_ReadGlobalPwrPolicy(); test_ReadProcessorPwrScheme(); test_SetSuspendState(); + test_ValidatePowerPolicies_Old(); test_ValidatePowerPolicies(); test_WriteGlobalPwrPolicy(); test_WriteProcessorPwrScheme(); } - -void func_ros_init(void) -{ - HKEY hUser, hKeyPowrCfg, hKeyGlobalPowrPol, hKeyPowerPolicies, hKeytmp; - DWORD err; - GLOBAL_USER_POWER_POLICY gupp; - GLOBAL_MACHINE_POWER_POLICY gmpp; - USER_POWER_POLICY upp; - MACHINE_POWER_POLICY mpp; - MACHINE_PROCESSOR_POWER_POLICY mppp; - GLOBAL_POWER_POLICY gpp; - POWER_POLICY pp; - - int i; - - static const WCHAR szUserPowrCfgKey[] = { 'C', 'o', 'n', 't', 'r', 'o', 'l', ' ', - 'P', 'a', 'n', 'e', 'l', '\\', 'P', 'o', 'w', 'e', 'r', 'C', 'f', 'g', 0}; - - static const WCHAR szCurrentPowerPolicy[] = {'C', 'u', 'r', 'r', 'e', 'n', 't', 'P', - 'o', 'w', 'e', 'r', 'P', 'o', 'l', 'i', 'c', 'y', 0}; - static const WCHAR szcpp[] = {'3', 0 }; - - static const WCHAR szGlobalPowerPolicy[] = { 'G', 'l', 'o', 'b', 'a', 'l', 'P', 'o', - 'w', 'e', 'r', 'P', 'o', 'l', 'i', 'c', 'y', 0}; - static const WCHAR szPolicies[] = {'P', 'o', 'l', 'i', 'c', 'i', 'e', 's', 0}; - static const WCHAR szPowerPolicies[] = { 'P', 'o', 'w', 'e', 'r', 'P', 'o', 'l', 'i', - 'c', 'i', 'e', 's', 0}; - - static const WCHAR szProcessorPolicies[] = { 'P', 'r', 'o', 'c', 'e', 's', 's', 'o', 'r', - 'P', 'o', 'l', 'i', 'c', 'i', 'e', 's', 0}; - - static const WCHAR szcName[] = {'N', 'a', 'm', 'e', 0}; - static const WCHAR szcDescription[] = {'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 0}; - - static WCHAR szName[] = {'N', 'a', 'm', 'e', '(', '0', ')', 0}; - static WCHAR szDescription[] = {'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', '(', '0', ')', 0}; - - static const WCHAR szMachPowrCfgKey[] = {'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\', 'M', 'i', - 'c', 'r', 'o', 's', 'o', 'f', 't', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 'C', 'u', - 'r', 'r', 'e', 'n', 't', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\\', 'C', 'o', 'n', 't', 'r', - 'o', 'l', 's', ' ', 'F', 'o', 'l', 'd', 'e', 'r', '\\', 'P', 'o', 'w', 'e', 'r', 'C', 'f', 'g', 0}; - - static const WCHAR szLastID[] = {'L', 'a', 's', 't', 'I', 'D', 0}; - static const WCHAR szDiskSpinDownMax[] = {'D', 'i', 's', 'k', 'S', 'p', 'i', 'n', 'D', 'o', 'w', 'n', 'M', 'a', 'x', 0}; - static const WCHAR szDiskSpinDownMin[] = {'D', 'i', 's', 'k', 'S', 'p', 'i', 'n', 'D', 'o', 'w', 'n', 'M', 'i', 'n', 0}; - - static const WCHAR szLastIDValue[] = {'5', 0}; - static const WCHAR szDiskSpinDownMaxValue[] = {'3', '6', '0', '0', 0}; - static const WCHAR szDiskSpinDownMinValue[] = {'3', 0}; - - WCHAR tmp[20]; - /* - * Erstelle die Registry-struktur und Daten, welche dafür erforderlich ist damit diese Tests funktionieren - */ - - /* - * User - */ - err = RegOpenCurrentUser(KEY_ALL_ACCESS,&hUser); - ok(err == ERROR_SUCCESS,"Öffnen des Aktuellen Users Fehlgeschlagen\n"); - if (err == ERROR_SUCCESS) - { - err = RegCreateKey(hUser,szUserPowrCfgKey,&hKeyPowrCfg); - ok(err == ERROR_SUCCESS,"Create Key UserPowrCfg failed with error %i\n",(UINT)err); - ok(hKeyPowrCfg != NULL,"Erstellen des Eintrages Powercfg fehlgeschalgen\n"); - err = RegSetValueExW(hKeyPowrCfg,szCurrentPowerPolicy,(DWORD)NULL,REG_SZ,(CONST BYTE *)szcpp,strlenW(szcpp)*sizeof(WCHAR)); - ok(err == ERROR_SUCCESS,"Set Value CurrentPowerPolicy failed with error %i\n",(UINT)err); - err = RegCreateKey(hKeyPowrCfg,szGlobalPowerPolicy,&hKeyGlobalPowrPol); - ok(err == ERROR_SUCCESS,"Create Key GlobalPowerPolicy failed with error %i\n",(UINT)err); - gupp.Revision = 1; - gupp.PowerButtonAc.Action = PowerActionNone; - gupp.PowerButtonDc.Action = PowerActionNone; - gupp.SleepButtonAc.Action = PowerActionNone; - gupp.SleepButtonDc.Action = PowerActionNone; - gupp.LidCloseAc.Action = PowerActionNone; - gupp.LidCloseDc.Action = PowerActionNone; - for (i=0; i - . - - kernel32 + ntdll psapi testlist.c psapi_main.c - diff --git a/rostests/winetests/psapi/psapi_main.c b/rostests/winetests/psapi/psapi_main.c index 1978fd4d787..7921c8d537c 100644 --- a/rostests/winetests/psapi/psapi_main.c +++ b/rostests/winetests/psapi/psapi_main.c @@ -21,10 +21,17 @@ #include #include -#include "wine/test.h" #include "windows.h" +#include "wine/test.h" #include "psapi.h" +#define expect_eq_d(expected, actual) \ + do { \ + int value = (actual); \ + ok((expected) == value, "Expected " #actual " to be %d (" #expected ") is %d\n", \ + (expected), value); \ + } while (0) + #define PSAPI_GET_PROC(func) \ p ## func = (void*)GetProcAddress(hpsapi, #func); \ if(!p ## func) { \ @@ -63,6 +70,7 @@ static DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE, HMODULE, LPSTR, DWORD); static BOOL (WINAPI *pGetModuleInformation)(HANDLE, HMODULE, LPMODULEINFO, DWORD); static DWORD (WINAPI *pGetMappedFileNameA)(HANDLE, LPVOID, LPSTR, DWORD); static DWORD (WINAPI *pGetProcessImageFileNameA)(HANDLE, LPSTR, DWORD); +static DWORD (WINAPI *pGetProcessImageFileNameW)(HANDLE, LPWSTR, DWORD); static BOOL (WINAPI *pGetProcessMemoryInfo)(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD); static BOOL (WINAPI *pGetWsChanges)(HANDLE, PPSAPI_WS_WATCH_INFORMATION, DWORD); static BOOL (WINAPI *pInitializeProcessForWsWatch)(HANDLE); @@ -84,6 +92,8 @@ static BOOL InitFunctionPtrs(HMODULE hpsapi) /* GetProcessImageFileName is not exported on NT4 */ pGetProcessImageFileNameA = (void *)GetProcAddress(hpsapi, "GetProcessImageFileNameA"); + pGetProcessImageFileNameW = + (void *)GetProcAddress(hpsapi, "GetProcessImageFileNameW"); return TRUE; } @@ -166,6 +176,7 @@ static void test_GetProcessImageFileName(void) { HMODULE hMod = GetModuleHandle(NULL); char szImgPath[MAX_PATH], szMapPath[MAX_PATH]; + WCHAR szImgPathW[MAX_PATH]; DWORD ret; if(pGetProcessImageFileNameA == NULL) @@ -175,28 +186,51 @@ static void test_GetProcessImageFileName(void) SetLastError(0xdeadbeef); if(!pGetProcessImageFileNameA(hpQI, szImgPath, sizeof(szImgPath))) { - if(GetLastError() == ERROR_INVALID_FUNCTION) - trace("GetProcessImageFileName not implemented\n"); - else if(GetLastError() == 0xdeadbeef) - ok(0, "failed without error code\n"); - else - ok(0, "failed with %d\n", GetLastError()); - + if(GetLastError() == ERROR_INVALID_FUNCTION) { + win_skip("GetProcessImageFileName not implemented\n"); return; } - w32_err(pGetProcessImageFileNameA(NULL, szImgPath, sizeof(szImgPath)), ERROR_INVALID_HANDLE); - w32_err(pGetProcessImageFileNameA(hpSR, szImgPath, sizeof(szImgPath)), ERROR_ACCESS_DENIED); - w32_err(pGetProcessImageFileNameA(hpQI, szImgPath, 0), ERROR_INSUFFICIENT_BUFFER); - if(!w32_suc(ret = pGetProcessImageFileNameA(hpQI, szImgPath, sizeof(szImgPath))) || - !w32_suc(pGetMappedFileNameA(hpQV, hMod, szMapPath, sizeof(szMapPath)))) - return; + if(GetLastError() == 0xdeadbeef) + todo_wine ok(0, "failed without error code\n"); + else + todo_wine ok(0, "failed with %d\n", GetLastError()); + } + + todo_wine w32_err(pGetProcessImageFileNameA(NULL, szImgPath, sizeof(szImgPath)), ERROR_INVALID_HANDLE); + todo_wine w32_err(pGetProcessImageFileNameA(hpSR, szImgPath, sizeof(szImgPath)), ERROR_ACCESS_DENIED); + todo_wine w32_err(pGetProcessImageFileNameA(hpQI, szImgPath, 0), ERROR_INSUFFICIENT_BUFFER); + todo_wine + if(w32_suc(ret = pGetProcessImageFileNameA(hpQI, szImgPath, sizeof(szImgPath))) && + w32_suc(pGetMappedFileNameA(hpQV, hMod, szMapPath, sizeof(szMapPath)))) { /* Windows returns 2*strlen-1 */ ok(ret >= strlen(szImgPath), "szImgPath=\"%s\" ret=%d\n", szImgPath, ret); ok(!strcmp(szImgPath, szMapPath), "szImgPath=\"%s\" szMapPath=\"%s\"\n", szImgPath, szMapPath); } + w32_err(pGetProcessImageFileNameW(NULL, szImgPathW, sizeof(szImgPathW)), ERROR_INVALID_HANDLE); + /* no information about correct buffer size returned: */ + w32_err(pGetProcessImageFileNameW(hpQI, szImgPathW, 0), ERROR_INSUFFICIENT_BUFFER); + w32_err(pGetProcessImageFileNameW(hpQI, NULL, 0), ERROR_INSUFFICIENT_BUFFER); + + /* correct call */ + memset(szImgPathW, 0xff, sizeof(szImgPathW)); + ret = pGetProcessImageFileNameW(hpQI, szImgPathW, sizeof(szImgPathW)/sizeof(WCHAR)); + ok(ret > 0, "GetProcessImageFileNameW should have succeeded.\n"); + ok(szImgPathW[0] == '\\', "GetProcessImageFileNameW should have returned an NT path.\n"); + expect_eq_d(lstrlenW(szImgPathW), ret); + + /* boundary values of 'size' */ + w32_err(pGetProcessImageFileNameW(hpQI, szImgPathW, ret), ERROR_INSUFFICIENT_BUFFER); + + memset(szImgPathW, 0xff, sizeof(szImgPathW)); + ret = pGetProcessImageFileNameW(hpQI, szImgPathW, ret + 1); + ok(ret > 0, "GetProcessImageFileNameW should have succeeded.\n"); + ok(szImgPathW[0] == '\\', "GetProcessImageFileNameW should have returned an NT path.\n"); + expect_eq_d(lstrlenW(szImgPathW), ret); +} + static void test_GetModuleFileNameEx(void) { HMODULE hMod = GetModuleHandle(NULL); @@ -309,7 +343,7 @@ START_TEST(psapi_main) test_GetModuleInformation(); test_GetProcessMemoryInfo(); todo_wine test_GetMappedFileName(); - todo_wine test_GetProcessImageFileName(); + test_GetProcessImageFileName(); test_GetModuleFileNameEx(); test_GetModuleBaseName(); test_ws_functions(); diff --git a/rostests/winetests/qmgr/enum_files.c b/rostests/winetests/qmgr/enum_files.c new file mode 100644 index 00000000000..eeb80095829 --- /dev/null +++ b/rostests/winetests/qmgr/enum_files.c @@ -0,0 +1,295 @@ +/* + * Unit test suite for Enum Background Copy Files Interface + * + * Copyright 2007, 2008 Google (Roy Shea, Dan Hipschman) + * + * 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 + */ + +#include +#include + +#define COBJMACROS + +#include "wine/test.h" +#include "bits.h" + +/* Globals used by many tests */ +#define NUM_FILES 2 /* At least two. */ +static const WCHAR test_remoteNameA[] = {'r','e','m','o','t','e','A', 0}; +static const WCHAR test_localNameA[] = {'l','o','c','a','l','A', 0}; +static const WCHAR test_remoteNameB[] = {'r','e','m','o','t','e','B', 0}; +static const WCHAR test_localNameB[] = {'l','o','c','a','l','B', 0}; +static const WCHAR test_displayName[] = {'T', 'e', 's', 't', 0}; +static const ULONG test_fileCount = NUM_FILES; +static IBackgroundCopyJob *test_job; +static IBackgroundCopyManager *test_manager; +static IEnumBackgroundCopyFiles *test_enumFiles; + +/* Helper function to add a file to a job. The helper function takes base + file name and creates properly formed path and URL strings for creation of + the file. */ +static HRESULT addFileHelper(IBackgroundCopyJob* job, + const WCHAR *localName, const WCHAR *remoteName) +{ + DWORD urlSize; + WCHAR localFile[MAX_PATH]; + WCHAR remoteUrl[MAX_PATH]; + WCHAR remoteFile[MAX_PATH]; + + GetCurrentDirectoryW(MAX_PATH, localFile); + PathAppendW(localFile, localName); + GetCurrentDirectoryW(MAX_PATH, remoteFile); + PathAppendW(remoteFile, remoteName); + urlSize = MAX_PATH; + UrlCreateFromPathW(remoteFile, remoteUrl, &urlSize, 0); + UrlUnescapeW(remoteUrl, NULL, &urlSize, URL_UNESCAPE_INPLACE); + return IBackgroundCopyJob_AddFile(test_job, remoteUrl, localFile); +} + +/* Generic test setup */ +static BOOL setup(void) +{ + HRESULT hres; + GUID test_jobId; + + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, + CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager, + (void **) &test_manager); + if(hres != S_OK) + return FALSE; + + hres = IBackgroundCopyManager_CreateJob(test_manager, test_displayName, + BG_JOB_TYPE_DOWNLOAD, &test_jobId, + &test_job); + if(hres != S_OK) + { + IBackgroundCopyManager_Release(test_manager); + return FALSE; + } + + if (addFileHelper(test_job, test_localNameA, test_remoteNameA) != S_OK + || addFileHelper(test_job, test_localNameB, test_remoteNameB) != S_OK + || IBackgroundCopyJob_EnumFiles(test_job, &test_enumFiles) != S_OK) + { + IBackgroundCopyJob_Release(test_job); + IBackgroundCopyManager_Release(test_manager); + return FALSE; + } + + return TRUE; +} + +/* Generic test cleanup */ +static void teardown(void) +{ + IEnumBackgroundCopyFiles_Release(test_enumFiles); + IBackgroundCopyJob_Release(test_job); + IBackgroundCopyManager_Release(test_manager); +} + +/* Test GetCount */ +static void test_GetCount(void) +{ + HRESULT hres; + ULONG fileCount; + + hres = IEnumBackgroundCopyFiles_GetCount(test_enumFiles, &fileCount); + ok(hres == S_OK, "GetCount failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get count from test_enumFiles.\n"); + return; + } + ok(fileCount == test_fileCount, "Got incorrect count\n"); +} + +/* Test Next with a NULL pceltFetched*/ +static void test_Next_walkListNull(void) +{ + HRESULT hres; + IBackgroundCopyFile *file; + ULONG i; + + /* Fetch the available files */ + for (i = 0; i < test_fileCount; i++) + { + hres = IEnumBackgroundCopyFiles_Next(test_enumFiles, 1, &file, NULL); + ok(hres == S_OK, "Next failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get file from test_enumFiles\n"); + return; + } + IBackgroundCopyFile_Release(file); + } + + /* Attempt to fetch one more than the number of available files */ + hres = IEnumBackgroundCopyFiles_Next(test_enumFiles, 1, &file, NULL); + ok(hres == S_FALSE, "Next off end of available files failed: %08x\n", hres); +} + +/* Test Next by requesting one file at a time */ +static void test_Next_walkList_1(void) +{ + HRESULT hres; + IBackgroundCopyFile *file; + ULONG fetched; + ULONG i; + + /* Fetch the available files */ + for (i = 0; i < test_fileCount; i++) + { + file = NULL; + fetched = 0; + hres = IEnumBackgroundCopyFiles_Next(test_enumFiles, 1, &file, &fetched); + ok(hres == S_OK, "Next failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get file from test_enumFiles\n"); + return; + } + ok(fetched == 1, "Next returned the incorrect number of files: %08x\n", hres); + ok(file != NULL, "Next returned NULL\n"); + if (file) + IBackgroundCopyFile_Release(file); + } + + /* Attempt to fetch one more than the number of available files */ + fetched = 0; + hres = IEnumBackgroundCopyFiles_Next(test_enumFiles, 1, &file, &fetched); + ok(hres == S_FALSE, "Next off end of available files failed: %08x\n", hres); + ok(fetched == 0, "Next returned the incorrect number of files: %08x\n", hres); +} + +/* Test Next by requesting multiple files at a time */ +static void test_Next_walkList_2(void) +{ + HRESULT hres; + IBackgroundCopyFile *files[NUM_FILES]; + ULONG fetched; + ULONG i; + + for (i = 0; i < test_fileCount; i++) + files[i] = NULL; + + fetched = 0; + hres = IEnumBackgroundCopyFiles_Next(test_enumFiles, test_fileCount, files, &fetched); + ok(hres == S_OK, "Next failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get file from test_enumFiles\n"); + return; + } + ok(fetched == test_fileCount, "Next returned the incorrect number of files: %08x\n", hres); + + for (i = 0; i < test_fileCount; i++) + { + ok(files[i] != NULL, "Next returned NULL\n"); + if (files[i]) + IBackgroundCopyFile_Release(files[i]); + } +} + +/* Test Next Error conditions */ +static void test_Next_errors(void) +{ + HRESULT hres; + IBackgroundCopyFile *files[NUM_FILES]; + + /* E_INVALIDARG: pceltFetched can ONLY be NULL if celt is 1 */ + hres = IEnumBackgroundCopyFiles_Next(test_enumFiles, 2, files, NULL); + ok(hres == E_INVALIDARG, "Invalid call to Next succeeded: %08x\n", hres); +} + +/* Test skipping through the files in a list */ +static void test_Skip_walkList(void) +{ + HRESULT hres; + ULONG i; + + for (i = 0; i < test_fileCount; i++) + { + hres = IEnumBackgroundCopyFiles_Skip(test_enumFiles, 1); + ok(hres == S_OK, "Skip failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to propely Skip files\n"); + return; + } + } + + hres = IEnumBackgroundCopyFiles_Skip(test_enumFiles, 1); + ok(hres == S_FALSE, "Skip expected end of list: %08x\n", hres); +} + +/* Test skipping off the end of the list */ +static void test_Skip_offEnd(void) +{ + HRESULT hres; + + hres = IEnumBackgroundCopyFiles_Skip(test_enumFiles, test_fileCount + 1); + ok(hres == S_FALSE, "Skip expected end of list: %08x\n", hres); +} + +/* Test resetting the file enumerator */ +static void test_Reset(void) +{ + HRESULT hres; + + hres = IEnumBackgroundCopyFiles_Skip(test_enumFiles, test_fileCount); + ok(hres == S_OK, "Skip failed: %08x\n", hres); + hres = IEnumBackgroundCopyFiles_Reset(test_enumFiles); + ok(hres == S_OK, "Reset failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to Reset enumerator\n"); + return; + } + hres = IEnumBackgroundCopyFiles_Skip(test_enumFiles, test_fileCount); + ok(hres == S_OK, "Reset failed: %08x\n", hres); +} + +typedef void (*test_t)(void); + +START_TEST(enum_files) +{ + static const test_t tests[] = { + test_GetCount, + test_Next_walkListNull, + test_Next_walkList_1, + test_Next_walkList_2, + test_Next_errors, + test_Skip_walkList, + test_Skip_offEnd, + test_Reset, + 0 + }; + const test_t *test; + + CoInitialize(NULL); + for (test = tests; *test; ++test) + { + /* Keep state separate between tests. */ + if (!setup()) + { + skip("Unable to setup test\n"); + break; + } + (*test)(); + teardown(); + } + CoUninitialize(); +} diff --git a/rostests/winetests/qmgr/enum_jobs.c b/rostests/winetests/qmgr/enum_jobs.c new file mode 100644 index 00000000000..f95404c041c --- /dev/null +++ b/rostests/winetests/qmgr/enum_jobs.c @@ -0,0 +1,324 @@ +/* + * Unit test suite for Enum Background Copy Jobs Interface + * + * Copyright 2007 Google (Roy Shea, Dan Hipschman) + * + * 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 + */ + +#include + +#define COBJMACROS + +#include "wine/test.h" +#include "bits.h" + +/* Globals used by many tests */ +static const WCHAR test_displayNameA[] = {'T','e','s','t','A', 0}; +static const WCHAR test_displayNameB[] = {'T','e','s','t','B', 0}; +static IBackgroundCopyManager *test_manager; +static IBackgroundCopyJob *test_jobA; +static IBackgroundCopyJob *test_jobB; +static ULONG test_jobCountB; +static IEnumBackgroundCopyJobs *test_enumJobsA; +static IEnumBackgroundCopyJobs *test_enumJobsB; +static GUID test_jobIdA; +static GUID test_jobIdB; + +/* Generic test setup */ +static BOOL setup(void) +{ + HRESULT hres; + + test_manager = NULL; + test_jobA = NULL; + test_jobB = NULL; + memset(&test_jobIdA, 0, sizeof test_jobIdA); + memset(&test_jobIdB, 0, sizeof test_jobIdB); + + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, + CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager, + (void **) &test_manager); + if(hres != S_OK) + return FALSE; + + hres = IBackgroundCopyManager_CreateJob(test_manager, test_displayNameA, + BG_JOB_TYPE_DOWNLOAD, &test_jobIdA, + &test_jobA); + if(hres != S_OK) + return FALSE; + + hres = IBackgroundCopyManager_EnumJobs(test_manager, 0, &test_enumJobsA); + if(hres != S_OK) + return FALSE; + + hres = IBackgroundCopyManager_CreateJob(test_manager, test_displayNameB, + BG_JOB_TYPE_DOWNLOAD, &test_jobIdB, + &test_jobB); + if(hres != S_OK) + return FALSE; + + hres = IBackgroundCopyManager_EnumJobs(test_manager, 0, &test_enumJobsB); + if(hres != S_OK) + return FALSE; + + hres = IEnumBackgroundCopyJobs_GetCount(test_enumJobsB, &test_jobCountB); + if (hres != S_OK) + return FALSE; + + return TRUE; +} + +/* Generic test cleanup */ +static void teardown(void) +{ + if (test_enumJobsB) + IEnumBackgroundCopyJobs_Release(test_enumJobsB); + test_enumJobsB = NULL; + if (test_jobB) + IBackgroundCopyJob_Release(test_jobB); + test_jobB = NULL; + if (test_enumJobsA) + IEnumBackgroundCopyJobs_Release(test_enumJobsA); + test_enumJobsA = NULL; + if (test_jobA) + IBackgroundCopyJob_Release(test_jobA); + test_jobA = NULL; + if (test_manager) + IBackgroundCopyManager_Release(test_manager); + test_manager = NULL; +} + +/* We can't assume the job count will start at any fixed number since esp + when testing on Windows there may be other jobs created by other + processes. Even this approach of creating two jobs and checking the + difference in counts could fail if a job was created in between, but + it's probably not worth worrying about in sane test environments. */ +static void test_GetCount(void) +{ + HRESULT hres; + ULONG jobCountA, jobCountB; + + hres = IEnumBackgroundCopyJobs_GetCount(test_enumJobsA, &jobCountA); + ok(hres == S_OK, "GetCount failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Couldn't get job count\n"); + return; + } + + hres = IEnumBackgroundCopyJobs_GetCount(test_enumJobsB, &jobCountB); + ok(hres == S_OK, "GetCount failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Couldn't get job count\n"); + return; + } + + ok(jobCountB == jobCountA + 1, "Got incorrect count\n"); +} + +/* Test Next with a NULL pceltFetched*/ +static void test_Next_walkListNull(void) +{ + HRESULT hres; + IBackgroundCopyJob *job; + ULONG i; + + /* Fetch the available jobs */ + for (i = 0; i < test_jobCountB; i++) + { + hres = IEnumBackgroundCopyJobs_Next(test_enumJobsB, 1, &job, NULL); + ok(hres == S_OK, "Next failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get job from Next\n"); + return; + } + IBackgroundCopyJob_Release(job); + } + + /* Attempt to fetch one more than the number of available jobs */ + hres = IEnumBackgroundCopyJobs_Next(test_enumJobsB, 1, &job, NULL); + ok(hres == S_FALSE, "Next off end of available jobs failed: %08x\n", hres); +} + +/* Test Next */ +static void test_Next_walkList_1(void) +{ + HRESULT hres; + IBackgroundCopyJob *job; + ULONG fetched; + ULONG i; + + /* Fetch the available jobs */ + for (i = 0; i < test_jobCountB; i++) + { + fetched = 0; + hres = IEnumBackgroundCopyJobs_Next(test_enumJobsB, 1, &job, &fetched); + ok(hres == S_OK, "Next failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get job from Next\n"); + return; + } + ok(fetched == 1, "Next returned the incorrect number of jobs: %08x\n", hres); + IBackgroundCopyJob_Release(job); + } + + /* Attempt to fetch one more than the number of available jobs */ + fetched = 0; + hres = IEnumBackgroundCopyJobs_Next(test_enumJobsB, 1, &job, &fetched); + ok(hres == S_FALSE, "Next off end of available jobs failed: %08x\n", hres); + ok(fetched == 0, "Next returned the incorrect number of jobs: %08x\n", hres); +} + +/* Test Next by requesting multiple files at a time */ +static void test_Next_walkList_2(void) +{ + HRESULT hres; + IBackgroundCopyJob **jobs; + ULONG fetched; + ULONG i; + + jobs = HeapAlloc(GetProcessHeap(), 0, test_jobCountB * sizeof *jobs); + if (!jobs) + { + skip("Couldn't allocate memory\n"); + return; + } + + for (i = 0; i < test_jobCountB; i++) + jobs[i] = NULL; + + fetched = 0; + hres = IEnumBackgroundCopyJobs_Next(test_enumJobsB, test_jobCountB, jobs, &fetched); + ok(hres == S_OK, "Next failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get file from test_enumJobs\n"); + HeapFree(GetProcessHeap(), 0, jobs); + return; + } + ok(fetched == test_jobCountB, "Next returned the incorrect number of jobs: %08x\n", hres); + + for (i = 0; i < test_jobCountB; i++) + { + ok(jobs[i] != NULL, "Next returned NULL\n"); + if (jobs[i]) + IBackgroundCopyFile_Release(jobs[i]); + } + + HeapFree(GetProcessHeap(), 0, jobs); +} + +/* Test Next Error conditions */ +static void test_Next_errors(void) +{ + HRESULT hres; + IBackgroundCopyJob *jobs[2]; + + /* E_INVALIDARG: pceltFetched can ONLY be NULL if celt is 1 */ + hres = IEnumBackgroundCopyJobs_Next(test_enumJobsB, 2, jobs, NULL); + ok(hres != S_OK, "Invalid call to Next succeeded: %08x\n", hres); +} + +/* Test skipping through the jobs in a list */ +static void test_Skip_walkList(void) +{ + HRESULT hres; + ULONG i; + + for (i = 0; i < test_jobCountB; i++) + { + hres = IEnumBackgroundCopyJobs_Skip(test_enumJobsB, 1); + ok(hres == S_OK, "Skip failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to propely Skip jobs\n"); + return; + } + } + + hres = IEnumBackgroundCopyJobs_Skip(test_enumJobsB, 1); + ok(hres == S_FALSE, "Skip expected end of list: %08x\n", hres); +} + +/* Test skipping off the end of the list */ +static void test_Skip_offEnd(void) +{ + HRESULT hres; + + hres = IEnumBackgroundCopyJobs_Skip(test_enumJobsB, test_jobCountB + 1); + ok(hres == S_FALSE, "Skip expected end of list: %08x\n", hres); +} + +/* Test reset */ +static void test_Reset(void) +{ + HRESULT hres; + + hres = IEnumBackgroundCopyJobs_Skip(test_enumJobsB, test_jobCountB); + ok(hres == S_OK, "Skip failed: %08x\n", hres); + if (hres != S_OK) + { + skip("Skip failed\n"); + return; + } + + hres = IEnumBackgroundCopyJobs_Reset(test_enumJobsB); + ok(hres == S_OK, "Reset failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to Reset enumerator\n"); + return; + } + + hres = IEnumBackgroundCopyJobs_Skip(test_enumJobsB, test_jobCountB); + ok(hres == S_OK, "Reset failed: %08x\n", hres); +} + +typedef void (*test_t)(void); + +START_TEST(enum_jobs) +{ + static const test_t tests[] = { + test_GetCount, + test_Next_walkListNull, + test_Next_walkList_1, + test_Next_walkList_2, + test_Next_errors, + test_Skip_walkList, + test_Skip_offEnd, + test_Reset, + 0 + }; + const test_t *test; + + CoInitialize(NULL); + for (test = tests; *test; ++test) + { + /* Keep state separate between tests */ + if (!setup()) + { + teardown(); + skip("Unable to setup test\n"); + break; + } + (*test)(); + teardown(); + } + CoUninitialize(); +} diff --git a/rostests/winetests/qmgr/file.c b/rostests/winetests/qmgr/file.c new file mode 100644 index 00000000000..033b2c500f0 --- /dev/null +++ b/rostests/winetests/qmgr/file.c @@ -0,0 +1,193 @@ +/* + * Unit test suite for Background Copy File Interface + * + * Copyright 2007 Google (Roy Shea) + * + * 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 + */ + +#include + +#include + +#define COBJMACROS + +#include "wine/test.h" +#include "bits.h" + +/* Globals used by many tests */ +#define NUM_FILES 1 +static const WCHAR test_remoteName[] = {'r','e','m','o','t','e', 0}; +static const WCHAR test_localName[] = {'l','o','c','a','l', 0}; +static WCHAR test_localFile[MAX_PATH]; +static WCHAR test_remoteUrl[MAX_PATH]; +static const ULONG test_fileCount = NUM_FILES; +static const WCHAR test_displayName[] = {'T','e','s','t', 0}; +static IBackgroundCopyJob *test_job; +static IBackgroundCopyManager *test_manager; +static IEnumBackgroundCopyFiles *test_enumFiles; +static IBackgroundCopyFile *test_file; + +/* Helper function to add a file to a job. The helper function takes base + file name and creates properly formed path and URL strings for creation of + the file. */ +static HRESULT addFileHelper(IBackgroundCopyJob* job, + const WCHAR *localName, const WCHAR *remoteName) +{ + DWORD urlSize; + + GetCurrentDirectoryW(MAX_PATH, test_localFile); + PathAppendW(test_localFile, localName); + GetCurrentDirectoryW(MAX_PATH, test_remoteUrl); + PathAppendW(test_remoteUrl, remoteName); + urlSize = MAX_PATH; + UrlCreateFromPathW(test_remoteUrl, test_remoteUrl, &urlSize, 0); + UrlUnescapeW(test_remoteUrl, NULL, &urlSize, URL_UNESCAPE_INPLACE); + return IBackgroundCopyJob_AddFile(test_job, test_remoteUrl, test_localFile); +} + +/* Generic test setup */ +static BOOL setup(void) +{ + HRESULT hres; + GUID test_jobId; + + test_manager = NULL; + test_job = NULL; + memset(&test_jobId, 0, sizeof test_jobId); + + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, + CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager, + (void **) &test_manager); + if(hres != S_OK) + return FALSE; + + hres = IBackgroundCopyManager_CreateJob(test_manager, test_displayName, + BG_JOB_TYPE_DOWNLOAD, &test_jobId, &test_job); + if(hres != S_OK) + { + IBackgroundCopyManager_Release(test_manager); + return FALSE; + } + + if (addFileHelper(test_job, test_localName, test_remoteName) != S_OK + || IBackgroundCopyJob_EnumFiles(test_job, &test_enumFiles) != S_OK) + { + IBackgroundCopyJob_Release(test_job); + IBackgroundCopyManager_Release(test_manager); + return FALSE; + } + + hres = IEnumBackgroundCopyFiles_Next(test_enumFiles, 1, &test_file, NULL); + if(hres != S_OK) + { + IEnumBackgroundCopyFiles_Release(test_enumFiles); + IBackgroundCopyJob_Release(test_job); + IBackgroundCopyManager_Release(test_manager); + return FALSE; + } + + return TRUE; +} + +/* Generic test cleanup */ +static void teardown(void) +{ + IBackgroundCopyFile_Release(test_file); + IEnumBackgroundCopyFiles_Release(test_enumFiles); + IBackgroundCopyJob_Release(test_job); + IBackgroundCopyManager_Release(test_manager); +} + +/* Test that the remote name is properly set */ +static void test_GetRemoteName(void) +{ + HRESULT hres; + LPWSTR name; + + hres = IBackgroundCopyFile_GetRemoteName(test_file, &name); + ok(hres == S_OK, "GetRemoteName failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get remote name of test_file.\n"); + return; + } + ok(lstrcmpW(name, test_remoteUrl) == 0, "Got incorrect remote name\n"); + CoTaskMemFree(name); +} + +/* Test that the local name is properly set */ +static void test_GetLocalName(void) +{ + HRESULT hres; + LPWSTR name; + + hres = IBackgroundCopyFile_GetLocalName(test_file, &name); + ok(hres == S_OK, "GetLocalName failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get local name of test_file.\n"); + return; + } + ok(lstrcmpW(name, test_localFile) == 0, "Got incorrect local name\n"); + CoTaskMemFree(name); +} + +/* Test getting the progress of a file*/ +static void test_GetProgress_PreTransfer(void) +{ + HRESULT hres; + BG_FILE_PROGRESS progress; + + hres = IBackgroundCopyFile_GetProgress(test_file, &progress); + ok(hres == S_OK, "GetProgress failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get progress of test_file.\n"); + return; + } + ok(progress.BytesTotal == BG_SIZE_UNKNOWN, "Got incorrect total size: %x%08x\n", + (DWORD)(progress.BytesTotal >> 32), (DWORD)progress.BytesTotal); + ok(progress.BytesTransferred == 0, "Got incorrect number of transferred bytes: %x%08x\n", + (DWORD)(progress.BytesTransferred >> 32), (DWORD)progress.BytesTransferred); + ok(progress.Completed == FALSE, "Got incorret completion status\n"); +} + +typedef void (*test_t)(void); + +START_TEST(file) +{ + static const test_t tests[] = { + test_GetRemoteName, + test_GetLocalName, + test_GetProgress_PreTransfer, + 0 + }; + const test_t *test; + + CoInitialize(NULL); + for (test = tests; *test; ++test) + { + /* Keep state separate between tests. */ + if (!setup()) + { + skip("Unable to setup test\n"); + break; + } + (*test)(); + teardown(); + } + CoUninitialize(); +} diff --git a/rostests/winetests/qmgr/job.c b/rostests/winetests/qmgr/job.c new file mode 100644 index 00000000000..d0e2306bfc0 --- /dev/null +++ b/rostests/winetests/qmgr/job.c @@ -0,0 +1,585 @@ +/* + * Unit test suite for Background Copy Job Interface + * + * Copyright 2007 Google (Roy Shea) + * + * 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 + */ + +#include + +#define COBJMACROS + +#include "wine/test.h" +#include "bits.h" +#include "initguid.h" + +/* Globals used by many tests */ +static const WCHAR test_displayName[] = {'T', 'e', 's', 't', 0}; +static const WCHAR test_remoteNameA[] = {'r','e','m','o','t','e','A', 0}; +static const WCHAR test_remoteNameB[] = {'r','e','m','o','t','e','B', 0}; +static const WCHAR test_localNameA[] = {'l','o','c','a','l','A', 0}; +static const WCHAR test_localNameB[] = {'l','o','c','a','l','B', 0}; +static WCHAR *test_currentDir; +static WCHAR *test_remotePathA; +static WCHAR *test_remotePathB; +static WCHAR *test_localPathA; +static WCHAR *test_localPathB; +static IBackgroundCopyManager *test_manager; +static IBackgroundCopyJob *test_job; +static GUID test_jobId; +static BG_JOB_TYPE test_type; + +static BOOL init_paths(void) +{ + static const WCHAR format[] = {'%','s','\\','%','s', 0}; + DWORD n; + + n = GetCurrentDirectoryW(0, NULL); + if (n == 0) + { + skip("Couldn't get current directory size\n"); + return FALSE; + } + + test_currentDir = HeapAlloc(GetProcessHeap(), 0, n * sizeof(WCHAR)); + test_localPathA + = HeapAlloc(GetProcessHeap(), 0, + (n + 1 + lstrlenW(test_localNameA)) * sizeof(WCHAR)); + test_localPathB + = HeapAlloc(GetProcessHeap(), 0, + (n + 1 + lstrlenW(test_localNameB)) * sizeof(WCHAR)); + test_remotePathA + = HeapAlloc(GetProcessHeap(), 0, + (n + 1 + lstrlenW(test_remoteNameA)) * sizeof(WCHAR)); + test_remotePathB + = HeapAlloc(GetProcessHeap(), 0, + (n + 1 + lstrlenW(test_remoteNameB)) * sizeof(WCHAR)); + + if (!test_currentDir || !test_localPathA || !test_localPathB + || !test_remotePathA || !test_remotePathB) + { + skip("Couldn't allocate memory for full paths\n"); + return FALSE; + } + + if (GetCurrentDirectoryW(n, test_currentDir) != n - 1) + { + skip("Couldn't get current directory\n"); + return FALSE; + } + + wsprintfW(test_localPathA, format, test_currentDir, test_localNameA); + wsprintfW(test_localPathB, format, test_currentDir, test_localNameB); + wsprintfW(test_remotePathA, format, test_currentDir, test_remoteNameA); + wsprintfW(test_remotePathB, format, test_currentDir, test_remoteNameB); + + return TRUE; +} + +/* Generic test setup */ +static BOOL setup(void) +{ + HRESULT hres; + + test_manager = NULL; + test_job = NULL; + memset(&test_jobId, 0, sizeof test_jobId); + test_type = BG_JOB_TYPE_DOWNLOAD; + + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, + CLSCTX_LOCAL_SERVER, + &IID_IBackgroundCopyManager, + (void **) &test_manager); + if(hres != S_OK) + return FALSE; + + hres = IBackgroundCopyManager_CreateJob(test_manager, test_displayName, + test_type, &test_jobId, &test_job); + if(hres != S_OK) + { + IBackgroundCopyManager_Release(test_manager); + return FALSE; + } + + return TRUE; +} + +/* Generic test cleanup */ +static void teardown(void) +{ + IBackgroundCopyJob_Release(test_job); + IBackgroundCopyManager_Release(test_manager); +} + +/* FIXME: Remove when Wine has implemented this */ +DEFINE_GUID(CLSID_BackgroundCopyManager2_0, 0x6d18ad12, 0xbde3, 0x4393, 0xb3,0x11, 0x09,0x9c,0x34,0x6e,0x6d,0xf9); + +static BOOL check_bits20(void) +{ + HRESULT hres; + IBackgroundCopyManager *manager; + BOOL ret = TRUE; + + hres = CoCreateInstance(&CLSID_BackgroundCopyManager2_0, NULL, + CLSCTX_LOCAL_SERVER, + &IID_IBackgroundCopyManager, + (void **) &manager); + + if (hres == REGDB_E_CLASSNOTREG) + { + ret = FALSE; + + /* FIXME: Wine implements 2.0 functionality but doesn't advertise 2.0 + * + * Remove when Wine is fixed + */ + if (setup()) + { + HRESULT hres2; + + hres2 = IBackgroundCopyJob_AddFile(test_job, test_remotePathA, + test_localPathA); + if (hres2 == S_OK) + { + trace("Running on Wine, claim 2.0 is present\n"); + ret = TRUE; + } + teardown(); + } + } + + if (manager) + IBackgroundCopyManager_Release(manager); + + return ret; +} + +/* Test that the jobId is properly set */ +static void test_GetId(void) +{ + HRESULT hres; + GUID tmpId; + + hres = IBackgroundCopyJob_GetId(test_job, &tmpId); + ok(hres == S_OK, "GetId failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get ID of test_job.\n"); + return; + } + ok(memcmp(&tmpId, &test_jobId, sizeof tmpId) == 0, "Got incorrect GUID\n"); +} + +/* Test that the type is properly set */ +static void test_GetType(void) +{ + HRESULT hres; + BG_JOB_TYPE type; + + hres = IBackgroundCopyJob_GetType(test_job, &type); + ok(hres == S_OK, "GetType failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get type of test_job.\n"); + return; + } + ok(type == test_type, "Got incorrect type\n"); +} + +/* Test that the display name is properly set */ +static void test_GetName(void) +{ + HRESULT hres; + LPWSTR displayName; + + hres = IBackgroundCopyJob_GetDisplayName(test_job, &displayName); + ok(hres == S_OK, "GetName failed: %08x\n", hres); + if(hres != S_OK) + { + skip("Unable to get display name of test_job.\n"); + return; + } + ok(lstrcmpW(displayName, test_displayName) == 0, "Got incorrect type\n"); + CoTaskMemFree(displayName); +} + +/* Test adding a file */ +static void test_AddFile(void) +{ + HRESULT hres; + + hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA, + test_localPathA); + ok(hres == S_OK, "First call to AddFile failed: 0x%08x\n", hres); + if (hres != S_OK) + { + skip("Unable to add first file to job\n"); + return; + } + + hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathB, + test_localPathB); + ok(hres == S_OK, "Second call to AddFile failed: 0x%08x\n", hres); +} + +/* Test adding a set of files */ +static void test_AddFileSet(void) +{ + HRESULT hres; + BG_FILE_INFO files[2] = + { + {test_remotePathA, test_localPathA}, + {test_remotePathB, test_localPathB} + }; + hres = IBackgroundCopyJob_AddFileSet(test_job, 2, files); + ok(hres == S_OK, "AddFileSet failed: 0x%08x\n", hres); +} + +/* Test creation of a job enumerator */ +static void test_EnumFiles(void) +{ + HRESULT hres; + IEnumBackgroundCopyFiles *enumFiles; + ULONG res; + + hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA, + test_localPathA); + if (hres != S_OK) + { + skip("Unable to add file to job\n"); + return; + } + + hres = IBackgroundCopyJob_EnumFiles(test_job, &enumFiles); + ok(hres == S_OK, "EnumFiles failed: 0x%08x\n", hres); + if(hres != S_OK) + { + skip("Unable to create file enumerator.\n"); + return; + } + + res = IEnumBackgroundCopyFiles_Release(enumFiles); + ok(res == 0, "Bad ref count on release: %u\n", res); +} + +/* Test getting job progress */ +static void test_GetProgress_preTransfer(void) +{ + HRESULT hres; + BG_JOB_PROGRESS progress; + + hres = IBackgroundCopyJob_GetProgress(test_job, &progress); + ok(hres == S_OK, "GetProgress failed: 0x%08x\n", hres); + if (hres != S_OK) + { + skip("Unable to get job progress\n"); + teardown(); + return; + } + + ok(progress.BytesTotal == 0, "Incorrect BytesTotal: %x%08x\n", + (DWORD)(progress.BytesTotal >> 32), (DWORD)progress.BytesTotal); + ok(progress.BytesTransferred == 0, "Incorrect BytesTransferred: %x%08x\n", + (DWORD)(progress.BytesTransferred >> 32), (DWORD)progress.BytesTransferred); + ok(progress.FilesTotal == 0, "Incorrect FilesTotal: %u\n", progress.FilesTotal); + ok(progress.FilesTransferred == 0, "Incorrect FilesTransferred %u\n", progress.FilesTransferred); +} + +/* Test getting job state */ +static void test_GetState(void) +{ + HRESULT hres; + BG_JOB_STATE state; + + state = BG_JOB_STATE_ERROR; + hres = IBackgroundCopyJob_GetState(test_job, &state); + ok(hres == S_OK, "GetState failed: 0x%08x\n", hres); + if (hres != S_OK) + { + skip("Unable to get job state\n"); + return; + } + ok(state == BG_JOB_STATE_SUSPENDED, "Incorrect job state: %d\n", state); +} + +/* Test resuming a job */ +static void test_ResumeEmpty(void) +{ + HRESULT hres; + BG_JOB_STATE state; + + hres = IBackgroundCopyJob_Resume(test_job); + ok(hres == BG_E_EMPTY, "Resume failed to return BG_E_EMPTY error: 0x%08x\n", hres); + if (hres != BG_E_EMPTY) + { + skip("Failed calling resume job\n"); + return; + } + + state = BG_JOB_STATE_ERROR; + hres = IBackgroundCopyJob_GetState(test_job, &state); + if (hres != S_OK) + { + skip("Unable to get job state\n"); + return; + } + ok(state == BG_JOB_STATE_SUSPENDED, "Incorrect job state: %d\n", state); +} + +static void makeFile(WCHAR *name, const char *contents) +{ + HANDLE file; + DWORD w, len = strlen(contents); + + DeleteFileW(name); + file = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile\n"); + ok(WriteFile(file, contents, len, &w, NULL), "WriteFile\n"); + CloseHandle(file); +} + +static void compareFiles(WCHAR *n1, WCHAR *n2) +{ + char b1[256]; + char b2[256]; + DWORD s1, s2; + HANDLE f1, f2; + + f1 = CreateFileW(n1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(f1 != INVALID_HANDLE_VALUE, "CreateFile\n"); + + f2 = CreateFileW(n2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(f2 != INVALID_HANDLE_VALUE, "CreateFile\n"); + + /* Neither of these files is very big */ + ok(ReadFile(f1, b1, sizeof b1, &s1, NULL), "ReadFile\n"); + ok(ReadFile(f2, b2, sizeof b2, &s2, NULL), "ReadFile\n"); + + CloseHandle(f1); + CloseHandle(f2); + + ok(s1 == s2, "Files differ in length\n"); + ok(memcmp(b1, b2, s1) == 0, "Files differ in contents\n"); +} + +/* Test a complete transfer for local files */ +static void test_CompleteLocal(void) +{ + static const int timeout_sec = 30; + HRESULT hres; + BG_JOB_STATE state; + int i; + + DeleteFileW(test_localPathA); + DeleteFileW(test_localPathB); + makeFile(test_remotePathA, "This is a WINE test file for BITS\n"); + makeFile(test_remotePathB, "This is another WINE test file for BITS\n"); + + hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathA, + test_localPathA); + if (hres != S_OK) + { + skip("Unable to add file to job\n"); + return; + } + + hres = IBackgroundCopyJob_AddFile(test_job, test_remotePathB, + test_localPathB); + if (hres != S_OK) + { + skip("Unable to add file to job\n"); + return; + } + + hres = IBackgroundCopyJob_Resume(test_job); + ok(hres == S_OK, "IBackgroundCopyJob_Resume\n"); + + for (i = 0; i < timeout_sec; ++i) + { + hres = IBackgroundCopyJob_GetState(test_job, &state); + ok(hres == S_OK, "IBackgroundCopyJob_GetState\n"); + ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING + || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED, + "Bad state: %d\n", state); + if (state == BG_JOB_STATE_TRANSFERRED) + break; + Sleep(1000); + } + + ok(i < timeout_sec, "BITS jobs timed out\n"); + hres = IBackgroundCopyJob_Complete(test_job); + ok(hres == S_OK, "IBackgroundCopyJob_Complete\n"); + hres = IBackgroundCopyJob_GetState(test_job, &state); + ok(hres == S_OK, "IBackgroundCopyJob_GetState\n"); + ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state); + + compareFiles(test_remotePathA, test_localPathA); + compareFiles(test_remotePathB, test_localPathB); + + ok(DeleteFileW(test_remotePathA), "DeleteFile\n"); + ok(DeleteFileW(test_remotePathB), "DeleteFile\n"); + DeleteFileW(test_localPathA); + DeleteFileW(test_localPathB); +} + +/* Test a complete transfer for local files */ +static void test_CompleteLocalURL(void) +{ + static const WCHAR prot[] = {'f','i','l','e',':','/','/', 0}; + static const int timeout_sec = 30; + WCHAR *urlA, *urlB; + HRESULT hres; + BG_JOB_STATE state; + int i; + + DeleteFileW(test_localPathA); + DeleteFileW(test_localPathB); + makeFile(test_remotePathA, "This is a WINE test file for BITS\n"); + makeFile(test_remotePathB, "This is another WINE test file for BITS\n"); + + urlA = HeapAlloc(GetProcessHeap(), 0, + (7 + lstrlenW(test_remotePathA) + 1) * sizeof urlA[0]); + urlB = HeapAlloc(GetProcessHeap(), 0, + (7 + lstrlenW(test_remotePathB) + 1) * sizeof urlB[0]); + if (!urlA || !urlB) + { + skip("Unable to allocate memory for URLs\n"); + HeapFree(GetProcessHeap(), 0, urlA); + HeapFree(GetProcessHeap(), 0, urlB); + return; + } + + lstrcpyW(urlA, prot); + lstrcatW(urlA, test_remotePathA); + lstrcpyW(urlB, prot); + lstrcatW(urlB, test_remotePathB); + + hres = IBackgroundCopyJob_AddFile(test_job, urlA, test_localPathA); + if (hres != S_OK) + { + skip("Unable to add file to job\n"); + HeapFree(GetProcessHeap(), 0, urlA); + HeapFree(GetProcessHeap(), 0, urlB); + return; + } + + hres = IBackgroundCopyJob_AddFile(test_job, urlB, test_localPathB); + if (hres != S_OK) + { + skip("Unable to add file to job\n"); + HeapFree(GetProcessHeap(), 0, urlA); + HeapFree(GetProcessHeap(), 0, urlB); + return; + } + + hres = IBackgroundCopyJob_Resume(test_job); + ok(hres == S_OK, "IBackgroundCopyJob_Resume\n"); + + for (i = 0; i < timeout_sec; ++i) + { + hres = IBackgroundCopyJob_GetState(test_job, &state); + ok(hres == S_OK, "IBackgroundCopyJob_GetState\n"); + ok(state == BG_JOB_STATE_QUEUED || state == BG_JOB_STATE_CONNECTING + || state == BG_JOB_STATE_TRANSFERRING || state == BG_JOB_STATE_TRANSFERRED, + "Bad state: %d\n", state); + if (state == BG_JOB_STATE_TRANSFERRED) + break; + Sleep(1000); + } + + ok(i < timeout_sec, "BITS jobs timed out\n"); + hres = IBackgroundCopyJob_Complete(test_job); + ok(hres == S_OK, "IBackgroundCopyJob_Complete\n"); + hres = IBackgroundCopyJob_GetState(test_job, &state); + ok(hres == S_OK, "IBackgroundCopyJob_GetState\n"); + ok(state == BG_JOB_STATE_ACKNOWLEDGED, "Bad state: %d\n", state); + + compareFiles(test_remotePathA, test_localPathA); + compareFiles(test_remotePathB, test_localPathB); + + ok(DeleteFileW(test_remotePathA), "DeleteFile\n"); + ok(DeleteFileW(test_remotePathB), "DeleteFile\n"); + DeleteFileW(test_localPathA); + DeleteFileW(test_localPathB); + + HeapFree(GetProcessHeap(), 0, urlA); + HeapFree(GetProcessHeap(), 0, urlB); +} + +typedef void (*test_t)(void); + +START_TEST(job) +{ + static const test_t tests[] = { + test_GetId, + test_GetType, + test_GetName, + test_GetProgress_preTransfer, + test_GetState, + test_ResumeEmpty, + 0 + }; + static const test_t tests_bits20[] = { + test_AddFile, + test_AddFileSet, + test_EnumFiles, + test_CompleteLocal, + test_CompleteLocalURL, + 0 + }; + const test_t *test; + + if (!init_paths()) + return; + + CoInitialize(NULL); + + for (test = tests; *test; ++test) + { + /* Keep state separate between tests. */ + if (!setup()) + { + skip("Unable to setup test\n"); + break; + } + (*test)(); + teardown(); + } + + if (check_bits20()) + { + for (test = tests_bits20; *test; ++test) + { + /* Keep state separate between tests. */ + if (!setup()) + { + skip("Unable to setup test\n"); + break; + } + (*test)(); + teardown(); + } + } + else + { + win_skip("Tests need BITS 2.0 or higher\n"); + } + + CoUninitialize(); +} diff --git a/rostests/winetests/qmgr/qmgr.c b/rostests/winetests/qmgr/qmgr.c new file mode 100644 index 00000000000..8c955862a11 --- /dev/null +++ b/rostests/winetests/qmgr/qmgr.c @@ -0,0 +1,240 @@ +/* + * Unit test suite for bits functions + * + * Copyright 2007 Google (Roy Shea) + * + * 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 + */ + +#include + +#define COBJMACROS + +#include "wine/test.h" +#include "initguid.h" +#include "bits.h" + +static WCHAR progname[MAX_PATH]; + +static void +test_CreateInstance(void) +{ + HRESULT hres; + ULONG res; + IBackgroundCopyManager *manager = NULL; + + /* Creating BITS instance */ + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, CLSCTX_LOCAL_SERVER, + &IID_IBackgroundCopyManager, (void **) &manager); + ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); + if(hres != S_OK) { + skip("Unable to create bits instance.\n"); + return; + } + + /* Releasing bits manager */ + res = IBackgroundCopyManager_Release(manager); + ok(res == 0, "Bad ref count on release: %u\n", res); + +} + +static void test_CreateJob(void) +{ + /* Job information */ + static const WCHAR copyNameW[] = {'T', 'e', 's', 't', 0}; + IBackgroundCopyJob* job = NULL; + GUID tmpId; + HRESULT hres; + ULONG res; + IBackgroundCopyManager* manager = NULL; + + /* Setup */ + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, + CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager, + (void **) &manager); + if(hres != S_OK) + { + skip("Unable to create bits instance required for test.\n"); + return; + } + + /* Create bits job */ + hres = IBackgroundCopyManager_CreateJob(manager, copyNameW, + BG_JOB_TYPE_DOWNLOAD, &tmpId, + &job); + ok(hres == S_OK, "CreateJob failed: %08x\n", hres); + if(hres != S_OK) + skip("Unable to create bits job.\n"); + else + { + res = IBackgroundCopyJob_Release(job); + ok(res == 0, "Bad ref count on release: %u\n", res); + } + + IBackgroundCopyManager_Release(manager); +} + +static void test_EnumJobs(void) +{ + /* Job Enumerator */ + IEnumBackgroundCopyJobs* enumJobs; + + static const WCHAR copyNameW[] = {'T', 'e', 's', 't', 0}; + IBackgroundCopyManager *manager = NULL; + IBackgroundCopyJob *job = NULL; + HRESULT hres; + GUID tmpId; + ULONG res; + + /* Setup */ + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, + CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager, + (void **) &manager); + if(hres != S_OK) + { + skip("Unable to create bits instance required for test.\n"); + return; + } + hres = IBackgroundCopyManager_CreateJob(manager, copyNameW, + BG_JOB_TYPE_DOWNLOAD, &tmpId, + &job); + if(hres != S_OK) + { + skip("Unable to create bits job.\n"); + IBackgroundCopyManager_Release(manager); + return; + } + + hres = IBackgroundCopyManager_EnumJobs(manager, 0, &enumJobs); + ok(hres == S_OK, "EnumJobs failed: %08x\n", hres); + if(hres != S_OK) + skip("Unable to create job enumerator.\n"); + else + { + res = IEnumBackgroundCopyJobs_Release(enumJobs); + ok(res == 0, "Bad ref count on release: %u\n", res); + } + + /* Tear down */ + IBackgroundCopyJob_Release(job); + IBackgroundCopyManager_Release(manager); +} + +static void run_child(WCHAR *secret) +{ + static const WCHAR format[] = {'%','s',' ','q','m','g','r',' ','%','s', 0}; + WCHAR cmdline[MAX_PATH]; + PROCESS_INFORMATION info; + STARTUPINFOW startup; + + memset(&startup, 0, sizeof startup); + startup.cb = sizeof startup; + + wsprintfW(cmdline, format, progname, secret); + ok(CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n"); + winetest_wait_child_process(info.hProcess); + ok(CloseHandle(info.hProcess), "CloseHandle\n"); + ok(CloseHandle(info.hThread), "CloseHandle\n"); +} + +static void do_child(const char *secretA) +{ + WCHAR secretW[MAX_PATH]; + IBackgroundCopyManager *manager = NULL; + GUID id; + IBackgroundCopyJob *job; + HRESULT hres; + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, + CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager, + (void **) &manager); + if(hres != S_OK) + { + skip("Unable to create bits instance required for test.\n"); + return; + } + + MultiByteToWideChar(CP_ACP, 0, secretA, -1, secretW, MAX_PATH); + hres = IBackgroundCopyManager_CreateJob(manager, secretW, + BG_JOB_TYPE_DOWNLOAD, &id, &job); + ok(hres == S_OK, "CreateJob in child process\n"); + IBackgroundCopyJob_Release(job); + IBackgroundCopyManager_Release(manager); +} + +static void test_globalness(void) +{ + static const WCHAR format[] = {'t','e','s','t','_','%','u', 0}; + WCHAR secretName[MAX_PATH]; + IEnumBackgroundCopyJobs* enumJobs; + IBackgroundCopyManager *manager = NULL; + HRESULT hres; + hres = CoCreateInstance(&CLSID_BackgroundCopyManager, NULL, + CLSCTX_LOCAL_SERVER, &IID_IBackgroundCopyManager, + (void **) &manager); + if(hres != S_OK) + { + skip("Unable to create bits instance required for test.\n"); + return; + } + + wsprintfW(secretName, format, GetTickCount()); + run_child(secretName); + + hres = IBackgroundCopyManager_EnumJobs(manager, 0, &enumJobs); + ok(hres == S_OK, "EnumJobs failed: %08x\n", hres); + if(hres != S_OK) + skip("Unable to create job enumerator.\n"); + else + { + ULONG i, n; + IBackgroundCopyJob *job; + BOOL found = FALSE; + + hres = IEnumBackgroundCopyJobs_GetCount(enumJobs, &n); + for (i = 0; i < n && !found; ++i) + { + LPWSTR name; + IEnumBackgroundCopyJobs_Next(enumJobs, 1, &job, NULL); + IBackgroundCopyJob_GetDisplayName(job, &name); + if (lstrcmpW(name, secretName) == 0) + found = TRUE; + CoTaskMemFree(name); + IBackgroundCopyJob_Release(job); + } + hres = IEnumBackgroundCopyJobs_Release(enumJobs); + ok(found, "Adding a job in another process failed\n"); + } + + IBackgroundCopyManager_Release(manager); +} + +START_TEST(qmgr) +{ + char **argv; + int argc = winetest_get_mainargs(&argv); + MultiByteToWideChar(CP_ACP, 0, argv[0], -1, progname, MAX_PATH); + + CoInitialize(NULL); + if (argc == 3) + do_child(argv[2]); + else + { + test_CreateInstance(); + test_CreateJob(); + test_EnumJobs(); + test_globalness(); + } + CoUninitialize(); +} diff --git a/rostests/winetests/qmgr/qmgr.rbuild b/rostests/winetests/qmgr/qmgr.rbuild new file mode 100644 index 00000000000..ea3ecdea9c3 --- /dev/null +++ b/rostests/winetests/qmgr/qmgr.rbuild @@ -0,0 +1,15 @@ + + . + + enum_files.c + enum_jobs.c + file.c + job.c + qmgr.c + testlist.c + wine + ole32 + shlwapi + user32 + ntdll + diff --git a/rostests/winetests/qmgr/testlist.c b/rostests/winetests/qmgr/testlist.c new file mode 100644 index 00000000000..7292b44ab5f --- /dev/null +++ b/rostests/winetests/qmgr/testlist.c @@ -0,0 +1,23 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_qmgr(void); +extern void func_job(void); +extern void func_file(void); +extern void func_enum_jobs(void); +extern void func_enum_files(void); + +const struct test winetest_testlist[] = +{ + { "qmgr", func_qmgr }, + { "job", func_job }, + { "file", func_file }, + { "enum_jobs", func_enum_jobs }, + { "enum_files", func_enum_files }, + { 0, 0 } +}; diff --git a/rostests/winetests/quartz/avisplitter.c b/rostests/winetests/quartz/avisplitter.c new file mode 100644 index 00000000000..33a0d6d24e2 --- /dev/null +++ b/rostests/winetests/quartz/avisplitter.c @@ -0,0 +1,477 @@ +/* + * Unit tests for the avi splitter functions + * + * Copyright (C) 2007 Google (Lei Zhang) + * Copyright (C) 2008 Google (Maarten Lankhorst) + * + * 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 + */ + +#define COBJMACROS + +#include "wine/test.h" +#include "dshow.h" +#include "tlhelp32.h" + +static HANDLE (WINAPI *pCreateToolhelp32Snapshot)(DWORD, DWORD); +static BOOL (WINAPI *pThread32First)(HANDLE, LPTHREADENTRY32); +static BOOL (WINAPI *pThread32Next)(HANDLE, LPTHREADENTRY32); + +static IUnknown *pAviSplitter = NULL; + +static int count_threads(void) +{ + THREADENTRY32 te; + int threads; + HANDLE h; + + h = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + te.dwSize = sizeof(te); + + if (h == INVALID_HANDLE_VALUE) + return -1; + + pThread32First(h, &te); + if (te.th32OwnerProcessID == GetCurrentProcessId()) + threads = 1; + else + threads = 0; + + while (pThread32Next(h, &te)) + if (te.th32OwnerProcessID == GetCurrentProcessId()) + ++threads; + + CloseHandle(h); + return threads; +} + +static int create_avisplitter(void) +{ + HRESULT hr; + + hr = CoCreateInstance(&CLSID_AviSplitter, NULL, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (LPVOID*)&pAviSplitter); + return (hr == S_OK && pAviSplitter != NULL); +} + +static void release_avisplitter(void) +{ + HRESULT hr; + + Sleep(1000); + hr = IUnknown_Release(pAviSplitter); + + /* Looks like wine has a reference leak somewhere on test_threads tests, + * it passes in windows + */ + ok(hr == 0, "IUnknown_Release failed with %d\n", (INT)hr); + + while (hr > 0) + hr = IUnknown_Release(pAviSplitter); + pAviSplitter = NULL; +} + +static void test_query_interface(void) +{ + HRESULT hr; + ULONG ref; + IUnknown *iface= NULL; + + hr = IUnknown_QueryInterface(pAviSplitter, &IID_IBaseFilter, + (void**)&iface); + + ok(hr == S_OK, + "IID_IBaseFilter should exist, got %08x!\n", GetLastError()); + if (hr == S_OK) + { + ref = IUnknown_Release(iface); + iface = NULL; + ok(ref == 1, "Reference is %u, expected 1\n", ref); + } + + hr = IUnknown_QueryInterface(pAviSplitter, &IID_IMediaSeeking, + (void**)&iface); + if (hr == S_OK) + ref = IUnknown_Release(iface); + iface = NULL; + todo_wine ok(hr == E_NOINTERFACE, + "Query for IMediaSeeking returned: %08x\n", hr); + +/* These interfaces should not be present: + IID_IKsPropertySet, IID_IMediaPosition, IID_IQualityControl, IID_IQualProp +*/ +} + +static void test_pin(IPin *pin) +{ + IMemInputPin *mpin = NULL; + + IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&mpin); + + ok(mpin == NULL, "IMemInputPin found!\n"); + if (mpin) + IMemInputPin_Release(mpin); + /* TODO */ +} + +static void test_basefilter(void) +{ + IEnumPins *pin_enum = NULL; + IBaseFilter *base = NULL; + IPin *pins[2]; + ULONG ref; + HRESULT hr; + + IUnknown_QueryInterface(pAviSplitter, &IID_IBaseFilter, (void *)&base); + if (base == NULL) + { + /* test_query_interface handles this case */ + skip("No IBaseFilter\n"); + return; + } + + hr = IBaseFilter_EnumPins(base, NULL); + ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr); + + hr= IBaseFilter_EnumPins(base, &pin_enum); + ok(hr == S_OK, "hr = %08x and not S_OK\n", hr); + + hr = IEnumPins_Next(pin_enum, 1, NULL, NULL); + ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr); + + hr = IEnumPins_Next(pin_enum, 2, pins, NULL); + ok(hr == E_INVALIDARG, "hr = %08x and not E_INVALIDARG\n", hr); + + pins[0] = (void *)0xdead; + pins[1] = (void *)0xdeed; + + hr = IEnumPins_Next(pin_enum, 2, pins, &ref); + ok(hr == S_FALSE, "hr = %08x instead of S_FALSE\n", hr); + ok(pins[0] != (void *)0xdead && pins[0] != NULL, + "pins[0] = %p\n", pins[0]); + if (pins[0] != (void *)0xdead && pins[0] != NULL) + { + test_pin(pins[0]); + IPin_Release(pins[0]); + } + + ok(pins[1] == (void *)0xdeed, "pins[1] = %p\n", pins[1]); + + ref = IEnumPins_Release(pin_enum); + ok(ref == 0, "ref is %u and not 0!\n", ref); + + IBaseFilter_Release(base); +} + +static const WCHAR wfile[] = {'t','e','s','t','.','a','v','i',0}; +static const char afile[] = "test.avi"; + +/* This test doesn't use the quartz filtergraph because it makes it impossible + * to be certain that a thread is really one owned by the avi splitter + * A lot of the decoder filters will also have their own thread, and windows' + * filtergraph has a separate thread for start/stop/seeking requests. + * By avoiding the filtergraph all together and connecting streams directly to + * the null renderer I am sure that this is not the case here. + */ +static void test_threads(void) +{ + IFileSourceFilter *pfile = NULL; + IBaseFilter *preader = NULL, *pavi = NULL; + IEnumPins *enumpins = NULL; + IPin *filepin = NULL, *avipin = NULL; + HRESULT hr; + int baselevel, curlevel, expected; + HANDLE file = NULL; + PIN_DIRECTION dir = PINDIR_OUTPUT; + char buffer[13]; + DWORD readbytes; + FILTER_STATE state; + + /* We need another way of counting threads on NT4. Skip these tests (for now) */ + if (!pCreateToolhelp32Snapshot || !pThread32First || !pThread32Next) + { + win_skip("Needed thread functions are not available (NT4)\n"); + return; + } + + /* Before doing anything (number of threads at the start differs per OS) */ + baselevel = count_threads(); + + file = CreateFileW(wfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (file == INVALID_HANDLE_VALUE) + { + skip("Could not read test file \"%s\", skipping test\n", afile); + return; + } + + memset(buffer, 0, 13); + readbytes = 12; + ReadFile(file, buffer, readbytes, &readbytes, NULL); + CloseHandle(file); + if (strncmp(buffer, "RIFF", 4) || strcmp(buffer + 8, "AVI ")) + { + skip("%s is not an avi riff file, not doing the avi splitter test\n", + afile); + return; + } + + hr = IUnknown_QueryInterface(pAviSplitter, &IID_IFileSourceFilter, + (void **)&pfile); + ok(hr == E_NOINTERFACE, + "Avi splitter returns unexpected error: %08x\n", hr); + if (pfile) + IUnknown_Release(pfile); + pfile = NULL; + + hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (LPVOID*)&preader); + ok(hr == S_OK, "Could not create asynchronous reader: %08x\n", hr); + if (hr != S_OK) + goto fail; + + hr = IUnknown_QueryInterface(preader, &IID_IFileSourceFilter, + (void**)&pfile); + ok(hr == S_OK, "Could not get IFileSourceFilter: %08x\n", hr); + if (hr != S_OK) + goto fail; + + hr = IUnknown_QueryInterface(pAviSplitter, &IID_IBaseFilter, + (void**)&pavi); + ok(hr == S_OK, "Could not get base filter: %08x\n", hr); + if (hr != S_OK) + goto fail; + + hr = IFileSourceFilter_Load(pfile, wfile, NULL); + if (hr != S_OK) + { + trace("Could not load file\n"); + goto fail; + } + + hr = IBaseFilter_EnumPins(preader, &enumpins); + ok(hr == S_OK, "No enumpins: %08x\n", hr); + if (hr != S_OK) + goto fail; + + hr = IEnumPins_Next(enumpins, 1, &filepin, NULL); + ok(hr == S_OK, "No pin: %08x\n", hr); + if (hr != S_OK) + goto fail; + + IUnknown_Release(enumpins); + enumpins = NULL; + + hr = IBaseFilter_EnumPins(pavi, &enumpins); + ok(hr == S_OK, "No enumpins: %08x\n", hr); + if (hr != S_OK) + goto fail; + + hr = IEnumPins_Next(enumpins, 1, &avipin, NULL); + ok(hr == S_OK, "No pin: %08x\n", hr); + if (hr != S_OK) + goto fail; + + curlevel = count_threads(); + ok(curlevel == baselevel, + "Amount of threads should be %d not %d\n", baselevel, curlevel); + + hr = IPin_Connect(filepin, avipin, NULL); + ok(hr == S_OK, "Could not connect: %08x\n", hr); + if (hr != S_OK) + goto fail; + + expected = 1 + baselevel; + curlevel = count_threads(); + ok(curlevel == expected, + "Amount of threads should be %d not %d\n", expected, curlevel); + + IUnknown_Release(avipin); + avipin = NULL; + + IEnumPins_Reset(enumpins); + + /* Windows puts the pins in the order: Outputpins - Inputpin, + * wine does the reverse, just don't test it for now + * Hate to admit it, but windows way makes more sense + */ + while (IEnumPins_Next(enumpins, 1, &avipin, NULL) == S_OK) + { + ok(hr == S_OK, "hr: %08x\n", hr); + IPin_QueryDirection(avipin, &dir); + if (dir == PINDIR_OUTPUT) + { + /* Well, connect it to a null renderer! */ + IBaseFilter *pnull = NULL; + IEnumPins *nullenum = NULL; + IPin *nullpin = NULL; + + hr = CoCreateInstance(&CLSID_NullRenderer, NULL, + CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pnull); + ok(hr == S_OK, "Could not create null renderer: %08x\n", hr); + if (hr != S_OK) + break; + + IBaseFilter_EnumPins(pnull, &nullenum); + IEnumPins_Next(nullenum, 1, &nullpin, NULL); + IEnumPins_Release(nullenum); + IPin_QueryDirection(nullpin, &dir); + + hr = IPin_Connect(avipin, nullpin, NULL); + ok(hr == S_OK, "Failed to connect output pin: %08x\n", hr); + IPin_Release(nullpin); + if (hr != S_OK) + { + IBaseFilter_Release(pnull); + break; + } + IBaseFilter_Run(pnull, 0); + ++expected; + } + + IUnknown_Release(avipin); + avipin = NULL; + } + + if (avipin) + IUnknown_Release(avipin); + avipin = NULL; + + if (hr != S_OK) + goto fail2; + /* At this point there is a minimalistic connected avi splitter that can + * Be used for all sorts of source filter tests, however that still needs + * to be written at a later time. + * + * Interesting tests: + * - Can you disconnect an output pin while running? + * Expecting: Yes + * - Can you disconnect the pullpin while running? + * Expecting: No + * - Is the reference count incremented during playback or when connected? + * Does this happen once for every output pin? Or is there something else + * going on. + * Expecting: You tell me + */ + + IBaseFilter_Run(preader, 0); + IBaseFilter_Run(pavi, 0); + IBaseFilter_GetState(pavi, INFINITE, &state); + + curlevel = count_threads(); + ok(curlevel == expected, + "Amount of threads should be %d not %d\n", expected, curlevel); + + IBaseFilter_Pause(pavi); + IBaseFilter_Pause(preader); + IBaseFilter_Stop(pavi); + IBaseFilter_Stop(preader); + IBaseFilter_GetState(pavi, INFINITE, &state); + IBaseFilter_GetState(preader, INFINITE, &state); + +fail2: + IEnumPins_Reset(enumpins); + while (IEnumPins_Next(enumpins, 1, &avipin, NULL) == S_OK) + { + IPin *to = NULL; + + IPin_QueryDirection(avipin, &dir); + IPin_ConnectedTo(avipin, &to); + if (to) + { + IPin_Release(to); + + if (dir == PINDIR_OUTPUT) + { + PIN_INFO info; + IPin_QueryPinInfo(to, &info); + + /* Release twice: Once normal, second from the + * previous while loop + */ + IBaseFilter_Stop(info.pFilter); + IPin_Disconnect(to); + IPin_Disconnect(avipin); + IBaseFilter_Release(info.pFilter); + IBaseFilter_Release(info.pFilter); + } + else + { + IPin_Disconnect(to); + IPin_Disconnect(avipin); + } + } + IPin_Release(avipin); + avipin = NULL; + } + +fail: + if (hr != S_OK) + skip("Prerequisites not matched, skipping remainder of test\n"); + if (enumpins) + IUnknown_Release(enumpins); + + if (avipin) + IUnknown_Release(avipin); + if (filepin) + { + IPin *to = NULL; + + IPin_ConnectedTo(filepin, &to); + if (to) + { + IPin_Disconnect(filepin); + IPin_Disconnect(to); + } + IUnknown_Release(filepin); + } + + if (preader) + IUnknown_Release(preader); + if (pavi) + IUnknown_Release(pavi); + if (pfile) + IUnknown_Release(pfile); + + curlevel = count_threads(); + todo_wine + ok(curlevel == baselevel, + "Amount of threads should be %d not %d\n", baselevel, curlevel); +} + +START_TEST(avisplitter) +{ + HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); + + pCreateToolhelp32Snapshot = (void*)GetProcAddress(kernel32, "CreateToolhelp32Snapshot"); + pThread32First = (void*)GetProcAddress(kernel32, "Thread32First"); + pThread32Next = (void*)GetProcAddress(kernel32, "Thread32Next"); + + CoInitialize(NULL); + + if (!create_avisplitter()) + { + skip("Could not create avisplitter\n"); + return; + } + + test_query_interface(); + test_basefilter(); + test_threads(); + + release_avisplitter(); + + CoUninitialize(); +} diff --git a/rostests/winetests/quartz/filtergraph.c b/rostests/winetests/quartz/filtergraph.c new file mode 100644 index 00000000000..26a72beef8d --- /dev/null +++ b/rostests/winetests/quartz/filtergraph.c @@ -0,0 +1,1857 @@ +/* + * Unit tests for Direct Show functions + * + * Copyright (C) 2004 Christian Costa + * Copyright (C) 2008 Alexander Dorofeyev + * + * 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 + */ + +#include + +#define COBJMACROS + +#include "wine/test.h" +#include "dshow.h" +#include "control.h" + +#define FILE_LEN 9 +static const char avifileA[FILE_LEN] = "test.avi"; +static const char mpegfileA[FILE_LEN] = "test.mpg"; + +IGraphBuilder* pgraph; + +static int createfiltergraph(void) +{ + return S_OK == CoCreateInstance( + &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph); +} + +static void renderfile(const char * fileA) +{ + HRESULT hr; + WCHAR fileW[FILE_LEN]; + + MultiByteToWideChar(CP_ACP, 0, fileA, -1, fileW, FILE_LEN); + + hr = IGraphBuilder_RenderFile(pgraph, fileW, NULL); + ok(hr==S_OK, "RenderFile returned: %x\n", hr); +} + +static void rungraph(void) +{ + HRESULT hr; + IMediaControl* pmc; + IMediaEvent* pme; + IMediaFilter* pmf; + HANDLE hEvent; + + hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc); + ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr); + + hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf); + ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr); + + IMediaControl_Stop(pmc); + + IMediaFilter_SetSyncSource(pmf, NULL); + + IMediaFilter_Release(pmf); + + hr = IMediaControl_Run(pmc); + ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr); + + Sleep(10); + /* Crash fun */ + trace("run -> stop\n"); + hr = IMediaControl_Stop(pmc); + ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr); + + IGraphBuilder_SetDefaultSyncSource(pgraph); + + Sleep(10); + trace("stop -> pause\n"); + hr = IMediaControl_Pause(pmc); + ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr); + + Sleep(10); + trace("pause -> run\n"); + hr = IMediaControl_Run(pmc); + ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr); + + Sleep(10); + trace("run -> pause\n"); + hr = IMediaControl_Pause(pmc); + ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr); + + Sleep(10); + trace("pause -> stop\n"); + hr = IMediaControl_Stop(pmc); + ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr); + + Sleep(10); + trace("pause -> run\n"); + hr = IMediaControl_Run(pmc); + ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr); + + trace("run -> stop\n"); + hr = IMediaControl_Stop(pmc); + ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr); + + trace("stop -> run\n"); + hr = IMediaControl_Run(pmc); + ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr); + + hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme); + ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr); + + hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent); + ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr); + + /* WaitForSingleObject(hEvent, INFINITE); */ + Sleep(20000); + + hr = IMediaEvent_Release(pme); + ok(hr==2, "Releasing mediaevent returned: %x\n", hr); + + hr = IMediaControl_Stop(pmc); + ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr); + + hr = IMediaControl_Release(pmc); + ok(hr==1, "Releasing mediacontrol returned: %x\n", hr); +} + +static void releasefiltergraph(void) +{ + HRESULT hr; + + hr = IGraphBuilder_Release(pgraph); + ok(hr==0, "Releasing filtergraph returned: %x\n", hr); +} + +static void test_render_run(const char * fileA) +{ + HANDLE h; + + if (!createfiltergraph()) + return; + + h = CreateFileA(fileA, 0, 0, NULL, OPEN_EXISTING, 0, NULL); + if (h != INVALID_HANDLE_VALUE) { + CloseHandle(h); + renderfile(fileA); + rungraph(); + } + + releasefiltergraph(); +} + +static void test_graph_builder(void) +{ + HRESULT hr; + IBaseFilter *pF = NULL; + IBaseFilter *pF2 = NULL; + IPin *pIn = NULL; + IEnumPins *pEnum = NULL; + PIN_DIRECTION dir; + static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0}; + static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0}; + + if (!createfiltergraph()) + return; + + /* create video filter */ + hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (LPVOID*)&pF); + ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); + ok(pF != NULL, "pF is NULL\n"); + + /* add the two filters to the graph */ + hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW); + ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr); + + /* find the pins */ + hr = IBaseFilter_EnumPins(pF, &pEnum); + ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr); + ok(pEnum != NULL, "pEnum is NULL\n"); + hr = IEnumPins_Next(pEnum, 1, &pIn, NULL); + ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr); + ok(pIn != NULL, "pIn is NULL\n"); + hr = IPin_QueryDirection(pIn, &dir); + ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr); + ok(dir == PINDIR_INPUT, "pin has wrong direction\n"); + + hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2); + ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr); + ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2); + hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2); + ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr); + ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n"); + hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL); + ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr); + + if (pIn) IPin_Release(pIn); + if (pEnum) IEnumPins_Release(pEnum); + if (pF) IBaseFilter_Release(pF); + if (pF2) IBaseFilter_Release(pF2); + + releasefiltergraph(); +} + +static void test_graph_builder_addfilter(void) +{ + HRESULT hr; + IBaseFilter *pF = NULL; + static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0}; + + if (!createfiltergraph()) + return; + + hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW); + ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr); + + /* create video filter */ + hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (LPVOID*)&pF); + ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); + ok(pF != NULL, "pF is NULL\n"); + if (!pF) { + skip("failed to created filter, skipping\n"); + return; + } + + hr = IGraphBuilder_AddFilter(pgraph, pF, NULL); + ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr); + IMediaFilter_Release(pF); +} + +static void test_mediacontrol(void) +{ + HRESULT hr; + LONGLONG pos = 0xdeadbeef; + IMediaSeeking *seeking = NULL; + IMediaFilter *filter = NULL; + IMediaControl *control = NULL; + + IFilterGraph2_SetDefaultSyncSource(pgraph); + hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking); + ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr); + if (FAILED(hr)) + return; + + hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter); + ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr); + if (FAILED(hr)) + { + IUnknown_Release(seeking); + return; + } + + hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control); + ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr); + if (FAILED(hr)) + { + IUnknown_Release(seeking); + IUnknown_Release(filter); + return; + } + + hr = IMediaSeeking_GetCurrentPosition(seeking, &pos); + ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr); + ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos); + + hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning); + ok(hr == S_OK, "SetPositions failed: %08x\n", hr); + hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime); + ok(hr == S_OK, "SetPositions failed: %08x\n", hr); + + IMediaFilter_SetSyncSource(filter, NULL); + pos = 0xdeadbeef; + hr = IMediaSeeking_GetCurrentPosition(seeking, &pos); + ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr); + ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos); + + hr = IMediaControl_GetState(control, 1000, NULL); + ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr); + + IUnknown_Release(control); + IUnknown_Release(seeking); + IUnknown_Release(filter); + releasefiltergraph(); +} + +static void test_filter_graph2(void) +{ + HRESULT hr; + IFilterGraph2 *pF = NULL; + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterGraph2, (LPVOID*)&pF); + ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); + ok(pF != NULL, "pF is NULL\n"); + + hr = IFilterGraph2_Release(pF); + ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr); +} + +/* IEnumMediaTypes implementation (supporting code for Render() test.) */ +static void FreeMediaType(AM_MEDIA_TYPE * pMediaType) +{ + if (pMediaType->pbFormat) + { + CoTaskMemFree(pMediaType->pbFormat); + pMediaType->pbFormat = NULL; + } + if (pMediaType->pUnk) + { + IUnknown_Release(pMediaType->pUnk); + pMediaType->pUnk = NULL; + } +} + +static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc) +{ + *pDest = *pSrc; + if (!pSrc->pbFormat) return S_OK; + if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat))) + return E_OUTOFMEMORY; + memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat); + if (pDest->pUnk) + IUnknown_AddRef(pDest->pUnk); + return S_OK; +} + +static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc) +{ + AM_MEDIA_TYPE * pDest; + + pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (!pDest) + return NULL; + + if (FAILED(CopyMediaType(pDest, pSrc))) + { + CoTaskMemFree(pDest); + return NULL; + } + + return pDest; +} + +static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards) +{ + return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) && + ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype))); +} + +static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType) +{ + FreeMediaType(pMediaType); + CoTaskMemFree(pMediaType); +} + +typedef struct IEnumMediaTypesImpl +{ + const IEnumMediaTypesVtbl * lpVtbl; + LONG refCount; + AM_MEDIA_TYPE *pMediaTypes; + ULONG cMediaTypes; + ULONG uIndex; +} IEnumMediaTypesImpl; + +static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl; + +static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum) +{ + ULONG i; + IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl)); + + if (!pEnumMediaTypes) + { + *ppEnum = NULL; + return E_OUTOFMEMORY; + } + pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl; + pEnumMediaTypes->refCount = 1; + pEnumMediaTypes->uIndex = 0; + pEnumMediaTypes->cMediaTypes = cMediaTypes; + pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes); + for (i = 0; i < cMediaTypes; i++) + if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i]))) + { + while (i--) + FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]); + CoTaskMemFree(pEnumMediaTypes->pMediaTypes); + return E_OUTOFMEMORY; + } + *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl); + return S_OK; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv) +{ + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IEnumMediaTypes)) + *ppv = iface; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface) +{ + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + + return refCount; +} + +static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface) +{ + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + if (!refCount) + { + int i; + for (i = 0; i < This->cMediaTypes; i++) + FreeMediaType(&This->pMediaTypes[i]); + CoTaskMemFree(This->pMediaTypes); + CoTaskMemFree(This); + } + return refCount; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched) +{ + ULONG cFetched; + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + + cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex; + + if (cFetched > 0) + { + ULONG i; + for (i = 0; i < cFetched; i++) + if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i]))) + { + while (i--) + DeleteMediaType(ppMediaTypes[i]); + *pcFetched = 0; + return E_OUTOFMEMORY; + } + } + + if ((cMediaTypes != 1) || pcFetched) + *pcFetched = cFetched; + + This->uIndex += cFetched; + + if (cFetched != cMediaTypes) + return S_FALSE; + return S_OK; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes) +{ + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + + if (This->uIndex + cMediaTypes < This->cMediaTypes) + { + This->uIndex += cMediaTypes; + return S_OK; + } + return S_FALSE; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface) +{ + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + + This->uIndex = 0; + return S_OK; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum) +{ + HRESULT hr; + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + + hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum); + if (FAILED(hr)) + return hr; + return IEnumMediaTypes_Skip(*ppEnum, This->uIndex); +} + +static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl = +{ + IEnumMediaTypesImpl_QueryInterface, + IEnumMediaTypesImpl_AddRef, + IEnumMediaTypesImpl_Release, + IEnumMediaTypesImpl_Next, + IEnumMediaTypesImpl_Skip, + IEnumMediaTypesImpl_Reset, + IEnumMediaTypesImpl_Clone +}; + +/* Implementation of a very stripped down pin for the test filter. Just enough + functionality for connecting and Render() to work. */ + +static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc) +{ + lstrcpyW(pDest->achName, pSrc->achName); + pDest->dir = pSrc->dir; + pDest->pFilter = pSrc->pFilter; +} + +typedef struct ITestPinImpl +{ + const struct IPinVtbl * lpVtbl; + LONG refCount; + LPCRITICAL_SECTION pCritSec; + PIN_INFO pinInfo; + IPin * pConnectedTo; + AM_MEDIA_TYPE mtCurrent; + LPVOID pUserData; +} ITestPinImpl; + +static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) +{ + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IPin)) + *ppv = iface; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + return refCount; +} + +static ULONG WINAPI TestFilter_Pin_Release(IPin * iface) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + if (!refCount) + { + FreeMediaType(&This->mtCurrent); + This->lpVtbl = NULL; + CoTaskMemFree(This); + return 0; + } + else + return refCount; +} + +static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt) +{ + return E_UNEXPECTED; +} + +static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + PIN_DIRECTION pindirReceive; + HRESULT hr = S_OK; + + EnterCriticalSection(This->pCritSec); + { + if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) || + IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))) + hr = VFW_E_TYPE_NOT_ACCEPTED; + + if (This->pConnectedTo) + hr = VFW_E_ALREADY_CONNECTED; + + if (SUCCEEDED(hr)) + { + IPin_QueryDirection(pReceivePin, &pindirReceive); + + if (pindirReceive != PINDIR_OUTPUT) + { + hr = VFW_E_INVALID_DIRECTION; + } + } + + if (SUCCEEDED(hr)) + { + CopyMediaType(&This->mtCurrent, pmt); + This->pConnectedTo = pReceivePin; + IPin_AddRef(pReceivePin); + } + } + LeaveCriticalSection(This->pCritSec); + + return hr; +} + +static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface) +{ + HRESULT hr; + ITestPinImpl *This = (ITestPinImpl *)iface; + + EnterCriticalSection(This->pCritSec); + { + if (This->pConnectedTo) + { + IPin_Release(This->pConnectedTo); + This->pConnectedTo = NULL; + hr = S_OK; + } + else + hr = S_FALSE; + } + LeaveCriticalSection(This->pCritSec); + + return hr; +} + +static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin) +{ + HRESULT hr; + ITestPinImpl *This = (ITestPinImpl *)iface; + + EnterCriticalSection(This->pCritSec); + { + if (This->pConnectedTo) + { + *ppPin = This->pConnectedTo; + IPin_AddRef(*ppPin); + hr = S_OK; + } + else + { + hr = VFW_E_NOT_CONNECTED; + *ppPin = NULL; + } + } + LeaveCriticalSection(This->pCritSec); + + return hr; +} + +static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt) +{ + HRESULT hr; + ITestPinImpl *This = (ITestPinImpl *)iface; + + EnterCriticalSection(This->pCritSec); + { + if (This->pConnectedTo) + { + CopyMediaType(pmt, &This->mtCurrent); + hr = S_OK; + } + else + { + ZeroMemory(pmt, sizeof(*pmt)); + hr = VFW_E_NOT_CONNECTED; + } + } + LeaveCriticalSection(This->pCritSec); + + return hr; +} + +static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + + Copy_PinInfo(pInfo, &This->pinInfo); + IBaseFilter_AddRef(pInfo->pFilter); + + return S_OK; +} + +static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + + *pPinDir = This->pinInfo.dir; + + return S_OK; +} + +static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + + if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) || + IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))) + return S_OK; + else + return VFW_E_TYPE_NOT_ACCEPTED; +} + +static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + + return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum); +} + +static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface) +{ + return E_NOTIMPL; +} + +static const IPinVtbl TestFilter_InputPin_Vtbl = +{ + TestFilter_Pin_QueryInterface, + TestFilter_Pin_AddRef, + TestFilter_Pin_Release, + TestFilter_InputPin_Connect, + TestFilter_InputPin_ReceiveConnection, + TestFilter_Pin_Disconnect, + TestFilter_Pin_ConnectedTo, + TestFilter_Pin_ConnectionMediaType, + TestFilter_Pin_QueryPinInfo, + TestFilter_Pin_QueryDirection, + TestFilter_Pin_QueryId, + TestFilter_Pin_QueryAccept, + TestFilter_Pin_EnumMediaTypes, + TestFilter_Pin_QueryInternalConnections, + TestFilter_Pin_EndOfStream, + TestFilter_Pin_BeginFlush, + TestFilter_Pin_EndFlush, + TestFilter_Pin_NewSegment +}; + +static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + return E_UNEXPECTED; +} + +/* Private helper function */ +static HRESULT TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + HRESULT hr; + + This->pConnectedTo = pReceivePin; + IPin_AddRef(pReceivePin); + + hr = IPin_ReceiveConnection(pReceivePin, iface, pmt); + + if (FAILED(hr)) + { + IPin_Release(This->pConnectedTo); + This->pConnectedTo = NULL; + } + + return hr; +} + +static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + ITestPinImpl *This = (ITestPinImpl *)iface; + HRESULT hr; + + EnterCriticalSection(This->pCritSec); + { + /* if we have been a specific type to connect with, then we can either connect + * with that or fail. We cannot choose different AM_MEDIA_TYPE */ + if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL)) + hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt); + else + { + if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) && + (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK)) + hr = S_OK; + else hr = VFW_E_NO_ACCEPTABLE_TYPES; + } /* if negotiate media type */ + } /* if succeeded */ + LeaveCriticalSection(This->pCritSec); + + return hr; +} + +static const IPinVtbl TestFilter_OutputPin_Vtbl = +{ + TestFilter_Pin_QueryInterface, + TestFilter_Pin_AddRef, + TestFilter_Pin_Release, + TestFilter_OutputPin_Connect, + TestFilter_OutputPin_ReceiveConnection, + TestFilter_Pin_Disconnect, + TestFilter_Pin_ConnectedTo, + TestFilter_Pin_ConnectionMediaType, + TestFilter_Pin_QueryPinInfo, + TestFilter_Pin_QueryDirection, + TestFilter_Pin_QueryId, + TestFilter_Pin_QueryAccept, + TestFilter_Pin_EnumMediaTypes, + TestFilter_Pin_QueryInternalConnections, + TestFilter_Pin_EndOfStream, + TestFilter_Pin_BeginFlush, + TestFilter_Pin_EndFlush, + TestFilter_Pin_NewSegment +}; + +static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt, + LPCRITICAL_SECTION pCritSec, IPin ** ppPin) +{ + ITestPinImpl * pPinImpl; + + *ppPin = NULL; + + pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl)); + + if (!pPinImpl) + return E_OUTOFMEMORY; + + pPinImpl->refCount = 1; + pPinImpl->pConnectedTo = NULL; + pPinImpl->pCritSec = pCritSec; + Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo); + pPinImpl->mtCurrent = *pinmt; + + pPinImpl->lpVtbl = Pin_Vtbl; + + *ppPin = (IPin *)pPinImpl; + return S_OK; +} + +/* IEnumPins implementation */ + +typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick); + +typedef struct IEnumPinsImpl +{ + const IEnumPinsVtbl * lpVtbl; + LONG refCount; + ULONG uIndex; + IBaseFilter *base; + FNOBTAINPIN receive_pin; + DWORD synctime; +} IEnumPinsImpl; + +static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl; + +static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base) +{ + IEnumPinsImpl * pEnumPins; + + if (!ppEnum) + return E_POINTER; + + pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl)); + if (!pEnumPins) + { + *ppEnum = NULL; + return E_OUTOFMEMORY; + } + pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl; + pEnumPins->refCount = 1; + pEnumPins->uIndex = 0; + pEnumPins->receive_pin = receive_pin; + pEnumPins->base = base; + IBaseFilter_AddRef(base); + *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl); + + receive_pin(base, ~0, NULL, &pEnumPins->synctime); + + return S_OK; +} + +static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv) +{ + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IEnumPins)) + *ppv = iface; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + + return refCount; +} + +static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + if (!refCount) + { + IBaseFilter_Release(This->base); + CoTaskMemFree(This); + return 0; + } + else + return refCount; +} + +static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + DWORD synctime = This->synctime; + HRESULT hr = S_OK; + ULONG i = 0; + + if (!ppPins) + return E_POINTER; + + if (cPins > 1 && !pcFetched) + return E_INVALIDARG; + + if (pcFetched) + *pcFetched = 0; + + while (i < cPins && hr == S_OK) + { + hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime); + + if (hr == S_OK) + ++i; + + if (synctime != This->synctime) + break; + } + + if (!i && synctime != This->synctime) + return VFW_E_ENUM_OUT_OF_SYNC; + + if (pcFetched) + *pcFetched = i; + This->uIndex += i; + + if (i < cPins) + return S_FALSE; + return S_OK; +} + +static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + DWORD synctime = This->synctime; + HRESULT hr; + IPin *pin = NULL; + + hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime); + if (pin) + IPin_Release(pin); + + if (synctime != This->synctime) + return VFW_E_ENUM_OUT_OF_SYNC; + + if (hr == S_OK) + This->uIndex += cPins; + + return hr; +} + +static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + + This->receive_pin(This->base, ~0, NULL, &This->synctime); + + This->uIndex = 0; + return S_OK; +} + +static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum) +{ + HRESULT hr; + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + + hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base); + if (FAILED(hr)) + return hr; + return IEnumPins_Skip(*ppEnum, This->uIndex); +} + +static const IEnumPinsVtbl IEnumPinsImpl_Vtbl = +{ + IEnumPinsImpl_QueryInterface, + IEnumPinsImpl_AddRef, + IEnumPinsImpl_Release, + IEnumPinsImpl_Next, + IEnumPinsImpl_Skip, + IEnumPinsImpl_Reset, + IEnumPinsImpl_Clone +}; + +/* Test filter implementation - a filter that has few predefined pins with single media type + * that accept only this single media type. Enough for Render(). */ + +typedef struct TestFilterPinData +{ +PIN_DIRECTION pinDir; +const GUID *mediasubtype; +} TestFilterPinData; + +typedef struct TestFilterImpl +{ + const IBaseFilterVtbl * lpVtbl; + + LONG refCount; + CRITICAL_SECTION csFilter; + FILTER_STATE state; + FILTER_INFO filterInfo; + CLSID clsid; + IPin ** ppPins; + UINT nPins; +} TestFilterImpl; + +static const IBaseFilterVtbl TestFilter_Vtbl; + +static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv) +{ + static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; + static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0}; + HRESULT hr; + PIN_INFO pinInfo; + TestFilterImpl* pTestFilter = NULL; + UINT nPins, i; + AM_MEDIA_TYPE mt; + + pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl)); + if (!pTestFilter) return E_OUTOFMEMORY; + + pTestFilter->clsid = *pClsid; + pTestFilter->lpVtbl = &TestFilter_Vtbl; + pTestFilter->refCount = 1; + InitializeCriticalSection(&pTestFilter->csFilter); + pTestFilter->state = State_Stopped; + + ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO)); + + nPins = 0; + while(pinData[nPins].mediasubtype) ++nPins; + + pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *)); + if (!pTestFilter->ppPins) + { + hr = E_OUTOFMEMORY; + goto error; + } + ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *)); + + for (i = 0; i < nPins; i++) + { + ZeroMemory(&mt, sizeof(mt)); + mt.majortype = MEDIATYPE_Video; + mt.formattype = FORMAT_None; + mt.subtype = *pinData[i].mediasubtype; + + pinInfo.dir = pinData[i].pinDir; + pinInfo.pFilter = (IBaseFilter *)pTestFilter; + if (pinInfo.dir == PINDIR_INPUT) + { + lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0])); + hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter, + &pTestFilter->ppPins[i]); + + } + else + { + lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0])); + hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter, + &pTestFilter->ppPins[i]); + } + if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error; + } + + pTestFilter->nPins = nPins; + *ppv = pTestFilter; + return S_OK; + + error: + + if (pTestFilter->ppPins) + { + for (i = 0; i < nPins; i++) + { + if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]); + } + } + CoTaskMemFree(pTestFilter->ppPins); + DeleteCriticalSection(&pTestFilter->csFilter); + CoTaskMemFree(pTestFilter); + + return hr; +} + +static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) +{ + TestFilterImpl *This = (TestFilterImpl *)iface; + + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = This; + else if (IsEqualIID(riid, &IID_IPersist)) + *ppv = This; + else if (IsEqualIID(riid, &IID_IMediaFilter)) + *ppv = This; + else if (IsEqualIID(riid, &IID_IBaseFilter)) + *ppv = This; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface) +{ + TestFilterImpl *This = (TestFilterImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + + return refCount; +} + +static ULONG WINAPI TestFilter_Release(IBaseFilter * iface) +{ + TestFilterImpl *This = (TestFilterImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + if (!refCount) + { + ULONG i; + + for (i = 0; i < This->nPins; i++) + { + IPin *pConnectedTo; + + if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo))) + { + IPin_Disconnect(pConnectedTo); + IPin_Release(pConnectedTo); + } + IPin_Disconnect(This->ppPins[i]); + + IPin_Release(This->ppPins[i]); + } + + CoTaskMemFree(This->ppPins); + This->lpVtbl = NULL; + + DeleteCriticalSection(&This->csFilter); + + CoTaskMemFree(This); + + return 0; + } + else + return refCount; +} +/** IPersist methods **/ + +static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid) +{ + TestFilterImpl *This = (TestFilterImpl *)iface; + + *pClsid = This->clsid; + + return S_OK; +} + +/** IMediaFilter methods **/ + +static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + TestFilterImpl *This = (TestFilterImpl *)iface; + + EnterCriticalSection(&This->csFilter); + { + *pState = This->state; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) +{ + return E_NOTIMPL; +} + +/** IBaseFilter implementation **/ + +static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) +{ + TestFilterImpl *This = (TestFilterImpl *)iface; + + /* Our pins are static, not changing so setting static tick count is ok */ + *lastsynctick = 0; + + if (pos >= This->nPins) + return S_FALSE; + + *pin = This->ppPins[pos]; + IPin_AddRef(*pin); + return S_OK; +} + +static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) +{ + return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface); +} + +static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) +{ + TestFilterImpl *This = (TestFilterImpl *)iface; + + lstrcpyW(pInfo->achName, This->filterInfo.achName); + pInfo->pGraph = This->filterInfo.pGraph; + + if (pInfo->pGraph) + IFilterGraph_AddRef(pInfo->pGraph); + + return S_OK; +} + +static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) +{ + HRESULT hr = S_OK; + TestFilterImpl *This = (TestFilterImpl *)iface; + + EnterCriticalSection(&This->csFilter); + { + if (pName) + lstrcpyW(This->filterInfo.achName, pName); + else + *This->filterInfo.achName = '\0'; + This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */ + } + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) +{ + return E_NOTIMPL; +} + +static const IBaseFilterVtbl TestFilter_Vtbl = +{ + TestFilter_QueryInterface, + TestFilter_AddRef, + TestFilter_Release, + TestFilter_GetClassID, + TestFilter_Stop, + TestFilter_Pause, + TestFilter_Run, + TestFilter_GetState, + TestFilter_SetSyncSource, + TestFilter_GetSyncSource, + TestFilter_EnumPins, + TestFilter_FindPin, + TestFilter_QueryFilterInfo, + TestFilter_JoinFilterGraph, + TestFilter_QueryVendorInfo +}; + +/* IClassFactory implementation */ + +typedef struct TestClassFactoryImpl +{ + IClassFactoryVtbl *lpVtbl; + const TestFilterPinData *filterPinData; + const CLSID *clsid; +} TestClassFactoryImpl; + +static HRESULT WINAPI Test_IClassFactory_QueryInterface( + LPCLASSFACTORY iface, + REFIID riid, + LPVOID *ppvObj) +{ + if (ppvObj == NULL) return E_POINTER; + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IClassFactory)) + { + *ppvObj = iface; + IClassFactory_AddRef(iface); + return S_OK; + } + + *ppvObj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap-based object */ +} + +static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap-based object */ +} + +static HRESULT WINAPI Test_IClassFactory_CreateInstance( + LPCLASSFACTORY iface, + LPUNKNOWN pUnkOuter, + REFIID riid, + LPVOID *ppvObj) +{ + TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface; + HRESULT hr; + IUnknown *punk = NULL; + + *ppvObj = NULL; + + if (pUnkOuter) return CLASS_E_NOAGGREGATION; + + hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk); + if (SUCCEEDED(hr)) { + hr = IUnknown_QueryInterface(punk, riid, ppvObj); + IUnknown_Release(punk); + } + return hr; +} + +static HRESULT WINAPI Test_IClassFactory_LockServer( + LPCLASSFACTORY iface, + BOOL fLock) +{ + return S_OK; +} + +static IClassFactoryVtbl TestClassFactory_Vtbl = +{ + Test_IClassFactory_QueryInterface, + Test_IClassFactory_AddRef, + Test_IClassFactory_Release, + Test_IClassFactory_CreateInstance, + Test_IClassFactory_LockServer +}; + +static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName) +{ + IPin *pin = NULL; + PIN_INFO pinInfo; + FILTER_INFO filterInfo; + HRESULT hr; + + FilterName[0] = 0; + + hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin); + ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr); + if (FAILED(hr)) return hr; + + hr = IPin_QueryPinInfo(pin, &pinInfo); + ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr); + IPin_Release(pin); + if (FAILED(hr)) return hr; + + SetLastError(0xdeadbeef); + hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo); + if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + IBaseFilter_Release(pinInfo.pFilter); + return E_NOTIMPL; + } + ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr); + IBaseFilter_Release(pinInfo.pFilter); + if (FAILED(hr)) return hr; + + IFilterGraph_Release(filterInfo.pGraph); + + WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL); + + return S_OK; +} + +static void test_render_filter_priority(void) +{ + /* Tests filter choice priorities in Render(). */ + DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0; + HRESULT hr; + IFilterGraph2* pgraph2 = NULL; + IFilterMapper2 *pMapper2 = NULL; + IBaseFilter* ptestfilter = NULL; + IBaseFilter* ptestfilter2 = NULL; + static const CLSID CLSID_TestFilter2 = { + 0x37a4edb0, + 0x4d13, + 0x11dd, + {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce} + }; + static const CLSID CLSID_TestFilter3 = { + 0x37a4f2d8, + 0x4d13, + 0x11dd, + {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce} + }; + static const CLSID CLSID_TestFilter4 = { + 0x37a4f3b4, + 0x4d13, + 0x11dd, + {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce} + }; + static const GUID mediasubtype1 = { + 0x37a4f51c, + 0x4d13, + 0x11dd, + {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce} + }; + static const GUID mediasubtype2 = { + 0x37a4f5c6, + 0x4d13, + 0x11dd, + {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce} + }; + static const TestFilterPinData PinData1[] = { + { PINDIR_OUTPUT, &mediasubtype1 }, + { 0, 0 } + }; + static const TestFilterPinData PinData2[] = { + { PINDIR_INPUT, &mediasubtype1 }, + { 0, 0 } + }; + static const TestFilterPinData PinData3[] = { + { PINDIR_INPUT, &GUID_NULL }, + { 0, 0 } + }; + static const TestFilterPinData PinData4[] = { + { PINDIR_INPUT, &mediasubtype1 }, + { PINDIR_OUTPUT, &mediasubtype2 }, + { 0, 0 } + }; + static const TestFilterPinData PinData5[] = { + { PINDIR_INPUT, &mediasubtype2 }, + { 0, 0 } + }; + TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 }; + TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 }; + TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 }; + char ConnectedFilterName1[MAX_FILTER_NAME]; + char ConnectedFilterName2[MAX_FILTER_NAME]; + REGFILTER2 rgf2; + REGFILTERPINS2 rgPins2[2]; + REGPINTYPES rgPinType[2]; + static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I', + 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 }; + static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I', + 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 }; + static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I', + 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 }; + static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I', + 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 }; + + /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is + "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating + no preference given to exact match. */ + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2); + ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); + if (!pgraph2) return; + + hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]); + ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr); + + hr = get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1); + + IFilterGraph2_Release(pgraph2); + pgraph2 = NULL; + IBaseFilter_Release(ptestfilter); + ptestfilter = NULL; + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + if (hr == E_NOTIMPL) + { + win_skip("Needed functions are not implemented\n"); + return; + } + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2); + ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); + if (!pgraph2) goto out; + + hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]); + ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr); + + hr = IFilterGraph2_Disconnect(pgraph2, NULL); + ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr); + + get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2); + ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2), + "expected connected filters to be different but got %s both times\n", ConnectedFilterName1); + + IFilterGraph2_Release(pgraph2); + pgraph2 = NULL; + IBaseFilter_Release(ptestfilter); + ptestfilter = NULL; + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + /* Test if any preference is given to existing renderer which renders the pin directly vs + an existing renderer which renders the pin indirectly, through an additional middle filter, + again trying different orders of creation. Native appears not to give a preference. */ + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2); + ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); + if (!pgraph2) goto out; + + hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]); + ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr); + + get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1); + ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"), + "unexpected connected filter: %s\n", ConnectedFilterName1); + + IFilterGraph2_Release(pgraph2); + pgraph2 = NULL; + IBaseFilter_Release(ptestfilter); + ptestfilter = NULL; + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2); + ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); + if (!pgraph2) goto out; + + hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]); + ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr); + + get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2); + ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"), + "unexpected connected filter: %s\n", ConnectedFilterName2); + ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2), + "expected connected filters to be different but got %s both times\n", ConnectedFilterName1); + + IFilterGraph2_Release(pgraph2); + pgraph2 = NULL; + IBaseFilter_Release(ptestfilter); + ptestfilter = NULL; + IBaseFilter_Release(ptestfilter2); + ptestfilter2 = NULL; + + /* Test if renderers are tried before non-renderers (intermediary filters). */ + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2); + ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); + if (!pgraph2) goto out; + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2); + ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); + if (!pMapper2) goto out; + + hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter); + ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1); + ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr); + + /* Register our filters with COM and with Filtermapper. */ + hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1); + ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr); + if (FAILED(hr)) goto out; + hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2); + ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr); + if (FAILED(hr)) goto out; + hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3); + ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr); + if (FAILED(hr)) goto out; + + rgf2.dwVersion = 2; + rgf2.dwMerit = MERIT_UNLIKELY; + S1(U(rgf2)).cPins2 = 1; + S1(U(rgf2)).rgPins2 = rgPins2; + rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER; + rgPins2[0].cInstances = 1; + rgPins2[0].nMediaTypes = 1; + rgPins2[0].lpMediaType = &rgPinType[0]; + rgPins2[0].nMediums = 0; + rgPins2[0].lpMedium = NULL; + rgPins2[0].clsPinCategory = NULL; + rgPinType[0].clsMajorType = &MEDIATYPE_Video; + rgPinType[0].clsMinorType = &mediasubtype1; + + hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL, + &CLSID_LegacyAmFilterCategory, NULL, &rgf2); + ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr); + + rgf2.dwMerit = MERIT_PREFERRED; + rgPinType[0].clsMinorType = &mediasubtype2; + + hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL, + &CLSID_LegacyAmFilterCategory, NULL, &rgf2); + ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr); + + S1(U(rgf2)).cPins2 = 2; + rgPins2[0].dwFlags = 0; + rgPinType[0].clsMinorType = &mediasubtype1; + + rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT; + rgPins2[1].cInstances = 1; + rgPins2[1].nMediaTypes = 1; + rgPins2[1].lpMediaType = &rgPinType[1]; + rgPins2[1].nMediums = 0; + rgPins2[1].lpMedium = NULL; + rgPins2[1].clsPinCategory = NULL; + rgPinType[1].clsMajorType = &MEDIATYPE_Video; + rgPinType[1].clsMinorType = &mediasubtype2; + + hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL, + &CLSID_LegacyAmFilterCategory, NULL, &rgf2); + ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr); + + hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]); + ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr); + + get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1); + ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"), + "unexpected connected filter: %s\n", ConnectedFilterName1); + + hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL, + &CLSID_TestFilter2); + ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr); + hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL, + &CLSID_TestFilter3); + ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr); + hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL, + &CLSID_TestFilter4); + ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr); + + out: + + if (ptestfilter) IBaseFilter_Release(ptestfilter); + if (ptestfilter2) IBaseFilter_Release(ptestfilter2); + if (pgraph2) IFilterGraph2_Release(pgraph2); + if (pMapper2) IFilterMapper2_Release(pMapper2); + + hr = CoRevokeClassObject(cookie1); + ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr); + hr = CoRevokeClassObject(cookie2); + ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr); + hr = CoRevokeClassObject(cookie3); + ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr); +} + +START_TEST(filtergraph) +{ + CoInitializeEx(NULL, COINIT_MULTITHREADED); + test_render_run(avifileA); + test_render_run(mpegfileA); + test_graph_builder(); + test_graph_builder_addfilter(); + test_mediacontrol(); + test_filter_graph2(); + test_render_filter_priority(); + CoUninitialize(); +} diff --git a/rostests/winetests/quartz/filtermapper.c b/rostests/winetests/quartz/filtermapper.c new file mode 100644 index 00000000000..4a8a3bb579b --- /dev/null +++ b/rostests/winetests/quartz/filtermapper.c @@ -0,0 +1,466 @@ +/* + * Filtermapper unit tests for Quartz + * + * Copyright (C) 2008 Alexander Dorofeyev + * + * 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 + */ + +#define COBJMACROS + +#include "wine/test.h" +#include "winbase.h" +#include "initguid.h" +#include "dshow.h" + +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + +/* Helper function, checks if filter with given name was enumerated. */ +static BOOL enum_find_filter(const WCHAR *wszFilterName, IEnumMoniker *pEnum) +{ + IMoniker *pMoniker = NULL; + BOOL found = FALSE; + ULONG nb; + HRESULT hr; + static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; + + while(!found && IEnumMoniker_Next(pEnum, 1, &pMoniker, &nb) == S_OK) + { + IPropertyBag * pPropBagCat = NULL; + VARIANT var; + + VariantInit(&var); + + hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat); + ok(SUCCEEDED(hr), "IMoniker_BindToStorage failed with %x\n", hr); + if (FAILED(hr) || !pPropBagCat) + { + VariantClear(&var); + IMoniker_Release(pMoniker); + continue; + } + + hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, &var, NULL); + ok(SUCCEEDED(hr), "IPropertyBag_Read failed with %x\n", hr); + + if (SUCCEEDED(hr)) + { + CHAR val1[512], val2[512]; + + WideCharToMultiByte(CP_ACP, 0, V_UNION(&var, bstrVal), -1, val1, sizeof(val1), 0, 0); + WideCharToMultiByte(CP_ACP, 0, wszFilterName, -1, val2, sizeof(val2), 0, 0); + if (!lstrcmpA(val1, val2)) found = TRUE; + } + + IPropertyBag_Release(pPropBagCat); + IMoniker_Release(pMoniker); + VariantClear(&var); + } + + return found; +} + +static void test_fm2_enummatchingfilters(void) +{ + IFilterMapper2 *pMapper = NULL; + HRESULT hr; + REGFILTER2 rgf2; + REGFILTERPINS2 rgPins2[2]; + REGPINTYPES rgPinType; + static const WCHAR wszFilterName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', '1', 0 }; + static const WCHAR wszFilterName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', '2', 0 }; + CLSID clsidFilter1; + CLSID clsidFilter2; + IEnumMoniker *pEnum = NULL; + BOOL found; + + ZeroMemory(&rgf2, sizeof(rgf2)); + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterMapper2, (LPVOID*)&pMapper); + ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); + if (FAILED(hr)) goto out; + + hr = CoCreateGuid(&clsidFilter1); + ok(hr == S_OK, "CoCreateGuid failed with %x\n", hr); + hr = CoCreateGuid(&clsidFilter2); + ok(hr == S_OK, "CoCreateGuid failed with %x\n", hr); + + /* Test that a test renderer filter is returned when enumerating filters with bRender=FALSE */ + rgf2.dwVersion = 2; + rgf2.dwMerit = MERIT_UNLIKELY; + S1(U(rgf2)).cPins2 = 1; + S1(U(rgf2)).rgPins2 = rgPins2; + + rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER; + rgPins2[0].cInstances = 1; + rgPins2[0].nMediaTypes = 1; + rgPins2[0].lpMediaType = &rgPinType; + rgPins2[0].nMediums = 0; + rgPins2[0].lpMedium = NULL; + rgPins2[0].clsPinCategory = NULL; + + rgPinType.clsMajorType = &GUID_NULL; + rgPinType.clsMinorType = &GUID_NULL; + + hr = IFilterMapper2_RegisterFilter(pMapper, &clsidFilter1, wszFilterName1, NULL, + &CLSID_LegacyAmFilterCategory, NULL, &rgf2); + ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr); + + rgPins2[0].dwFlags = 0; + + rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT; + rgPins2[1].cInstances = 1; + rgPins2[1].nMediaTypes = 1; + rgPins2[1].lpMediaType = &rgPinType; + rgPins2[1].nMediums = 0; + rgPins2[1].lpMedium = NULL; + rgPins2[1].clsPinCategory = NULL; + + S1(U(rgf2)).cPins2 = 2; + + hr = IFilterMapper2_RegisterFilter(pMapper, &clsidFilter2, wszFilterName2, NULL, + &CLSID_LegacyAmFilterCategory, NULL, &rgf2); + ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr); + + hr = IFilterMapper2_EnumMatchingFilters(pMapper, &pEnum, 0, TRUE, MERIT_UNLIKELY, TRUE, + 0, NULL, NULL, &GUID_NULL, FALSE, FALSE, 0, NULL, NULL, &GUID_NULL); + ok(hr == S_OK, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr); + if (SUCCEEDED(hr) && pEnum) + { + found = enum_find_filter(wszFilterName1, pEnum); + ok(found, "EnumMatchingFilters failed to return the test filter 1\n"); + } + + if (pEnum) IEnumMoniker_Release(pEnum); + pEnum = NULL; + + hr = IFilterMapper2_EnumMatchingFilters(pMapper, &pEnum, 0, TRUE, MERIT_UNLIKELY, TRUE, + 0, NULL, NULL, &GUID_NULL, FALSE, FALSE, 0, NULL, NULL, &GUID_NULL); + ok(hr == S_OK, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr); + if (SUCCEEDED(hr) && pEnum) + { + found = enum_find_filter(wszFilterName2, pEnum); + ok(found, "EnumMatchingFilters failed to return the test filter 2\n"); + } + + if (pEnum) IEnumMoniker_Release(pEnum); + pEnum = NULL; + + /* Non renderer must not be returned with bRender=TRUE */ + + hr = IFilterMapper2_EnumMatchingFilters(pMapper, &pEnum, 0, TRUE, MERIT_UNLIKELY, TRUE, + 0, NULL, NULL, &GUID_NULL, TRUE, FALSE, 0, NULL, NULL, &GUID_NULL); + ok(hr == S_OK, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr); + + if (SUCCEEDED(hr) && pEnum) + { + found = enum_find_filter(wszFilterName1, pEnum); + ok(found, "EnumMatchingFilters failed to return the test filter 1\n"); + } + + if (pEnum) IEnumMoniker_Release(pEnum); + pEnum = NULL; + + hr = IFilterMapper2_EnumMatchingFilters(pMapper, &pEnum, 0, TRUE, MERIT_UNLIKELY, TRUE, + 0, NULL, NULL, &GUID_NULL, TRUE, FALSE, 0, NULL, NULL, &GUID_NULL); + ok(hr == S_OK, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr); + + if (SUCCEEDED(hr) && pEnum) + { + found = enum_find_filter(wszFilterName2, pEnum); + ok(!found, "EnumMatchingFilters should not return the test filter 2\n"); + } + + hr = IFilterMapper2_UnregisterFilter(pMapper, &CLSID_LegacyAmFilterCategory, NULL, + &clsidFilter1); + ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr); + + hr = IFilterMapper2_UnregisterFilter(pMapper, &CLSID_LegacyAmFilterCategory, NULL, + &clsidFilter2); + ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr); + + out: + + if (pEnum) IEnumMoniker_Release(pEnum); + if (pMapper) IFilterMapper2_Release(pMapper); +} + +static void test_legacy_filter_registration(void) +{ + IFilterMapper2 *pMapper2 = NULL; + IFilterMapper *pMapper = NULL; + HRESULT hr; + static const WCHAR wszFilterName[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 0 }; + static const CHAR szFilterName[] = "Testfilter"; + static const WCHAR wszPinName[] = {'P', 'i', 'n', '1', 0 }; + CLSID clsidFilter; + CHAR szRegKey[MAX_PATH]; + static const CHAR szClsid[] = "CLSID"; + WCHAR wszGuidstring[MAX_PATH]; + CHAR szGuidstring[MAX_PATH]; + LONG lRet; + HKEY hKey = NULL; + IEnumMoniker *pEnum = NULL; + BOOL found; + IEnumRegFilters *pRegEnum = NULL; + + /* Test if legacy filter registration scheme works (filter is added to HKCR\Filter). IFilterMapper_RegisterFilter + * registers in this way. Filters so registered must then be accessible through both IFilterMapper_EnumMatchingFilters + * and IFilterMapper2_EnumMatchingFilters. */ + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterMapper2, (LPVOID*)&pMapper2); + ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); + if (FAILED(hr)) goto out; + + hr = IFilterMapper2_QueryInterface(pMapper2, &IID_IFilterMapper, (LPVOID)&pMapper); + ok(hr == S_OK, "IFilterMapper2_QueryInterface failed with %x\n", hr); + if (FAILED(hr)) goto out; + + /* Register a test filter. */ + hr = CoCreateGuid(&clsidFilter); + ok(hr == S_OK, "CoCreateGuid failed with %x\n", hr); + + lRet = StringFromGUID2(&clsidFilter, wszGuidstring, MAX_PATH); + ok(lRet > 0, "StringFromGUID2 failed\n"); + if (!lRet) goto out; + WideCharToMultiByte(CP_ACP, 0, wszGuidstring, -1, szGuidstring, MAX_PATH, 0, 0); + + lstrcpyA(szRegKey, szClsid); + lstrcatA(szRegKey, "\\"); + lstrcatA(szRegKey, szGuidstring); + + /* Register---- functions need a filter class key to write pin and pin media type data to. Create a bogus + * class key for it. */ + lRet = RegCreateKeyExA(HKEY_CLASSES_ROOT, szRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL); + ok(lRet == ERROR_SUCCESS, "RegCreateKeyExA failed with %x\n", HRESULT_FROM_WIN32(lRet)); + + /* Set default value - this is interpreted as "friendly name" later. */ + lRet = RegSetValueExA(hKey, NULL, 0, REG_SZ, (LPBYTE)szFilterName, lstrlenA(szFilterName) + 1); + ok(lRet == ERROR_SUCCESS, "RegSetValueExA failed with %x\n", HRESULT_FROM_WIN32(lRet)); + + if (hKey) RegCloseKey(hKey); + hKey = NULL; + + hr = IFilterMapper_RegisterFilter(pMapper, clsidFilter, wszFilterName, MERIT_UNLIKELY); + ok(hr == S_OK, "IFilterMapper_RegisterFilter failed with %x\n", hr); + + hr = IFilterMapper_RegisterPin(pMapper, clsidFilter, wszPinName, TRUE, FALSE, FALSE, FALSE, GUID_NULL, NULL); + ok(hr == S_OK, "IFilterMapper_RegisterPin failed with %x\n", hr); + + hr = IFilterMapper_RegisterPinType(pMapper, clsidFilter, wszPinName, GUID_NULL, GUID_NULL); + ok(hr == S_OK, "IFilterMapper_RegisterPinType failed with %x\n", hr); + + hr = IFilterMapper2_EnumMatchingFilters(pMapper2, &pEnum, 0, TRUE, MERIT_UNLIKELY, TRUE, + 0, NULL, NULL, &GUID_NULL, FALSE, FALSE, 0, NULL, NULL, &GUID_NULL); + ok(hr == S_OK, "IFilterMapper2_EnumMatchingFilters failed with %x\n", hr); + if (SUCCEEDED(hr) && pEnum) + { + found = enum_find_filter(wszFilterName, pEnum); + ok(found, "IFilterMapper2_EnumMatchingFilters failed to return the test filter\n"); + } + + if (pEnum) IEnumMoniker_Release(pEnum); + pEnum = NULL; + + found = FALSE; + hr = IFilterMapper_EnumMatchingFilters(pMapper, &pRegEnum, MERIT_UNLIKELY, TRUE, GUID_NULL, GUID_NULL, + FALSE, FALSE, GUID_NULL, GUID_NULL); + ok(hr == S_OK, "IFilterMapper_EnumMatchingFilters failed with %x\n", hr); + if (SUCCEEDED(hr) && pRegEnum) + { + ULONG cFetched; + REGFILTER *prgf; + + while(!found && IEnumRegFilters_Next(pRegEnum, 1, &prgf, &cFetched) == S_OK) + { + CHAR val[512]; + + WideCharToMultiByte(CP_ACP, 0, prgf->Name, -1, val, sizeof(val), 0, 0); + if (!lstrcmpA(val, szFilterName)) found = TRUE; + + CoTaskMemFree(prgf); + } + + IEnumRegFilters_Release(pRegEnum); + } + ok(found, "IFilterMapper_EnumMatchingFilters failed to return the test filter\n"); + + hr = IFilterMapper_UnregisterFilter(pMapper, clsidFilter); + ok(hr == S_OK, "FilterMapper_UnregisterFilter failed with %x\n", hr); + + lRet = RegOpenKeyExA(HKEY_CLASSES_ROOT, szClsid, 0, KEY_WRITE | DELETE, &hKey); + ok(lRet == ERROR_SUCCESS, "RegOpenKeyExA failed with %x\n", HRESULT_FROM_WIN32(lRet)); + + lRet = RegDeleteKeyA(hKey, szGuidstring); + ok(lRet == ERROR_SUCCESS, "RegDeleteKeyA failed with %x\n", HRESULT_FROM_WIN32(lRet)); + + if (hKey) RegCloseKey(hKey); + hKey = NULL; + + out: + + if (pMapper) IFilterMapper_Release(pMapper); + if (pMapper2) IFilterMapper2_Release(pMapper2); +} + +static ULONG getRefcount(IUnknown *iface) +{ + IUnknown_AddRef(iface); + return IUnknown_Release(iface); +} + +static void test_ifiltermapper_from_filtergraph(void) +{ + IFilterGraph2* pgraph2 = NULL; + IFilterMapper2 *pMapper2 = NULL; + IFilterGraph *filtergraph = NULL; + HRESULT hr; + ULONG refcount; + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2); + ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); + if (!pgraph2) goto out; + + hr = IFilterGraph2_QueryInterface(pgraph2, &IID_IFilterMapper2, (LPVOID*)&pMapper2); + ok(hr == S_OK, "IFilterGraph2_QueryInterface failed with %08x\n", hr); + if (!pMapper2) goto out; + + refcount = getRefcount((IUnknown*)pgraph2); + ok(refcount == 2, "unexpected reference count: %u\n", refcount); + refcount = getRefcount((IUnknown*)pMapper2); + ok(refcount == 2, "unexpected reference count: %u\n", refcount); + + IFilterMapper2_AddRef(pMapper2); + refcount = getRefcount((IUnknown*)pgraph2); + ok(refcount == 3, "unexpected reference count: %u\n", refcount); + refcount = getRefcount((IUnknown*)pMapper2); + ok(refcount == 3, "unexpected reference count: %u\n", refcount); + IFilterMapper2_Release(pMapper2); + + hr = IFilterMapper2_QueryInterface(pMapper2, &IID_IFilterGraph, (LPVOID*)&filtergraph); + ok(hr == S_OK, "IFilterMapper2_QueryInterface failed with %08x\n", hr); + if (!filtergraph) goto out; + + IFilterMapper2_Release(pMapper2); + pMapper2 = NULL; + IFilterGraph_Release(filtergraph); + filtergraph = NULL; + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2); + ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr); + if (!pMapper2) goto out; + + hr = IFilterMapper2_QueryInterface(pMapper2, &IID_IFilterGraph, (LPVOID*)&filtergraph); + ok(hr == E_NOINTERFACE, "IFilterMapper2_QueryInterface unexpected result: %08x\n", hr); + + out: + + if (pMapper2) IFilterMapper2_Release(pMapper2); + if (filtergraph) IFilterGraph_Release(filtergraph); + if (pgraph2) IFilterGraph2_Release(pgraph2); +} + +static void test_register_filter_with_null_clsMinorType(void) +{ + IFilterMapper2 *pMapper = NULL; + HRESULT hr; + REGFILTER2 rgf2; + REGFILTERPINS rgPins; + REGFILTERPINS2 rgPins2; + REGPINTYPES rgPinType; + static WCHAR wszPinName[] = {'P', 'i', 'n', 0 }; + static const WCHAR wszFilterName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', '1', 0 }; + static const WCHAR wszFilterName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', '2', 0 }; + CLSID clsidFilter1; + CLSID clsidFilter2; + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterMapper2, (LPVOID*)&pMapper); + ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); + if (FAILED(hr)) goto out; + + hr = CoCreateGuid(&clsidFilter1); + ok(hr == S_OK, "CoCreateGuid failed with %x\n", hr); + hr = CoCreateGuid(&clsidFilter2); + ok(hr == S_OK, "CoCreateGuid failed with %x\n", hr); + + rgPinType.clsMajorType = &GUID_NULL; + /* Make sure quartz accepts it without crashing */ + rgPinType.clsMinorType = NULL; + + /* Test with pin descript version 1 */ + ZeroMemory(&rgf2, sizeof(rgf2)); + rgf2.dwVersion = 1; + rgf2.dwMerit = MERIT_UNLIKELY; + S(U(rgf2)).cPins = 1; + S(U(rgf2)).rgPins = &rgPins; + + rgPins.strName = wszPinName; + rgPins.bRendered = 1; + rgPins.bOutput = 0; + rgPins.bZero = 0; + rgPins.bMany = 0; + rgPins.clsConnectsToFilter = NULL; + rgPins.strConnectsToPin = NULL; + rgPins.nMediaTypes = 1; + rgPins.lpMediaType = &rgPinType; + + hr = IFilterMapper2_RegisterFilter(pMapper, &clsidFilter1, wszFilterName1, NULL, + &CLSID_LegacyAmFilterCategory, NULL, &rgf2); + ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr); + + hr = IFilterMapper2_UnregisterFilter(pMapper, &CLSID_LegacyAmFilterCategory, NULL, &clsidFilter1); + ok(hr == S_OK, "FilterMapper_UnregisterFilter failed with %x\n", hr); + + /* Test with pin descript version 2 */ + ZeroMemory(&rgf2, sizeof(rgf2)); + rgf2.dwVersion = 2; + rgf2.dwMerit = MERIT_UNLIKELY; + S1(U(rgf2)).cPins2 = 1; + S1(U(rgf2)).rgPins2 = &rgPins2; + + rgPins2.dwFlags = REG_PINFLAG_B_RENDERER; + rgPins2.cInstances = 1; + rgPins2.nMediaTypes = 1; + rgPins2.lpMediaType = &rgPinType; + rgPins2.nMediums = 0; + rgPins2.lpMedium = NULL; + rgPins2.clsPinCategory = NULL; + + hr = IFilterMapper2_RegisterFilter(pMapper, &clsidFilter2, wszFilterName2, NULL, + &CLSID_LegacyAmFilterCategory, NULL, &rgf2); + ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr); + + hr = IFilterMapper2_UnregisterFilter(pMapper, &CLSID_LegacyAmFilterCategory, NULL, &clsidFilter2); + ok(hr == S_OK, "FilterMapper_UnregisterFilter failed with %x\n", hr); + + out: + + if (pMapper) IFilterMapper2_Release(pMapper); +} + + +START_TEST(filtermapper) +{ + CoInitialize(NULL); + + test_fm2_enummatchingfilters(); + test_legacy_filter_registration(); + test_ifiltermapper_from_filtergraph(); + test_register_filter_with_null_clsMinorType(); + + CoUninitialize(); +} diff --git a/rostests/winetests/quartz/memallocator.c b/rostests/winetests/quartz/memallocator.c new file mode 100644 index 00000000000..c5313f74dd4 --- /dev/null +++ b/rostests/winetests/quartz/memallocator.c @@ -0,0 +1,92 @@ +/* + * Unit tests for Direct Show functions + * + * Copyright (C) 2005 Christian Costa + * + * 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 + */ + +#include + +#define COBJMACROS + +#include "wine/test.h" +#include "uuids.h" +#include "dshow.h" +#include "control.h" + +static void CommitDecommitTest(void) +{ + IMemAllocator* pMemAllocator; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAllocator); + ok(hr==S_OK, "Unable to create memory allocator %x\n", hr); + + if (hr == S_OK) + { + ALLOCATOR_PROPERTIES RequestedProps; + ALLOCATOR_PROPERTIES ActualProps; + + IMediaSample *sample = NULL, *sample2 = NULL; + + RequestedProps.cBuffers = 2; + RequestedProps.cbBuffer = 65536; + RequestedProps.cbAlign = 1; + RequestedProps.cbPrefix = 0; + + hr = IMemAllocator_SetProperties(pMemAllocator, &RequestedProps, &ActualProps); + ok(hr==S_OK, "SetProperties returned: %x\n", hr); + + hr = IMemAllocator_Commit(pMemAllocator); + ok(hr==S_OK, "Commit returned: %x\n", hr); + hr = IMemAllocator_Commit(pMemAllocator); + ok(hr==S_OK, "Commit returned: %x\n", hr); + + hr = IMemAllocator_GetBuffer(pMemAllocator, &sample, NULL, NULL, 0); + ok(hr==S_OK, "Could not get a buffer: %x\n", hr); + + hr = IMemAllocator_Decommit(pMemAllocator); + ok(hr==S_OK, "Decommit returned: %x\n", hr); + hr = IMemAllocator_Decommit(pMemAllocator); + ok(hr==S_OK, "Cecommit returned: %x\n", hr); + + /* Decommit and recommit while holding a sample */ + if (sample) + { + hr = IMemAllocator_Commit(pMemAllocator); + ok(hr==S_OK, "Commit returned: %x\n", hr); + + hr = IMemAllocator_GetBuffer(pMemAllocator, &sample2, NULL, NULL, 0); + ok(hr==S_OK, "Could not get a buffer: %x\n", hr); + IUnknown_Release(sample); + if (sample2) + IUnknown_Release(sample2); + + hr = IMemAllocator_Decommit(pMemAllocator); + ok(hr==S_OK, "Cecommit returned: %x\n", hr); + } + IMemAllocator_Release(pMemAllocator); + } +} + +START_TEST(memallocator) +{ + CoInitialize(NULL); + + CommitDecommitTest(); + + CoUninitialize(); +} diff --git a/rostests/winetests/quartz/misc.c b/rostests/winetests/quartz/misc.c new file mode 100644 index 00000000000..74c386b6670 --- /dev/null +++ b/rostests/winetests/quartz/misc.c @@ -0,0 +1,214 @@ +/* + * Misc unit tests for Quartz + * + * Copyright (C) 2007 Google (Lei Zhang) + * + * 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 + */ + +#define COBJMACROS + +#include "wine/test.h" +#include "dshow.h" + +#define QI_SUCCEED(iface, riid, ppv) hr = IUnknown_QueryInterface(iface, &riid, (LPVOID*)&ppv); \ + ok(hr == S_OK, "IUnknown_QueryInterface returned %x\n", hr); \ + ok(ppv != NULL, "Pointer is NULL\n"); + +#define QI_FAIL(iface, riid, ppv) hr = IUnknown_QueryInterface(iface, &riid, (LPVOID*)&ppv); \ + ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface returned %x\n", hr); \ + ok(ppv == NULL, "Pointer is %p\n", ppv); + +#define ADDREF_EXPECT(iface, num) if (iface) { \ + refCount = IUnknown_AddRef(iface); \ + ok(refCount == num, "IUnknown_AddRef should return %d, got %d\n", num, refCount); \ +} + +#define RELEASE_EXPECT(iface, num) if (iface) { \ + refCount = IUnknown_Release(iface); \ + ok(refCount == num, "IUnknown_Release should return %d, got %d\n", num, refCount); \ +} + +static void test_aggregation(const CLSID clsidOuter, const CLSID clsidInner, + const IID iidOuter, const IID iidInner) +{ + HRESULT hr; + ULONG refCount; + IUnknown *pUnkOuter = NULL; + IUnknown *pUnkInner = NULL; + IUnknown *pUnkInnerFail = NULL; + IUnknown *pUnkOuterTest = NULL; + IUnknown *pUnkInnerTest = NULL; + IUnknown *pUnkAggregatee = NULL; + IUnknown *pUnkAggregator = NULL; + IUnknown *pUnkTest = NULL; + + hr = CoCreateInstance(&clsidOuter, NULL, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (LPVOID*)&pUnkOuter); + ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr); + ok(pUnkOuter != NULL, "pUnkOuter is NULL\n"); + + if (!pUnkOuter) + { + skip("pUnkOuter is NULL\n"); + return; + } + + /* for aggregation, we should only be able to request IUnknown */ + hr = CoCreateInstance(&clsidInner, pUnkOuter, CLSCTX_INPROC_SERVER, + &iidInner, (LPVOID*)&pUnkInnerFail); + ok(hr == E_NOINTERFACE, "CoCreateInstance returned %x\n", hr); + ok(pUnkInnerFail == NULL, "pUnkInnerFail is not NULL\n"); + + /* aggregation, request IUnknown */ + hr = CoCreateInstance(&clsidInner, pUnkOuter, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (LPVOID*)&pUnkInner); + ok(hr == S_OK, "CoCreateInstance returned %x\n", hr); + ok(pUnkInner != NULL, "pUnkInner is NULL\n"); + + if (!pUnkInner) + { + skip("pUnkInner is NULL\n"); + return; + } + + ADDREF_EXPECT(pUnkOuter, 2); + ADDREF_EXPECT(pUnkInner, 2); + RELEASE_EXPECT(pUnkOuter, 1); + RELEASE_EXPECT(pUnkInner, 1); + + QI_FAIL(pUnkOuter, iidInner, pUnkAggregatee); + QI_FAIL(pUnkInner, iidOuter, pUnkAggregator); + + /* these QueryInterface calls should work */ + QI_SUCCEED(pUnkOuter, iidOuter, pUnkAggregator); + QI_SUCCEED(pUnkOuter, IID_IUnknown, pUnkOuterTest); + /* IGraphConfig interface comes with DirectShow 9 */ + if(IsEqualGUID(&IID_IGraphConfig, &iidInner)) + { + hr = IUnknown_QueryInterface(pUnkInner, &iidInner, (LPVOID*)&pUnkAggregatee); + ok(hr == S_OK || broken(hr == E_NOINTERFACE), "IUnknown_QueryInterface returned %x\n", hr); + ok(pUnkAggregatee != NULL || broken(!pUnkAggregatee), "Pointer is NULL\n"); + } + else + { + QI_SUCCEED(pUnkInner, iidInner, pUnkAggregatee); + } + QI_SUCCEED(pUnkInner, IID_IUnknown, pUnkInnerTest); + + if (!pUnkAggregator || !pUnkOuterTest || !pUnkAggregatee + || !pUnkInnerTest) + { + skip("One of the required interfaces is NULL\n"); + return; + } + + ADDREF_EXPECT(pUnkAggregator, 5); + ADDREF_EXPECT(pUnkOuterTest, 6); + ADDREF_EXPECT(pUnkAggregatee, 7); + ADDREF_EXPECT(pUnkInnerTest, 3); + RELEASE_EXPECT(pUnkAggregator, 6); + RELEASE_EXPECT(pUnkOuterTest, 5); + RELEASE_EXPECT(pUnkAggregatee, 4); + RELEASE_EXPECT(pUnkInnerTest, 2); + + QI_SUCCEED(pUnkAggregator, IID_IUnknown, pUnkTest); + QI_SUCCEED(pUnkOuterTest, IID_IUnknown, pUnkTest); + QI_SUCCEED(pUnkAggregatee, IID_IUnknown, pUnkTest); + QI_SUCCEED(pUnkInnerTest, IID_IUnknown, pUnkTest); + + QI_FAIL(pUnkAggregator, iidInner, pUnkTest); + QI_FAIL(pUnkOuterTest, iidInner, pUnkTest); + QI_FAIL(pUnkAggregatee, iidInner, pUnkTest); + QI_SUCCEED(pUnkInnerTest, iidInner, pUnkTest); + + QI_SUCCEED(pUnkAggregator, iidOuter, pUnkTest); + QI_SUCCEED(pUnkOuterTest, iidOuter, pUnkTest); + QI_SUCCEED(pUnkAggregatee, iidOuter, pUnkTest); + QI_FAIL(pUnkInnerTest, iidOuter, pUnkTest); + + RELEASE_EXPECT(pUnkAggregator, 10); + RELEASE_EXPECT(pUnkOuterTest, 9); + RELEASE_EXPECT(pUnkAggregatee, 8); + RELEASE_EXPECT(pUnkInnerTest, 2); + RELEASE_EXPECT(pUnkOuter, 7); + RELEASE_EXPECT(pUnkInner, 1); + + do + { + refCount = IUnknown_Release(pUnkInner); + } while (refCount); + + do + { + refCount = IUnknown_Release(pUnkOuter); + } while (refCount); +} + +static void test_video_renderer_aggregations(void) +{ + const IID * iids[] = { + &IID_IMediaFilter, &IID_IBaseFilter, &IID_IBasicVideo, &IID_IVideoWindow + }; + int i; + + for (i = 0; i < sizeof(iids) / sizeof(iids[0]); i++) + { + test_aggregation(CLSID_SystemClock, CLSID_VideoRenderer, + IID_IReferenceClock, *iids[i]); + } +} + +static void test_filter_graph_aggregations(void) +{ + const IID * iids[] = { + &IID_IFilterGraph2, &IID_IMediaControl, &IID_IGraphBuilder, + &IID_IFilterGraph, &IID_IMediaSeeking, &IID_IBasicAudio, &IID_IBasicVideo, + &IID_IVideoWindow, &IID_IMediaEventEx, &IID_IMediaFilter, + &IID_IMediaEventSink, &IID_IGraphConfig, &IID_IMediaPosition + }; + int i; + + for (i = 0; i < sizeof(iids) / sizeof(iids[0]); i++) + { + test_aggregation(CLSID_SystemClock, CLSID_FilterGraph, + IID_IReferenceClock, *iids[i]); + } +} + +static void test_filter_mapper_aggregations(void) +{ + const IID * iids[] = { + &IID_IFilterMapper2, &IID_IFilterMapper + }; + int i; + + for (i = 0; i < sizeof(iids) / sizeof(iids[0]); i++) + { + test_aggregation(CLSID_SystemClock, CLSID_FilterMapper2, + IID_IReferenceClock, *iids[i]); + } +} + +START_TEST(misc) +{ + CoInitialize(NULL); + + test_video_renderer_aggregations(); + test_filter_graph_aggregations(); + test_filter_mapper_aggregations(); + + CoUninitialize(); +} diff --git a/rostests/winetests/quartz/quartz.rbuild b/rostests/winetests/quartz/quartz.rbuild new file mode 100644 index 00000000000..4e6ab816799 --- /dev/null +++ b/rostests/winetests/quartz/quartz.rbuild @@ -0,0 +1,17 @@ + + . + + avisplitter.c + filtergraph.c + filtermapper.c + memallocator.c + misc.c + referenceclock.c + videorenderer.c + testlist.c + wine + oleaut32 + ole32 + advapi32 + ntdll + diff --git a/rostests/winetests/quartz/referenceclock.c b/rostests/winetests/quartz/referenceclock.c new file mode 100644 index 00000000000..164fc3d89f8 --- /dev/null +++ b/rostests/winetests/quartz/referenceclock.c @@ -0,0 +1,115 @@ +/* + * Unit tests for Direct Show functions - IReferenceClock + * + * Copyright (C) 2007 Alex Villacís Lasso + * + * 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 + */ + +#include + +#define COBJMACROS + +#include "wine/test.h" +#include "uuids.h" +#include "dshow.h" +#include "control.h" + +static void test_IReferenceClock_query_interface(const char * clockdesc, IReferenceClock * pClock) +{ + HRESULT hr; + IUnknown *pF; + + hr = IReferenceClock_QueryInterface(pClock, &IID_IUnknown, (LPVOID *)&pF); + ok(hr == S_OK, "IReferenceClock_QueryInterface returned %x\n", hr); + ok(pF != NULL, "pF is NULL\n"); + + hr = IReferenceClock_QueryInterface(pClock, &IID_IDirectDraw, (LPVOID *)&pF); + ok(hr == E_NOINTERFACE, "IReferenceClock_QueryInterface returned %x\n", hr); + ok(pF == NULL, "pF is not NULL\n"); + + hr = IReferenceClock_QueryInterface(pClock, &IID_IReferenceClock, (LPVOID *)&pF); + ok(hr == S_OK, "IReferenceClock_QueryInterface returned %x\n", hr); + ok(pF != NULL, "pF is NULL\n"); +} + +/* The following method expects a reference clock that will keep ticking for + * at least 5 seconds since its creation. This method assumes no other methods + * were called on the IReferenceClock interface since its creation. + */ +static void test_IReferenceClock_methods(const char * clockdesc, IReferenceClock * pClock) +{ + HRESULT hr; + REFERENCE_TIME time1; + REFERENCE_TIME time2; + signed long diff; + + /* Test response from invalid (NULL) argument */ + hr = IReferenceClock_GetTime(pClock, NULL); + ok (hr == E_POINTER, "%s - Expected E_POINTER (0x%08x), got 0x%08x\n", clockdesc, E_POINTER, hr); + + /* Test response for valid value - try 1 */ + /* TODO: test whether Windows actually returns S_FALSE in its first invocation */ + time1 = (REFERENCE_TIME)0xdeadbeef; + hr = IReferenceClock_GetTime(pClock, &time1); + ok (hr == S_FALSE || hr == S_OK, "%s - Expected S_OK or S_FALSE, got 0x%08x\n", clockdesc, hr); + ok (time1 != 0xdeadbeef, "%s - value was NOT changed on return!\n", clockdesc); + + /* Test response for valid value - try 2 */ + time2 = (REFERENCE_TIME)0xdeadbeef; + hr = IReferenceClock_GetTime(pClock, &time2); + ok (hr == S_FALSE || hr == S_OK, "%s - Expected S_OK or S_FALSE, got 0x%08x\n", clockdesc, hr); + ok (time2 != 0xdeadbeef, "%s - value was NOT changed on return!\n", clockdesc); + + /* In case the second invocation managed to return S_FALSE, MSDN says the + returned time is the same as the previous one. */ + ok ((hr != S_FALSE || time1 == time2), "%s - returned S_FALSE, but values not equal!\n", clockdesc); + + time1 = time2; + Sleep(1000); /* Sleep for at least 1 second */ + hr = IReferenceClock_GetTime(pClock, &time2); + /* After a 1-second sleep, there is no excuse to get S_FALSE (see TODO above) */ + ok (hr == S_OK, "%s - Expected S_OK, got 0x%08x\n", clockdesc, hr); + + /* FIXME: How much deviation should be allowed after a sleep? */ + /* 0.3% is common, and 0.4% is sometimes observed. */ + diff = time2 - time1; + ok (9940000 <= diff && diff <= 10240000, "%s - Expected difference around 10000000, got %lu\n", clockdesc, diff); + +} + +static void test_IReferenceClock_SystemClock(void) +{ + IReferenceClock * pReferenceClock; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pReferenceClock); + ok(hr == S_OK, "Unable to create reference clock from system clock %x\n", hr); + if (hr == S_OK) + { + test_IReferenceClock_query_interface("SystemClock", pReferenceClock); + test_IReferenceClock_methods("SystemClock", pReferenceClock); + IReferenceClock_Release(pReferenceClock); + } +} + +START_TEST(referenceclock) +{ + CoInitialize(NULL); + + test_IReferenceClock_SystemClock(); + + CoUninitialize(); +} diff --git a/rostests/winetests/quartz/testlist.c b/rostests/winetests/quartz/testlist.c new file mode 100644 index 00000000000..bc231d1c2cd --- /dev/null +++ b/rostests/winetests/quartz/testlist.c @@ -0,0 +1,27 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_avisplitter(void); +extern void func_videorenderer(void); +extern void func_referenceclock(void); +extern void func_misc(void); +extern void func_memallocator(void); +extern void func_filtermapper(void); +extern void func_filtergraph(void); + +const struct test winetest_testlist[] = +{ + { "avisplitter", func_avisplitter }, + { "videorenderer", func_videorenderer }, + { "referenceclock", func_referenceclock }, + { "misc", func_misc }, + { "memallocator", func_memallocator }, + { "filtermapper", func_filtermapper }, + { "filtergraph", func_filtergraph }, + { 0, 0 } +}; diff --git a/rostests/winetests/quartz/videorenderer.c b/rostests/winetests/quartz/videorenderer.c new file mode 100644 index 00000000000..967abd4ff96 --- /dev/null +++ b/rostests/winetests/quartz/videorenderer.c @@ -0,0 +1,165 @@ +/* + * Unit tests for Video Renderer functions + * + * Copyright (C) 2007 Google (Lei Zhang) + * + * 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 + */ + +#define COBJMACROS + +#include "wine/test.h" +#include "dshow.h" + +#define QI_SUCCEED(iface, riid, ppv) hr = IUnknown_QueryInterface(iface, &riid, (LPVOID*)&ppv); \ + ok(hr == S_OK, "IUnknown_QueryInterface returned %x\n", hr); \ + ok(ppv != NULL, "Pointer is NULL\n"); + +#define RELEASE_EXPECT(iface, num) if (iface) { \ + hr = IUnknown_Release(iface); \ + ok(hr == num, "IUnknown_Release should return %d, got %d\n", num, hr); \ +} + +static IUnknown *pVideoRenderer = NULL; + +static int create_video_renderer(void) +{ + HRESULT hr; + + hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (LPVOID*)&pVideoRenderer); + return (hr == S_OK && pVideoRenderer != NULL); +} + +static void release_video_renderer(void) +{ + HRESULT hr; + + hr = IUnknown_Release(pVideoRenderer); + ok(hr == 0, "IUnknown_Release failed with %x\n", hr); +} + +static void test_query_interface(void) +{ + HRESULT hr; + IBaseFilter *pBaseFilter = NULL; + IBasicVideo *pBasicVideo = NULL; + IDirectDrawVideo *pDirectDrawVideo = NULL; + IKsPropertySet *pKsPropertySet = NULL; + IMediaPosition *pMediaPosition = NULL; + IMediaSeeking *pMediaSeeking = NULL; + IQualityControl *pQualityControl = NULL; + IQualProp *pQualProp = NULL; + IVideoWindow *pVideoWindow = NULL; + + QI_SUCCEED(pVideoRenderer, IID_IBaseFilter, pBaseFilter); + RELEASE_EXPECT(pBaseFilter, 1); + QI_SUCCEED(pVideoRenderer, IID_IBasicVideo, pBasicVideo); + RELEASE_EXPECT(pBasicVideo, 1); + QI_SUCCEED(pVideoRenderer, IID_IMediaSeeking, pMediaSeeking); + RELEASE_EXPECT(pMediaSeeking, 1); + todo_wine { + QI_SUCCEED(pVideoRenderer, IID_IDirectDrawVideo, pDirectDrawVideo); + RELEASE_EXPECT(pDirectDrawVideo, 1); + QI_SUCCEED(pVideoRenderer, IID_IKsPropertySet, pKsPropertySet); + RELEASE_EXPECT(pKsPropertySet, 1); + QI_SUCCEED(pVideoRenderer, IID_IMediaPosition, pMediaPosition); + RELEASE_EXPECT(pMediaPosition, 1); + QI_SUCCEED(pVideoRenderer, IID_IQualityControl, pQualityControl); + RELEASE_EXPECT(pQualityControl, 1); + QI_SUCCEED(pVideoRenderer, IID_IQualProp, pQualProp); + RELEASE_EXPECT(pQualProp, 1); + } + QI_SUCCEED(pVideoRenderer, IID_IVideoWindow, pVideoWindow); + RELEASE_EXPECT(pVideoWindow, 1); +} + +static void test_pin(IPin *pin) +{ + IMemInputPin *mpin = NULL; + + IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&mpin); + + ok(mpin != NULL, "No IMemInputPin found!\n"); + if (mpin) + { + ok(IMemInputPin_ReceiveCanBlock(mpin) == S_OK, "Receive can't block for pin!\n"); + ok(IMemInputPin_NotifyAllocator(mpin, NULL, 0) == E_POINTER, "NotifyAllocator likes a NULL pointer argument\n"); + IMemInputPin_Release(mpin); + } + /* TODO */ +} + +static void test_basefilter(void) +{ + IEnumPins *pin_enum = NULL; + IBaseFilter *base = NULL; + IPin *pins[2]; + ULONG ref; + HRESULT hr; + + IUnknown_QueryInterface(pVideoRenderer, &IID_IBaseFilter, (void *)&base); + if (base == NULL) + { + /* test_query_interface handles this case */ + skip("No IBaseFilter\n"); + return; + } + + hr = IBaseFilter_EnumPins(base, NULL); + ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr); + + hr= IBaseFilter_EnumPins(base, &pin_enum); + ok(hr == S_OK, "hr = %08x and not S_OK\n", hr); + + hr = IEnumPins_Next(pin_enum, 1, NULL, NULL); + ok(hr == E_POINTER, "hr = %08x and not E_POINTER\n", hr); + + hr = IEnumPins_Next(pin_enum, 2, pins, NULL); + ok(hr == E_INVALIDARG, "hr = %08x and not E_INVALIDARG\n", hr); + + pins[0] = (void *)0xdead; + pins[1] = (void *)0xdeed; + + hr = IEnumPins_Next(pin_enum, 2, pins, &ref); + ok(hr == S_FALSE, "hr = %08x instead of S_FALSE\n", hr); + ok(pins[0] != (void *)0xdead && pins[0] != NULL, "pins[0] = %p\n", pins[0]); + if (pins[0] != (void *)0xdead && pins[0] != NULL) + { + test_pin(pins[0]); + IPin_Release(pins[0]); + } + + ok(pins[1] == (void *)0xdeed, "pins[1] = %p\n", pins[1]); + + ref = IEnumPins_Release(pin_enum); + ok(ref == 0, "ref is %u and not 0!\n", ref); + + IBaseFilter_Release(base); +} + +START_TEST(videorenderer) +{ + CoInitialize(NULL); + if (!create_video_renderer()) + return; + + test_query_interface(); + test_basefilter(); + + release_video_renderer(); + + CoUninitialize(); +} diff --git a/rostests/winetests/rasapi32/rasapi.c b/rostests/winetests/rasapi32/rasapi.c new file mode 100644 index 00000000000..11fca0eb4ad --- /dev/null +++ b/rostests/winetests/rasapi32/rasapi.c @@ -0,0 +1,168 @@ +/* +* Unit test suite for rasapi32 functions +* +* Copyright 2008 Austin English +* +* 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 +*/ + +#include +#include +#include +#include +#include +#include "ras.h" +#include "raserror.h" + +static HMODULE hmodule; +static DWORD (WINAPI *pRasEnumDevicesA)(LPRASDEVINFOA, LPDWORD, LPDWORD); + +#define RASAPI32_GET_PROC(func) \ + p ## func = (void*)GetProcAddress(hmodule, #func); \ + if(!p ## func) \ + trace("GetProcAddress(%s) failed\n", #func); + +static void InitFunctionPtrs(void) +{ + hmodule = LoadLibraryA("rasapi32.dll"); + + RASAPI32_GET_PROC(RasEnumDevicesA) +} + +static void test_rasenum(void) +{ + DWORD result; + DWORD cDevices = 0; + DWORD bufsize = 0, cb = 0; + LPRASDEVINFOA rasDevInfo; + + if(!pRasEnumDevicesA) { + win_skip("Skipping RasEnumDevicesA tests, function not present\n"); + return; + } + + /* create the return buffer */ + result = pRasEnumDevicesA(NULL, &bufsize, &cDevices); + if(ERROR_RASMAN_CANNOT_INITIALIZE == result) { + win_skip("RAS configuration problem\n"); + return; + } + if(ERROR_SUCCESS == result) { + win_skip("RasEnumDevicesA found nothing to enumerate\n"); + return; + } + trace("RasEnumDevicesA: returned %d buffersize %d\n", result, bufsize); + ok(result == ERROR_BUFFER_TOO_SMALL, + "Expected ERROR_BUFFER_TOO_SMALL, got %08d\n", result); + + rasDevInfo = (LPRASDEVINFO) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + max(bufsize,sizeof(RASDEVINFOA))); + if(!rasDevInfo) { + win_skip("failed to allocate buffer for RasEnumDevicesA tests\n"); + return; + } + + /* test first parameter */ + cb = bufsize; + result = pRasEnumDevicesA(NULL, &cb, &cDevices); + ok(result == ERROR_BUFFER_TOO_SMALL || + result == ERROR_INVALID_USER_BUFFER, /* win98 */ + "Expected ERROR_BUFFER_TOO_SMALL, got %08d\n", result); + + rasDevInfo[0].dwSize = 0; + cb = bufsize; + result = pRasEnumDevicesA(rasDevInfo, &cb, &cDevices); + todo_wine + ok(result == ERROR_INVALID_SIZE || + result == ERROR_INVALID_USER_BUFFER, /* win98 */ + "Expected ERROR_INVALID_SIZE, got %08d\n", result); + + rasDevInfo[0].dwSize = sizeof(RASDEVINFOA) -1; + cb = bufsize; + result = pRasEnumDevicesA(rasDevInfo, &cb, &cDevices); + todo_wine + ok(result == ERROR_INVALID_SIZE || + result == ERROR_INVALID_USER_BUFFER, /* win98 */ + "Expected ERROR_INVALID_SIZE, got %08d\n", result); + + rasDevInfo[0].dwSize = sizeof(RASDEVINFOA) +1; + cb = bufsize; + result = pRasEnumDevicesA(rasDevInfo, &cb, &cDevices); + todo_wine + ok(result == ERROR_INVALID_SIZE || + result == ERROR_INVALID_USER_BUFFER, /* win98 */ + "Expected ERROR_INVALID_SIZE, got %08d\n", result); + + /* test second parameter */ + rasDevInfo[0].dwSize = sizeof(RASDEVINFOA); + result = pRasEnumDevicesA(rasDevInfo, NULL, &cDevices); + ok(result == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08d\n", result); + + rasDevInfo[0].dwSize = sizeof(RASDEVINFOA); + cb = 0; + result = pRasEnumDevicesA(rasDevInfo, &cb, &cDevices); + ok(result == ERROR_BUFFER_TOO_SMALL || + result == ERROR_INVALID_SIZE, /* vista, 2k8 */ + "Expected ERROR_BUFFER_TOO_SMALL/ERROR_INVALID_SIZE, got %08d\n", result); + + rasDevInfo[0].dwSize = sizeof(RASDEVINFOA); + cb = bufsize -1; + result = pRasEnumDevicesA(rasDevInfo, &cb, &cDevices); + ok(result == ERROR_BUFFER_TOO_SMALL, + "Expected ERROR_BUFFER_TOO_SMALL, got %08d\n", result); + + rasDevInfo[0].dwSize = sizeof(RASDEVINFOA); + cb = bufsize +1; + result = pRasEnumDevicesA(rasDevInfo, &cb, &cDevices); + ok(result == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %08d\n", result); + + /* test third parameter */ + rasDevInfo[0].dwSize = sizeof(RASDEVINFOA); + cb = bufsize; + result = pRasEnumDevicesA(rasDevInfo, &cb, NULL); + ok(result == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08d\n", result); + + /* test combinations of invalid parameters */ + result = pRasEnumDevicesA(NULL, NULL, &cDevices); + ok(result == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08d\n", result); + + result = pRasEnumDevicesA(NULL, &cb, NULL); + ok(result == ERROR_INVALID_PARAMETER || + result == ERROR_INVALID_USER_BUFFER, /* win98 */ + "Expected ERROR_INVALID_PARAMETER, got %08d\n", result); + + cb = 0; + rasDevInfo[0].dwSize = 0; + result = pRasEnumDevicesA(rasDevInfo, &cb, &cDevices); + todo_wine + ok(result == ERROR_INVALID_SIZE || + broken(result == ERROR_BUFFER_TOO_SMALL), /* win98 */ + "Expected ERROR_INVALID_SIZE, got %08d\n", result); + + HeapFree(GetProcessHeap(), 0, rasDevInfo); +} + +START_TEST(rasapi) +{ + InitFunctionPtrs(); + + test_rasenum(); + + FreeLibrary(hmodule); +} diff --git a/rostests/winetests/rasapi32/rasapi32.rbuild b/rostests/winetests/rasapi32/rasapi32.rbuild new file mode 100644 index 00000000000..dff0d77da22 --- /dev/null +++ b/rostests/winetests/rasapi32/rasapi32.rbuild @@ -0,0 +1,8 @@ + + . + + rasapi.c + testlist.c + wine + ntdll + diff --git a/rostests/winetests/rasapi32/testlist.c b/rostests/winetests/rasapi32/testlist.c new file mode 100644 index 00000000000..a608f4e2785 --- /dev/null +++ b/rostests/winetests/rasapi32/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_rasapi(void); + +const struct test winetest_testlist[] = +{ + { "rasapi", func_rasapi }, + { 0, 0 } +}; diff --git a/rostests/winetests/riched20/editor.c b/rostests/winetests/riched20/editor.c index 0776fe47f14..112b29ae450 100644 --- a/rostests/winetests/riched20/editor.c +++ b/rostests/winetests/riched20/editor.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -32,8 +33,19 @@ #include #include +static CHAR string1[MAX_PATH], string2[MAX_PATH], string3[MAX_PATH]; + +#define ok_w3(format, szString1, szString2, szString3) \ + WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ + WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ + WideCharToMultiByte(CP_ACP, 0, szString3, -1, string3, MAX_PATH, NULL, NULL); \ + ok(!lstrcmpW(szString3, szString1) || !lstrcmpW(szString3, szString2), \ + format, string1, string2, string3); + static HMODULE hmoduleRichEdit; +static int is_win9x = 0; + static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) { HWND hwnd; hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL @@ -47,6 +59,26 @@ static HWND new_richedit(HWND parent) { return new_window(RICHEDIT_CLASS, ES_MULTILINE, parent); } +/* Keeps the window reponsive for the deley_time in seconds. + * This is useful for debugging a test to see what is happening. */ +static void keep_responsive(time_t delay_time) +{ + MSG msg; + time_t end; + + /* The message pump uses PeekMessage() to empty the queue and then + * sleeps for 50ms before retrying the queue. */ + end = time(NULL) + delay_time; + while (time(NULL) < end) { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + Sleep(50); + } + } +} + static void processPendingMessages(void) { MSG msg; @@ -81,6 +113,34 @@ static void simulate_typing_characters(HWND hwnd, const char* szChars) } } +static BOOL hold_key(int vk) +{ + BYTE key_state[256]; + BOOL result; + + result = GetKeyboardState(key_state); + ok(result, "GetKeyboardState failed.\n"); + if (!result) return FALSE; + key_state[vk] |= 0x80; + result = SetKeyboardState(key_state); + ok(result, "SetKeyboardState failed.\n"); + return result != 0; +} + +static BOOL release_key(int vk) +{ + BYTE key_state[256]; + BOOL result; + + result = GetKeyboardState(key_state); + ok(result, "GetKeyboardState failed.\n"); + if (!result) return FALSE; + key_state[vk] &= ~0x80; + result = SetKeyboardState(key_state); + ok(result, "SetKeyboardState failed.\n"); + return result != 0; +} + static const char haystack[] = "WINEWine wineWine wine WineWine"; /* ^0 ^10 ^20 ^30 */ @@ -90,80 +150,79 @@ struct find_s { const char *needle; int flags; int expected_loc; - int _todo_wine; }; struct find_s find_tests[] = { /* Find in empty text */ - {0, -1, "foo", FR_DOWN, -1, 0}, - {0, -1, "foo", 0, -1, 0}, - {0, -1, "", FR_DOWN, -1, 0}, - {20, 5, "foo", FR_DOWN, -1, 0}, - {5, 20, "foo", FR_DOWN, -1, 0} + {0, -1, "foo", FR_DOWN, -1}, + {0, -1, "foo", 0, -1}, + {0, -1, "", FR_DOWN, -1}, + {20, 5, "foo", FR_DOWN, -1}, + {5, 20, "foo", FR_DOWN, -1} }; struct find_s find_tests2[] = { /* No-result find */ - {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0}, - {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0}, + {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1}, + {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1}, /* Subsequent finds */ - {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0}, - {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0}, - {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0}, - {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, + {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4}, + {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13}, + {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23}, + {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27}, /* Find backwards */ - {19, 20, "Wine", FR_MATCHCASE, 13, 0}, - {10, 20, "Wine", FR_MATCHCASE, 4, 0}, - {20, 10, "Wine", FR_MATCHCASE, 13, 0}, + {19, 20, "Wine", FR_MATCHCASE, 13}, + {10, 20, "Wine", FR_MATCHCASE, 4}, + {20, 10, "Wine", FR_MATCHCASE, 13}, /* Case-insensitive */ - {1, 31, "wInE", FR_DOWN, 4, 0}, - {1, 31, "Wine", FR_DOWN, 4, 0}, + {1, 31, "wInE", FR_DOWN, 4}, + {1, 31, "Wine", FR_DOWN, 4}, /* High-to-low ranges */ - {20, 5, "Wine", FR_DOWN, -1, 0}, - {2, 1, "Wine", FR_DOWN, -1, 0}, - {30, 29, "Wine", FR_DOWN, -1, 0}, - {20, 5, "Wine", 0, 13, 0}, + {20, 5, "Wine", FR_DOWN, -1}, + {2, 1, "Wine", FR_DOWN, -1}, + {30, 29, "Wine", FR_DOWN, -1}, + {20, 5, "Wine", 0, 13}, /* Find nothing */ - {5, 10, "", FR_DOWN, -1, 0}, - {10, 5, "", FR_DOWN, -1, 0}, - {0, -1, "", FR_DOWN, -1, 0}, - {10, 5, "", 0, -1, 0}, + {5, 10, "", FR_DOWN, -1}, + {10, 5, "", FR_DOWN, -1}, + {0, -1, "", FR_DOWN, -1}, + {10, 5, "", 0, -1}, /* Whole-word search */ - {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0}, - {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0}, - {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0}, - {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0}, - {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0}, - {11, -1, "winewine", FR_WHOLEWORD, 0, 0}, - {31, -1, "winewine", FR_WHOLEWORD, 23, 0}, + {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18}, + {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1}, + {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18}, + {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0}, + {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23}, + {11, -1, "winewine", FR_WHOLEWORD, 0}, + {31, -1, "winewine", FR_WHOLEWORD, 23}, /* Bad ranges */ - {5, 200, "XXX", FR_DOWN, -1, 0}, - {-20, 20, "Wine", FR_DOWN, -1, 0}, - {-20, 20, "Wine", FR_DOWN, -1, 0}, - {-15, -20, "Wine", FR_DOWN, -1, 0}, - {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0}, + {5, 200, "XXX", FR_DOWN, -1}, + {-20, 20, "Wine", FR_DOWN, -1}, + {-20, 20, "Wine", FR_DOWN, -1}, + {-15, -20, "Wine", FR_DOWN, -1}, + {1<<12, 1<<13, "Wine", FR_DOWN, -1}, /* Check the case noted in bug 4479 where matches at end aren't recognized */ - {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0}, - {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, - {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, - {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0}, - {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0}, + {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23}, + {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27}, + {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27}, + {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23}, + {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23}, /* The backwards case of bug 4479; bounds look right * Fails because backward find is wrong */ - {19, 20, "WINE", FR_MATCHCASE, 0, 0}, - {0, 20, "WINE", FR_MATCHCASE, -1, 0}, + {19, 20, "WINE", FR_MATCHCASE, 0}, + {0, 20, "WINE", FR_MATCHCASE, -1}, - {0, -1, "wineWine wine", 0, -1, 0}, + {0, -1, "wineWine wine", 0, -1}, }; static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) { @@ -209,17 +268,10 @@ static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *fi int i; for (i = 0; i < num_tests; i++) { - if (find[i]._todo_wine) { - todo_wine { check_EM_FINDTEXT(hwnd, name, &find[i], i); check_EM_FINDTEXTEX(hwnd, name, &find[i], i); } - } else { - check_EM_FINDTEXT(hwnd, name, &find[i], i); - check_EM_FINDTEXTEX(hwnd, name, &find[i], i); } - } -} static void test_EM_FINDTEXT(void) { @@ -296,7 +348,7 @@ static void test_EM_GETLINE(void) { int nCopied; int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text)); - int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1); + int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text)); memset(dest, 0xBB, nBuf); *(WORD *) dest = gl[i].buffer_len; @@ -314,11 +366,37 @@ static void test_EM_GETLINE(void) !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n"); else { + /* Prepare hex strings of buffers to dump on failure. */ + char expectedbuf[1024]; + char resultbuf[1024]; + int j; + resultbuf[0] = '\0'; + for (j = 0; j < 32; j++) + sprintf(resultbuf+strlen(resultbuf), "%02x", dest[j] & 0xFF); + expectedbuf[0] = '\0'; + for (j = 0; j < expected_bytes_written; j++) /* Written bytes */ + sprintf(expectedbuf+strlen(expectedbuf), "%02x", gl[i].text[j] & 0xFF); + for (; j < gl[i].buffer_len; j++) /* Ignored bytes */ + sprintf(expectedbuf+strlen(expectedbuf), "??"); + for (; j < 32; j++) /* Bytes after declared buffer size */ + sprintf(expectedbuf+strlen(expectedbuf), "%02x", origdest[j] & 0xFF); + + /* Test the part of the buffer that is expected to be written according + * to the MSDN documentation fo EM_GETLINE, which does not state that + * a NULL terminating character will be added unless no text is copied. + * + * Windows 95, 98 & NT do not append a NULL terminating character, but + * Windows 2000 and up do append a NULL terminating character if there + * is space in the buffer. The test will ignore this difference. */ ok(!strncmp(dest, gl[i].text, expected_bytes_written), - "%d: expected_bytes_written=%d\n", i, expected_bytes_written); - ok(!strncmp(dest + expected_bytes_written, origdest - + expected_bytes_written, nBuf - expected_bytes_written), - "%d: expected_bytes_written=%d\n", i, expected_bytes_written); + "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n", + i, expected_bytes_written, expectedbuf, resultbuf); + /* Test the part of the buffer after the declared length to make sure + * there are no buffer overruns. */ + ok(!strncmp(dest + gl[i].buffer_len, origdest + gl[i].buffer_len, + nBuf - gl[i].buffer_len), + "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n", + i, expected_bytes_written, expectedbuf, resultbuf); } } @@ -367,7 +445,7 @@ static int get_scroll_pos_y(HWND hwnd) return p.y; } -static void move_cursor(HWND hwnd, long charindex) +static void move_cursor(HWND hwnd, LONG charindex) { CHARRANGE cr; cr.cpMax = charindex; @@ -383,7 +461,6 @@ static void line_scroll(HWND hwnd, int amount) static void test_EM_SCROLLCARET(void) { int prevY, curY; - HWND hwndRichEdit = new_richedit(NULL); const char text[] = "aa\n" "this is a long line of text that should be longer than the " "control's width\n" @@ -393,6 +470,14 @@ static void test_EM_SCROLLCARET(void) "ff\n" "gg\n" "hh\n"; + /* The richedit window height needs to be large enough vertically to fit in + * more than two lines of text, so the new_richedit function can't be used + * since a height of 60 was not large enough on some systems. + */ + HWND hwndRichEdit = CreateWindow(RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwndRichEdit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); /* Can't verify this */ SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0); @@ -438,6 +523,7 @@ static void test_EM_POSFROMCHAR(void) LRESULT result; unsigned int height = 0; int xpos = 0; + POINTL pt; static const char text[] = "aa\n" "this is a long line of text that should be longer than the " "control's width\n" @@ -475,9 +561,7 @@ static void test_EM_POSFROMCHAR(void) if (i == 0) { ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); - todo_wine { ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); - } xpos = LOWORD(result); } else if (i == 1) @@ -531,20 +615,35 @@ static void test_EM_POSFROMCHAR(void) result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, 0, 0); ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); - todo_wine { ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result)); - } xpos = LOWORD(result); SendMessage(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0); result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, 0, 0); ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result)); - todo_wine { - /* Fails on builtin because horizontal scrollbar is not being shown */ ok((signed short)(LOWORD(result)) < xpos, "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n", (signed short)(LOWORD(result)), xpos); - } + SendMessage(hwndRichEdit, WM_HSCROLL, SB_LINELEFT, 0); + + /* Test around end of text that doesn't end in a newline. */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "12345678901234"); + SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, + SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)-1); + ok(pt.x > 1, "pt.x = %d\n", pt.x); + xpos = pt.x; + SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, + SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)); + ok(pt.x > xpos, "pt.x = %d\n", pt.x); + xpos = pt.x; + SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, + SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)+1); + ok(pt.x == xpos, "pt.x = %d\n", pt.x); + + /* Try a negative position. */ + SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, -1); + ok(pt.x == 1, "pt.x = %d\n", pt.x); + DestroyWindow(hwndRichEdit); } @@ -614,7 +713,7 @@ static void test_EM_SETCHARFORMAT(void) (LPARAM) &cf2); ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc); rc = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0); - todo_wine ok(rc == FALSE, "Should not be able to undo here.\n"); + ok(rc == FALSE, "Should not be able to undo here.\n"); SendMessage(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0); /* A valid flag, CHARFORMAT2 structure minimally filled */ @@ -659,7 +758,7 @@ static void test_EM_SETCHARFORMAT(void) cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects; /* wParam==0 is default char format, does not set modify */ - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); ok(rc == 0, "Text marked as modified, expected not modified!\n"); rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM) &cf2); @@ -668,7 +767,7 @@ static void test_EM_SETCHARFORMAT(void) ok(rc == 0, "Text marked as modified, expected not modified!\n"); /* wParam==SCF_SELECTION sets modify if nonempty selection */ - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); ok(rc == 0, "Text marked as modified, expected not modified!\n"); rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf2); @@ -690,7 +789,7 @@ static void test_EM_SETCHARFORMAT(void) ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc); /* wParam==SCF_ALL sets modify regardless of whether text is present */ - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); rc = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); ok(rc == 0, "Text marked as modified, expected not modified!\n"); rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2); @@ -1087,6 +1186,34 @@ static void test_EM_SETTEXTMODE(void) DestroyWindow(hwndRichEdit); } +static void test_SETPARAFORMAT(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + PARAFORMAT2 fmt; + HRESULT ret; + LONG expectedMask = PFM_ALL2 & ~PFM_TABLEROWDELIMITER; + fmt.cbSize = sizeof(PARAFORMAT2); + fmt.dwMask = PFM_ALIGNMENT; + fmt.wAlignment = PFA_LEFT; + + ret = SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &fmt); + ok(ret != 0, "expected non-zero got %d\n", ret); + + fmt.cbSize = sizeof(PARAFORMAT2); + fmt.dwMask = -1; + ret = SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM) &fmt); + /* Ignore the PFM_TABLEROWDELIMITER bit because it changes + * between richedit different native builds of riched20.dll + * used on different Windows versions. */ + ret &= ~PFM_TABLEROWDELIMITER; + fmt.dwMask &= ~PFM_TABLEROWDELIMITER; + + ok(ret == expectedMask, "expected %x got %x\n", expectedMask, ret); + ok(fmt.dwMask == expectedMask, "expected %x got %x\n", expectedMask, fmt.dwMask); + + DestroyWindow(hwndRichEdit); +} + static void test_TM_PLAINTEXT(void) { /*Tests plain text properties*/ @@ -1293,6 +1420,46 @@ static void test_EM_GETTEXTRANGE(void) ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + /* cpMax of text length is used instead of -1 in this case */ + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 0; + textRange.chrg.cpMax = -1; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + /* cpMin < 0 causes no text to be copied, and 0 to be returned */ + textRange.lpstrText = buffer; + textRange.chrg.cpMin = -1; + textRange.chrg.cpMax = 1; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + /* cpMax of -1 is not replaced with text length if cpMin != 0 */ + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 1; + textRange.chrg.cpMax = -1; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + /* no end character is copied if cpMax - cpMin < 0 */ + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 5; + textRange.chrg.cpMax = 5; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + /* cpMax of text length is used if cpMax > text length*/ + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 0; + textRange.chrg.cpMax = 1000; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + DestroyWindow(hwndRichEdit); } @@ -1325,9 +1492,34 @@ static void test_EM_GETSELTEXT(void) /* FIXME: need to test unimplemented options and robustly test wparam */ static void test_EM_SETOPTIONS(void) { - HWND hwndRichEdit = new_richedit(NULL); + HWND hwndRichEdit; static const char text[] = "Hello. My name is RichEdit!"; char buffer[1024] = {0}; + DWORD dwStyle, options, oldOptions; + DWORD optionStyles = ES_AUTOVSCROLL|ES_AUTOHSCROLL|ES_NOHIDESEL| + ES_READONLY|ES_WANTRETURN|ES_SAVESEL| + ES_SELECTIONBAR|ES_VERTICAL; + + /* Test initial options. */ + hwndRichEdit = CreateWindow(RICHEDIT_CLASS, NULL, WS_POPUP, + 0, 0, 200, 60, NULL, NULL, + hmoduleRichEdit, NULL); + ok(hwndRichEdit != NULL, "class: %s, error: %d\n", + RICHEDIT_CLASS, (int) GetLastError()); + options = SendMessage(hwndRichEdit, EM_GETOPTIONS, 0, 0); + ok(options == 0, "Incorrect initial options %x\n", options); + DestroyWindow(hwndRichEdit); + + hwndRichEdit = CreateWindow(RICHEDIT_CLASS, NULL, + WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, + 0, 0, 200, 60, NULL, NULL, + hmoduleRichEdit, NULL); + ok(hwndRichEdit != NULL, "class: %s, error: %d\n", + RICHEDIT_CLASS, (int) GetLastError()); + options = SendMessage(hwndRichEdit, EM_GETOPTIONS, 0, 0); + /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */ + ok(options == (ECO_AUTOVSCROLL|ECO_AUTOHSCROLL), + "Incorrect initial options %x\n", options); /* NEGATIVE TESTING - NO OPTIONS SET */ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text); @@ -1350,6 +1542,25 @@ static void test_EM_SETOPTIONS(void) ok(buffer[0]==text[0], "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer); + /* EM_SETOPTIONS changes the window style, but changing the + * window style does not change the options. */ + dwStyle = GetWindowLong(hwndRichEdit, GWL_STYLE); + ok(dwStyle & ES_READONLY, "Readonly style not set by EM_SETOPTIONS\n"); + SetWindowLong(hwndRichEdit, GWL_STYLE, dwStyle & ~ES_READONLY); + options = SendMessage(hwndRichEdit, EM_GETOPTIONS, 0, 0); + ok(options & ES_READONLY, "Readonly option set by SetWindowLong\n"); + /* Confirm that the text is still read only. */ + SendMessage(hwndRichEdit, WM_CHAR, 'a', ('a' << 16) | 0x0001); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok(buffer[0]==text[0], + "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer); + + oldOptions = options; + SetWindowLong(hwndRichEdit, GWL_STYLE, dwStyle|optionStyles); + options = SendMessage(hwndRichEdit, EM_GETOPTIONS, 0, 0); + ok(options == oldOptions, + "Options set by SetWindowLong (%x -> %x)\n", oldOptions, options); + DestroyWindow(hwndRichEdit); } @@ -1383,6 +1594,9 @@ static HWND new_static_wnd(HWND parent) { static void test_EM_AUTOURLDETECT(void) { + /* DO NOT change the properties of the first two elements. To shorten the + tests, all tests after WM_SETTEXT test just the first two elements - + one non-URL and one URL */ struct urls_s { const char *text; int is_url; @@ -1647,10 +1861,12 @@ static void test_EM_AUTOURLDETECT(void) } /* Test detection of URLs within normal text - WM_CHAR case. */ - for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { + /* Test only the first two URL examples for brevity */ + for (i = 0; i < 2; i++) { hwndRichEdit = new_richedit(parent); - for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { + /* Also for brevity, test only the first three delimiters */ + for (j = 0; j < 3; j++) { char * at_pos; int at_offset; int end_offset; @@ -1674,7 +1890,6 @@ static void test_EM_AUTOURLDETECT(void) } } SendMessage(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer); - trace("Using template: %s\n", templates_delim[j]); /* This assumes no templates start with the URL itself, and that they have at least two characters before the URL text */ @@ -1784,7 +1999,8 @@ static void test_EM_AUTOURLDETECT(void) } /* Test detection of URLs within normal text - EM_SETTEXTEX case. */ - for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { + /* Test just the first two URL examples for brevity */ + for (i = 0; i < 2; i++) { SETTEXTEX st; hwndRichEdit = new_richedit(parent); @@ -1971,7 +2187,8 @@ static void test_EM_AUTOURLDETECT(void) } /* Test detection of URLs within normal text - EM_REPLACESEL case. */ - for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { + /* Test just the first two URL examples for brevity */ + for (i = 0; i < 2; i++) { hwndRichEdit = new_richedit(parent); /* Set selection with X to the URL */ @@ -2223,6 +2440,728 @@ static void test_EM_SCROLL(void) DestroyWindow(hwndRichEdit); } +unsigned int recursionLevel = 0; +unsigned int WM_SIZE_recursionLevel = 0; +BOOL bailedOutOfRecursion = FALSE; +LRESULT (WINAPI *richeditProc)(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT r; + + if (bailedOutOfRecursion) return 0; + if (recursionLevel >= 32) { + bailedOutOfRecursion = TRUE; + return 0; + } + + recursionLevel++; + switch (message) { + case WM_SIZE: + WM_SIZE_recursionLevel++; + r = richeditProc(hwnd, message, wParam, lParam); + /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */ + ShowScrollBar(hwnd, SB_VERT, TRUE); + WM_SIZE_recursionLevel--; + break; + default: + r = richeditProc(hwnd, message, wParam, lParam); + break; + } + recursionLevel--; + return r; +} + +static void test_scrollbar_visibility(void) +{ + HWND hwndRichEdit; + const char * text="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"; + SCROLLINFO si; + WNDCLASSA cls; + BOOL r; + + /* These tests show that richedit should temporarily refrain from automatically + hiding or showing its scrollbars (vertical at least) when an explicit request + is made via ShowScrollBar() or similar, outside of standard richedit logic. + Some applications depend on forced showing (when otherwise richedit would + hide the vertical scrollbar) and are thrown on an endless recursive loop + if richedit auto-hides the scrollbar again. Apparently they never heard of + the ES_DISABLENOSCROLL style... */ + + hwndRichEdit = new_richedit(NULL); + + /* Test default scrollbar visibility behavior */ + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + /* Oddly, setting text to NULL does *not* reset the scrollbar range, + even though it hides the scrollbar */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + /* Setting non-scrolling text again does *not* reset scrollbar range */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + DestroyWindow(hwndRichEdit); + + /* Test again, with ES_DISABLENOSCROLL style */ + hwndRichEdit = new_window(RICHEDIT_CLASS, ES_MULTILINE|ES_DISABLENOSCROLL, NULL); + + /* Test default scrollbar visibility behavior */ + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1, + "reported page/range is %d (%d..%d) expected 0 (0..1)\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1, + "reported page/range is %d (%d..%d) expected 0 (0..1)\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + /* Oddly, setting text to NULL does *not* reset the scrollbar range */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + /* Setting non-scrolling text again does *not* reset scrollbar range */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + DestroyWindow(hwndRichEdit); + + /* Test behavior with explicit visibility request, using ShowScrollBar() */ + hwndRichEdit = new_richedit(NULL); + + /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */ + ShowScrollBar(hwndRichEdit, SB_VERT, TRUE); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + todo_wine { + ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, + "reported page/range is %d (%d..%d) expected 0 (0..100)\n", + si.nPage, si.nMin, si.nMax); + } + + /* Ditto, see above */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + todo_wine { + ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, + "reported page/range is %d (%d..%d) expected 0 (0..100)\n", + si.nPage, si.nMin, si.nMax); + } + + /* Ditto, see above */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + todo_wine { + ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, + "reported page/range is %d (%d..%d) expected 0 (0..100)\n", + si.nPage, si.nMin, si.nMax); + } + + /* Ditto, see above */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + todo_wine { + ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, + "reported page/range is %d (%d..%d) expected 0 (0..100)\n", + si.nPage, si.nMin, si.nMax); + } + + /* Ditto, see above */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + todo_wine { + ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100, + "reported page/range is %d (%d..%d) expected 0 (0..100)\n", + si.nPage, si.nMin, si.nMax); + } + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + DestroyWindow(hwndRichEdit); + + hwndRichEdit = new_richedit(NULL); + + ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */ + ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that + EM_SCROLL will make visible any forcefully invisible scrollbar */ + SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + ShowScrollBar(hwndRichEdit, SB_VERT, FALSE); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + /* Again, EM_SCROLL, with SB_LINEUP */ + SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + DestroyWindow(hwndRichEdit); + + + /* Test behavior with explicit visibility request, using SetWindowLong()() */ + hwndRichEdit = new_richedit(NULL); + +#define ENABLE_WS_VSCROLL(hwnd) \ + SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL) +#define DISABLE_WS_VSCROLL(hwnd) \ + SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL) + + /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */ + ENABLE_WS_VSCROLL(hwndRichEdit); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + /* Ditto, see above */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + /* Ditto, see above */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + /* Ditto, see above */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + /* Ditto, see above */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + DestroyWindow(hwndRichEdit); + + hwndRichEdit = new_richedit(NULL); + + DISABLE_WS_VSCROLL(hwndRichEdit); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a"); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100), + "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */ + DISABLE_WS_VSCROLL(hwndRichEdit); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n", + si.nPage, si.nMin, si.nMax); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + DISABLE_WS_VSCROLL(hwndRichEdit); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that + EM_SCROLL will make visible any forcefully invisible scrollbar */ + SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + DISABLE_WS_VSCROLL(hwndRichEdit); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), + "Vertical scrollbar is visible, should be invisible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + /* Again, EM_SCROLL, with SB_LINEUP */ + SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); + memset(&si, 0, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), + "Vertical scrollbar is invisible, should be visible.\n"); + ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0, + "reported page/range is %d (%d..%d)\n", + si.nPage, si.nMin, si.nMax); + + DestroyWindow(hwndRichEdit); + + /* This window proc models what is going on with Corman Lisp 3.0. + At WM_SIZE, this proc unconditionally calls ShowScrollBar() to + force the scrollbar into visibility. Recursion should NOT happen + as a result of this action. + */ + r = GetClassInfoA(NULL, RICHEDIT_CLASS, &cls); + if (r) { + richeditProc = cls.lpfnWndProc; + cls.lpfnWndProc = RicheditStupidOverrideProcA; + cls.lpszClassName = "RicheditStupidOverride"; + if(!RegisterClassA(&cls)) assert(0); + + recursionLevel = 0; + WM_SIZE_recursionLevel = 0; + bailedOutOfRecursion = FALSE; + hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL); + ok(!bailedOutOfRecursion, + "WM_SIZE/scrollbar mutual recursion detected, expected none!\n"); + + recursionLevel = 0; + WM_SIZE_recursionLevel = 0; + bailedOutOfRecursion = FALSE; + MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE); + ok(!bailedOutOfRecursion, + "WM_SIZE/scrollbar mutual recursion detected, expected none!\n"); + + /* Unblock window in order to process WM_DESTROY */ + recursionLevel = 0; + bailedOutOfRecursion = FALSE; + WM_SIZE_recursionLevel = 0; + DestroyWindow(hwndRichEdit); + } +} + static void test_EM_SETUNDOLIMIT(void) { /* cases we test for: @@ -2326,7 +3265,7 @@ static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, return 0; } -static void test_WM_SETTEXT() +static void test_WM_SETTEXT(void) { HWND hwndRichEdit = new_richedit(NULL); const char * TestItem1 = "TestSomeText"; @@ -2444,14 +3383,79 @@ static void test_EM_STREAMOUT(void) DestroyWindow(hwndRichEdit); } -static void test_EM_SETTEXTEX(void) +static void test_EM_STREAMOUT_FONTTBL(void) { HWND hwndRichEdit = new_richedit(NULL); + EDITSTREAM es; + char buf[1024] = {0}; + char * p; + char * fontTbl; + int brackCount; + + const char * TestItem = "TestSomeText"; + + /* fills in the richedit control with some text */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem); + + /* streams out the text in rtf format */ + p = buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_RTF), (LPARAM)&es); + + /* scans for \fonttbl, error if not found */ + fontTbl = strstr(buf, "\\fonttbl"); + ok(fontTbl != NULL, "missing \\fonttbl section\n"); + if(fontTbl) + { + /* scans for terminating closing bracket */ + brackCount = 1; + while(*fontTbl && brackCount) + { + if(*fontTbl == '{') + brackCount++; + else if(*fontTbl == '}') + brackCount--; + fontTbl++; + } + /* checks whether closing bracket is ok */ + ok(brackCount == 0, "missing closing bracket in \\fonttbl block\n"); + if(!brackCount) + { + /* char before closing fonttbl block should be a closed bracket */ + fontTbl -= 2; + ok(*fontTbl == '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl); + + /* char after fonttbl block should be a crlf */ + fontTbl += 2; + ok(*fontTbl == 0x0d && *(fontTbl+1) == 0x0a, "missing crlf after \\fonttbl block\n"); + } + } + DestroyWindow(hwndRichEdit); +} + + +static void test_EM_SETTEXTEX(void) +{ + HWND hwndRichEdit, parent; + SCROLLINFO si; + int sel_start, sel_end; SETTEXTEX setText; GETTEXTEX getText; WCHAR TestItem1[] = {'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't', 0}; + WCHAR TestItem1alt[] = {'T', 'T', 'e', 's', + 't', 'S', 'o', 'm', + 'e', 'T', 'e', 'x', + 't', 't', 'S', 'o', + 'm', 'e', 'T', 'e', + 'x', 't', 0}; + WCHAR TestItem1altn[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t', + '\r','t','S','o','m','e','T','e','x','t',0}; WCHAR TestItem2[] = {'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't', @@ -2480,10 +3484,81 @@ static void test_EM_SETTEXTEX(void) ' ','\r', 0}; #define MAX_BUF_LEN 1024 WCHAR buf[MAX_BUF_LEN]; + char bufACP[MAX_BUF_LEN]; char * p; int result; CHARRANGE cr; EDITSTREAM es; + WNDCLASSA cls; + + /* Test the scroll position with and without a parent window. + * + * For some reason the scroll position is 0 after EM_SETTEXTEX + * with the ST_SELECTION flag only when the control has a parent + * window, even though the selection is at the end. */ + cls.style = 0; + cls.lpfnWndProc = DefWindowProcA; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "ParentTestClass"; + if(!RegisterClassA(&cls)) assert(0); + + parent = CreateWindow(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE, + 0, 0, 200, 60, NULL, NULL, NULL, NULL); + ok (parent != 0, "Failed to create parent window\n"); + + hwndRichEdit = CreateWindowEx(0, + RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_VSCROLL|WS_VISIBLE|WS_CHILD, + 0, 0, 200, 60, parent, NULL, + hmoduleRichEdit, NULL); + + setText.codepage = CP_ACP; + setText.flags = ST_SELECTION; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, + (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); + si.cbSize = sizeof(si); + si.fMask = SIF_ALL; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + todo_wine ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos); + SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); + ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start); + ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end); + + DestroyWindow(parent); + + /* Test without a parent window */ + hwndRichEdit = new_richedit(NULL); + setText.codepage = CP_ACP; + setText.flags = ST_SELECTION; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, + (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); + si.cbSize = sizeof(si); + si.fMask = SIF_ALL; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok(si.nPos != 0, "Position is incorrectly at %d\n", si.nPos); + SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); + ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start); + ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end); + + /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT, + * but this time it is because the selection is at the beginning. */ + setText.codepage = CP_ACP; + setText.flags = ST_DEFAULT; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, + (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}"); + si.cbSize = sizeof(si); + si.fMask = SIF_ALL; + GetScrollInfo(hwndRichEdit, SB_VERT, &si); + ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos); + SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); + ok(sel_start == 0, "Selection start incorrectly at %d\n", sel_start); + ok(sel_end == 0, "Selection end incorrectly at %d\n", sel_end); setText.codepage = 1200; /* no constant for unicode */ getText.codepage = 1200; /* no constant for unicode */ @@ -2499,7 +3574,7 @@ static void test_EM_SETTEXTEX(void) "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not - convert \r to \r\n on return + convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf */ setText.codepage = 1200; /* no constant for unicode */ getText.codepage = 1200; /* no constant for unicode */ @@ -2545,7 +3620,7 @@ static void test_EM_SETTEXTEX(void) "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); - /* \r\n pairs get changed into \r */ + /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */ setText.codepage = 1200; /* no constant for unicode */ getText.codepage = 1200; /* no constant for unicode */ getText.cb = MAX_BUF_LEN; @@ -2558,7 +3633,7 @@ static void test_EM_SETTEXTEX(void) ok(lstrcmpW(buf, TestItem3_after) == 0, "EM_SETTEXTEX did not convert properly\n"); - /* \n also gets changed to \r */ + /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */ setText.codepage = 1200; /* no constant for unicode */ getText.codepage = 1200; /* no constant for unicode */ getText.cb = MAX_BUF_LEN; @@ -2571,7 +3646,7 @@ static void test_EM_SETTEXTEX(void) ok(lstrcmpW(buf, TestItem3_after) == 0, "EM_SETTEXTEX did not convert properly\n"); - /* \r\r\n gets changed into single space */ + /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */ setText.codepage = 1200; /* no constant for unicode */ getText.codepage = 1200; /* no constant for unicode */ getText.cb = MAX_BUF_LEN; @@ -2584,8 +3659,8 @@ static void test_EM_SETTEXTEX(void) ok(lstrcmpW(buf, TestItem4_after) == 0, "EM_SETTEXTEX did not convert properly\n"); - result = SendMessage(hwndRichEdit, EM_SETTEXTEX, - (WPARAM)&setText, (LPARAM) NULL); + /* !ST_SELECTION && Unicode && !\rtf */ + result = SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0); SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf); ok (result == 1, @@ -2593,30 +3668,29 @@ static void test_EM_SETTEXTEX(void) ok(lstrlenW(buf) == 0, "EM_SETTEXTEX with NULL lParam should clear rich edit.\n"); - /* put some text back */ + /* put some text back: !ST_SELECTION && Unicode && !\rtf */ setText.flags = 0; SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1); /* select some text */ cr.cpMax = 1; cr.cpMin = 3; SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr); - /* replace current selection */ + /* replace current selection: ST_SELECTION && Unicode && !\rtf */ setText.flags = ST_SELECTION; - result = SendMessage(hwndRichEdit, EM_SETTEXTEX, - (WPARAM)&setText, (LPARAM) NULL); + result = SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0); ok(result == 0, "EM_SETTEXTEX with NULL lParam to replace selection" " with no text should return 0. Got %i\n", result); - /* put some text back */ + /* put some text back: !ST_SELECTION && Unicode && !\rtf */ setText.flags = 0; SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1); /* select some text */ cr.cpMax = 1; cr.cpMin = 3; SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr); - /* replace current selection */ + /* replace current selection: ST_SELECTION && Unicode && !\rtf */ setText.flags = ST_SELECTION; result = SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1); @@ -2641,6 +3715,7 @@ static void test_EM_SETTEXTEX(void) (WPARAM)(SF_RTF), (LPARAM)&es); trace("EM_STREAMOUT produced: \n%s\n", (char *)buf); + /* !ST_SELECTION && !Unicode && \rtf */ setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */ getText.codepage = 1200; /* no constant for unicode */ getText.cb = MAX_BUF_LEN; @@ -2654,6 +3729,102 @@ static void test_EM_SETTEXTEX(void) ok(lstrcmpW(buf, TestItem1) == 0, "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); + /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it + * starts with ASCII characters "{\rtf" even when the codepage is unicode. */ + setText.codepage = 1200; /* Lie about code page (actual ASCII) */ + getText.codepage = CP_ACP; + getText.cb = MAX_BUF_LEN; + getText.flags = GT_DEFAULT; + getText.lpDefaultChar = NULL; + getText.lpUsedDefChar = NULL; + + setText.flags = ST_SELECTION; + SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); + result = SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) "{\\rtf not unicode}"); + todo_wine ok(result == 11, "EM_SETTEXTEX incorrectly returned %d\n", result); + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) bufACP); + ok(lstrcmpA(bufACP, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP); + + /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "TestSomeText"); /* TestItem1 */ + p = (char *)buf; + es.dwCookie = (DWORD_PTR)&p; + es.dwError = 0; + es.pfnCallback = test_WM_SETTEXT_esCallback; + memset(buf, 0, sizeof(buf)); + SendMessage(hwndRichEdit, EM_STREAMOUT, + (WPARAM)(SF_RTF), (LPARAM)&es); + trace("EM_STREAMOUT produced:\n%s\n", (char *)buf); + + /* select some text */ + cr.cpMax = 1; + cr.cpMin = 3; + SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr); + + /* ST_SELECTION && !Unicode && \rtf */ + setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */ + getText.codepage = 1200; /* no constant for unicode */ + getText.cb = MAX_BUF_LEN; + getText.flags = GT_DEFAULT; + getText.lpDefaultChar = NULL; + getText.lpUsedDefChar = NULL; + + setText.flags = ST_SELECTION; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) buf); + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf); + ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt, TestItem1altn, buf); + + /* The following test demonstrates that EM_SETTEXTEX replacing a selection */ + setText.codepage = 1200; /* no constant for unicode */ + getText.codepage = CP_ACP; + getText.cb = MAX_BUF_LEN; + + setText.flags = 0; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1); /* TestItem1 */ + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) bufACP); + + /* select some text */ + cr.cpMax = 1; + cr.cpMin = 3; + SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr); + + /* ST_SELECTION && !Unicode && !\rtf */ + setText.codepage = CP_ACP; + getText.codepage = 1200; /* no constant for unicode */ + getText.cb = MAX_BUF_LEN; + getText.flags = GT_DEFAULT; + getText.lpDefaultChar = NULL; + getText.lpUsedDefChar = NULL; + + setText.flags = ST_SELECTION; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) bufACP); + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf); + ok(lstrcmpW(buf, TestItem1alt) == 0, + "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when" + " using ST_SELECTION and non-Unicode\n"); + + /* Test setting text using rich text format */ + setText.flags = 0; + setText.codepage = CP_ACP; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf richtext}"); + getText.codepage = CP_ACP; + getText.cb = MAX_BUF_LEN; + getText.flags = GT_DEFAULT; + getText.lpDefaultChar = NULL; + getText.lpUsedDefChar = NULL; + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) bufACP); + ok(!strcmp(bufACP, "richtext"), "expected 'richtext' but got '%s'\n", bufACP); + + setText.flags = 0; + setText.codepage = CP_ACP; + SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\urtf morerichtext}"); + getText.codepage = CP_ACP; + getText.cb = MAX_BUF_LEN; + getText.flags = GT_DEFAULT; + getText.lpDefaultChar = NULL; + getText.lpUsedDefChar = NULL; + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) bufACP); + ok(!strcmp(bufACP, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP); DestroyWindow(hwndRichEdit); } @@ -2868,7 +4039,7 @@ static void test_WM_SETFONT(void) returnedCF2A.cbSize = sizeof(returnedCF2A); SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x"); - SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0)); + SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1, MAKELPARAM(TRUE, 0)); SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A); GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont); @@ -2876,14 +4047,14 @@ static void test_WM_SETFONT(void) "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n", sentLogFont.lfFaceName,returnedCF2A.szFaceName); - SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0)); + SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2, MAKELPARAM(TRUE, 0)); SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A); GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont); ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n", sentLogFont.lfFaceName,returnedCF2A.szFaceName); - SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0)); + SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3, MAKELPARAM(TRUE, 0)); SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A); GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont); ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName), @@ -2896,7 +4067,7 @@ static void test_WM_SETFONT(void) ZeroMemory(&sentLogFont,sizeof(sentLogFont)); returnedCF2A.cbSize = sizeof(returnedCF2A); - SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0)); + SendMessage(hwndRichEdit, WM_SETFONT, 0, MAKELPARAM((WORD) TRUE, 0)); SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A); GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont); ok (!strcmp("System",returnedCF2A.szFaceName), @@ -2970,7 +4141,7 @@ static void test_EM_GETMODIFY(void) /* setting font doesn't change modify flag */ SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0); - SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0)); + SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont, MAKELPARAM(TRUE, 0)); result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0); ok (result == 0, "EM_GETMODIFY returned non-zero, instead of zero on setting font\n"); @@ -3095,37 +4266,36 @@ static void test_EM_GETMODIFY(void) } struct exsetsel_s { - long min; - long max; - long expected_retval; + LONG min; + LONG max; + LRESULT expected_retval; int expected_getsel_start; int expected_getsel_end; - int _exsetsel_todo_wine; int _getsel_todo_wine; }; const struct exsetsel_s exsetsel_tests[] = { /* sanity tests */ - {5, 10, 10, 5, 10, 0, 0}, - {15, 17, 17, 15, 17, 0, 0}, + {5, 10, 10, 5, 10, 0}, + {15, 17, 17, 15, 17, 0}, /* test cpMax > strlen() */ - {0, 100, 18, 0, 18, 0, 1}, + {0, 100, 18, 0, 18, 1}, /* test cpMin == cpMax */ - {5, 5, 5, 5, 5, 0, 0}, + {5, 5, 5, 5, 5, 0}, /* test cpMin < 0 && cpMax >= 0 (bug 4462) */ - {-1, 0, 5, 5, 5, 0, 0}, - {-1, 17, 5, 5, 5, 0, 0}, - {-1, 18, 5, 5, 5, 0, 0}, + {-1, 0, 5, 5, 5, 0}, + {-1, 17, 5, 5, 5, 0}, + {-1, 18, 5, 5, 5, 0}, /* test cpMin < 0 && cpMax < 0 */ - {-1, -1, 17, 17, 17, 0, 0}, - {-4, -5, 17, 17, 17, 0, 0}, + {-1, -1, 17, 17, 17, 0}, + {-4, -5, 17, 17, 17, 0}, /* test cMin >=0 && cpMax < 0 (bug 6814) */ - {0, -1, 18, 0, 18, 0, 1}, - {17, -5, 18, 17, 18, 0, 1}, - {18, -3, 17, 17, 17, 0, 0}, + {0, -1, 18, 0, 18, 1}, + {17, -5, 18, 17, 18, 1}, + {18, -3, 17, 17, 17, 0}, /* test if cpMin > cpMax */ - {15, 19, 18, 15, 18, 0, 1}, - {19, 15, 18, 15, 18, 0, 1} + {15, 19, 18, 15, 18, 1}, + {19, 15, 18, 15, 18, 1} }; static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) { @@ -3137,13 +4307,7 @@ static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id cr.cpMax = setsel->max; result = SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr); - if (setsel->_exsetsel_todo_wine) { - todo_wine { ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result); - } - } else { - ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result); - } SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end); @@ -3189,7 +4353,7 @@ static void test_EM_REPLACESEL(int redraw) /* FIXME add more tests */ SendMessage(hwndRichEdit, EM_SETSEL, 7, 17); - r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) NULL); + r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, 0); ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r); SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); r = strcmp(buffer, "testing"); @@ -3203,7 +4367,7 @@ static void test_EM_REPLACESEL(int redraw) SendMessage(hwndRichEdit, WM_SETREDRAW, redraw, 0); /* Test behavior with carriage returns and newlines */ - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1"); ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r); SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); @@ -3222,7 +4386,7 @@ static void test_EM_REPLACESEL(int redraw) r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r"); ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r); SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); @@ -3248,7 +4412,7 @@ static void test_EM_REPLACESEL(int redraw) characters interpreted from the original lParam. Wine's builtin riched20 implements the WinXP behavior. */ - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r\n"); ok(11 == r /* WinXP */ || 10 == r /* Win98 */, "EM_REPLACESEL returned %d, expected 11 or 10\n", r); @@ -3285,7 +4449,7 @@ static void test_EM_REPLACESEL(int redraw) string. */ - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r"); ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r); r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); @@ -3307,7 +4471,7 @@ static void test_EM_REPLACESEL(int redraw) r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n"); ok(3 == r /* WinXP */ || 1 == r /* Win98 */, "EM_REPLACESEL returned %d, expected 3 or 1\n", r); @@ -3330,7 +4494,7 @@ static void test_EM_REPLACESEL(int redraw) r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\r\r\r\n\r\r\r"); ok(9 == r /* WinXP */ || 7 == r /* Win98 */, "EM_REPLACESEL returned %d, expected 9 or 7\n", r); @@ -3353,7 +4517,7 @@ static void test_EM_REPLACESEL(int redraw) r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\n"); ok(5 == r /* WinXP */ || 2 == r /* Win98 */, "EM_REPLACESEL returned %d, expected 5 or 2\n", r); @@ -3376,7 +4540,7 @@ static void test_EM_REPLACESEL(int redraw) r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\r"); ok(5 == r /* WinXP */ || 3 == r /* Win98 */, "EM_REPLACESEL returned %d, expected 5 or 3\n", r); @@ -3399,7 +4563,7 @@ static void test_EM_REPLACESEL(int redraw) r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\rX\r\n\r\r"); ok(6 == r /* WinXP */ || 5 == r /* Win98 */, "EM_REPLACESEL returned %d, expected 6 or 5\n", r); @@ -3422,7 +4586,7 @@ static void test_EM_REPLACESEL(int redraw) r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n"); ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r); r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr); @@ -3444,7 +4608,7 @@ static void test_EM_REPLACESEL(int redraw) r = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n\n\n\r\r\r\r\n"); ok(9 == r /* WinXP */ || 7 == r /* Win98 */, "EM_REPLACESEL returned %d, expected 9 or 7\n", r); @@ -3487,11 +4651,15 @@ static void test_WM_PASTE(void) const char* text3 = "testing paste\r\npaste\r\ntesting paste"; HWND hwndRichEdit = new_richedit(NULL); - /* Native riched20 won't obey WM_CHAR messages or WM_KEYDOWN/WM_KEYUP - messages, probably because it inspects the keyboard state itself. - Therefore, native requires this in order to obey Ctrl- keystrokes. + /* Native riched20 inspects the keyboard state (e.g. GetKeyState) + * to test the state of the modifiers (Ctrl/Alt/Shift). + * + * Therefore Ctrl- keystrokes need to be simulated with + * keybd_event or by using SetKeyboardState to set the modifiers + * and SendMessage to simulate the keystrokes. */ + /* Sent keystrokes with keybd_event */ #define SEND_CTRL_C(hwnd) pressKeyWithModifier(hwnd, VK_CONTROL, 'C') #define SEND_CTRL_X(hwnd) pressKeyWithModifier(hwnd, VK_CONTROL, 'X') #define SEND_CTRL_V(hwnd) pressKeyWithModifier(hwnd, VK_CONTROL, 'V') @@ -3508,13 +4676,14 @@ static void test_WM_PASTE(void) /* Pasted text should be visible at this step */ result = strcmp(text1_step1, buffer); ok(result == 0, - "test paste: strcmp = %i\n", result); + "test paste: strcmp = %i, text='%s'\n", result, buffer); + SEND_CTRL_Z(hwndRichEdit); /* Undo */ SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); /* Text should be the same as before (except for \r -> \r\n conversion) */ result = strcmp(text1_after, buffer); ok(result == 0, - "test paste: strcmp = %i\n", result); + "test paste: strcmp = %i, text='%s'\n", result, buffer); SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2); SendMessage(hwndRichEdit, EM_SETSEL, 8, 13); @@ -3539,51 +4708,181 @@ static void test_WM_PASTE(void) ok(result == 0, "test paste: strcmp = %i\n", result); +#undef SEND_CTRL_C +#undef SEND_CTRL_X +#undef SEND_CTRL_V +#undef SEND_CTRL_Z +#undef SEND_CTRL_Y + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + /* Send WM_CHAR to simulates Ctrl-V */ + SendMessage(hwndRichEdit, WM_CHAR, 22, + (MapVirtualKey('V', MAPVK_VK_TO_VSC) << 16) & 1); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + /* Shouldn't paste because pasting is handled by WM_KEYDOWN */ + result = strcmp(buffer,""); + ok(result == 0, + "test paste: strcmp = %i, actual = '%s'\n", result, buffer); + + /* Send keystrokes with WM_KEYDOWN after setting the modifiers + * with SetKeyboard state. */ + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + /* Simulates paste (Ctrl-V) */ + hold_key(VK_CONTROL); + SendMessage(hwndRichEdit, WM_KEYDOWN, 'V', + (MapVirtualKey('V', MAPVK_VK_TO_VSC) << 16) & 1); + release_key(VK_CONTROL); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp(buffer,"paste"); + ok(result == 0, + "test paste: strcmp = %i, actual = '%s'\n", result, buffer); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text1); + SendMessage(hwndRichEdit, EM_SETSEL, 0, 7); + /* Simulates copy (Ctrl-C) */ + hold_key(VK_CONTROL); + SendMessage(hwndRichEdit, WM_KEYDOWN, 'C', + (MapVirtualKey('C', MAPVK_VK_TO_VSC) << 16) & 1); + release_key(VK_CONTROL); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + SendMessage(hwndRichEdit, WM_PASTE, 0, 0); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp(buffer,"testing"); + ok(result == 0, + "test paste: strcmp = %i, actual = '%s'\n", result, buffer); + + /* Cut with WM_KEYDOWN to simulate Ctrl-X */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "cut"); + /* Simulates select all (Ctrl-A) */ + hold_key(VK_CONTROL); + SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', + (MapVirtualKey('A', MAPVK_VK_TO_VSC) << 16) & 1); + /* Simulates select cut (Ctrl-X) */ + SendMessage(hwndRichEdit, WM_KEYDOWN, 'X', + (MapVirtualKey('X', MAPVK_VK_TO_VSC) << 16) & 1); + release_key(VK_CONTROL); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp(buffer,""); + ok(result == 0, + "test paste: strcmp = %i, actual = '%s'\n", result, buffer); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0); + SendMessage(hwndRichEdit, WM_PASTE, 0, 0); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp(buffer,"cut\r\n"); + todo_wine ok(result == 0, + "test paste: strcmp = %i, actual = '%s'\n", result, buffer); + /* Simulates undo (Ctrl-Z) */ + hold_key(VK_CONTROL); + SendMessage(hwndRichEdit, WM_KEYDOWN, 'Z', + (MapVirtualKey('Z', MAPVK_VK_TO_VSC) << 16) & 1); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp(buffer,""); + ok(result == 0, + "test paste: strcmp = %i, actual = '%s'\n", result, buffer); + /* Simulates redo (Ctrl-Y) */ + SendMessage(hwndRichEdit, WM_KEYDOWN, 'Y', + (MapVirtualKey('Y', MAPVK_VK_TO_VSC) << 16) & 1); + SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + result = strcmp(buffer,"cut\r\n"); + todo_wine ok(result == 0, + "test paste: strcmp = %i, actual = '%s'\n", result, buffer); + release_key(VK_CONTROL); + DestroyWindow(hwndRichEdit); } static void test_EM_FORMATRANGE(void) { - int r; - FORMATRANGE fr; + int i, tpp_x, tpp_y; HDC hdc; HWND hwndRichEdit = new_richedit(NULL); - - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack); + static const struct { + const char *string; /* The string */ + int first; /* First 'pagebreak', 0 for don't care */ + int second; /* Second 'pagebreak', 0 for don't care */ + } fmtstrings[] = { + {"WINE wine", 0, 0}, + {"WINE wineWine", 0, 0}, + {"WINE\r\nwine\r\nwine", 5, 10}, + {"WINE\r\nWINEwine\r\nWINEwine", 5, 14}, + {"WINE\r\n\r\nwine\r\nwine", 5, 6} + }; hdc = GetDC(hwndRichEdit); ok(hdc != NULL, "Could not get HDC\n"); + /* Calculate the twips per pixel */ + tpp_x = 1440 / GetDeviceCaps(hdc, LOGPIXELSX); + tpp_y = 1440 / GetDeviceCaps(hdc, LOGPIXELSY); + + SendMessage(hwndRichEdit, EM_FORMATRANGE, FALSE, 0); + + for (i = 0; i < sizeof(fmtstrings)/sizeof(fmtstrings[0]); i++) + { + FORMATRANGE fr; + GETTEXTLENGTHEX gtl; + SIZE stringsize; + int r, len; + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) fmtstrings[i].string); + + gtl.flags = GTL_NUMCHARS | GTL_PRECISE; + gtl.codepage = CP_ACP; + len = SendMessageA(hwndRichEdit, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + + /* Get some size information for the string */ + GetTextExtentPoint32(hdc, fmtstrings[i].string, strlen(fmtstrings[i].string), &stringsize); + + /* Define the box to be half the width needed and a bit larger than the height. + * Changes to the width means we have at least 2 pages. Changes to the height + * is done so we can check the changing of fr.rc.bottom. + */ fr.hdc = fr.hdcTarget = hdc; fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0; - fr.rc.right = fr.rcPage.right = GetDeviceCaps(hdc, HORZRES); - fr.rc.bottom = fr.rcPage.bottom = GetDeviceCaps(hdc, VERTRES); - fr.chrg.cpMin = 0; - fr.chrg.cpMax = 20; + fr.rc.right = fr.rcPage.right = (stringsize.cx / 2) * tpp_x; + fr.rc.bottom = fr.rcPage.bottom = (stringsize.cy + 10) * tpp_y; - r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL); + r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, 0); todo_wine { - ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r); + ok(r == len, "Expected %d, got %d\n", len, r); } + /* We know that the page can't hold the full string. See how many characters + * are on the first one + */ + fr.chrg.cpMin = 0; + fr.chrg.cpMax = -1; r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr); todo_wine { - ok(r == 20, "EM_FORMATRANGE expect %d, got %d\n", 20, r); + ok(fr.rc.bottom == (stringsize.cy * tpp_y), "Expected bottom to be %d, got %d\n", (stringsize.cy * tpp_y), fr.rc.bottom); } + if (fmtstrings[i].first) + todo_wine { + ok(r == fmtstrings[i].first, "Expected %d, got %d\n", fmtstrings[i].first, r); + } + else + ok(r < len, "Expected < %d, got %d\n", len, r); - fr.chrg.cpMin = 0; - fr.chrg.cpMax = 10; - + /* Do another page */ + fr.chrg.cpMin = r; r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr); + if (fmtstrings[i].second) todo_wine { - ok(r == 10, "EM_FORMATRANGE expect %d, got %d\n", 10, r); - } - - r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL); - todo_wine { - ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r); + ok(r == fmtstrings[i].second, "Expected %d, got %d\n", fmtstrings[i].second, r); + } + else + ok (r < len, "Expected < %d, got %d\n", len, r); + + /* There is at least on more page, but we don't care */ + + r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, 0); + todo_wine { + ok(r == len, "Expected %d, got %d\n", len, r); + } } + ReleaseDC(NULL, hdc); DestroyWindow(hwndRichEdit); } @@ -3668,26 +4967,26 @@ static void test_EM_STREAMIN(void) const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}"; const char * streamText1 = - "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" \ - "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" \ + "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" + "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" "}\r\n"; /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */ const char * streamText2 = - "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" \ - "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" \ - "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " \ - "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " \ - "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " \ - "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " \ + "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" + "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" + "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " + "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " + "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " + "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }"; const char * streamText3 = "RichEdit1"; struct StringWithLength cookieForStream4; const char * streamText4 = - "This text just needs to be long enough to cause run to be split onto "\ - "two seperate lines and make sure the null terminating character is "\ + "This text just needs to be long enough to cause run to be split onto " + "two separate lines and make sure the null terminating character is " "handled properly.\0"; int length4 = strlen(streamText4) + 1; cookieForStream4.buffer = (char *)streamText4; @@ -3880,9 +5179,7 @@ static void test_unicode_conversions(void) char bufA[64]; WCHAR bufW[64]; HWND hwnd; - int is_win9x, em_settextex_supported, ret; - - is_win9x = GetVersion() & 0x80000000; + int em_settextex_supported, ret; #define set_textA(hwnd, wm_set_text, txt) \ do { \ @@ -4115,8 +5412,12 @@ static void test_EM_GETTEXTLENGTHEX(void) char buffer[64] = {0}; /* single line */ + if (!is_win9x) hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP, 0, 0, 200, 60, 0, 0, 0, 0); + else + hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP, + 0, 0, 200, 60, 0, 0, 0, 0); ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; @@ -4160,8 +5461,12 @@ static void test_EM_GETTEXTLENGTHEX(void) DestroyWindow(hwnd); /* multi line */ + if (!is_win9x) hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE, 0, 0, 200, 60, 0, 0, 0, 0); + else + hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP | ES_MULTILINE, + 0, 0, 200, 60, 0, 0, 0, 0); ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; @@ -4233,7 +5538,7 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam static void test_eventMask(void) { HWND parent; - int ret; + int ret, style; WNDCLASSA cls; const char text[] = "foo bar\n"; int eventMask; @@ -4245,7 +5550,7 @@ static void test_eventMask(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "EventMaskParentClass"; @@ -4274,6 +5579,38 @@ static void test_eventMask(void) ok(queriedEventMask == (eventMask & ~ENM_CHANGE), "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); + /* check to see if EN_CHANGE is sent when redraw is turned off */ + SendMessage(eventMaskEditHwnd, WM_CLEAR, 0, 0); + ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); + SendMessage(eventMaskEditHwnd, WM_SETREDRAW, FALSE, 0); + /* redraw is disabled by making the window invisible. */ + ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n"); + queriedEventMask = 0; /* initialize to something other than we expect */ + SendMessage(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM) text); + ok(queriedEventMask == (eventMask & ~ENM_CHANGE), + "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); + SendMessage(eventMaskEditHwnd, WM_SETREDRAW, TRUE, 0); + ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); + + /* check to see if EN_UPDATE is sent when the editor isn't visible */ + SendMessage(eventMaskEditHwnd, WM_CLEAR, 0, 0); + style = GetWindowLong(eventMaskEditHwnd, GWL_STYLE); + SetWindowLong(eventMaskEditHwnd, GWL_STYLE, style & ~WS_VISIBLE); + ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n"); + watchForEventMask = EN_UPDATE; + queriedEventMask = 0; /* initialize to something other than we expect */ + SendMessage(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM) text); + ok(queriedEventMask == 0, + "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); + SetWindowLong(eventMaskEditHwnd, GWL_STYLE, style); + ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n"); + queriedEventMask = 0; /* initialize to something other than we expect */ + SendMessage(eventMaskEditHwnd, EM_REPLACESEL, 0, (LPARAM) text); + ok(queriedEventMask == eventMask, + "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask); + + + DestroyWindow(parent); } static int received_WM_NOTIFY = 0; @@ -4303,7 +5640,7 @@ static void test_WM_NOTIFY(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "WM_NOTIFY_ParentClass"; @@ -4349,6 +5686,14 @@ static void test_WM_NOTIFY(void) ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n"); + /* Test for WM_NOTIFY messages with redraw disabled. */ + SendMessage(hwndRichedit_WM_NOTIFY, EM_SETSEL, 0, 0); + SendMessage(hwndRichedit_WM_NOTIFY, WM_SETREDRAW, FALSE, 0); + received_WM_NOTIFY = 0; + SendMessage(hwndRichedit_WM_NOTIFY, EM_REPLACESEL, FALSE, (LPARAM)"inserted"); + ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n"); + SendMessage(hwndRichedit_WM_NOTIFY, WM_SETREDRAW, TRUE, 0); + DestroyWindow(hwndRichedit_WM_NOTIFY); DestroyWindow(parent); } @@ -4360,8 +5705,12 @@ static void test_undo_coalescing(void) char buffer[64] = {0}; /* multi-line control inserts CR normally */ + if (!is_win9x) hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE, 0, 0, 200, 60, 0, 0, 0, 0); + else + hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP|ES_MULTILINE, + 0, 0, 200, 60, 0, 0, 0, 0); ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError()); result = SendMessage(hwnd, EM_CANUNDO, 0, 0); @@ -4403,8 +5752,8 @@ static void test_undo_coalescing(void) simulate_typing_characters(hwnd, "one two three"); result = SendMessage(hwnd, EM_CANREDO, 0, 0); ok (result == FALSE, "Redo buffer should have been cleared by typing.\n"); - SendMessage(hwnd, WM_KILLFOCUS, (WPARAM)NULL, 0); - SendMessage(hwnd, WM_SETFOCUS, (WPARAM)NULL, 0); + SendMessage(hwnd, WM_KILLFOCUS, 0, 0); + SendMessage(hwnd, WM_SETFOCUS, 0, 0); simulate_typing_characters(hwnd, " four five six"); result = SendMessage(hwnd, EM_UNDO, 0, 0); ok (result == TRUE, "Failed to undo typed characters.\n"); @@ -4471,6 +5820,43 @@ static void test_undo_coalescing(void) DestroyWindow(hwnd); } +static LONG CALLBACK customWordBreakProc(WCHAR *text, int pos, int bytes, int code) +{ + int length; + + /* MSDN lied, length is actually the number of bytes. */ + length = bytes / sizeof(WCHAR); + switch(code) + { + case WB_ISDELIMITER: + return text[pos] == 'X'; + case WB_LEFT: + case WB_MOVEWORDLEFT: + if (customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) + return pos-1; + return min(customWordBreakProc(text, pos, bytes, WB_LEFTBREAK)-1, 0); + case WB_LEFTBREAK: + pos--; + while (pos > 0 && !customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) + pos--; + return pos; + case WB_RIGHT: + case WB_MOVEWORDRIGHT: + if (customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) + return pos+1; + return min(customWordBreakProc(text, pos, bytes, WB_RIGHTBREAK)+1, length); + case WB_RIGHTBREAK: + pos++; + while (pos < length && !customWordBreakProc(text, pos, bytes, WB_ISDELIMITER)) + pos++; + return pos; + default: + ok(FALSE, "Unexpected code %d\n", code); + break; + } + return 0; +} + #define SEND_CTRL_LEFT(hwnd) pressKeyWithModifier(hwnd, VK_CONTROL, VK_LEFT) #define SEND_CTRL_RIGHT(hwnd) pressKeyWithModifier(hwnd, VK_CONTROL, VK_RIGHT) @@ -4479,6 +5865,7 @@ static void test_word_movement(void) HWND hwnd; int result; int sel_start, sel_end; + const WCHAR textW[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0}; /* multi-line control inserts CR normally */ hwnd = new_richedit(NULL); @@ -4492,25 +5879,25 @@ static void test_word_movement(void) /* one |two three */ SendMessage(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); ok(sel_start == sel_end, "Selection should be empty\n"); - ok(sel_start == 4, "Cursur is at %d instead of %d\n", sel_start, 4); + ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4); SEND_CTRL_RIGHT(hwnd); /* one two |three */ SendMessage(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); ok(sel_start == sel_end, "Selection should be empty\n"); - ok(sel_start == 9, "Cursur is at %d instead of %d\n", sel_start, 9); + ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); SEND_CTRL_LEFT(hwnd); /* one |two three */ SendMessage(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); ok(sel_start == sel_end, "Selection should be empty\n"); - ok(sel_start == 4, "Cursur is at %d instead of %d\n", sel_start, 4); + ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4); SEND_CTRL_LEFT(hwnd); /* |one two three */ SendMessage(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); ok(sel_start == sel_end, "Selection should be empty\n"); - ok(sel_start == 0, "Cursur is at %d instead of %d\n", sel_start, 0); + ok(sel_start == 0, "Cursor is at %d instead of %d\n", sel_start, 0); SendMessage(hwnd, EM_SETSEL, 8, 8); /* one two | three */ @@ -4518,7 +5905,7 @@ static void test_word_movement(void) /* one two |three */ SendMessage(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); ok(sel_start == sel_end, "Selection should be empty\n"); - ok(sel_start == 9, "Cursur is at %d instead of %d\n", sel_start, 9); + ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); SendMessage(hwnd, EM_SETSEL, 11, 11); /* one two th|ree */ @@ -4526,7 +5913,43 @@ static void test_word_movement(void) /* one two |three */ SendMessage(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); ok(sel_start == sel_end, "Selection should be empty\n"); - ok(sel_start == 9, "Cursur is at %d instead of %d\n", sel_start, 9); + ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9); + + /* Test with a custom word break procedure that uses X as the delimiter. */ + result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one twoXthree"); + ok (result == TRUE, "Failed to clear the text.\n"); + SendMessage(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)customWordBreakProc); + /* |one twoXthree */ + SEND_CTRL_RIGHT(hwnd); + /* one twoX|three */ + SendMessage(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); + ok(sel_start == sel_end, "Selection should be empty\n"); + ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8); + + DestroyWindow(hwnd); + + /* Make sure the behaviour is the same with a unicode richedit window, + * and using unicode functions. */ + if (is_win9x) + { + skip("Cannot test with unicode richedit window\n"); + return; +} + + hwnd = CreateWindowW(RICHEDIT_CLASS20W, NULL, + ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + + /* Test with a custom word break procedure that uses X as the delimiter. */ + result = SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW); + ok (result == TRUE, "Failed to clear the text.\n"); + SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0, (LPARAM)customWordBreakProc); + /* |one twoXthree */ + SEND_CTRL_RIGHT(hwnd); + /* one twoX|three */ + SendMessageW(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); + ok(sel_start == sel_end, "Selection should be empty\n"); + ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8); DestroyWindow(hwnd); } @@ -4535,36 +5958,713 @@ static void test_EM_CHARFROMPOS(void) { HWND hwnd; int result; + RECT rcClient; POINTL point; point.x = 0; - point.y = 50; + point.y = 40; /* multi-line control inserts CR normally */ hwnd = new_richedit(NULL); result = SendMessageA(hwnd, WM_SETTEXT, 0, - (LPARAM)"one two three four five six seven"); + (LPARAM)"one two three four five six seven\reight"); + + GetClientRect(hwnd, &rcClient); result = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); - ok(result == 0, "expected character index of 0 but got %d\n", result); + ok(result == 34, "expected character index of 34 but got %d\n", result); + + /* Test with points outside the bounds of the richedit control. */ + point.x = -1; + point.y = 40; + result = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); + todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result); + + point.x = 1000; + point.y = 0; + result = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); + todo_wine ok(result == 33, "expected character index of 33 but got %d\n", result); + + point.x = 1000; + point.y = 40; + result = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); + todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result); + + point.x = 1000; + point.y = -1; + result = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); + todo_wine ok(result == 0, "expected character index of 0 but got %d\n", result); + + point.x = 1000; + point.y = rcClient.bottom + 1; + result = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); + todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result); + + point.x = 1000; + point.y = rcClient.bottom; + result = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&point); + todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result); + + DestroyWindow(hwnd); +} + +static void test_word_wrap(void) +{ + HWND hwnd; + POINTL point = {0, 60}; /* This point must be below the first line */ + const char *text = "Must be long enough to test line wrapping"; + DWORD dwCommonStyle = WS_VISIBLE|WS_POPUP|WS_VSCROLL|ES_MULTILINE; + int res, pos, lines; + + /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping + * when specified on window creation and set later. */ + hwnd = CreateWindow(RICHEDIT_CLASS, NULL, dwCommonStyle, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text); + ok(res, "WM_SETTEXT failed.\n"); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); + + SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); + DestroyWindow(hwnd); + + hwnd = CreateWindow(RICHEDIT_CLASS, NULL, dwCommonStyle|WS_HSCROLL, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + + res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text); + ok(res, "WM_SETTEXT failed.\n"); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines); + + SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + DestroyWindow(hwnd); + + hwnd = CreateWindow(RICHEDIT_CLASS, NULL, dwCommonStyle|ES_AUTOHSCROLL, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text); + ok(res, "WM_SETTEXT failed.\n"); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + + SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + DestroyWindow(hwnd); + + hwnd = CreateWindow(RICHEDIT_CLASS, NULL, + dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text); + ok(res, "WM_SETTEXT failed.\n"); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + + SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + + /* Test the effect of EM_SETTARGETDEVICE on word wrap. */ + res = SendMessage(hwnd, EM_SETTARGETDEVICE, 0, 1); + ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + + res = SendMessage(hwnd, EM_SETTARGETDEVICE, 0, 0); + ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); + DestroyWindow(hwnd); + + /* Test to see if wrapping happens with redraw disabled. */ + hwnd = CreateWindow(RICHEDIT_CLASS, NULL, dwCommonStyle, + 0, 0, 400, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + res = SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) text); + ok(res, "EM_REPLACESEL failed.\n"); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines); + MoveWindow(hwnd, 0, 0, 200, 80, FALSE); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); + + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + DestroyWindow(hwnd); +} + +static void test_autoscroll(void) +{ + HWND hwnd = new_richedit(NULL); + int lines, ret, redraw; + POINT pt; + + for (redraw = 0; redraw <= 1; redraw++) { + trace("testing with WM_SETREDRAW=%d\n", redraw); + SendMessage(hwnd, WM_SETREDRAW, redraw, 0); + SendMessage(hwnd, EM_REPLACESEL, 0, (LPARAM)"1\n2\n3\n4\n5\n6\n7\n8"); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines == 8, "%d lines instead of 8\n", lines); + ret = SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM)&pt); + ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret); + ok(pt.y != 0, "Didn't scroll down after replacing text.\n"); + ret = GetWindowLong(hwnd, GWL_STYLE); + ok(ret & WS_VSCROLL, "Scrollbar was not shown yet (style=%x).\n", (UINT)ret); + + SendMessage(hwnd, WM_SETTEXT, 0, 0); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines == 1, "%d lines instead of 1\n", lines); + ret = SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM)&pt); + ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret); + ok(pt.y == 0, "y scroll position is %d after clearing text.\n", pt.y); + ret = GetWindowLong(hwnd, GWL_STYLE); + ok(!(ret & WS_VSCROLL), "Scrollbar is still shown (style=%x).\n", (UINT)ret); + } + + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + DestroyWindow(hwnd); + + /* The WS_VSCROLL and WS_HSCROLL styles implicitly set + * auto vertical/horizontal scrolling options. */ + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + WS_POPUP|ES_MULTILINE|WS_VSCROLL|WS_HSCROLL, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + ret = SendMessage(hwnd, EM_GETOPTIONS, 0, 0); + ok(ret & ECO_AUTOVSCROLL, "ECO_AUTOVSCROLL isn't set.\n"); + ok(ret & ECO_AUTOHSCROLL, "ECO_AUTOHSCROLL isn't set.\n"); + ret = GetWindowLong(hwnd, GWL_STYLE); + ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n"); + ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n"); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + WS_POPUP|ES_MULTILINE, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + ret = SendMessage(hwnd, EM_GETOPTIONS, 0, 0); + ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n"); + ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n"); + ret = GetWindowLong(hwnd, GWL_STYLE); + ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n"); + ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n"); + DestroyWindow(hwnd); +} + + +static void test_format_rect(void) +{ + HWND hwnd; + RECT rc, expected, clientRect; + int n; + DWORD options; + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + + GetClientRect(hwnd, &clientRect); + + expected = clientRect; + expected.left += 1; + expected.right -= 1; + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + for (n = -3; n <= 3; n++) + { + rc = clientRect; + rc.top += n; + rc.left += n; + rc.bottom -= n; + rc.right -= n; + SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); + + expected = rc; + expected.top = max(0, rc.top); + expected.left = max(0, rc.left); + expected.bottom = min(clientRect.bottom, rc.bottom); + expected.right = min(clientRect.right, rc.right); + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + n, rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + } + + rc = clientRect; + SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); + expected = clientRect; + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + /* Adding the selectionbar adds the selectionbar width to the left side. */ + SendMessageA(hwnd, EM_SETOPTIONS, ECOOP_OR, ECO_SELECTIONBAR); + options = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); + ok(options & ECO_SELECTIONBAR, "EM_SETOPTIONS failed to add selectionbar.\n"); + expected.left += 8; /* selection bar width */ + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + rc = clientRect; + SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); + expected = clientRect; + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + /* Removing the selectionbar subtracts the selectionbar width from the left side, + * even if the left side is already 0. */ + SendMessageA(hwnd, EM_SETOPTIONS, ECOOP_AND, ~ECO_SELECTIONBAR); + options = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0); + ok(!(options & ECO_SELECTIONBAR), "EM_SETOPTIONS failed to remove selectionbar.\n"); + expected.left -= 8; /* selection bar width */ + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + /* Set the absolute value of the formatting rectangle. */ + rc = clientRect; + SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); + expected = clientRect; + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + n, rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + /* MSDN documents the EM_SETRECT message as using the rectangle provided in + * LPARAM as being a relative offset when the WPARAM value is 1, but these + * tests show that this isn't true. */ + rc.top = 15; + rc.left = 15; + rc.bottom = clientRect.bottom - 15; + rc.right = clientRect.right - 15; + expected = rc; + SendMessageA(hwnd, EM_SETRECT, 1, (LPARAM)&rc); + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + /* For some reason it does not limit the values to the client rect with + * a WPARAM value of 1. */ + rc.top = -15; + rc.left = -15; + rc.bottom = clientRect.bottom + 15; + rc.right = clientRect.right + 15; + expected = rc; + SendMessageA(hwnd, EM_SETRECT, 1, (LPARAM)&rc); + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + DestroyWindow(hwnd); + + /* The extended window style affects the formatting rectangle. */ + hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_POPUP|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + + GetClientRect(hwnd, &clientRect); + + expected = clientRect; + expected.left += 1; + expected.top += 1; + expected.right -= 1; + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + rc = clientRect; + rc.top += 5; + rc.left += 5; + rc.bottom -= 5; + rc.right -= 5; + expected = rc; + expected.top -= 1; + expected.left -= 1; + expected.right += 1; + SendMessageA(hwnd, EM_SETRECT, 0, (LPARAM)&rc); + SendMessageA(hwnd, EM_GETRECT, 0, (LPARAM)&rc); + ok(rc.top == expected.top && rc.left == expected.left && + rc.bottom == expected.bottom && rc.right == expected.right, + "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n", + rc.top, rc.left, rc.bottom, rc.right, + expected.top, expected.left, expected.bottom, expected.right); + + DestroyWindow(hwnd); +} + +static void test_WM_GETDLGCODE(void) +{ + HWND hwnd; + UINT res, expected; + MSG msg; + + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_MULTILINE|ES_WANTRETURN|WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, 0); + expected = expected | DLGC_WANTMESSAGE; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + msg.message = WM_KEYDOWN; + msg.wParam = VK_RETURN; + msg.lParam = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC) | 0x0001; + msg.pt.x = 0; + msg.pt.y = 0; + msg.time = GetTickCount(); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_MULTILINE|ES_WANTRETURN|WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = expected | DLGC_WANTMESSAGE; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_WANTRETURN|WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + msg.wParam = VK_TAB; + msg.lParam = MapVirtualKey(VK_TAB, MAPVK_VK_TO_VSC) | 0x0001; + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + hold_key(VK_CONTROL); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + release_key(VK_CONTROL); + + msg.wParam = 'a'; + msg.lParam = MapVirtualKey('a', MAPVK_VK_TO_VSC) | 0x0001; + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + msg.message = WM_CHAR; + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + ES_MULTILINE|WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL|DLGC_WANTMESSAGE; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + msg.hwnd = hwnd; + res = SendMessage(hwnd, WM_GETDLGCODE, VK_RETURN, (LPARAM)&msg); + expected = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; + ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n", + res, expected); + DestroyWindow(hwnd); +} + +static void test_zoom(void) +{ + HWND hwnd; + UINT ret; + RECT rc; + POINT pt; + int numerator, denominator; + + hwnd = new_richedit(NULL); + GetClientRect(hwnd, &rc); + pt.x = (rc.right - rc.left) / 2; + pt.y = (rc.bottom - rc.top) / 2; + ClientToScreen(hwnd, &pt); + + /* Test initial zoom value */ + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 0, "Numerator should be initialized to 0 (got %d).\n", numerator); + ok(denominator == 0, "Denominator should be initialized to 0 (got %d).\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + /* test scroll wheel */ + hold_key(VK_CONTROL); + ret = SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), + MAKELPARAM(pt.x, pt.y)); + ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); + release_key(VK_CONTROL); + + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 110, "incorrect numerator is %d\n", numerator); + ok(denominator == 100, "incorrect denominator is %d\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + /* Test how much the mouse wheel can zoom in and out. */ + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)490, (LPARAM)100); + ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); + + hold_key(VK_CONTROL); + ret = SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), + MAKELPARAM(pt.x, pt.y)); + ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); + release_key(VK_CONTROL); + + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 500, "incorrect numerator is %d\n", numerator); + ok(denominator == 100, "incorrect denominator is %d\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)491, (LPARAM)100); + ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); + + hold_key(VK_CONTROL); + ret = SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), + MAKELPARAM(pt.x, pt.y)); + ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); + release_key(VK_CONTROL); + + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 491, "incorrect numerator is %d\n", numerator); + ok(denominator == 100, "incorrect denominator is %d\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)20, (LPARAM)100); + ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); + + hold_key(VK_CONTROL); + ret = SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, -WHEEL_DELTA), + MAKELPARAM(pt.x, pt.y)); + ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); + release_key(VK_CONTROL); + + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 10, "incorrect numerator is %d\n", numerator); + ok(denominator == 100, "incorrect denominator is %d\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)19, (LPARAM)100); + ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); + + hold_key(VK_CONTROL); + ret = SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, -WHEEL_DELTA), + MAKELPARAM(pt.x, pt.y)); + ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); + release_key(VK_CONTROL); + + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 19, "incorrect numerator is %d\n", numerator); + ok(denominator == 100, "incorrect denominator is %d\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + /* Test how WM_SCROLLWHEEL treats our custom denominator. */ + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)50, (LPARAM)13); + ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); + + hold_key(VK_CONTROL); + ret = SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(MK_CONTROL, WHEEL_DELTA), + MAKELPARAM(pt.x, pt.y)); + ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret); + release_key(VK_CONTROL); + + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 394, "incorrect numerator is %d\n", numerator); + ok(denominator == 100, "incorrect denominator is %d\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + /* Test bounds checking on EM_SETZOOM */ + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)2, (LPARAM)127); + ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret); + + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)127, (LPARAM)2); + ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret); + + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)2, (LPARAM)128); + ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); + + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 127, "incorrect numerator is %d\n", numerator); + ok(denominator == 2, "incorrect denominator is %d\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)128, (LPARAM)2); + ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); + + /* See if negative numbers are accepted. */ + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)-100, (LPARAM)-100); + ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret); + + /* See if negative numbers are accepted. */ + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)0, (LPARAM)100); + ok(ret == FALSE, "EM_SETZOOM failed (%d).\n", ret); + + ret = SendMessage(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator); + ok(numerator == 127, "incorrect numerator is %d\n", numerator); + ok(denominator == 2, "incorrect denominator is %d\n", denominator); + ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret); + + /* Reset the zoom value */ + ret = SendMessage(hwnd, EM_SETZOOM, (WPARAM)0, (LPARAM)0); + ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret); DestroyWindow(hwnd); } START_TEST( editor ) { - MSG msg; - time_t end; - /* Must explicitly LoadLibrary(). The test has no references to functions in * RICHED20.DLL, so the linker doesn't actually link to it. */ hmoduleRichEdit = LoadLibrary("RICHED20.DLL"); ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError()); + + is_win9x = GetVersion() & 0x80000000; + test_WM_CHAR(); test_EM_FINDTEXT(); test_EM_GETLINE(); test_EM_POSFROMCHAR(); test_EM_SCROLLCARET(); test_EM_SCROLL(); + test_scrollbar_visibility(); test_WM_SETTEXT(); test_EM_LINELENGTH(); test_EM_SETCHARFORMAT(); @@ -4586,6 +6686,7 @@ START_TEST( editor ) test_WM_PASTE(); test_EM_STREAMIN(); test_EM_STREAMOUT(); + test_EM_STREAMOUT_FONTTBL(); test_EM_StreamIn_Undo(); test_EM_FORMATRANGE(); test_unicode_conversions(); @@ -4598,23 +6699,19 @@ START_TEST( editor ) test_undo_coalescing(); test_word_movement(); test_EM_CHARFROMPOS(); + test_SETPARAFORMAT(); + test_word_wrap(); + test_autoscroll(); + test_format_rect(); + test_WM_GETDLGCODE(); + test_zoom(); /* Set the environment variable WINETEST_RICHED20 to keep windows * responsive and open for 30 seconds. This is useful for debugging. - * - * The message pump uses PeekMessage() to empty the queue and then sleeps for - * 50ms before retrying the queue. */ - end = time(NULL) + 30; + */ if (getenv( "WINETEST_RICHED20" )) { - while (time(NULL) < end) { - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } else { - Sleep(50); + keep_responsive(30); } - } - } OleFlushClipboard(); ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError()); diff --git a/rostests/winetests/riched20/riched20.rbuild b/rostests/winetests/riched20/riched20.rbuild index edd64974862..a1515c64a48 100644 --- a/rostests/winetests/riched20/riched20.rbuild +++ b/rostests/winetests/riched20/riched20.rbuild @@ -3,17 +3,17 @@ . - 0x600 - 0x600 + editor.c richole.c testlist.c + txtsrv.c wine uuid ole32 + oleaut32 user32 gdi32 - kernel32 ntdll diff --git a/rostests/winetests/riched20/richole.c b/rostests/winetests/riched20/richole.c index f6c2928e3d0..6eefdd0ffb5 100644 --- a/rostests/winetests/riched20/richole.c +++ b/rostests/winetests/riched20/richole.c @@ -26,17 +26,13 @@ #include #include #include +#include #include #include #include #include #include -#include -DEFINE_GUID(IID_ITextDocument, 0x8cc497c0, 0xa1df, 0x11ce, 0x80, 0x98, 0x00, 0xaa, 0x00, 0x47, 0xbe, 0x5d); -DEFINE_GUID(IID_ITextRange, 0x8cc497c2, 0xa1df, 0x11ce, 0x80, 0x98, 0x00, 0xaa, 0x00, 0x47, 0xbe, 0x5d); -DEFINE_GUID(IID_ITextSelection, 0x8cc497c1, 0xa1df, 0x11ce, 0x80, 0x98, 0x00, 0xaa, 0x00, 0x47, 0xbe, 0x5d); - static HMODULE hmoduleRichEdit; static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) diff --git a/rostests/winetests/riched20/testlist.c b/rostests/winetests/riched20/testlist.c index b9d14484609..621cb423de0 100644 --- a/rostests/winetests/riched20/testlist.c +++ b/rostests/winetests/riched20/testlist.c @@ -7,11 +7,11 @@ #include "wine/test.h" extern void func_editor(void); -extern void func_richole(void); +extern void func_txtsrv(void); const struct test winetest_testlist[] = { { "editor", func_editor }, - { "richole", func_richole }, + { "txtsrv", func_txtsrv }, { 0, 0 } }; diff --git a/rostests/winetests/riched20/txtsrv.c b/rostests/winetests/riched20/txtsrv.c new file mode 100644 index 00000000000..e4d6ae44822 --- /dev/null +++ b/rostests/winetests/riched20/txtsrv.c @@ -0,0 +1,761 @@ +/* + * Unit test suite for windowless rich edit controls + * + * Copyright 2008 Maarten Lankhorst + * Copyright 2008 Austin Lund + * Copyright 2008 Dylan Smith + * + * 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 + */ + +#define COBJMACROS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static HMODULE hmoduleRichEdit; + +/* Define C Macros for ITextServices calls. */ + +/* Use a special table for x86 machines to convert the thiscall + * calling convention. This isn't needed on other platforms. */ +#ifdef __i386__ +static ITextServicesVtbl itextServicesStdcallVtbl; +#define TXTSERV_VTABLE(This) (&itextServicesStdcallVtbl) +#else /* __i386__ */ +#define TXTSERV_VTABLE(This) (This)->lpVtbl +#endif /* __i386__ */ + +#define ITextServices_TxSendMessage(This,a,b,c,d) TXTSERV_VTABLE(This)->TxSendMessage(This,a,b,c,d) +#define ITextServices_TxDraw(This,a,b,c,d,e,f,g,h,i,j,k,l) TXTSERV_VTABLE(This)->TxDraw(This,a,b,c,d,e,f,g,h,i,j,k,l) +#define ITextServices_TxGetHScroll(This,a,b,c,d,e) TXTSERV_VTABLE(This)->TxGetHScroll(This,a,b,c,d,e) +#define ITextServices_TxGetVScroll(This,a,b,c,d,e) TXTSERV_VTABLE(This)->TxGetVScroll(This,a,b,c,d,e) +#define ITextServices_OnTxSetCursor(This,a,b,c,d,e,f,g,h,i) TXTSERV_VTABLE(This)->OnTxSetCursor(This,a,b,c,d,e,f,g,h,i) +#define ITextServices_TxQueryHitPoint(This,a,b,c,d,e,f,g,h,i,j) TXTSERV_VTABLE(This)->TxQueryHitPoint(This,a,b,c,d,e,f,g,h,i,j) +#define ITextServices_OnTxInplaceActivate(This,a) TXTSERV_VTABLE(This)->OnTxInplaceActivate(This,a) +#define ITextServices_OnTxInplaceDeactivate(This) TXTSERV_VTABLE(This)->OnTxInplaceDeactivate(This) +#define ITextServices_OnTxUIActivate(This) TXTSERV_VTABLE(This)->OnTxUIActivate(This) +#define ITextServices_OnTxUIDeactivate(This) TXTSERV_VTABLE(This)->OnTxUIDeactivate(This) +#define ITextServices_TxGetText(This,a) TXTSERV_VTABLE(This)->TxGetText(This,a) +#define ITextServices_TxSetText(This,a) TXTSERV_VTABLE(This)->TxSetText(This,a) +#define ITextServices_TxGetCurrentTargetX(This,a) TXTSERV_VTABLE(This)->TxGetCurrentTargetX(This,a) +#define ITextServices_TxGetBaseLinePos(This,a) TXTSERV_VTABLE(This)->TxGetBaseLinePos(This,a) +#define ITextServices_TxGetNaturalSize(This,a,b,c,d,e,f,g,h) TXTSERV_VTABLE(This)->TxGetNaturalSize(This,a,b,c,d,e,f,g,h) +#define ITextServices_TxGetDropTarget(This,a) TXTSERV_VTABLE(This)->TxGetDropTarget(This,a) +#define ITextServices_OnTxPropertyBitsChange(This,a,b) TXTSERV_VTABLE(This)->OnTxPropertyBitsChange(This,a,b) +#define ITextServices_TxGetCachedSize(This,a,b) TXTSERV_VTABLE(This)->TxGetCachedSize(This,a,b) + +/* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose + * function call traces of ITextHost. */ +#define TRACECALL if(winetest_debug > 1) trace + +/************************************************************************/ +/* ITextHost implementation for conformance testing. */ + +typedef struct ITextHostTestImpl +{ + ITextHostVtbl *lpVtbl; + LONG refCount; +} ITextHostTestImpl; + +static HRESULT WINAPI ITextHostImpl_QueryInterface(ITextHost *iface, + REFIID riid, + LPVOID *ppvObject) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_ITextHost)) { + *ppvObject = This; + ITextHost_AddRef((ITextHost *)*ppvObject); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI ITextHostImpl_AddRef(ITextHost *iface) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + return refCount; +} + +static ULONG WINAPI ITextHostImpl_Release(ITextHost *iface) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + if (!refCount) + { + CoTaskMemFree(This); + return 0; + } else { + return refCount; + } +} + +static HDC WINAPI ITextHostImpl_TxGetDC(ITextHost *iface) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetDC(%p)\n", This); + return NULL; +} + +static INT WINAPI ITextHostImpl_TxReleaseDC(ITextHost *iface, + HDC hdc) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxReleaseDC(%p)\n", This); + return 0; +} + +static BOOL WINAPI ITextHostImpl_TxShowScrollBar(ITextHost *iface, + INT fnBar, + BOOL fShow) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxShowScrollBar(%p, fnBar=%d, fShow=%d)\n", + This, fnBar, fShow); + return FALSE; +} + +static BOOL WINAPI ITextHostImpl_TxEnableScrollBar(ITextHost *iface, + INT fuSBFlags, + INT fuArrowflags) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxEnableScrollBar(%p, fuSBFlags=%d, fuArrowflags=%d)\n", + This, fuSBFlags, fuArrowflags); + return FALSE; +} + +static BOOL WINAPI ITextHostImpl_TxSetScrollRange(ITextHost *iface, + INT fnBar, + LONG nMinPos, + INT nMaxPos, + BOOL fRedraw) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxSetScrollRange(%p, fnBar=%d, nMinPos=%d, nMaxPos=%d, fRedraw=%d)\n", + This, fnBar, nMinPos, nMaxPos, fRedraw); + return FALSE; +} + +static BOOL WINAPI ITextHostImpl_TxSetScrollPos(ITextHost *iface, + INT fnBar, + INT nPos, + BOOL fRedraw) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxSetScrollPos(%p, fnBar=%d, nPos=%d, fRedraw=%d)\n", + This, fnBar, nPos, fRedraw); + return FALSE; +} + +static void WINAPI ITextHostImpl_TxInvalidateRect(ITextHost *iface, + LPCRECT prc, + BOOL fMode) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxInvalidateRect(%p, prc=%p, fMode=%d)\n", + This, prc, fMode); +} + +static void WINAPI ITextHostImpl_TxViewChange(ITextHost *iface, BOOL fUpdate) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxViewChange(%p, fUpdate=%d)\n", + This, fUpdate); +} + +static BOOL WINAPI ITextHostImpl_TxCreateCaret(ITextHost *iface, + HBITMAP hbmp, + INT xWidth, INT yHeight) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxCreateCaret(%p, nbmp=%p, xWidth=%d, yHeight=%d)\n", + This, hbmp, xWidth, yHeight); + return FALSE; +} + +static BOOL WINAPI ITextHostImpl_TxShowCaret(ITextHost *iface, BOOL fShow) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxShowCaret(%p, fShow=%d)\n", + This, fShow); + return FALSE; +} + +static BOOL WINAPI ITextHostImpl_TxSetCaretPos(ITextHost *iface, + INT x, INT y) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxSetCaretPos(%p, x=%d, y=%d)\n", This, x, y); + return FALSE; +} + +static BOOL WINAPI ITextHostImpl_TxSetTimer(ITextHost *iface, + UINT idTimer, UINT uTimeout) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxSetTimer(%p, idTimer=%u, uTimeout=%u)\n", + This, idTimer, uTimeout); + return FALSE; +} + +static void WINAPI ITextHostImpl_TxKillTimer(ITextHost *iface, UINT idTimer) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxKillTimer(%p, idTimer=%u)\n", This, idTimer); +} + +static void WINAPI ITextHostImpl_TxScrollWindowEx(ITextHost *iface, + INT dx, INT dy, + LPCRECT lprcScroll, + LPCRECT lprcClip, + HRGN hRgnUpdate, + LPRECT lprcUpdate, + UINT fuScroll) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxScrollWindowEx(%p, %d, %d, %p, %p, %p, %p, %d)\n", + This, dx, dy, lprcScroll, lprcClip, hRgnUpdate, lprcUpdate, fuScroll); +} + +static void WINAPI ITextHostImpl_TxSetCapture(ITextHost *iface, BOOL fCapture) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxSetCapture(%p, fCapture=%d)\n", This, fCapture); +} + +static void WINAPI ITextHostImpl_TxSetFocus(ITextHost *iface) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxSetFocus(%p)\n", This); +} + +static void WINAPI ITextHostImpl_TxSetCursor(ITextHost *iface, + HCURSOR hcur, + BOOL fText) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxSetCursor(%p, hcur=%p, fText=%d)\n", + This, hcur, fText); +} + +static BOOL WINAPI ITextHostImpl_TxScreenToClient(ITextHost *iface, + LPPOINT lppt) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxScreenToClient(%p, lppt=%p)\n", This, lppt); + return FALSE; +} + +static BOOL WINAPI ITextHostImpl_TxClientToScreen(ITextHost *iface, + LPPOINT lppt) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxClientToScreen(%p, lppt=%p)\n", This, lppt); + return FALSE; +} + +static HRESULT WINAPI ITextHostImpl_TxActivate(ITextHost *iface, + LONG *plOldState) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxActivate(%p, plOldState=%p)\n", This, plOldState); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxDeactivate(ITextHost *iface, + LONG lNewState) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxDeactivate(%p, lNewState=%d)\n", This, lNewState); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetClientRect(ITextHost *iface, + LPRECT prc) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetClientRect(%p, prc=%p)\n", This, prc); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetViewInset(ITextHost *iface, + LPRECT prc) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetViewInset(%p, prc=%p)\n", This, prc); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetCharFormat(ITextHost *iface, + const CHARFORMATW **ppCF) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetCharFormat(%p, ppCF=%p)\n", This, ppCF); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetParaFormat(ITextHost *iface, + const PARAFORMAT **ppPF) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetParaFormat(%p, ppPF=%p)\n", This, ppPF); + return E_NOTIMPL; +} + +static COLORREF WINAPI ITextHostImpl_TxGetSysColor(ITextHost *iface, + int nIndex) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetSysColor(%p, nIndex=%d)\n", This, nIndex); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetBackStyle(ITextHost *iface, + TXTBACKSTYLE *pStyle) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetBackStyle(%p, pStyle=%p)\n", This, pStyle); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetMaxLength(ITextHost *iface, + DWORD *pLength) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetMaxLength(%p, pLength=%p)\n", This, pLength); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetScrollBars(ITextHost *iface, + DWORD *pdwScrollBar) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetScrollBars(%p, pdwScrollBar=%p)\n", + This, pdwScrollBar); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetPasswordChar(ITextHost *iface, + WCHAR *pch) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetPasswordChar(%p, pch=%p)\n", This, pch); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetAcceleratorPos(ITextHost *iface, + LONG *pch) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetAcceleratorPos(%p, pch=%p)\n", This, pch); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_TxGetExtent(ITextHost *iface, + LPSIZEL lpExtent) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetExtent(%p, lpExtent=%p)\n", This, lpExtent); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_OnTxCharFormatChange(ITextHost *iface, + const CHARFORMATW *pcf) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to OnTxCharFormatChange(%p, pcf=%p)\n", This, pcf); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITextHostImpl_OnTxParaFormatChange(ITextHost *iface, + const PARAFORMAT *ppf) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to OnTxParaFormatChange(%p, ppf=%p)\n", This, ppf); + return E_NOTIMPL; +} + +/* This must return S_OK for the native ITextServices object to + initialize. */ +static HRESULT WINAPI ITextHostImpl_TxGetPropertyBits(ITextHost *iface, + DWORD dwMask, + DWORD *pdwBits) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetPropertyBits(%p, dwMask=0x%08x, pdwBits=%p)\n", + This, dwMask, pdwBits); + *pdwBits = 0; + return S_OK; +} + +static HRESULT WINAPI ITextHostImpl_TxNotify(ITextHost *iface, DWORD iNotify, + void *pv) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxNotify(%p, iNotify=%d, pv=%p)\n", This, iNotify, pv); + return E_NOTIMPL; +} + +static HIMC WINAPI ITextHostImpl_TxImmGetContext(ITextHost *iface) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxImmGetContext(%p)\n", This); + return 0; +} + +static void WINAPI ITextHostImpl_TxImmReleaseContext(ITextHost *iface, HIMC himc) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxImmReleaseContext(%p, himc=%p)\n", This, himc); +} + +/* This function must set the variable pointed to by *lSelBarWidth. + Otherwise an uninitalized value will be used to calculate + positions and sizes even if E_NOTIMPL is returned. */ +static HRESULT WINAPI ITextHostImpl_TxGetSelectionBarWidth(ITextHost *iface, + LONG *lSelBarWidth) +{ + ITextHostTestImpl *This = (ITextHostTestImpl *)iface; + TRACECALL("Call to TxGetSelectionBarWidth(%p, lSelBarWidth=%p)\n", + This, lSelBarWidth); + *lSelBarWidth = 0; + return E_NOTIMPL; +} + +static ITextHostVtbl itextHostVtbl = { + ITextHostImpl_QueryInterface, + ITextHostImpl_AddRef, + ITextHostImpl_Release, + ITextHostImpl_TxGetDC, + ITextHostImpl_TxReleaseDC, + ITextHostImpl_TxShowScrollBar, + ITextHostImpl_TxEnableScrollBar, + ITextHostImpl_TxSetScrollRange, + ITextHostImpl_TxSetScrollPos, + ITextHostImpl_TxInvalidateRect, + ITextHostImpl_TxViewChange, + ITextHostImpl_TxCreateCaret, + ITextHostImpl_TxShowCaret, + ITextHostImpl_TxSetCaretPos, + ITextHostImpl_TxSetTimer, + ITextHostImpl_TxKillTimer, + ITextHostImpl_TxScrollWindowEx, + ITextHostImpl_TxSetCapture, + ITextHostImpl_TxSetFocus, + ITextHostImpl_TxSetCursor, + ITextHostImpl_TxScreenToClient, + ITextHostImpl_TxClientToScreen, + ITextHostImpl_TxActivate, + ITextHostImpl_TxDeactivate, + ITextHostImpl_TxGetClientRect, + ITextHostImpl_TxGetViewInset, + ITextHostImpl_TxGetCharFormat, + ITextHostImpl_TxGetParaFormat, + ITextHostImpl_TxGetSysColor, + ITextHostImpl_TxGetBackStyle, + ITextHostImpl_TxGetMaxLength, + ITextHostImpl_TxGetScrollBars, + ITextHostImpl_TxGetPasswordChar, + ITextHostImpl_TxGetAcceleratorPos, + ITextHostImpl_TxGetExtent, + ITextHostImpl_OnTxCharFormatChange, + ITextHostImpl_OnTxParaFormatChange, + ITextHostImpl_TxGetPropertyBits, + ITextHostImpl_TxNotify, + ITextHostImpl_TxImmGetContext, + ITextHostImpl_TxImmReleaseContext, + ITextHostImpl_TxGetSelectionBarWidth +}; + +static ITextServices *txtserv = NULL; +static ITextHostTestImpl *dummyTextHost; +static void *wrapperCodeMem = NULL; + +#include "pshpack1.h" + +/* Code structure for x86 byte code */ +typedef struct +{ + BYTE pop_eax; /* popl %eax */ + BYTE push_ecx; /* pushl %ecx */ + BYTE push_eax; /* pushl %eax */ + BYTE jmp_func; /* jmp $func */ + DWORD func; +} THISCALL_TO_STDCALL_THUNK; + +typedef struct +{ + BYTE pop_eax; /* popl %eax */ + BYTE pop_ecx; /* popl %ecx */ + BYTE push_eax; /* pushl %eax */ + BYTE mov_vtable_eax[2]; /* movl (%ecx), %eax */ + BYTE jmp_eax[2]; /* jmp *$vtablefunc_offset(%eax) */ + int vtablefunc_offset; +} STDCALL_TO_THISCALL_THUNK; + +#include "poppack.h" + +static void setup_thiscall_wrappers(void) +{ +#ifdef __i386__ + void** pVtable; + void** pVtableEnd; + THISCALL_TO_STDCALL_THUNK *thunk; + STDCALL_TO_THISCALL_THUNK *thunk2; + + wrapperCodeMem = VirtualAlloc(NULL, + (sizeof(ITextHostVtbl)/sizeof(void*) - 3) + * sizeof(THISCALL_TO_STDCALL_THUNK) + +(sizeof(ITextServicesVtbl)/sizeof(void*) - 3) + * sizeof(STDCALL_TO_THISCALL_THUNK), + MEM_COMMIT, PAGE_EXECUTE_READWRITE); + thunk = wrapperCodeMem; + + /* Wrap all ITextHostImpl methods with code to perform a thiscall to + * stdcall conversion. The thiscall calling convention places the This + * pointer in ecx on the x86 platform, and the stdcall calling convention + * pushes the This pointer on the stack as the first argument. + * + * The byte code does the conversion then jumps to the real function. + * + * Each wrapper needs to be modified so that the function to jump to is + * modified in the byte code. */ + + /* Skip QueryInterface, AddRef, and Release native actually + * defined them with the stdcall calling convention. */ + pVtable = (void**)&itextHostVtbl + 3; + pVtableEnd = (void**)(&itextHostVtbl + 1); + while (pVtable != pVtableEnd) { + /* write byte code to executable memory */ + thunk->pop_eax = 0x58; /* popl %eax */ + thunk->push_ecx = 0x51; /* pushl %ecx */ + thunk->push_eax = 0x50; /* pushl %eax */ + thunk->jmp_func = 0xe9; /* jmp $func */ + /* The address needs to be relative to the end of the jump instructions. */ + thunk->func = (char*)*pVtable - (char*)(&thunk->func + 1); + *pVtable = thunk; + pVtable++; + thunk++; + } + + /* Setup an ITextServices standard call vtable that will call the + * native thiscall vtable when the methods are called. */ + + /* QueryInterface, AddRef, and Release should be called directly on the + * real vtable since they use the stdcall calling convention. */ + thunk2 = (STDCALL_TO_THISCALL_THUNK *)thunk; + pVtable = (void**)&itextServicesStdcallVtbl + 3; + pVtableEnd = (void**)(&itextServicesStdcallVtbl + 1); + while (pVtable != pVtableEnd) { + /* write byte code to executable memory */ + thunk2->pop_eax = 0x58; /* popl %eax */ + thunk2->pop_ecx = 0x59; /* popl %ecx */ + thunk2->push_eax = 0x50; /* pushl %eax */ + thunk2->mov_vtable_eax[0] = 0x8b; /* movl (%ecx), %eax */ + thunk2->mov_vtable_eax[1] = 0x01; + thunk2->jmp_eax[0] = 0xff; /* jmp *$vtablefunc_offset(%eax) */ + thunk2->jmp_eax[1] = 0xa0; + thunk2->vtablefunc_offset = (char*)pVtable - (char*)&itextServicesStdcallVtbl; + *pVtable = thunk2; + pVtable++; + thunk2++; + } +#endif /* __i386__ */ +} + +/*************************************************************************/ +/* Conformance test functions. */ + +/* Initialize the test texthost structure */ +static BOOL init_texthost(void) +{ + IUnknown *init; + HRESULT result; + PCreateTextServices pCreateTextServices; + + dummyTextHost = CoTaskMemAlloc(sizeof(*dummyTextHost)); + if (dummyTextHost == NULL) { + skip("Insufficient memory to create ITextHost interface\n"); + return FALSE; + } + dummyTextHost->lpVtbl = &itextHostVtbl; + dummyTextHost->refCount = 1; + + /* MSDN states that an IUnknown object is returned by + CreateTextServices which is then queried to obtain a + ITextServices object. */ + pCreateTextServices = (void*)GetProcAddress(hmoduleRichEdit, "CreateTextServices"); + result = (*pCreateTextServices)(NULL,(ITextHost*)dummyTextHost, &init); + ok(result == S_OK, "Did not return OK when created. Returned %x\n", result); + if (result != S_OK) { + CoTaskMemFree(dummyTextHost); + skip("CreateTextServices failed.\n"); + return FALSE; + } + + result = IUnknown_QueryInterface(init, &IID_ITextServices, + (void **)&txtserv); + ok((result == S_OK) && (txtserv != NULL), "Querying interface failed\n"); + IUnknown_Release(init); + if (!((result == S_OK) && (txtserv != NULL))) { + CoTaskMemFree(dummyTextHost); + skip("Could not retrieve ITextServices interface\n"); + return FALSE; + } + + return TRUE; +} + +static void test_TxGetText(void) +{ + HRESULT hres; + BSTR rettext; + + if (!init_texthost()) + return; + + hres = ITextServices_TxGetText(txtserv, &rettext); + ok(hres == S_OK, "ITextServices_TxGetText failed\n"); + + IUnknown_Release(txtserv); + CoTaskMemFree(dummyTextHost); +} + +static void test_TxSetText(void) +{ + HRESULT hres; + BSTR rettext; + WCHAR settext[] = {'T','e','s','t',0}; + + if (!init_texthost()) + return; + + hres = ITextServices_TxSetText(txtserv, settext); + ok(hres == S_OK, "ITextServices_TxSetText failed\n"); + + hres = ITextServices_TxGetText(txtserv, &rettext); + ok(hres == S_OK, "ITextServices_TxGetText failed\n"); + + ok(SysStringLen(rettext) == 4, + "String returned of wrong length\n"); + ok(memcmp(rettext,settext,SysStringByteLen(rettext)) == 0, + "String returned differs\n"); + + IUnknown_Release(txtserv); + CoTaskMemFree(dummyTextHost); +} + +static void test_TxGetNaturalSize(void) { + HRESULT result; + BOOL ret; + + /* This value is used when calling TxGetNaturalSize. MSDN says + that this is not supported however a null pointer cannot be + used as it will cause a segmentation violation. The values in + the structure being pointed to are required to be INT_MAX + otherwise calculations can give wrong values. */ + const SIZEL psizelExtent = {INT_MAX,INT_MAX}; + + static const WCHAR oneA[] = {'A',0}; + + /* Results of measurements */ + LONG xdim, ydim; + + /* The device context to do the tests in */ + HDC hdcDraw; + + /* Variables with the text metric information */ + INT charwidth_caps_text[26]; + TEXTMETRIC tmInfo_text; + + if (!init_texthost()) + return; + + hdcDraw = GetDC(NULL); + SaveDC(hdcDraw); + + /* Populate the metric strucs */ + SetMapMode(hdcDraw,MM_TEXT); + GetTextMetrics(hdcDraw, &tmInfo_text); + SetLastError(0xdeadbeef); + ret = GetCharWidth32(hdcDraw,'A','Z',charwidth_caps_text); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + win_skip("GetCharWidth32 is not available\n"); + RestoreDC(hdcDraw,1); + ReleaseDC(NULL,hdcDraw); + return; + } + + /* Make measurements in MM_TEXT */ + SetMapMode(hdcDraw,MM_TEXT); + xdim = 0; ydim = 0; + + result = ITextServices_TxSetText(txtserv, oneA); + ok(result == S_OK, "ITextServices_TxSetText failed\n"); + + result = ITextServices_TxGetNaturalSize(txtserv, DVASPECT_CONTENT, + hdcDraw, NULL, NULL, + TXTNS_FITTOCONTENT, &psizelExtent, + &xdim, &ydim); + todo_wine ok(result == S_OK, "TxGetNaturalSize failed\n"); + todo_wine ok(ydim == tmInfo_text.tmHeight, + "Height calculated incorrectly (expected %d, got %d)\n", + tmInfo_text.tmHeight, ydim); + /* The native DLL adds one pixel extra when calculating widths. */ + todo_wine ok(xdim >= charwidth_caps_text[0] && xdim <= charwidth_caps_text[0] + 1, + "Width calculated incorrectly (expected %d {+1}, got %d)\n", + charwidth_caps_text[0], xdim); + + RestoreDC(hdcDraw,1); + ReleaseDC(NULL,hdcDraw); + + IUnknown_Release(txtserv); + CoTaskMemFree(dummyTextHost); +} + +START_TEST( txtsrv ) +{ + setup_thiscall_wrappers(); + + /* Must explicitly LoadLibrary(). The test has no references to functions in + * RICHED20.DLL, so the linker doesn't actually link to it. */ + hmoduleRichEdit = LoadLibrary("RICHED20.DLL"); + ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError()); + + if (init_texthost()) + { + IUnknown_Release(txtserv); + CoTaskMemFree(dummyTextHost); + + test_TxGetText(); + test_TxSetText(); + test_TxGetNaturalSize(); + } + if (wrapperCodeMem) VirtualFree(wrapperCodeMem, 0, MEM_RELEASE); +} diff --git a/rostests/winetests/riched32/editor.c b/rostests/winetests/riched32/editor.c index 63a63f13018..47911dba8b1 100644 --- a/rostests/winetests/riched32/editor.c +++ b/rostests/winetests/riched32/editor.c @@ -48,7 +48,7 @@ static HWND new_richedit(HWND parent) { return new_window(RICHEDIT_CLASS10A, ES_MULTILINE, parent); } -static void test_WM_SETTEXT() +static void test_WM_SETTEXT(void) { HWND hwndRichEdit = new_richedit(NULL); const char * TestItem1 = "TestSomeText"; @@ -71,23 +71,21 @@ static void test_WM_SETTEXT() LRESULT result; /* This test attempts to show that WM_SETTEXT on a riched32 control does not - attempt to modify the text that is pasted into the control, and should - return it as is. In particular, \r\r\n is NOT converted, unlike riched20. - Currently, builtin riched32 mangles solitary \r or \n when not part of - a \r\n pair. - - For riched32, the rules for breaking lines seem to be the following: - - \r\n is one line break. This is the normal case. - - \r{0,N}\n is one line break. In particular, \n by itself is a line break. - - \n{1,N} are that many line breaks. - - \r with text or other characters (except \n) past it, is a line break. That - is, a run of \r{N} without a terminating \n is considered N line breaks - - \r at the end of the text is NOT a line break. This differs from riched20, - where \r at the end of the text is a proper line break. This causes - TestItem2 to fail its test. + * attempt to modify the text that is pasted into the control, and should + * return it as is. In particular, \r\r\n is NOT converted, unlike riched20. + * + * For riched32, the rules for breaking lines seem to be the following: + * - \r\n is one line break. This is the normal case. + * - \r{0,2}\n is one line break. In particular, \n by itself is a line break. + * - \r{0,N-1}\r\r\n is N line breaks. + * - \n{1,N} are that many line breaks. + * - \r with text or other characters (except \n) past it, is a line break. That + * is, a run of \r{N} without a terminating \n is considered N line breaks + * - \r at the end of the text is NOT a line break. This differs from riched20, + * where \r at the end of the text is a proper line break. */ -#define TEST_SETTEXT(a, b, nlines, is_todo, is_todo2) \ +#define TEST_SETTEXT(a, b, nlines) \ result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \ ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \ result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \ @@ -95,36 +93,27 @@ static void test_WM_SETTEXT() "WM_GETTEXT returned %ld instead of expected %u\n", \ result, lstrlen(buf)); \ result = strcmp(b, buf); \ - if (is_todo) todo_wine { \ ok(result == 0, \ "WM_SETTEXT round trip: strcmp = %ld\n", result); \ - } else { \ - ok(result == 0, \ - "WM_SETTEXT round trip: strcmp = %ld\n", result); \ - } \ result = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); \ - if (is_todo2) todo_wine { \ - ok(result == nlines, "EM_GETLINECOUNT returned %ld, expected %d\n", result, nlines); \ - } else { \ - ok(result == nlines, "EM_GETLINECOUNT returned %ld, expected %d\n", result, nlines); \ - } + ok(result == nlines, "EM_GETLINECOUNT returned %ld, expected %d\n", result, nlines); - TEST_SETTEXT(TestItem1, TestItem1, 1, 0, 0) - TEST_SETTEXT(TestItem2, TestItem2, 1, 0, 0) - TEST_SETTEXT(TestItem3, TestItem3, 2, 0, 0) - TEST_SETTEXT(TestItem4, TestItem4, 3, 0, 0) - TEST_SETTEXT(TestItem5, TestItem5, 2, 0, 0) - TEST_SETTEXT(TestItem6, TestItem6, 3, 0, 0) - TEST_SETTEXT(TestItem7, TestItem7, 4, 0, 0) - TEST_SETTEXT(TestItem8, TestItem8, 2, 0, 0) - TEST_SETTEXT(TestItem9, TestItem9, 3, 0, 0) - TEST_SETTEXT(TestItem10, TestItem10, 3, 0, 0) - TEST_SETTEXT(TestItem11, TestItem11, 1, 0, 0) - TEST_SETTEXT(TestItem12, TestItem12, 2, 0, 0) - TEST_SETTEXT(TestItem13, TestItem13, 3, 0, 0) - TEST_SETTEXT(TestItem14, TestItem14, 2, 0, 0) - TEST_SETTEXT(TestItem15, TestItem15, 3, 0, 0) - TEST_SETTEXT(TestItem16, TestItem16, 4, 0, 0) + TEST_SETTEXT(TestItem1, TestItem1, 1) + TEST_SETTEXT(TestItem2, TestItem2, 1) + TEST_SETTEXT(TestItem3, TestItem3, 2) + TEST_SETTEXT(TestItem4, TestItem4, 3) + TEST_SETTEXT(TestItem5, TestItem5, 2) + TEST_SETTEXT(TestItem6, TestItem6, 3) + TEST_SETTEXT(TestItem7, TestItem7, 4) + TEST_SETTEXT(TestItem8, TestItem8, 2) + TEST_SETTEXT(TestItem9, TestItem9, 3) + TEST_SETTEXT(TestItem10, TestItem10, 3) + TEST_SETTEXT(TestItem11, TestItem11, 1) + TEST_SETTEXT(TestItem12, TestItem12, 2) + TEST_SETTEXT(TestItem13, TestItem13, 3) + TEST_SETTEXT(TestItem14, TestItem14, 2) + TEST_SETTEXT(TestItem15, TestItem15, 3) + TEST_SETTEXT(TestItem16, TestItem16, 4) #undef TEST_SETTEXT DestroyWindow(hwndRichEdit); @@ -184,18 +173,18 @@ static void test_EM_STREAMIN(void) const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}"; const char * streamText1 = - "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" \ - "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" \ + "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" + "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" "}\r\n"; /* This should be accepted in richedit 1.0 emulation. See bug #8326 */ const char * streamText2 = - "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" \ - "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" \ - "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " \ - "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " \ - "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " \ - "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " \ + "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" + "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" + "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " + "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " + "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " + "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }"; const char * streamText3 = "RichEdit1"; @@ -365,17 +354,17 @@ static const struct getline_s { int line; size_t buffer_len; const char *text; - int wine_todo; } gl[] = { - {0, 10, "foo bar\r\n", 0}, - {1, 10, "\n", 0}, - {2, 10, "bar\n", 0}, - {3, 10, "\r\n", 0}, + {0, 10, "foo bar\r\n"}, + {1, 10, "\r"}, + {2, 10, "\r\r\n"}, + {3, 10, "bar\n"}, + {4, 10, "\r\n"}, /* Buffer smaller than line length */ - {0, 2, "foo bar\r", 0}, - {0, 1, "foo bar\r", 0}, - {0, 0, "foo bar\r", 0} + {0, 2, "foo bar\r"}, + {0, 1, "foo bar\r"}, + {0, 0, "foo bar\r"} }; static void test_EM_GETLINE(void) @@ -385,7 +374,8 @@ static void test_EM_GETLINE(void) static const int nBuf = 1024; char dest[1024], origdest[1024]; const char text[] = "foo bar\r\n" - "\n" + "\r" + "\r\r\n" "bar\n"; SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text); @@ -402,10 +392,6 @@ static void test_EM_GETLINE(void) /* EM_GETLINE appends a "\r\0" to the end of the line * nCopied counts up to and including the '\r' */ nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest); - if (gl[i].wine_todo) todo_wine { - ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied, - expected_nCopied); - } else ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied, expected_nCopied); /* two special cases since a parameter is passed via dest */ @@ -417,23 +403,13 @@ static void test_EM_GETLINE(void) !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n"); else { - if (gl[i].wine_todo) todo_wine { ok(!strncmp(dest, gl[i].text, expected_bytes_written), "%d: expected_bytes_written=%d\n", i, expected_bytes_written); ok(!strncmp(dest + expected_bytes_written, origdest + expected_bytes_written, nBuf - expected_bytes_written), "%d: expected_bytes_written=%d\n", i, expected_bytes_written); } - else - { - ok(!strncmp(dest, gl[i].text, expected_bytes_written), - "%d: expected_bytes_written=%d\n", i, expected_bytes_written); - ok(!strncmp(dest + expected_bytes_written, origdest - + expected_bytes_written, nBuf - expected_bytes_written), - "%d: expected_bytes_written=%d\n", i, expected_bytes_written); } - } - } DestroyWindow(hwndRichEdit); } @@ -445,25 +421,42 @@ static void test_EM_LINELENGTH(void) "richedit1\r" "richedit1\n" "richedit1\r\n" - "richedit1\r\r\r\r\r\n"; - int offset_test[10][2] = { - {0, 9}, - {5, 9}, - {10, 9}, - {15, 9}, - {20, 9}, - {25, 9}, - {30, 9}, - {35, 9}, - {40, 9}, /* <----- in the middle of the \r run, but run not counted */ - {45, 0}, + "short\r" + "richedit1\r" + "\r" + "\r" + "\r\r\n"; + int offset_test[16][2] = { + {0, 9}, /* Line 1: |richedit1\r */ + {5, 9}, /* Line 1: riche|dit1\r */ + {10, 9}, /* Line 2: |richedit1\n */ + {15, 9}, /* Line 2: riche|dit1\n */ + {20, 9}, /* Line 3: |richedit1\r\n */ + {25, 9}, /* Line 3: riche|dit1\r\n */ + {30, 9}, /* Line 3: richedit1\r|\n */ + {31, 5}, /* Line 4: |short\r */ + {42, 9}, /* Line 5: riche|dit1\r */ + {46, 9}, /* Line 5: richedit1|\r */ + {47, 0}, /* Line 6: |\r */ + {48, 0}, /* Line 7: |\r */ + {49, 0}, /* Line 8: |\r\r\n */ + {50, 0}, /* Line 8: \r|\r\n */ + {51, 0}, /* Line 8: \r\r|\n */ + {52, 0}, /* Line 9: \r\r\n| */ }; int i; LRESULT result; SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text); - for (i = 0; i < 10; i++) { + result = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); + if (result == 4) { + win_skip("Win9x, WinME and NT4 don't handle '\\r only' correctly\n"); + return; + } + ok(result == 9, "Incorrect line count of %ld\n", result); + + for (i = 0; i < sizeof(offset_test)/sizeof(offset_test[0]); i++) { result = SendMessage(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0); ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n", offset_test[i][0], result, offset_test[i][1]); @@ -476,9 +469,10 @@ static void test_EM_GETTEXTRANGE(void) { HWND hwndRichEdit = new_richedit(NULL); const char * text1 = "foo bar\r\nfoo bar"; - const char * text2 = "foo bar\rfoo bar"; + const char * text3 = "foo bar\rfoo bar"; const char * expect1 = "bar\r\nfoo"; - const char * expect2 = "bar\rfoo"; + const char * expect2 = "\nfoo"; + const char * expect3 = "bar\rfoo"; char buffer[1024] = {0}; LRESULT result; TEXTRANGEA textRange; @@ -492,7 +486,14 @@ static void test_EM_GETTEXTRANGE(void) ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result); ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); - SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2); + textRange.lpstrText = buffer; + textRange.chrg.cpMin = 8; + textRange.chrg.cpMax = 12; + result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); + ok(result == 4, "EM_GETTEXTRANGE returned %ld\n", result); + ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3); textRange.lpstrText = buffer; textRange.chrg.cpMin = 4; @@ -500,7 +501,7 @@ static void test_EM_GETTEXTRANGE(void) result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange); ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result); - ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); + ok(!strcmp(expect3, buffer), "EM_GETTEXTRANGE filled %s\n", buffer); DestroyWindow(hwndRichEdit); @@ -538,90 +539,98 @@ static void test_EM_GETSELTEXT(void) static const char haystack[] = "WINEWine wineWine wine WineWine"; /* ^0 ^10 ^20 ^30 */ +static const char haystack2[] = "first\r\r\nsecond"; + struct find_s { int start; int end; const char *needle; int flags; int expected_loc; - int _todo_wine; }; struct find_s find_tests[] = { /* Find in empty text */ - {0, -1, "foo", FR_DOWN, -1, 0}, - {0, -1, "foo", 0, -1, 0}, - {0, -1, "", FR_DOWN, -1, 0}, - {20, 5, "foo", FR_DOWN, -1, 0}, - {5, 20, "foo", FR_DOWN, -1, 0} + {0, -1, "foo", FR_DOWN, -1}, + {0, -1, "foo", 0, -1}, + {0, -1, "", FR_DOWN, -1}, + {20, 5, "foo", FR_DOWN, -1}, + {5, 20, "foo", FR_DOWN, -1} }; struct find_s find_tests2[] = { /* No-result find */ - {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0}, - {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0}, + {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1}, + {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1}, /* Subsequent finds */ - {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0}, - {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0}, - {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0}, - {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, + {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4}, + {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13}, + {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23}, + {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27}, /* Find backwards */ - {19, 20, "Wine", FR_MATCHCASE, -1, 0}, - {10, 20, "Wine", FR_MATCHCASE, 13, 0}, - {20, 10, "Wine", FR_MATCHCASE, -1, 0}, + {19, 20, "Wine", FR_MATCHCASE, -1}, + {10, 20, "Wine", FR_MATCHCASE, 13}, + {20, 10, "Wine", FR_MATCHCASE, -1}, /* Case-insensitive */ - {1, 31, "wInE", FR_DOWN, 4, 0}, - {1, 31, "Wine", FR_DOWN, 4, 0}, + {1, 31, "wInE", FR_DOWN, 4}, + {1, 31, "Wine", FR_DOWN, 4}, /* High-to-low ranges */ - {20, 5, "Wine", FR_DOWN, -1, 0}, - {2, 1, "Wine", FR_DOWN, -1, 0}, - {30, 29, "Wine", FR_DOWN, -1, 0}, - {20, 5, "Wine", 0, /*13*/ -1, 0}, + {20, 5, "Wine", FR_DOWN, -1}, + {2, 1, "Wine", FR_DOWN, -1}, + {30, 29, "Wine", FR_DOWN, -1}, + {20, 5, "Wine", 0, /*13*/ -1}, /* Find nothing */ - {5, 10, "", FR_DOWN, -1, 0}, - {10, 5, "", FR_DOWN, -1, 0}, - {0, -1, "", FR_DOWN, -1, 0}, - {10, 5, "", 0, -1, 0}, + {5, 10, "", FR_DOWN, -1}, + {10, 5, "", FR_DOWN, -1}, + {0, -1, "", FR_DOWN, -1}, + {10, 5, "", 0, -1}, /* Whole-word search */ - {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0}, - {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0}, - {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0}, - {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0}, - {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0}, - {11, -1, "winewine", FR_WHOLEWORD, 23, 0}, - {31, -1, "winewine", FR_WHOLEWORD, -1, 0}, + {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18}, + {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1}, + {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18}, + {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0}, + {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23}, + {11, -1, "winewine", FR_WHOLEWORD, 23}, + {31, -1, "winewine", FR_WHOLEWORD, -1}, /* Bad ranges */ - {5, 200, "XXX", FR_DOWN, -1, 0}, - {-20, 20, "Wine", FR_DOWN, -1, 0}, - {-20, 20, "Wine", FR_DOWN, -1, 0}, - {-15, -20, "Wine", FR_DOWN, -1, 0}, - {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0}, + {5, 200, "XXX", FR_DOWN, -1}, + {-20, 20, "Wine", FR_DOWN, -1}, + {-20, 20, "Wine", FR_DOWN, -1}, + {-15, -20, "Wine", FR_DOWN, -1}, + {1<<12, 1<<13, "Wine", FR_DOWN, -1}, /* Check the case noted in bug 4479 where matches at end aren't recognized */ - {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0}, - {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, - {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0}, - {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0}, - {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0}, + {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23}, + {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27}, + {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27}, + {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23}, + {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23}, /* The backwards case of bug 4479; bounds look right * Fails because backward find is wrong */ - {19, 20, "WINE", FR_MATCHCASE, -1, 0}, - {0, 20, "WINE", FR_MATCHCASE, 0, 0}, + {19, 20, "WINE", FR_MATCHCASE, -1}, + {0, 20, "WINE", FR_MATCHCASE, 0}, - {0, -1, "wineWine wine", FR_DOWN, 0, 0}, - {0, -1, "wineWine wine", 0, 0, 0}, - {0, -1, "INEW", 0, 1, 0}, - {0, 31, "INEW", 0, 1, 0}, - {4, -1, "INEW", 0, 10, 0}, + {0, -1, "wineWine wine", FR_DOWN, 0}, + {0, -1, "wineWine wine", 0, 0}, + {0, -1, "INEW", 0, 1}, + {0, 31, "INEW", 0, 1}, + {4, -1, "INEW", 0, 10}, +}; + +struct find_s find_tests3[] = { + /* Searching for end of line characters */ + {0, -1, "t\r\r\ns", FR_DOWN | FR_MATCHCASE, 4}, + {6, -1, "\r\n", FR_DOWN | FR_MATCHCASE, 6}, + {7, -1, "\n", FR_DOWN | FR_MATCHCASE, 7}, }; static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) { @@ -667,17 +676,10 @@ static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *fi int i; for (i = 0; i < num_tests; i++) { - if (find[i]._todo_wine) { - todo_wine { check_EM_FINDTEXT(hwnd, name, &find[i], i); check_EM_FINDTEXTEX(hwnd, name, &find[i], i); } - } else { - check_EM_FINDTEXT(hwnd, name, &find[i], i); - check_EM_FINDTEXTEX(hwnd, name, &find[i], i); } - } -} static void test_EM_FINDTEXT(void) { @@ -693,6 +695,12 @@ static void test_EM_FINDTEXT(void) run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, sizeof(find_tests2)/sizeof(struct find_s)); + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack2); + + /* Haystack text 2 (with EOL characters) */ + run_tests_EM_FINDTEXT(hwndRichEdit, "3", find_tests3, + sizeof(find_tests3)/sizeof(struct find_s)); + DestroyWindow(hwndRichEdit); } @@ -742,9 +750,7 @@ static void test_EM_POSFROMCHAR(void) if (i == 0) { ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y); - todo_wine { ok(pl.x == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x); - } xpos = pl.x; } else if (i == 1) @@ -805,9 +811,7 @@ static void test_EM_POSFROMCHAR(void) result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0); ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result); ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y); - todo_wine { ok(pl.x == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x); - } xpos = pl.x; SendMessage(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0); @@ -821,6 +825,163 @@ static void test_EM_POSFROMCHAR(void) DestroyWindow(hwndRichEdit); } +static void test_word_wrap(void) +{ + HWND hwnd; + POINTL point = {0, 60}; /* This point must be below the first line */ + const char *text = "Must be long enough to test line wrapping"; + DWORD dwCommonStyle = WS_VISIBLE|WS_POPUP|WS_VSCROLL|ES_MULTILINE; + int res, pos, lines; + + /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping + * when specified on window creation and set later. */ + hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text); + ok(res, "WM_SETTEXT failed.\n"); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); + + SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); + DestroyWindow(hwnd); + + hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle|WS_HSCROLL, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + + res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text); + ok(res, "WM_SETTEXT failed.\n"); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); + + SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); + DestroyWindow(hwnd); + + hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle|ES_AUTOHSCROLL, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text); + ok(res, "WM_SETTEXT failed.\n"); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + + SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + DestroyWindow(hwnd); + + hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, + dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL, + 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text); + ok(res, "WM_SETTEXT failed.\n"); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + + SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + + /* Test the effect of EM_SETTARGETDEVICE on word wrap. */ + res = SendMessage(hwnd, EM_SETTARGETDEVICE, 0, 1); + ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos); + + res = SendMessage(hwnd, EM_SETTARGETDEVICE, 0, 0); + ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res); + pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point); + ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos); + DestroyWindow(hwnd); + + /* Test to see if wrapping happens with redraw disabled. */ + hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle, + 0, 0, 400, 80, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "error: %d\n", (int) GetLastError()); + ok(IsWindowVisible(hwnd), "Window should be visible.\n"); + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + /* redraw is disabled by making the window invisible. */ + ok(!IsWindowVisible(hwnd), "Window shouldn't be visible.\n"); + res = SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) text); + ok(res, "EM_REPLACESEL failed.\n"); + MoveWindow(hwnd, 0, 0, 100, 80, TRUE); + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + /* Wrapping didn't happen while redraw was disabled. */ + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + todo_wine ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines); + /* There isn't even a rewrap from resizing the window. */ + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + todo_wine ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines); + res = SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) text); + ok(res, "EM_REPLACESEL failed.\n"); + lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines); + + DestroyWindow(hwnd); +} + +static void test_EM_GETOPTIONS(void) +{ + HWND hwnd; + DWORD options; + + hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, + WS_POPUP, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + options = SendMessage(hwnd, EM_GETOPTIONS, 0, 0); + ok(options == 0, "Incorrect options %x\n", options); + DestroyWindow(hwnd); + + hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, + WS_POPUP|WS_VSCROLL|WS_HSCROLL, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + options = SendMessage(hwnd, EM_GETOPTIONS, 0, 0); + ok(options == ECO_AUTOVSCROLL, + "Incorrect initial options %x\n", options); + DestroyWindow(hwnd); +} + +static void test_autoscroll(void) +{ + HWND hwnd; + UINT ret; + + /* The WS_VSCROLL and WS_HSCROLL styles implicitly set + * auto vertical/horizontal scrolling options. */ + hwnd = CreateWindowEx(0, RICHEDIT_CLASS10A, NULL, + WS_POPUP|ES_MULTILINE|WS_VSCROLL|WS_HSCROLL, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + ret = SendMessage(hwnd, EM_GETOPTIONS, 0, 0); + ok(ret & ECO_AUTOVSCROLL, "ECO_AUTOVSCROLL isn't set.\n"); + ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n"); + ret = GetWindowLong(hwnd, GWL_STYLE); + todo_wine ok(ret & ES_AUTOVSCROLL, "ES_AUTOVSCROLL isn't set.\n"); + ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n"); + DestroyWindow(hwnd); + + hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL, + WS_POPUP|ES_MULTILINE, + 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError()); + ret = SendMessage(hwnd, EM_GETOPTIONS, 0, 0); + ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n"); + ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n"); + ret = GetWindowLong(hwnd, GWL_STYLE); + ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n"); + ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n"); + DestroyWindow(hwnd); +} START_TEST( editor ) { @@ -842,6 +1003,9 @@ START_TEST( editor ) test_EM_LINELENGTH(); test_EM_FINDTEXT(); test_EM_POSFROMCHAR(); + test_word_wrap(); + test_EM_GETOPTIONS(); + test_autoscroll(); /* Set the environment variable WINETEST_RICHED32 to keep windows * responsive and open for 30 seconds. This is useful for debugging. diff --git a/rostests/winetests/riched32/riched32.rbuild b/rostests/winetests/riched32/riched32.rbuild index 0b2cca9a566..13d3136017e 100644 --- a/rostests/winetests/riched32/riched32.rbuild +++ b/rostests/winetests/riched32/riched32.rbuild @@ -3,14 +3,12 @@ . - 0x600 - 0x600 + editor.c testlist.c wine ole32 user32 - kernel32 ntdll diff --git a/rostests/winetests/riched32/testlist.c b/rostests/winetests/riched32/testlist.c index 08e717eeb0d..1248a7cdc6a 100644 --- a/rostests/winetests/riched32/testlist.c +++ b/rostests/winetests/riched32/testlist.c @@ -6,10 +6,8 @@ #define STANDALONE #include "wine/test.h" -extern void func_editor(void); const struct test winetest_testlist[] = { - { "editor", func_editor }, { 0, 0 } }; diff --git a/rostests/winetests/rpcrt4/cstub.c b/rostests/winetests/rpcrt4/cstub.c index a47fa6eeb14..1ce24ceaea0 100644 --- a/rostests/winetests/rpcrt4/cstub.c +++ b/rostests/winetests/rpcrt4/cstub.c @@ -30,6 +30,7 @@ #include +#include "initguid.h" #include "rpc.h" #include "rpcdce.h" #include "rpcproxy.h" @@ -47,7 +48,7 @@ static GUID IID_if4 = {0x1234567b, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}}; static int my_alloc_called; static int my_free_called; -static void * CALLBACK my_alloc(size_t size) +static void * CALLBACK my_alloc(SIZE_T size) { my_alloc_called++; return NdrOleAllocate(size); @@ -258,13 +259,14 @@ static CInterfaceStubVtbl if2_stub_vtbl = { CStdStubBuffer_DELEGATING_METHODS } }; -static CINTERFACE_PROXY_VTABLE(4) if3_proxy_vtbl = +static CINTERFACE_PROXY_VTABLE(5) if3_proxy_vtbl = { { &IID_if3 }, { IUnknown_QueryInterface_Proxy, IUnknown_AddRef_Proxy, IUnknown_Release_Proxy , - if1_fn1_Proxy + if1_fn1_Proxy, + 0 } }; @@ -297,7 +299,7 @@ static CInterfaceStubVtbl if3_stub_vtbl = { &IID_if3, &if3_server_info, - 4, + 5, &if1_table[-3] }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } @@ -367,10 +369,10 @@ static const CInterfaceProxyVtbl *cstub_ProxyVtblList[] = static const CInterfaceStubVtbl *cstub_StubVtblList[] = { - (const CInterfaceStubVtbl *) &if1_stub_vtbl, - (const CInterfaceStubVtbl *) &if2_stub_vtbl, - (const CInterfaceStubVtbl *) &if3_stub_vtbl, - (const CInterfaceStubVtbl *) &if4_stub_vtbl, + &if1_stub_vtbl, + &if2_stub_vtbl, + &if3_stub_vtbl, + &if4_stub_vtbl, NULL }; @@ -429,10 +431,16 @@ static const ProxyFileInfo *proxy_file_list[] = { static IPSFactoryBuffer *test_NdrDllGetClassObject(void) { + HMODULE rpcrt4 = GetModuleHandleA("rpcrt4.dll"); IPSFactoryBuffer *ppsf = NULL; + const PCInterfaceProxyVtblList* proxy_vtbl; + const PCInterfaceStubVtblList* stub_vtbl; const CLSID PSDispatch = {0x20420, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}}; + const CLSID CLSID_Unknown = {0x45678, 0x1234, 0x6666, {0xff, 0x67, 0x45, 0x98, 0x76, 0x12, 0x34, 0x56}}; + static const GUID * const interfaces[] = { &IID_if1, &IID_if2, &IID_if3, &IID_if4 }; + UINT i; HRESULT r; - HMODULE hmod = LoadLibraryA("rpcrt4.dll"); + HMODULE hmod = GetModuleHandleA("rpcrt4.dll"); void *CStd_QueryInterface = GetProcAddress(hmod, "CStdStubBuffer_QueryInterface"); void *CStd_AddRef = GetProcAddress(hmod, "CStdStubBuffer_AddRef"); void *CStd_Release = GetProcAddress(hmod, "NdrCStdStubBuffer_Release"); @@ -444,28 +452,37 @@ static IPSFactoryBuffer *test_NdrDllGetClassObject(void) void *CStd_DebugServerQueryInterface = GetProcAddress(hmod, "CStdStubBuffer_DebugServerQueryInterface"); void *CStd_DebugServerRelease = GetProcAddress(hmod, "CStdStubBuffer_DebugServerRelease"); + r = NdrDllGetClassObject(&PSDispatch, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list, + &CLSID_Unknown, &PSFactoryBuffer); + ok(r == CLASS_E_CLASSNOTAVAILABLE, "NdrDllGetClassObject with unknown clsid should have returned CLASS_E_CLASSNOTAVAILABLE instead of 0x%x\n", r); + ok(ppsf == NULL, "NdrDllGetClassObject should have set ppsf to NULL on failure\n"); + r = NdrDllGetClassObject(&PSDispatch, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list, &PSDispatch, &PSFactoryBuffer); ok(r == S_OK, "ret %08x\n", r); ok(ppsf != NULL, "ppsf == NULL\n"); + proxy_vtbl = PSFactoryBuffer.pProxyFileList[0]->pProxyVtblList; + stub_vtbl = PSFactoryBuffer.pProxyFileList[0]->pStubVtblList; ok(PSFactoryBuffer.pProxyFileList == proxy_file_list, "pfl not the same\n"); - ok(PSFactoryBuffer.pProxyFileList[0]->pStubVtblList == (PCInterfaceStubVtblList *) &cstub_StubVtblList, "stub vtbllist not the same\n"); + ok(proxy_vtbl == (PCInterfaceProxyVtblList *) &cstub_ProxyVtblList, "proxy vtbllist not the same\n"); + ok(stub_vtbl == (PCInterfaceStubVtblList *) &cstub_StubVtblList, "stub vtbllist not the same\n"); /* if1 is non-delegating, if2 is delegating, if3 is non-delegating but I've zero'ed the vtbl entries, similarly if4 is delegating with zero'ed vtbl entries */ #define VTBL_TEST_NOT_CHANGE_TO(name, i) \ - ok(PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name != CStd_##name, #name "vtbl %d updated %p %p\n", \ - i, PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name, CStd_##name ); + ok(stub_vtbl[i]->Vtbl.name != CStd_##name, #name "vtbl %d updated %p %p\n", \ + i, stub_vtbl[i]->Vtbl.name, CStd_##name ) #define VTBL_TEST_CHANGE_TO(name, i) \ - ok(PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name == CStd_##name, #name "vtbl %d not updated %p %p\n", \ - i, PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name, CStd_##name ); + ok(stub_vtbl[i]->Vtbl.name == CStd_##name, #name "vtbl %d not updated %p %p\n", \ + i, stub_vtbl[i]->Vtbl.name, CStd_##name ) #define VTBL_TEST_ZERO(name, i) \ - ok(PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name == NULL, #name "vtbl %d not null %p\n", \ - i, PSFactoryBuffer.pProxyFileList[0]->pStubVtblList[i]->Vtbl.name ); + ok(stub_vtbl[i]->Vtbl.name == NULL, #name "vtbl %d not null %p\n", \ + i, stub_vtbl[i]->Vtbl.name ) + VTBL_TEST_NOT_CHANGE_TO(QueryInterface, 0); VTBL_TEST_NOT_CHANGE_TO(AddRef, 0); VTBL_TEST_NOT_CHANGE_TO(Release, 0); @@ -510,13 +527,64 @@ static IPSFactoryBuffer *test_NdrDllGetClassObject(void) VTBL_TEST_CHANGE_TO(DebugServerQueryInterface, 3); VTBL_TEST_CHANGE_TO(DebugServerRelease, 3); +#define VTBL_PROXY_TEST(i,num,ptr) \ + ok( proxy_vtbl[i]->Vtbl[num] == (ptr), "wrong proxy %u func %u %p/%p\n", \ + (i), (num), proxy_vtbl[i]->Vtbl[num], (ptr) ) +#define VTBL_PROXY_TEST_NOT_ZERO(i,num) \ + ok( proxy_vtbl[i]->Vtbl[num] != NULL, "wrong proxy %u func %u is NULL\n", (i), (num)) + VTBL_PROXY_TEST(0, 0, IUnknown_QueryInterface_Proxy); + VTBL_PROXY_TEST(0, 1, IUnknown_AddRef_Proxy); + VTBL_PROXY_TEST(0, 2, IUnknown_Release_Proxy); + VTBL_PROXY_TEST(0, 3, if1_fn1_Proxy); + VTBL_PROXY_TEST(0, 4, if1_fn2_Proxy); + + VTBL_PROXY_TEST(1, 0, GetProcAddress(rpcrt4,"IUnknown_QueryInterface_Proxy")); + VTBL_PROXY_TEST(1, 1, GetProcAddress(rpcrt4,"IUnknown_AddRef_Proxy")); + VTBL_PROXY_TEST(1, 2, GetProcAddress(rpcrt4,"IUnknown_Release_Proxy")); + VTBL_PROXY_TEST_NOT_ZERO(1, 3); + VTBL_PROXY_TEST_NOT_ZERO(1, 4); + VTBL_PROXY_TEST_NOT_ZERO(1, 5); + VTBL_PROXY_TEST_NOT_ZERO(1, 6); + VTBL_PROXY_TEST_NOT_ZERO(1, 7); + VTBL_PROXY_TEST_NOT_ZERO(1, 8); + VTBL_PROXY_TEST_NOT_ZERO(1, 9); + VTBL_PROXY_TEST_NOT_ZERO(1, 10); + VTBL_PROXY_TEST_NOT_ZERO(1, 11); + VTBL_PROXY_TEST_NOT_ZERO(1, 12); + + VTBL_PROXY_TEST(2, 0, IUnknown_QueryInterface_Proxy); + VTBL_PROXY_TEST(2, 1, IUnknown_AddRef_Proxy); + VTBL_PROXY_TEST(2, 2, IUnknown_Release_Proxy); + VTBL_PROXY_TEST(2, 3, if1_fn1_Proxy); + todo_wine VTBL_PROXY_TEST_NOT_ZERO(2, 4); + + VTBL_PROXY_TEST(3, 0, GetProcAddress(rpcrt4,"IUnknown_QueryInterface_Proxy")); + VTBL_PROXY_TEST(3, 1, GetProcAddress(rpcrt4,"IUnknown_AddRef_Proxy")); + VTBL_PROXY_TEST(3, 2, GetProcAddress(rpcrt4,"IUnknown_Release_Proxy")); + VTBL_PROXY_TEST_NOT_ZERO(3, 3); + VTBL_PROXY_TEST_NOT_ZERO(3, 4); + VTBL_PROXY_TEST_NOT_ZERO(3, 5); + VTBL_PROXY_TEST_NOT_ZERO(3, 6); #undef VTBL_TEST_NOT_CHANGE_TO #undef VTBL_TEST_CHANGE_TO #undef VTBL_TEST_ZERO +#undef VTBL_PROXY_TEST +#undef VTBL_PROXY_TEST_NOT_ZERO + + for (i = 0; i < sizeof(interfaces)/sizeof(interfaces[0]); i++) + ok( proxy_vtbl[i]->header.piid == interfaces[i], + "wrong proxy %u iid %p/%p\n", i, proxy_vtbl[i]->header.piid, interfaces[i] ); ok(PSFactoryBuffer.RefCount == 1, "ref count %d\n", PSFactoryBuffer.RefCount); + IPSFactoryBuffer_Release(ppsf); + + r = NdrDllGetClassObject(&IID_if3, &IID_IPSFactoryBuffer, (void**)&ppsf, proxy_file_list, + NULL, &PSFactoryBuffer); + ok(r == S_OK, "ret %08x\n", r); + ok(ppsf != NULL, "ppsf == NULL\n"); + return ppsf; } @@ -599,19 +667,87 @@ static IUnknownVtbl create_stub_test_fail_vtbl = NULL }; +struct dummy_unknown +{ + const IUnknownVtbl *vtbl; + LONG ref; +}; + +static HRESULT WINAPI dummy_QueryInterface(IUnknown *This, REFIID iid, void **ppv) +{ + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI dummy_AddRef(LPUNKNOWN iface) +{ + struct dummy_unknown *this = (struct dummy_unknown *)iface; + return InterlockedIncrement( &this->ref ); +} + +static ULONG WINAPI dummy_Release(LPUNKNOWN iface) +{ + struct dummy_unknown *this = (struct dummy_unknown *)iface; + return InterlockedDecrement( &this->ref ); +} + +static IUnknownVtbl dummy_unknown_vtbl = +{ + dummy_QueryInterface, + dummy_AddRef, + dummy_Release +}; +static struct dummy_unknown dummy_unknown = { &dummy_unknown_vtbl, 0 }; + +static void create_proxy_test( IPSFactoryBuffer *ppsf, REFIID iid, const void *expected_vtbl ) +{ + IRpcProxyBuffer *proxy = NULL; + IUnknown *iface = NULL; + HRESULT r; + ULONG count; + + r = IPSFactoryBuffer_CreateProxy(ppsf, NULL, iid, &proxy, (void **)&iface); + ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %x\n", r ); + ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl ); + count = IUnknown_Release( iface ); + ok( count == 1, "wrong refcount %u\n", count ); + count = IRpcProxyBuffer_Release( proxy ); + ok( count == 0, "wrong refcount %u\n", count ); + + dummy_unknown.ref = 4; + r = IPSFactoryBuffer_CreateProxy(ppsf, (IUnknown *)&dummy_unknown, iid, &proxy, (void **)&iface); + ok( r == S_OK, "IPSFactoryBuffer_CreateProxy failed %x\n", r ); + ok( dummy_unknown.ref == 5, "wrong refcount %u\n", dummy_unknown.ref ); + ok( *(void **)iface == expected_vtbl, "wrong iface pointer %p/%p\n", *(void **)iface, expected_vtbl ); + count = IUnknown_Release( iface ); + ok( count == 4, "wrong refcount %u\n", count ); + ok( dummy_unknown.ref == 4, "wrong refcount %u\n", dummy_unknown.ref ); + count = IRpcProxyBuffer_Release( proxy ); + ok( count == 0, "wrong refcount %u\n", count ); + ok( dummy_unknown.ref == 4, "wrong refcount %u\n", dummy_unknown.ref ); +} + +static void test_CreateProxy( IPSFactoryBuffer *ppsf ) +{ + create_proxy_test( ppsf, &IID_if1, if1_proxy_vtbl.Vtbl ); + create_proxy_test( ppsf, &IID_if2, if2_proxy_vtbl.Vtbl ); + create_proxy_test( ppsf, &IID_if3, if3_proxy_vtbl.Vtbl ); + create_proxy_test( ppsf, &IID_if4, if4_proxy_vtbl.Vtbl ); +} + static void test_CreateStub(IPSFactoryBuffer *ppsf) { IUnknownVtbl *vtbl = &create_stub_test_vtbl; IUnknown *obj = (IUnknown*)&vtbl; IRpcStubBuffer *pstub = create_stub(ppsf, &IID_if1, obj, S_OK); CStdStubBuffer *cstd_stub = (CStdStubBuffer*)pstub; - const CInterfaceStubHeader *header = ((const CInterfaceStubHeader *)cstd_stub->lpVtbl) - 1; + const CInterfaceStubHeader *header = &CONTAINING_RECORD(cstd_stub->lpVtbl, const CInterfaceStubVtbl, Vtbl)->header; ok(IsEqualIID(header->piid, &IID_if1), "header iid differs\n"); ok(cstd_stub->RefCount == 1, "ref count %d\n", cstd_stub->RefCount); /* 0xdeadbeef returned from create_stub_test_QI */ ok(cstd_stub->pvServerObject == (void*)0xdeadbeef, "pvServerObject %p\n", cstd_stub->pvServerObject); - ok(cstd_stub->pPSFactory == ppsf, "pPSFactory %p\n", cstd_stub->pPSFactory); + ok(cstd_stub->pPSFactory != NULL, "pPSFactory was NULL\n"); vtbl = &create_stub_test_fail_vtbl; pstub = create_stub(ppsf, &IID_if1, obj, E_NOINTERFACE); @@ -937,6 +1073,7 @@ START_TEST( cstub ) ppsf = test_NdrDllGetClassObject(); test_NdrStubForwardingFunction(); + test_CreateProxy(ppsf); test_CreateStub(ppsf); test_Connect(ppsf); test_Disconnect(ppsf); diff --git a/rostests/winetests/rpcrt4/generated.c b/rostests/winetests/rpcrt4/generated.c index b281d0bb1fc..9e26e5337ec 100644 --- a/rostests/winetests/rpcrt4/generated.c +++ b/rostests/winetests/rpcrt4/generated.c @@ -1,4 +1,4 @@ -/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* File generated automatically from tools/winapi/tests.dat; do not edit! */ /* This file can be copied, modified and distributed without restriction. */ /* @@ -32,22 +32,14 @@ * Windows API extension */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) -# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) -#elif defined(__GNUC__) -# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) -#else -/* FIXME: Not sure if is possible to do without compiler extension */ -#endif - #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) #elif defined(__GNUC__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* - * FIXME: Not sure if is possible to do without compiler extension - * (if type is not just a name that is, if so the normal) + * FIXME: May not be possible without a compiler extension + * (if type is not just a name that is, otherwise the normal * TYPE_ALIGNMENT can be used) */ #endif @@ -64,84 +56,70 @@ * Test helper macros */ -#ifdef FIELD_ALIGNMENT -# define TEST_FIELD_ALIGNMENT(type, field, align) \ - ok(FIELD_ALIGNMENT(type, field) == align, \ - "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ - (int)FIELD_ALIGNMENT(type, field)) +#ifdef _WIN64 + +# define TEST_TYPE_SIZE(type, size) +# define TEST_TYPE_ALIGN(type, align) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) +# define TEST_FIELD_OFFSET(type, field, offset) + #else -# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) + +# define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); + +# ifdef TYPE_ALIGNMENT +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +#else +# define TEST_TYPE_ALIGN(type, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) \ - ok(FIELD_OFFSET(type, field) == offset, \ - "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ - (long int)FIELD_OFFSET(type, field)) - -#ifdef _TYPE_ALIGNMENT -#define TEST__TYPE_ALIGNMENT(type, align) \ - ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +# ifdef _TYPE_ALIGNMENT +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else -# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) #endif -#ifdef TYPE_ALIGNMENT -#define TEST_TYPE_ALIGNMENT(type, align) \ - ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) -#else -# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); + #endif -#define TEST_TYPE_SIZE(type, size) \ - ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) +#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) +#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) +#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0); +#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0); -/*********************************************************************** - * Test macros - */ - -#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ - TEST_TYPE_SIZE(field_type, field_size); \ - TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ - TEST_FIELD_OFFSET(type, field_name, field_offset); \ - -#define TEST_TYPE(type, size, align) \ - TEST_TYPE_ALIGNMENT(type, align); \ - TEST_TYPE_SIZE(type, size) - -#define TEST_TYPE_POINTER(type, size, align) \ - TEST__TYPE_ALIGNMENT(*(type)0, align); \ - TEST_TYPE_SIZE(*(type)0, size) - -#define TEST_TYPE_SIGNED(type) \ - ok((type) -1 < 0, "(" #type ") -1 < 0\n"); - -#define TEST_TYPE_UNSIGNED(type) \ - ok((type) -1 > 0, "(" #type ") -1 > 0\n"); static void test_pack_I_RPC_HANDLE(void) { /* I_RPC_HANDLE */ - TEST_TYPE(I_RPC_HANDLE, 4, 4); + TEST_TYPE_SIZE (I_RPC_HANDLE, 4) + TEST_TYPE_ALIGN (I_RPC_HANDLE, 4) } static void test_pack_RPC_STATUS(void) { /* RPC_STATUS */ - TEST_TYPE(RPC_STATUS, 4, 4); - TEST_TYPE_SIGNED(RPC_STATUS); + TEST_TYPE_SIZE (RPC_STATUS, 4) + TEST_TYPE_ALIGN (RPC_STATUS, 4) } static void test_pack_PRPC_POLICY(void) { /* PRPC_POLICY */ - TEST_TYPE(PRPC_POLICY, 4, 4); - TEST_TYPE_POINTER(PRPC_POLICY, 12, 4); + TEST_TYPE_SIZE (PRPC_POLICY, 4) + TEST_TYPE_ALIGN (PRPC_POLICY, 4) + TEST_TARGET_SIZE (PRPC_POLICY, 12) + TEST_TARGET_ALIGN(PRPC_POLICY, 4) } static void test_pack_RPC_AUTH_IDENTITY_HANDLE(void) { /* RPC_AUTH_IDENTITY_HANDLE */ - TEST_TYPE(RPC_AUTH_IDENTITY_HANDLE, 4, 4); + TEST_TYPE_SIZE (RPC_AUTH_IDENTITY_HANDLE, 4) + TEST_TYPE_ALIGN (RPC_AUTH_IDENTITY_HANDLE, 4) } static void test_pack_RPC_AUTH_KEY_RETRIEVAL_FN(void) @@ -152,95 +130,168 @@ static void test_pack_RPC_AUTH_KEY_RETRIEVAL_FN(void) static void test_pack_RPC_AUTHZ_HANDLE(void) { /* RPC_AUTHZ_HANDLE */ - TEST_TYPE(RPC_AUTHZ_HANDLE, 4, 4); + TEST_TYPE_SIZE (RPC_AUTHZ_HANDLE, 4) + TEST_TYPE_ALIGN (RPC_AUTHZ_HANDLE, 4) } static void test_pack_RPC_BINDING_HANDLE(void) { /* RPC_BINDING_HANDLE */ - TEST_TYPE(RPC_BINDING_HANDLE, 4, 4); + TEST_TYPE_SIZE (RPC_BINDING_HANDLE, 4) + TEST_TYPE_ALIGN (RPC_BINDING_HANDLE, 4) } static void test_pack_RPC_BINDING_VECTOR(void) { /* RPC_BINDING_VECTOR (pack 4) */ - TEST_TYPE(RPC_BINDING_VECTOR, 8, 4); - TEST_FIELD(RPC_BINDING_VECTOR, unsigned long, Count, 0, 4, 4); - TEST_FIELD(RPC_BINDING_VECTOR, RPC_BINDING_HANDLE[1], BindingH, 4, 4, 4); + TEST_TYPE_SIZE (RPC_BINDING_VECTOR, 8) + TEST_TYPE_ALIGN (RPC_BINDING_VECTOR, 4) + TEST_FIELD_SIZE (RPC_BINDING_VECTOR, Count, 4) + TEST_FIELD_ALIGN (RPC_BINDING_VECTOR, Count, 4) + TEST_FIELD_OFFSET(RPC_BINDING_VECTOR, Count, 0) + TEST_FIELD_SIZE (RPC_BINDING_VECTOR, BindingH, 4) + TEST_FIELD_ALIGN (RPC_BINDING_VECTOR, BindingH, 4) + TEST_FIELD_OFFSET(RPC_BINDING_VECTOR, BindingH, 4) } static void test_pack_RPC_IF_HANDLE(void) { /* RPC_IF_HANDLE */ - TEST_TYPE(RPC_IF_HANDLE, 4, 4); + TEST_TYPE_SIZE (RPC_IF_HANDLE, 4) + TEST_TYPE_ALIGN (RPC_IF_HANDLE, 4) } static void test_pack_RPC_IF_ID(void) { /* RPC_IF_ID (pack 4) */ + TEST_TYPE_SIZE (RPC_IF_ID, 20) + TEST_TYPE_ALIGN (RPC_IF_ID, 4) + TEST_FIELD_SIZE (RPC_IF_ID, Uuid, 16) + TEST_FIELD_ALIGN (RPC_IF_ID, Uuid, 4) + TEST_FIELD_OFFSET(RPC_IF_ID, Uuid, 0) + TEST_FIELD_SIZE (RPC_IF_ID, VersMajor, 2) + TEST_FIELD_ALIGN (RPC_IF_ID, VersMajor, 2) + TEST_FIELD_OFFSET(RPC_IF_ID, VersMajor, 16) + TEST_FIELD_SIZE (RPC_IF_ID, VersMinor, 2) + TEST_FIELD_ALIGN (RPC_IF_ID, VersMinor, 2) + TEST_FIELD_OFFSET(RPC_IF_ID, VersMinor, 18) } static void test_pack_RPC_POLICY(void) { /* RPC_POLICY (pack 4) */ - TEST_TYPE(RPC_POLICY, 12, 4); - TEST_FIELD(RPC_POLICY, unsigned int, Length, 0, 4, 4); - TEST_FIELD(RPC_POLICY, unsigned long, EndpointFlags, 4, 4, 4); - TEST_FIELD(RPC_POLICY, unsigned long, NICFlags, 8, 4, 4); + TEST_TYPE_SIZE (RPC_POLICY, 12) + TEST_TYPE_ALIGN (RPC_POLICY, 4) + TEST_FIELD_SIZE (RPC_POLICY, Length, 4) + TEST_FIELD_ALIGN (RPC_POLICY, Length, 4) + TEST_FIELD_OFFSET(RPC_POLICY, Length, 0) + TEST_FIELD_SIZE (RPC_POLICY, EndpointFlags, 4) + TEST_FIELD_ALIGN (RPC_POLICY, EndpointFlags, 4) + TEST_FIELD_OFFSET(RPC_POLICY, EndpointFlags, 4) + TEST_FIELD_SIZE (RPC_POLICY, NICFlags, 4) + TEST_FIELD_ALIGN (RPC_POLICY, NICFlags, 4) + TEST_FIELD_OFFSET(RPC_POLICY, NICFlags, 8) } static void test_pack_UUID_VECTOR(void) { /* UUID_VECTOR (pack 4) */ - TEST_TYPE(UUID_VECTOR, 8, 4); - TEST_FIELD(UUID_VECTOR, unsigned long, Count, 0, 4, 4); - TEST_FIELD(UUID_VECTOR, UUID *[1], Uuid, 4, 4, 4); + TEST_TYPE_SIZE (UUID_VECTOR, 8) + TEST_TYPE_ALIGN (UUID_VECTOR, 4) + TEST_FIELD_SIZE (UUID_VECTOR, Count, 4) + TEST_FIELD_ALIGN (UUID_VECTOR, Count, 4) + TEST_FIELD_OFFSET(UUID_VECTOR, Count, 0) + TEST_FIELD_SIZE (UUID_VECTOR, Uuid, 4) + TEST_FIELD_ALIGN (UUID_VECTOR, Uuid, 4) + TEST_FIELD_OFFSET(UUID_VECTOR, Uuid, 4) } static void test_pack_PRPC_CLIENT_INTERFACE(void) { /* PRPC_CLIENT_INTERFACE */ - TEST_TYPE(PRPC_CLIENT_INTERFACE, 4, 4); + TEST_TYPE_SIZE (PRPC_CLIENT_INTERFACE, 4) + TEST_TYPE_ALIGN (PRPC_CLIENT_INTERFACE, 4) + TEST_TARGET_SIZE (PRPC_CLIENT_INTERFACE, 68) + TEST_TARGET_ALIGN(PRPC_CLIENT_INTERFACE, 4) } static void test_pack_PRPC_DISPATCH_TABLE(void) { /* PRPC_DISPATCH_TABLE */ - TEST_TYPE(PRPC_DISPATCH_TABLE, 4, 4); - TEST_TYPE_POINTER(PRPC_DISPATCH_TABLE, 12, 4); + TEST_TYPE_SIZE (PRPC_DISPATCH_TABLE, 4) + TEST_TYPE_ALIGN (PRPC_DISPATCH_TABLE, 4) + TEST_TARGET_SIZE (PRPC_DISPATCH_TABLE, 12) + TEST_TARGET_ALIGN(PRPC_DISPATCH_TABLE, 4) } static void test_pack_PRPC_MESSAGE(void) { /* PRPC_MESSAGE */ - TEST_TYPE(PRPC_MESSAGE, 4, 4); - TEST_TYPE_POINTER(PRPC_MESSAGE, 44, 4); + TEST_TYPE_SIZE (PRPC_MESSAGE, 4) + TEST_TYPE_ALIGN (PRPC_MESSAGE, 4) + TEST_TARGET_SIZE (PRPC_MESSAGE, 44) + TEST_TARGET_ALIGN(PRPC_MESSAGE, 4) } static void test_pack_PRPC_PROTSEQ_ENDPOINT(void) { /* PRPC_PROTSEQ_ENDPOINT */ - TEST_TYPE(PRPC_PROTSEQ_ENDPOINT, 4, 4); - TEST_TYPE_POINTER(PRPC_PROTSEQ_ENDPOINT, 8, 4); + TEST_TYPE_SIZE (PRPC_PROTSEQ_ENDPOINT, 4) + TEST_TYPE_ALIGN (PRPC_PROTSEQ_ENDPOINT, 4) + TEST_TARGET_SIZE (PRPC_PROTSEQ_ENDPOINT, 8) + TEST_TARGET_ALIGN(PRPC_PROTSEQ_ENDPOINT, 4) } static void test_pack_PRPC_SERVER_INTERFACE(void) { /* PRPC_SERVER_INTERFACE */ - TEST_TYPE(PRPC_SERVER_INTERFACE, 4, 4); + TEST_TYPE_SIZE (PRPC_SERVER_INTERFACE, 4) + TEST_TYPE_ALIGN (PRPC_SERVER_INTERFACE, 4) + TEST_TARGET_SIZE (PRPC_SERVER_INTERFACE, 68) + TEST_TARGET_ALIGN(PRPC_SERVER_INTERFACE, 4) } static void test_pack_PRPC_SYNTAX_IDENTIFIER(void) { /* PRPC_SYNTAX_IDENTIFIER */ - TEST_TYPE(PRPC_SYNTAX_IDENTIFIER, 4, 4); - TEST_TYPE_POINTER(PRPC_SYNTAX_IDENTIFIER, 20, 4); + TEST_TYPE_SIZE (PRPC_SYNTAX_IDENTIFIER, 4) + TEST_TYPE_ALIGN (PRPC_SYNTAX_IDENTIFIER, 4) + TEST_TARGET_SIZE (PRPC_SYNTAX_IDENTIFIER, 20) + TEST_TARGET_ALIGN(PRPC_SYNTAX_IDENTIFIER, 4) } static void test_pack_RPC_CLIENT_INTERFACE(void) { /* RPC_CLIENT_INTERFACE (pack 4) */ - TEST_FIELD(RPC_CLIENT_INTERFACE, unsigned int, Length, 0, 4, 4); + TEST_TYPE_SIZE (RPC_CLIENT_INTERFACE, 68) + TEST_TYPE_ALIGN (RPC_CLIENT_INTERFACE, 4) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, Length, 4) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, Length, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, Length, 0) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, InterfaceId, 20) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, InterfaceId, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, InterfaceId, 4) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, TransferSyntax, 20) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, TransferSyntax, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, TransferSyntax, 24) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, DispatchTable, 4) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, DispatchTable, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, DispatchTable, 44) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, RpcProtseqEndpointCount, 4) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, RpcProtseqEndpointCount, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, RpcProtseqEndpointCount, 48) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, RpcProtseqEndpoint, 4) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, RpcProtseqEndpoint, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, RpcProtseqEndpoint, 52) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, Reserved, 4) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, Reserved, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, Reserved, 56) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, InterpreterInfo, 4) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, InterpreterInfo, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, InterpreterInfo, 60) + TEST_FIELD_SIZE (RPC_CLIENT_INTERFACE, Flags, 4) + TEST_FIELD_ALIGN (RPC_CLIENT_INTERFACE, Flags, 4) + TEST_FIELD_OFFSET(RPC_CLIENT_INTERFACE, Flags, 64) } static void test_pack_RPC_DISPATCH_FUNCTION(void) @@ -251,86 +302,184 @@ static void test_pack_RPC_DISPATCH_FUNCTION(void) static void test_pack_RPC_DISPATCH_TABLE(void) { /* RPC_DISPATCH_TABLE (pack 4) */ - TEST_TYPE(RPC_DISPATCH_TABLE, 12, 4); - TEST_FIELD(RPC_DISPATCH_TABLE, unsigned int, DispatchTableCount, 0, 4, 4); - TEST_FIELD(RPC_DISPATCH_TABLE, RPC_DISPATCH_FUNCTION*, DispatchTable, 4, 4, 4); - TEST_FIELD(RPC_DISPATCH_TABLE, LONG_PTR, Reserved, 8, 4, 4); + TEST_TYPE_SIZE (RPC_DISPATCH_TABLE, 12) + TEST_TYPE_ALIGN (RPC_DISPATCH_TABLE, 4) + TEST_FIELD_SIZE (RPC_DISPATCH_TABLE, DispatchTableCount, 4) + TEST_FIELD_ALIGN (RPC_DISPATCH_TABLE, DispatchTableCount, 4) + TEST_FIELD_OFFSET(RPC_DISPATCH_TABLE, DispatchTableCount, 0) + TEST_FIELD_SIZE (RPC_DISPATCH_TABLE, DispatchTable, 4) + TEST_FIELD_ALIGN (RPC_DISPATCH_TABLE, DispatchTable, 4) + TEST_FIELD_OFFSET(RPC_DISPATCH_TABLE, DispatchTable, 4) + TEST_FIELD_SIZE (RPC_DISPATCH_TABLE, Reserved, 4) + TEST_FIELD_ALIGN (RPC_DISPATCH_TABLE, Reserved, 4) + TEST_FIELD_OFFSET(RPC_DISPATCH_TABLE, Reserved, 8) } static void test_pack_RPC_MESSAGE(void) { /* RPC_MESSAGE (pack 4) */ - TEST_TYPE(RPC_MESSAGE, 44, 4); - TEST_FIELD(RPC_MESSAGE, RPC_BINDING_HANDLE, Handle, 0, 4, 4); - TEST_FIELD(RPC_MESSAGE, unsigned long, DataRepresentation, 4, 4, 4); - TEST_FIELD(RPC_MESSAGE, void*, Buffer, 8, 4, 4); - TEST_FIELD(RPC_MESSAGE, unsigned int, BufferLength, 12, 4, 4); - TEST_FIELD(RPC_MESSAGE, unsigned int, ProcNum, 16, 4, 4); - TEST_FIELD(RPC_MESSAGE, PRPC_SYNTAX_IDENTIFIER, TransferSyntax, 20, 4, 4); - TEST_FIELD(RPC_MESSAGE, void*, RpcInterfaceInformation, 24, 4, 4); - TEST_FIELD(RPC_MESSAGE, void*, ReservedForRuntime, 28, 4, 4); - TEST_FIELD(RPC_MESSAGE, RPC_MGR_EPV*, ManagerEpv, 32, 4, 4); - TEST_FIELD(RPC_MESSAGE, void*, ImportContext, 36, 4, 4); - TEST_FIELD(RPC_MESSAGE, unsigned long, RpcFlags, 40, 4, 4); + TEST_TYPE_SIZE (RPC_MESSAGE, 44) + TEST_TYPE_ALIGN (RPC_MESSAGE, 4) + TEST_FIELD_SIZE (RPC_MESSAGE, Handle, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, Handle, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, Handle, 0) + TEST_FIELD_SIZE (RPC_MESSAGE, DataRepresentation, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, DataRepresentation, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, DataRepresentation, 4) + TEST_FIELD_SIZE (RPC_MESSAGE, Buffer, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, Buffer, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, Buffer, 8) + TEST_FIELD_SIZE (RPC_MESSAGE, BufferLength, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, BufferLength, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, BufferLength, 12) + TEST_FIELD_SIZE (RPC_MESSAGE, ProcNum, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, ProcNum, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, ProcNum, 16) + TEST_FIELD_SIZE (RPC_MESSAGE, TransferSyntax, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, TransferSyntax, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, TransferSyntax, 20) + TEST_FIELD_SIZE (RPC_MESSAGE, RpcInterfaceInformation, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, RpcInterfaceInformation, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, RpcInterfaceInformation, 24) + TEST_FIELD_SIZE (RPC_MESSAGE, ReservedForRuntime, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, ReservedForRuntime, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, ReservedForRuntime, 28) + TEST_FIELD_SIZE (RPC_MESSAGE, ManagerEpv, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, ManagerEpv, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, ManagerEpv, 32) + TEST_FIELD_SIZE (RPC_MESSAGE, ImportContext, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, ImportContext, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, ImportContext, 36) + TEST_FIELD_SIZE (RPC_MESSAGE, RpcFlags, 4) + TEST_FIELD_ALIGN (RPC_MESSAGE, RpcFlags, 4) + TEST_FIELD_OFFSET(RPC_MESSAGE, RpcFlags, 40) } static void test_pack_RPC_PROTSEQ_ENDPOINT(void) { /* RPC_PROTSEQ_ENDPOINT (pack 4) */ - TEST_TYPE(RPC_PROTSEQ_ENDPOINT, 8, 4); - TEST_FIELD(RPC_PROTSEQ_ENDPOINT, unsigned char*, RpcProtocolSequence, 0, 4, 4); - TEST_FIELD(RPC_PROTSEQ_ENDPOINT, unsigned char*, Endpoint, 4, 4, 4); + TEST_TYPE_SIZE (RPC_PROTSEQ_ENDPOINT, 8) + TEST_TYPE_ALIGN (RPC_PROTSEQ_ENDPOINT, 4) + TEST_FIELD_SIZE (RPC_PROTSEQ_ENDPOINT, RpcProtocolSequence, 4) + TEST_FIELD_ALIGN (RPC_PROTSEQ_ENDPOINT, RpcProtocolSequence, 4) + TEST_FIELD_OFFSET(RPC_PROTSEQ_ENDPOINT, RpcProtocolSequence, 0) + TEST_FIELD_SIZE (RPC_PROTSEQ_ENDPOINT, Endpoint, 4) + TEST_FIELD_ALIGN (RPC_PROTSEQ_ENDPOINT, Endpoint, 4) + TEST_FIELD_OFFSET(RPC_PROTSEQ_ENDPOINT, Endpoint, 4) } static void test_pack_RPC_SERVER_INTERFACE(void) { /* RPC_SERVER_INTERFACE (pack 4) */ - TEST_FIELD(RPC_SERVER_INTERFACE, unsigned int, Length, 0, 4, 4); + TEST_TYPE_SIZE (RPC_SERVER_INTERFACE, 68) + TEST_TYPE_ALIGN (RPC_SERVER_INTERFACE, 4) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, Length, 4) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, Length, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, Length, 0) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, InterfaceId, 20) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, InterfaceId, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, InterfaceId, 4) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, TransferSyntax, 20) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, TransferSyntax, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, TransferSyntax, 24) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, DispatchTable, 4) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, DispatchTable, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, DispatchTable, 44) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, RpcProtseqEndpointCount, 4) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, RpcProtseqEndpointCount, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, RpcProtseqEndpointCount, 48) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, RpcProtseqEndpoint, 4) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, RpcProtseqEndpoint, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, RpcProtseqEndpoint, 52) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, DefaultManagerEpv, 4) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, DefaultManagerEpv, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, DefaultManagerEpv, 56) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, InterpreterInfo, 4) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, InterpreterInfo, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, InterpreterInfo, 60) + TEST_FIELD_SIZE (RPC_SERVER_INTERFACE, Flags, 4) + TEST_FIELD_ALIGN (RPC_SERVER_INTERFACE, Flags, 4) + TEST_FIELD_OFFSET(RPC_SERVER_INTERFACE, Flags, 64) } static void test_pack_RPC_SYNTAX_IDENTIFIER(void) { /* RPC_SYNTAX_IDENTIFIER (pack 4) */ - TEST_TYPE(RPC_SYNTAX_IDENTIFIER, 20, 4); - TEST_FIELD(RPC_SYNTAX_IDENTIFIER, GUID, SyntaxGUID, 0, 16, 4); - TEST_FIELD(RPC_SYNTAX_IDENTIFIER, RPC_VERSION, SyntaxVersion, 16, 4, 2); + TEST_TYPE_SIZE (RPC_SYNTAX_IDENTIFIER, 20) + TEST_TYPE_ALIGN (RPC_SYNTAX_IDENTIFIER, 4) + TEST_FIELD_SIZE (RPC_SYNTAX_IDENTIFIER, SyntaxGUID, 16) + TEST_FIELD_ALIGN (RPC_SYNTAX_IDENTIFIER, SyntaxGUID, 4) + TEST_FIELD_OFFSET(RPC_SYNTAX_IDENTIFIER, SyntaxGUID, 0) + TEST_FIELD_SIZE (RPC_SYNTAX_IDENTIFIER, SyntaxVersion, 4) + TEST_FIELD_ALIGN (RPC_SYNTAX_IDENTIFIER, SyntaxVersion, 2) + TEST_FIELD_OFFSET(RPC_SYNTAX_IDENTIFIER, SyntaxVersion, 16) } static void test_pack_RPC_VERSION(void) { /* RPC_VERSION (pack 4) */ - TEST_TYPE(RPC_VERSION, 4, 2); - TEST_FIELD(RPC_VERSION, unsigned short, MajorVersion, 0, 2, 2); - TEST_FIELD(RPC_VERSION, unsigned short, MinorVersion, 2, 2, 2); + TEST_TYPE_SIZE (RPC_VERSION, 4) + TEST_TYPE_ALIGN (RPC_VERSION, 2) + TEST_FIELD_SIZE (RPC_VERSION, MajorVersion, 2) + TEST_FIELD_ALIGN (RPC_VERSION, MajorVersion, 2) + TEST_FIELD_OFFSET(RPC_VERSION, MajorVersion, 0) + TEST_FIELD_SIZE (RPC_VERSION, MinorVersion, 2) + TEST_FIELD_ALIGN (RPC_VERSION, MinorVersion, 2) + TEST_FIELD_OFFSET(RPC_VERSION, MinorVersion, 2) } static void test_pack_ARRAY_INFO(void) { /* ARRAY_INFO (pack 4) */ - TEST_TYPE(ARRAY_INFO, 24, 4); - TEST_FIELD(ARRAY_INFO, long, Dimension, 0, 4, 4); - TEST_FIELD(ARRAY_INFO, unsigned long *, BufferConformanceMark, 4, 4, 4); - TEST_FIELD(ARRAY_INFO, unsigned long *, BufferVarianceMark, 8, 4, 4); - TEST_FIELD(ARRAY_INFO, unsigned long *, MaxCountArray, 12, 4, 4); - TEST_FIELD(ARRAY_INFO, unsigned long *, OffsetArray, 16, 4, 4); - TEST_FIELD(ARRAY_INFO, unsigned long *, ActualCountArray, 20, 4, 4); + TEST_TYPE_SIZE (ARRAY_INFO, 24) + TEST_TYPE_ALIGN (ARRAY_INFO, 4) + TEST_FIELD_SIZE (ARRAY_INFO, Dimension, 4) + TEST_FIELD_ALIGN (ARRAY_INFO, Dimension, 4) + TEST_FIELD_OFFSET(ARRAY_INFO, Dimension, 0) + TEST_FIELD_SIZE (ARRAY_INFO, BufferConformanceMark, 4) + TEST_FIELD_ALIGN (ARRAY_INFO, BufferConformanceMark, 4) + TEST_FIELD_OFFSET(ARRAY_INFO, BufferConformanceMark, 4) + TEST_FIELD_SIZE (ARRAY_INFO, BufferVarianceMark, 4) + TEST_FIELD_ALIGN (ARRAY_INFO, BufferVarianceMark, 4) + TEST_FIELD_OFFSET(ARRAY_INFO, BufferVarianceMark, 8) + TEST_FIELD_SIZE (ARRAY_INFO, MaxCountArray, 4) + TEST_FIELD_ALIGN (ARRAY_INFO, MaxCountArray, 4) + TEST_FIELD_OFFSET(ARRAY_INFO, MaxCountArray, 12) + TEST_FIELD_SIZE (ARRAY_INFO, OffsetArray, 4) + TEST_FIELD_ALIGN (ARRAY_INFO, OffsetArray, 4) + TEST_FIELD_OFFSET(ARRAY_INFO, OffsetArray, 16) + TEST_FIELD_SIZE (ARRAY_INFO, ActualCountArray, 4) + TEST_FIELD_ALIGN (ARRAY_INFO, ActualCountArray, 4) + TEST_FIELD_OFFSET(ARRAY_INFO, ActualCountArray, 20) } static void test_pack_COMM_FAULT_OFFSETS(void) { /* COMM_FAULT_OFFSETS (pack 4) */ - TEST_TYPE(COMM_FAULT_OFFSETS, 4, 2); - TEST_FIELD(COMM_FAULT_OFFSETS, short, CommOffset, 0, 2, 2); - TEST_FIELD(COMM_FAULT_OFFSETS, short, FaultOffset, 2, 2, 2); + TEST_TYPE_SIZE (COMM_FAULT_OFFSETS, 4) + TEST_TYPE_ALIGN (COMM_FAULT_OFFSETS, 2) + TEST_FIELD_SIZE (COMM_FAULT_OFFSETS, CommOffset, 2) + TEST_FIELD_ALIGN (COMM_FAULT_OFFSETS, CommOffset, 2) + TEST_FIELD_OFFSET(COMM_FAULT_OFFSETS, CommOffset, 0) + TEST_FIELD_SIZE (COMM_FAULT_OFFSETS, FaultOffset, 2) + TEST_FIELD_ALIGN (COMM_FAULT_OFFSETS, FaultOffset, 2) + TEST_FIELD_OFFSET(COMM_FAULT_OFFSETS, FaultOffset, 2) } static void test_pack_CS_STUB_INFO(void) { /* CS_STUB_INFO (pack 4) */ - TEST_TYPE(CS_STUB_INFO, 12, 4); - TEST_FIELD(CS_STUB_INFO, unsigned long, WireCodeset, 0, 4, 4); - TEST_FIELD(CS_STUB_INFO, unsigned long, DesiredReceivingCodeset, 4, 4, 4); - TEST_FIELD(CS_STUB_INFO, void *, CSArrayInfo, 8, 4, 4); + TEST_TYPE_SIZE (CS_STUB_INFO, 12) + TEST_TYPE_ALIGN (CS_STUB_INFO, 4) + TEST_FIELD_SIZE (CS_STUB_INFO, WireCodeset, 4) + TEST_FIELD_ALIGN (CS_STUB_INFO, WireCodeset, 4) + TEST_FIELD_OFFSET(CS_STUB_INFO, WireCodeset, 0) + TEST_FIELD_SIZE (CS_STUB_INFO, DesiredReceivingCodeset, 4) + TEST_FIELD_ALIGN (CS_STUB_INFO, DesiredReceivingCodeset, 4) + TEST_FIELD_OFFSET(CS_STUB_INFO, DesiredReceivingCodeset, 4) + TEST_FIELD_SIZE (CS_STUB_INFO, CSArrayInfo, 4) + TEST_FIELD_ALIGN (CS_STUB_INFO, CSArrayInfo, 4) + TEST_FIELD_OFFSET(CS_STUB_INFO, CSArrayInfo, 8) } static void test_pack_EXPR_EVAL(void) @@ -341,11 +490,20 @@ static void test_pack_EXPR_EVAL(void) static void test_pack_FULL_PTR_TO_REFID_ELEMENT(void) { /* FULL_PTR_TO_REFID_ELEMENT (pack 4) */ - TEST_TYPE(FULL_PTR_TO_REFID_ELEMENT, 16, 4); - TEST_FIELD(FULL_PTR_TO_REFID_ELEMENT, struct _FULL_PTR_TO_REFID_ELEMENT *, Next, 0, 4, 4); - TEST_FIELD(FULL_PTR_TO_REFID_ELEMENT, void *, Pointer, 4, 4, 4); - TEST_FIELD(FULL_PTR_TO_REFID_ELEMENT, unsigned long, RefId, 8, 4, 4); - TEST_FIELD(FULL_PTR_TO_REFID_ELEMENT, unsigned char, State, 12, 1, 1); + TEST_TYPE_SIZE (FULL_PTR_TO_REFID_ELEMENT, 16) + TEST_TYPE_ALIGN (FULL_PTR_TO_REFID_ELEMENT, 4) + TEST_FIELD_SIZE (FULL_PTR_TO_REFID_ELEMENT, Next, 4) + TEST_FIELD_ALIGN (FULL_PTR_TO_REFID_ELEMENT, Next, 4) + TEST_FIELD_OFFSET(FULL_PTR_TO_REFID_ELEMENT, Next, 0) + TEST_FIELD_SIZE (FULL_PTR_TO_REFID_ELEMENT, Pointer, 4) + TEST_FIELD_ALIGN (FULL_PTR_TO_REFID_ELEMENT, Pointer, 4) + TEST_FIELD_OFFSET(FULL_PTR_TO_REFID_ELEMENT, Pointer, 4) + TEST_FIELD_SIZE (FULL_PTR_TO_REFID_ELEMENT, RefId, 4) + TEST_FIELD_ALIGN (FULL_PTR_TO_REFID_ELEMENT, RefId, 4) + TEST_FIELD_OFFSET(FULL_PTR_TO_REFID_ELEMENT, RefId, 8) + TEST_FIELD_SIZE (FULL_PTR_TO_REFID_ELEMENT, State, 1) + TEST_FIELD_ALIGN (FULL_PTR_TO_REFID_ELEMENT, State, 1) + TEST_FIELD_OFFSET(FULL_PTR_TO_REFID_ELEMENT, State, 12) } static void test_pack_FULL_PTR_XLAT_TABLES(void) @@ -356,8 +514,12 @@ static void test_pack_FULL_PTR_XLAT_TABLES(void) static void test_pack_GENERIC_BINDING_INFO(void) { /* GENERIC_BINDING_INFO (pack 4) */ - TEST_FIELD(GENERIC_BINDING_INFO, void *, pObj, 0, 4, 4); - TEST_FIELD(GENERIC_BINDING_INFO, unsigned int, Size, 4, 4, 4); + TEST_FIELD_SIZE (GENERIC_BINDING_INFO, pObj, 4) + TEST_FIELD_ALIGN (GENERIC_BINDING_INFO, pObj, 4) + TEST_FIELD_OFFSET(GENERIC_BINDING_INFO, pObj, 0) + TEST_FIELD_SIZE (GENERIC_BINDING_INFO, Size, 4) + TEST_FIELD_ALIGN (GENERIC_BINDING_INFO, Size, 4) + TEST_FIELD_OFFSET(GENERIC_BINDING_INFO, Size, 4) } static void test_pack_GENERIC_BINDING_ROUTINE_PAIR(void) @@ -373,74 +535,170 @@ static void test_pack_MALLOC_FREE_STRUCT(void) static void test_pack_MIDL_FORMAT_STRING(void) { /* MIDL_FORMAT_STRING (pack 4) */ - TEST_FIELD(MIDL_FORMAT_STRING, short, Pad, 0, 2, 2); + TEST_FIELD_SIZE (MIDL_FORMAT_STRING, Pad, 2) + TEST_FIELD_ALIGN (MIDL_FORMAT_STRING, Pad, 2) + TEST_FIELD_OFFSET(MIDL_FORMAT_STRING, Pad, 0) } static void test_pack_MIDL_SERVER_INFO(void) { /* MIDL_SERVER_INFO (pack 4) */ - TEST_TYPE(MIDL_SERVER_INFO, 32, 4); - TEST_FIELD(MIDL_SERVER_INFO, PMIDL_STUB_DESC, pStubDesc, 0, 4, 4); - TEST_FIELD(MIDL_SERVER_INFO, SERVER_ROUTINE *, DispatchTable, 4, 4, 4); - TEST_FIELD(MIDL_SERVER_INFO, PFORMAT_STRING, ProcString, 8, 4, 4); - TEST_FIELD(MIDL_SERVER_INFO, unsigned short *, FmtStringOffset, 12, 4, 4); - TEST_FIELD(MIDL_SERVER_INFO, STUB_THUNK *, ThunkTable, 16, 4, 4); - TEST_FIELD(MIDL_SERVER_INFO, PRPC_SYNTAX_IDENTIFIER, pTransferSyntax, 20, 4, 4); - TEST_FIELD(MIDL_SERVER_INFO, ULONG_PTR, nCount, 24, 4, 4); - TEST_FIELD(MIDL_SERVER_INFO, PMIDL_SYNTAX_INFO, pSyntaxInfo, 28, 4, 4); + TEST_TYPE_SIZE (MIDL_SERVER_INFO, 32) + TEST_TYPE_ALIGN (MIDL_SERVER_INFO, 4) + TEST_FIELD_SIZE (MIDL_SERVER_INFO, pStubDesc, 4) + TEST_FIELD_ALIGN (MIDL_SERVER_INFO, pStubDesc, 4) + TEST_FIELD_OFFSET(MIDL_SERVER_INFO, pStubDesc, 0) + TEST_FIELD_SIZE (MIDL_SERVER_INFO, DispatchTable, 4) + TEST_FIELD_ALIGN (MIDL_SERVER_INFO, DispatchTable, 4) + TEST_FIELD_OFFSET(MIDL_SERVER_INFO, DispatchTable, 4) + TEST_FIELD_SIZE (MIDL_SERVER_INFO, ProcString, 4) + TEST_FIELD_ALIGN (MIDL_SERVER_INFO, ProcString, 4) + TEST_FIELD_OFFSET(MIDL_SERVER_INFO, ProcString, 8) + TEST_FIELD_SIZE (MIDL_SERVER_INFO, FmtStringOffset, 4) + TEST_FIELD_ALIGN (MIDL_SERVER_INFO, FmtStringOffset, 4) + TEST_FIELD_OFFSET(MIDL_SERVER_INFO, FmtStringOffset, 12) + TEST_FIELD_SIZE (MIDL_SERVER_INFO, ThunkTable, 4) + TEST_FIELD_ALIGN (MIDL_SERVER_INFO, ThunkTable, 4) + TEST_FIELD_OFFSET(MIDL_SERVER_INFO, ThunkTable, 16) + TEST_FIELD_SIZE (MIDL_SERVER_INFO, pTransferSyntax, 4) + TEST_FIELD_ALIGN (MIDL_SERVER_INFO, pTransferSyntax, 4) + TEST_FIELD_OFFSET(MIDL_SERVER_INFO, pTransferSyntax, 20) + TEST_FIELD_SIZE (MIDL_SERVER_INFO, nCount, 4) + TEST_FIELD_ALIGN (MIDL_SERVER_INFO, nCount, 4) + TEST_FIELD_OFFSET(MIDL_SERVER_INFO, nCount, 24) + TEST_FIELD_SIZE (MIDL_SERVER_INFO, pSyntaxInfo, 4) + TEST_FIELD_ALIGN (MIDL_SERVER_INFO, pSyntaxInfo, 4) + TEST_FIELD_OFFSET(MIDL_SERVER_INFO, pSyntaxInfo, 28) } static void test_pack_MIDL_STUB_DESC(void) { /* MIDL_STUB_DESC (pack 4) */ - TEST_FIELD(MIDL_STUB_DESC, void *, RpcInterfaceInformation, 0, 4, 4); + TEST_FIELD_SIZE (MIDL_STUB_DESC, RpcInterfaceInformation, 4) + TEST_FIELD_ALIGN (MIDL_STUB_DESC, RpcInterfaceInformation, 4) + TEST_FIELD_OFFSET(MIDL_STUB_DESC, RpcInterfaceInformation, 0) } static void test_pack_MIDL_STUB_MESSAGE(void) { /* MIDL_STUB_MESSAGE (pack 4) */ - TEST_FIELD(MIDL_STUB_MESSAGE, PRPC_MESSAGE, RpcMsg, 0, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned char *, Buffer, 4, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned char *, BufferStart, 8, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned char *, BufferEnd, 12, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned char *, BufferMark, 16, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned long, BufferLength, 20, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned long, MemorySize, 24, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned char *, Memory, 28, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, int, IsClient, 32, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, int, ReuseBuffer, 36, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, struct NDR_ALLOC_ALL_NODES_CONTEXT *, pAllocAllNodesContext, 40, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, struct NDR_POINTER_QUEUE_STATE *, pPointerQueueState, 44, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, int, IgnoreEmbeddedPointers, 48, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned char *, PointerBufferMark, 52, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned char, fBufferValid, 56, 1, 1); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned char, uFlags, 57, 1, 1); - TEST_FIELD(MIDL_STUB_MESSAGE, ULONG_PTR, MaxCount, 60, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned long, Offset, 64, 4, 4); - TEST_FIELD(MIDL_STUB_MESSAGE, unsigned long, ActualCount, 68, 4, 4); + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, RpcMsg, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, RpcMsg, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, RpcMsg, 0) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, Buffer, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, Buffer, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, Buffer, 4) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, BufferStart, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, BufferStart, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, BufferStart, 8) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, BufferEnd, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, BufferEnd, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, BufferEnd, 12) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, BufferMark, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, BufferMark, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, BufferMark, 16) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, BufferLength, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, BufferLength, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, BufferLength, 20) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, MemorySize, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, MemorySize, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, MemorySize, 24) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, Memory, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, Memory, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, Memory, 28) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, ReuseBuffer, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, ReuseBuffer, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, ReuseBuffer, 36) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, pAllocAllNodesContext, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, pAllocAllNodesContext, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, pAllocAllNodesContext, 40) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, pPointerQueueState, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, pPointerQueueState, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, pPointerQueueState, 44) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, IgnoreEmbeddedPointers, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, IgnoreEmbeddedPointers, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, IgnoreEmbeddedPointers, 48) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, PointerBufferMark, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, PointerBufferMark, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, PointerBufferMark, 52) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, CorrDespIncrement, 1) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, CorrDespIncrement, 1) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, CorrDespIncrement, 56) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, uFlags, 1) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, uFlags, 1) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, uFlags, 57) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, MaxCount, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, MaxCount, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, MaxCount, 60) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, Offset, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, Offset, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, Offset, 64) + TEST_FIELD_SIZE (MIDL_STUB_MESSAGE, ActualCount, 4) + TEST_FIELD_ALIGN (MIDL_STUB_MESSAGE, ActualCount, 4) + TEST_FIELD_OFFSET(MIDL_STUB_MESSAGE, ActualCount, 68) } static void test_pack_MIDL_STUBLESS_PROXY_INFO(void) { /* MIDL_STUBLESS_PROXY_INFO (pack 4) */ - TEST_TYPE(MIDL_STUBLESS_PROXY_INFO, 24, 4); - TEST_FIELD(MIDL_STUBLESS_PROXY_INFO, PMIDL_STUB_DESC, pStubDesc, 0, 4, 4); - TEST_FIELD(MIDL_STUBLESS_PROXY_INFO, PFORMAT_STRING, ProcFormatString, 4, 4, 4); - TEST_FIELD(MIDL_STUBLESS_PROXY_INFO, unsigned short *, FormatStringOffset, 8, 4, 4); - TEST_FIELD(MIDL_STUBLESS_PROXY_INFO, PRPC_SYNTAX_IDENTIFIER, pTransferSyntax, 12, 4, 4); - TEST_FIELD(MIDL_STUBLESS_PROXY_INFO, ULONG_PTR, nCount, 16, 4, 4); - TEST_FIELD(MIDL_STUBLESS_PROXY_INFO, PMIDL_SYNTAX_INFO, pSyntaxInfo, 20, 4, 4); + TEST_TYPE_SIZE (MIDL_STUBLESS_PROXY_INFO, 24) + TEST_TYPE_ALIGN (MIDL_STUBLESS_PROXY_INFO, 4) + TEST_FIELD_SIZE (MIDL_STUBLESS_PROXY_INFO, pStubDesc, 4) + TEST_FIELD_ALIGN (MIDL_STUBLESS_PROXY_INFO, pStubDesc, 4) + TEST_FIELD_OFFSET(MIDL_STUBLESS_PROXY_INFO, pStubDesc, 0) + TEST_FIELD_SIZE (MIDL_STUBLESS_PROXY_INFO, ProcFormatString, 4) + TEST_FIELD_ALIGN (MIDL_STUBLESS_PROXY_INFO, ProcFormatString, 4) + TEST_FIELD_OFFSET(MIDL_STUBLESS_PROXY_INFO, ProcFormatString, 4) + TEST_FIELD_SIZE (MIDL_STUBLESS_PROXY_INFO, FormatStringOffset, 4) + TEST_FIELD_ALIGN (MIDL_STUBLESS_PROXY_INFO, FormatStringOffset, 4) + TEST_FIELD_OFFSET(MIDL_STUBLESS_PROXY_INFO, FormatStringOffset, 8) + TEST_FIELD_SIZE (MIDL_STUBLESS_PROXY_INFO, pTransferSyntax, 4) + TEST_FIELD_ALIGN (MIDL_STUBLESS_PROXY_INFO, pTransferSyntax, 4) + TEST_FIELD_OFFSET(MIDL_STUBLESS_PROXY_INFO, pTransferSyntax, 12) + TEST_FIELD_SIZE (MIDL_STUBLESS_PROXY_INFO, nCount, 4) + TEST_FIELD_ALIGN (MIDL_STUBLESS_PROXY_INFO, nCount, 4) + TEST_FIELD_OFFSET(MIDL_STUBLESS_PROXY_INFO, nCount, 16) + TEST_FIELD_SIZE (MIDL_STUBLESS_PROXY_INFO, pSyntaxInfo, 4) + TEST_FIELD_ALIGN (MIDL_STUBLESS_PROXY_INFO, pSyntaxInfo, 4) + TEST_FIELD_OFFSET(MIDL_STUBLESS_PROXY_INFO, pSyntaxInfo, 20) } static void test_pack_MIDL_SYNTAX_INFO(void) { /* MIDL_SYNTAX_INFO (pack 4) */ + TEST_TYPE_SIZE (MIDL_SYNTAX_INFO, 48) + TEST_TYPE_ALIGN (MIDL_SYNTAX_INFO, 4) + TEST_FIELD_SIZE (MIDL_SYNTAX_INFO, TransferSyntax, 20) + TEST_FIELD_ALIGN (MIDL_SYNTAX_INFO, TransferSyntax, 4) + TEST_FIELD_OFFSET(MIDL_SYNTAX_INFO, TransferSyntax, 0) + TEST_FIELD_SIZE (MIDL_SYNTAX_INFO, DispatchTable, 4) + TEST_FIELD_ALIGN (MIDL_SYNTAX_INFO, DispatchTable, 4) + TEST_FIELD_OFFSET(MIDL_SYNTAX_INFO, DispatchTable, 20) + TEST_FIELD_SIZE (MIDL_SYNTAX_INFO, ProcString, 4) + TEST_FIELD_ALIGN (MIDL_SYNTAX_INFO, ProcString, 4) + TEST_FIELD_OFFSET(MIDL_SYNTAX_INFO, ProcString, 24) + TEST_FIELD_SIZE (MIDL_SYNTAX_INFO, FmtStringOffset, 4) + TEST_FIELD_ALIGN (MIDL_SYNTAX_INFO, FmtStringOffset, 4) + TEST_FIELD_OFFSET(MIDL_SYNTAX_INFO, FmtStringOffset, 28) + TEST_FIELD_SIZE (MIDL_SYNTAX_INFO, TypeString, 4) + TEST_FIELD_ALIGN (MIDL_SYNTAX_INFO, TypeString, 4) + TEST_FIELD_OFFSET(MIDL_SYNTAX_INFO, TypeString, 32) + TEST_FIELD_SIZE (MIDL_SYNTAX_INFO, aUserMarshalQuadruple, 4) + TEST_FIELD_ALIGN (MIDL_SYNTAX_INFO, aUserMarshalQuadruple, 4) + TEST_FIELD_OFFSET(MIDL_SYNTAX_INFO, aUserMarshalQuadruple, 36) + TEST_FIELD_SIZE (MIDL_SYNTAX_INFO, pReserved1, 4) + TEST_FIELD_ALIGN (MIDL_SYNTAX_INFO, pReserved1, 4) + TEST_FIELD_OFFSET(MIDL_SYNTAX_INFO, pReserved1, 40) + TEST_FIELD_SIZE (MIDL_SYNTAX_INFO, pReserved2, 4) + TEST_FIELD_ALIGN (MIDL_SYNTAX_INFO, pReserved2, 4) + TEST_FIELD_OFFSET(MIDL_SYNTAX_INFO, pReserved2, 44) } static void test_pack_NDR_CCONTEXT(void) { /* NDR_CCONTEXT */ - TEST_TYPE(NDR_CCONTEXT, 4, 4); + TEST_TYPE_SIZE (NDR_CCONTEXT, 4) + TEST_TYPE_ALIGN (NDR_CCONTEXT, 4) } static void test_pack_NDR_NOTIFY_ROUTINE(void) @@ -461,110 +719,157 @@ static void test_pack_NDR_RUNDOWN(void) static void test_pack_NDR_SCONTEXT(void) { /* NDR_SCONTEXT */ - TEST_TYPE(NDR_SCONTEXT, 4, 4); + TEST_TYPE_SIZE (NDR_SCONTEXT, 4) + TEST_TYPE_ALIGN (NDR_SCONTEXT, 4) +} + +static void test_pack_NDR_USER_MARSHAL_INFO(void) +{ + /* NDR_USER_MARSHAL_INFO (pack 4) */ + TEST_FIELD_SIZE (NDR_USER_MARSHAL_INFO, InformationLevel, 4) + TEST_FIELD_ALIGN (NDR_USER_MARSHAL_INFO, InformationLevel, 4) + TEST_FIELD_OFFSET(NDR_USER_MARSHAL_INFO, InformationLevel, 0) +} + +static void test_pack_NDR_USER_MARSHAL_INFO_LEVEL1(void) +{ + /* NDR_USER_MARSHAL_INFO_LEVEL1 (pack 4) */ + TEST_FIELD_SIZE (NDR_USER_MARSHAL_INFO_LEVEL1, Buffer, 4) + TEST_FIELD_ALIGN (NDR_USER_MARSHAL_INFO_LEVEL1, Buffer, 4) + TEST_FIELD_OFFSET(NDR_USER_MARSHAL_INFO_LEVEL1, Buffer, 0) + TEST_FIELD_SIZE (NDR_USER_MARSHAL_INFO_LEVEL1, BufferSize, 4) + TEST_FIELD_ALIGN (NDR_USER_MARSHAL_INFO_LEVEL1, BufferSize, 4) + TEST_FIELD_OFFSET(NDR_USER_MARSHAL_INFO_LEVEL1, BufferSize, 4) } static void test_pack_PARRAY_INFO(void) { /* PARRAY_INFO */ - TEST_TYPE(PARRAY_INFO, 4, 4); - TEST_TYPE_POINTER(PARRAY_INFO, 24, 4); + TEST_TYPE_SIZE (PARRAY_INFO, 4) + TEST_TYPE_ALIGN (PARRAY_INFO, 4) + TEST_TARGET_SIZE (PARRAY_INFO, 24) + TEST_TARGET_ALIGN(PARRAY_INFO, 4) } static void test_pack_PFORMAT_STRING(void) { /* PFORMAT_STRING */ - TEST_TYPE(PFORMAT_STRING, 4, 4); + TEST_TYPE_SIZE (PFORMAT_STRING, 4) + TEST_TYPE_ALIGN (PFORMAT_STRING, 4) } static void test_pack_PFULL_PTR_TO_REFID_ELEMENT(void) { /* PFULL_PTR_TO_REFID_ELEMENT */ - TEST_TYPE(PFULL_PTR_TO_REFID_ELEMENT, 4, 4); - TEST_TYPE_POINTER(PFULL_PTR_TO_REFID_ELEMENT, 16, 4); + TEST_TYPE_SIZE (PFULL_PTR_TO_REFID_ELEMENT, 4) + TEST_TYPE_ALIGN (PFULL_PTR_TO_REFID_ELEMENT, 4) + TEST_TARGET_SIZE (PFULL_PTR_TO_REFID_ELEMENT, 16) + TEST_TARGET_ALIGN(PFULL_PTR_TO_REFID_ELEMENT, 4) } static void test_pack_PFULL_PTR_XLAT_TABLES(void) { /* PFULL_PTR_XLAT_TABLES */ - TEST_TYPE(PFULL_PTR_XLAT_TABLES, 4, 4); + TEST_TYPE_SIZE (PFULL_PTR_XLAT_TABLES, 4) + TEST_TYPE_ALIGN (PFULL_PTR_XLAT_TABLES, 4) } static void test_pack_PGENERIC_BINDING_INFO(void) { /* PGENERIC_BINDING_INFO */ - TEST_TYPE(PGENERIC_BINDING_INFO, 4, 4); + TEST_TYPE_SIZE (PGENERIC_BINDING_INFO, 4) + TEST_TYPE_ALIGN (PGENERIC_BINDING_INFO, 4) } static void test_pack_PGENERIC_BINDING_ROUTINE_PAIR(void) { /* PGENERIC_BINDING_ROUTINE_PAIR */ - TEST_TYPE(PGENERIC_BINDING_ROUTINE_PAIR, 4, 4); + TEST_TYPE_SIZE (PGENERIC_BINDING_ROUTINE_PAIR, 4) + TEST_TYPE_ALIGN (PGENERIC_BINDING_ROUTINE_PAIR, 4) } static void test_pack_PMIDL_SERVER_INFO(void) { /* PMIDL_SERVER_INFO */ - TEST_TYPE(PMIDL_SERVER_INFO, 4, 4); - TEST_TYPE_POINTER(PMIDL_SERVER_INFO, 32, 4); + TEST_TYPE_SIZE (PMIDL_SERVER_INFO, 4) + TEST_TYPE_ALIGN (PMIDL_SERVER_INFO, 4) + TEST_TARGET_SIZE (PMIDL_SERVER_INFO, 32) + TEST_TARGET_ALIGN(PMIDL_SERVER_INFO, 4) } static void test_pack_PMIDL_STUB_DESC(void) { /* PMIDL_STUB_DESC */ - TEST_TYPE(PMIDL_STUB_DESC, 4, 4); + TEST_TYPE_SIZE (PMIDL_STUB_DESC, 4) + TEST_TYPE_ALIGN (PMIDL_STUB_DESC, 4) } static void test_pack_PMIDL_STUB_MESSAGE(void) { /* PMIDL_STUB_MESSAGE */ - TEST_TYPE(PMIDL_STUB_MESSAGE, 4, 4); + TEST_TYPE_SIZE (PMIDL_STUB_MESSAGE, 4) + TEST_TYPE_ALIGN (PMIDL_STUB_MESSAGE, 4) } static void test_pack_PMIDL_STUBLESS_PROXY_INFO(void) { /* PMIDL_STUBLESS_PROXY_INFO */ - TEST_TYPE(PMIDL_STUBLESS_PROXY_INFO, 4, 4); - TEST_TYPE_POINTER(PMIDL_STUBLESS_PROXY_INFO, 24, 4); + TEST_TYPE_SIZE (PMIDL_STUBLESS_PROXY_INFO, 4) + TEST_TYPE_ALIGN (PMIDL_STUBLESS_PROXY_INFO, 4) + TEST_TARGET_SIZE (PMIDL_STUBLESS_PROXY_INFO, 24) + TEST_TARGET_ALIGN(PMIDL_STUBLESS_PROXY_INFO, 4) } static void test_pack_PMIDL_SYNTAX_INFO(void) { /* PMIDL_SYNTAX_INFO */ - TEST_TYPE(PMIDL_SYNTAX_INFO, 4, 4); + TEST_TYPE_SIZE (PMIDL_SYNTAX_INFO, 4) + TEST_TYPE_ALIGN (PMIDL_SYNTAX_INFO, 4) + TEST_TARGET_SIZE (PMIDL_SYNTAX_INFO, 48) + TEST_TARGET_ALIGN(PMIDL_SYNTAX_INFO, 4) } static void test_pack_PNDR_ASYNC_MESSAGE(void) { /* PNDR_ASYNC_MESSAGE */ - TEST_TYPE(PNDR_ASYNC_MESSAGE, 4, 4); + TEST_TYPE_SIZE (PNDR_ASYNC_MESSAGE, 4) + TEST_TYPE_ALIGN (PNDR_ASYNC_MESSAGE, 4) } static void test_pack_PNDR_CORRELATION_INFO(void) { /* PNDR_CORRELATION_INFO */ - TEST_TYPE(PNDR_CORRELATION_INFO, 4, 4); + TEST_TYPE_SIZE (PNDR_CORRELATION_INFO, 4) + TEST_TYPE_ALIGN (PNDR_CORRELATION_INFO, 4) } static void test_pack_PSCONTEXT_QUEUE(void) { /* PSCONTEXT_QUEUE */ - TEST_TYPE(PSCONTEXT_QUEUE, 4, 4); - TEST_TYPE_POINTER(PSCONTEXT_QUEUE, 8, 4); + TEST_TYPE_SIZE (PSCONTEXT_QUEUE, 4) + TEST_TYPE_ALIGN (PSCONTEXT_QUEUE, 4) + TEST_TARGET_SIZE (PSCONTEXT_QUEUE, 8) + TEST_TARGET_ALIGN(PSCONTEXT_QUEUE, 4) } static void test_pack_PXMIT_ROUTINE_QUINTUPLE(void) { /* PXMIT_ROUTINE_QUINTUPLE */ - TEST_TYPE(PXMIT_ROUTINE_QUINTUPLE, 4, 4); + TEST_TYPE_SIZE (PXMIT_ROUTINE_QUINTUPLE, 4) + TEST_TYPE_ALIGN (PXMIT_ROUTINE_QUINTUPLE, 4) } static void test_pack_SCONTEXT_QUEUE(void) { /* SCONTEXT_QUEUE (pack 4) */ - TEST_TYPE(SCONTEXT_QUEUE, 8, 4); - TEST_FIELD(SCONTEXT_QUEUE, unsigned long, NumberOfObjects, 0, 4, 4); - TEST_FIELD(SCONTEXT_QUEUE, NDR_SCONTEXT *, ArrayOfObjects, 4, 4, 4); + TEST_TYPE_SIZE (SCONTEXT_QUEUE, 8) + TEST_TYPE_ALIGN (SCONTEXT_QUEUE, 4) + TEST_FIELD_SIZE (SCONTEXT_QUEUE, NumberOfObjects, 4) + TEST_FIELD_ALIGN (SCONTEXT_QUEUE, NumberOfObjects, 4) + TEST_FIELD_OFFSET(SCONTEXT_QUEUE, NumberOfObjects, 0) + TEST_FIELD_SIZE (SCONTEXT_QUEUE, ArrayOfObjects, 4) + TEST_FIELD_ALIGN (SCONTEXT_QUEUE, ArrayOfObjects, 4) + TEST_FIELD_OFFSET(SCONTEXT_QUEUE, ArrayOfObjects, 4) } static void test_pack_SERVER_ROUTINE(void) @@ -580,10 +885,18 @@ static void test_pack_STUB_THUNK(void) static void test_pack_USER_MARSHAL_CB(void) { /* USER_MARSHAL_CB (pack 4) */ - TEST_FIELD(USER_MARSHAL_CB, unsigned long, Flags, 0, 4, 4); - TEST_FIELD(USER_MARSHAL_CB, PMIDL_STUB_MESSAGE, pStubMsg, 4, 4, 4); - TEST_FIELD(USER_MARSHAL_CB, PFORMAT_STRING, pReserve, 8, 4, 4); - TEST_FIELD(USER_MARSHAL_CB, unsigned long, Signature, 12, 4, 4); + TEST_FIELD_SIZE (USER_MARSHAL_CB, Flags, 4) + TEST_FIELD_ALIGN (USER_MARSHAL_CB, Flags, 4) + TEST_FIELD_OFFSET(USER_MARSHAL_CB, Flags, 0) + TEST_FIELD_SIZE (USER_MARSHAL_CB, pStubMsg, 4) + TEST_FIELD_ALIGN (USER_MARSHAL_CB, pStubMsg, 4) + TEST_FIELD_OFFSET(USER_MARSHAL_CB, pStubMsg, 4) + TEST_FIELD_SIZE (USER_MARSHAL_CB, pReserve, 4) + TEST_FIELD_ALIGN (USER_MARSHAL_CB, pReserve, 4) + TEST_FIELD_OFFSET(USER_MARSHAL_CB, pReserve, 8) + TEST_FIELD_SIZE (USER_MARSHAL_CB, Signature, 4) + TEST_FIELD_ALIGN (USER_MARSHAL_CB, Signature, 4) + TEST_FIELD_OFFSET(USER_MARSHAL_CB, Signature, 12) } static void test_pack_USER_MARSHAL_FREEING_ROUTINE(void) @@ -649,6 +962,8 @@ static void test_pack(void) test_pack_NDR_NOTIFY_ROUTINE(); test_pack_NDR_RUNDOWN(); test_pack_NDR_SCONTEXT(); + test_pack_NDR_USER_MARSHAL_INFO(); + test_pack_NDR_USER_MARSHAL_INFO_LEVEL1(); test_pack_PARRAY_INFO(); test_pack_PFORMAT_STRING(); test_pack_PFULL_PTR_TO_REFID_ELEMENT(); @@ -705,5 +1020,9 @@ static void test_pack(void) START_TEST(generated) { +#ifdef _WIN64 + ok(0, "The type size / alignment tests don't support Win64 yet\n"); +#else test_pack(); +#endif } diff --git a/rostests/winetests/rpcrt4/ndr_marshall.c b/rostests/winetests/rpcrt4/ndr_marshall.c index 1ff5e3b0438..565b677278a 100644 --- a/rostests/winetests/rpcrt4/ndr_marshall.c +++ b/rostests/winetests/rpcrt4/ndr_marshall.c @@ -36,7 +36,7 @@ static int my_alloc_called; static int my_free_called; -static void * CALLBACK my_alloc(size_t size) +static void * CALLBACK my_alloc(SIZE_T size) { my_alloc_called++; return NdrOleAllocate(size); @@ -97,13 +97,48 @@ static const RPC_SERVER_INTERFACE IFoo___RpcServerInterface = }; static RPC_IF_HANDLE IFoo_v0_0_s_ifspec = (RPC_IF_HANDLE)& IFoo___RpcServerInterface; +static BOOL use_pointer_ids = FALSE; + +static void determine_pointer_marshalling_style(void) +{ + RPC_MESSAGE RpcMessage; + MIDL_STUB_MESSAGE StubMsg; + MIDL_STUB_DESC StubDesc; + char ch = 0xde; + + static const unsigned char fmtstr_up_char[] = + { + 0x12, 0x8, /* FC_UP [simple_pointer] */ + 0x2, /* FC_CHAR */ + 0x5c, /* FC_PAD */ + }; + + StubDesc = Object_StubDesc; + StubDesc.pFormatTypes = NULL; + + NdrClientInitializeNew( + &RpcMessage, + &StubMsg, + &StubDesc, + 0); + + StubMsg.BufferLength = 8; + StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength); + NdrPointerMarshall(&StubMsg, (unsigned char*)&ch, fmtstr_up_char); + ok(StubMsg.Buffer == StubMsg.BufferStart + 5, "%p %p\n", StubMsg.Buffer, StubMsg.BufferStart); + + use_pointer_ids = (*(unsigned int *)StubMsg.BufferStart != (UINT_PTR)&ch); + trace("Pointer marshalling using %s\n", use_pointer_ids ? "pointer ids" : "pointer value"); + + HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart); +} static void test_ndr_simple_type(void) { RPC_MESSAGE RpcMessage; MIDL_STUB_MESSAGE StubMsg; MIDL_STUB_DESC StubDesc; - long l, l2 = 0; + LONG l, l2 = 0; StubDesc = Object_StubDesc; StubDesc.pFormatTypes = NULL; @@ -119,28 +154,27 @@ static void test_ndr_simple_type(void) l = 0xcafebabe; NdrSimpleTypeMarshall(&StubMsg, (unsigned char*)&l, 8 /* FC_LONG */); ok(StubMsg.Buffer == StubMsg.BufferStart + 4, "%p %p\n", StubMsg.Buffer, StubMsg.BufferStart); - ok(*(long*)StubMsg.BufferStart == l, "%ld\n", *(long*)StubMsg.BufferStart); + ok(*(LONG*)StubMsg.BufferStart == l, "%d\n", *(LONG*)StubMsg.BufferStart); StubMsg.Buffer = StubMsg.BufferStart + 1; NdrSimpleTypeMarshall(&StubMsg, (unsigned char*)&l, 8 /* FC_LONG */); ok(StubMsg.Buffer == StubMsg.BufferStart + 8, "%p %p\n", StubMsg.Buffer, StubMsg.BufferStart); - ok(*(long*)(StubMsg.BufferStart + 4) == l, "%ld\n", *(long*)StubMsg.BufferStart); + ok(*(LONG*)(StubMsg.BufferStart + 4) == l, "%d\n", *(LONG*)StubMsg.BufferStart); StubMsg.Buffer = StubMsg.BufferStart + 1; NdrSimpleTypeUnmarshall(&StubMsg, (unsigned char*)&l2, 8 /* FC_LONG */); ok(StubMsg.Buffer == StubMsg.BufferStart + 8, "%p %p\n", StubMsg.Buffer, StubMsg.BufferStart); - ok(l2 == l, "%ld\n", l2); + ok(l2 == l, "%d\n", l2); HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart); } static void test_pointer_marshal(const unsigned char *formattypes, - void *memsrc, - long srcsize, + void *memsrc, DWORD srcsize, const void *wiredata, ULONG wiredatalen, int(*cmp)(const void*,const void*,size_t), - long num_additional_allocs, + int num_additional_allocs, const char *msgpfx) { RPC_MESSAGE RpcMessage; @@ -177,20 +211,25 @@ static void test_pointer_marshal(const unsigned char *formattypes, ptr = NdrPointerMarshall( &StubMsg, memsrc, formattypes ); ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr); + if (srcsize == 8 && wiredatalen == 16 && StubMsg.Buffer - StubMsg.BufferStart == 12) + { + /* win9x doesn't align 8-byte types properly */ + wiredatalen = 12; + } + else + { ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen); ok(!memcmp(StubMsg.BufferStart, wiredata, wiredatalen), "%s: incorrectly marshaled\n", msgpfx); + } StubMsg.Buffer = StubMsg.BufferStart; StubMsg.MemorySize = 0; - if (0) - { - /* NdrPointerMemorySize crashes under Wine */ size = NdrPointerMemorySize( &StubMsg, formattypes ); ok(size == StubMsg.MemorySize, "%s: mem size %u size %u\n", msgpfx, StubMsg.MemorySize, size); ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen); if(formattypes[1] & 0x10 /* FC_POINTER_DEREF */) - ok(size == srcsize + 4, "%s: mem size %u\n", msgpfx, size); + ok(size == srcsize + sizeof(void *), "%s: mem size %u\n", msgpfx, size); else ok(size == srcsize, "%s: mem size %u\n", msgpfx, size); @@ -200,7 +239,7 @@ static void test_pointer_marshal(const unsigned char *formattypes, ok(size == StubMsg.MemorySize, "%s: mem size %u size %u\n", msgpfx, StubMsg.MemorySize, size); ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen); if(formattypes[1] & 0x10 /* FC_POINTER_DEREF */) - ok(size == srcsize + 4 + 16, "%s: mem size %u\n", msgpfx, size); + ok(size == srcsize + sizeof(void *) + 16, "%s: mem size %u\n", msgpfx, size); else ok(size == srcsize + 16, "%s: mem size %u\n", msgpfx, size); @@ -210,10 +249,9 @@ static void test_pointer_marshal(const unsigned char *formattypes, ok(size == StubMsg.MemorySize, "%s: mem size %u size %u\n", msgpfx, StubMsg.MemorySize, size); ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p len %d\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart, wiredatalen); if(formattypes[1] & 0x10 /* FC_POINTER_DEREF */) - ok(size == srcsize + 4 + (srcsize == 8 ? 8 : 4), "%s: mem size %u\n", msgpfx, size); + ok(size == srcsize + sizeof(void *) + (srcsize == 8 ? 8 : sizeof(void *)), "%s: mem size %u\n", msgpfx, size); else - ok(size == srcsize + (srcsize == 8 ? 8 : 4), "%s: mem size %u\n", msgpfx, size); - } + ok(size == srcsize + (srcsize == 8 ? 8 : sizeof(void *)), "%s: mem size %u\n", msgpfx, size); size = srcsize; if(formattypes[1] & 0x10) size += 4; @@ -267,6 +305,8 @@ todo_wine { NdrPointerFree(&StubMsg, mem, formattypes); /* again pass address of NULL ptr, but pretend we're a server */ + if (0) /* crashes on Win9x and NT4 */ + { mem = NULL; StubMsg.Buffer = StubMsg.BufferStart; StubMsg.IsClient = 0; @@ -284,6 +324,7 @@ todo_wine { my_alloc_called = 0; } } + } HeapFree(GetProcessHeap(), 0, mem_orig); HeapFree(GetProcessHeap(), 0, StubMsg.BufferStart); } @@ -301,7 +342,7 @@ static void test_simple_types(void) unsigned char *ch_ptr; unsigned short s; unsigned int i; - unsigned long l; + ULONG l; ULONGLONG ll; float f; double d; @@ -423,8 +464,11 @@ static void test_simple_types(void) ch = 0xa5; ch_ptr = &ch; - *(void**)wiredata = ch_ptr; - wiredata[sizeof(void*)] = ch; + if (use_pointer_ids) + *(unsigned int *)wiredata = 0x20000; + else + *(unsigned int *)wiredata = (UINT_PTR)ch_ptr; + wiredata[4] = ch; test_pointer_marshal(fmtstr_up_char, ch_ptr, 1, wiredata, 5, NULL, 0, "up_char"); test_pointer_marshal(fmtstr_up_byte, ch_ptr, 1, wiredata, 5, NULL, 0, "up_byte"); @@ -437,21 +481,30 @@ static void test_simple_types(void) test_pointer_marshal(fmtstr_rpup_char2, ch_ptr, 1, wiredata, 5, NULL, 0, "rpup_char2"); s = 0xa597; - *(void**)wiredata = &s; - *(unsigned short*)(wiredata + sizeof(void*)) = s; + if (use_pointer_ids) + *(unsigned int *)wiredata = 0x20000; + else + *(unsigned int *)wiredata = (UINT_PTR)&s; + *(unsigned short*)(wiredata + 4) = s; test_pointer_marshal(fmtstr_up_wchar, &s, 2, wiredata, 6, NULL, 0, "up_wchar"); test_pointer_marshal(fmtstr_up_short, &s, 2, wiredata, 6, NULL, 0, "up_short"); test_pointer_marshal(fmtstr_up_ushort, &s, 2, wiredata, 6, NULL, 0, "up_ushort"); i = 0x7fff; - *(void**)wiredata = &i; - *(unsigned short*)(wiredata + sizeof(void*)) = i; - test_pointer_marshal(fmtstr_up_enum16, &i, 2, wiredata, 6, NULL, 0, "up_enum16"); + if (use_pointer_ids) + *(unsigned int *)wiredata = 0x20000; + else + *(unsigned int *)wiredata = (UINT_PTR)&i; + *(unsigned short*)(wiredata + 4) = i; + test_pointer_marshal(fmtstr_up_enum16, &i, 4, wiredata, 6, NULL, 0, "up_enum16"); l = 0xcafebabe; - *(void**)wiredata = &l; - *(unsigned long*)(wiredata + sizeof(void*)) = l; + if (use_pointer_ids) + *(unsigned int *)wiredata = 0x20000; + else + *(unsigned int *)wiredata = (UINT_PTR)&l; + *(ULONG*)(wiredata + 4) = l; test_pointer_marshal(fmtstr_up_long, &l, 4, wiredata, 8, NULL, 0, "up_long"); test_pointer_marshal(fmtstr_up_ulong, &l, 4, wiredata, 8, NULL, 0, "up_ulong"); @@ -459,20 +512,29 @@ static void test_simple_types(void) test_pointer_marshal(fmtstr_up_errorstatus, &l, 4, wiredata, 8, NULL, 0, "up_errorstatus"); ll = ((ULONGLONG)0xcafebabe) << 32 | 0xdeadbeef; - *(void**)wiredata = ≪ - *(void**)(wiredata + sizeof(void*)) = NULL; - *(ULONGLONG*)(wiredata + 2 * sizeof(void*)) = ll; + if (use_pointer_ids) + *(unsigned int *)wiredata = 0x20000; + else + *(unsigned int *)wiredata = (UINT_PTR)≪ + *(unsigned int *)(wiredata + 4) = 0; + *(ULONGLONG*)(wiredata + 8) = ll; test_pointer_marshal(fmtstr_up_longlong, &ll, 8, wiredata, 16, NULL, 0, "up_longlong"); f = 3.1415f; - *(void**)wiredata = &f; - *(float*)(wiredata + sizeof(void*)) = f; + if (use_pointer_ids) + *(unsigned int *)wiredata = 0x20000; + else + *(unsigned int *)wiredata = (UINT_PTR)&f; + *(float*)(wiredata + 4) = f; test_pointer_marshal(fmtstr_up_float, &f, 4, wiredata, 8, NULL, 0, "up_float"); d = 3.1415; - *(void**)wiredata = &d; - *(void**)(wiredata + sizeof(void*)) = NULL; - *(double*)(wiredata + 2 * sizeof(void*)) = d; + if (use_pointer_ids) + *(unsigned int *)wiredata = 0x20000; + else + *(unsigned int *)wiredata = (UINT_PTR)&d; + *(unsigned int *)(wiredata + 4) = 0; + *(double*)(wiredata + 8) = d; test_pointer_marshal(fmtstr_up_double, &d, 8, wiredata, 16, NULL, 0, "up_double"); } @@ -482,6 +544,7 @@ static void test_nontrivial_pointer_types(void) RPC_MESSAGE RpcMessage; MIDL_STUB_MESSAGE StubMsg; MIDL_STUB_DESC StubDesc; + DWORD size; void *ptr; char **p1; char *p2; @@ -524,8 +587,8 @@ static void test_nontrivial_pointer_types(void) ptr = NdrPointerMarshall( &StubMsg, (unsigned char *)p1, &fmtstr_ref_unique_out[4] ); ok(ptr == NULL, "ret %p\n", ptr); - ok(StubMsg.Buffer - StubMsg.BufferStart == 5, "Buffer %p Start %p len %d\n", - StubMsg.Buffer, StubMsg.BufferStart, StubMsg.Buffer - StubMsg.BufferStart); + size = StubMsg.Buffer - StubMsg.BufferStart; + ok(size == 5, "Buffer %p Start %p len %d\n", StubMsg.Buffer, StubMsg.BufferStart, size); ok(*(unsigned int *)StubMsg.BufferStart != 0, "pointer ID marshalled incorrectly\n"); ok(*(unsigned char *)(StubMsg.BufferStart + 4) == 0x22, "char data marshalled incorrectly: 0x%x\n", *(unsigned char *)(StubMsg.BufferStart + 4)); @@ -633,12 +696,11 @@ static void test_nontrivial_pointer_types(void) } static void test_simple_struct_marshal(const unsigned char *formattypes, - void *memsrc, - long srcsize, + void *memsrc, DWORD srcsize, const void *wiredata, ULONG wiredatalen, int(*cmp)(const void*,const void*,size_t), - long num_additional_allocs, + int num_additional_allocs, const char *msgpfx) { RPC_MESSAGE RpcMessage; @@ -658,18 +720,15 @@ static void test_simple_struct_marshal(const unsigned char *formattypes, NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0); StubMsg.BufferLength = 0; - NdrSimpleStructBufferSize( &StubMsg, (unsigned char *)memsrc, formattypes ); + NdrSimpleStructBufferSize( &StubMsg, memsrc, formattypes ); ok(StubMsg.BufferLength >= wiredatalen, "%s: length %d\n", msgpfx, StubMsg.BufferLength); StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength); StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength; - ptr = NdrSimpleStructMarshall( &StubMsg, (unsigned char*)memsrc, formattypes ); + ptr = NdrSimpleStructMarshall( &StubMsg, memsrc, formattypes ); ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr); ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart); ok(!memcmp(StubMsg.BufferStart, wiredata, wiredatalen), "%s: incorrectly marshaled %08x %08x %08x\n", msgpfx, *(DWORD*)StubMsg.BufferStart,*((DWORD*)StubMsg.BufferStart+1),*((DWORD*)StubMsg.BufferStart+2)); - if (0) - { - /* FIXME: Causes Wine to crash */ StubMsg.Buffer = StubMsg.BufferStart; StubMsg.MemorySize = 0; size = NdrSimpleStructMemorySize( &StubMsg, formattypes ); @@ -679,12 +738,9 @@ static void test_simple_struct_marshal(const unsigned char *formattypes, StubMsg.Buffer = StubMsg.BufferStart; size = NdrSimpleStructMemorySize( &StubMsg, formattypes ); -todo_wine { ok(size == StubMsg.MemorySize, "%s: size != MemorySize\n", msgpfx); -} ok(StubMsg.MemorySize == ((srcsize + 3) & ~3) + srcsize, "%s: mem size %u\n", msgpfx, size); ok(StubMsg.Buffer - StubMsg.BufferStart == wiredatalen, "%s: Buffer %p Start %p\n", msgpfx, StubMsg.Buffer, StubMsg.BufferStart); - } size = srcsize; /*** Unmarshalling first with must_alloc false ***/ @@ -715,16 +771,19 @@ todo_wine { Passing a NULL ptr while we're a client && !must_alloc crashes on Windows, so we won't do that. */ + if (0) /* crashes on Win9x and NT4 */ + { mem = NULL; StubMsg.IsClient = 0; StubMsg.Buffer = StubMsg.BufferStart; - ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, 0 ); + ptr = NdrSimpleStructUnmarshall( &StubMsg, &mem, formattypes, FALSE ); ok(ptr == NULL, "%s: ret %p\n", msgpfx, ptr); ok(mem == StubMsg.BufferStart, "%s: mem not equal buffer\n", msgpfx); ok(!cmp(mem, memsrc, srcsize), "%s: incorrectly unmarshaled\n", msgpfx); ok(my_alloc_called == num_additional_allocs, "%s: my_alloc got called %d times\n", msgpfx, my_alloc_called); my_alloc_called = 0; ok(StubMsg.MemorySize == 0, "%s: memorysize touched in unmarshal\n", msgpfx); + } /*** now must_alloc is true ***/ @@ -782,8 +841,8 @@ todo_wine { typedef struct { - long l1; - long *pl1; + LONG l1; + LONG *pl1; char *pc1; } ps1_t; @@ -819,8 +878,8 @@ static int ps1_cmp(const void *s1, const void *s2, size_t num) static void test_simple_struct(void) { unsigned char wiredata[28]; - unsigned long wiredatalen; - long l; + ULONG wiredatalen; + LONG l; char c; ps1_t ps1; @@ -842,7 +901,7 @@ static void test_simple_struct(void) struct { short s; char c; - long l1, l2; + LONG l1, l2; LONGLONG ll; } s1; @@ -850,6 +909,25 @@ static void test_simple_struct(void) { 0x12, 0x0, /* FC_UP */ NdrFcShort( 0x2 ), /* Offset=2 */ +#ifdef _WIN64 + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ + NdrFcShort(0x18), /* [size 24] */ + NdrFcShort(0x0), + NdrFcShort(0x8), /* Offset= 8 (266) */ + 0x08, /* FC_LONG */ + 0x39, /* FC_ALIGNM8 */ + 0x36, /* FC_POINTER */ + 0x36, /* FC_POINTER */ + 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ + 0x08, /* FC_LONG */ + 0x5c, /* FC_PAD */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ + 0x02, /* FC_CHAR */ + 0x5c, /* FC_PAD */ +#else 0x16, 0x3, /* FC_PSTRUCT [align 4] */ NdrFcShort( 0xc ), /* [size 12] */ 0x4b, /* FC_PP */ @@ -874,9 +952,12 @@ static void test_simple_struct(void) 0x8, /* FC_LONG */ 0x5c, /* FC_PAD */ 0x5b, /* FC_END */ - +#endif }; + /* zero the entire structure, including the holes */ + memset(&s1, 0, sizeof(s1)); + /* FC_STRUCT */ s1.s = 0x1234; s1.c = 0xa5; @@ -888,13 +969,17 @@ static void test_simple_struct(void) memcpy(wiredata, &s1, wiredatalen); test_simple_struct_marshal(fmtstr_simple_struct + 4, &s1, 24, wiredata, 24, NULL, 0, "struct"); - *(void**)wiredata = &s1; + if (use_pointer_ids) + *(unsigned int *)wiredata = 0x20000; + else + *(unsigned int *)wiredata = (UINT_PTR)&s1; memcpy(wiredata + 4, &s1, wiredatalen); - if (0) - { - /* one of the unmarshallings crashes Wine */ test_pointer_marshal(fmtstr_simple_struct, &s1, 24, wiredata, 28, NULL, 0, "struct"); - } + + if (sizeof(void *) == 8) return; /* it cannot be represented as a simple struct on Win64 */ + + /* zero the entire structure, including the hole */ + memset(&ps1, 0, sizeof(ps1)); /* FC_PSTRUCT */ ps1.l1 = 0xdeadbeef; @@ -902,18 +987,31 @@ static void test_simple_struct(void) ps1.pl1 = &l; c = 'a'; ps1.pc1 = &c; - memcpy(wiredata + 4, &ps1, 12); + *(unsigned int *)(wiredata + 4) = 0xdeadbeef; + if (use_pointer_ids) + { + *(unsigned int *)(wiredata + 8) = 0x20000; + *(unsigned int *)(wiredata + 12) = 0x20004; + } + else + { + *(unsigned int *)(wiredata + 8) = (UINT_PTR)&l; + *(unsigned int *)(wiredata + 12) = (UINT_PTR)&c; + } memcpy(wiredata + 16, &l, 4); memcpy(wiredata + 20, &c, 1); test_simple_struct_marshal(fmtstr_pointer_struct + 4, &ps1, 17, wiredata + 4, 17, ps1_cmp, 2, "pointer_struct"); - *(void**)wiredata = &ps1; - if (0) + if (use_pointer_ids) { - /* one of the unmarshallings crashes Wine */ + *(unsigned int *)wiredata = 0x20000; + *(unsigned int *)(wiredata + 8) = 0x20004; + *(unsigned int *)(wiredata + 12) = 0x20008; + } + else + *(unsigned int *)wiredata = (UINT_PTR)&ps1; test_pointer_marshal(fmtstr_pointer_struct, &ps1, 17, wiredata, 21, ps1_cmp, 2, "pointer_struct"); } -} static void test_fullpointer_xlat(void) { @@ -1041,76 +1139,84 @@ static void test_fullpointer_xlat(void) NdrFullPointerXlatFree(pXlatTables); } -static void test_client_init(void) +/* verify stub data that is identical between client and server */ +static void test_common_stub_data( const char *prefix, const MIDL_STUB_MESSAGE *stubMsg ) { - MIDL_STUB_MESSAGE stubMsg; - RPC_MESSAGE rpcMsg; + void *unset_ptr; - memset(&rpcMsg, 0xcc, sizeof(rpcMsg)); - memset(&stubMsg, 0xcc, sizeof(stubMsg)); + memset(&unset_ptr, 0xcc, sizeof(unset_ptr)); - NdrClientInitializeNew(&rpcMsg, &stubMsg, &Object_StubDesc, 1); +#define TEST_ZERO(field, fmt) ok(stubMsg->field == 0, "%s: " #field " should have been set to zero instead of " fmt "\n", prefix, stubMsg->field) +#define TEST_POINTER_UNSET(field) ok(stubMsg->field == unset_ptr, "%s: " #field " should have been unset instead of %p\n", prefix, stubMsg->field) +#define TEST_ULONG_UNSET(field) ok(stubMsg->field == 0xcccccccc, "%s: " #field " should have been unset instead of 0x%x\n", prefix, stubMsg->field) +#define TEST_ULONG_PTR_UNSET(field) ok(stubMsg->field == (ULONG_PTR)unset_ptr, "%s: " #field " should have been unset instead of 0x%lx\n", prefix, stubMsg->field) -#define TEST_POINTER_UNSET(field) ok(rpcMsg.field == (void *)0xcccccccc, #field " should have been unset instead of %p\n", rpcMsg.field) - - ok(rpcMsg.Handle == NULL, "rpcMsg.Handle should have been NULL instead of %p\n", rpcMsg.Handle); - TEST_POINTER_UNSET(Buffer); - ok(rpcMsg.BufferLength == 0xcccccccc, "rpcMsg.BufferLength should have been unset instead of %d\n", rpcMsg.BufferLength); - ok(rpcMsg.ProcNum == 0x8001, "rpcMsg.ProcNum should have been 0x8001 instead of 0x%x\n", rpcMsg.ProcNum); - TEST_POINTER_UNSET(TransferSyntax); - ok(rpcMsg.RpcInterfaceInformation == Object_StubDesc.RpcInterfaceInformation, - "rpcMsg.RpcInterfaceInformation should have been %p instead of %p\n", - Object_StubDesc.RpcInterfaceInformation, rpcMsg.RpcInterfaceInformation); - /* Note: ReservedForRuntime not tested */ - TEST_POINTER_UNSET(ManagerEpv); - TEST_POINTER_UNSET(ImportContext); - ok(rpcMsg.RpcFlags == 0, "rpcMsg.RpcFlags should have been 0 instead of 0x%lx\n", rpcMsg.RpcFlags); -#undef TEST_POINTER_UNSET - -#define TEST_ZERO(field, fmt) ok(stubMsg.field == 0, #field " should have been set to zero instead of " fmt "\n", stubMsg.field) -#define TEST_POINTER_UNSET(field) ok(stubMsg.field == (void *)0xcccccccc, #field " should have been unset instead of %p\n", stubMsg.field) -#define TEST_ULONG_UNSET(field) ok(stubMsg.field == 0xcccccccc, #field " should have been unset instead of 0x%x\n", stubMsg.field) -#define TEST_ULONG_PTR_UNSET(field) ok(stubMsg.field == 0xcccccccc, #field " should have been unset instead of 0x%lx\n", stubMsg.field) - - ok(stubMsg.RpcMsg == &rpcMsg, "stubMsg.RpcMsg should have been %p instead of %p\n", &rpcMsg, stubMsg.RpcMsg); - TEST_POINTER_UNSET(Buffer); - TEST_ZERO(BufferStart, "%p"); - TEST_ZERO(BufferEnd, "%p"); TEST_POINTER_UNSET(BufferMark); - TEST_ZERO(BufferLength, "%d"); TEST_ULONG_UNSET(MemorySize); TEST_POINTER_UNSET(Memory); - ok(stubMsg.IsClient == 1, "stubMsg.IsClient should have been 1 instead of %u\n", stubMsg.IsClient); - TEST_ZERO(ReuseBuffer, "%d"); TEST_ZERO(pAllocAllNodesContext, "%p"); - TEST_ZERO(pPointerQueueState, "%p"); + ok(stubMsg->pPointerQueueState == 0 || + broken(stubMsg->pPointerQueueState == unset_ptr), /* win2k */ + "%s: pPointerQueueState should have been unset instead of %p\n", + prefix, stubMsg->pPointerQueueState); TEST_ZERO(IgnoreEmbeddedPointers, "%d"); TEST_ZERO(PointerBufferMark, "%p"); - TEST_ZERO(fBufferValid, "%d"); - TEST_ZERO(uFlags, "%d"); + ok( stubMsg->uFlags == 0 || + broken(stubMsg->uFlags == 0xcc), /* win9x */ + "%s: uFlags should have been set to zero instead of 0x%x\n", prefix, stubMsg->uFlags ); /* FIXME: UniquePtrCount */ TEST_ULONG_PTR_UNSET(MaxCount); TEST_ULONG_UNSET(Offset); TEST_ULONG_UNSET(ActualCount); - ok(stubMsg.pfnAllocate == my_alloc, "stubMsg.pfnAllocate should have been %p instead of %p\n", my_alloc, stubMsg.pfnAllocate); - ok(stubMsg.pfnFree == my_free, "stubMsg.pfnFree should have been %p instead of %p\n", my_free, stubMsg.pfnFree); + ok(stubMsg->pfnAllocate == my_alloc, "%s: pfnAllocate should have been %p instead of %p\n", + prefix, my_alloc, stubMsg->pfnAllocate); + ok(stubMsg->pfnFree == my_free, "%s: pfnFree should have been %p instead of %p\n", + prefix, my_free, stubMsg->pfnFree); TEST_ZERO(StackTop, "%p"); TEST_POINTER_UNSET(pPresentedType); TEST_POINTER_UNSET(pTransmitType); TEST_POINTER_UNSET(SavedHandle); - ok(stubMsg.StubDesc == &Object_StubDesc, "stubMsg.StubDesc should have been %p instead of %p\n", &Object_StubDesc, stubMsg.StubDesc); - TEST_POINTER_UNSET(FullPtrXlatTables); + ok(stubMsg->StubDesc == &Object_StubDesc, "%s: StubDesc should have been %p instead of %p\n", + prefix, &Object_StubDesc, stubMsg->StubDesc); TEST_ZERO(FullPtrRefId, "%d"); - TEST_ZERO(PointerLength, "%d"); + ok( stubMsg->PointerLength == 0 || + broken(stubMsg->PointerLength == 1), /* win9x, nt4 */ + "%s: pAsyncMsg should have been set to zero instead of %d\n", prefix, stubMsg->PointerLength ); TEST_ZERO(fInDontFree, "%d"); TEST_ZERO(fDontCallFreeInst, "%d"); - TEST_ZERO(fInOnlyParam, "%d"); - TEST_ZERO(fHasReturn, "%d"); + ok(stubMsg->fInOnlyParam == 0 || + stubMsg->fInOnlyParam == -1, /* Vista */ + "%s: fInOnlyParam should have been set to 0 or -1 instead of %d\n", prefix, stubMsg->fInOnlyParam); + ok( stubMsg->fHasReturn == 0 || + broken(stubMsg->fHasReturn == -1), /* win9x, nt4 */ + "%s: fHasReturn should have been set to zero instead of %d\n", prefix, stubMsg->fHasReturn ); TEST_ZERO(fHasExtensions, "%d"); TEST_ZERO(fHasNewCorrDesc, "%d"); - TEST_ZERO(fUnused, "%d"); - ok(stubMsg.fUnused2 == 0xffffcccc, "stubMsg.fUnused2 should have been 0xcccc instead of 0x%x\n", stubMsg.fUnused2); - ok(stubMsg.dwDestContext == MSHCTX_DIFFERENTMACHINE, "stubMsg.dwDestContext should have been MSHCTX_DIFFERENTMACHINE instead of %d\n", stubMsg.dwDestContext); + ok(stubMsg->fIsIn == 0 || + broken(stubMsg->fIsIn == -1), /* win9x, nt4 */ + "%s: fIsIn should have been set to 0 instead of %d\n", prefix, stubMsg->fIsIn); + ok(stubMsg->fIsOut == 0 || + stubMsg->fIsOut == -1, /* XP-SP3 */ + "%s: fIsOut should have been set to 0 or -1 instead of %d\n", prefix, stubMsg->fIsOut); + TEST_ZERO(fIsOicf, "%d"); + ok(stubMsg->fBufferValid == 0, + "%s: fBufferValid should have been set to 0 instead of %d\n", prefix, stubMsg->fBufferValid); + ok(stubMsg->fHasMemoryValidateCallback == 0 || + stubMsg->fHasMemoryValidateCallback == -1, /* XP-SP3 */ + "%s: fHasMemoryValidateCallback should have been set to 0 or -1 instead of %d\n", + prefix, stubMsg->fHasMemoryValidateCallback); + ok(stubMsg->fInFree == 0 || + stubMsg->fInFree == -1, /* XP-SP3 */ + "%s: fInFree should have been set to 0 or -1 instead of %d\n", prefix, stubMsg->fInFree); + TEST_ZERO(fNeedMCCP, "%d"); + ok(stubMsg->fUnused == 0 || + stubMsg->fUnused == -2, /* Vista */ + "%s: fUnused should have been set to 0 or -2 instead of %d\n", prefix, stubMsg->fUnused); + ok(stubMsg->fUnused2 == 0xffffcccc, "%s: fUnused2 should have been 0xffffcccc instead of 0x%x\n", + prefix, stubMsg->fUnused2); + ok(stubMsg->dwDestContext == MSHCTX_DIFFERENTMACHINE, + "%s: dwDestContext should have been MSHCTX_DIFFERENTMACHINE instead of %d\n", + prefix, stubMsg->dwDestContext); TEST_ZERO(pvDestContext, "%p"); TEST_POINTER_UNSET(SavedContextHandles); TEST_ULONG_UNSET(ParamNumber); @@ -1122,25 +1228,77 @@ static void test_client_init(void) TEST_POINTER_UNSET(pArgQueue); TEST_ZERO(dwStubPhase, "%d"); /* FIXME: where does this value come from? */ - trace("LowStackMark is %p\n", stubMsg.LowStackMark); - TEST_ZERO(pAsyncMsg, "%p"); - TEST_ZERO(pCorrInfo, "%p"); - TEST_ZERO(pCorrMemory, "%p"); - TEST_ZERO(pMemoryList, "%p"); + trace("%s: LowStackMark is %p\n", prefix, stubMsg->LowStackMark); + ok( stubMsg->pAsyncMsg == 0 || broken(stubMsg->pAsyncMsg == unset_ptr), /* win9x, nt4 */ + "%s: pAsyncMsg should have been set to zero instead of %p\n", prefix, stubMsg->pAsyncMsg ); + ok( stubMsg->pCorrInfo == 0 || broken(stubMsg->pCorrInfo == unset_ptr), /* win9x, nt4 */ + "%s: pCorrInfo should have been set to zero instead of %p\n", prefix, stubMsg->pCorrInfo ); + ok( stubMsg->pCorrMemory == 0 || broken(stubMsg->pCorrMemory == unset_ptr), /* win9x, nt4 */ + "%s: pCorrMemory should have been set to zero instead of %p\n", prefix, stubMsg->pCorrMemory ); + ok( stubMsg->pMemoryList == 0 || broken(stubMsg->pMemoryList == unset_ptr), /* win9x, nt4 */ + "%s: pMemoryList should have been set to zero instead of %p\n", prefix, stubMsg->pMemoryList ); TEST_POINTER_UNSET(pCSInfo); TEST_POINTER_UNSET(ConformanceMark); TEST_POINTER_UNSET(VarianceMark); - ok(stubMsg.Unused == 0xcccccccc, "Unused should have be unset instead of 0x%lx\n", stubMsg.Unused); + ok(stubMsg->Unused == (ULONG_PTR)unset_ptr, "%s: Unused should have be unset instead of 0x%lx\n", + prefix, stubMsg->Unused); TEST_POINTER_UNSET(pContext); TEST_POINTER_UNSET(ContextHandleHash); TEST_POINTER_UNSET(pUserMarshalList); TEST_ULONG_PTR_UNSET(Reserved51_3); TEST_ULONG_PTR_UNSET(Reserved51_4); TEST_ULONG_PTR_UNSET(Reserved51_5); + +#undef TEST_ULONG_PTR_UNSET #undef TEST_ULONG_UNSET #undef TEST_POINTER_UNSET #undef TEST_ZERO +} +static void test_client_init(void) +{ + MIDL_STUB_MESSAGE stubMsg; + RPC_MESSAGE rpcMsg; + void *unset_ptr; + + memset(&rpcMsg, 0xcc, sizeof(rpcMsg)); + memset(&stubMsg, 0xcc, sizeof(stubMsg)); + memset(&unset_ptr, 0xcc, sizeof(unset_ptr)); + + NdrClientInitializeNew(&rpcMsg, &stubMsg, &Object_StubDesc, 1); + + test_common_stub_data( "NdrClientInitializeNew", &stubMsg ); + + ok(stubMsg.RpcMsg == &rpcMsg, "stubMsg.RpcMsg should have been %p instead of %p\n", &rpcMsg, stubMsg.RpcMsg); + ok(rpcMsg.Handle == NULL, "rpcMsg.Handle should have been NULL instead of %p\n", rpcMsg.Handle); + ok(rpcMsg.Buffer == unset_ptr, "rpcMsg.Buffer should have been unset instead of %p\n", + rpcMsg.Buffer); + ok(rpcMsg.BufferLength == 0xcccccccc, "rpcMsg.BufferLength should have been unset instead of %d\n", rpcMsg.BufferLength); + ok(rpcMsg.ProcNum == 0x8001, "rpcMsg.ProcNum should have been 0x8001 instead of 0x%x\n", rpcMsg.ProcNum); + ok(rpcMsg.TransferSyntax == unset_ptr, "rpcMsg.TransferSyntax should have been unset instead of %p\n", rpcMsg.TransferSyntax); + ok(rpcMsg.RpcInterfaceInformation == Object_StubDesc.RpcInterfaceInformation, + "rpcMsg.RpcInterfaceInformation should have been %p instead of %p\n", + Object_StubDesc.RpcInterfaceInformation, rpcMsg.RpcInterfaceInformation); + /* Note: ReservedForRuntime not tested */ + ok(rpcMsg.ManagerEpv == unset_ptr, "rpcMsg.ManagerEpv should have been unset instead of %p\n", rpcMsg.ManagerEpv); + ok(rpcMsg.ImportContext == unset_ptr, "rpcMsg.ImportContext should have been unset instead of %p\n", rpcMsg.ImportContext); + ok(rpcMsg.RpcFlags == 0, "rpcMsg.RpcFlags should have been 0 instead of 0x%x\n", rpcMsg.RpcFlags); + + ok(stubMsg.Buffer == unset_ptr, "stubMsg.Buffer should have been unset instead of %p\n", + stubMsg.Buffer); + ok(stubMsg.BufferStart == NULL, "stubMsg.BufferStart should have been NULL instead of %p\n", + stubMsg.BufferStart); + ok(stubMsg.BufferEnd == NULL, "stubMsg.BufferEnd should have been NULL instead of %p\n", + stubMsg.BufferEnd); + ok(stubMsg.BufferLength == 0, "stubMsg.BufferLength should have been 0 instead of %u\n", + stubMsg.BufferLength); + ok(stubMsg.IsClient == 1, "stubMsg.IsClient should have been 1 instead of %u\n", stubMsg.IsClient); + ok(stubMsg.ReuseBuffer == 0, "stubMsg.ReuseBuffer should have been 0 instead of %d\n", + stubMsg.ReuseBuffer); + ok(stubMsg.CorrDespIncrement == 0, "stubMsg.CorrDespIncrement should have been 0 instead of %d\n", + stubMsg.CorrDespIncrement); + ok(stubMsg.FullPtrXlatTables == unset_ptr, "stubMsg.FullPtrXlatTables should have been unset instead of %p\n", + stubMsg.FullPtrXlatTables); } static void test_server_init(void) @@ -1160,81 +1318,22 @@ static void test_server_init(void) ret = NdrServerInitializeNew(&rpcMsg, &stubMsg, &Object_StubDesc); ok(ret == NULL, "NdrServerInitializeNew should have returned NULL instead of %p\n", ret); -#define TEST_ZERO(field, fmt) ok(stubMsg.field == 0, #field " should have been set to zero instead of " fmt "\n", stubMsg.field) -#define TEST_POINTER_UNSET(field) ok(stubMsg.field == (void *)0xcccccccc, #field " should have been unset instead of %p\n", stubMsg.field) -#define TEST_ULONG_UNSET(field) ok(stubMsg.field == 0xcccccccc, #field " should have been unset instead of 0x%x\n", stubMsg.field) -#define TEST_ULONG_PTR_UNSET(field) ok(stubMsg.field == 0xcccccccc, #field " should have been unset instead of 0x%lx\n", stubMsg.field) + test_common_stub_data( "NdrServerInitializeNew", &stubMsg ); ok(stubMsg.RpcMsg == &rpcMsg, "stubMsg.RpcMsg should have been %p instead of %p\n", &rpcMsg, stubMsg.RpcMsg); ok(stubMsg.Buffer == buffer, "stubMsg.Buffer should have been %p instead of %p\n", buffer, stubMsg.Buffer); ok(stubMsg.BufferStart == buffer, "stubMsg.BufferStart should have been %p instead of %p\n", buffer, stubMsg.BufferStart); ok(stubMsg.BufferEnd == buffer + sizeof(buffer), "stubMsg.BufferEnd should have been %p instead of %p\n", buffer + sizeof(buffer), stubMsg.BufferEnd); - TEST_POINTER_UNSET(BufferMark); todo_wine - TEST_ZERO(BufferLength, "%d"); - TEST_ULONG_UNSET(MemorySize); - TEST_POINTER_UNSET(Memory); + ok(stubMsg.BufferLength == 0, "stubMsg.BufferLength should have been 0 instead of %u\n", stubMsg.BufferLength); ok(stubMsg.IsClient == 0, "stubMsg.IsClient should have been 0 instead of %u\n", stubMsg.IsClient); - TEST_ZERO(ReuseBuffer, "%d"); - TEST_ZERO(pAllocAllNodesContext, "%p"); - TEST_ZERO(pPointerQueueState, "%p"); - TEST_ZERO(IgnoreEmbeddedPointers, "%d"); - TEST_ZERO(PointerBufferMark, "%p"); - ok(stubMsg.fBufferValid == 0xcc, "fBufferValid should have been unset instead of 0x%x\n", stubMsg.fBufferValid); - TEST_ZERO(uFlags, "%d"); - /* FIXME: UniquePtrCount */ - TEST_ULONG_PTR_UNSET(MaxCount); - TEST_ULONG_UNSET(Offset); - TEST_ULONG_UNSET(ActualCount); - ok(stubMsg.pfnAllocate == my_alloc, "stubMsg.pfnAllocate should have been %p instead of %p\n", my_alloc, stubMsg.pfnAllocate); - ok(stubMsg.pfnFree == my_free, "stubMsg.pfnFree should have been %p instead of %p\n", my_free, stubMsg.pfnFree); - TEST_ZERO(StackTop, "%p"); - TEST_POINTER_UNSET(pPresentedType); - TEST_POINTER_UNSET(pTransmitType); - TEST_POINTER_UNSET(SavedHandle); - ok(stubMsg.StubDesc == &Object_StubDesc, "stubMsg.StubDesc should have been %p instead of %p\n", &Object_StubDesc, stubMsg.StubDesc); - TEST_ZERO(FullPtrXlatTables, "%p"); - TEST_ZERO(FullPtrRefId, "%d"); - TEST_ZERO(PointerLength, "%d"); - TEST_ZERO(fInDontFree, "%d"); - TEST_ZERO(fDontCallFreeInst, "%d"); - TEST_ZERO(fInOnlyParam, "%d"); - TEST_ZERO(fHasReturn, "%d"); - TEST_ZERO(fHasExtensions, "%d"); - TEST_ZERO(fHasNewCorrDesc, "%d"); - TEST_ZERO(fUnused, "%d"); - ok(stubMsg.fUnused2 == 0xffffcccc, "stubMsg.fUnused2 should have been 0xcccc instead of 0x%x\n", stubMsg.fUnused2); - ok(stubMsg.dwDestContext == MSHCTX_DIFFERENTMACHINE, "stubMsg.dwDestContext should have been MSHCTX_DIFFERENTMACHINE instead of %d\n", stubMsg.dwDestContext); - TEST_ZERO(pvDestContext, "%p"); - TEST_POINTER_UNSET(SavedContextHandles); - TEST_ULONG_UNSET(ParamNumber); - TEST_ZERO(pRpcChannelBuffer, "%p"); - TEST_ZERO(pArrayInfo, "%p"); - TEST_POINTER_UNSET(SizePtrCountArray); - TEST_POINTER_UNSET(SizePtrOffsetArray); - TEST_POINTER_UNSET(SizePtrLengthArray); - TEST_POINTER_UNSET(pArgQueue); - TEST_ZERO(dwStubPhase, "%d"); - /* FIXME: where does this value come from? */ - trace("LowStackMark is %p\n", stubMsg.LowStackMark); - TEST_ZERO(pAsyncMsg, "%p"); - TEST_ZERO(pCorrInfo, "%p"); - TEST_ZERO(pCorrMemory, "%p"); - TEST_ZERO(pMemoryList, "%p"); - TEST_POINTER_UNSET(pCSInfo); - TEST_POINTER_UNSET(ConformanceMark); - TEST_POINTER_UNSET(VarianceMark); - ok(stubMsg.Unused == 0xcccccccc, "Unused should have be unset instead of 0x%lx\n", stubMsg.Unused); - TEST_POINTER_UNSET(pContext); - TEST_POINTER_UNSET(ContextHandleHash); - TEST_POINTER_UNSET(pUserMarshalList); - TEST_ULONG_PTR_UNSET(Reserved51_3); - TEST_ULONG_PTR_UNSET(Reserved51_4); - TEST_ULONG_PTR_UNSET(Reserved51_5); -#undef TEST_ULONG_UNSET -#undef TEST_POINTER_UNSET -#undef TEST_ZERO - + ok(stubMsg.ReuseBuffer == 0 || + broken(stubMsg.ReuseBuffer == 1), /* win2k */ + "stubMsg.ReuseBuffer should have been set to zero instead of %d\n", stubMsg.ReuseBuffer); + ok(stubMsg.CorrDespIncrement == 0xcc || + stubMsg.CorrDespIncrement == 0, + "CorrDespIncrement should have been unset instead of 0x%x\n", stubMsg.CorrDespIncrement); + ok(stubMsg.FullPtrXlatTables == 0, "stubMsg.BufferLength should have been 0 instead of %p\n", stubMsg.FullPtrXlatTables); } static void test_ndr_allocate(void) @@ -1243,12 +1342,6 @@ static void test_ndr_allocate(void) MIDL_STUB_MESSAGE StubMsg; MIDL_STUB_DESC StubDesc; void *p1, *p2; - struct tag_mem_list_v1_t - { - DWORD magic; - void *ptr; - struct tag_mem_list_v1_t *next; - } *mem_list_v1; struct tag_mem_list_v2_t { DWORD magic; @@ -1261,7 +1354,6 @@ static void test_ndr_allocate(void) StubDesc = Object_StubDesc; NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0); - ok(StubMsg.pMemoryList == NULL, "memlist %p\n", StubMsg.pMemoryList); my_alloc_called = my_free_called = 0; p1 = NdrAllocate(&StubMsg, 10); p2 = NdrAllocate(&StubMsg, 24); @@ -1288,22 +1380,8 @@ static void test_ndr_allocate(void) ok(mem_list_v2->next == NULL, "next %p\n", mem_list_v2->next); } } - else - { - trace("v1 mem list format\n"); - mem_list_v1 = StubMsg.pMemoryList; - ok(mem_list_v1->magic == magic_MEML, "magic %08x\n", mem_list_v1->magic); - ok(mem_list_v1->ptr == p2, "ptr != p2\n"); - ok(mem_list_v1->next != NULL, "next NULL\n"); - mem_list_v1 = mem_list_v1->next; - if(mem_list_v1) - { - ok(mem_list_v1->magic == magic_MEML, "magic %08x\n", mem_list_v1->magic); - ok(mem_list_v1->ptr == p1, "ptr != p1\n"); - ok(mem_list_v1->next == NULL, "next %p\n", mem_list_v1->next); + else win_skip("v1 mem list format\n"); } - } - } /* NdrFree isn't exported so we can't test free'ing */ } @@ -1315,6 +1393,7 @@ static void test_conformant_array(void) void *ptr; unsigned char *mem, *mem_orig; unsigned char memsrc[20]; + unsigned int i; static const unsigned char fmtstr_conf_array[] = { @@ -1328,6 +1407,9 @@ static void test_conformant_array(void) 0x5b /* FC_END */ }; + for (i = 0; i < sizeof(memsrc); i++) + memsrc[i] = i * i; + StubDesc = Object_StubDesc; StubDesc.pFormatTypes = fmtstr_conf_array; @@ -1391,7 +1473,8 @@ static void test_conformant_array(void) mem = NULL; StubMsg.Buffer = StubMsg.BufferStart; NdrConformantArrayUnmarshall( &StubMsg, &mem, fmtstr_conf_array, 0); - ok(mem == StubMsg.BufferStart + 4, "mem not pointing at buffer\n"); + ok(mem == StubMsg.BufferStart + 4 || broken(!mem), /* win9x, nt4 */ + "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 4); ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called); my_alloc_called = 0; mem = NULL; @@ -1425,6 +1508,7 @@ static void test_conformant_string(void) RPC_MESSAGE RpcMessage; MIDL_STUB_MESSAGE StubMsg; MIDL_STUB_DESC StubDesc; + DWORD size; void *ptr; unsigned char *mem, *mem_orig; char memsrc[] = "This is a test string"; @@ -1439,6 +1523,7 @@ static void test_conformant_string(void) StubDesc = Object_StubDesc; StubDesc.pFormatTypes = fmtstr_conf_str; + memset( &StubMsg, 0, sizeof(StubMsg) ); /* needed on win9x and nt4 */ NdrClientInitializeNew( &RpcMessage, &StubMsg, @@ -1457,8 +1542,9 @@ static void test_conformant_string(void) ptr = NdrPointerMarshall( &StubMsg, (unsigned char *)memsrc, fmtstr_conf_str ); ok(ptr == NULL, "ret %p\n", ptr); - ok(StubMsg.Buffer - StubMsg.BufferStart == sizeof(memsrc) + 12, "Buffer %p Start %p len %d\n", - StubMsg.Buffer, StubMsg.BufferStart, StubMsg.Buffer - StubMsg.BufferStart); + size = StubMsg.Buffer - StubMsg.BufferStart; + ok(size == sizeof(memsrc) + 12, "Buffer %p Start %p len %d\n", + StubMsg.Buffer, StubMsg.BufferStart, size); ok(!memcmp(StubMsg.BufferStart + 12, memsrc, sizeof(memsrc)), "incorrectly marshaled\n"); StubMsg.Buffer = StubMsg.BufferStart; @@ -1498,7 +1584,8 @@ todo_wine { mem = NULL; StubMsg.Buffer = StubMsg.BufferStart; NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 0); - ok(mem == StubMsg.BufferStart + 12, "mem not pointing at buffer\n"); + ok(mem == StubMsg.BufferStart + 12 || broken(!mem), /* win9x, nt4 */ + "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 12 ); ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called); my_alloc_called = 0; @@ -1506,15 +1593,17 @@ todo_wine { StubMsg.Buffer = StubMsg.BufferStart; NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 1); todo_wine { - ok(mem == StubMsg.BufferStart + 12, "mem not pointing at buffer\n"); + ok(mem == StubMsg.BufferStart + 12 || broken(!mem), /* win9x, nt4 */ + "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 12 ); ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called); } my_alloc_called = 0; - mem = mem_orig; + mem = mem_orig = HeapAlloc(GetProcessHeap(), 0, sizeof(memsrc)); StubMsg.Buffer = StubMsg.BufferStart; NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 0); - ok(mem == StubMsg.BufferStart + 12, "mem not pointing at buffer\n"); + ok(mem == StubMsg.BufferStart + 12 || broken(!mem), /* win9x, nt4 */ + "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 12 ); ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called); my_alloc_called = 0; @@ -1522,7 +1611,8 @@ todo_wine { StubMsg.Buffer = StubMsg.BufferStart; NdrPointerUnmarshall( &StubMsg, &mem, fmtstr_conf_str, 1); todo_wine { - ok(mem == StubMsg.BufferStart + 12, "mem not pointing at buffer\n"); + ok(mem == StubMsg.BufferStart + 12 || broken(!mem), /* win9x, nt4 */ + "mem not pointing at buffer %p/%p\n", mem, StubMsg.BufferStart + 12 ); ok(my_alloc_called == 0, "alloc called %d\n", my_alloc_called); } @@ -1541,6 +1631,7 @@ static void test_nonconformant_string(void) RPC_MESSAGE RpcMessage; MIDL_STUB_MESSAGE StubMsg; MIDL_STUB_DESC StubDesc; + DWORD size; void *ptr; unsigned char *mem, *mem_orig; unsigned char memsrc[10] = "This is"; @@ -1565,19 +1656,18 @@ static void test_nonconformant_string(void) StubMsg.BufferLength = 0; - NdrNonConformantStringBufferSize( &StubMsg, - (unsigned char *)memsrc, - fmtstr_nonconf_str ); + NdrNonConformantStringBufferSize( &StubMsg, memsrc, fmtstr_nonconf_str ); ok(StubMsg.BufferLength >= strlen((char *)memsrc) + 1 + 8, "length %d\n", StubMsg.BufferLength); /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/ StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength); StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength; - ptr = NdrNonConformantStringMarshall( &StubMsg, (unsigned char *)memsrc, fmtstr_nonconf_str ); + ptr = NdrNonConformantStringMarshall( &StubMsg, memsrc, fmtstr_nonconf_str ); ok(ptr == NULL, "ret %p\n", ptr); - ok(StubMsg.Buffer - StubMsg.BufferStart == strlen((char *)memsrc) + 1 + 8, "Buffer %p Start %p len %d\n", - StubMsg.Buffer, StubMsg.BufferStart, StubMsg.Buffer - StubMsg.BufferStart); + size = StubMsg.Buffer - StubMsg.BufferStart; + ok(size == strlen((char *)memsrc) + 1 + 8, "Buffer %p Start %p len %d\n", + StubMsg.Buffer, StubMsg.BufferStart, size); ok(!memcmp(StubMsg.BufferStart + 8, memsrc, strlen((char *)memsrc) + 1), "incorrectly marshaled\n"); StubMsg.Buffer = StubMsg.BufferStart; @@ -1639,19 +1729,18 @@ static void test_nonconformant_string(void) StubMsg.BufferLength = 0; - NdrNonConformantStringBufferSize( &StubMsg, - (unsigned char *)memsrc2, - fmtstr_nonconf_str ); + NdrNonConformantStringBufferSize( &StubMsg, memsrc2, fmtstr_nonconf_str ); ok(StubMsg.BufferLength >= strlen((char *)memsrc2) + 1 + 8, "length %d\n", StubMsg.BufferLength); /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/ StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength); StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength; - ptr = NdrNonConformantStringMarshall( &StubMsg, (unsigned char *)memsrc2, fmtstr_nonconf_str ); + ptr = NdrNonConformantStringMarshall( &StubMsg, memsrc2, fmtstr_nonconf_str ); ok(ptr == NULL, "ret %p\n", ptr); - ok(StubMsg.Buffer - StubMsg.BufferStart == strlen((char *)memsrc2) + 1 + 8, "Buffer %p Start %p len %d\n", - StubMsg.Buffer, StubMsg.BufferStart, StubMsg.Buffer - StubMsg.BufferStart); + size = StubMsg.Buffer - StubMsg.BufferStart; + ok(size == strlen((char *)memsrc2) + 1 + 8, "Buffer %p Start %p len %d\n", + StubMsg.Buffer, StubMsg.BufferStart, size); ok(!memcmp(StubMsg.BufferStart + 8, memsrc2, strlen((char *)memsrc2) + 1), "incorrectly marshaled\n"); StubMsg.Buffer = StubMsg.BufferStart; @@ -1705,6 +1794,105 @@ static void test_nonconformant_string(void) HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer); } +static void test_conf_complex_struct(void) +{ + RPC_MESSAGE RpcMessage; + MIDL_STUB_MESSAGE StubMsg; + MIDL_STUB_DESC StubDesc; + void *ptr; + unsigned int i; + struct conf_complex + { + unsigned int size; + unsigned int *array[1]; + }; + struct conf_complex *memsrc; + struct conf_complex *mem; + + static const unsigned char fmtstr_complex_struct[] = + { +/* 0 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 2 */ NdrFcShort( 0x4 ), /* 4 */ +/* 4 */ 0x8, /* Corr desc: FC_LONG */ + 0x0, /* */ +/* 6 */ NdrFcShort( 0xfffc ), /* -4 */ +/* 8 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 10 */ + 0x48, /* FC_VARIABLE_REPEAT */ + 0x49, /* FC_FIXED_OFFSET */ +/* 12 */ NdrFcShort( 0x4 ), /* 4 */ +/* 14 */ NdrFcShort( 0x0 ), /* 0 */ +/* 16 */ NdrFcShort( 0x1 ), /* 1 */ +/* 18 */ NdrFcShort( 0x0 ), /* 0 */ +/* 20 */ NdrFcShort( 0x0 ), /* 0 */ +/* 22 */ 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 24 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 26 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 28 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 30 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 32 */ NdrFcShort( 0x4 ), /* 4 */ +/* 34 */ NdrFcShort( 0xffffffde ), /* Offset= -34 (0) */ +/* 36 */ NdrFcShort( 0x0 ), /* Offset= 0 (36) */ +/* 38 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ + }; + + memsrc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + FIELD_OFFSET(struct conf_complex, array[20])); + memsrc->size = 20; + + StubDesc = Object_StubDesc; + StubDesc.pFormatTypes = fmtstr_complex_struct; + + NdrClientInitializeNew( + &RpcMessage, + &StubMsg, + &StubDesc, + 0); + + StubMsg.BufferLength = 0; + NdrComplexStructBufferSize( &StubMsg, + (unsigned char *)memsrc, + &fmtstr_complex_struct[30] ); + ok(StubMsg.BufferLength >= 28, "length %d\n", StubMsg.BufferLength); + + /*NdrGetBuffer(&_StubMsg, _StubMsg.BufferLength, NULL);*/ + StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength); + StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength; + + ptr = NdrComplexStructMarshall( &StubMsg, (unsigned char *)memsrc, + &fmtstr_complex_struct[30] ); + ok(ptr == NULL, "ret %p\n", ptr); + ok(*(unsigned int *)StubMsg.BufferStart == 20, "Conformance should have been 20 instead of %d\n", *(unsigned int *)StubMsg.BufferStart); + ok(*(unsigned int *)(StubMsg.BufferStart + 4) == 20, "conf_complex.size should have been 20 instead of %d\n", *(unsigned int *)(StubMsg.BufferStart + 4)); + for (i = 0; i < 20; i++) + ok(*(unsigned int *)(StubMsg.BufferStart + 8 + i * 4) == 0, "pointer id for conf_complex.array[%d] should have been 0 instead of 0x%x\n", i, *(unsigned int *)(StubMsg.BufferStart + 8 + i * 4)); + + /* Server */ + my_alloc_called = 0; + StubMsg.IsClient = 0; + mem = NULL; + StubMsg.Buffer = StubMsg.BufferStart; + ptr = NdrComplexStructUnmarshall( &StubMsg, (unsigned char **)&mem, &fmtstr_complex_struct[30], 0); + ok(ptr == NULL, "ret %p\n", ptr); + ok(mem->size == 20, "mem->size wasn't unmarshalled correctly (%d)\n", mem->size); + ok(mem->array[0] == NULL, "mem->array[0] wasn't unmarshalled correctly (%p)\n", mem->array[0]); + StubMsg.pfnFree(mem); + + HeapFree(GetProcessHeap(), 0, StubMsg.RpcMsg->Buffer); +} + static void test_ndr_buffer(void) { static unsigned char ncalrpc[] = "ncalrpc"; @@ -1716,15 +1904,17 @@ static void test_ndr_buffer(void) unsigned char *binding; RPC_BINDING_HANDLE Handle; RPC_STATUS status; + ULONG prev_buffer_length; + BOOL old_buffer_valid_location; StubDesc.RpcInterfaceInformation = (void *)&IFoo___RpcServerInterface; status = RpcServerUseProtseqEp(ncalrpc, 20, endpoint, NULL); - ok(RPC_S_OK == status, "RpcServerUseProtseqEp failed with status %lu\n", status); + ok(RPC_S_OK == status, "RpcServerUseProtseqEp failed with status %u\n", status); status = RpcServerRegisterIf(IFoo_v0_0_s_ifspec, NULL, NULL); - ok(RPC_S_OK == status, "RpcServerRegisterIf failed with status %lu\n", status); + ok(RPC_S_OK == status, "RpcServerRegisterIf failed with status %u\n", status); status = RpcServerListen(1, 20, TRUE); - ok(RPC_S_OK == status, "RpcServerListen failed with status %lu\n", status); + ok(RPC_S_OK == status, "RpcServerListen failed with status %u\n", status); if (status != RPC_S_OK) { /* Failed to create a server, running client tests is useless */ @@ -1732,10 +1922,10 @@ static void test_ndr_buffer(void) } status = RpcStringBindingCompose(NULL, ncalrpc, NULL, endpoint, NULL, &binding); - ok(status == RPC_S_OK, "RpcStringBindingCompose failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcStringBindingCompose failed (%u)\n", status); status = RpcBindingFromStringBinding(binding, &Handle); - ok(status == RPC_S_OK, "RpcBindingFromStringBinding failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcBindingFromStringBinding failed (%u)\n", status); RpcStringFree(&binding); NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 5); @@ -1744,23 +1934,33 @@ static void test_ndr_buffer(void) ok(ret == StubMsg.Buffer, "NdrGetBuffer should have returned the same value as StubMsg.Buffer instead of %p\n", ret); ok(RpcMessage.Handle != NULL, "RpcMessage.Handle should not have been NULL\n"); ok(RpcMessage.Buffer != NULL, "RpcMessage.Buffer should not have been NULL\n"); - ok(RpcMessage.BufferLength == 10, "RpcMessage.BufferLength should have been 10 instead of %d\n", RpcMessage.BufferLength); - ok(RpcMessage.RpcFlags == 0, "RpcMessage.RpcFlags should have been 0x0 instead of 0x%lx\n", RpcMessage.RpcFlags); + ok(RpcMessage.BufferLength == 10 || + broken(RpcMessage.BufferLength == 12), /* win2k */ + "RpcMessage.BufferLength should have been 10 instead of %d\n", RpcMessage.BufferLength); + ok(RpcMessage.RpcFlags == 0, "RpcMessage.RpcFlags should have been 0x0 instead of 0x%x\n", RpcMessage.RpcFlags); ok(StubMsg.Buffer != NULL, "Buffer should not have been NULL\n"); ok(!StubMsg.BufferStart, "BufferStart should have been NULL instead of %p\n", StubMsg.BufferStart); ok(!StubMsg.BufferEnd, "BufferEnd should have been NULL instead of %p\n", StubMsg.BufferEnd); todo_wine ok(StubMsg.BufferLength == 0, "BufferLength should have left as 0 instead of being set to %d\n", StubMsg.BufferLength); - ok(StubMsg.fBufferValid == TRUE, "fBufferValid should have been TRUE instead of 0x%x\n", StubMsg.fBufferValid); + old_buffer_valid_location = !StubMsg.fBufferValid; + if (old_buffer_valid_location) + ok(broken(StubMsg.CorrDespIncrement == TRUE), "fBufferValid should have been TRUE instead of 0x%x\n", StubMsg.CorrDespIncrement); + else + ok(StubMsg.fBufferValid, "fBufferValid should have been non-zero instead of 0x%x\n", StubMsg.fBufferValid); + prev_buffer_length = RpcMessage.BufferLength; StubMsg.BufferLength = 1; NdrFreeBuffer(&StubMsg); ok(RpcMessage.Handle != NULL, "RpcMessage.Handle should not have been NULL\n"); ok(RpcMessage.Buffer != NULL, "RpcMessage.Buffer should not have been NULL\n"); - ok(RpcMessage.BufferLength == 10, "RpcMessage.BufferLength should have been left as 10 instead of %d\n", RpcMessage.BufferLength); + ok(RpcMessage.BufferLength == prev_buffer_length, "RpcMessage.BufferLength should have been left as %d instead of %d\n", prev_buffer_length, RpcMessage.BufferLength); ok(StubMsg.Buffer != NULL, "Buffer should not have been NULL\n"); ok(StubMsg.BufferLength == 1, "BufferLength should have left as 1 instead of being set to %d\n", StubMsg.BufferLength); - ok(StubMsg.fBufferValid == FALSE, "fBufferValid should have been FALSE instead of 0x%x\n", StubMsg.fBufferValid); + if (old_buffer_valid_location) + ok(broken(StubMsg.CorrDespIncrement == FALSE), "fBufferValid should have been FALSE instead of 0x%x\n", StubMsg.CorrDespIncrement); + else + ok(!StubMsg.fBufferValid, "fBufferValid should have been FALSE instead of %d\n", StubMsg.fBufferValid); /* attempt double-free */ NdrFreeBuffer(&StubMsg); @@ -1768,7 +1968,7 @@ todo_wine RpcBindingFree(&Handle); status = RpcServerUnregisterIf(NULL, NULL, FALSE); - ok(status == RPC_S_OK, "RpcServerUnregisterIf failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcServerUnregisterIf failed (%u)\n", status); } static void test_NdrMapCommAndFaultStatus(void) @@ -1787,7 +1987,7 @@ static void test_NdrMapCommAndFaultStatus(void) ULONG expected_comm_status = 0; ULONG expected_fault_status = 0; status = NdrMapCommAndFaultStatus(&StubMsg, &comm_status, &fault_status, rpc_status); - ok(status == RPC_S_OK, "NdrMapCommAndFaultStatus failed with error %ld\n", status); + ok(status == RPC_S_OK, "NdrMapCommAndFaultStatus failed with error %d\n", status); switch (rpc_status) { case ERROR_INVALID_HANDLE: @@ -1807,15 +2007,224 @@ static void test_NdrMapCommAndFaultStatus(void) default: expected_fault_status = rpc_status; } - ok(comm_status == expected_comm_status, "NdrMapCommAndFaultStatus should have mapped %ld to comm status %d instead of %d\n", + ok(comm_status == expected_comm_status, "NdrMapCommAndFaultStatus should have mapped %d to comm status %d instead of %d\n", rpc_status, expected_comm_status, comm_status); - ok(fault_status == expected_fault_status, "NdrMapCommAndFaultStatus should have mapped %ld to fault status %d instead of %d\n", + ok(fault_status == expected_fault_status, "NdrMapCommAndFaultStatus should have mapped %d to fault status %d instead of %d\n", rpc_status, expected_fault_status, fault_status); } } +static void test_NdrGetUserMarshalInfo(void) +{ + RPC_STATUS status; + MIDL_STUB_MESSAGE stubmsg; + USER_MARSHAL_CB umcb; + NDR_USER_MARSHAL_INFO umi; + unsigned char buffer[16]; + void *rpc_channel_buffer = (void *)(ULONG_PTR)0xcafebabe; + RPC_MESSAGE rpc_msg; + RPC_STATUS (RPC_ENTRY *pNdrGetUserMarshalInfo)(ULONG *,ULONG,NDR_USER_MARSHAL_INFO *); + + pNdrGetUserMarshalInfo = (void *)GetProcAddress(GetModuleHandle("rpcrt4.dll"), "NdrGetUserMarshalInfo"); + if (!pNdrGetUserMarshalInfo) + { + skip("NdrGetUserMarshalInfo not exported\n"); + return; + } + + /* unmarshall */ + + memset(&rpc_msg, 0xcc, sizeof(rpc_msg)); + rpc_msg.Buffer = buffer; + rpc_msg.BufferLength = 16; + + memset(&stubmsg, 0xcc, sizeof(stubmsg)); + stubmsg.RpcMsg = &rpc_msg; + stubmsg.dwDestContext = MSHCTX_INPROC; + stubmsg.pvDestContext = NULL; + stubmsg.Buffer = buffer + 15; + stubmsg.BufferLength = 0; + stubmsg.BufferEnd = NULL; + stubmsg.pRpcChannelBuffer = rpc_channel_buffer; + stubmsg.StubDesc = NULL; + stubmsg.pfnAllocate = my_alloc; + stubmsg.pfnFree = my_free; + + memset(&umcb, 0xcc, sizeof(umcb)); + umcb.Flags = MAKELONG(MSHCTX_INPROC, NDR_LOCAL_DATA_REPRESENTATION); + umcb.pStubMsg = &stubmsg; + umcb.Signature = USER_MARSHAL_CB_SIGNATURE; + umcb.CBType = USER_MARSHAL_CB_UNMARSHALL; + + memset(&umi, 0xaa, sizeof(umi)); + + status = pNdrGetUserMarshalInfo(&umcb.Flags, 1, &umi); + ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status); + ok( umi.InformationLevel == 1, + "umi.InformationLevel was %u instead of 1\n", + umi.InformationLevel); + ok( U(umi.Level1).Buffer == buffer + 15, + "U(umi.Level1).Buffer was %p instead of %p\n", + U(umi.Level1).Buffer, buffer); + ok( U(umi.Level1).BufferSize == 1, + "U(umi.Level1).BufferSize was %u instead of 1\n", + U(umi.Level1).BufferSize); + ok( U(umi.Level1).pfnAllocate == my_alloc, + "U(umi.Level1).pfnAllocate was %p instead of %p\n", + U(umi.Level1).pfnAllocate, my_alloc); + ok( U(umi.Level1).pfnFree == my_free, + "U(umi.Level1).pfnFree was %p instead of %p\n", + U(umi.Level1).pfnFree, my_free); + ok( U(umi.Level1).pRpcChannelBuffer == rpc_channel_buffer, + "U(umi.Level1).pRpcChannelBuffer was %p instead of %p\n", + U(umi.Level1).pRpcChannelBuffer, rpc_channel_buffer); + + /* buffer size */ + + rpc_msg.Buffer = buffer; + rpc_msg.BufferLength = 16; + + stubmsg.Buffer = buffer; + stubmsg.BufferLength = 16; + stubmsg.BufferEnd = NULL; + + umcb.CBType = USER_MARSHAL_CB_BUFFER_SIZE; + + memset(&umi, 0xaa, sizeof(umi)); + + status = pNdrGetUserMarshalInfo(&umcb.Flags, 1, &umi); + ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status); + ok( umi.InformationLevel == 1, + "umi.InformationLevel was %u instead of 1\n", + umi.InformationLevel); + ok( U(umi.Level1).Buffer == NULL, + "U(umi.Level1).Buffer was %p instead of NULL\n", + U(umi.Level1).Buffer); + ok( U(umi.Level1).BufferSize == 0, + "U(umi.Level1).BufferSize was %u instead of 0\n", + U(umi.Level1).BufferSize); + ok( U(umi.Level1).pfnAllocate == my_alloc, + "U(umi.Level1).pfnAllocate was %p instead of %p\n", + U(umi.Level1).pfnAllocate, my_alloc); + ok( U(umi.Level1).pfnFree == my_free, + "U(umi.Level1).pfnFree was %p instead of %p\n", + U(umi.Level1).pfnFree, my_free); + ok( U(umi.Level1).pRpcChannelBuffer == rpc_channel_buffer, + "U(umi.Level1).pRpcChannelBuffer was %p instead of %p\n", + U(umi.Level1).pRpcChannelBuffer, rpc_channel_buffer); + + /* marshall */ + + rpc_msg.Buffer = buffer; + rpc_msg.BufferLength = 16; + + stubmsg.Buffer = buffer + 15; + stubmsg.BufferLength = 0; + stubmsg.BufferEnd = NULL; + + umcb.CBType = USER_MARSHAL_CB_MARSHALL; + + memset(&umi, 0xaa, sizeof(umi)); + + status = pNdrGetUserMarshalInfo(&umcb.Flags, 1, &umi); + ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status); + ok( umi.InformationLevel == 1, + "umi.InformationLevel was %u instead of 1\n", + umi.InformationLevel); + ok( U(umi.Level1).Buffer == buffer + 15, + "U(umi.Level1).Buffer was %p instead of %p\n", + U(umi.Level1).Buffer, buffer); + ok( U(umi.Level1).BufferSize == 1, + "U(umi.Level1).BufferSize was %u instead of 1\n", + U(umi.Level1).BufferSize); + ok( U(umi.Level1).pfnAllocate == my_alloc, + "U(umi.Level1).pfnAllocate was %p instead of %p\n", + U(umi.Level1).pfnAllocate, my_alloc); + ok( U(umi.Level1).pfnFree == my_free, + "U(umi.Level1).pfnFree was %p instead of %p\n", + U(umi.Level1).pfnFree, my_free); + ok( U(umi.Level1).pRpcChannelBuffer == rpc_channel_buffer, + "U(umi.Level1).pRpcChannelBuffer was %p instead of %p\n", + U(umi.Level1).pRpcChannelBuffer, rpc_channel_buffer); + + /* free */ + + rpc_msg.Buffer = buffer; + rpc_msg.BufferLength = 16; + + stubmsg.Buffer = buffer; + stubmsg.BufferLength = 16; + stubmsg.BufferEnd = NULL; + + umcb.CBType = USER_MARSHAL_CB_FREE; + + memset(&umi, 0xaa, sizeof(umi)); + + status = pNdrGetUserMarshalInfo(&umcb.Flags, 1, &umi); + ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status); + ok( umi.InformationLevel == 1, + "umi.InformationLevel was %u instead of 1\n", + umi.InformationLevel); + ok( U(umi.Level1).Buffer == NULL, + "U(umi.Level1).Buffer was %p instead of NULL\n", + U(umi.Level1).Buffer); + ok( U(umi.Level1).BufferSize == 0, + "U(umi.Level1).BufferSize was %u instead of 0\n", + U(umi.Level1).BufferSize); + ok( U(umi.Level1).pfnAllocate == my_alloc, + "U(umi.Level1).pfnAllocate was %p instead of %p\n", + U(umi.Level1).pfnAllocate, my_alloc); + ok( U(umi.Level1).pfnFree == my_free, + "U(umi.Level1).pfnFree was %p instead of %p\n", + U(umi.Level1).pfnFree, my_free); + ok( U(umi.Level1).pRpcChannelBuffer == rpc_channel_buffer, + "U(umi.Level1).pRpcChannelBuffer was %p instead of %p\n", + U(umi.Level1).pRpcChannelBuffer, rpc_channel_buffer); + + /* boundary test */ + + rpc_msg.Buffer = buffer; + rpc_msg.BufferLength = 15; + + stubmsg.Buffer = buffer + 15; + stubmsg.BufferLength = 0; + stubmsg.BufferEnd = NULL; + + umcb.CBType = USER_MARSHAL_CB_MARSHALL; + + status = pNdrGetUserMarshalInfo(&umcb.Flags, 1, &umi); + ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status); + ok( U(umi.Level1).BufferSize == 0, + "U(umi.Level1).BufferSize was %u instead of 0\n", + U(umi.Level1).BufferSize); + + /* error conditions */ + + rpc_msg.BufferLength = 14; + status = pNdrGetUserMarshalInfo(&umcb.Flags, 1, &umi); + ok(status == ERROR_INVALID_USER_BUFFER, + "NdrGetUserMarshalInfo should have failed with ERROR_INVALID_USER_BUFFER instead of %d\n", status); + + rpc_msg.BufferLength = 15; + status = pNdrGetUserMarshalInfo(&umcb.Flags, 9999, &umi); + ok(status == RPC_S_INVALID_ARG, + "NdrGetUserMarshalInfo should have failed with RPC_S_INVALID_ARG instead of %d\n", status); + + umcb.CBType = 9999; + status = pNdrGetUserMarshalInfo(&umcb.Flags, 1, &umi); + ok(status == RPC_S_OK, "NdrGetUserMarshalInfo failed with error %d\n", status); + + umcb.CBType = USER_MARSHAL_CB_MARSHALL; + umcb.Signature = 0; + status = pNdrGetUserMarshalInfo(&umcb.Flags, 1, &umi); + ok(status == RPC_S_INVALID_ARG, + "NdrGetUserMarshalInfo should have failed with RPC_S_INVALID_ARG instead of %d\n", status); +} + START_TEST( ndr_marshall ) { + determine_pointer_marshalling_style(); + test_ndr_simple_type(); test_simple_types(); test_nontrivial_pointer_types(); @@ -1827,6 +2236,8 @@ START_TEST( ndr_marshall ) test_conformant_array(); test_conformant_string(); test_nonconformant_string(); + test_conf_complex_struct(); test_ndr_buffer(); test_NdrMapCommAndFaultStatus(); + test_NdrGetUserMarshalInfo(); } diff --git a/rostests/winetests/rpcrt4/rpc.c b/rostests/winetests/rpcrt4/rpc.c index 4197707d7d4..2b7b592a0fa 100644 --- a/rostests/winetests/rpcrt4/rpc.c +++ b/rostests/winetests/rpcrt4/rpc.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include "rpc.h" #include "rpcdce.h" @@ -225,63 +225,68 @@ static void test_rpc_ncacn_ip_tcp(void) status = RpcMgmtStopServerListening(NULL); todo_wine { ok(status == RPC_S_NOT_LISTENING, - "wrong RpcMgmtStopServerListening error (%lu)\n", status); + "wrong RpcMgmtStopServerListening error (%u)\n", status); } status = RpcMgmtWaitServerListen(); ok(status == RPC_S_NOT_LISTENING, - "wrong RpcMgmtWaitServerListen error status (%lu)\n", status); + "wrong RpcMgmtWaitServerListen error status (%u)\n", status); status = RpcServerListen(1, 20, FALSE); ok(status == RPC_S_NO_PROTSEQS_REGISTERED, - "wrong RpcServerListen error (%lu)\n", status); + "wrong RpcServerListen error (%u)\n", status); status = RpcServerUseProtseqEp(ncacn_ip_tcp, 20, endpoint, NULL); - ok(status == RPC_S_OK, "RpcServerUseProtseqEp failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcServerUseProtseqEp failed (%u)\n", status); status = RpcServerRegisterIf(IFoo_v0_0_s_ifspec, NULL, NULL); - ok(status == RPC_S_OK, "RpcServerRegisterIf failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcServerRegisterIf failed (%u)\n", status); status = RpcServerListen(1, 20, TRUE); todo_wine { - ok(status == RPC_S_OK, "RpcServerListen failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcServerListen failed (%u)\n", status); } status = RpcServerListen(1, 20, TRUE); todo_wine { ok(status == RPC_S_ALREADY_LISTENING, - "wrong RpcServerListen error (%lu)\n", status); + "wrong RpcServerListen error (%u)\n", status); } status = RpcStringBindingCompose(NULL, ncacn_ip_tcp, address, endpoint, NULL, &binding); - ok(status == RPC_S_OK, "RpcStringBindingCompose failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcStringBindingCompose failed (%u)\n", status); status = RpcBindingFromStringBinding(binding, &IFoo_IfHandle); - ok(status == RPC_S_OK, "RpcBindingFromStringBinding failed (%lu)\n", + ok(status == RPC_S_OK, "RpcBindingFromStringBinding failed (%u)\n", + status); + + status = RpcBindingSetAuthInfo(IFoo_IfHandle, NULL, RPC_C_AUTHN_LEVEL_NONE, + RPC_C_AUTHN_WINNT, NULL, RPC_C_AUTHZ_NAME); + ok(status == RPC_S_OK || broken(status == RPC_S_UNKNOWN_AUTHN_SERVICE), /* win9x */ + "RpcBindingSetAuthInfo failed (%u)\n", status); + + status = RpcMgmtStopServerListening(NULL); + ok(status == RPC_S_OK, "RpcMgmtStopServerListening failed (%u)\n", status); status = RpcMgmtStopServerListening(NULL); - ok(status == RPC_S_OK, "RpcMgmtStopServerListening failed (%lu)\n", - status); - - status = RpcMgmtStopServerListening(NULL); - ok(status == RPC_S_OK, "RpcMgmtStopServerListening failed (%lu)\n", + ok(status == RPC_S_OK, "RpcMgmtStopServerListening failed (%u)\n", status); status = RpcServerUnregisterIf(NULL, NULL, FALSE); - ok(status == RPC_S_OK, "RpcServerUnregisterIf failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcServerUnregisterIf failed (%u)\n", status); status = RpcMgmtWaitServerListen(); todo_wine { - ok(status == RPC_S_OK, "RpcMgmtWaitServerListen failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcMgmtWaitServerListen failed (%u)\n", status); } status = RpcStringFree(&binding); - ok(status == RPC_S_OK, "RpcStringFree failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcStringFree failed (%u)\n", status); status = RpcBindingFree(&IFoo_IfHandle); - ok(status == RPC_S_OK, "RpcBindingFree failed (%lu)\n", status); + ok(status == RPC_S_OK, "RpcBindingFree failed (%u)\n", status); } /* this is what's generated with MS/RPC - it includes an extra 2 @@ -325,11 +330,13 @@ static void test_towers(void) BOOL same; ret = TowerConstruct(&mapi_if_id, &ndr_syntax, "ncacn_ip_tcp", "135", "10.0.0.1", &tower); - ok(ret == RPC_S_OK, "TowerConstruct failed with error %ld\n", ret); + ok(ret == RPC_S_OK || + broken(ret == RPC_S_INVALID_RPC_PROTSEQ), /* Vista */ + "TowerConstruct failed with error %d\n", ret); if (ret == RPC_S_INVALID_RPC_PROTSEQ) { /* Windows Vista fails with this error and crashes if we continue */ - skip("TowerConstruct failed, we are most likely on Windows Vista\n"); + win_skip("TowerConstruct failed, we are most likely on Windows Vista\n"); return; } @@ -358,7 +365,7 @@ static void test_towers(void) } ret = TowerExplode(tower, &object, &syntax, &protseq, &endpoint, &address); - ok(ret == RPC_S_OK, "TowerExplode failed with error %ld\n", ret); + ok(ret == RPC_S_OK, "TowerExplode failed with error %d\n", ret); ok(!memcmp(&object, &mapi_if_id, sizeof(mapi_if_id)), "object id didn't match\n"); ok(!memcmp(&syntax, &ndr_syntax, sizeof(syntax)), "syntax id didn't match\n"); ok(!strcmp(protseq, "ncacn_ip_tcp"), "protseq was \"%s\" instead of \"ncacn_ip_tcp\"\n", protseq); @@ -370,27 +377,31 @@ static void test_towers(void) I_RpcFree(address); ret = TowerExplode(tower, NULL, NULL, NULL, NULL, NULL); - ok(ret == RPC_S_OK, "TowerExplode failed with error %ld\n", ret); + ok(ret == RPC_S_OK, "TowerExplode failed with error %d\n", ret); I_RpcFree(tower); /* test the behaviour for ip_tcp with name instead of dotted IP notation */ ret = TowerConstruct(&mapi_if_id, &ndr_syntax, "ncacn_ip_tcp", "135", "localhost", &tower); - ok(ret == RPC_S_OK, "TowerConstruct failed with error %ld\n", ret); + ok(ret == RPC_S_OK, "TowerConstruct failed with error %d\n", ret); ret = TowerExplode(tower, NULL, NULL, NULL, NULL, &address); - ok(ret == RPC_S_OK, "TowerExplode failed with error %ld\n", ret); - ok(!strcmp(address, "0.0.0.0"), "address was \"%s\" instead of \"0.0.0.0\"\n", address); + ok(ret == RPC_S_OK, "TowerExplode failed with error %d\n", ret); + ok(!strcmp(address, "0.0.0.0") || + broken(!strcmp(address, "255.255.255.255")), + "address was \"%s\" instead of \"0.0.0.0\"\n", address); I_RpcFree(address); I_RpcFree(tower); /* test the behaviour for np with no address */ ret = TowerConstruct(&mapi_if_id, &ndr_syntax, "ncacn_np", "\\pipe\\test", NULL, &tower); - ok(ret == RPC_S_OK, "TowerConstruct failed with error %ld\n", ret); + ok(ret == RPC_S_OK, "TowerConstruct failed with error %d\n", ret); ret = TowerExplode(tower, NULL, NULL, NULL, NULL, &address); - ok(ret == RPC_S_OK, "TowerExplode failed with error %ld\n", ret); + ok(ret == RPC_S_OK || + broken(ret != RPC_S_OK), /* win2k, indeterminate */ + "TowerExplode failed with error %d\n", ret); /* Windows XP SP3 sets address to NULL */ - ok(!address || !strcmp(address, ""), "address was \"%s\" instead of \"\"\n or NULL (XP SP3)", address); + ok(!address || !strcmp(address, ""), "address was \"%s\" instead of \"\" or NULL (XP SP3)\n", address); I_RpcFree(address); I_RpcFree(tower); @@ -400,8 +411,14 @@ static void test_I_RpcMapWin32Status(void) { LONG win32status; RPC_STATUS rpc_status; + BOOL on_win9x = FALSE; BOOL w2k3_up = FALSE; + /* Win9x always returns the given status */ + win32status = I_RpcMapWin32Status(ERROR_ACCESS_DENIED); + if (win32status == ERROR_ACCESS_DENIED) + on_win9x = TRUE; + /* Windows 2003 and Vista return STATUS_UNSUCCESSFUL if given an unknown status */ win32status = I_RpcMapWin32Status(9999); if (win32status == STATUS_UNSUCCESSFUL) @@ -410,9 +427,14 @@ static void test_I_RpcMapWin32Status(void) w2k3_up = TRUE; } + /* On Windows XP-SP1 and below some statuses are not mapped and return + * the given status + */ for (rpc_status = 0; rpc_status < 10000; rpc_status++) { LONG expected_win32status; + BOOL missing = FALSE; + win32status = I_RpcMapWin32Status(rpc_status); switch (rpc_status) { @@ -425,10 +447,10 @@ static void test_I_RpcMapWin32Status(void) case ERROR_MAX_THRDS_REACHED: expected_win32status = STATUS_NO_MEMORY; break; case ERROR_NOACCESS: expected_win32status = STATUS_ACCESS_VIOLATION; break; case ERROR_NOT_ENOUGH_SERVER_MEMORY: expected_win32status = STATUS_INSUFF_SERVER_RESOURCES; break; - case ERROR_WRONG_PASSWORD: expected_win32status = STATUS_WRONG_PASSWORD; break; - case ERROR_INVALID_LOGON_HOURS: expected_win32status = STATUS_INVALID_LOGON_HOURS; break; - case ERROR_PASSWORD_EXPIRED: expected_win32status = STATUS_PASSWORD_EXPIRED; break; - case ERROR_ACCOUNT_DISABLED: expected_win32status = STATUS_ACCOUNT_DISABLED; break; + case ERROR_WRONG_PASSWORD: expected_win32status = STATUS_WRONG_PASSWORD; missing = TRUE; break; + case ERROR_INVALID_LOGON_HOURS: expected_win32status = STATUS_INVALID_LOGON_HOURS; missing = TRUE; break; + case ERROR_PASSWORD_EXPIRED: expected_win32status = STATUS_PASSWORD_EXPIRED; missing = TRUE; break; + case ERROR_ACCOUNT_DISABLED: expected_win32status = STATUS_ACCOUNT_DISABLED; missing = TRUE; break; case ERROR_INVALID_SECURITY_DESCR: expected_win32status = STATUS_INVALID_SECURITY_DESCR; break; case RPC_S_INVALID_STRING_BINDING: expected_win32status = RPC_NT_INVALID_STRING_BINDING; break; case RPC_S_WRONG_KIND_OF_BINDING: expected_win32status = RPC_NT_WRONG_KIND_OF_BINDING; break; @@ -502,10 +524,10 @@ static void test_I_RpcMapWin32Status(void) case RPC_S_FP_OVERFLOW: expected_win32status = RPC_NT_FP_OVERFLOW; break; case RPC_S_CALL_IN_PROGRESS: expected_win32status = RPC_NT_CALL_IN_PROGRESS; break; case RPC_S_NO_MORE_BINDINGS: expected_win32status = RPC_NT_NO_MORE_BINDINGS; break; - case RPC_S_CALL_CANCELLED: expected_win32status = RPC_NT_CALL_CANCELLED; break; + case RPC_S_CALL_CANCELLED: expected_win32status = RPC_NT_CALL_CANCELLED; missing = TRUE; break; case RPC_S_INVALID_OBJECT: expected_win32status = RPC_NT_INVALID_OBJECT; break; - case RPC_S_INVALID_ASYNC_HANDLE: expected_win32status = RPC_NT_INVALID_ASYNC_HANDLE; break; - case RPC_S_INVALID_ASYNC_CALL: expected_win32status = RPC_NT_INVALID_ASYNC_CALL; break; + case RPC_S_INVALID_ASYNC_HANDLE: expected_win32status = RPC_NT_INVALID_ASYNC_HANDLE; missing = TRUE; break; + case RPC_S_INVALID_ASYNC_CALL: expected_win32status = RPC_NT_INVALID_ASYNC_CALL; missing = TRUE; break; case RPC_S_GROUP_MEMBER_NOT_FOUND: expected_win32status = RPC_NT_GROUP_MEMBER_NOT_FOUND; break; case RPC_X_NO_MORE_ENTRIES: expected_win32status = RPC_NT_NO_MORE_ENTRIES; break; case RPC_X_SS_CHAR_TRANS_OPEN_FAIL: expected_win32status = RPC_NT_SS_CHAR_TRANS_OPEN_FAIL; break; @@ -518,19 +540,26 @@ static void test_I_RpcMapWin32Status(void) case RPC_X_ENUM_VALUE_OUT_OF_RANGE: expected_win32status = RPC_NT_ENUM_VALUE_OUT_OF_RANGE; break; case RPC_X_BYTE_COUNT_TOO_SMALL: expected_win32status = RPC_NT_BYTE_COUNT_TOO_SMALL; break; case RPC_X_BAD_STUB_DATA: expected_win32status = RPC_NT_BAD_STUB_DATA; break; - case RPC_X_PIPE_CLOSED: expected_win32status = RPC_NT_PIPE_CLOSED; break; - case RPC_X_PIPE_DISCIPLINE_ERROR: expected_win32status = RPC_NT_PIPE_DISCIPLINE_ERROR; break; - case RPC_X_PIPE_EMPTY: expected_win32status = RPC_NT_PIPE_EMPTY; break; - case ERROR_PASSWORD_MUST_CHANGE: expected_win32status = STATUS_PASSWORD_MUST_CHANGE; break; - case ERROR_ACCOUNT_LOCKED_OUT: expected_win32status = STATUS_ACCOUNT_LOCKED_OUT; break; + case RPC_X_PIPE_CLOSED: expected_win32status = RPC_NT_PIPE_CLOSED; missing = TRUE; break; + case RPC_X_PIPE_DISCIPLINE_ERROR: expected_win32status = RPC_NT_PIPE_DISCIPLINE_ERROR; missing = TRUE; break; + case RPC_X_PIPE_EMPTY: expected_win32status = RPC_NT_PIPE_EMPTY; missing = TRUE; break; + case ERROR_PASSWORD_MUST_CHANGE: expected_win32status = STATUS_PASSWORD_MUST_CHANGE; missing = TRUE; break; + case ERROR_ACCOUNT_LOCKED_OUT: expected_win32status = STATUS_ACCOUNT_LOCKED_OUT; missing = TRUE; break; default: if (w2k3_up) expected_win32status = STATUS_UNSUCCESSFUL; else expected_win32status = rpc_status; } - ok(win32status == expected_win32status, "I_RpcMapWin32Status(%ld) should have returned 0x%x instead of 0x%x\n", - rpc_status, expected_win32status, win32status); + + if (on_win9x) + missing = TRUE; + + ok(win32status == expected_win32status || + broken(missing && win32status == rpc_status), + "I_RpcMapWin32Status(%d) should have returned 0x%x instead of 0x%x%s\n", + rpc_status, expected_win32status, win32status, + broken(missing) ? " (or have returned with the given status)" : ""); } } @@ -550,11 +579,10 @@ static void test_RpcStringBindingParseA(void) /* test all parameters */ status = RpcStringBindingParseA(valid_binding, &uuid, &protseq, &network_addr, &endpoint, &options); - ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %ld\n", status); + ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %d\n", status); ok(!strcmp((char *)uuid, "00000000-0000-0000-c000-000000000046"), "uuid should have been 00000000-0000-0000-C000-000000000046 instead of %s\n", uuid); ok(!strcmp((char *)protseq, "ncacn_np"), "protseq should have been ncacn_np instead of %s\n", protseq); ok(!strcmp((char *)network_addr, "."), "network_addr should have been . instead of %s\n", network_addr); - todo_wine ok(!strcmp((char *)endpoint, "pipetest"), "endpoint should have been pipetest instead of %s\n", endpoint); todo_wine ok(options && !strcmp((char *)options, ""), "options should have been \"\" of \"%s\"\n", options); @@ -566,11 +594,10 @@ static void test_RpcStringBindingParseA(void) /* test all parameters with different type of string binding */ status = RpcStringBindingParseA(valid_binding2, &uuid, &protseq, &network_addr, &endpoint, &options); - ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %ld\n", status); + ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %d\n", status); ok(!strcmp((char *)uuid, "00000000-0000-0000-c000-000000000046"), "uuid should have been 00000000-0000-0000-C000-000000000046 instead of %s\n", uuid); ok(!strcmp((char *)protseq, "ncacn_np"), "protseq should have been ncacn_np instead of %s\n", protseq); ok(!strcmp((char *)network_addr, "."), "network_addr should have been . instead of %s\n", network_addr); - todo_wine ok(!strcmp((char *)endpoint, "pipetest"), "endpoint should have been pipetest instead of %s\n", endpoint); todo_wine ok(options && !strcmp((char *)options, ""), "options should have been \"\" of \"%s\"\n", options); @@ -582,26 +609,24 @@ static void test_RpcStringBindingParseA(void) /* test with as many parameters NULL as possible */ status = RpcStringBindingParseA(valid_binding, NULL, &protseq, NULL, NULL, NULL); - ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %ld\n", status); + ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %d\n", status); ok(!strcmp((char *)protseq, "ncacn_np"), "protseq should have been ncacn_np instead of %s\n", protseq); RpcStringFreeA(&protseq); /* test with invalid uuid */ status = RpcStringBindingParseA(invalid_uuid_binding, NULL, &protseq, NULL, NULL, NULL); - todo_wine - ok(status == RPC_S_INVALID_STRING_UUID, "RpcStringBindingParseA should have returned RPC_S_INVALID_STRING_UUID instead of %ld\n", status); - todo_wine + ok(status == RPC_S_INVALID_STRING_UUID, "RpcStringBindingParseA should have returned RPC_S_INVALID_STRING_UUID instead of %d\n", status); ok(protseq == NULL, "protseq was %p instead of NULL\n", protseq); /* test with invalid endpoint */ status = RpcStringBindingParseA(invalid_ep_binding, NULL, &protseq, NULL, NULL, NULL); - ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %ld\n", status); + ok(status == RPC_S_OK, "RpcStringBindingParseA failed with error %d\n", status); RpcStringFreeA(&protseq); /* test with invalid binding */ status = RpcStringBindingParseA(invalid_binding, &uuid, &protseq, &network_addr, &endpoint, &options); todo_wine - ok(status == RPC_S_INVALID_STRING_BINDING, "RpcStringBindingParseA should have returned RPC_S_INVALID_STRING_BINDING instead of %ld\n", status); + ok(status == RPC_S_INVALID_STRING_BINDING, "RpcStringBindingParseA should have returned RPC_S_INVALID_STRING_BINDING instead of %d\n", status); todo_wine ok(uuid == NULL, "uuid was %p instead of NULL\n", uuid); ok(protseq == NULL, "protseq was %p instead of NULL\n", protseq); @@ -644,6 +669,11 @@ static void test_I_RpcExceptionFilter(void) ok(retval == EXCEPTION_CONTINUE_SEARCH, "I_RpcExceptionFilter(0x%x) should have returned %d instead of %d\n", exception, EXCEPTION_CONTINUE_SEARCH, retval); break; + case STATUS_GUARD_PAGE_VIOLATION: + case STATUS_IN_PAGE_ERROR: + case STATUS_HANDLE_NOT_CLOSABLE: + trace("I_RpcExceptionFilter(0x%x) returned %d\n", exception, retval); + break; default: ok(retval == EXCEPTION_EXECUTE_HANDLER, "I_RpcExceptionFilter(0x%x) should have returned %d instead of %d\n", exception, EXCEPTION_EXECUTE_HANDLER, retval); @@ -651,15 +681,109 @@ static void test_I_RpcExceptionFilter(void) } } +static void test_RpcStringBindingFromBinding(void) +{ + static unsigned char ncacn_np[] = "ncacn_np"; + static unsigned char address[] = "."; + static unsigned char endpoint[] = "\\pipe\\wine_rpc_test"; + RPC_STATUS status; + handle_t handle; + RPC_CSTR binding; + + status = RpcStringBindingCompose(NULL, ncacn_np, address, + endpoint, NULL, &binding); + ok(status == RPC_S_OK, "RpcStringBindingCompose failed (%u)\n", status); + + status = RpcBindingFromStringBinding(binding, &handle); + ok(status == RPC_S_OK, "RpcBindingFromStringBinding failed (%u)\n", status); + RpcStringFree(&binding); + + status = RpcBindingToStringBinding(handle, &binding); + ok(status == RPC_S_OK, "RpcStringBindingFromBinding failed with error %u\n", status); + + ok(!strcmp((const char *)binding, "ncacn_np:.[\\\\pipe\\\\wine_rpc_test]"), + "binding string didn't match what was expected: \"%s\"\n", binding); + RpcStringFree(&binding); + + status = RpcBindingFree(&handle); + ok(status == RPC_S_OK, "RpcBindingFree failed with error %u\n", status); +} + +static char *printGuid(char *buf, int size, const UUID *guid) +{ + snprintf(buf, size, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], + guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], + guid->Data4[6], guid->Data4[7]); + return buf; +} + +static void test_UuidCreate(void) +{ + UUID guid; + BYTE version; + + UuidCreate(&guid); + version = (guid.Data3 & 0xf000) >> 12; + ok(version == 4 || broken(version == 1), "unexpected version %d\n", + version); + if (version == 4) + { + static UUID v4and = { 0, 0, 0x4000, { 0x80,0,0,0,0,0,0,0 } }; + static UUID v4or = { 0xffffffff, 0xffff, 0x4fff, + { 0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff } }; + UUID and, or; + RPC_STATUS rslt; + int i; + char buf[39]; + + and = guid; + or = guid; + /* Generate a bunch of UUIDs and mask them. By the end, we expect + * every randomly generated bit to have been zero at least once, + * resulting in no bits set in the and mask except those which are not + * randomly generated: the version number and the topmost bits of the + * Data4 field (treated as big-endian.) Similarly, we expect only + * the bits which are not randomly set to be cleared in the or mask. + */ + for (i = 0; i < 1000; i++) + { + LPBYTE src, dst; + + UuidCreate(&guid); + for (src = (LPBYTE)&guid, dst = (LPBYTE)∧ + src - (LPBYTE)&guid < sizeof(guid); src++, dst++) + *dst &= *src; + for (src = (LPBYTE)&guid, dst = (LPBYTE)∨ + src - (LPBYTE)&guid < sizeof(guid); src++, dst++) + *dst |= *src; + } + ok(UuidEqual(&and, &v4and, &rslt), + "unexpected bits set in V4 UUID: %s\n", printGuid(buf, sizeof(buf), &and)); + ok(UuidEqual(&or, &v4or, &rslt), + "unexpected bits set in V4 UUID: %s\n", printGuid(buf, sizeof(buf), &or)); + } + else + { + /* Older versions of Windows generate V1 UUIDs. For these, there are + * many stable bits, including at least the MAC address if one is + * present. Just check that Data4[0]'s most significant bits are + * set as expected. + */ + ok((guid.Data4[0] & 0xc0) == 0x80, + "unexpected value in Data4[0]: %02x\n", guid.Data4[0] & 0xc0); + } +} + START_TEST( rpc ) { - trace ( " ** Uuid Conversion and Comparison Tests **\n" ); UuidConversionAndComparison(); - trace ( " ** DceErrorInqText **\n"); TestDceErrorInqText(); test_rpc_ncacn_ip_tcp(); test_towers(); test_I_RpcMapWin32Status(); test_RpcStringBindingParseA(); test_I_RpcExceptionFilter(); + test_RpcStringBindingFromBinding(); + test_UuidCreate(); } diff --git a/rostests/winetests/rpcrt4/rpc_async.c b/rostests/winetests/rpcrt4/rpc_async.c index 0cc5557ce06..f82799cffc8 100644 --- a/rostests/winetests/rpcrt4/rpc_async.c +++ b/rostests/winetests/rpcrt4/rpc_async.c @@ -34,23 +34,25 @@ static void test_RpcAsyncInitializeHandle(void) RPC_ASYNC_STATE async; RPC_STATUS status; int i; + void *unset_ptr; status = pRpcAsyncInitializeHandle((PRPC_ASYNC_STATE)buffer, sizeof(buffer)); - ok(status == ERROR_INVALID_PARAMETER, "RpcAsyncInitializeHandle with large Size should have returned ERROR_INVALID_PARAMETER instead of %ld\n", status); + ok(status == ERROR_INVALID_PARAMETER, "RpcAsyncInitializeHandle with large Size should have returned ERROR_INVALID_PARAMETER instead of %d\n", status); status = pRpcAsyncInitializeHandle(&async, sizeof(async) - 1); - ok(status == ERROR_INVALID_PARAMETER, "RpcAsyncInitializeHandle with small Size should have returned ERROR_INVALID_PARAMETER instead of %ld\n", status); + ok(status == ERROR_INVALID_PARAMETER, "RpcAsyncInitializeHandle with small Size should have returned ERROR_INVALID_PARAMETER instead of %d\n", status); memset(&async, 0xcc, sizeof(async)); + memset(&unset_ptr, 0xcc, sizeof(unset_ptr)); status = pRpcAsyncInitializeHandle(&async, sizeof(async)); - ok(status == RPC_S_OK, "RpcAsyncInitializeHandle failed with error %ld\n", status); + ok(status == RPC_S_OK, "RpcAsyncInitializeHandle failed with error %d\n", status); ok(async.Size == sizeof(async), "async.Size wrong: %d\n", async.Size); ok(async.Signature == 0x43595341, "async.Signature should be 0x43595341, but is 0x%x instead\n", async.Signature); ok(async.Lock == 0, "async.Lock should be 0, but is %d instead\n", async.Lock); ok(async.Flags == 0, "async.Flags should be 0, but is %d instead\n", async.Flags); ok(async.StubInfo == NULL, "async.StubInfo should be NULL, not %p\n", async.StubInfo); - ok(async.UserInfo == (void *)0xcccccccc, "async.UserInfo should be unset, not %p\n", async.UserInfo); + ok(async.UserInfo == unset_ptr, "async.UserInfo should be unset, not %p\n", async.UserInfo); ok(async.RuntimeInfo == NULL, "async.RuntimeInfo should be NULL, not %p\n", async.RuntimeInfo); ok(async.Event == 0xcccccccc, "async.Event should be unset, not %d\n", async.Event); ok(async.NotificationType == 0xcccccccc, "async.NotificationType should be unset, not %d\n", async.NotificationType); @@ -64,16 +66,16 @@ static void test_RpcAsyncGetCallStatus(void) RPC_STATUS status; status = pRpcAsyncInitializeHandle(&async, sizeof(async)); - ok(status == RPC_S_OK, "RpcAsyncInitializeHandle failed with error %ld\n", status); + ok(status == RPC_S_OK, "RpcAsyncInitializeHandle failed with error %d\n", status); status = pRpcAsyncGetCallStatus(&async); todo_wine - ok(status == RPC_S_INVALID_BINDING, "RpcAsyncGetCallStatus should have returned RPC_S_INVALID_BINDING instead of %ld\n", status); + ok(status == RPC_S_INVALID_BINDING, "RpcAsyncGetCallStatus should have returned RPC_S_INVALID_BINDING instead of %d\n", status); memset(&async, 0, sizeof(async)); status = pRpcAsyncGetCallStatus(&async); todo_wine - ok(status == RPC_S_INVALID_BINDING, "RpcAsyncGetCallStatus should have returned RPC_S_INVALID_BINDING instead of %ld\n", status); + ok(status == RPC_S_INVALID_BINDING, "RpcAsyncGetCallStatus should have returned RPC_S_INVALID_BINDING instead of %d\n", status); } START_TEST( rpc_async ) @@ -83,7 +85,7 @@ START_TEST( rpc_async ) pRpcAsyncGetCallStatus = (void *)GetProcAddress(hRpcRt4, "RpcAsyncGetCallStatus"); if (!pRpcAsyncInitializeHandle || !pRpcAsyncGetCallStatus) { - skip("asynchronous functions not available\n"); + win_skip("asynchronous functions not available\n"); return; } test_RpcAsyncInitializeHandle(); diff --git a/rostests/winetests/rpcrt4/rpc_protseq.c b/rostests/winetests/rpcrt4/rpc_protseq.c new file mode 100644 index 00000000000..4837f6afdef --- /dev/null +++ b/rostests/winetests/rpcrt4/rpc_protseq.c @@ -0,0 +1,204 @@ +/* + * RPC Protocol Sequence Server Tests + * + * Copyright 2008-2009 Robert Shearman + * + * 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 + */ + +#include +#include + +#include "wine/test.h" +#include +#include +#include +#include + +#include "rpc.h" +#include "rpcdce.h" + +static void test_RpcServerUseProtseq(void) +{ + RPC_STATUS status; + RPC_BINDING_VECTOR *bindings; + ULONG i; + ULONG binding_count_before; + ULONG binding_count_after1; + ULONG binding_count_after2; + ULONG endpoints_registered = 0; + static unsigned char iptcp[] = "ncacn_ip_tcp"; + static unsigned char np[] = "ncacn_np"; + static unsigned char ncalrpc[] = "ncalrpc"; + + status = RpcServerInqBindings(&bindings); + if (status == RPC_S_NO_BINDINGS) + binding_count_before = 0; + else + { + binding_count_before = bindings->Count; + ok(status == RPC_S_OK, "RpcServerInqBindings failed with status %d\n", status); + RpcBindingVectorFree(&bindings); + } + + /* show that RpcServerUseProtseqEp(..., NULL, ...) is the same as + * RpcServerUseProtseq(...) */ + status = RpcServerUseProtseqEp(ncalrpc, 0, NULL, NULL); + ok(status == RPC_S_OK || broken(status == RPC_S_INVALID_ENDPOINT_FORMAT), + "RpcServerUseProtseqEp with NULL endpoint failed with status %d\n", + status); + + /* register protocol sequences without explicit endpoints */ + status = RpcServerUseProtseq(np, 0, NULL); + if (status == RPC_S_PROTSEQ_NOT_SUPPORTED) + win_skip("ncacn_np not supported\n"); + else + ok(status == RPC_S_OK, "RpcServerUseProtseq(ncacn_np) failed with status %d\n", status); + if (status == RPC_S_OK) endpoints_registered++; + + status = RpcServerUseProtseq(iptcp, 0, NULL); + ok(status == RPC_S_OK, "RpcServerUseProtseq(ncacn_ip_tcp) failed with status %d\n", status); + if (status == RPC_S_OK) endpoints_registered++; + + status = RpcServerUseProtseq(ncalrpc, 0, NULL); + ok(status == RPC_S_OK, "RpcServerUseProtseqEp(ncalrpc) failed with status %d\n", status); + if (status == RPC_S_OK) endpoints_registered++; + + status = RpcServerInqBindings(&bindings); + ok(status == RPC_S_OK, "RpcServerInqBindings failed with status %d\n", status); + binding_count_after1 = bindings->Count; + ok(binding_count_after1 == binding_count_before + endpoints_registered, + "wrong binding count - before: %u, after %u, endpoints registered %u\n", + binding_count_before, binding_count_after1, endpoints_registered); + for (i = 0; i < bindings->Count; i++) + { + RPC_CSTR str_bind; + status = RpcBindingToStringBinding(bindings->BindingH[i], &str_bind); + ok(status == RPC_S_OK, "RpcBindingToStringBinding failed with status %d\n", status); + trace("string binding: %s\n", str_bind); + RpcStringFree(&str_bind); + } + RpcBindingVectorFree(&bindings); + + /* re-register - endpoints should be reused */ + status = RpcServerUseProtseq(np, 0, NULL); + if (status == RPC_S_PROTSEQ_NOT_SUPPORTED) + win_skip("ncacn_np not supported\n"); + else + ok(status == RPC_S_OK, "RpcServerUseProtseq(ncacn_np) failed with status %d\n", status); + + status = RpcServerUseProtseq(iptcp, 0, NULL); + ok(status == RPC_S_OK, "RpcServerUseProtseq(ncacn_ip_tcp) failed with status %d\n", status); + + status = RpcServerUseProtseq(ncalrpc, 0, NULL); + ok(status == RPC_S_OK, "RpcServerUseProtseqEp(ncalrpc) failed with status %d\n", status); + + status = RpcServerInqBindings(&bindings); + ok(status == RPC_S_OK, "RpcServerInqBindings failed with status %d\n", status); + binding_count_after2 = bindings->Count; + ok(binding_count_after2 == binding_count_after1, + "bindings should have been re-used - after1: %u after2: %u\n", + binding_count_after1, binding_count_after2); + RpcBindingVectorFree(&bindings); +} + +static RPC_DISPATCH_FUNCTION IFoo_table[] = +{ + 0 +}; + +static RPC_DISPATCH_TABLE IFoo_v0_0_DispatchTable = +{ + 0, + IFoo_table +}; + +static const RPC_SERVER_INTERFACE IFoo___RpcServerInterface = +{ + sizeof(RPC_SERVER_INTERFACE), + {{0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x34}},{0,0}}, + {{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}}, + &IFoo_v0_0_DispatchTable, + 0, + 0, + 0, + 0, + 0, +}; + +static RPC_IF_HANDLE IFoo_v0_0_s_ifspec = (RPC_IF_HANDLE)& IFoo___RpcServerInterface; + +static void test_endpoint_mapper(RPC_CSTR protseq, RPC_CSTR address) +{ + static unsigned char annotation[] = "Test annotation string."; + RPC_STATUS status; + RPC_BINDING_VECTOR *binding_vector; + handle_t handle; + unsigned char *binding; + + status = RpcServerRegisterIf(IFoo_v0_0_s_ifspec, NULL, NULL); + ok(status == RPC_S_OK, "%s: RpcServerRegisterIf failed (%u)\n", protseq, status); + + status = RpcServerInqBindings(&binding_vector); + ok(status == RPC_S_OK, "%s: RpcServerInqBindings failed with error %u\n", protseq, status); + + /* register endpoints created in test_RpcServerUseProtseq */ + status = RpcEpRegisterA(IFoo_v0_0_s_ifspec, binding_vector, NULL, annotation); + ok(status == RPC_S_OK, "%s: RpcEpRegisterA failed with error %u\n", protseq, status); + + status = RpcStringBindingCompose(NULL, protseq, address, + NULL, NULL, &binding); + ok(status == RPC_S_OK, "%s: RpcStringBindingCompose failed (%u)\n", protseq, status); + + status = RpcBindingFromStringBinding(binding, &handle); + ok(status == RPC_S_OK, "%s: RpcBindingFromStringBinding failed (%u)\n", protseq, status); + + RpcStringFree(&binding); + + status = RpcBindingReset(handle); + ok(status == RPC_S_OK, "%s: RpcBindingReset failed with error %u\n", protseq, status); + + RpcStringFree(&binding); + + status = RpcEpResolveBinding(handle, IFoo_v0_0_s_ifspec); + ok(status == RPC_S_OK || broken(status == RPC_S_SERVER_UNAVAILABLE), /* win9x */ + "%s: RpcEpResolveBinding failed with error %u\n", protseq, status); + + status = RpcBindingReset(handle); + ok(status == RPC_S_OK, "%s: RpcBindingReset failed with error %u\n", protseq, status); + + status = RpcBindingFree(&handle); + ok(status == RPC_S_OK, "%s: RpcBindingFree failed with error %u\n", protseq, status); + + status = RpcServerUnregisterIf(NULL, NULL, FALSE); + ok(status == RPC_S_OK, "%s: RpcServerUnregisterIf failed (%u)\n", protseq, status); + + status = RpcEpUnregister(IFoo_v0_0_s_ifspec, binding_vector, NULL); + ok(status == RPC_S_OK, "%s: RpcEpUnregisterA failed with error %u\n", protseq, status); + + status = RpcBindingVectorFree(&binding_vector); + ok(status == RPC_S_OK, "%s: RpcBindingVectorFree failed with error %u\n", protseq, status); +} + +START_TEST( rpc_protseq ) +{ + static unsigned char ncacn_np[] = "ncacn_np"; + static unsigned char ncalrpc[] = "ncalrpc"; + static unsigned char np_address[] = "."; + + test_RpcServerUseProtseq(); + test_endpoint_mapper(ncacn_np, np_address); + test_endpoint_mapper(ncalrpc, NULL); +} diff --git a/rostests/winetests/rpcrt4/rpcrt4.rbuild b/rostests/winetests/rpcrt4/rpcrt4.rbuild index c1044b37d9a..3f7686e46d8 100644 --- a/rostests/winetests/rpcrt4/rpcrt4.rbuild +++ b/rostests/winetests/rpcrt4/rpcrt4.rbuild @@ -4,13 +4,14 @@ server.idl - + server.idl . . - + + 0x0500 wine pseh ole32 @@ -18,14 +19,14 @@ rpcrt4_winetest_server rpcrt4_winetest_client rpcrt4 - kernel32 ntdll cstub.c generated.c ndr_marshall.c rpc.c rpc_async.c + rpc_protseq.c server.c testlist.c - \ No newline at end of file +
diff --git a/rostests/winetests/rpcrt4/server.c b/rostests/winetests/rpcrt4/server.c index eb1baacd6c5..daee30e5254 100644 --- a/rostests/winetests/rpcrt4/server.c +++ b/rostests/winetests/rpcrt4/server.c @@ -33,11 +33,14 @@ #define INT_CODE 4198 static const char *progname; +static BOOL old_windows_version; static HANDLE stop_event; static void (WINAPI *pNDRSContextMarshall2)(RPC_BINDING_HANDLE, NDR_SCONTEXT, void*, NDR_RUNDOWN, void*, ULONG); static NDR_SCONTEXT (WINAPI *pNDRSContextUnmarshall2)(RPC_BINDING_HANDLE, void*, ULONG, void*, ULONG); +static RPC_STATUS (WINAPI *pRpcServerRegisterIfEx)(RPC_IF_HANDLE,UUID*, RPC_MGR_EPV*, unsigned int, + unsigned int,RPC_IF_CALLBACK_FN*); static void InitFunctionPointers(void) { @@ -45,18 +48,21 @@ static void InitFunctionPointers(void) pNDRSContextMarshall2 = (void *)GetProcAddress(hrpcrt4, "NDRSContextMarshall2"); pNDRSContextUnmarshall2 = (void *)GetProcAddress(hrpcrt4, "NDRSContextUnmarshall2"); + pRpcServerRegisterIfEx = (void *)GetProcAddress(hrpcrt4, "RpcServerRegisterIfEx"); + + if (!pNDRSContextMarshall2) old_windows_version = TRUE; } void __RPC_FAR *__RPC_USER -midl_user_allocate(size_t n) +midl_user_allocate(SIZE_T n) { - return malloc(n); + return HeapAlloc(GetProcessHeap(), 0, n); } void __RPC_USER midl_user_free(void __RPC_FAR *p) { - free(p); + HeapFree(GetProcessHeap(), 0, p); } static char * @@ -138,8 +144,8 @@ s_square_half_float(float x, float *y) return x * x; } -long -s_square_half_long(long x, long *y) +LONG +s_square_half_long(LONG x, LONG *y) { *y = x / 2; return x * x; @@ -223,6 +229,23 @@ s_sum_conf_array(int x[], int n) return sum; } +int +s_sum_conf_ptr_by_conf_ptr(int n1, int *n2_then_x1, int *x2) +{ + int i; + int sum = 0; + if(n1 == 0) + return 0; + + for(i = 1; i < n1; ++i) + sum += n2_then_x1[i]; + + for(i = 0; i < *n2_then_x1; ++i) + sum += x2[i]; + + return sum; +} + int s_sum_unique_conf_array(int x[], int n) { @@ -333,12 +356,30 @@ s_square_encu(encu_t *eu) } } +double +s_square_unencu(int t, unencu_t *eu) +{ + switch (t) + { + case ENCU_I: return eu->i * eu->i; + case ENCU_F: return eu->f * eu->f; + default: + return 0.0; + } +} + void s_check_se2(se_t *s) { ok(s->f == E2, "check_se2\n"); } +int +s_sum_parr(int *a[3]) +{ + return s_sum_pcarr(a, 3); +} + int s_sum_pcarr(int *a[], int n) { @@ -348,12 +389,6 @@ s_sum_pcarr(int *a[], int n) return s; } -int -s_sum_parr(int *a[3]) -{ - return s_sum_pcarr(a, 3); -} - int s_enum_ord(e_t e) { @@ -559,6 +594,12 @@ s_context_handle_test(void) binding = I_RpcGetCurrentCallHandle(); ok(binding != NULL, "I_RpcGetCurrentCallHandle returned NULL\n"); + if (!pNDRSContextMarshall2 || !pNDRSContextUnmarshall2) + { + win_skip("NDRSContextMarshall2 or NDRSContextUnmarshall2 not exported from rpcrt4.dll\n"); + return; + } + h = pNDRSContextUnmarshall2(binding, NULL, NDR_LOCAL_DATA_REPRESENTATION, NULL, 0); ok(h != NULL, "NDRSContextUnmarshall2 returned NULL\n"); @@ -578,6 +619,9 @@ s_context_handle_test(void) ok(*(ULONG *)buf == 0, "attributes should have been set to 0 instead of 0x%x\n", *(ULONG *)buf); ok(!UuidIsNil((UUID *)&buf[4], &status), "uuid should not have been nil\n"); + /* raises ERROR_INVALID_HANDLE exception on Vista upwards */ + if (0) + { h = pNDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, NULL, 0); ok(h != NULL, "NDRSContextUnmarshall2 returned NULL\n"); ok(h->userContext == (void *)0xdeadbeef, "userContext of interface didn't unmarshal properly: %p\n", h->userContext); @@ -595,6 +639,7 @@ s_context_handle_test(void) h = pNDRSContextUnmarshall2(binding, buf, NDR_LOCAL_DATA_REPRESENTATION, &server_if.InterfaceId, 0); ok(h != NULL, "NDRSContextUnmarshall2 returned NULL\n"); ok(h->userContext == (void *)0xcafebabe, "userContext of interface didn't unmarshal properly: %p\n", h->userContext); + } /* test same interface data, but different pointer */ /* raises ERROR_INVALID_HANDLE exception */ @@ -627,19 +672,6 @@ s_context_handle_test(void) } } -void -s_get_5numbers(int count, pints_t n[5]) -{ - int i; - for (i = 0; i < count; i++) - { - n[i].pi = midl_user_allocate(sizeof(*n[i].pi)); - *n[i].pi = i; - n[i].ppi = NULL; - n[i].pppi = NULL; - } -} - void s_get_numbers(int length, int size, pints_t n[]) { @@ -653,6 +685,24 @@ s_get_numbers(int length, int size, pints_t n[]) } } +void +s_get_numbers_struct(numbers_struct_t **ns) +{ + int i; + *ns = midl_user_allocate(FIELD_OFFSET(numbers_struct_t, numbers[5])); + if (!*ns) return; + (*ns)->length = 5; + (*ns)->size = 5; + for (i = 0; i < (*ns)->length; i++) + { + (*ns)->numbers[i].pi = NULL; + (*ns)->numbers[i].ppi = NULL; + (*ns)->numbers[i].pppi = NULL; + } + (*ns)->numbers[0].pi = midl_user_allocate(sizeof(*(*ns)->numbers[i].pi)); + *(*ns)->numbers[0].pi = 5; +} + void s_stop(void) { @@ -704,7 +754,7 @@ basic_tests(void) int i1, i2, i3, *pi2, *pi3, **ppi3; double u, v; float s, t; - long q, r; + LONG q, r; short h; char c; int x; @@ -826,6 +876,7 @@ union_tests(void) { encue_t eue; encu_t eu; + unencu_t uneu; sun_t su; int i; @@ -854,6 +905,12 @@ union_tests(void) eu.tagged_union.f = 3.0; ok(square_encu(&eu) == 9.0, "RPC square_encu\n"); + uneu.i = 4; + ok(square_unencu(ENCU_I, &uneu) == 16.0, "RPC square_unencu\n"); + + uneu.f = 5.0; + ok(square_unencu(ENCU_F, &uneu) == 25.0, "RPC square_unencu\n"); + eue.t = E1; eue.tagged_union.i1 = 8; ok(square_encue(&eue) == 64.0, "RPC square_encue\n"); @@ -953,27 +1010,27 @@ us_t_UserFree(ULONG *flags, us_t *pus) ULONG __RPC_USER bstr_t_UserSize(ULONG *flags, ULONG start, bstr_t *b) { - return start + FIELD_OFFSET(wire_bstr_t, data[(*b)[-1]]); + return start + FIELD_OFFSET(user_bstr_t, data[(*b)[-1]]); } unsigned char * __RPC_USER bstr_t_UserMarshal(ULONG *flags, unsigned char *buffer, bstr_t *b) { - wire_bstr_t *wb = (wire_bstr_t *) buffer; + wire_bstr_t wb = (wire_bstr_t) buffer; wb->n = (*b)[-1]; memcpy(&wb->data, *b, wb->n * sizeof wb->data[0]); - return buffer + FIELD_OFFSET(wire_bstr_t, data[wb->n]); + return buffer + FIELD_OFFSET(user_bstr_t, data[wb->n]); } unsigned char * __RPC_USER bstr_t_UserUnmarshal(ULONG *flags, unsigned char *buffer, bstr_t *b) { - wire_bstr_t *wb = (wire_bstr_t *) buffer; + wire_bstr_t wb = (wire_bstr_t) buffer; short *data = HeapAlloc(GetProcessHeap(), 0, (wb->n + 1) * sizeof *data); data[0] = wb->n; memcpy(&data[1], wb->data, wb->n * sizeof data[1]); *b = &data[1]; - return buffer + FIELD_OFFSET(wire_bstr_t, data[wb->n]); + return buffer + FIELD_OFFSET(user_bstr_t, data[wb->n]); } void __RPC_USER @@ -1042,12 +1099,15 @@ pointer_tests(void) free_list(list); + if (!old_windows_version) + { name.size = 10; name.name = buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, name.size); get_name(&name); ok(name.name == buffer, "[in,out] pointer should have stayed as %p but instead changed to %p\n", name.name, buffer); ok(!strcmp(name.name, "Jeremy Wh"), "name didn't unmarshall properly, expected \"Jeremy Wh\", but got \"%s\"\n", name.name); HeapFree(GetProcessHeap(), 0, name.name); + } pa2 = a; ok(sum_pcarr2(4, &pa2) == 10, "RPC sum_pcarr2\n"); @@ -1080,13 +1140,13 @@ free_pyramid_doub_carr(doub_carr_t *dc) static void array_tests(void) { - const char str1[25] = "Hello"; int m[2][3][4] = { {{1, 2, 3, 4}, {-1, -3, -5, -7}, {0, 2, 4, 6}}, {{1, -2, 3, -4}, {2, 3, 5, 7}, {-4, -1, -14, 4114}} }; int c[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + int c2[] = {10, 100, 200}; vector_t vs[2] = {{1, -2, 3}, {4, -5, -6}}; cps_t cps; cpsc_t cpsc; @@ -1096,8 +1156,13 @@ array_tests(void) doub_carr_t *dc; int *pi; pints_t api[5]; + numbers_struct_t *ns; + if (!old_windows_version) + { + const char str1[25] = "Hello"; ok(cstr_length(str1, sizeof str1) == strlen(str1), "RPC cstr_length\n"); + } ok(sum_fixed_int_3d(m) == 4116, "RPC sum_fixed_int_3d\n"); @@ -1106,6 +1171,11 @@ array_tests(void) ok(sum_conf_array(&c[7], 1) == 7, "RPC sum_conf_array\n"); ok(sum_conf_array(&c[2], 0) == 0, "RPC sum_conf_array\n"); + ok(sum_conf_ptr_by_conf_ptr(1, c2, c) == 45, "RPC sum_conf_ptr_by_conf_ptr\n"); + ok(sum_conf_ptr_by_conf_ptr(3, c2, c) == 345, "RPC sum_conf_ptr_by_conf_ptr\n"); + c2[0] = 0; + ok(sum_conf_ptr_by_conf_ptr(3, c2, c) == 300, "RPC sum_conf_ptr_by_conf_ptr\n"); + ok(sum_unique_conf_array(ca, 4) == -2, "RPC sum_unique_conf_array\n"); ok(sum_unique_conf_ptr(ca, 5) == 3, "RPC sum_unique_conf_array\n"); ok(sum_unique_conf_ptr(NULL, 10) == 0, "RPC sum_unique_conf_array\n"); @@ -1148,21 +1218,21 @@ array_tests(void) ok(sum_toplev_conf_cond(c, 5, 6, 1) == 10, "RPC sum_toplev_conf_cond\n"); ok(sum_toplev_conf_cond(c, 5, 6, 0) == 15, "RPC sum_toplev_conf_cond\n"); - dc = malloc(FIELD_OFFSET(doub_carr_t, a[2])); + dc = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(doub_carr_t, a[2])); dc->n = 2; - dc->a[0] = malloc(FIELD_OFFSET(doub_carr_1_t, a[3])); + dc->a[0] = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(doub_carr_1_t, a[3])); dc->a[0]->n = 3; dc->a[0]->a[0] = 5; dc->a[0]->a[1] = 1; dc->a[0]->a[2] = 8; - dc->a[1] = malloc(FIELD_OFFSET(doub_carr_1_t, a[2])); + dc->a[1] = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(doub_carr_1_t, a[2])); dc->a[1]->n = 2; dc->a[1]->a[0] = 2; dc->a[1]->a[1] = 3; ok(sum_doub_carr(dc) == 19, "RPC sum_doub_carr\n"); - free(dc->a[0]); - free(dc->a[1]); - free(dc); + HeapFree(GetProcessHeap(), 0, dc->a[0]); + HeapFree(GetProcessHeap(), 0, dc->a[1]); + HeapFree(GetProcessHeap(), 0, dc); dc = NULL; make_pyramid_doub_carr(4, &dc); @@ -1174,15 +1244,22 @@ array_tests(void) memset(api, 0, sizeof(api)); pi = HeapAlloc(GetProcessHeap(), 0, sizeof(*pi)); *pi = -1; - api[0].pi = pi; - get_5numbers(1, api); - ok(api[0].pi == pi, "RPC varying array [out] pointer changed from %p to %p\n", pi, api[0].pi); - ok(*api[0].pi == 0, "pi unmarshalled incorrectly %d\n", *pi); - api[0].pi = pi; get_numbers(1, 1, api); ok(api[0].pi == pi, "RPC conformant varying array [out] pointer changed from %p to %p\n", pi, api[0].pi); - ok(*api[0].pi == 0, "pi unmarshalled incorrectly %d\n", *pi); + ok(*api[0].pi == 0, "pi unmarshalled incorrectly %d\n", *api[0].pi); + + if (!old_windows_version) + { + ns = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(numbers_struct_t, numbers[5])); + ns->length = 5; + ns->size = 5; + ns->numbers[0].pi = pi; + get_numbers_struct(&ns); + ok(ns->numbers[0].pi == pi, "RPC conformant varying struct embedded pointer changed from %p to %p\n", pi, ns->numbers[0].pi); + ok(*ns->numbers[0].pi == 5, "pi unmarshalled incorrectly %d\n", *ns->numbers[0].pi); + HeapFree(GetProcessHeap(), 0, ns); + } HeapFree(GetProcessHeap(), 0, pi); } @@ -1240,16 +1317,28 @@ server(void) static unsigned char np[] = "ncacn_np"; static unsigned char pipe[] = PIPE; RPC_STATUS status, iptcp_status, np_status; + DWORD ret; iptcp_status = RpcServerUseProtseqEp(iptcp, 20, port, NULL); - ok(iptcp_status == RPC_S_OK, "RpcServerUseProtseqEp(ncacn_ip_tcp) failed with status %ld\n", iptcp_status); + ok(iptcp_status == RPC_S_OK, "RpcServerUseProtseqEp(ncacn_ip_tcp) failed with status %d\n", iptcp_status); np_status = RpcServerUseProtseqEp(np, 0, pipe, NULL); - ok(np_status == RPC_S_OK, "RpcServerUseProtseqEp(ncacn_np) failed with status %ld\n", np_status); + if (np_status == RPC_S_PROTSEQ_NOT_SUPPORTED) + skip("Protocol sequence ncacn_np is not supported\n"); + else + ok(np_status == RPC_S_OK, "RpcServerUseProtseqEp(ncacn_np) failed with status %d\n", np_status); - //status = RpcServerRegisterIf(s_IServer_v0_0_s_ifspec, NULL, NULL); - //ok(status == RPC_S_OK, "RpcServerRegisterIf failed with status %ld\n", status); + if (pRpcServerRegisterIfEx) + { + trace("Using RpcServerRegisterIfEx\n"); + status = pRpcServerRegisterIfEx(IServer_v0_0_s_ifspec, NULL, NULL, + RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH, + RPC_C_LISTEN_MAX_CALLS_DEFAULT, NULL); + } + else + status = RpcServerRegisterIf(IServer_v0_0_s_ifspec, NULL, NULL); + ok(status == RPC_S_OK, "RpcServerRegisterIf failed with status %d\n", status); status = RpcServerListen(1, 20, TRUE); - ok(status == RPC_S_OK, "RpcServerListen failed with status %ld\n", status); + ok(status == RPC_S_OK, "RpcServerListen failed with status %d\n", status); stop_event = CreateEvent(NULL, FALSE, FALSE, NULL); ok(stop_event != NULL, "CreateEvent failed with error %d\n", GetLastError()); @@ -1267,12 +1356,18 @@ server(void) return; } - ok(WAIT_OBJECT_0 == WaitForSingleObject(stop_event, 60000), "WaitForSingleObject\n"); + ret = WaitForSingleObject(stop_event, 1000); + ok(WAIT_OBJECT_0 == ret, "WaitForSingleObject\n"); + /* if the stop event didn't fire then RpcMgmtWaitServerListen will wait + * forever, so don't bother calling it in this case */ + if (ret == WAIT_OBJECT_0) + { status = RpcMgmtWaitServerListen(); todo_wine { - ok(status == RPC_S_OK, "RpcMgmtWaitServerListening failed with status %ld\n", status); + ok(status == RPC_S_OK, "RpcMgmtWaitServerListening failed with status %d\n", status); } } +} START_TEST(server) { diff --git a/rostests/winetests/rpcrt4/server.idl b/rostests/winetests/rpcrt4/server.idl index 33e3a480a1c..788516189b4 100644 --- a/rostests/winetests/rpcrt4/server.idl +++ b/rostests/winetests/rpcrt4/server.idl @@ -121,6 +121,7 @@ cpp_quote("#endif") int test_list_length(test_list_t *ls); int sum_fixed_int_3d(int m[2][3][4]); int sum_conf_array([size_is(n)] int x[], int n); + int sum_conf_ptr_by_conf_ptr(int n1, [size_is(n1)] int *n2_then_x1, [size_is(*n2_then_x1)] int *x2); int sum_unique_conf_array([size_is(n), unique] int x[], int n); int sum_unique_conf_ptr([size_is(n), unique] int *x, int n); int sum_var_array([length_is(n)] int x[20], int n); @@ -195,6 +196,12 @@ cpp_quote("#endif") case ENCU_F: float f; } encu_t; + typedef [switch_type(int)] union unencu + { + [case (ENCU_I)] int i; + [case (ENCU_F)] float f; + } unencu_t; + typedef enum { E1 = 23, @@ -215,6 +222,7 @@ cpp_quote("#endif") } se_t; double square_encu(encu_t *eu); + double square_unencu(int t, [switch_is(t)] unencu_t *eu); int sum_parr(int *a[3]); int sum_pcarr([size_is(n)] int *a[], int n); int enum_ord(e_t e); @@ -292,8 +300,9 @@ cpp_quote("#endif") { short n; [size_is(n)] short data[]; - } wire_bstr_t; + } user_bstr_t; + typedef [unique] user_bstr_t *wire_bstr_t; typedef [wire_marshal(wire_bstr_t)] short *bstr_t; unsigned hash_bstr(bstr_t s); @@ -319,8 +328,16 @@ cpp_quote("#endif") type as a return value. */ s123_t *get_s123(void); - void get_5numbers([in] int count, [out, length_is(count)] pints_t pn[5]); + typedef struct + { + unsigned int length; + unsigned int size; + [size_is(size), length_is(length)] pints_t numbers[]; + } numbers_struct_t; + void get_numbers([in] int length, [in] int size, [out, length_is(length), size_is(size)] pints_t pn[]); + void get_numbers_struct([out] numbers_struct_t **ns); + str_t get_filename(void); void context_handle_test(void); void stop(void); diff --git a/rostests/winetests/rpcrt4/warningfix.diff b/rostests/winetests/rpcrt4/warningfix.diff new file mode 100644 index 00000000000..ba36e4bbbeb --- /dev/null +++ b/rostests/winetests/rpcrt4/warningfix.diff @@ -0,0 +1,30 @@ +Index: server.c +=================================================================== +--- server.c (revision 38883) ++++ server.c (working copy) +@@ -352,12 +352,6 @@ + } + + int +-s_sum_parr(int *a[3]) +-{ +- return s_sum_pcarr(a, 3); +-} +- +-int + s_sum_pcarr(int *a[], int n) + { + int i, s = 0; +@@ -367,6 +361,12 @@ + } + + int ++s_sum_parr(int *a[3]) ++{ ++ return s_sum_pcarr(a, 3); ++} ++ ++int + s_enum_ord(e_t e) + { + switch (e) diff --git a/rostests/winetests/rsabase/rsabase.rbuild b/rostests/winetests/rsabase/rsabase.rbuild index 65d4fc5ad8b..0aba4aa4238 100644 --- a/rostests/winetests/rsabase/rsabase.rbuild +++ b/rostests/winetests/rsabase/rsabase.rbuild @@ -2,11 +2,9 @@ . - 0x600 - 0x600 + wine advapi32 - kernel32 ntdll rsabase.c testlist.c diff --git a/rostests/winetests/rsaenh/rsaenh.c b/rostests/winetests/rsaenh/rsaenh.c index 479b4286d46..5a3fafd2fbc 100644 --- a/rostests/winetests/rsaenh/rsaenh.c +++ b/rostests/winetests/rsaenh/rsaenh.c @@ -72,9 +72,15 @@ static void uniquecontainer(char *unique) HKEY hkey; char guid[MAX_PATH]; DWORD size = MAX_PATH; + HRESULT ret; /* Get the MachineGUID */ + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, szCryptography, 0, KEY_READ | KEY_WOW64_64KEY, &hkey); + if (ret == ERROR_ACCESS_DENIED) + { + /* Windows 2000 can't handle KEY_WOW64_64KEY */ RegOpenKeyA(HKEY_LOCAL_MACHINE, szCryptography, &hkey); + } RegQueryValueExA(hkey, szMachineGuid, NULL, NULL, (LPBYTE)guid, &size); RegCloseKey(hkey); @@ -112,7 +118,7 @@ static void trace_hex(BYTE *pbData, DWORD dwLen) { } */ -static int init_base_environment(void) +static int init_base_environment(DWORD dwKeyFlags) { HCRYPTKEY hKey; BOOL result; @@ -132,10 +138,10 @@ static int init_base_environment(void) CRYPT_NEWKEYSET); ok(result, "%08x\n", GetLastError()); if (!result) return 0; - result = CryptGenKey(hProv, AT_KEYEXCHANGE, 0, &hKey); + result = CryptGenKey(hProv, AT_KEYEXCHANGE, dwKeyFlags, &hKey); ok(result, "%08x\n", GetLastError()); if (result) CryptDestroyKey(hKey); - result = CryptGenKey(hProv, AT_SIGNATURE, 0, &hKey); + result = CryptGenKey(hProv, AT_SIGNATURE, dwKeyFlags, &hKey); ok(result, "%08x\n", GetLastError()); if (result) CryptDestroyKey(hKey); } @@ -146,9 +152,16 @@ static void clean_up_base_environment(void) { BOOL result; + SetLastError(0xdeadbeef); result = CryptReleaseContext(hProv, 1); - ok(!result && GetLastError()==NTE_BAD_FLAGS, "%08x\n", GetLastError()); + ok(!result || broken(result) /* Win98 */, "Expected failure\n"); + ok(GetLastError()==NTE_BAD_FLAGS, "Expected NTE_BAD_FLAGS, got %08x\n", GetLastError()); + /* Just to prove that Win98 also released the CSP */ + SetLastError(0xdeadbeef); + result = CryptReleaseContext(hProv, 0); + ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "%08x\n", GetLastError()); + CryptAcquireContext(&hProv, szContainer, szProvider, PROV_RSA_FULL, CRYPT_DELETEKEYSET); } @@ -167,6 +180,11 @@ static int init_aes_environment(void) * This provider is available on Windows XP, Windows 2003 and Vista. */ result = CryptAcquireContext(&hProv, szContainer, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); + if (!result && GetLastError() == NTE_PROV_TYPE_NOT_DEF) + { + win_skip("RSA_AES provider not supported\n"); + return 0; + } ok(!result && GetLastError()==NTE_BAD_FLAGS, "%d, %08x\n", result, GetLastError()); if (!CryptAcquireContext(&hProv, szContainer, NULL, PROV_RSA_AES, 0)) @@ -248,7 +266,7 @@ static BOOL derive_key(ALG_ID aiAlgid, HCRYPTKEY *phKey, DWORD len) unsigned char pbData[2000]; int i; - *phKey = (HCRYPTKEY)NULL; + *phKey = 0; for (i=0; i<2000; i++) pbData[i] = (unsigned char)i; result = CryptCreateHash(hProv, CALG_MD2, 0, 0, &hHash); if (!result) { @@ -258,7 +276,7 @@ static BOOL derive_key(ALG_ID aiAlgid, HCRYPTKEY *phKey, DWORD len) } ok(result, "%08x\n", GetLastError()); if (!result) return FALSE; - result = CryptHashData(hHash, (BYTE*)pbData, sizeof(pbData), 0); + result = CryptHashData(hHash, pbData, sizeof(pbData), 0); ok(result, "%08x\n", GetLastError()); if (!result) return FALSE; result = CryptDeriveKey(hProv, aiAlgid, hHash, (len << 16) | CRYPT_EXPORTABLE, phKey); @@ -303,7 +321,7 @@ static void test_hashes(void) /* rsaenh compiled without OpenSSL */ ok(GetLastError() == NTE_BAD_ALGID, "%08x\n", GetLastError()); } else { - result = CryptHashData(hHash, (BYTE*)pbData, sizeof(pbData), 0); + result = CryptHashData(hHash, pbData, sizeof(pbData), 0); ok(result, "%08x\n", GetLastError()); len = sizeof(DWORD); @@ -324,7 +342,7 @@ static void test_hashes(void) result = CryptCreateHash(hProv, CALG_MD4, 0, 0, &hHash); ok(result, "%08x\n", GetLastError()); - result = CryptHashData(hHash, (BYTE*)pbData, sizeof(pbData), 0); + result = CryptHashData(hHash, pbData, sizeof(pbData), 0); ok(result, "%08x\n", GetLastError()); len = sizeof(DWORD); @@ -348,7 +366,7 @@ static void test_hashes(void) result = CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashlen, &len, 0); ok(result && (hashlen == 16), "%08x, hashlen: %d\n", GetLastError(), hashlen); - result = CryptHashData(hHash, (BYTE*)pbData, sizeof(pbData), 0); + result = CryptHashData(hHash, pbData, sizeof(pbData), 0); ok(result, "%08x\n", GetLastError()); len = 16; @@ -378,8 +396,11 @@ static void test_hashes(void) /* Can't add data after the hash been retrieved */ SetLastError(0xdeadbeef); - result = CryptHashData(hHash, (BYTE*)pbData, sizeof(pbData), 0); - ok(!result && GetLastError() == NTE_BAD_HASH_STATE, "%08x\n", GetLastError()); + result = CryptHashData(hHash, pbData, sizeof(pbData), 0); + ok(!result, "Expected failure\n"); + ok(GetLastError() == NTE_BAD_HASH_STATE || + GetLastError() == NTE_BAD_ALGID, /* Win9x, WinMe, NT4 */ + "Expected NTE_BAD_HASH_STATE or NTE_BAD_ALGID, got %08x\n", GetLastError()); /* You can still retrieve the hash, its value just hasn't changed */ result = CryptGetHashParam(hHash, HP_HASHVAL, pbHashValue, &len, 0); @@ -394,7 +415,7 @@ static void test_hashes(void) result = CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash); ok(result, "%08x\n", GetLastError()); - result = CryptHashData(hHash, (BYTE*)pbData, 5, 0); + result = CryptHashData(hHash, pbData, 5, 0); ok(result, "%08x\n", GetLastError()); if(pCryptDuplicateHash) { @@ -444,24 +465,24 @@ static void test_block_cipher_modes(void) result = derive_key(CALG_RC2, &hKey, 40); if (!result) return; - memcpy(abData, plain, sizeof(abData)); + memcpy(abData, plain, sizeof(plain)); dwMode = CRYPT_MODE_ECB; result = CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&dwMode, 0); ok(result, "%08x\n", GetLastError()); dwLen = 23; - result = CryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, NULL, &dwLen, 24); + result = CryptEncrypt(hKey, 0, TRUE, 0, NULL, &dwLen, 24); ok(result, "CryptEncrypt failed: %08x\n", GetLastError()); ok(dwLen == 24, "Unexpected length %d\n", dwLen); SetLastError(ERROR_SUCCESS); dwLen = 23; - result = CryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, abData, &dwLen, 24); + result = CryptEncrypt(hKey, 0, TRUE, 0, abData, &dwLen, 24); ok(result && dwLen == 24 && !memcmp(ecb, abData, sizeof(ecb)), "%08x, dwLen: %d\n", GetLastError(), dwLen); - result = CryptDecrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, abData, &dwLen); + result = CryptDecrypt(hKey, 0, TRUE, 0, abData, &dwLen); ok(result && dwLen == 23 && !memcmp(plain, abData, sizeof(plain)), "%08x, dwLen: %d\n", GetLastError(), dwLen); @@ -470,16 +491,16 @@ static void test_block_cipher_modes(void) ok(result, "%08x\n", GetLastError()); dwLen = 23; - result = CryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, NULL, &dwLen, 24); + result = CryptEncrypt(hKey, 0, TRUE, 0, NULL, &dwLen, 24); ok(result, "CryptEncrypt failed: %08x\n", GetLastError()); ok(dwLen == 24, "Unexpected length %d\n", dwLen); dwLen = 23; - result = CryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, abData, &dwLen, 24); + result = CryptEncrypt(hKey, 0, TRUE, 0, abData, &dwLen, 24); ok(result && dwLen == 24 && !memcmp(cbc, abData, sizeof(cbc)), "%08x, dwLen: %d\n", GetLastError(), dwLen); - result = CryptDecrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, abData, &dwLen); + result = CryptDecrypt(hKey, 0, TRUE, 0, abData, &dwLen); ok(result && dwLen == 23 && !memcmp(plain, abData, sizeof(plain)), "%08x, dwLen: %d\n", GetLastError(), dwLen); @@ -488,20 +509,20 @@ static void test_block_cipher_modes(void) ok(result, "%08x\n", GetLastError()); dwLen = 16; - result = CryptEncrypt(hKey, (HCRYPTHASH)NULL, FALSE, 0, abData, &dwLen, 24); + result = CryptEncrypt(hKey, 0, FALSE, 0, abData, &dwLen, 24); ok(result && dwLen == 16, "%08x, dwLen: %d\n", GetLastError(), dwLen); dwLen = 7; - result = CryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, abData+16, &dwLen, 8); + result = CryptEncrypt(hKey, 0, TRUE, 0, abData+16, &dwLen, 8); ok(result && dwLen == 8 && !memcmp(cfb, abData, sizeof(cfb)), "%08x, dwLen: %d\n", GetLastError(), dwLen); dwLen = 8; - result = CryptDecrypt(hKey, (HCRYPTHASH)NULL, FALSE, 0, abData, &dwLen); + result = CryptDecrypt(hKey, 0, FALSE, 0, abData, &dwLen); ok(result && dwLen == 8, "%08x, dwLen: %d\n", GetLastError(), dwLen); dwLen = 16; - result = CryptDecrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, abData+8, &dwLen); + result = CryptDecrypt(hKey, 0, TRUE, 0, abData+8, &dwLen); ok(result && dwLen == 15 && !memcmp(plain, abData, sizeof(plain)), "%08x, dwLen: %d\n", GetLastError(), dwLen); @@ -510,7 +531,7 @@ static void test_block_cipher_modes(void) ok(result, "%08x\n", GetLastError()); dwLen = 23; - result = CryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, abData, &dwLen, 24); + result = CryptEncrypt(hKey, 0, TRUE, 0, abData, &dwLen, 24); ok(!result && GetLastError() == NTE_BAD_ALGID, "%08x\n", GetLastError()); CryptDestroyKey(hKey); @@ -534,10 +555,10 @@ static void test_3des112(void) for (i=0; i . - 0x600 - 0x600 + rsaenh.c testlist.c wine advapi32 - kernel32 ntdll
diff --git a/rostests/winetests/schannel/main.c b/rostests/winetests/schannel/main.c index 814b60a696c..d05275fd37d 100644 --- a/rostests/winetests/schannel/main.c +++ b/rostests/winetests/schannel/main.c @@ -57,20 +57,26 @@ static void testInitialize(void) /* SpLsaModeInitialize does not care about the LSA version. */ status = pSpLsaModeInitialize(0, &Version, &pTables2, &cTables); ok(status == STATUS_SUCCESS, "status: 0x%x\n", status); - ok(cTables == 2, "cTables: %d\n", cTables); + ok(cTables == 2 || + broken(cTables == 1), /* Win2k */ + "cTables: %d\n", cTables); ok(pTables2 != NULL,"pTables: %p\n", pTables2); /* We can call it as many times we want. */ status = pSpLsaModeInitialize(0x10000, &Version, &pTables, &cTables); ok(status == STATUS_SUCCESS, "status: 0x%x\n", status); - ok(cTables == 2, "cTables: %d\n", cTables); + ok(cTables == 2 || + broken(cTables == 1), /* Win2k */ + "cTables: %d\n", cTables); ok(pTables != NULL, "pTables: %p\n", pTables); /* It will always return the same pointer. */ ok(pTables == pTables2, "pTables: %p, pTables2: %p\n", pTables, pTables2); status = pSpLsaModeInitialize(0x23456, &Version, &pTables, &cTables); ok(status == STATUS_SUCCESS, "status: 0x%x\n", status); - ok(cTables == 2, "cTables: %d\n", cTables); + ok(cTables == 2 || + broken(cTables == 1), /* Win2k */ + "cTables: %d\n", cTables); ok(pTables != NULL, "pTables: %p\n", pTables); ok(pTables == pTables2, "pTables: %p, pTables2: %p\n", pTables, pTables2); @@ -96,7 +102,9 @@ static void testInitialize(void) &pUserTables, &cUserTables); ok(status == STATUS_SUCCESS, "status: 0x%x\n", status); ok(Version == SECPKG_INTERFACE_VERSION, "Version: 0x%x\n", Version); - ok(cUserTables == 2, "cUserTables: %d\n", cUserTables); + ok(cUserTables == 2 || + broken(cUserTables == 4), /* Win2k */ + "cUserTables: %d\n", cUserTables); ok(pUserTables != NULL, "pUserTables: %p\n", pUserTables); /* Initializing user again */ @@ -144,14 +152,21 @@ static void testGetInfo(void) /* First package: Unified */ status = pTables->GetInfo(&PackageInfo); ok(status == STATUS_SUCCESS, "status: 0x%x\n", status); - ok(PackageInfo.fCapabilities == 0x107b3, "fCapabilities: 0x%lx\n", + ok(PackageInfo.fCapabilities == 0x107b3, "fCapabilities: 0x%x\n", PackageInfo.fCapabilities); ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion); ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID); - ok(PackageInfo.cbMaxToken == 0x4000, "cbMaxToken: 0x%lx\n", + ok(PackageInfo.cbMaxToken == 0x4000 || + PackageInfo.cbMaxToken == 0x6000, /* Vista */ + "cbMaxToken: 0x%x\n", PackageInfo.cbMaxToken); - /* Second package: SChannel */ + /* Second package */ + if (cTables == 1) + { + win_skip("Second package missing\n"); + return; + } pTables = getNextSecPkgTable(pTables, Version); if (!pTables) return; @@ -162,11 +177,11 @@ static void testGetInfo(void) if (status == STATUS_SUCCESS) { - ok(PackageInfo.fCapabilities == 0x107b3, "fCapabilities: 0x%lx\n", + ok(PackageInfo.fCapabilities == 0x107b3, "fCapabilities: 0x%x\n", PackageInfo.fCapabilities); ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion); ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID); - ok(PackageInfo.cbMaxToken == 0x4000, "cbMaxToken: 0x%lx\n", + ok(PackageInfo.cbMaxToken == 0x4000, "cbMaxToken: 0x%x\n", PackageInfo.cbMaxToken); } } @@ -175,7 +190,7 @@ START_TEST(main) { HMODULE hMod = LoadLibraryA("schannel.dll"); if (!hMod) { - skip("schannel.dll not found.\n"); + win_skip("schannel.dll not available\n"); return; } @@ -187,7 +202,7 @@ START_TEST(main) testInitialize(); testGetInfo(); } - else skip( "schannel functions not found\n" ); + else win_skip( "schannel functions not found\n" ); FreeLibrary(hMod); } diff --git a/rostests/winetests/schannel/schannel.rbuild b/rostests/winetests/schannel/schannel.rbuild index 500c97bcd15..22fb80863ed 100644 --- a/rostests/winetests/schannel/schannel.rbuild +++ b/rostests/winetests/schannel/schannel.rbuild @@ -3,10 +3,8 @@ . - 0x600 - 0x600 + wine - kernel32 ntdll main.c testlist.c diff --git a/rostests/winetests/secur32/main.c b/rostests/winetests/secur32/main.c new file mode 100644 index 00000000000..e652485859b --- /dev/null +++ b/rostests/winetests/secur32/main.c @@ -0,0 +1,258 @@ +/* + * Miscellaneous secur32 tests + * + * Copyright 2005, 2006 Kai Blin + * + * 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 + */ + +#define SECURITY_WIN32 + +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static HMODULE secdll; +static PSecurityFunctionTableA (SEC_ENTRY * pInitSecurityInterfaceA)(void); +static SECURITY_STATUS (SEC_ENTRY * pEnumerateSecurityPackagesA)(PULONG, PSecPkgInfoA*); +static SECURITY_STATUS (SEC_ENTRY * pFreeContextBuffer)(PVOID pv); +static SECURITY_STATUS (SEC_ENTRY * pQuerySecurityPackageInfoA)(SEC_CHAR*, PSecPkgInfoA*); +static SECURITY_STATUS (SEC_ENTRY * pAcquireCredentialsHandleA)(SEC_CHAR*, SEC_CHAR*, + ULONG, PLUID, PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp); +static SECURITY_STATUS (SEC_ENTRY * pInitializeSecurityContextA)(PCredHandle, PCtxtHandle, + SEC_CHAR*, ULONG, ULONG, ULONG, PSecBufferDesc, ULONG, + PCtxtHandle, PSecBufferDesc, PULONG, PTimeStamp); +static SECURITY_STATUS (SEC_ENTRY * pCompleteAuthToken)(PCtxtHandle, PSecBufferDesc); +static SECURITY_STATUS (SEC_ENTRY * pAcceptSecurityContext)(PCredHandle, PCtxtHandle, + PSecBufferDesc, ULONG, ULONG, PCtxtHandle, PSecBufferDesc, + PULONG, PTimeStamp); +static SECURITY_STATUS (SEC_ENTRY * pFreeCredentialsHandle)(PCredHandle); +static SECURITY_STATUS (SEC_ENTRY * pDeleteSecurityContext)(PCtxtHandle); +static SECURITY_STATUS (SEC_ENTRY * pQueryContextAttributesA)(PCtxtHandle, ULONG, PVOID); + +static void InitFunctionPtrs(void) +{ + secdll = LoadLibraryA("secur32.dll"); + if(!secdll) + secdll = LoadLibraryA("security.dll"); + if(secdll) + { + pInitSecurityInterfaceA = (PVOID)GetProcAddress(secdll, "InitSecurityInterfaceA"); + pEnumerateSecurityPackagesA = (PVOID)GetProcAddress(secdll, "EnumerateSecurityPackagesA"); + pFreeContextBuffer = (PVOID)GetProcAddress(secdll, "FreeContextBuffer"); + pQuerySecurityPackageInfoA = (PVOID)GetProcAddress(secdll, "QuerySecurityPackageInfoA"); + pAcquireCredentialsHandleA = (PVOID)GetProcAddress(secdll, "AcquireCredentialsHandleA"); + pInitializeSecurityContextA = (PVOID)GetProcAddress(secdll, "InitializeSecurityContextA"); + pCompleteAuthToken = (PVOID)GetProcAddress(secdll, "CompleteAuthToken"); + pAcceptSecurityContext = (PVOID)GetProcAddress(secdll, "AcceptSecurityContext"); + pFreeCredentialsHandle = (PVOID)GetProcAddress(secdll, "FreeCredentialsHandle"); + pDeleteSecurityContext = (PVOID)GetProcAddress(secdll, "DeleteSecurityContext"); + pQueryContextAttributesA = (PVOID)GetProcAddress(secdll, "QueryContextAttributesA"); + } +} + +/*---------------------------------------------------------*/ +/* General helper functions */ + +static const char* getSecError(SECURITY_STATUS status) +{ + static char buf[20]; + +#define _SEC_ERR(x) case (x): return #x; + switch(status) + { + _SEC_ERR(SEC_E_OK); + _SEC_ERR(SEC_E_INSUFFICIENT_MEMORY); + _SEC_ERR(SEC_E_INVALID_HANDLE); + _SEC_ERR(SEC_E_UNSUPPORTED_FUNCTION); + _SEC_ERR(SEC_E_TARGET_UNKNOWN); + _SEC_ERR(SEC_E_INTERNAL_ERROR); + _SEC_ERR(SEC_E_SECPKG_NOT_FOUND); + _SEC_ERR(SEC_E_NOT_OWNER); + _SEC_ERR(SEC_E_CANNOT_INSTALL); + _SEC_ERR(SEC_E_INVALID_TOKEN); + _SEC_ERR(SEC_E_CANNOT_PACK); + _SEC_ERR(SEC_E_QOP_NOT_SUPPORTED); + _SEC_ERR(SEC_E_NO_IMPERSONATION); + _SEC_ERR(SEC_I_CONTINUE_NEEDED); + _SEC_ERR(SEC_E_BUFFER_TOO_SMALL); + _SEC_ERR(SEC_E_ILLEGAL_MESSAGE); + _SEC_ERR(SEC_E_LOGON_DENIED); + _SEC_ERR(SEC_E_NO_CREDENTIALS); + _SEC_ERR(SEC_E_OUT_OF_SEQUENCE); + default: + sprintf(buf, "%08x\n", status); + return buf; + } +#undef _SEC_ERR +} + +/*---------------------------------------------------------*/ +/* Helper for testQuerySecurityPagageInfo */ + +static SECURITY_STATUS setupPackageA(SEC_CHAR *p_package_name, + PSecPkgInfo *p_pkg_info) +{ + SECURITY_STATUS ret; + + ret = pQuerySecurityPackageInfoA( p_package_name, p_pkg_info); + return ret; +} + +/*--------------------------------------------------------- */ +/* The test functions */ + +static void testInitSecurityInterface(void) +{ + PSecurityFunctionTable sec_fun_table = NULL; + + sec_fun_table = pInitSecurityInterfaceA(); + ok(sec_fun_table != NULL, "InitSecurityInterface() returned NULL.\n"); + +} + +static void testEnumerateSecurityPackages(void) +{ + + SECURITY_STATUS sec_status; + ULONG num_packages, i; + PSecPkgInfo pkg_info = NULL; + + trace("Running testEnumerateSecurityPackages\n"); + + sec_status = pEnumerateSecurityPackagesA(&num_packages, &pkg_info); + + ok(sec_status == SEC_E_OK, + "EnumerateSecurityPackages() should return %d, not %08x\n", + SEC_E_OK, sec_status); + + if (num_packages == 0) + { + todo_wine + ok(num_packages > 0, "Number of sec packages should be > 0 ,but is %d\n", + num_packages); + skip("no sec packages to check\n"); + return; + } + else + ok(num_packages > 0, "Number of sec packages should be > 0 ,but is %d\n", + num_packages); + + ok(pkg_info != NULL, + "pkg_info should not be NULL after EnumerateSecurityPackages\n"); + + trace("Number of packages: %d\n", num_packages); + for(i = 0; i < num_packages; ++i){ + trace("%d: Package \"%s\"\n", i, pkg_info[i].Name); + trace("Supported flags:\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_INTEGRITY) + trace("\tSECPKG_FLAG_INTEGRITY\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_PRIVACY) + trace("\tSECPKG_FLAG_PRIVACY\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_TOKEN_ONLY) + trace("\tSECPKG_FLAG_TOKEN_ONLY\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_DATAGRAM) + trace("\tSECPKG_FLAG_DATAGRAM\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_CONNECTION) + trace("\tSECPKG_FLAG_CONNECTION\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_MULTI_REQUIRED) + trace("\tSECPKG_FLAG_MULTI_REQUIRED\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_CLIENT_ONLY) + trace("\tSECPKG_FLAG_CLIENT_ONLY\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_EXTENDED_ERROR) + trace("\tSECPKG_FLAG_EXTENDED_ERROR\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_IMPERSONATION) + trace("\tSECPKG_FLAG_IMPERSONATION\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_ACCEPT_WIN32_NAME) + trace("\tSECPKG_FLAG_ACCEPT_WIN32_NAME\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_STREAM) + trace("\tSECPKG_FLAG_STREAM\n"); + if(pkg_info[i].fCapabilities & SECPKG_FLAG_READONLY_WITH_CHECKSUM) + trace("\tSECPKG_FLAG_READONLY_WITH_CHECKSUM\n"); + trace("Comment: %s\n", pkg_info[i].Comment); + trace("\n"); + } + + pFreeContextBuffer(pkg_info); +} + + +static void testQuerySecurityPackageInfo(void) +{ + SECURITY_STATUS sec_status; + PSecPkgInfo pkg_info; + static SEC_CHAR ntlm[] = "NTLM", + winetest[] = "Winetest"; + + trace("Running testQuerySecurityPackageInfo\n"); + + /* Test with an existing package. Test should pass */ + + pkg_info = (void *)0xdeadbeef; + sec_status = setupPackageA(ntlm, &pkg_info); + + ok((sec_status == SEC_E_OK) || (sec_status == SEC_E_SECPKG_NOT_FOUND) || + broken(sec_status == SEC_E_UNSUPPORTED_FUNCTION), /* win95 */ + "Return value of QuerySecurityPackageInfo() shouldn't be %s\n", + getSecError(sec_status) ); + + if (sec_status == SEC_E_OK) + { + ok(pkg_info != (void *)0xdeadbeef, "wrong pkg_info address %p\n", pkg_info); + ok(pkg_info->wVersion == 1, "wVersion always should be 1, but is %d\n", pkg_info->wVersion); + /* there is no point in testing pkg_info->cbMaxToken since it varies + * between implementations. + */ + + sec_status = pFreeContextBuffer(pkg_info); + ok( sec_status == SEC_E_OK, + "Return value of FreeContextBuffer() shouldn't be %s\n", + getSecError(sec_status) ); + } + + /* Test with a nonexistent package, test should fail */ + + pkg_info = (void *)0xdeadbeef; + sec_status = pQuerySecurityPackageInfoA(winetest, &pkg_info); + + ok( sec_status == SEC_E_SECPKG_NOT_FOUND, + "Return value of QuerySecurityPackageInfo() should be %s for a nonexistent package\n", + getSecError(SEC_E_SECPKG_NOT_FOUND)); + + ok(pkg_info == (void *)0xdeadbeef, "wrong pkg_info address %p\n", pkg_info); +} + +START_TEST(main) +{ + InitFunctionPtrs(); + if(pInitSecurityInterfaceA) + testInitSecurityInterface(); + if(pFreeContextBuffer) + { + if(pEnumerateSecurityPackagesA) + testEnumerateSecurityPackages(); + if(pQuerySecurityPackageInfoA) + { + testQuerySecurityPackageInfo(); + } + } + if(secdll) + FreeLibrary(secdll); +} diff --git a/rostests/winetests/secur32/ntlm.c b/rostests/winetests/secur32/ntlm.c new file mode 100644 index 00000000000..43b72653d30 --- /dev/null +++ b/rostests/winetests/secur32/ntlm.c @@ -0,0 +1,1299 @@ +/* + * Tests for the NTLM security provider + * + * Copyright 2005, 2006 Kai Blin + * Copyright 2006 Dmitry Timoshkov + * + * 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 + * + * The code that tests for the behaviour of ISC_REQ_ALLOCATE_MEMORY is based + * on code written by Dmitry Timoshkov. + + */ + +#include +#include +#include +#include +#include +#define SECURITY_WIN32 +#include +#include +#include + +#include "wine/test.h" + +static HMODULE secdll; +static PSecurityFunctionTableA (SEC_ENTRY * pInitSecurityInterfaceA)(void); +static SECURITY_STATUS (SEC_ENTRY * pFreeContextBuffer)(PVOID pv); +static SECURITY_STATUS (SEC_ENTRY * pQuerySecurityPackageInfoA)(SEC_CHAR*, PSecPkgInfoA*); +static SECURITY_STATUS (SEC_ENTRY * pAcquireCredentialsHandleA)(SEC_CHAR*, SEC_CHAR*, + ULONG, PLUID, PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp); +static SECURITY_STATUS (SEC_ENTRY * pInitializeSecurityContextA)(PCredHandle, PCtxtHandle, + SEC_CHAR*, ULONG, ULONG, ULONG, PSecBufferDesc, ULONG, + PCtxtHandle, PSecBufferDesc, PULONG, PTimeStamp); +static SECURITY_STATUS (SEC_ENTRY * pCompleteAuthToken)(PCtxtHandle, PSecBufferDesc); +static SECURITY_STATUS (SEC_ENTRY * pAcceptSecurityContext)(PCredHandle, PCtxtHandle, + PSecBufferDesc, ULONG, ULONG, PCtxtHandle, PSecBufferDesc, + PULONG, PTimeStamp); +static SECURITY_STATUS (SEC_ENTRY * pFreeCredentialsHandle)(PCredHandle); +static SECURITY_STATUS (SEC_ENTRY * pDeleteSecurityContext)(PCtxtHandle); +static SECURITY_STATUS (SEC_ENTRY * pQueryContextAttributesA)(PCtxtHandle, ULONG, PVOID); +static SECURITY_STATUS (SEC_ENTRY * pMakeSignature)(PCtxtHandle, ULONG, + PSecBufferDesc, ULONG); +static SECURITY_STATUS (SEC_ENTRY * pVerifySignature)(PCtxtHandle, PSecBufferDesc, + ULONG, PULONG); +static SECURITY_STATUS (SEC_ENTRY * pEncryptMessage)(PCtxtHandle, ULONG, + PSecBufferDesc, ULONG); +static SECURITY_STATUS (SEC_ENTRY * pDecryptMessage)(PCtxtHandle, PSecBufferDesc, + ULONG, PULONG); + +typedef struct _SspiData { + PCredHandle cred; + PCtxtHandle ctxt; + PSecBufferDesc in_buf; + PSecBufferDesc out_buf; + PSEC_WINNT_AUTH_IDENTITY id; + ULONG max_token; +} SspiData; + +static BYTE network_challenge[] = + {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x05, 0x82, 0x82, 0xa0, 0xe9, 0x58, 0x7f, 0x14, 0xa2, 0x86, + 0x3b, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x54, 0x00, 0x40, 0x00, 0x00, 0x00, 0x43, 0x00, + 0x41, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x4f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x02, 0x00, 0x10, 0x00, 0x43, 0x00, + 0x41, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x4f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x01, 0x00, 0x10, 0x00, 0x43, 0x00, + 0x41, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x4f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x04, 0x00, 0x10, 0x00, 0x63, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x03, 0x00, 0x10, 0x00, 0x63, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static BYTE native_challenge[] = + {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x05, 0x82, 0x82, 0xa0, 0xb5, 0x60, 0x8e, 0x95, 0xb5, 0x3c, + 0xee, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x54, 0x00, 0x40, 0x00, 0x00, 0x00, 0x43, 0x00, + 0x41, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x4f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x02, 0x00, 0x10, 0x00, 0x43, 0x00, + 0x41, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x4f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x01, 0x00, 0x10, 0x00, 0x43, 0x00, + 0x41, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x4f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x04, 0x00, 0x10, 0x00, 0x63, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x03, 0x00, 0x10, 0x00, 0x63, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6f, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static BYTE message_signature[] = + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static BYTE message_binary[] = + {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, + 0x6c, 0x64, 0x21}; + +static char message[] = "Hello, world!"; + +static char message_header[] = "Header Test"; + +static BYTE crypt_trailer_client[] = + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xc7, + 0xaa, 0x26, 0x16, 0x39, 0x07, 0x4e}; + +static BYTE crypt_message_client[] = + {0x86, 0x9c, 0x5a, 0x10, 0x78, 0xb3, 0x30, 0x98, 0x46, 0x15, + 0xa0, 0x31, 0xd9}; + +static BYTE crypt_trailer_client2[] = + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xa7, + 0xf7, 0x0f, 0x5b, 0x25, 0xbe, 0xa4}; + +static BYTE crypt_message_client2[] = + {0x20, 0x6c, 0x01, 0xab, 0xb0, 0x4c, 0x93, 0xe4, 0x1e, 0xfc, + 0xe1, 0xfa, 0xfe}; + +static BYTE crypt_trailer_server[] = + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x46, + 0x2e, 0x77, 0xeb, 0xf0, 0xf6, 0x9e}; + +static BYTE crypt_message_server[] = + {0xf6, 0xb7, 0x92, 0x0c, 0xac, 0xea, 0x98, 0xe6, 0xef, 0xa0, + 0x29, 0x66, 0xfd}; + +static BYTE crypt_trailer_server2[] = + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x4e, + 0x46, 0xb7, 0xca, 0xf7, 0x7f, 0xb3}; + +static BYTE crypt_message_server2[] = + {0xc8, 0xf2, 0x39, 0x7f, 0x0c, 0xaf, 0xf5, 0x5d, 0xef, 0x0c, + 0x8b, 0x5f, 0x82}; + +static void InitFunctionPtrs(void) +{ + secdll = LoadLibraryA("secur32.dll"); + if(!secdll) + secdll = LoadLibraryA("security.dll"); + if(secdll) + { + pInitSecurityInterfaceA = (PVOID)GetProcAddress(secdll, "InitSecurityInterfaceA"); + pFreeContextBuffer = (PVOID)GetProcAddress(secdll, "FreeContextBuffer"); + pQuerySecurityPackageInfoA = (PVOID)GetProcAddress(secdll, "QuerySecurityPackageInfoA"); + pAcquireCredentialsHandleA = (PVOID)GetProcAddress(secdll, "AcquireCredentialsHandleA"); + pInitializeSecurityContextA = (PVOID)GetProcAddress(secdll, "InitializeSecurityContextA"); + pCompleteAuthToken = (PVOID)GetProcAddress(secdll, "CompleteAuthToken"); + pAcceptSecurityContext = (PVOID)GetProcAddress(secdll, "AcceptSecurityContext"); + pFreeCredentialsHandle = (PVOID)GetProcAddress(secdll, "FreeCredentialsHandle"); + pDeleteSecurityContext = (PVOID)GetProcAddress(secdll, "DeleteSecurityContext"); + pQueryContextAttributesA = (PVOID)GetProcAddress(secdll, "QueryContextAttributesA"); + pMakeSignature = (PVOID)GetProcAddress(secdll, "MakeSignature"); + pVerifySignature = (PVOID)GetProcAddress(secdll, "VerifySignature"); + pEncryptMessage = (PVOID)GetProcAddress(secdll, "EncryptMessage"); + pDecryptMessage = (PVOID)GetProcAddress(secdll, "DecryptMessage"); + } +} + +static const char* getSecError(SECURITY_STATUS status) +{ + static char buf[20]; + +#define _SEC_ERR(x) case (x): return #x; + switch(status) + { + _SEC_ERR(SEC_E_OK); + _SEC_ERR(SEC_E_INSUFFICIENT_MEMORY); + _SEC_ERR(SEC_E_INVALID_HANDLE); + _SEC_ERR(SEC_E_UNSUPPORTED_FUNCTION); + _SEC_ERR(SEC_E_TARGET_UNKNOWN); + _SEC_ERR(SEC_E_INTERNAL_ERROR); + _SEC_ERR(SEC_E_SECPKG_NOT_FOUND); + _SEC_ERR(SEC_E_NOT_OWNER); + _SEC_ERR(SEC_E_CANNOT_INSTALL); + _SEC_ERR(SEC_E_INVALID_TOKEN); + _SEC_ERR(SEC_E_CANNOT_PACK); + _SEC_ERR(SEC_E_QOP_NOT_SUPPORTED); + _SEC_ERR(SEC_E_NO_IMPERSONATION); + _SEC_ERR(SEC_I_CONTINUE_NEEDED); + _SEC_ERR(SEC_E_BUFFER_TOO_SMALL); + _SEC_ERR(SEC_E_ILLEGAL_MESSAGE); + _SEC_ERR(SEC_E_LOGON_DENIED); + _SEC_ERR(SEC_E_NO_CREDENTIALS); + _SEC_ERR(SEC_E_OUT_OF_SEQUENCE); + _SEC_ERR(SEC_E_MESSAGE_ALTERED); + default: + sprintf(buf, "%08x\n", status); + return buf; + } +#undef _SEC_ERR +} + +/**********************************************************************/ + +static SECURITY_STATUS setupBuffers(SspiData *sspi_data, SecPkgInfoA *sec_pkg_info) +{ + + sspi_data->in_buf = HeapAlloc(GetProcessHeap(), 0, sizeof(SecBufferDesc)); + sspi_data->out_buf = HeapAlloc(GetProcessHeap(), 0, sizeof(SecBufferDesc)); + sspi_data->max_token = sec_pkg_info->cbMaxToken; + + if(sspi_data->in_buf != NULL) + { + PSecBuffer sec_buffer = HeapAlloc(GetProcessHeap(), 0, + sizeof(SecBuffer)); + if(sec_buffer == NULL){ + trace("in_buf: sec_buffer == NULL\n"); + return SEC_E_INSUFFICIENT_MEMORY; + } + + sspi_data->in_buf->ulVersion = SECBUFFER_VERSION; + sspi_data->in_buf->cBuffers = 1; + sspi_data->in_buf->pBuffers = sec_buffer; + + sec_buffer->cbBuffer = sec_pkg_info->cbMaxToken; + sec_buffer->BufferType = SECBUFFER_TOKEN; + if((sec_buffer->pvBuffer = HeapAlloc(GetProcessHeap(), 0, + sec_pkg_info->cbMaxToken)) == NULL) + { + trace("in_buf: sec_buffer->pvBuffer == NULL\n"); + return SEC_E_INSUFFICIENT_MEMORY; + } + } + else + { + trace("HeapAlloc in_buf returned NULL\n"); + return SEC_E_INSUFFICIENT_MEMORY; + } + + if(sspi_data->out_buf != NULL) + { + PSecBuffer sec_buffer = HeapAlloc(GetProcessHeap(), 0, + sizeof(SecBuffer)); + + if(sec_buffer == NULL){ + trace("out_buf: sec_buffer == NULL\n"); + return SEC_E_INSUFFICIENT_MEMORY; + } + + sspi_data->out_buf->ulVersion = SECBUFFER_VERSION; + sspi_data->out_buf->cBuffers = 1; + sspi_data->out_buf->pBuffers = sec_buffer; + + sec_buffer->cbBuffer = sec_pkg_info->cbMaxToken; + sec_buffer->BufferType = SECBUFFER_TOKEN; + if((sec_buffer->pvBuffer = HeapAlloc(GetProcessHeap(), 0, + sec_pkg_info->cbMaxToken)) == NULL){ + trace("out_buf: sec_buffer->pvBuffer == NULL\n"); + return SEC_E_INSUFFICIENT_MEMORY; + } + } + else + { + trace("HeapAlloc out_buf returned NULL\n"); + return SEC_E_INSUFFICIENT_MEMORY; + } + + return SEC_E_OK; +} + +/**********************************************************************/ + +static void cleanupBuffers(SspiData *sspi_data) +{ + ULONG i; + + if(sspi_data->in_buf != NULL) + { + for(i = 0; i < sspi_data->in_buf->cBuffers; ++i) + { + HeapFree(GetProcessHeap(), 0, sspi_data->in_buf->pBuffers[i].pvBuffer); + } + HeapFree(GetProcessHeap(), 0, sspi_data->in_buf->pBuffers); + HeapFree(GetProcessHeap(), 0, sspi_data->in_buf); + } + + if(sspi_data->out_buf != NULL) + { + for(i = 0; i < sspi_data->out_buf->cBuffers; ++i) + { + HeapFree(GetProcessHeap(), 0, sspi_data->out_buf->pBuffers[i].pvBuffer); + } + HeapFree(GetProcessHeap(), 0, sspi_data->out_buf->pBuffers); + HeapFree(GetProcessHeap(), 0, sspi_data->out_buf); + } +} + +/**********************************************************************/ + +static SECURITY_STATUS setupClient(SspiData *sspi_data, SEC_CHAR *provider) +{ + SECURITY_STATUS ret; + TimeStamp ttl; + SecPkgInfoA *sec_pkg_info; + + trace("Running setupClient\n"); + + sspi_data->cred = HeapAlloc(GetProcessHeap(), 0, sizeof(CredHandle)); + sspi_data->ctxt = HeapAlloc(GetProcessHeap(), 0, sizeof(CtxtHandle)); + + ret = pQuerySecurityPackageInfoA(provider, &sec_pkg_info); + + ok(ret == SEC_E_OK, "QuerySecurityPackageInfo returned %s\n", getSecError(ret)); + + setupBuffers(sspi_data, sec_pkg_info); + + if((ret = pAcquireCredentialsHandleA(NULL, provider, SECPKG_CRED_OUTBOUND, + NULL, sspi_data->id, NULL, NULL, sspi_data->cred, &ttl)) + != SEC_E_OK) + { + trace("AcquireCredentialsHandle() returned %s\n", getSecError(ret)); + } + + ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n", + getSecError(ret)); + + return ret; +} +/**********************************************************************/ + +static SECURITY_STATUS setupServer(SspiData *sspi_data, SEC_CHAR *provider) +{ + SECURITY_STATUS ret; + TimeStamp ttl; + SecPkgInfoA *sec_pkg_info; + + trace("Running setupServer\n"); + + sspi_data->cred = HeapAlloc(GetProcessHeap(), 0, sizeof(CredHandle)); + sspi_data->ctxt = HeapAlloc(GetProcessHeap(), 0, sizeof(CtxtHandle)); + + ret = pQuerySecurityPackageInfoA(provider, &sec_pkg_info); + + ok(ret == SEC_E_OK, "QuerySecurityPackageInfo returned %s\n", getSecError(ret)); + + setupBuffers(sspi_data, sec_pkg_info); + + if((ret = pAcquireCredentialsHandleA(NULL, provider, SECPKG_CRED_INBOUND, + NULL, NULL, NULL, NULL, sspi_data->cred, &ttl)) != SEC_E_OK) + { + trace("AcquireCredentialsHandle() returned %s\n", getSecError(ret)); + } + + ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n", + getSecError(ret)); + + return ret; +} + +/**********************************************************************/ + +static SECURITY_STATUS setupFakeServer(SspiData *sspi_data, SEC_CHAR *provider) +{ + SECURITY_STATUS ret; + SecPkgInfoA *sec_pkg_info; + + trace("Running setupFakeServer\n"); + + sspi_data->cred = HeapAlloc(GetProcessHeap(), 0, sizeof(CredHandle)); + sspi_data->ctxt = HeapAlloc(GetProcessHeap(), 0, sizeof(CtxtHandle)); + + ret = pQuerySecurityPackageInfoA(provider, &sec_pkg_info); + + ok(ret == SEC_E_OK, "QuerySecurityPackageInfo returned %s\n", getSecError(ret)); + + ret = setupBuffers(sspi_data, sec_pkg_info); + + return ret; +} + + +/**********************************************************************/ + +static SECURITY_STATUS runClient(SspiData *sspi_data, BOOL first, ULONG data_rep) +{ + SECURITY_STATUS ret; + ULONG req_attr = 0; + ULONG ctxt_attr; + TimeStamp ttl; + PSecBufferDesc in_buf = sspi_data->in_buf; + PSecBufferDesc out_buf = sspi_data->out_buf; + + assert(in_buf->cBuffers >= 1); + assert(in_buf->pBuffers[0].pvBuffer != NULL); + assert(in_buf->pBuffers[0].cbBuffer != 0); + + assert(out_buf->cBuffers >= 1); + assert(out_buf->pBuffers[0].pvBuffer != NULL); + assert(out_buf->pBuffers[0].cbBuffer != 0); + + trace("Running the client the %s time.\n", first?"first":"second"); + + /* We can either use ISC_REQ_ALLOCATE_MEMORY flag to ask the provider + * always allocate output buffers for us, or initialize cbBuffer + * before each call because the API changes it to represent actual + * amount of data in the buffer. + */ + + /* test a failing call only the first time, otherwise we get + * SEC_E_OUT_OF_SEQUENCE + */ + if (first) + { + void *old_buf; + + /* pass NULL as an output buffer */ + ret = pInitializeSecurityContextA(sspi_data->cred, NULL, NULL, req_attr, + 0, data_rep, NULL, 0, sspi_data->ctxt, NULL, + &ctxt_attr, &ttl); + + ok(ret == SEC_E_BUFFER_TOO_SMALL, "expected SEC_E_BUFFER_TOO_SMALL, got %s\n", getSecError(ret)); + + /* pass NULL as an output buffer */ + old_buf = out_buf->pBuffers[0].pvBuffer; + out_buf->pBuffers[0].pvBuffer = NULL; + + ret = pInitializeSecurityContextA(sspi_data->cred, NULL, NULL, req_attr, + 0, data_rep, NULL, 0, sspi_data->ctxt, out_buf, + &ctxt_attr, &ttl); + + ok(ret == SEC_E_INTERNAL_ERROR, "expected SEC_E_INTERNAL_ERROR, got %s\n", getSecError(ret)); + + out_buf->pBuffers[0].pvBuffer = old_buf; + + /* pass an output buffer of 0 size */ + out_buf->pBuffers[0].cbBuffer = 0; + + ret = pInitializeSecurityContextA(sspi_data->cred, NULL, NULL, req_attr, + 0, data_rep, NULL, 0, sspi_data->ctxt, out_buf, + &ctxt_attr, &ttl); + + ok(ret == SEC_E_BUFFER_TOO_SMALL, "expected SEC_E_BUFFER_TOO_SMALL, got %s\n", getSecError(ret)); + + ok(out_buf->pBuffers[0].cbBuffer == 0, + "InitializeSecurityContext set buffer size to %u\n", out_buf->pBuffers[0].cbBuffer); + + out_buf->pBuffers[0].cbBuffer = sspi_data->max_token; + out_buf->pBuffers[0].BufferType = SECBUFFER_DATA; + + ret = pInitializeSecurityContextA(sspi_data->cred, NULL, NULL, req_attr, + 0, data_rep, NULL, 0, sspi_data->ctxt, out_buf, + &ctxt_attr, &ttl); + + ok(ret == SEC_E_BUFFER_TOO_SMALL, "expected SEC_E_BUFFER_TOO_SMALL, got %s\n", getSecError(ret)); + out_buf->pBuffers[0].BufferType = SECBUFFER_TOKEN; + } + + out_buf->pBuffers[0].cbBuffer = sspi_data->max_token; + + ret = pInitializeSecurityContextA(first?sspi_data->cred:NULL, first?NULL:sspi_data->ctxt, NULL, req_attr, + 0, data_rep, first?NULL:in_buf, 0, sspi_data->ctxt, out_buf, + &ctxt_attr, &ttl); + + if(ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED) + { + pCompleteAuthToken(sspi_data->ctxt, out_buf); + if(ret == SEC_I_COMPLETE_AND_CONTINUE) + ret = SEC_I_CONTINUE_NEEDED; + else if(ret == SEC_I_COMPLETE_NEEDED) + ret = SEC_E_OK; + } + + ok(out_buf->pBuffers[0].BufferType == SECBUFFER_TOKEN, + "buffer type was changed from SECBUFFER_TOKEN to %d\n", out_buf->pBuffers[0].BufferType); + ok(out_buf->pBuffers[0].cbBuffer < sspi_data->max_token, + "InitializeSecurityContext set buffer size to %u\n", out_buf->pBuffers[0].cbBuffer); + + return ret; +} + +/**********************************************************************/ + +static SECURITY_STATUS runServer(SspiData *sspi_data, BOOL first, ULONG data_rep) +{ + SECURITY_STATUS ret; + ULONG ctxt_attr; + TimeStamp ttl; + + trace("Running the server the %s time\n", first?"first":"second"); + + ret = pAcceptSecurityContext(sspi_data->cred, first?NULL:sspi_data->ctxt, + sspi_data->in_buf, 0, data_rep, sspi_data->ctxt, + sspi_data->out_buf, &ctxt_attr, &ttl); + + if(ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED) + { + pCompleteAuthToken(sspi_data->ctxt, sspi_data->out_buf); + if(ret == SEC_I_COMPLETE_AND_CONTINUE) + ret = SEC_I_CONTINUE_NEEDED; + else if(ret == SEC_I_COMPLETE_NEEDED) + ret = SEC_E_OK; + } + + return ret; +} + +/**********************************************************************/ + +static SECURITY_STATUS runFakeServer(SspiData *sspi_data, BOOL first, ULONG data_rep) +{ + trace("Running the fake server the %s time\n", first?"first":"second"); + + if(!first) + { + sspi_data->out_buf->pBuffers[0].cbBuffer = 0; + return SEC_E_OK; + } + + if(data_rep == SECURITY_NATIVE_DREP) + { + sspi_data->out_buf->pBuffers[0].cbBuffer = sizeof(native_challenge); + memcpy(sspi_data->out_buf->pBuffers[0].pvBuffer, native_challenge, + sspi_data->out_buf->pBuffers[0].cbBuffer); + } + else + { + sspi_data->out_buf->pBuffers[0].cbBuffer = sizeof(network_challenge); + memcpy(sspi_data->out_buf->pBuffers[0].pvBuffer, network_challenge, + sspi_data->out_buf->pBuffers[0].cbBuffer); + } + + return SEC_I_CONTINUE_NEEDED; +} + +/**********************************************************************/ + +static void communicate(SspiData *from, SspiData *to) +{ + if(from->out_buf != NULL && to->in_buf != NULL) + { + trace("Running communicate.\n"); + if((from->out_buf->cBuffers >= 1) && (to->in_buf->cBuffers >= 1)) + { + if((from->out_buf->pBuffers[0].pvBuffer != NULL) && + (to->in_buf->pBuffers[0].pvBuffer != NULL)) + { + memset(to->in_buf->pBuffers[0].pvBuffer, 0, to->max_token); + + memcpy(to->in_buf->pBuffers[0].pvBuffer, + from->out_buf->pBuffers[0].pvBuffer, + from->out_buf->pBuffers[0].cbBuffer); + + to->in_buf->pBuffers[0].cbBuffer = from->out_buf->pBuffers[0].cbBuffer; + + memset(from->out_buf->pBuffers[0].pvBuffer, 0, from->max_token); + } + } + } +} + +/**********************************************************************/ +static void testInitializeSecurityContextFlags(void) +{ + SECURITY_STATUS sec_status; + PSecPkgInfo pkg_info = NULL; + SspiData client; + SEC_WINNT_AUTH_IDENTITY id; + static char sec_pkg_name[] = "NTLM", + test_user[] = "testuser", + workgroup[] = "WORKGROUP", + test_pass[] = "testpass"; + ULONG req_attr, ctxt_attr; + TimeStamp ttl; + PBYTE packet; + + if(pQuerySecurityPackageInfoA( sec_pkg_name, &pkg_info) != SEC_E_OK) + { + skip("Package not installed, skipping test!\n"); + return; + } + + pFreeContextBuffer(pkg_info); + id.User = (unsigned char*) test_user; + id.UserLength = strlen((char *) id.User); + id.Domain = (unsigned char *) workgroup; + id.DomainLength = strlen((char *) id.Domain); + id.Password = (unsigned char*) test_pass; + id.PasswordLength = strlen((char *) id.Password); + id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + + client.id = &id; + + if((sec_status = setupClient(&client, sec_pkg_name)) != SEC_E_OK) + { + skip("Setting up the client returned %s, skipping test!\n", + getSecError(sec_status)); + return; + } + + packet = client.out_buf->pBuffers[0].pvBuffer; + + /* Due to how the requesting of the flags is implemented in ntlm_auth, + * the tests need to be in this order, as there is no way to specify + * "I request no special features" in ntlm_auth */ + + /* Without any flags, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = 0; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "With req_attr == 0, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_CONNECTION, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_CONNECTION; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_CONNECTION, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_EXTENDED_ERROR, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_EXTENDED_ERROR; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_EXTENDED_ERROR, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_MUTUAL_AUTH, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_MUTUAL_AUTH; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_MUTUAL_AUTH, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_USE_DCE_STYLE, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_USE_DCE_STYLE; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_USE_DCE_STYLE, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_DELEGATE, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_DELEGATE; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_DELEGATE, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_INTEGRITY, the lowest byte should have bit 0x10 set */ + req_attr = ISC_REQ_INTEGRITY; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok((packet[12] & 0x10) != 0, + "For ISC_REQ_INTEGRITY, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_REPLAY_DETECT, the lowest byte should have bit 0x10 set */ + req_attr = ISC_REQ_REPLAY_DETECT; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok((packet[12] & 0x10) != 0, + "For ISC_REQ_REPLAY_DETECT, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_SEQUENCE_DETECT, the lowest byte should have bit 0x10 set */ + req_attr = ISC_REQ_SEQUENCE_DETECT; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok((packet[12] & 0x10) != 0, + "For ISC_REQ_SEQUENCE_DETECT, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_CONFIDENTIALITY, the lowest byte should have bit 0x20 set */ + req_attr = ISC_REQ_CONFIDENTIALITY; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok((packet[12] & 0x20) != 0, + "For ISC_REQ_CONFIDENTIALITY, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + +tISCFend: + cleanupBuffers(&client); + pFreeCredentialsHandle(client.cred); + +} + +/**********************************************************************/ + +static void testAuth(ULONG data_rep, BOOL fake) +{ + SECURITY_STATUS client_stat = SEC_I_CONTINUE_NEEDED; + SECURITY_STATUS server_stat = SEC_I_CONTINUE_NEEDED; + SECURITY_STATUS sec_status; + PSecPkgInfo pkg_info = NULL; + BOOL first = TRUE; + SspiData client, server; + SEC_WINNT_AUTH_IDENTITY id; + SecPkgContext_Sizes ctxt_sizes; + static char sec_pkg_name[] = "NTLM", + test_user[] = "testuser", + workgroup[] = "WORKGROUP", + test_pass[] = "testpass"; + + if(pQuerySecurityPackageInfoA( sec_pkg_name, &pkg_info)!= SEC_E_OK) + { + skip("Package not installed, skipping test.\n"); + return; + } + + pFreeContextBuffer(pkg_info); + id.User = (unsigned char*) test_user; + id.UserLength = strlen((char *) id.User); + id.Domain = (unsigned char *) workgroup; + id.DomainLength = strlen((char *) id.Domain); + id.Password = (unsigned char*) test_pass; + id.PasswordLength = strlen((char *) id.Password); + id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + + client.id = &id; + + sec_status = setupClient(&client, sec_pkg_name); + + if(sec_status != SEC_E_OK) + { + skip("Error: Setting up the client returned %s, exiting test!\n", + getSecError(sec_status)); + pFreeCredentialsHandle(client.cred); + return; + } + + if(fake) + sec_status = setupFakeServer(&server, sec_pkg_name); + else + sec_status = setupServer(&server, sec_pkg_name); + + if(sec_status != SEC_E_OK) + { + skip("Error: Setting up the server returned %s, exiting test!\n", + getSecError(sec_status)); + pFreeCredentialsHandle(server.cred); + pFreeCredentialsHandle(client.cred); + return; + } + + while(client_stat == SEC_I_CONTINUE_NEEDED && server_stat == SEC_I_CONTINUE_NEEDED) + { + client_stat = runClient(&client, first, data_rep); + + ok(client_stat == SEC_E_OK || client_stat == SEC_I_CONTINUE_NEEDED, + "Running the client returned %s, more tests will fail.\n", + getSecError(client_stat)); + + communicate(&client, &server); + + if(fake) + server_stat = runFakeServer(&server, first, data_rep); + else + server_stat = runServer(&server, first, data_rep); + + ok(server_stat == SEC_E_OK || server_stat == SEC_I_CONTINUE_NEEDED || + server_stat == SEC_E_LOGON_DENIED, + "Running the server returned %s, more tests will fail from now.\n", + getSecError(server_stat)); + + communicate(&server, &client); + trace("Looping\n"); + first = FALSE; + } + + if(client_stat != SEC_E_OK) + { + skip("Authentication failed, skipping test.\n"); + goto tAuthend; + } + + sec_status = pQueryContextAttributesA(client.ctxt, + SECPKG_ATTR_SIZES, &ctxt_sizes); + + ok(sec_status == SEC_E_OK, + "pQueryContextAttributesA(SECPKG_ATTR_SIZES) returned %s\n", + getSecError(sec_status)); + ok((ctxt_sizes.cbMaxToken == 1904) || (ctxt_sizes.cbMaxToken == 2888), + "cbMaxToken should be 1904 or 2888 but is %u\n", + ctxt_sizes.cbMaxToken); + ok(ctxt_sizes.cbMaxSignature == 16, + "cbMaxSignature should be 16 but is %u\n", + ctxt_sizes.cbMaxSignature); + ok(ctxt_sizes.cbSecurityTrailer == 16, + "cbSecurityTrailer should be 16 but is %u\n", + ctxt_sizes.cbSecurityTrailer); + ok(ctxt_sizes.cbBlockSize == 0, + "cbBlockSize should be 0 but is %u\n", + ctxt_sizes.cbBlockSize); + +tAuthend: + cleanupBuffers(&client); + cleanupBuffers(&server); + + if(!fake) + { + sec_status = pDeleteSecurityContext(server.ctxt); + ok(sec_status == SEC_E_OK, "DeleteSecurityContext(server) returned %s\n", + getSecError(sec_status)); + } + + sec_status = pDeleteSecurityContext(client.ctxt); + ok(sec_status == SEC_E_OK, "DeleteSecurityContext(client) returned %s\n", + getSecError(sec_status)); + + if(!fake) + { + sec_status = pFreeCredentialsHandle(server.cred); + ok(sec_status == SEC_E_OK, "FreeCredentialsHandle(server) returned %s\n", + getSecError(sec_status)); + } + + sec_status = pFreeCredentialsHandle(client.cred); + ok(sec_status == SEC_E_OK, "FreeCredentialsHandle(client) returned %s\n", + getSecError(sec_status)); +} + +static void testSignSeal(void) +{ + SECURITY_STATUS client_stat = SEC_I_CONTINUE_NEEDED; + SECURITY_STATUS server_stat = SEC_I_CONTINUE_NEEDED; + SECURITY_STATUS sec_status; + PSecPkgInfo pkg_info = NULL; + BOOL first = TRUE; + SspiData client, server; + SEC_WINNT_AUTH_IDENTITY id; + static char sec_pkg_name[] = "NTLM"; + SecBufferDesc crypt; + SecBuffer data[2], fake_data[2], complex_data[4]; + ULONG qop = 0; + SecPkgContext_Sizes ctxt_sizes; + static char test_user[] = "testuser", + workgroup[] = "WORKGROUP", + test_pass[] = "testpass"; + + complex_data[1].pvBuffer = complex_data[3].pvBuffer = NULL; + + /**************************************************************** + * This is basically the same as in testAuth with a fake server, + * as we need a valid, authenticated context. + */ + if(pQuerySecurityPackageInfoA( sec_pkg_name, &pkg_info) != SEC_E_OK) + { + skip("Package not installed, skipping test.\n"); + return; + } + + pFreeContextBuffer(pkg_info); + id.User = (unsigned char*) test_user; + id.UserLength = strlen((char *) id.User); + id.Domain = (unsigned char *) workgroup; + id.DomainLength = strlen((char *) id.Domain); + id.Password = (unsigned char*) test_pass; + id.PasswordLength = strlen((char *) id.Password); + id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + + client.id = &id; + + sec_status = setupClient(&client, sec_pkg_name); + + if(sec_status != SEC_E_OK) + { + skip("Error: Setting up the client returned %s, exiting test!\n", + getSecError(sec_status)); + pFreeCredentialsHandle(client.cred); + return; + } + + sec_status = setupFakeServer(&server, sec_pkg_name); + + while(client_stat == SEC_I_CONTINUE_NEEDED && server_stat == SEC_I_CONTINUE_NEEDED) + { + client_stat = runClient(&client, first, SECURITY_NETWORK_DREP); + + communicate(&client, &server); + + server_stat = runFakeServer(&server, first, SECURITY_NETWORK_DREP); + + communicate(&server, &client); + trace("Looping\n"); + first = FALSE; + } + + /******************************************** + * Now start with the actual testing * + ********************************************/ + + if(pQueryContextAttributesA(client.ctxt, SECPKG_ATTR_SIZES, + &ctxt_sizes) != SEC_E_OK) + { + skip("Failed to get context sizes, aborting test.\n"); + goto end; + } + + crypt.ulVersion = SECBUFFER_VERSION; + crypt.cBuffers = 2; + + crypt.pBuffers = fake_data; + + fake_data[0].BufferType = SECBUFFER_DATA; + fake_data[0].cbBuffer = ctxt_sizes.cbSecurityTrailer; + fake_data[0].pvBuffer = HeapAlloc(GetProcessHeap(), 0, fake_data[0].cbBuffer); + + fake_data[1].BufferType = SECBUFFER_DATA; + fake_data[1].cbBuffer = lstrlen(message); + fake_data[1].pvBuffer = HeapAlloc(GetProcessHeap(), 0, fake_data[1].cbBuffer); + + sec_status = pMakeSignature(client.ctxt, 0, &crypt, 0); + ok(sec_status == SEC_E_INVALID_TOKEN, + "MakeSignature returned %s, not SEC_E_INVALID_TOKEN.\n", + getSecError(sec_status)); + + crypt.pBuffers = data; + + data[0].BufferType = SECBUFFER_TOKEN; + data[0].cbBuffer = ctxt_sizes.cbSecurityTrailer; + data[0].pvBuffer = HeapAlloc(GetProcessHeap(), 0, data[0].cbBuffer); + + data[1].BufferType = SECBUFFER_DATA; + data[1].cbBuffer = lstrlen(message); + data[1].pvBuffer = HeapAlloc(GetProcessHeap(), 0, data[1].cbBuffer); + memcpy(data[1].pvBuffer, message, data[1].cbBuffer); + + /* As we forced NTLM to fall back to a password-derived session key, + * we should get the same signature for our data, no matter if + * it is sent by the client or the server + */ + sec_status = pMakeSignature(client.ctxt, 0, &crypt, 0); + ok(sec_status == SEC_E_OK, "MakeSignature returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + ok(!memcmp(crypt.pBuffers[0].pvBuffer, message_signature, + crypt.pBuffers[0].cbBuffer), "Signature is not as expected.\n"); + + data[0].cbBuffer = sizeof(message_signature); + + memcpy(data[0].pvBuffer, crypt_trailer_client, data[0].cbBuffer); + + sec_status = pVerifySignature(client.ctxt, &crypt, 0, &qop); + ok(sec_status == SEC_E_MESSAGE_ALTERED, + "VerifySignature returned %s, not SEC_E_MESSAGE_ALTERED.\n", + getSecError(sec_status)); + + memcpy(data[0].pvBuffer, message_signature, data[0].cbBuffer); + + sec_status = pVerifySignature(client.ctxt, &crypt, 0, &qop); + ok(sec_status == SEC_E_OK, "VerifySignature returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + + sec_status = pEncryptMessage(client.ctxt, 0, &crypt, 0); + if (sec_status == SEC_E_UNSUPPORTED_FUNCTION) + { + skip("Encrypt message returned SEC_E_UNSUPPORTED_FUNCTION. " + "Expected on Vista.\n"); + goto end; + } + ok(sec_status == SEC_E_OK, "EncryptMessage returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + + ok(!memcmp(crypt.pBuffers[0].pvBuffer, crypt_trailer_client, + crypt.pBuffers[0].cbBuffer), "Crypt trailer not as expected.\n"); + ok(!memcmp(crypt.pBuffers[1].pvBuffer, crypt_message_client, + crypt.pBuffers[1].cbBuffer), "Crypt message not as expected.\n"); + + data[0].cbBuffer = sizeof(crypt_trailer_server); + data[1].cbBuffer = sizeof(crypt_message_server); + memcpy(data[0].pvBuffer, crypt_trailer_server, data[0].cbBuffer); + memcpy(data[1].pvBuffer, crypt_message_server, data[1].cbBuffer); + + sec_status = pDecryptMessage(client.ctxt, &crypt, 0, &qop); + + ok(sec_status == SEC_E_OK, "DecryptMessage returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + ok(!memcmp(crypt.pBuffers[1].pvBuffer, message_binary, + crypt.pBuffers[1].cbBuffer), + "Failed to decrypt message correctly.\n"); + + trace("Testing with more than one buffer.\n"); + + crypt.cBuffers = sizeof(complex_data)/sizeof(complex_data[0]); + crypt.pBuffers = complex_data; + + complex_data[0].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + complex_data[0].cbBuffer = sizeof(message_header); + complex_data[0].pvBuffer = message_header; + + complex_data[1].BufferType = SECBUFFER_DATA; + complex_data[1].cbBuffer = lstrlen(message); + complex_data[1].pvBuffer = HeapAlloc(GetProcessHeap(), 0, data[1].cbBuffer); + memcpy(complex_data[1].pvBuffer, message, complex_data[1].cbBuffer); + + complex_data[2].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + complex_data[2].cbBuffer = sizeof(message_header); + complex_data[2].pvBuffer = message_header; + + complex_data[3].BufferType = SECBUFFER_TOKEN; + complex_data[3].cbBuffer = ctxt_sizes.cbSecurityTrailer; + complex_data[3].pvBuffer = HeapAlloc(GetProcessHeap(), 0, complex_data[3].cbBuffer); + + /* We should get a dummy signature again. */ + sec_status = pMakeSignature(client.ctxt, 0, &crypt, 0); + ok(sec_status == SEC_E_OK, "MakeSignature returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + ok(!memcmp(crypt.pBuffers[3].pvBuffer, message_signature, + crypt.pBuffers[3].cbBuffer), "Signature is not as expected.\n"); + + /* Being a dummy signature, it will verify right away, as if the server + * sent it */ + sec_status = pVerifySignature(client.ctxt, &crypt, 0, &qop); + ok(sec_status == SEC_E_OK, "VerifySignature returned %s, not SEC_E_OK\n", + getSecError(sec_status)); + + sec_status = pEncryptMessage(client.ctxt, 0, &crypt, 0); + ok(sec_status == SEC_E_OK, "EncryptMessage returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + + ok(!memcmp(crypt.pBuffers[3].pvBuffer, crypt_trailer_client2, + crypt.pBuffers[3].cbBuffer), "Crypt trailer not as expected.\n"); + + ok(!memcmp(crypt.pBuffers[1].pvBuffer, crypt_message_client2, + crypt.pBuffers[1].cbBuffer), "Crypt message not as expected.\n"); + + memcpy(complex_data[1].pvBuffer, crypt_message_server2, complex_data[1].cbBuffer); + memcpy(complex_data[3].pvBuffer, crypt_trailer_server2, complex_data[3].cbBuffer); + + sec_status = pDecryptMessage(client.ctxt, &crypt, 0, &qop); + ok(sec_status == SEC_E_OK, "DecryptMessage returned %s, not SEC_E_OK.\n", + getSecError(sec_status)); + + +end: + cleanupBuffers(&client); + cleanupBuffers(&server); + + pDeleteSecurityContext(client.ctxt); + pFreeCredentialsHandle(client.cred); + + HeapFree(GetProcessHeap(), 0, fake_data[0].pvBuffer); + HeapFree(GetProcessHeap(), 0, fake_data[1].pvBuffer); + HeapFree(GetProcessHeap(), 0, data[0].pvBuffer); + HeapFree(GetProcessHeap(), 0, data[1].pvBuffer); + HeapFree(GetProcessHeap(), 0, complex_data[1].pvBuffer); + HeapFree(GetProcessHeap(), 0, complex_data[3].pvBuffer); +} + +static void testAcquireCredentialsHandle(void) +{ + CredHandle cred; + TimeStamp ttl; + static char test_user[] = "testuser", + workgroup[] = "WORKGROUP", + test_pass[] = "testpass", + sec_pkg_name[] = "NTLM"; + SECURITY_STATUS ret; + SEC_WINNT_AUTH_IDENTITY id; + PSecPkgInfo pkg_info = NULL; + + if(pQuerySecurityPackageInfoA(sec_pkg_name, &pkg_info) != SEC_E_OK) + { + skip("NTLM package not installed, skipping test\n"); + return; + } + pFreeContextBuffer(pkg_info); + + id.User = (unsigned char*) test_user; + id.UserLength = strlen((char *) id.User); + id.Domain = (unsigned char *) workgroup; + id.DomainLength = strlen((char *) id.Domain); + id.Password = (unsigned char*) test_pass; + id.PasswordLength = strlen((char *) id.Password); + id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + + ret = pAcquireCredentialsHandleA(NULL, sec_pkg_name, SECPKG_CRED_OUTBOUND, + NULL, &id, NULL, NULL, &cred, &ttl); + ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n", + getSecError(ret)); + pFreeCredentialsHandle(&cred); + + id.DomainLength = 0; + ret = pAcquireCredentialsHandleA(NULL, sec_pkg_name, SECPKG_CRED_OUTBOUND, + NULL, &id, NULL, NULL, &cred, &ttl); + ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n", + getSecError(ret)); + pFreeCredentialsHandle(&cred); + + id.Domain = NULL; + ret = pAcquireCredentialsHandleA(NULL, sec_pkg_name, SECPKG_CRED_OUTBOUND, + NULL, &id, NULL, NULL, &cred, &ttl); + ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n", + getSecError(ret)); + pFreeCredentialsHandle(&cred); + + id.Domain = (unsigned char *) workgroup; + id.DomainLength = strlen((char *) id.Domain); + id.UserLength = 0; + id.User = NULL; + ret = pAcquireCredentialsHandleA(NULL, sec_pkg_name, SECPKG_CRED_OUTBOUND, + NULL, &id, NULL, NULL, &cred, &ttl); + ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n", + getSecError(ret)); + pFreeCredentialsHandle(&cred); + + id.User = (unsigned char*) test_user; + id.UserLength = strlen((char *) id.User); + id.Password = NULL; + id.PasswordLength = 0; + ret = pAcquireCredentialsHandleA(NULL, sec_pkg_name, SECPKG_CRED_OUTBOUND, + NULL, &id, NULL, NULL, &cred, &ttl); + ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n", + getSecError(ret)); + pFreeCredentialsHandle(&cred); +} + +static void test_cred_multiple_use(void) +{ + static char test_user[] = "testuser", + workgroup[] = "WORKGROUP", + test_pass[] = "testpass", + sec_pkg_name[] = "NTLM"; + SECURITY_STATUS ret; + SEC_WINNT_AUTH_IDENTITY id; + PSecPkgInfo pkg_info = NULL; + CredHandle cred; + CtxtHandle ctxt1; + CtxtHandle ctxt2; + SecBufferDesc buffer_desc; + SecBuffer buffers[1]; + ULONG ctxt_attr; + TimeStamp ttl; + + if(pQuerySecurityPackageInfoA(sec_pkg_name, &pkg_info) != SEC_E_OK) + { + skip("NTLM package not installed, skipping test\n"); + return; + } + buffers[0].cbBuffer = pkg_info->cbMaxToken; + buffers[0].BufferType = SECBUFFER_TOKEN; + buffers[0].pvBuffer = HeapAlloc(GetProcessHeap(), 0, buffers[0].cbBuffer); + + pFreeContextBuffer(pkg_info); + + id.User = (unsigned char*) test_user; + id.UserLength = strlen((char *) id.User); + id.Domain = (unsigned char *) workgroup; + id.DomainLength = strlen((char *) id.Domain); + id.Password = (unsigned char*) test_pass; + id.PasswordLength = strlen((char *) id.Password); + id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + + ret = pAcquireCredentialsHandleA(NULL, sec_pkg_name, SECPKG_CRED_OUTBOUND, + NULL, &id, NULL, NULL, &cred, &ttl); + ok(ret == SEC_E_OK, "AcquireCredentialsHande() returned %s\n", + getSecError(ret)); + + buffer_desc.ulVersion = SECBUFFER_VERSION; + buffer_desc.cBuffers = sizeof(buffers)/sizeof(buffers[0]); + buffer_desc.pBuffers = buffers; + + ret = pInitializeSecurityContextA(&cred, NULL, NULL, ISC_REQ_CONNECTION, + 0, SECURITY_NETWORK_DREP, NULL, 0, &ctxt1, &buffer_desc, + &ctxt_attr, &ttl); + ok(ret == SEC_I_CONTINUE_NEEDED, "InitializeSecurityContextA failed with error 0x%x\n", ret); + + ret = pInitializeSecurityContextA(&cred, NULL, NULL, ISC_REQ_CONNECTION, + 0, SECURITY_NETWORK_DREP, NULL, 0, &ctxt2, &buffer_desc, + &ctxt_attr, &ttl); + ok(ret == SEC_I_CONTINUE_NEEDED, "Second InitializeSecurityContextA on cred handle failed with error 0x%x\n", ret); + + ret = pDeleteSecurityContext(&ctxt1); + ok(ret == SEC_E_OK, "DeleteSecurityContext failed with error 0x%x\n", ret); + ret = pDeleteSecurityContext(&ctxt2); + ok(ret == SEC_E_OK, "DeleteSecurityContext failed with error 0x%x\n", ret); + ret = pFreeCredentialsHandle(&cred); + ok(ret == SEC_E_OK, "FreeCredentialsHandle failed with error 0x%x\n", ret); +} + +START_TEST(ntlm) +{ + InitFunctionPtrs(); + + if(pFreeCredentialsHandle && pDeleteSecurityContext && + pDeleteSecurityContext && pAcquireCredentialsHandleA && + pInitializeSecurityContextA && pCompleteAuthToken && + pQuerySecurityPackageInfoA) + { + testAcquireCredentialsHandle(); + testInitializeSecurityContextFlags(); + if(pAcceptSecurityContext) + { + testAuth(SECURITY_NATIVE_DREP, TRUE); + testAuth(SECURITY_NETWORK_DREP, TRUE); + testAuth(SECURITY_NATIVE_DREP, FALSE); + testAuth(SECURITY_NETWORK_DREP, FALSE); + } + if(pMakeSignature && pVerifySignature && pEncryptMessage && + pDecryptMessage) + testSignSeal(); + + test_cred_multiple_use(); + } + else + win_skip("Needed functions are not available\n"); + + if(secdll) + FreeLibrary(secdll); +} diff --git a/rostests/winetests/secur32/schannel.c b/rostests/winetests/secur32/schannel.c new file mode 100644 index 00000000000..167a0b47d60 --- /dev/null +++ b/rostests/winetests/secur32/schannel.c @@ -0,0 +1,460 @@ +/* + * Schannel tests + * + * Copyright 2006 Juan Lang + * + * 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 + */ +#include +#include +#include +#include +#define SECURITY_WIN32 +#include +#include + +#include "wine/test.h" + +static HMODULE secdll, crypt32dll; + +static ACQUIRE_CREDENTIALS_HANDLE_FN_A pAcquireCredentialsHandleA; +static ENUMERATE_SECURITY_PACKAGES_FN_A pEnumerateSecurityPackagesA; +static FREE_CONTEXT_BUFFER_FN pFreeContextBuffer; +static FREE_CREDENTIALS_HANDLE_FN pFreeCredentialsHandle; +static QUERY_CREDENTIALS_ATTRIBUTES_FN_A pQueryCredentialsAttributesA; + +static PCCERT_CONTEXT (WINAPI *pCertCreateCertificateContext)(DWORD,const BYTE*,DWORD); +static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT); +static BOOL (WINAPI *pCertSetCertificateContextProperty)(PCCERT_CONTEXT,DWORD,DWORD,const void*); + +static BOOL (WINAPI *pCryptAcquireContextW)(HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD); +static BOOL (WINAPI *pCryptDestroyKey)(HCRYPTKEY); +static BOOL (WINAPI *pCryptImportKey)(HCRYPTPROV,CONST BYTE*,DWORD,HCRYPTKEY,DWORD,HCRYPTKEY*); +static BOOL (WINAPI *pCryptReleaseContext)(HCRYPTPROV,ULONG_PTR); + +static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06, + 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22, + 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, + 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01, + 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 }; +static WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e', + 'm','p',0 }; +static BYTE privKey[] = { + 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, + 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10, + 0x18, 0x30, 0x94, 0x61, 0xdc, 0x0e, 0xcb, 0x96, 0x4e, 0x21, 0x3f, 0x79, 0xcd, + 0xa9, 0x17, 0x62, 0xbc, 0xbb, 0x61, 0x4c, 0xe0, 0x75, 0x38, 0x6c, 0xf3, 0xde, + 0x60, 0x86, 0x03, 0x97, 0x65, 0xeb, 0x1e, 0x6b, 0xdb, 0x53, 0x85, 0xad, 0x68, + 0x21, 0xf1, 0x5d, 0xe7, 0x1f, 0xe6, 0x53, 0xb4, 0xbb, 0x59, 0x3e, 0x14, 0x27, + 0xb1, 0x83, 0xa7, 0x3a, 0x54, 0xe2, 0x8f, 0x65, 0x8e, 0x6a, 0x4a, 0xcf, 0x3b, + 0x1f, 0x65, 0xff, 0xfe, 0xf1, 0x31, 0x3a, 0x37, 0x7a, 0x8b, 0xcb, 0xc6, 0xd4, + 0x98, 0x50, 0x36, 0x67, 0xe4, 0xa1, 0xe8, 0x7e, 0x8a, 0xc5, 0x23, 0xf2, 0x77, + 0xf5, 0x37, 0x61, 0x49, 0x72, 0x59, 0xe8, 0x3d, 0xf7, 0x60, 0xb2, 0x77, 0xca, + 0x78, 0x54, 0x6d, 0x65, 0x9e, 0x03, 0x97, 0x1b, 0x61, 0xbd, 0x0c, 0xd8, 0x06, + 0x63, 0xe2, 0xc5, 0x48, 0xef, 0xb3, 0xe2, 0x6e, 0x98, 0x7d, 0xbd, 0x4e, 0x72, + 0x91, 0xdb, 0x31, 0x57, 0xe3, 0x65, 0x3a, 0x49, 0xca, 0xec, 0xd2, 0x02, 0x4e, + 0x22, 0x7e, 0x72, 0x8e, 0xf9, 0x79, 0x84, 0x82, 0xdf, 0x7b, 0x92, 0x2d, 0xaf, + 0xc9, 0xe4, 0x33, 0xef, 0x89, 0x5c, 0x66, 0x99, 0xd8, 0x80, 0x81, 0x47, 0x2b, + 0xb1, 0x66, 0x02, 0x84, 0x59, 0x7b, 0xc3, 0xbe, 0x98, 0x45, 0x4a, 0x3d, 0xdd, + 0xea, 0x2b, 0xdf, 0x4e, 0xb4, 0x24, 0x6b, 0xec, 0xe7, 0xd9, 0x0c, 0x45, 0xb8, + 0xbe, 0xca, 0x69, 0x37, 0x92, 0x4c, 0x38, 0x6b, 0x96, 0x6d, 0xcd, 0x86, 0x67, + 0x5c, 0xea, 0x54, 0x94, 0xa4, 0xca, 0xa4, 0x02, 0xa5, 0x21, 0x4d, 0xae, 0x40, + 0x8f, 0x9d, 0x51, 0x83, 0xf2, 0x3f, 0x33, 0xc1, 0x72, 0xb4, 0x1d, 0x94, 0x6e, + 0x7d, 0xe4, 0x27, 0x3f, 0xea, 0xff, 0xe5, 0x9b, 0xa7, 0x5e, 0x55, 0x8e, 0x0d, + 0x69, 0x1c, 0x7a, 0xff, 0x81, 0x9d, 0x53, 0x52, 0x97, 0x9a, 0x76, 0x79, 0xda, + 0x93, 0x32, 0x16, 0xec, 0x69, 0x51, 0x1a, 0x4e, 0xc3, 0xf1, 0x72, 0x80, 0x78, + 0x5e, 0x66, 0x4a, 0x8d, 0x85, 0x2f, 0x3f, 0xb2, 0xa7 }; + +static const BYTE selfSignedCert[] = { + 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, + 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49, + 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, + 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30, + 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31, + 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, + 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, + 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4, + 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b, + 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0, + 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96, + 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, + 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41, + 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66, + 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a, + 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7, + 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f, + 0xa8, 0x76, 0x57, 0x92, 0x36 }; + +static void InitFunctionPtrs(void) +{ + HMODULE advapi32dll; + + crypt32dll = LoadLibraryA("crypt32.dll"); + secdll = LoadLibraryA("secur32.dll"); + if(!secdll) + secdll = LoadLibraryA("security.dll"); + advapi32dll = GetModuleHandleA("advapi32.dll"); + +#define GET_PROC(h, func) p ## func = (void*)GetProcAddress(h, #func) + + if(secdll) + { + GET_PROC(secdll, AcquireCredentialsHandleA); + GET_PROC(secdll, EnumerateSecurityPackagesA); + GET_PROC(secdll, FreeContextBuffer); + GET_PROC(secdll, FreeCredentialsHandle); + GET_PROC(secdll, QueryCredentialsAttributesA); + } + + GET_PROC(advapi32dll, CryptAcquireContextW); + GET_PROC(advapi32dll, CryptDestroyKey); + GET_PROC(advapi32dll, CryptImportKey); + GET_PROC(advapi32dll, CryptReleaseContext); + + GET_PROC(crypt32dll, CertFreeCertificateContext); + GET_PROC(crypt32dll, CertSetCertificateContextProperty); + GET_PROC(crypt32dll, CertCreateCertificateContext); + +#undef GET_PROC +} + +static void test_strength(PCredHandle handle) +{ + SecPkgCred_CipherStrengths strength = {-1,-1}; + SECURITY_STATUS st; + + st = pQueryCredentialsAttributesA(handle, SECPKG_ATTR_CIPHER_STRENGTHS, &strength); + ok(st == SEC_E_OK, "QueryCredentialsAttributesA failed: %u\n", GetLastError()); + ok(strength.dwMinimumCipherStrength, "dwMinimumCipherStrength not changed\n"); + ok(strength.dwMaximumCipherStrength, "dwMaximumCipherStrength not changed\n"); + trace("strength %d - %d\n", strength.dwMinimumCipherStrength, strength.dwMaximumCipherStrength); +} + +static void testAcquireSecurityContext(void) +{ + BOOL has_schannel = FALSE; + SecPkgInfoA *package_info; + ULONG i; + SECURITY_STATUS st; + CredHandle cred; + TimeStamp exp; + SCHANNEL_CRED schanCred; + PCCERT_CONTEXT certs[2]; + HCRYPTPROV csp; + static CHAR unisp_name_a[] = UNISP_NAME_A; + WCHAR ms_def_prov_w[MAX_PATH]; + BOOL ret; + HCRYPTKEY key; + CRYPT_KEY_PROV_INFO keyProvInfo; + + if (!pAcquireCredentialsHandleA || !pCertCreateCertificateContext || + !pEnumerateSecurityPackagesA || !pFreeContextBuffer || + !pFreeCredentialsHandle || !pCryptAcquireContextW) + { + win_skip("Needed functions are not available\n"); + return; + } + + if (SUCCEEDED(pEnumerateSecurityPackagesA(&i, &package_info))) + { + while(i--) + { + if (!strcmp(package_info[i].Name, unisp_name_a)) + { + has_schannel = TRUE; + break; + } + } + pFreeContextBuffer(package_info); + } + if (!has_schannel) + { + skip("Schannel not available\n"); + return; + } + + lstrcpyW(ms_def_prov_w, MS_DEF_PROV_W); + + keyProvInfo.pwszContainerName = cspNameW; + keyProvInfo.pwszProvName = ms_def_prov_w; + keyProvInfo.dwProvType = PROV_RSA_FULL; + keyProvInfo.dwFlags = 0; + keyProvInfo.cProvParam = 0; + keyProvInfo.rgProvParam = NULL; + keyProvInfo.dwKeySpec = AT_SIGNATURE; + + certs[0] = pCertCreateCertificateContext(X509_ASN_ENCODING, bigCert, + sizeof(bigCert)); + certs[1] = pCertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert, + sizeof(selfSignedCert)); + + pCryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + + st = pAcquireCredentialsHandleA(NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, + NULL); + ok(st == SEC_E_SECPKG_NOT_FOUND, + "Expected SEC_E_SECPKG_NOT_FOUND, got %08x\n", st); + if (0) + { + /* Crashes on Win2K */ + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, 0, NULL, NULL, NULL, + NULL, NULL, NULL); + ok(st == SEC_E_NO_CREDENTIALS, "Expected SEC_E_NO_CREDENTIALS, got %08x\n", + st); + } + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_BOTH, NULL, + NULL, NULL, NULL, NULL, NULL); + ok(st == SEC_E_NO_CREDENTIALS, "Expected SEC_E_NO_CREDENTIALS, got %08x\n", + st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, NULL, NULL, NULL, NULL, NULL); + ok(st == SEC_E_NO_CREDENTIALS, "Expected SEC_E_NO_CREDENTIALS, got %08x\n", + st); + if (0) + { + /* Crashes */ + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, NULL, NULL, NULL, NULL, NULL); + } + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, NULL, NULL, NULL, &cred, NULL); + ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st); + if(st == SEC_E_OK) + pFreeCredentialsHandle(&cred); + memset(&cred, 0, sizeof(cred)); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, NULL, NULL, NULL, &cred, &exp); + ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st); + /* expriy is indeterminate in win2k3 */ + trace("expiry: %08x%08x\n", exp.HighPart, exp.LowPart); + pFreeCredentialsHandle(&cred); + + /* Bad version in SCHANNEL_CRED */ + memset(&schanCred, 0, sizeof(schanCred)); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, NULL, NULL); + ok(st == SEC_E_INTERNAL_ERROR || + st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */, + "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, NULL, NULL); + ok(st == SEC_E_INTERNAL_ERROR || + st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */, + "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + + /* No cert in SCHANNEL_CRED succeeds for outbound.. */ + schanCred.dwVersion = SCHANNEL_CRED_VERSION; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st); + pFreeCredentialsHandle(&cred); + /* but fails for inbound. */ + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_NO_CREDENTIALS || + st == SEC_E_OK /* Vista/win2k8 */, + "Expected SEC_E_NO_CREDENTIALS or SEC_E_OK, got %08x\n", st); + + if (0) + { + /* Crashes with bad paCred pointer */ + schanCred.cCreds = 1; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, NULL, NULL); + } + + /* Bogus cert in SCHANNEL_CRED. Windows fails with + * SEC_E_UNKNOWN_CREDENTIALS, but I'll accept SEC_E_NO_CREDENTIALS too. + */ + schanCred.cCreds = 1; + schanCred.paCred = &certs[0]; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, NULL, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS || st == SEC_E_NO_CREDENTIALS, + "Expected SEC_E_UNKNOWN_CREDENTIALS or SEC_E_NO_CREDENTIALS, got %08x\n", + st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, NULL, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS || st == SEC_E_NO_CREDENTIALS, + "Expected SEC_E_UNKNOWN_CREDENTIALS or SEC_E_NO_CREDENTIALS, got %08x\n", + st); + + /* Good cert, but missing private key. Windows fails with + * SEC_E_NO_CREDENTIALS, but I'll accept SEC_E_UNKNOWN_CREDENTIALS too. + */ + schanCred.cCreds = 1; + schanCred.paCred = &certs[1]; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS || st == SEC_E_NO_CREDENTIALS || + st == SEC_E_INTERNAL_ERROR, /* win2k */ + "Expected SEC_E_UNKNOWN_CREDENTIALS, SEC_E_NO_CREDENTIALS " + "or SEC_E_INTERNAL_ERROR, got %08x\n", st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, NULL, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS || st == SEC_E_NO_CREDENTIALS || + st == SEC_E_INTERNAL_ERROR, /* win2k */ + "Expected SEC_E_UNKNOWN_CREDENTIALS, SEC_E_NO_CREDENTIALS " + "or SEC_E_INTERNAL_ERROR, got %08x\n", st); + + /* Good cert, with CRYPT_KEY_PROV_INFO set before it's had a key loaded. */ + if (pCertSetCertificateContextProperty) + { + ret = pCertSetCertificateContextProperty(certs[1], + CERT_KEY_PROV_INFO_PROP_ID, 0, &keyProvInfo); + schanCred.dwVersion = SCH_CRED_V3; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS, + "Expected SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS, + "Expected SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + } + + ret = pCryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL, + CRYPT_NEWKEYSET); + ok(ret, "CryptAcquireContextW failed: %08x\n", GetLastError()); + ret = 0; + if (pCryptImportKey) + { + ret = pCryptImportKey(csp, privKey, sizeof(privKey), 0, 0, &key); + ok(ret, "CryptImportKey failed: %08x\n", GetLastError()); + } + if (ret) + { + PCCERT_CONTEXT tmp; + + if (0) + { + /* Crashes */ + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, NULL, NULL); + } + /* Good cert with private key, bogus version */ + schanCred.dwVersion = SCH_CRED_V1; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_INTERNAL_ERROR || + st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */, + "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_INTERNAL_ERROR || + st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */, + "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + schanCred.dwVersion = SCH_CRED_V2; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_INTERNAL_ERROR || + st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */, + "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_INTERNAL_ERROR || + st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */, + "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + + /* Succeeds on V3 or higher */ + schanCred.dwVersion = SCH_CRED_V3; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st); + pFreeCredentialsHandle(&cred); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_OK || + st == SEC_E_UNKNOWN_CREDENTIALS, /* win2k3 */ + "AcquireCredentialsHandleA failed: %08x\n", st); + pFreeCredentialsHandle(&cred); + schanCred.dwVersion = SCHANNEL_CRED_VERSION; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st); + pFreeCredentialsHandle(&cred); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_OK || + st == SEC_E_UNKNOWN_CREDENTIALS, /* win2k3 */ + "AcquireCredentialsHandleA failed: %08x\n", st); + if (st == SEC_E_OK) test_strength(&cred); + pFreeCredentialsHandle(&cred); + + /* How about more than one cert? */ + schanCred.cCreds = 2; + schanCred.paCred = certs; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS || + st == SEC_E_NO_CREDENTIALS /* Vista/win2k8 */, + "Expected SEC_E_UNKNOWN_CREDENTIALS or SEC_E_NO_CREDENTIALS, got %08x\n", st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS || + st == SEC_E_NO_CREDENTIALS, + "Expected SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + tmp = certs[0]; + certs[0] = certs[1]; + certs[1] = tmp; + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS || + st == SEC_E_NO_CREDENTIALS, + "Expected SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, + NULL, &schanCred, NULL, NULL, &cred, NULL); + ok(st == SEC_E_UNKNOWN_CREDENTIALS, + "Expected SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st); + /* FIXME: what about two valid certs? */ + + if (pCryptDestroyKey) + pCryptDestroyKey(key); + } + + if (pCryptReleaseContext) + pCryptReleaseContext(csp, 0); + pCryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL, + CRYPT_DELETEKEYSET); + + if (pCertFreeCertificateContext) + { + pCertFreeCertificateContext(certs[0]); + pCertFreeCertificateContext(certs[1]); + } +} + +START_TEST(schannel) +{ + InitFunctionPtrs(); + + testAcquireSecurityContext(); + + if(secdll) + FreeLibrary(secdll); + if(crypt32dll) + FreeLibrary(crypt32dll); +} diff --git a/rostests/winetests/secur32/secur32.c b/rostests/winetests/secur32/secur32.c new file mode 100644 index 00000000000..21bb83a5cba --- /dev/null +++ b/rostests/winetests/secur32/secur32.c @@ -0,0 +1,265 @@ +/* + * tests + * + * Copyright 2006 Robert Reif + * + * 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 + */ +#include +#include +#include +#include +#include +#define SECURITY_WIN32 +#include +#include + +#include "wine/test.h" + +static HMODULE secdll; + +static BOOLEAN (WINAPI * pGetComputerObjectNameA)(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG lpnSize); +static BOOLEAN (WINAPI * pGetComputerObjectNameW)(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG lpnSize); +static BOOLEAN (WINAPI * pGetUserNameExA)(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG lpnSize); +static BOOLEAN (WINAPI * pGetUserNameExW)(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG lpnSize); +static PSecurityFunctionTableA (SEC_ENTRY * pInitSecurityInterfaceA)(void); +static PSecurityFunctionTableW (SEC_ENTRY * pInitSecurityInterfaceW)(void); + +static EXTENDED_NAME_FORMAT formats[] = { + NameUnknown, NameFullyQualifiedDN, NameSamCompatible, NameDisplay, + NameUniqueId, NameCanonical, NameUserPrincipal, NameCanonicalEx, + NameServicePrincipal, NameDnsDomain +}; + +static void testGetComputerObjectNameA(void) +{ + char name[256]; + ULONG size; + BOOLEAN rc; + int i; + + for (i = 0; i < (sizeof(formats) / sizeof(formats[0])); i++) { + size = sizeof(name); + ZeroMemory(name, sizeof(name)); + rc = pGetComputerObjectNameA(formats[i], name, &size); + ok(rc || ((formats[i] == NameUnknown) && + (GetLastError() == ERROR_INVALID_PARAMETER)) || + (GetLastError() == ERROR_CANT_ACCESS_DOMAIN_INFO) || + (GetLastError() == ERROR_NO_SUCH_DOMAIN) || + (GetLastError() == ERROR_NO_SUCH_USER) || + (GetLastError() == ERROR_NONE_MAPPED) || + (GetLastError() == ERROR_ACCESS_DENIED), + "GetComputerObjectNameA(%d) failed: %d\n", + formats[i], GetLastError()); + if (rc) + trace("GetComputerObjectNameA() returned %s\n", name); + } +} + +static void testGetComputerObjectNameW(void) +{ + WCHAR nameW[256]; + ULONG size; + BOOLEAN rc; + int i; + + for (i = 0; i < (sizeof(formats) / sizeof(formats[0])); i++) { + size = sizeof(nameW)/sizeof(nameW[0]); + ZeroMemory(nameW, sizeof(nameW)); + rc = pGetComputerObjectNameW(formats[i], nameW, &size); + ok(rc || ((formats[i] == NameUnknown) && + (GetLastError() == ERROR_INVALID_PARAMETER)) || + (GetLastError() == ERROR_CANT_ACCESS_DOMAIN_INFO) || + (GetLastError() == ERROR_NO_SUCH_DOMAIN) || + (GetLastError() == ERROR_NO_SUCH_USER) || + (GetLastError() == ERROR_NONE_MAPPED) || + (GetLastError() == ERROR_ACCESS_DENIED), + "GetComputerObjectNameW(%d) failed: %d\n", + formats[i], GetLastError()); + if (rc) { + char name[256]; + WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, sizeof(name), NULL, NULL ); + trace("GetComputerObjectNameW() returned %s\n", name); + } + } +} + +static void testGetUserNameExA(void) +{ + char name[256]; + ULONG size; + BOOLEAN rc; + int i; + + for (i = 0; i < (sizeof(formats) / sizeof(formats[0])); i++) { + size = sizeof(name); + ZeroMemory(name, sizeof(name)); + rc = pGetUserNameExA(formats[i], name, &size); + ok(rc || + (formats[i] == NameUnknown && + GetLastError() == ERROR_NO_SUCH_USER) || + GetLastError() == ERROR_NONE_MAPPED || + broken(formats[i] == NameDnsDomain && + GetLastError() == ERROR_INVALID_PARAMETER), + "GetUserNameExW(%d) failed: %d\n", + formats[i], GetLastError()); + } + + if (0) /* Crashes on Windows */ + rc = pGetUserNameExA(NameSamCompatible, NULL, NULL); + + size = 0; + rc = pGetUserNameExA(NameSamCompatible, NULL, &size); + ok(! rc && GetLastError() == ERROR_MORE_DATA, "Expected fail with ERROR_MORE_DATA, got %d with %u\n", rc, GetLastError()); + ok(size != 0, "Expected size to be set to required size\n"); + + if (0) /* Crashes on Windows with big enough size */ + { + /* Returned size is already big enough */ + rc = pGetUserNameExA(NameSamCompatible, NULL, &size); + } + + size = 0; + rc = pGetUserNameExA(NameSamCompatible, name, &size); + ok(! rc && GetLastError() == ERROR_MORE_DATA, "Expected fail with ERROR_MORE_DATA, got %d with %u\n", rc, GetLastError()); + ok(size != 0, "Expected size to be set to required size\n"); + size = 1; + name[0] = 0xff; + rc = pGetUserNameExA(NameSamCompatible, name, &size); + ok(! rc && GetLastError() == ERROR_MORE_DATA, "Expected fail with ERROR_MORE_DATA, got %d with %u\n", rc, GetLastError()); + ok(1 < size, "Expected size to be set to required size\n"); + ok(name[0] == (char) 0xff, "Expected unchanged buffer\n"); +} + +static void testGetUserNameExW(void) +{ + WCHAR nameW[256]; + ULONG size; + BOOLEAN rc; + int i; + + for (i = 0; i < (sizeof(formats) / sizeof(formats[0])); i++) { + size = sizeof(nameW); + ZeroMemory(nameW, sizeof(nameW)); + rc = pGetUserNameExW(formats[i], nameW, &size); + ok(rc || + (formats[i] == NameUnknown && + GetLastError() == ERROR_NO_SUCH_USER) || + GetLastError() == ERROR_NONE_MAPPED || + broken(formats[i] == NameDnsDomain && + GetLastError() == ERROR_INVALID_PARAMETER), + "GetUserNameExW(%d) failed: %d\n", + formats[i], GetLastError()); + } + + if (0) /* Crashes on Windows */ + rc = pGetUserNameExW(NameSamCompatible, NULL, NULL); + + size = 0; + rc = pGetUserNameExW(NameSamCompatible, NULL, &size); + ok(! rc && GetLastError() == ERROR_MORE_DATA, "Expected fail with ERROR_MORE_DATA, got %d with %u\n", rc, GetLastError()); + ok(size != 0, "Expected size to be set to required size\n"); + + if (0) /* Crashes on Windows with big enough size */ + { + /* Returned size is already big enough */ + rc = pGetUserNameExW(NameSamCompatible, NULL, &size); + } + + size = 0; + rc = pGetUserNameExW(NameSamCompatible, nameW, &size); + ok(! rc && GetLastError() == ERROR_MORE_DATA, "Expected fail with ERROR_MORE_DATA, got %d with %u\n", rc, GetLastError()); + ok(size != 0, "Expected size to be set to required size\n"); + size = 1; + nameW[0] = 0xff; + rc = pGetUserNameExW(NameSamCompatible, nameW, &size); + ok(! rc && GetLastError() == ERROR_MORE_DATA, "Expected fail with ERROR_MORE_DATA, got %d with %u\n", rc, GetLastError()); + ok(1 < size, "Expected size to be set to required size\n"); + ok(nameW[0] == (WCHAR) 0xff, "Expected unchanged buffer\n"); +} + +static void test_InitSecurityInterface(void) +{ + PSecurityFunctionTableA sftA; + PSecurityFunctionTableW sftW; + + sftA = pInitSecurityInterfaceA(); + ok(sftA != NULL, "pInitSecurityInterfaceA failed\n"); + ok(sftA->dwVersion == SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION, "wrong dwVersion %d in security function table\n", sftA->dwVersion); + ok(!sftA->Reserved2 || broken(sftA->Reserved2 != NULL) /* WinME */, + "Reserved2 should be NULL instead of %p in security function table\n", + sftA->Reserved2); + ok(sftA->Reserved3 == sftA->EncryptMessage || + broken(sftA->Reserved3 != sftA->EncryptMessage) /* Win9x */, + "Reserved3 should be equal to EncryptMessage in the security function table\n"); + ok(sftA->Reserved4 == sftA->DecryptMessage || + broken(sftA->Reserved4 != sftA->DecryptMessage) /* Win9x */, + "Reserved4 should be equal to DecryptMessage in the security function table\n"); + + if (!pInitSecurityInterfaceW) + { + win_skip("InitSecurityInterfaceW not exported by secur32.dll\n"); + return; + } + + sftW = pInitSecurityInterfaceW(); + ok(sftW != NULL, "pInitSecurityInterfaceW failed\n"); + ok(sftW->dwVersion == SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION, "wrong dwVersion %d in security function table\n", sftW->dwVersion); + ok(!sftW->Reserved2, "Reserved2 should be NULL instead of %p in security function table\n", sftW->Reserved2); + ok(sftW->Reserved3 == sftW->EncryptMessage, "Reserved3 should be equal to EncryptMessage in the security function table\n"); + ok(sftW->Reserved4 == sftW->DecryptMessage, "Reserved4 should be equal to DecryptMessage in the security function table\n"); +} + +START_TEST(secur32) +{ + secdll = LoadLibraryA("secur32.dll"); + + if (!secdll) + secdll = LoadLibraryA("security.dll"); + + if (secdll) + { + pGetComputerObjectNameA = (PVOID)GetProcAddress(secdll, "GetComputerObjectNameA"); + pGetComputerObjectNameW = (PVOID)GetProcAddress(secdll, "GetComputerObjectNameW"); + pGetUserNameExA = (PVOID)GetProcAddress(secdll, "GetUserNameExA"); + pGetUserNameExW = (PVOID)GetProcAddress(secdll, "GetUserNameExW"); + pInitSecurityInterfaceA = (PVOID)GetProcAddress(secdll, "InitSecurityInterfaceA"); + pInitSecurityInterfaceW = (PVOID)GetProcAddress(secdll, "InitSecurityInterfaceW"); + + if (pGetComputerObjectNameA) + testGetComputerObjectNameA(); + else + win_skip("GetComputerObjectNameA not exported by secur32.dll\n"); + + if (pGetComputerObjectNameW) + testGetComputerObjectNameW(); + else + win_skip("GetComputerObjectNameW not exported by secur32.dll\n"); + + if (pGetUserNameExA) + testGetUserNameExA(); + else + win_skip("GetUserNameExA not exported by secur32.dll\n"); + + if (pGetUserNameExW) + testGetUserNameExW(); + else + win_skip("GetUserNameExW not exported by secur32.dll\n"); + + test_InitSecurityInterface(); + + FreeLibrary(secdll); + } +} diff --git a/rostests/winetests/secur32/secur32.rbuild b/rostests/winetests/secur32/secur32.rbuild new file mode 100644 index 00000000000..9aa670f26fb --- /dev/null +++ b/rostests/winetests/secur32/secur32.rbuild @@ -0,0 +1,12 @@ + + . + + main.c + ntlm.c + schannel.c + secur32.c + testlist.c + wine + advapi32 + ntdll + diff --git a/rostests/winetests/secur32/testlist.c b/rostests/winetests/secur32/testlist.c new file mode 100644 index 00000000000..cc04b8414f0 --- /dev/null +++ b/rostests/winetests/secur32/testlist.c @@ -0,0 +1,21 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_secur32(void); +extern void func_schannel(void); +extern void func_ntlm(void); +extern void func_main(void); + +const struct test winetest_testlist[] = +{ + { "secur32", func_secur32 }, + { "schannel", func_schannel }, + { "ntlm", func_ntlm }, + { "main", func_main }, + { 0, 0 } +}; diff --git a/rostests/winetests/serialui/confdlg.c b/rostests/winetests/serialui/confdlg.c new file mode 100644 index 00000000000..4606a75b60b --- /dev/null +++ b/rostests/winetests/serialui/confdlg.c @@ -0,0 +1,431 @@ +/* + * Unit test suite for serialui API functions + * + * Copyright 2007 Detlef Riekenberg + * + * 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 + * + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" + +#include "wine/test.h" + + +static HINSTANCE hdll; +static DWORD (WINAPI *pCommConfigDialogA)(LPCSTR, HWND, LPCOMMCONFIG); +static DWORD (WINAPI *pCommConfigDialogW)(LPCWSTR, HWND, LPCOMMCONFIG); +static DWORD (WINAPI *pGetDefaultCommConfigA)(LPCSTR, LPCOMMCONFIG, LPDWORD); +static DWORD (WINAPI *pGetDefaultCommConfigW)(LPCWSTR, LPCOMMCONFIG, LPDWORD); + + +static const CHAR com1A[] = "com1"; +static const CHAR emptyA[] = ""; +static const CHAR fmt_comA[] = "com%d"; +static const CHAR str_colonA[] = ":"; + +static const WCHAR com1W[] = {'c','o','m','1',0}; +static const WCHAR emptyW[] = {0}; +static const WCHAR str_colonW[] = {':',0}; + +/* ################# */ + +static LPCSTR load_functions(void) +{ + LPCSTR ptr; + + ptr = "serialui.dll"; + hdll = LoadLibraryA(ptr); + if (!hdll) return ptr; + + ptr = "drvCommConfigDialogA"; + pCommConfigDialogA = (VOID *) GetProcAddress(hdll, ptr); + if (!pCommConfigDialogA) return ptr; + + ptr = "drvCommConfigDialogW"; + pCommConfigDialogW = (VOID *) GetProcAddress(hdll, ptr); + if (!pCommConfigDialogW) return ptr; + + ptr = "drvGetDefaultCommConfigA"; + pGetDefaultCommConfigA = (VOID *) GetProcAddress(hdll, ptr); + if (!pGetDefaultCommConfigA) return ptr; + + ptr = "drvGetDefaultCommConfigW"; + pGetDefaultCommConfigW = (VOID *) GetProcAddress(hdll, ptr); + if (!pGetDefaultCommConfigW) return ptr; + + + return NULL; +} + +/* ################# */ + +static void test_drvCommConfigDialogA(void) +{ + COMMCONFIG pCC[3]; + CHAR bufferA[16]; + DWORD i; + DWORD res; + DWORD len; + + + /* test ports "com1" - "com4" */ + for (i = 1; i < 5 ; i++) { + sprintf(bufferA, fmt_comA, i); + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigA(bufferA, pCC, &len); + if (res == ERROR_CALL_NOT_IMPLEMENTED) { + /* NT does not implement the ANSI API */ + win_skip("*A not implemented\n"); + return; + } + + if (res == ERROR_SUCCESS) { + + if (winetest_interactive) { + SetLastError(0xdeadbeef); + res = pCommConfigDialogA(bufferA, NULL, pCC); + /* OK: ERROR_SUCCESS, Cancel: ERROR_CANCELLED */ + trace("returned %u with %u for '%s'\n", res, GetLastError(), bufferA); + } + + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pCommConfigDialogA(bufferA, NULL, pCC); + ok( res == ERROR_INSUFFICIENT_BUFFER, + "returned %u with %u for '%s' (expected ERROR_INSUFFICIENT_BUFFER)\n", + res, GetLastError(), bufferA); + + + SetLastError(0xdeadbeef); + res = pCommConfigDialogA(bufferA, NULL, NULL); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u for '%s' (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError(), bufferA); + } + } + + + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pCommConfigDialogA(emptyA, NULL, pCC); + ok( res == ERROR_INSUFFICIENT_BUFFER, + "returned %u with %u (expected ERROR_INSUFFICIENT_BUFFER)\n", + res, GetLastError()); + + + ZeroMemory(pCC, sizeof(pCC)); + pCC[0].dwSize = sizeof(COMMCONFIG); + SetLastError(0xdeadbeef); + res = pCommConfigDialogA(emptyA, NULL, pCC); + ok( res == ERROR_BADKEY, "returned %u with %u (expected ERROR_BADKEY)\n", + res, GetLastError()); + + + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pCommConfigDialogA(NULL, NULL, pCC); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); +} + +/* ################# */ + +static void test_drvCommConfigDialogW(void) +{ + COMMCONFIG pCC[3]; + CHAR bufferA[16]; + WCHAR bufferW[16]; + DWORD i; + DWORD res; + DWORD len; + + + /* test ports "com1" - "com4" */ + for (i = 1; i < 5 ; i++) { + sprintf(bufferA, fmt_comA, i); + MultiByteToWideChar( CP_ACP, 0, bufferA, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ); + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigW(bufferW, pCC, &len); + if (res == ERROR_CALL_NOT_IMPLEMENTED) { + win_skip("*W not implemented\n"); + return; + } + + if (res == ERROR_SUCCESS) { + + if (winetest_interactive) { + SetLastError(0xdeadbeef); + res = pCommConfigDialogW(bufferW, NULL, pCC); + /* OK: ERROR_SUCCESS, Cancel: ERROR_CANCELLED */ + trace("returned %u with %u for '%s'\n", res, GetLastError(), bufferA); + } + + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pCommConfigDialogW(bufferW, NULL, pCC); + ok( res == ERROR_INSUFFICIENT_BUFFER, + "returned %u with %u for '%s' (expected ERROR_INSUFFICIENT_BUFFER)\n", + res, GetLastError(), bufferA); + + SetLastError(0xdeadbeef); + res = pCommConfigDialogW(bufferW, NULL, NULL); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u for '%s' (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError(), bufferA); + } + } + + + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pCommConfigDialogW(emptyW, NULL, pCC); + ok( res == ERROR_INSUFFICIENT_BUFFER, + "returned %u with %u (expected ERROR_INSUFFICIENT_BUFFER)\n", + res, GetLastError()); + + + ZeroMemory(pCC, sizeof(pCC)); + pCC[0].dwSize = sizeof(COMMCONFIG); + SetLastError(0xdeadbeef); + res = pCommConfigDialogW(emptyW, NULL, pCC); + ok( res == ERROR_BADKEY, "returned %u with %u (expected ERROR_BADKEY)\n", + res, GetLastError()); + + + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pCommConfigDialogW(NULL, NULL, pCC); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); +} + + +/* ################# */ + +static void test_drvGetDefaultCommConfigA(void) +{ + COMMCONFIG pCC[3]; + CHAR bufferA[16]; + DWORD i; + DWORD res; + DWORD len; + + + /* off by one: one byte smaller */ + i = sizeof(COMMCONFIG); + len = sizeof(COMMCONFIG) -1; + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigA(com1A, pCC, &len); + if (res == ERROR_CALL_NOT_IMPLEMENTED) { + /* NT does not implement the ANSI API */ + win_skip("*A not implemented\n"); + return; + } + ok( (res == ERROR_INSUFFICIENT_BUFFER) && (len >= i), + "returned %u with %u and %u (expected " + "ERROR_INSUFFICIENT_BUFFER and '>= %u')\n", res, GetLastError(), len, i); + + /* test ports "com0" - "com10" */ + for (i = 0; i < 11 ; i++) { + sprintf(bufferA, fmt_comA, i); + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigA(bufferA, pCC, &len); + if (i == 0) { + ok( res == ERROR_BADKEY, + "returned %u with %u and %u for %s (expected " + "ERROR_BADKEY)\n", res, GetLastError(), len, bufferA); + } + else + { + ok((res == ERROR_SUCCESS) || (res == ERROR_BADKEY), + "returned %u with %u and %u for %s (expected ERROR_SUCCESS or " + "ERROR_BADKEY)\n", res, GetLastError(), len, bufferA); + } + + /* a name with a colon is invalid */ + if (res == ERROR_SUCCESS) { + lstrcatA(bufferA, str_colonA); + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + res = pGetDefaultCommConfigA(bufferA, pCC, &len); + ok( res == ERROR_BADKEY, + "returned %u with %u and %u for %s (expected '0' with " + "ERROR_BADKEY)\n", res, GetLastError(), len, bufferA); + } + } + + + /* an empty String is not allowed */ + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigA(emptyA, pCC, &len); + ok( res == ERROR_BADKEY, + "returned %u with %u and %u for %s (expected ERROR_BADKEY)\n", + res, GetLastError(), len, emptyA); + + /* some NULL checks */ + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigA(NULL, pCC, &len); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u and %u for NULL (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError(), len); + + + len = sizeof(pCC); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigA(com1A, NULL, &len); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u and %u (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError(), len); + + + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigA(com1A, pCC, NULL); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); +} + +/* ################# */ + +static void test_drvGetDefaultCommConfigW(void) +{ + COMMCONFIG pCC[3]; + WCHAR bufferW[16]; + CHAR bufferA[16]; + DWORD i; + DWORD res; + DWORD len; + + + /* off by one: one byte smaller */ + i = sizeof(COMMCONFIG); + len = sizeof(COMMCONFIG) -1; + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigW(com1W, pCC, &len); + if (res == ERROR_CALL_NOT_IMPLEMENTED) { + win_skip("*W not implemented\n"); + return; + } + ok( (res == ERROR_INSUFFICIENT_BUFFER) && (len >= i), + "returned %u with %u and %u (expected " + "ERROR_INSUFFICIENT_BUFFER and '>= %u')\n", res, GetLastError(), len, i); + + /* test ports "com0" - "com10" */ + for (i = 0; i < 11 ; i++) { + sprintf(bufferA, fmt_comA, i); + MultiByteToWideChar( CP_ACP, 0, bufferA, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ); + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigW(bufferW, pCC, &len); + if (i == 0) { + ok( res == ERROR_BADKEY, + "returned %u with %u and %u for %s (expected " + "ERROR_BADKEY)\n", res, GetLastError(), len, bufferA); + } + else + { + ok((res == ERROR_SUCCESS) || (res == ERROR_BADKEY), + "returned %u with %u and %u for %s (expected ERROR_SUCCESS or " + "ERROR_BADKEY)\n", res, GetLastError(), len, bufferA); + } + + /* a name with a colon is invalid */ + if (res == ERROR_SUCCESS) { + lstrcatA(bufferA, str_colonA); + lstrcatW(bufferW, str_colonW); + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + res = pGetDefaultCommConfigW(bufferW, pCC, &len); + ok( res == ERROR_BADKEY, + "returned %u with %u and %u for %s (expected '0' with " + "ERROR_BADKEY)\n", res, GetLastError(), len, bufferA); + } + } + + /* an empty String is not allowed */ + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigW(emptyW, pCC, &len); + ok( res == ERROR_BADKEY, + "returned %u with %u and %u for %s (expected ERROR_BADKEY)\n", + res, GetLastError(), len, emptyA); + + /* some NULL checks */ + len = sizeof(pCC); + ZeroMemory(pCC, sizeof(pCC)); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigW(NULL, pCC, &len); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u and %u for NULL (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError(), len); + + + len = sizeof(pCC); + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigW(com1W, NULL, &len); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u and %u (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError(), len); + + + SetLastError(0xdeadbeef); + res = pGetDefaultCommConfigW(com1W, pCC, NULL); + ok( res == ERROR_INVALID_PARAMETER, + "returned %u with %u (expected ERROR_INVALID_PARAMETER)\n", + res, GetLastError()); + +} + +/* ################# */ + +START_TEST(confdlg) +{ + LPCSTR ptr; + + ptr = load_functions(); + if (ptr) { + win_skip("got NULL with %u for %s\n", GetLastError(), ptr); + return; + } + + test_drvCommConfigDialogA(); + test_drvCommConfigDialogW(); + test_drvGetDefaultCommConfigA(); + test_drvGetDefaultCommConfigW(); + +} diff --git a/rostests/winetests/serialui/serialui.rbuild b/rostests/winetests/serialui/serialui.rbuild new file mode 100644 index 00000000000..9c5e14d62ec --- /dev/null +++ b/rostests/winetests/serialui/serialui.rbuild @@ -0,0 +1,8 @@ + + . + + confdlg.c + testlist.c + wine + ntdll + diff --git a/rostests/winetests/serialui/testlist.c b/rostests/winetests/serialui/testlist.c new file mode 100644 index 00000000000..f4b05a73b78 --- /dev/null +++ b/rostests/winetests/serialui/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_confdlg(void); + +const struct test winetest_testlist[] = +{ + { "confdlg", func_confdlg }, + { 0, 0 } +}; diff --git a/rostests/winetests/setupapi/devclass.c b/rostests/winetests/setupapi/devclass.c index 212b0eb0bba..b525c980b57 100644 --- a/rostests/winetests/setupapi/devclass.c +++ b/rostests/winetests/setupapi/devclass.c @@ -22,6 +22,7 @@ #include #include +#undef __ROS_LONG64__ #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -68,9 +69,9 @@ static void test_SetupDiBuildClassInfoList(void) SetLastError( 0xdeadbeef ); ok( !SetupDiBuildClassInfoList( 0, NULL, 0, &required_size ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected error %lx, got %lx", ERROR_INSUFFICIENT_BUFFER, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INSUFFICIENT_BUFFER, GetLastError() ); guid_list = HeapAlloc( GetProcessHeap(), 0, ( required_size + 1 ) * sizeof( GUID ) ); if ( !guid_list ) @@ -78,12 +79,12 @@ static void test_SetupDiBuildClassInfoList(void) SetLastError( 0xdeadbeef ); ok( SetupDiBuildClassInfoList( 0, guid_list, required_size, &size ), - "Error reported %lx", GetLastError() ); - ok( size == required_size, "Expected size %lu, got %lu", required_size, size ); + "Error reported %lx\n", GetLastError() ); + ok( size == required_size, "Expected size %lu, got %lu\n", required_size, size ); SetLastError( 0xdeadbeef ); ok( SetupDiBuildClassInfoList( 0, guid_list, required_size + 1, &size ), - "Error reported %lx", GetLastError() ); - ok( size == required_size, "Expected size %lu, got %lu", required_size, size ); + "Error reported %lx\n", GetLastError() ); + ok( size == required_size, "Expected size %lu, got %lu\n", required_size, size ); if ( size > 0 ) { @@ -101,28 +102,27 @@ static void test_SetupDiClassGuidsFromNameA(void) SetLastError( 0xdeadbeef ); ok( !SetupDiClassGuidsFromNameA( NULL, NULL, 0, NULL ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, - "Expected error %lx, got %lx", ERROR_INVALID_PARAMETER, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_PARAMETER, GetLastError() ); SetLastError( 0xdeadbeef ); ok( !SetupDiClassGuidsFromNameA( NULL, NULL, 0, &required_size ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, - "Expected error %lx, got %lx", ERROR_INVALID_PARAMETER, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_PARAMETER, GetLastError() ); SetLastError( 0xdeadbeef ); ok( SetupDiClassGuidsFromNameA( "", NULL, 0, &required_size ), - "Error reported %lx", GetLastError() ); - ok( required_size == 0, "Expected 0, got %lu", required_size ); + "Error reported %lx\n", GetLastError() ); + ok( required_size == 0, "Expected 0, got %lu\n", required_size ); SetLastError( 0xdeadbeef ); ok( !SetupDiClassGuidsFromNameA( test_class_name, NULL, 0, &required_size ), - "Fail expected" ); - SetLastError( 0xdeadbeef ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected error %lx, got %lx", ERROR_INSUFFICIENT_BUFFER, GetLastError() ); - ok( required_size > 0, "Expected > 0, got %lu", required_size ); + "Expected error %lx, got %lx\n", ERROR_INSUFFICIENT_BUFFER, GetLastError() ); + ok( required_size > 0, "Expected > 0, got %lu\n", required_size ); guid_list = HeapAlloc( GetProcessHeap(), 0, ( required_size + 1 ) * sizeof( GUID ) ); if ( !guid_list ) @@ -130,16 +130,16 @@ static void test_SetupDiClassGuidsFromNameA(void) SetLastError( 0xdeadbeef ); ok( SetupDiClassGuidsFromNameA( test_class_name, guid_list, required_size, &size ), - "Error reported %lx", GetLastError() ); - ok( size == required_size, "Expected size %lu, got %lu", required_size, size ); + "Error reported %lx\n", GetLastError() ); + ok( size == required_size, "Expected size %lu, got %lu\n", required_size, size ); ok( IsEqualIID( &guid_list[0], &test_class_guid ), - "Expected %s, got %s", debugstr_guid( &test_class_guid ), debugstr_guid( &guid_list[0] ) ); + "Expected %s, got %s\n", debugstr_guid( &test_class_guid ), debugstr_guid( &guid_list[0] ) ); SetLastError( 0xdeadbeef ); ok( SetupDiClassGuidsFromNameA( test_class_name, guid_list, required_size + 1, &size ), - "Error reported %lx", GetLastError() ); - ok( size == required_size, "Expected size %lu, got %lu", required_size, size ); + "Error reported %lx\n", GetLastError() ); + ok( size == required_size, "Expected size %lu, got %lu\n", required_size, size ); ok( IsEqualIID( &guid_list[0], &test_class_guid ), - "Expected %s, got %s", debugstr_guid( &test_class_guid ), debugstr_guid( &guid_list[0] ) ); + "Expected %s, got %s\n", debugstr_guid( &test_class_guid ), debugstr_guid( &guid_list[0] ) ); HeapFree( GetProcessHeap(), 0, guid_list ); } @@ -151,23 +151,23 @@ static void test_SetupDiClassNameFromGuidA(void) SetLastError( 0xdeadbeef ); ok( !SetupDiClassNameFromGuidA( NULL, NULL, 0, NULL ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_CLASS, - "Expected error %x, got %lx", ERROR_INVALID_CLASS, GetLastError() ); + "Expected error %x, got %lx\n", ERROR_INVALID_CLASS, GetLastError() ); SetLastError( 0xdeadbeef ); ok( !SetupDiClassNameFromGuidA( NULL, NULL, 0, &required_size ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_CLASS, - "Expected error %x, got %lx", ERROR_INVALID_CLASS, GetLastError() ); + "Expected error %x, got %lx\n", ERROR_INVALID_CLASS, GetLastError() ); SetLastError( 0xdeadbeef ); ok( !SetupDiClassNameFromGuidA( &test_class_guid, NULL, 0, &required_size ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected error %lx, got %lx", ERROR_INSUFFICIENT_BUFFER, GetLastError() ); - ok( required_size > 0, "Expected > 0, got %lu", required_size ); - ok( required_size < MAX_CLASS_NAME_LEN, "Expected < %u, got %lu", MAX_CLASS_NAME_LEN, required_size ); + "Expected error %lx, got %lx\n", ERROR_INSUFFICIENT_BUFFER, GetLastError() ); + ok( required_size > 0, "Expected > 0, got %lu\n", required_size ); + ok( required_size < MAX_CLASS_NAME_LEN, "Expected < %u, got %lu\n", MAX_CLASS_NAME_LEN, required_size ); class_name = HeapAlloc( GetProcessHeap(), 0, required_size ); if ( !class_name ) @@ -175,16 +175,16 @@ static void test_SetupDiClassNameFromGuidA(void) SetLastError( 0xdeadbeef ); ok( SetupDiClassNameFromGuidA( &test_class_guid, class_name, required_size, &size ), - "Error reported %lx", GetLastError() ); - ok( size == required_size, "Expected size %lu, got %lu", required_size, size ); + "Error reported %lx\n", GetLastError() ); + ok( size == required_size, "Expected size %lu, got %lu\n", required_size, size ); ok( !strcmp( class_name, test_class_name ), - "Expected %s, got %s", test_class_name, class_name ); + "Expected %s, got %s\n", test_class_name, class_name ); SetLastError( 0xdeadbeef ); ok( SetupDiClassNameFromGuidA( &test_class_guid, class_name, required_size + 1, &size ), - "Error reported %lx", GetLastError() ); - ok( size == required_size, "Expected size %lu, got %lu", required_size, size ); + "Error reported %lx\n", GetLastError() ); + ok( size == required_size, "Expected size %lu, got %lu\n", required_size, size ); ok( !strcmp( class_name, test_class_name ), - "Expected %s, got %s", test_class_name, class_name ); + "Expected %s, got %s\n", test_class_name, class_name ); HeapFree( GetProcessHeap(), 0, class_name ); } @@ -196,23 +196,23 @@ static void test_SetupDiGetClassDescriptionA(void) SetLastError( 0xdeadbeef ); ok( !SetupDiGetClassDescriptionA( NULL, NULL, 0, NULL ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, - "Expected error %lx, got %lx", ERROR_INVALID_PARAMETER, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_PARAMETER, GetLastError() ); SetLastError( 0xdeadbeef ); ok( !SetupDiGetClassDescriptionA( NULL, NULL, 0, &required_size ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, - "Expected error %lx, got %lx", ERROR_INVALID_PARAMETER, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_PARAMETER, GetLastError() ); SetLastError( 0xdeadbeef ); ok( !SetupDiGetClassDescriptionA( &test_class_guid, NULL, 0, &required_size ), - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, - "Expected error %lx, got %lx", ERROR_INSUFFICIENT_BUFFER, GetLastError() ); - ok( required_size > 0, "Expected > 0, got %lu", required_size ); - ok( required_size < LINE_LEN, "Expected < %u, got %lu", LINE_LEN, required_size ); + "Expected error %lx, got %lx\n", ERROR_INSUFFICIENT_BUFFER, GetLastError() ); + ok( required_size > 0, "Expected > 0, got %lu\n", required_size ); + ok( required_size < LINE_LEN, "Expected < %u, got %lu\n", LINE_LEN, required_size ); class_desc = HeapAlloc( GetProcessHeap(), 0, required_size ); if ( !class_desc ) @@ -220,12 +220,12 @@ static void test_SetupDiGetClassDescriptionA(void) SetLastError( 0xdeadbeef ); ok( SetupDiGetClassDescriptionA( &test_class_guid, class_desc, required_size, &size ), - "Error reported %lx", GetLastError() ); - ok( size == required_size, "Expected size %lu, got %lu", required_size, size ); + "Error reported %lx\n", GetLastError() ); + ok( size == required_size, "Expected size %lu, got %lu\n", required_size, size ); SetLastError( 0xdeadbeef ); ok( SetupDiGetClassDescriptionA( &test_class_guid, class_desc, required_size + 1, &size ), - "Error reported %lx", GetLastError() ); - ok( size == required_size, "Expected size %lu, got %lu", required_size, size ); + "Error reported %lx\n", GetLastError() ); + ok( size == required_size, "Expected size %lu, got %lu\n", required_size, size ); HeapFree( GetProcessHeap(), 0, class_desc ); } @@ -237,47 +237,47 @@ static void test_SetupDiGetClassDevsA(void) SetLastError( 0xdeadbeef ); device_info = SetupDiGetClassDevs( NULL, NULL, NULL, 0 ); ok( device_info == INVALID_HANDLE_VALUE, - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, - "Expected error %lx, got %lx", ERROR_INVALID_PARAMETER, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_PARAMETER, GetLastError() ); SetLastError( 0xdeadbeef ); device_info = SetupDiGetClassDevs( NULL, NULL, NULL, DIGCF_ALLCLASSES ); ok( device_info != INVALID_HANDLE_VALUE, - "Error reported %lx", GetLastError() ); + "Error reported %lx\n", GetLastError() ); SetLastError( 0xdeadbeef ); ok( SetupDiDestroyDeviceInfoList( device_info ), - "Error reported %lx", GetLastError() ); + "Error reported %lx\n", GetLastError() ); SetLastError( 0xdeadbeef ); device_info = SetupDiGetClassDevs( NULL, NULL, NULL, DIGCF_DEVICEINTERFACE ); ok( device_info == INVALID_HANDLE_VALUE, - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, - "Expected error %lx, got %lx", ERROR_INVALID_PARAMETER, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_PARAMETER, GetLastError() ); SetLastError( 0xdeadbeef ); device_info = SetupDiGetClassDevs( &test_class_guid, NULL, NULL, 0 ); ok( device_info != INVALID_HANDLE_VALUE, - "Error reported %lx", GetLastError() ); + "Error reported %lx\n", GetLastError() ); SetLastError( 0xdeadbeef ); ok( SetupDiDestroyDeviceInfoList( device_info ), - "Error reported %lx", GetLastError() ); + "Error reported %lx\n", GetLastError() ); SetLastError( 0xdeadbeef ); device_info = SetupDiGetClassDevs( NULL, "(invalid enumerator)", NULL, DIGCF_ALLCLASSES ); ok( device_info == INVALID_HANDLE_VALUE, - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_DATA, - "Expected error %lx, got %lx", ERROR_INVALID_DATA, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_DATA, GetLastError() ); SetLastError( 0xdeadbeef ); device_info = SetupDiGetClassDevs( NULL, "Root", NULL, DIGCF_ALLCLASSES ); ok( device_info != INVALID_HANDLE_VALUE, - "Error reported %lx", GetLastError() ); + "Error reported %lx\n", GetLastError() ); SetLastError( 0xdeadbeef ); ok( SetupDiDestroyDeviceInfoList( device_info ), - "Error reported %lx", GetLastError() ); + "Error reported %lx\n", GetLastError() ); } static void test_SetupDiOpenClassRegKeyExA(void) @@ -288,51 +288,51 @@ static void test_SetupDiOpenClassRegKeyExA(void) SetLastError( 0xdeadbeef ); hkey = SetupDiOpenClassRegKeyExA( NULL, 0, 0, NULL, NULL ); ok( hkey == INVALID_HANDLE_VALUE, - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_FLAGS, - "Expected error %lx, got %lx", ERROR_INVALID_FLAGS, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_FLAGS, GetLastError() ); SetLastError( 0xdeadbeef ); hkey = SetupDiOpenClassRegKeyExA( NULL, 0, DIOCR_INSTALLER | DIOCR_INTERFACE, NULL, NULL ); ok( hkey == INVALID_HANDLE_VALUE, - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_FLAGS, - "Expected error %lx, got %lx", ERROR_INVALID_FLAGS, GetLastError() ); + "Expected error %lx, got %lx\n", ERROR_INVALID_FLAGS, GetLastError() ); SetLastError( 0xdeadbeef ); hkey = SetupDiOpenClassRegKeyExA( NULL, 0, DIOCR_INSTALLER, NULL, NULL ); ok( hkey == INVALID_HANDLE_VALUE, - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_CLASS, - "Expected error %x, got %lx", ERROR_INVALID_CLASS, GetLastError() ); + "Expected error %x, got %lx\n", ERROR_INVALID_CLASS, GetLastError() ); SetLastError( 0xdeadbeef ); hkey = SetupDiOpenClassRegKeyExA( NULL, 0, DIOCR_INTERFACE, NULL, NULL ); ok( hkey == INVALID_HANDLE_VALUE, - "Fail expected" ); + "Fail expected\n" ); ok( GetLastError() == ERROR_INVALID_CLASS, - "Expected error %x, got %lx", ERROR_INVALID_CLASS, GetLastError() ); + "Expected error %x, got %lx\n", ERROR_INVALID_CLASS, GetLastError() ); SetLastError( 0xdeadbeef ); hkey = SetupDiOpenClassRegKeyExA( NULL, KEY_QUERY_VALUE, DIOCR_INSTALLER, NULL, NULL ); - ok( hkey != INVALID_HANDLE_VALUE, "Got error %lx", GetLastError() ); + ok( hkey != INVALID_HANDLE_VALUE, "Got error %lx\n", GetLastError() ); err = RegCloseKey( hkey ); - ok( err == ERROR_SUCCESS, "Got error %lx", err ); + ok( err == ERROR_SUCCESS, "Got error %lx\n", err ); SetLastError( 0xdeadbeef ); hkey = SetupDiOpenClassRegKeyExA( NULL, KEY_QUERY_VALUE, DIOCR_INTERFACE, NULL, NULL ); - ok( hkey != INVALID_HANDLE_VALUE, "Got error %lx", GetLastError() ); + ok( hkey != INVALID_HANDLE_VALUE, "Got error %lx\n", GetLastError() ); err = RegCloseKey( hkey ); - ok( err == ERROR_SUCCESS, "Got error %lx", err ); + ok( err == ERROR_SUCCESS, "Got error %lx\n", err ); SetLastError( 0xdeadbeef ); hkey = SetupDiOpenClassRegKeyExA( &test_class_guid, KEY_QUERY_VALUE, DIOCR_INSTALLER, NULL, NULL ); - ok( hkey != INVALID_HANDLE_VALUE, "Got error %lx", GetLastError() ); + ok( hkey != INVALID_HANDLE_VALUE, "Got error %lx\n", GetLastError() ); err = RegCloseKey( hkey ); - ok( err == ERROR_SUCCESS, "Got error %lx", err ); + ok( err == ERROR_SUCCESS, "Got error %lx\n", err ); err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\Class", 0, KEY_SET_VALUE, &hkey); - ok( err == ERROR_SUCCESS, "Got error %lx", err ); + ok( err == ERROR_SUCCESS, "Got error %lx\n", err ); } START_TEST(devclass) diff --git a/rostests/winetests/setupapi/devinst.c b/rostests/winetests/setupapi/devinst.c index 727e4540c47..816f66c84a5 100644 --- a/rostests/winetests/setupapi/devinst.c +++ b/rostests/winetests/setupapi/devinst.c @@ -57,6 +57,9 @@ static BOOL (WINAPI *pSetupDiSetDeviceRegistryPropertyW)(HDEVINFO, PSP_DEVIN static BOOL (WINAPI *pSetupDiGetDeviceRegistryPropertyA)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD); static BOOL (WINAPI *pSetupDiGetDeviceRegistryPropertyW)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD); +/* This is a unique guid for testing purposes */ +static GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04,0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + static void init_function_pointers(void) { hSetupAPI = GetModuleHandleA("setupapi.dll"); @@ -86,8 +89,68 @@ static void init_function_pointers(void) pSetupDiGetDeviceRegistryPropertyW = (void *)GetProcAddress(hSetupAPI, "SetupDiGetDeviceRegistryPropertyW"); } +static void change_reg_permissions(const WCHAR *regkey) +{ + HKEY hkey; + SID_IDENTIFIER_AUTHORITY ident = { SECURITY_WORLD_SID_AUTHORITY }; + SECURITY_DESCRIPTOR sd; + PSID EveryoneSid; + PACL pacl = NULL; + + RegOpenKeyExW(HKEY_LOCAL_MACHINE, regkey, 0, WRITE_DAC, &hkey); + + /* Initialize the 'Everyone' sid */ + AllocateAndInitializeSid(&ident, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &EveryoneSid); + + pacl = HeapAlloc(GetProcessHeap(), 0, 256); + InitializeAcl(pacl, 256, ACL_REVISION); + + /* Add 'Full Control' for 'Everyone' */ + AddAccessAllowedAce(pacl, ACL_REVISION, KEY_ALL_ACCESS, EveryoneSid); + + InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); + + SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE); + + /* Set the new security on the registry key */ + RegSetKeySecurity(hkey, DACL_SECURITY_INFORMATION, &sd); + + RegCloseKey(hkey); + + HeapFree(GetProcessHeap(), 0, pacl); + if (EveryoneSid) + FreeSid(EveryoneSid); +} + +static BOOL remove_device(void) +{ + HDEVINFO set; + SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } }; + BOOL ret; + + SetLastError(0xdeadbeef); + set = pSetupDiGetClassDevsA(&guid, NULL, 0, 0); + ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsA failed: %08x\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ok(pSetupDiEnumDeviceInfo(set, 0, &devInfo), + "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pSetupDiCallClassInstaller(DIF_REMOVE, set, &devInfo); + todo_wine + ok(ret, "SetupDiCallClassInstaller(DIF_REMOVE...) failed: %08x\n", GetLastError()); + + SetLastError(0xdeadbeef); + ok(pSetupDiDestroyDeviceInfoList(set), + "SetupDiDestroyDeviceInfoList failed: %08x\n", GetLastError()); + + return ret; +} + /* RegDeleteTreeW from dlls/advapi32/registry.c */ -LSTATUS WINAPI devinst_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey) +static LSTATUS devinst_RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey) { LONG ret; DWORD dwMaxSubkeyLen, dwMaxValueLen; @@ -153,6 +216,33 @@ cleanup: return ret; } +static void clean_devclass_key(void) +{ + static const WCHAR devclass[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\', + '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-', + '1','1','d','b','-','b','7','0','4','-', + '0','0','1','1','9','5','5','c','2','b','d','b','}',0}; + HKEY key; + DWORD subkeys; + + /* Check if we have subkeys as Windows 2000 doesn't delete + * the keys under the DeviceClasses key after a SetupDiDestroyDeviceInfoList. + */ + RegOpenKeyW(HKEY_LOCAL_MACHINE, devclass, &key); + RegQueryInfoKey(key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (subkeys > 0) + { + trace("We are most likely on Windows 2000\n"); + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass); + } + else + { + ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, devclass), + "Couldn't delete deviceclass key\n"); + } +} static void test_SetupDiCreateDeviceInfoListEx(void) { @@ -169,7 +259,7 @@ static void test_SetupDiCreateDeviceInfoListEx(void) error = GetLastError(); if (error == ERROR_CALL_NOT_IMPLEMENTED) { - skip("SetupDiCreateDeviceInfoListExW is not implemented\n"); + win_skip("SetupDiCreateDeviceInfoListExW is not implemented\n"); return; } ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE); @@ -181,7 +271,7 @@ static void test_SetupDiCreateDeviceInfoListEx(void) error = GetLastError(); ok(devlist == INVALID_HANDLE_VALUE, "SetupDiCreateDeviceInfoListExW failed : %p %d (expected %p)\n", devlist, error, INVALID_HANDLE_VALUE); - ok(error == ERROR_INVALID_MACHINENAME, "GetLastError returned wrong value : %d, (expected %d)\n", error, ERROR_INVALID_MACHINENAME); + ok(error == ERROR_INVALID_MACHINENAME || error == ERROR_MACHINE_UNAVAILABLE, "GetLastError returned wrong value : %d, (expected %d or %d)\n", error, ERROR_INVALID_MACHINENAME, ERROR_MACHINE_UNAVAILABLE); /* create empty DeviceInfoList */ devlist = pSetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); @@ -194,9 +284,6 @@ static void test_SetupDiCreateDeviceInfoListEx(void) static void test_SetupDiOpenClassRegKeyExA(void) { - /* This is a unique guid for testing purposes */ - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; static const CHAR guidString[] = "{6a55b5a4-3f65-11db-b704-0011955c2bdb}"; HKEY hkey; @@ -226,35 +313,30 @@ static void test_SetupDiOpenClassRegKeyExA(void) } else trace("failed to create registry key for test\n"); + + RegCloseKey(hkey); } else trace("failed to open classes key\n"); } -static void append_str(char **str, const char *data) -{ - sprintf(*str, data); - *str += strlen(*str); -} - static void create_inf_file(LPCSTR filename) { - char data[1024]; - char *ptr = data; DWORD dwNumberOfBytesWritten; HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - append_str(&ptr, "[Version]\n"); - append_str(&ptr, "Signature=\"$Chicago$\"\n"); - append_str(&ptr, "Class=Bogus\n"); - append_str(&ptr, "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n"); - append_str(&ptr, "[ClassInstall32]\n"); - append_str(&ptr, "AddReg=BogusClass.NT.AddReg\n"); - append_str(&ptr, "[BogusClass.NT.AddReg]\n"); - append_str(&ptr, "HKR,,,,\"Wine test devices\"\n"); + static const char data[] = + "[Version]\n" + "Signature=\"$Chicago$\"\n" + "Class=Bogus\n" + "ClassGUID={6a55b5a4-3f65-11db-b704-0011955c2bdb}\n" + "[ClassInstall32]\n" + "AddReg=BogusClass.NT.AddReg\n" + "[BogusClass.NT.AddReg]\n" + "HKR,,,,\"Wine test devices\"\n"; - WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); + WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL); CloseHandle(hf); } @@ -280,20 +362,9 @@ static void testInstallClass(void) '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-', '1','1','d','b','-','b','7','0','4','-', '0','0','1','1','9','5','5','c','2','b','d','b','}',0}; - static const CHAR classKey_win9x[] = - "System\\CurrentControlSet\\Services\\Class\\" - "{6a55b5a4-3f65-11db-b704-0011955c2bdb}"; - static const CHAR bogus_win9x[] = - "System\\CurrentControlSet\\Services\\Class\\Bogus"; char tmpfile[MAX_PATH]; BOOL ret; - HKEY hkey; - if (!pSetupDiInstallClassA) - { - skip("No SetupDiInstallClassA\n"); - return; - } tmpfile[0] = '.'; tmpfile[1] = '\\'; get_temp_filename(tmpfile + 2); @@ -316,21 +387,10 @@ static void testInstallClass(void) */ ret = pSetupDiInstallClassA(NULL, tmpfile, 0, NULL); ok(ret, "SetupDiInstallClassA failed: %08x\n", GetLastError()); - if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, classKey_win9x, &hkey)) - { - /* We are on win9x */ - RegCloseKey(hkey); - ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, classKey_win9x), - "Couldn't delete win9x classkey\n"); - ok(!RegDeleteKeyA(HKEY_LOCAL_MACHINE, bogus_win9x), - "Couldn't delete win9x bogus services class\n"); - } - else - { - /* NT4 and above */ + ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey), - "Couldn't delete NT classkey\n"); - } + "Couldn't delete classkey\n"); + DeleteFile(tmpfile); } @@ -338,19 +398,20 @@ static void testCreateDeviceInfo(void) { BOOL ret; HDEVINFO set; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; + HKEY key; + LONG res; + static const WCHAR bogus[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'E','n','u','m','\\','R','o','o','t','\\', + 'L','E','G','A','C','Y','_','B','O','G','U','S',0}; - if (!pSetupDiCreateDeviceInfoList || !pSetupDiEnumDeviceInfo || - !pSetupDiDestroyDeviceInfoList || !pSetupDiCreateDeviceInfoA) - { - skip("No SetupDiCreateDeviceInfoA\n"); - return; - } SetLastError(0xdeadbeef); ret = pSetupDiCreateDeviceInfoA(NULL, NULL, NULL, NULL, NULL, 0, NULL); - ok(!ret && GetLastError() == ERROR_INVALID_DEVINST_NAME, - "Expected ERROR_INVALID_DEVINST_NAME, got %08x\n", GetLastError()); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_DEVINST_NAME || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error, got %08x\n", GetLastError()); + SetLastError(0xdeadbeef); ret = pSetupDiCreateDeviceInfoA(NULL, "Root\\LEGACY_BOGUS\\0000", NULL, NULL, NULL, 0, NULL); @@ -363,16 +424,52 @@ static void testCreateDeviceInfo(void) { SP_DEVINFO_DATA devInfo = { 0 }; DWORD i; + static GUID deadbeef = + {0xdeadbeef, 0xdead, 0xbeef, {0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}}; + LONG res; + HKEY key; + static const WCHAR bogus0000[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'E','n','u','m','\\','R','o','o','t','\\', + 'L','E','G','A','C','Y','_','B','O','G','U','S','\\','0','0','0','0',0}; + /* So we know we have a clean start */ + res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus0000, &key); + ok(res != ERROR_SUCCESS, "Expected key to not exist\n"); + /* No GUID given */ SetLastError(0xdeadbeef); ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", NULL, NULL, NULL, 0, NULL); ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + /* Even though NT4 fails it still adds some stuff to the registry that + * can't be deleted via normal setupapi functions. As the registry is written + * by a different user (SYSTEM) we have to do some magic to get rid of the key + */ + if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus0000, &key)) + { + trace("NT4 created a bogus key on failure, will be removed now\n"); + change_reg_permissions(bogus0000); + ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus0000), + "Could not delete LEGACY_BOGUS\\0000 key\n"); + } + /* We can't add device information to the set with a different GUID */ + SetLastError(0xdeadbeef); + ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", + &deadbeef, NULL, NULL, 0, NULL); + ok(!ret && GetLastError() == ERROR_CLASS_MISMATCH, + "Expected ERROR_CLASS_MISMATCH, got %08x\n", GetLastError()); + if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus0000, &key)) + { + trace("NT4 created a bogus key on failure, will be removed now\n"); + change_reg_permissions(bogus0000); + ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus0000), + "Could not delete LEGACY_BOGUS\\0000 key\n"); + } /* Finally, with all three required parameters, this succeeds: */ ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, NULL); - ok(ret, "pSetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); /* This fails because the device ID already exists.. */ SetLastError(0xdeadbeef); ret = pSetupDiCreateDeviceInfoA(set, "Root\\LEGACY_BOGUS\\0000", &guid, @@ -385,10 +482,10 @@ static void testCreateDeviceInfo(void) DICD_GENERATE_ID, &devInfo); ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); + /* and this finally succeeds. */ devInfo.cbSize = sizeof(devInfo); ret = pSetupDiCreateDeviceInfoA(set, "LEGACY_BOGUS", &guid, NULL, NULL, DICD_GENERATE_ID, &devInfo); - /* and this finally succeeds. */ ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); /* There were three devices added, however - the second failure just * resulted in the SP_DEVINFO_DATA not getting copied. @@ -402,30 +499,59 @@ static void testCreateDeviceInfo(void) "SetupDiEnumDeviceInfo failed: %08x\n", GetLastError()); pSetupDiDestroyDeviceInfoList(set); } + + /* The bogus registry key shouldn't be there after this test. The only + * reasons this key would still be present: + * + * - We are running on Wine which has to be fixed + * - We have leftovers from old tests + */ + res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key); + todo_wine + ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n"); + if (res == ERROR_SUCCESS) + { + DWORD subkeys; + + /* Check if we have subkeys */ + RegQueryInfoKey(key, NULL, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (subkeys > 0) + { + int i; + + /* Leftovers from old tests */ + trace("Going to remove %d devices\n", subkeys); + for (i = 0; i < subkeys; i++) + { + BOOL ret; + + ret = remove_device(); + ok(ret, "Expected a device to be removed\n"); +} + } + else + { + /* Wine doesn't delete the bogus key itself currently */ + trace("We are most likely on Wine\n"); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus); + } + } } static void testGetDeviceInstanceId(void) { BOOL ret; HDEVINFO set; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; SP_DEVINFO_DATA devInfo = { 0 }; - if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || - !pSetupDiCreateDeviceInfoA || !pSetupDiGetDeviceInstanceIdA) - { - skip("No SetupDiGetDeviceInstanceIdA\n"); - return; - } SetLastError(0xdeadbeef); ret = pSetupDiGetDeviceInstanceIdA(NULL, NULL, NULL, 0, NULL); ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError()); + "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); ret = pSetupDiGetDeviceInstanceIdA(NULL, &devInfo, NULL, 0, NULL); ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLEHANDLE, got %08x\n", GetLastError()); + "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError()); set = pSetupDiCreateDeviceInfoList(&guid, NULL); ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %08x\n", GetLastError()); @@ -469,7 +595,8 @@ static void testGetDeviceInstanceId(void) ret = pSetupDiGetDeviceInstanceIdA(set, &devInfo, instanceID, sizeof(instanceID), NULL); ok(ret, "SetupDiGetDeviceInstanceIdA failed: %08x\n", GetLastError()); - ok(!lstrcmpA(instanceID, "ROOT\\LEGACY_BOGUS\\0001"), + /* NT4 returns 'Root' and W2K and above 'ROOT' */ + ok(!lstrcmpiA(instanceID, "ROOT\\LEGACY_BOGUS\\0001"), "Unexpected instance ID %s\n", instanceID); pSetupDiDestroyDeviceInfoList(set); } @@ -478,21 +605,12 @@ static void testGetDeviceInstanceId(void) static void testRegisterDeviceInfo(void) { BOOL ret; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; HDEVINFO set; - if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || - !pSetupDiRegisterDeviceInfo) - { - skip("No SetupDiRegisterDeviceInfo\n"); - return; - } SetLastError(0xdeadbeef); ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL); ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); - ret = pSetupDiRegisterDeviceInfo(NULL, NULL, 0, NULL, NULL, NULL); set = pSetupDiCreateDeviceInfoList(&guid, NULL); ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError()); if (set) @@ -524,8 +642,7 @@ static void testRegisterDeviceInfo(void) ok(ret, "SetupDiCreateDeviceInfoA failed: %d\n", GetLastError()); } /* FIXME: On Win2K+ systems, this is now persisted to registry in - * HKLM\System\CCS\Enum\USB\Bogus\0000. I don't check because the - * Win9x location is different. + * HKLM\System\CCS\Enum\USB\Bogus\0000. * FIXME: the key also becomes undeletable. How to get rid of it? */ pSetupDiDestroyDeviceInfoList(set); @@ -535,15 +652,22 @@ static void testRegisterDeviceInfo(void) static void testCreateDeviceInterface(void) { BOOL ret; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; HDEVINFO set; + HKEY key; + static const WCHAR bogus[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'E','n','u','m','\\','R','o','o','t','\\', + 'L','E','G','A','C','Y','_','B','O','G','U','S',0}; + static const WCHAR devclass[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\', + '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-', + '1','1','d','b','-','b','7','0','4','-', + '0','0','1','1','9','5','5','c','2','b','d','b','}',0}; - if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || - !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA || - !pSetupDiEnumDeviceInterfaces) + if (!pSetupDiCreateDeviceInterfaceA || !pSetupDiEnumDeviceInterfaces) { - skip("No SetupDiCreateDeviceInterfaceA\n"); + win_skip("SetupDiCreateDeviceInterfaceA and/or SetupDiEnumDeviceInterfaces are not available\n"); return; } SetLastError(0xdeadbeef); @@ -601,22 +725,46 @@ static void testCreateDeviceInterface(void) ok(i == 2, "expected 2 interfaces, got %d\n", i); ok(GetLastError() == ERROR_NO_MORE_ITEMS, "SetupDiEnumDeviceInterfaces failed: %08x\n", GetLastError()); - pSetupDiDestroyDeviceInfoList(set); + ret = pSetupDiDestroyDeviceInfoList(set); + ok(ret, "SetupDiDestroyDeviceInfoList failed: %08x\n", GetLastError()); + + /* Cleanup */ + /* FIXME: On Wine we still have the bogus entry in Enum\Root and + * subkeys, as well as the deviceclass key with subkeys. + * Only clean the deviceclass key once Wine if fixed. + */ + if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key)) + { + /* Wine doesn't delete the information currently */ + trace("We are most likely on Wine\n"); + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus); + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass); + } + else + { + clean_devclass_key(); +} } } static void testGetDeviceInterfaceDetail(void) { BOOL ret; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; HDEVINFO set; + static const WCHAR bogus[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'E','n','u','m','\\','R','o','o','t','\\', + 'L','E','G','A','C','Y','_','B','O','G','U','S',0}; + static const WCHAR devclass[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\', + '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-', + '1','1','d','b','-','b','7','0','4','-', + '0','0','1','1','9','5','5','c','2','b','d','b','}',0}; - if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || - !pSetupDiCreateDeviceInfoA || !pSetupDiCreateDeviceInterfaceA || - !pSetupDiGetDeviceInterfaceDetailA) + if (!pSetupDiCreateDeviceInterfaceA || !pSetupDiGetDeviceInterfaceDetailA) { - skip("No SetupDiGetDeviceInterfaceDetailA\n"); + win_skip("SetupDiCreateDeviceInterfaceA and/or SetupDiGetDeviceInterfaceDetailA are not available\n"); return; } SetLastError(0xdeadbeef); @@ -631,6 +779,7 @@ static void testGetDeviceInterfaceDetail(void) SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } }; DWORD size = 0; + HKEY key; SetLastError(0xdeadbeef); ret = pSetupDiGetDeviceInterfaceDetailA(set, NULL, NULL, 0, NULL, @@ -663,10 +812,12 @@ static void testGetDeviceInterfaceDetail(void) { static const char path[] = "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}"; + static const char path_w2k[] = + "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\"; LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, size); SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_A *)buf; - DWORD expectedsize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR)*(1 + strlen(path)); + DWORD expectedsize = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR)*(1 + strlen(path)); detail->cbSize = 0; SetLastError(0xdeadbeef); @@ -682,33 +833,42 @@ static void testGetDeviceInterfaceDetail(void) "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); SetLastError(0xdeadbeef); - ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail, - size, &size, NULL); - ok(!ret && GetLastError() == ERROR_INVALID_USER_BUFFER, - "Expected ERROR_INVALID_USER_BUFFER, got %08x\n", GetLastError()); - /* Windows 2000 and up check for the exact size. Win9x returns ERROR_INVALID_PARAMETER - * on every call (so doesn't get here) and NT4 doesn't have this function. - */ - detail->cbSize = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]); ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail, size, &size, NULL); ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %d\n", GetLastError()); - ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n", + ok(!lstrcmpiA(path, detail->DevicePath) || + !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n", detail->DevicePath); /* Check SetupDiGetDeviceInterfaceDetailW */ - if (pSetupDiGetDeviceInterfaceDetailW) - { ret = pSetupDiGetDeviceInterfaceDetailW(set, &interfaceData, NULL, 0, &size, NULL); - ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got error code: %d\n", GetLastError()); - ok(expectedsize == size, "SetupDiGetDeviceInterfaceDetailW returned wrong reqsize: expected %d, got %d\n", expectedsize, size); - } - else - skip("SetupDiGetDeviceInterfaceDetailW is not available\n"); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got error code: %d\n", GetLastError()); + ok(expectedsize == size || + (expectedsize + sizeof(WCHAR)) == size /* W2K adds a backslash */, + "SetupDiGetDeviceInterfaceDetailW returned wrong reqsize, got %d\n", + size); HeapFree(GetProcessHeap(), 0, buf); } pSetupDiDestroyDeviceInfoList(set); + + /* Cleanup */ + /* FIXME: On Wine we still have the bogus entry in Enum\Root and + * subkeys, as well as the deviceclass key with subkeys. + * Only do the RegDeleteKey, once Wine is fixed. + */ + if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key)) + { + /* Wine doesn't delete the information currently */ + trace("We are most likely on Wine\n"); + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus); + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass); + } + else + { + clean_devclass_key(); +} } } @@ -720,33 +880,46 @@ static void testDevRegKey(void) '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-', '1','1','d','b','-','b','7','0','4','-', '0','0','1','1','9','5','5','c','2','b','d','b','}',0}; + static const WCHAR bogus[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'E','n','u','m','\\','R','o','o','t','\\', + 'L','E','G','A','C','Y','_','B','O','G','U','S',0}; BOOL ret; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; HDEVINFO set; + HKEY key = NULL; + BOOL classKeyCreated; + + SetLastError(0xdeadbeef); + key = pSetupDiCreateDevRegKeyW(NULL, NULL, 0, 0, 0, NULL, NULL); + ok(key == INVALID_HANDLE_VALUE, + "Expected INVALID_HANDLE_VALUE, got %p\n", key); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %08x\n", GetLastError()); - if (!pSetupDiCreateDeviceInfoList || !pSetupDiDestroyDeviceInfoList || - !pSetupDiCreateDeviceInfoA || !pSetupDiOpenDevRegKey || - !pSetupDiRegisterDeviceInfo || !pSetupDiCreateDevRegKeyW || - !pSetupDiCallClassInstaller) - { - skip("No SetupDiOpenDevRegKey\n"); - return; - } set = pSetupDiCreateDeviceInfoList(&guid, NULL); ok(set != NULL, "SetupDiCreateDeviceInfoList failed: %d\n", GetLastError()); if (set) { SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } }; - HKEY key = INVALID_HANDLE_VALUE; + LONG res; + /* The device info key shouldn't be there */ + res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key); + ok(res != ERROR_SUCCESS, "Expected key to not exist\n"); + RegCloseKey(key); + /* Create the device information */ ret = pSetupDiCreateDeviceInfoA(set, "ROOT\\LEGACY_BOGUS\\0000", &guid, NULL, NULL, 0, &devInfo); ok(ret, "SetupDiCreateDeviceInfoA failed: %08x\n", GetLastError()); + /* The device info key should have been created */ + ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key), + "Expected registry key to exist\n"); + RegCloseKey(key); SetLastError(0xdeadbeef); key = pSetupDiOpenDevRegKey(NULL, NULL, 0, 0, 0, 0); - ok(key == INVALID_HANDLE_VALUE && - GetLastError() == ERROR_INVALID_HANDLE, + ok(!key || key == INVALID_HANDLE_VALUE, + "Expected INVALID_HANDLE_VALUE or a NULL key (NT4)\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); SetLastError(0xdeadbeef); key = pSetupDiOpenDevRegKey(set, NULL, 0, 0, 0, 0); @@ -785,46 +958,102 @@ static void testDevRegKey(void) todo_wine ok(key == INVALID_HANDLE_VALUE && GetLastError() == ERROR_KEY_DOES_NOT_EXIST, - "Expected ERROR_KEY_DOES_NOT_EXIST_EXIST, got %08x\n", GetLastError()); + "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DEV, 0); todo_wine ok(key == INVALID_HANDLE_VALUE && GetLastError() == ERROR_KEY_DOES_NOT_EXIST, - "Expected ERROR_KEY_DOES_NOT_EXIST_EXIST, got %08x\n", GetLastError()); + "Expected ERROR_KEY_DOES_NOT_EXIST, got %08x\n", GetLastError()); SetLastError(0xdeadbeef); + /* The class key shouldn't be there */ + res = RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key); + todo_wine + ok(res != ERROR_SUCCESS, "Expected key to not exist\n"); + RegCloseKey(key); + /* Create the device reg key */ key = pSetupDiCreateDevRegKeyW(set, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL); - ok(key != INVALID_HANDLE_VALUE, "SetupDiCreateDevRegKey failed: %08x\n", - GetLastError()); + /* Vista and higher don't actually create the key */ + ok(key != INVALID_HANDLE_VALUE || GetLastError() == ERROR_KEY_DOES_NOT_EXIST, + "SetupDiCreateDevRegKey failed: %08x\n", GetLastError()); + if (key != INVALID_HANDLE_VALUE) + { + classKeyCreated = TRUE; RegCloseKey(key); + /* The class key should have been created */ + ok(!RegOpenKeyW(HKEY_LOCAL_MACHINE, classKey, &key), + "Expected registry key to exist\n"); + RegCloseKey(key); SetLastError(0xdeadbeef); key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DRV, 0); todo_wine ok(key == INVALID_HANDLE_VALUE && - GetLastError() == ERROR_INVALID_DATA, - "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + (GetLastError() == ERROR_INVALID_DATA || + GetLastError() == ERROR_ACCESS_DENIED), /* win2k3 */ + "Expected ERROR_INVALID_DATA or ERROR_ACCESS_DENIED, got %08x\n", GetLastError()); key = pSetupDiOpenDevRegKey(set, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ); ok(key != INVALID_HANDLE_VALUE, "SetupDiOpenDevRegKey failed: %08x\n", GetLastError()); - ret = pSetupDiCallClassInstaller(DIF_REMOVE, set, &devInfo); pSetupDiDestroyDeviceInfoList(set); } + else + classKeyCreated = FALSE; + + /* Cleanup */ + ret = remove_device(); + todo_wine + ok(ret, "Expected the device to be removed: %08x\n", GetLastError()); + + /* FIXME: Only do the RegDeleteKey, once Wine is fixed */ + if (!ret) + { + /* Wine doesn't delete the information currently */ + trace("We are most likely on Wine\n"); + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus); devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, classKey); } + else if (classKeyCreated) + { + /* There should only be a class key entry, so a simple + * RegDeleteKey should work + * + * This could fail if it's the first time for this new test + * after running the old tests. + */ + ok(!RegDeleteKeyW(HKEY_LOCAL_MACHINE, classKey), + "Couldn't delete classkey\n"); + } + } +} static void testRegisterAndGetDetail(void) { HDEVINFO set; BOOL ret; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } }; SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(interfaceData), { 0 } }; DWORD dwSize = 0; + static const WCHAR bogus[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'E','n','u','m','\\','R','o','o','t','\\', + 'L','E','G','A','C','Y','_','B','O','G','U','S',0}; + static const WCHAR devclass[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\','D','e','v','i','c','e','C','l','a','s','s','e','s','\\', + '{','6','a','5','5','b','5','a','4','-','3','f','6','5','-', + '1','1','d','b','-','b','7','0','4','-', + '0','0','1','1','9','5','5','c','2','b','d','b','}',0}; + + if (!pSetupDiCreateDeviceInterfaceA || !pSetupDiEnumDeviceInterfaces || + !pSetupDiGetDeviceInterfaceDetailA) + { + win_skip("Needed functions are not available\n"); + return; + } SetLastError(0xdeadbeef); set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_ALLCLASSES); @@ -860,30 +1089,53 @@ static void testRegisterAndGetDetail(void) { static const char path[] = "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}"; + static const char path_w2k[] = + "\\\\?\\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\\"; PSP_DEVICE_INTERFACE_DETAIL_DATA_A detail = NULL; - detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)HeapAlloc(GetProcessHeap(), 0, dwSize); + detail = HeapAlloc(GetProcessHeap(), 0, dwSize); if (detail) { - detail->cbSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char); + detail->cbSize = sizeof(*detail); SetLastError(0xdeadbeef); ret = pSetupDiGetDeviceInterfaceDetailA(set, &interfaceData, detail, dwSize, &dwSize, NULL); ok(ret, "SetupDiGetDeviceInterfaceDetailA failed: %08x\n", GetLastError()); - ok(!lstrcmpiA(path, detail->DevicePath), "Unexpected path %s\n", + /* FIXME: This one only worked because old data wasn't removed properly. As soon + * as all the tests are cleaned up correctly this has to be (or should be) fixed + */ + todo_wine + ok(!lstrcmpiA(path, detail->DevicePath) || + !lstrcmpiA(path_w2k, detail->DevicePath), "Unexpected path %s\n", detail->DevicePath); HeapFree(GetProcessHeap(), 0, detail); } } pSetupDiDestroyDeviceInfoList(set); + + /* Cleanup */ + ret = remove_device(); + todo_wine + ok(ret, "Expected the device to be removed: %08x\n", GetLastError()); + + /* FIXME: Only do the RegDeleteKey, once Wine is fixed */ + if (!ret) + { + /* Wine doesn't delete the information currently */ + trace("We are most likely on Wine\n"); + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, bogus); + devinst_RegDeleteTreeW(HKEY_LOCAL_MACHINE, devclass); +} + else + { + clean_devclass_key(); + } } -static void testDeviceRegistryPropertyA() +static void testDeviceRegistryPropertyA(void) { HDEVINFO set; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } }; CHAR devName[] = "LEGACY_BOGUS"; CHAR friendlyName[] = "Bogus"; @@ -892,6 +1144,10 @@ static void testDeviceRegistryPropertyA() DWORD size; DWORD regType; BOOL ret; + LONG res; + HKEY key; + static const CHAR bogus[] = + "System\\CurrentControlSet\\Enum\\Root\\LEGACY_BOGUS"; SetLastError(0xdeadbeef); set = pSetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE); @@ -914,12 +1170,11 @@ static void testDeviceRegistryPropertyA() todo_wine ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY, "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError()); - SetLastError(0xdeadbeef); + /* GetLastError() returns nonsense in win2k3 */ ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, NULL, 0); todo_wine - ok(!ret && GetLastError() == ERROR_INVALID_DATA, - "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + ok(!ret, "Expected failure, got %d\n", ret); SetLastError(0xdeadbeef); ret = pSetupDiSetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, (PBYTE)friendlyName, buflen); @@ -937,11 +1192,10 @@ static void testDeviceRegistryPropertyA() todo_wine ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY, "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError()); - SetLastError(0xdeadbeef); + /* GetLastError() returns nonsense in win2k3 */ ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, NULL, NULL, buflen, NULL); - ok(!ret && GetLastError() == ERROR_INVALID_DATA, - "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + ok(!ret, "Expected failure, got %d\n", ret); SetLastError(0xdeadbeef); ret = pSetupDiGetDeviceRegistryPropertyA(set, &devInfo, SPDRP_FRIENDLYNAME, NULL, NULL, 0, &size); @@ -970,13 +1224,22 @@ static void testDeviceRegistryPropertyA() ok(!ret && GetLastError() == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); pSetupDiDestroyDeviceInfoList(set); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, bogus, &key); + todo_wine + ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n"); + /* FIXME: Remove when Wine is fixed */ + if (res == ERROR_SUCCESS) + { + /* Wine doesn't delete the information currently */ + trace("We are most likely on Wine\n"); + RegDeleteKeyA(HKEY_LOCAL_MACHINE, bogus); +} } -static void testDeviceRegistryPropertyW() +static void testDeviceRegistryPropertyW(void) { HDEVINFO set; - GUID guid = {0x6a55b5a4, 0x3f65, 0x11db, {0xb7,0x04, - 0x00,0x11,0x95,0x5c,0x2b,0xdb}}; SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA), { 0 } }; WCHAR devName[] = {'L','E','G','A','C','Y','_','B','O','G','U','S',0}; WCHAR friendlyName[] = {'B','o','g','u','s',0}; @@ -985,14 +1248,15 @@ static void testDeviceRegistryPropertyW() DWORD size; DWORD regType; BOOL ret; + LONG res; + HKEY key; + static const WCHAR bogus[] = {'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'E','n','u','m','\\','R','o','o','t','\\', + 'L','E','G','A','C','Y','_','B','O','G','U','S',0}; SetLastError(0xdeadbeef); set = pSetupDiGetClassDevsW(&guid, NULL, 0, DIGCF_DEVICEINTERFACE); - if (set == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - { - skip("W-functions are not implemented\n"); - return; - } ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevsW failed: %08x\n", GetLastError()); SetLastError(0xdeadbeef); @@ -1012,12 +1276,11 @@ static void testDeviceRegistryPropertyW() todo_wine ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY, "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError()); - SetLastError(0xdeadbeef); + /* GetLastError() returns nonsense in win2k3 */ ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, NULL, 0); todo_wine - ok(!ret && GetLastError() == ERROR_INVALID_DATA, - "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + ok(!ret, "Expected failure, got %d\n", ret); SetLastError(0xdeadbeef); ret = pSetupDiSetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, (PBYTE)friendlyName, buflen); @@ -1035,11 +1298,10 @@ static void testDeviceRegistryPropertyW() todo_wine ok(!ret && GetLastError() == ERROR_INVALID_REG_PROPERTY, "Expected ERROR_INVALID_REG_PROPERTY, got %08x\n", GetLastError()); - SetLastError(0xdeadbeef); + /* GetLastError() returns nonsense in win2k3 */ ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, NULL, NULL, buflen, NULL); - ok(!ret && GetLastError() == ERROR_INVALID_DATA, - "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); + ok(!ret, "Expected failure, got %d\n", ret); SetLastError(0xdeadbeef); ret = pSetupDiGetDeviceRegistryPropertyW(set, &devInfo, SPDRP_FRIENDLYNAME, NULL, NULL, 0, &size); @@ -1068,21 +1330,47 @@ static void testDeviceRegistryPropertyW() ok(!ret && GetLastError() == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %08x\n", GetLastError()); pSetupDiDestroyDeviceInfoList(set); + + res = RegOpenKeyW(HKEY_LOCAL_MACHINE, bogus, &key); + todo_wine + ok(res == ERROR_FILE_NOT_FOUND, "Expected key to not exist\n"); + /* FIXME: Remove when Wine is fixed */ + if (res == ERROR_SUCCESS) + { + /* Wine doesn't delete the information currently */ + trace("We are most likely on Wine\n"); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, bogus); +} } START_TEST(devinst) { + HDEVINFO set; + init_function_pointers(); - if (pSetupDiCreateDeviceInfoListExW && pSetupDiDestroyDeviceInfoList) + /* Win9x/WinMe does things totally different so we skip all the tests + * + * We don't want to exclude NT4 so hence this check. + */ + SetLastError(0xdeadbeef); + set = pSetupDiGetClassDevsW(NULL, NULL, 0, 0); + if (set == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Win9x/WinMe has totally different behavior\n"); + return; + } + + if (pSetupDiCreateDeviceInfoListExW) test_SetupDiCreateDeviceInfoListEx(); else - skip("SetupDiCreateDeviceInfoListExW and/or SetupDiDestroyDeviceInfoList not available\n"); + win_skip("SetupDiCreateDeviceInfoListExW is not available\n"); if (pSetupDiOpenClassRegKeyExA) test_SetupDiOpenClassRegKeyExA(); else - skip("SetupDiOpenClassRegKeyExA is not available\n"); + win_skip("SetupDiOpenClassRegKeyExA is not available\n"); + testInstallClass(); testCreateDeviceInfo(); testGetDeviceInstanceId(); diff --git a/rostests/winetests/setupapi/install.c b/rostests/winetests/setupapi/install.c index 0044f019e4b..5361238fb3b 100644 --- a/rostests/winetests/setupapi/install.c +++ b/rostests/winetests/setupapi/install.c @@ -30,6 +30,7 @@ #include "winreg.h" #include "winsvc.h" #include "setupapi.h" +#include "shlobj.h" #include "wine/test.h" @@ -137,6 +138,44 @@ static void test_cmdline(void) ok(DeleteFile(infwithspaces), "Expected source inf to exist, last error was %d\n", GetLastError()); } +static const char *cmdline_inf_reg = "[Version]\n" + "Signature=\"$Chicago$\"\n" + "[DefaultInstall]\n" + "DelReg=Del.Settings\n" + "[Del.Settings]\n" + "HKCU,Software\\Wine\\setupapitest\n"; + +static void test_registry(void) +{ + HKEY key; + LONG res; + char path[MAX_PATH]; + + /* First create a registry structure we would like to be deleted */ + ok(!RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest", &key), + "Expected RegCreateKeyA to succeed\n"); + + /* Doublecheck if the registry key is present */ + ok(!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest", &key), + "Expected registry key to exist\n"); + + create_inf_file(inffile, cmdline_inf_reg); + sprintf(path, "%s\\%s", CURR_DIR, inffile); + run_cmdline("DefaultInstall", 128, path); + + /* Check if the registry key is recursively deleted */ + res = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest", &key); + todo_wine + ok(res == ERROR_FILE_NOT_FOUND, "Didn't expect the registry key to exist\n"); + /* Just in case */ + if (res == ERROR_SUCCESS) + { + RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest"); + RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest"); + } + ok(DeleteFile(inffile), "Expected source inf to exist, last error was %d\n", GetLastError()); +} + static void test_install_svc_from(void) { char inf[2048]; @@ -151,7 +190,7 @@ static void test_install_svc_from(void) if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("OpenSCManagerA is not implemented, we are most likely on win9x\n"); + win_skip("OpenSCManagerA is not implemented, we are most likely on win9x\n"); return; } CloseServiceHandle(scm_handle); @@ -249,6 +288,13 @@ static void test_install_svc_from(void) infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL); SetLastError(0xdeadbeef); ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + skip("Not enough rights to install the service\n"); + SetupCloseInfFile(infhandle); + DeleteFile(inffile); + return; + } ok(ret, "Expected success\n"); ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %08x\n", GetLastError()); @@ -302,7 +348,12 @@ static void test_driver_install(void) if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { - skip("OpenSCManagerA is not implemented, we are most likely on win9x\n"); + win_skip("OpenSCManagerA is not implemented, we are most likely on win9x\n"); + return; + } + else if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED)) + { + skip("Not enough rights to install the service\n"); return; } CloseServiceHandle(scm_handle); @@ -344,6 +395,77 @@ static void test_driver_install(void) DeleteFile(driver); } +static void test_profile_items(void) +{ + char path[MAX_PATH], commonprogs[MAX_PATH]; + HMODULE hShell32; + BOOL (WINAPI *pSHGetFolderPathA)(HWND hwnd, int nFolder, HANDLE hToken, DWORD dwFlags, LPSTR pszPath); + + static const char *inf = + "[Version]\n" + "Signature=\"$Chicago$\"\n" + "[DefaultInstall]\n" + "ProfileItems=TestItem,TestItem2,TestGroup\n" + "[TestItem]\n" + "Name=TestItem\n" + "CmdLine=11,,notepad.exe\n" + "[TestItem2]\n" + "Name=TestItem2\n" + "CmdLine=11,,notepad.exe\n" + "SubDir=TestDir\n" + "[TestGroup]\n" + "Name=TestGroup,4\n" + ; + + hShell32 = LoadLibraryA("shell32"); + pSHGetFolderPathA = (void*)GetProcAddress(hShell32, "SHGetFolderPathA"); + if (!pSHGetFolderPathA) + { + win_skip("SHGetFolderPathA is not available\n"); + goto cleanup; + } + + if (S_OK != pSHGetFolderPathA(NULL, CSIDL_COMMON_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, commonprogs)) + { + skip("No common program files directory exists\n"); + goto cleanup; + } + + create_inf_file(inffile, inf); + sprintf(path, "%s\\%s", CURR_DIR, inffile); + run_cmdline("DefaultInstall", 128, path); + + snprintf(path, MAX_PATH, "%s\\TestItem.lnk", commonprogs); + if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(path)) + { + win_skip("ProfileItems not implemented on this system\n"); + } + else + { + snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs); + ok(INVALID_FILE_ATTRIBUTES != GetFileAttributes(path), "directory not created\n"); + snprintf(path, MAX_PATH, "%s\\TestDir\\TestItem2.lnk", commonprogs); + ok(INVALID_FILE_ATTRIBUTES != GetFileAttributes(path), "link not created\n"); + snprintf(path, MAX_PATH, "%s\\TestGroup", commonprogs); + ok(INVALID_FILE_ATTRIBUTES != GetFileAttributes(path), "group not created\n"); + } + + snprintf(path, MAX_PATH, "%s\\TestItem.lnk", commonprogs); + DeleteFile(path); + snprintf(path, MAX_PATH, "%s\\TestDir\\TestItem2.lnk", commonprogs); + DeleteFile(path); + snprintf(path, MAX_PATH, "%s\\TestItem2.lnk", commonprogs); + DeleteFile(path); + snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs); + RemoveDirectory(path); + snprintf(path, MAX_PATH, "%s\\TestGroup", commonprogs); + RemoveDirectory(path); + +cleanup: + if (hShell32) FreeLibrary(hShell32); + DeleteFile(inffile); +} + START_TEST(install) { HMODULE hsetupapi = GetModuleHandle("setupapi.dll"); @@ -378,7 +500,7 @@ START_TEST(install) ok(DeleteFile(inffile), "Expected source inf to exist, last error was %d\n", GetLastError()); } if (!pInstallHinfSectionW && !pInstallHinfSectionA) - skip("InstallHinfSectionA and InstallHinfSectionW are not available\n"); + win_skip("InstallHinfSectionA and InstallHinfSectionW are not available\n"); else { /* Set CBT hook to disallow MessageBox creation in current thread */ @@ -386,10 +508,15 @@ START_TEST(install) assert(hhook != 0); test_cmdline(); + test_registry(); test_install_svc_from(); test_driver_install(); UnhookWindowsHookEx(hhook); + + /* We have to run this test after the CBT hook is disabled because + ProfileItems needs to create a window on Windows XP. */ + test_profile_items(); } SetCurrentDirectory(prev_path); diff --git a/rostests/winetests/setupapi/misc.c b/rostests/winetests/setupapi/misc.c index f8750b60154..e110e221e8b 100644 --- a/rostests/winetests/setupapi/misc.c +++ b/rostests/winetests/setupapi/misc.c @@ -47,29 +47,22 @@ static BOOL (WINAPI *pSetupGetFileCompressionInfoExA)(PCSTR, PSTR, DWORD, PDWORD static BOOL (WINAPI *pSetupCopyOEMInfA)(PCSTR, PCSTR, DWORD, DWORD, PSTR, DWORD, PDWORD, PSTR *); static BOOL (WINAPI *pSetupQueryInfOriginalFileInformationA)(PSP_INF_INFORMATION, UINT, PSP_ALTPLATFORM_INFO, PSP_ORIGINAL_FILE_INFO_A); -static void append_str(char **str, const char *data) -{ - sprintf(*str, data); - *str += strlen(*str); -} - static void create_inf_file(LPCSTR filename) { - char data[1024]; - char *ptr = data; DWORD dwNumberOfBytesWritten; HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - append_str(&ptr, "[Version]\n"); - append_str(&ptr, "Signature=\"$Chicago$\"\n"); - append_str(&ptr, "AdvancedINF=2.5\n"); - append_str(&ptr, "[DefaultInstall]\n"); - append_str(&ptr, "RegisterOCXs=RegisterOCXsSection\n"); - append_str(&ptr, "[RegisterOCXsSection]\n"); - append_str(&ptr, "%%11%%\\ole32.dll\n"); + static const char data[] = + "[Version]\n" + "Signature=\"$Chicago$\"\n" + "AdvancedINF=2.5\n" + "[DefaultInstall]\n" + "RegisterOCXs=RegisterOCXsSection\n" + "[RegisterOCXsSection]\n" + "%%11%%\\ole32.dll\n"; - WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); + WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL); CloseHandle(hf); } @@ -114,7 +107,7 @@ static void test_original_file_name(LPCSTR original, LPCSTR dest) if (!pSetupQueryInfOriginalFileInformationA) { - skip("SetupQueryInfOriginalFileInformationA is not available\n"); + win_skip("SetupQueryInfOriginalFileInformationA is not available\n"); return; } @@ -151,7 +144,7 @@ static void test_SetupCopyOEMInf(void) CHAR toolong[MAX_PATH * 2]; CHAR path[MAX_PATH], dest[MAX_PATH]; CHAR tmpfile[MAX_PATH], dest_save[MAX_PATH]; - LPSTR inf; + LPSTR inf = NULL; DWORD size; BOOL res; @@ -166,8 +159,10 @@ static void test_SetupCopyOEMInf(void) SetLastError(0xdeadbeef); res = pSetupCopyOEMInfA("", NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); ok(res == FALSE, "Expected FALSE, got %d\n", res); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_BAD_PATHNAME || /* Win98 */ + GetLastError() == ERROR_INVALID_PARAMETER, /* Vista, W2K8 */ + "Unexpected error : %d\n", GetLastError()); /* try a relative nonexistent SourceInfFileName */ SetLastError(0xdeadbeef); @@ -191,8 +186,9 @@ static void test_SetupCopyOEMInf(void) SetLastError(0xdeadbeef); res = pSetupCopyOEMInfA(toolong, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); ok(res == FALSE, "Expected FALSE, got %d\n", res); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_FILENAME_EXCED_RANGE, /* Win98 */ + "Expected ERROR_FILE_NOT_FOUND or ERROR_FILENAME_EXCED_RANGE, got %d\n", GetLastError()); get_temp_filename(tmpfile); create_inf_file(tmpfile); @@ -201,8 +197,20 @@ static void test_SetupCopyOEMInf(void) SetLastError(0xdeadbeef); res = pSetupCopyOEMInfA(tmpfile, NULL, 0, SP_COPY_NOOVERWRITE, NULL, 0, NULL, NULL); ok(res == FALSE, "Expected FALSE, got %d\n", res); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, - "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + if (GetLastError() == ERROR_WRONG_INF_TYPE) + { + /* FIXME: + * Vista needs a [Manufacturer] entry in the inf file. Doing this will give some + * popups during the installation though as it also needs a catalog file (signed?). + */ + win_skip("Needs a different inf file on Vista/W2K8\n"); + DeleteFile(tmpfile); + return; + } + + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_FILE_EXISTS, /* Win98 */ + "Expected ERROR_FILE_NOT_FOUND or ERROR_FILE_EXISTS, got %d\n", GetLastError()); ok(file_exists(tmpfile), "Expected tmpfile to exist\n"); /* try SP_COPY_REPLACEONLY, dest does not exist */ @@ -285,6 +293,9 @@ static void test_SetupCopyOEMInf(void) ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); ok(lstrlen(dest) + 1 == size, "Expected sizes to match, got (%d, %d)\n", lstrlen(dest), size); ok(file_exists(dest), "Expected destination inf to exist\n"); + ok((inf && inf[0] != 0) || + broken(!inf), /* Win98 */ + "Expected inf to point to the filename\n"); ok(check_format(dest, inf), "Expected %%windir%%\\inf\\OEMx.inf, got %s\n", dest); ok(file_exists(path), "Expected source inf to exist\n"); ok(size == lstrlen(dest_save) + 1, "Expected size to be lstrlen(dest_save) + 1\n"); @@ -400,6 +411,7 @@ static void test_SetupGetFileCompressionInfo(void) ok(target_size == sizeof(uncompressed), "got %d\n", target_size); ok(type == FILE_COMPRESSION_NONE, "got %d, expected FILE_COMPRESSION_NONE\n", type); + MyFree(name); DeleteFileA(source); } @@ -582,14 +594,14 @@ START_TEST(misc) if (pSetupCopyOEMInfA) test_SetupCopyOEMInf(); else - skip("SetupCopyOEMInfA is not available\n"); + win_skip("SetupCopyOEMInfA is not available\n"); test_SetupGetFileCompressionInfo(); if (pSetupGetFileCompressionInfoExA) test_SetupGetFileCompressionInfoEx(); else - skip("SetupGetFileCompressionInfoExA is not available\n"); + win_skip("SetupGetFileCompressionInfoExA is not available\n"); test_SetupDecompressOrCopyFile(); } diff --git a/rostests/winetests/setupapi/parser.c b/rostests/winetests/setupapi/parser.c index 6341222819e..06bffaf13bb 100644 --- a/rostests/winetests/setupapi/parser.c +++ b/rostests/winetests/setupapi/parser.c @@ -33,12 +33,14 @@ /* function pointers */ static HMODULE hSetupAPI; static LPCWSTR (WINAPI *pSetupGetField)(PINFCONTEXT,DWORD); +static BOOL (WINAPI *pSetupEnumInfSectionsA)( HINF hinf, UINT index, PSTR buffer, DWORD size, UINT *need ); static void init_function_pointers(void) { hSetupAPI = GetModuleHandleA("setupapi.dll"); pSetupGetField = (void *)GetProcAddress(hSetupAPI, "pSetupGetField"); + pSetupEnumInfSectionsA = (void *)GetProcAddress(hSetupAPI, "SetupEnumInfSectionsA" ); } static const char tmpfilename[] = ".\\tmp.inf"; @@ -52,6 +54,7 @@ static const char tmpfilename[] = ".\\tmp.inf"; #define A400 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ "aaaaaaaaaaaaaaaa" A256 +#define A1200 A400 A400 A400 #define A511 A255 A256 #define A4097 "a" A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 A256 @@ -61,7 +64,7 @@ static const char tmpfilename[] = ".\\tmp.inf"; "per%%cent=abcd\nper=1\ncent=2\n22=foo\n" \ "big=" A400 "\n" \ "mydrive=\"C:\\\"\n" \ - "verybig=" A400 A400 A400 "\n" + "verybig=" A1200 "\n" /* create a new file with specified contents and open it */ static HINF test_file_contents( const char *data, UINT *err_line ) @@ -245,6 +248,52 @@ static void test_section_names(void) } } +static void test_enum_sections(void) +{ + static const char *contents = STD_HEADER "[s1]\nfoo=bar\n[s2]\nbar=foo\n[s3]\n[strings]\na=b\n"; + + BOOL ret; + DWORD len; + HINF hinf; + UINT err, index; + char buffer[256]; + + if (!pSetupEnumInfSectionsA) + { + win_skip( "SetupEnumInfSectionsA not available\n" ); + return; + } + + hinf = test_file_contents( contents, &err ); + ok( hinf != NULL, "Expected valid INF file\n" ); + + for (index = 0; ; index++) + { + SetLastError( 0xdeadbeef ); + ret = pSetupEnumInfSectionsA( hinf, index, NULL, 0, &len ); + err = GetLastError(); + if (!ret && GetLastError() == ERROR_NO_MORE_ITEMS) break; + ok( ret, "SetupEnumInfSectionsA failed\n" ); + ok( len == 3 || len == 8, "wrong len %u\n", len ); + + SetLastError( 0xdeadbeef ); + ret = pSetupEnumInfSectionsA( hinf, index, NULL, sizeof(buffer), &len ); + err = GetLastError(); + ok( !ret, "SetupEnumInfSectionsA succeeded\n" ); + ok( err == ERROR_INVALID_USER_BUFFER, "wrong error %u\n", err ); + ok( len == 3 || len == 8, "wrong len %u\n", len ); + + SetLastError( 0xdeadbeef ); + ret = pSetupEnumInfSectionsA( hinf, index, buffer, sizeof(buffer), &len ); + ok( ret, "SetupEnumInfSectionsA failed err %u\n", GetLastError() ); + ok( len == 3 || len == 8, "wrong len %u\n", len ); + ok( !lstrcmpi( buffer, "version" ) || !lstrcmpi( buffer, "s1" ) || + !lstrcmpi( buffer, "s2" ) || !lstrcmpi( buffer, "s3" ) || !lstrcmpi( buffer, "strings" ), + "bad section '%s'\n", buffer ); + } + SetupCloseInfFile( hinf ); +} + /* Test various key and value names */ @@ -315,7 +364,7 @@ static const struct { "loop=%loop%\n" STR_SECTION, "loop", { "%loop2%" } }, { "%per%%cent%=100\n" STR_SECTION, "12", { "100" } }, { "a=%big%\n" STR_SECTION, "a", { A400 } }, - { "a=%verybig%\n" STR_SECTION, "a", { A511 } }, /* truncated to 511 */ + { "a=%verybig%\n" STR_SECTION, "a", { A511 } }, /* truncated to 511, not on Vista/W2K8 */ { "a=%big%%big%%big%%big%\n" STR_SECTION, "a", { A400 A400 A400 A400 } }, { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION, "a", { A400 A400 A400 A400 A400 A400 A400 A400 A400 } }, { "a=%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%%big%\n" STR_SECTION, "a", { A4097 /*MAX_INF_STRING_LENGTH+1*/ } }, @@ -384,8 +433,21 @@ static void test_key_names(void) { ok( err == 0, "line %u: bad error %u\n", i, err ); if (key_names[i].fields[index]) + { + if (i == 49) + ok( !strcmp( field, key_names[i].fields[index] ) || + !strcmp( field, A1200), /* Vista, W2K8 */ + "line %u: bad field %s/%s\n", + i, field, key_names[i].fields[index] ); + else /* don't compare drive letter of paths */ + if (field[0] && field[1] == ':' && field[2] == '\\') + ok( !strcmp( field + 1, key_names[i].fields[index] + 1 ), + "line %u: bad field %s/%s\n", + i, field, key_names[i].fields[index] ); + else ok( !strcmp( field, key_names[i].fields[index] ), "line %u: bad field %s/%s\n", i, field, key_names[i].fields[index] ); + } else ok( 0, "line %u: got extra field %s\n", i, field ); strcat( buffer, "," ); @@ -416,12 +478,15 @@ static void test_close_inf_file(void) { SetLastError(0xdeadbeef); SetupCloseInfFile(NULL); - ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef || + GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */ + "Expected 0xdeadbeef, got %u\n", GetLastError()); SetLastError(0xdeadbeef); SetupCloseInfFile(INVALID_HANDLE_VALUE); - ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %u\n", GetLastError()); - + ok(GetLastError() == 0xdeadbeef || + GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x, WinMe */ + "Expected 0xdeadbeef, got %u\n", GetLastError()); } static const char *contents = "[Version]\n" @@ -447,6 +512,7 @@ static void test_pSetupGetField(void) LPCWSTR field; INFCONTEXT context; int i; + int len; hinf = test_file_contents( contents, &err ); ok( hinf != NULL, "Expected valid INF file\n" ); @@ -465,7 +531,11 @@ static void test_pSetupGetField(void) field = pSetupGetField( &context, 3 ); ok( field != NULL, "Failed to get field 3\n" ); - ok( lstrlenW( field ) == 511, "Expected 511, got %d\n", lstrlenW( field ) ); + len = lstrlenW( field ); + ok( len == 511 /* NT4, W2K, XP and W2K3 */ || + len == 4096 /* Vista */ || + len == 256 /* Win9x and WinME */, + "Unexpected length, got %d\n", len ); field = pSetupGetField( &context, 4 ); ok( field == NULL, "Expected NULL, got %p\n", field ); @@ -519,18 +589,18 @@ static void test_SetupGetIntField(void) retb = SetupGetIntField( &context, keys[i].index, &intfield ); if ( keys[i].err == ERROR_SUCCESS ) { - ok( retb, "Expected success\n" ); + ok( retb, "%u: Expected success\n", i ); ok( GetLastError() == ERROR_SUCCESS || GetLastError() == 0xdeadbeef /* win9x, NT4 */, - "Expected ERROR_SUCCESS or 0xdeadbeef, got %u\n", GetLastError() ); + "%u: Expected ERROR_SUCCESS or 0xdeadbeef, got %u\n", i, GetLastError() ); } else { - ok( !retb, "Expected failure\n" ); + ok( !retb, "%u: Expected failure\n", i ); ok( GetLastError() == keys[i].err, - "Expected %d, got %u\n", keys[i].err, GetLastError() ); + "%u: Expected %d, got %u\n", i, keys[i].err, GetLastError() ); } - ok( intfield == keys[i].value, "Expected %d, got %d\n", keys[i].value, intfield ); + ok( intfield == keys[i].value, "%u: Expected %d, got %d\n", i, keys[i].value, intfield ); SetupCloseInfFile( hinf ); } @@ -655,6 +725,7 @@ START_TEST(parser) init_function_pointers(); test_invalid_files(); test_section_names(); + test_enum_sections(); test_key_names(); test_close_inf_file(); test_pSetupGetField(); diff --git a/rostests/winetests/setupapi/query.c b/rostests/winetests/setupapi/query.c index 87f167306ca..bbc2c659724 100644 --- a/rostests/winetests/setupapi/query.c +++ b/rostests/winetests/setupapi/query.c @@ -43,56 +43,68 @@ static void get_directories(void) WIN_DIR[len-1] = 0; } -static void append_str(char **str, const char *data) -{ - sprintf(*str, data); - *str += strlen(*str); -} +static const char inf_data1[] = + "[Version]\n" + "Signature=\"$Chicago$\"\n" + "AdvancedINF=2.5\n" + "[SourceDisksNames]\n" + "2 = %SrcDiskName%, LANCOM\\LANtools\\lanconf.cab\n" + "[SourceDisksFiles]\n" + "lanconf.exe = 2\n" + "[DestinationDirs]\n" + "DefaultDestDir = 24, %DefaultDest%\n" + "[Strings]\n" + "LangDir = english\n" + "DefaultDest = LANCOM\n" + "SrcDiskName = \"LANCOM Software CD\"\n"; -static void create_inf_file(LPSTR filename) +static const char inf_data2[] = + "[SourceFileInfo]\n" + "sp1qfe\\bitsinst.exe=250B3702C7CCD7C2F9E4DAA1555C933E,000600060A28062C,27136,SP1QFE\n" + "sp1qfe\\bitsprx2.dll=4EBEA67F4BB4EB402E725CA7CA2857AE,000600060A280621,7680,SP1QFE\n" + "sp1qfe\\bitsprx3.dll=C788A1D9330DA011EF25E95D3BC7BDE5,000600060A280621,7168,SP1QFE\n" + "sp1qfe\\qmgr.dll=696AC82FB290A03F205901442E0E9589,000600060A280621,361984,SP1QFE\n" + "sp1qfe\\qmgrprxy.dll=8B5848144829E1BC985EA4C3D8CA7E3F,000600060A280621,17408,SP1QFE\n" + "sp1qfe\\winhttp.dll=3EC6F518114606CA59D4160322077437,000500010A280615,331776,SP1QFE\n" + "sp1qfe\\xpob2res.dll=DB83156B9F496F20D1EA70E4ABEC0166,000500010A280622,158720,SP1QFE\n"; + +static const char inf_data3[] = + "[Version]\n" + "Signature = \"$Windows NT$\"\n" + "[DestinationDirs]\n" + "CopyAlways.Windir.files = 10\n" + "[CopyAlways.Windir.Files]\n" + "WindowsCodecs.dll\n"; + +static const char inf_data4[] = + "[Version]\n" + "Signature = \"$Windows NT$\"\n" + "[CopyAlways.System32.Files]\n" + "WindowsCodecs.dll\n"; + +static const char inf_data5[] = + "[Version]\n" + "Signature = \"$Windows NT$\"\n" + "[DestinationDirs]\n" + "DefaultDestDir = 11\n" + "CopyAlways.Windir.files = 10\n" + "[CopyAlways.Windir.Files]\n" + "WindowsCodecs.dll\n"; + +static const char inf_data6[] = + "[Version]\n" + "Signature = \"$Windows NT$\"\n" + "[DestinationDirs]\n" + "DefaultDestDir = 10\n" + "[CopyAlways.Windir.Files]\n" + "WindowsCodecs.dll\n"; + +static void create_inf_file(LPSTR filename, const char *data, DWORD size) { - char data[1024]; - char *ptr = data; DWORD dwNumberOfBytesWritten; HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - append_str(&ptr, "[Version]\n"); - append_str(&ptr, "Signature=\"$Chicago$\"\n"); - append_str(&ptr, "AdvancedINF=2.5\n"); - append_str(&ptr, "[SourceDisksNames]\n"); - append_str(&ptr, "2 = %%SrcDiskName%%, LANCOM\\LANtools\\lanconf.cab\n"); - append_str(&ptr, "[SourceDisksFiles]\n"); - append_str(&ptr, "lanconf.exe = 2\n"); - append_str(&ptr, "[DestinationDirs]\n"); - append_str(&ptr, "DefaultDestDir = 24, %%DefaultDest%%\n"); - append_str(&ptr, "[Strings]\n"); - append_str(&ptr, "LangDir = english\n"); - append_str(&ptr, "DefaultDest = LANCOM\n"); - append_str(&ptr, "SrcDiskName = \"LANCOM Software CD\"\n"); - - WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); - CloseHandle(hf); -} - -static void create_inf_file2(LPSTR filename) -{ - char data[1024]; - char *ptr = data; - DWORD dwNumberOfBytesWritten; - HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - append_str(&ptr, "[SourceFileInfo]\n"); - append_str(&ptr, "sp1qfe\\bitsinst.exe=250B3702C7CCD7C2F9E4DAA1555C933E,000600060A28062C,27136,SP1QFE\n"); - append_str(&ptr, "sp1qfe\\bitsprx2.dll=4EBEA67F4BB4EB402E725CA7CA2857AE,000600060A280621,7680,SP1QFE\n"); - append_str(&ptr, "sp1qfe\\bitsprx3.dll=C788A1D9330DA011EF25E95D3BC7BDE5,000600060A280621,7168,SP1QFE\n"); - append_str(&ptr, "sp1qfe\\qmgr.dll=696AC82FB290A03F205901442E0E9589,000600060A280621,361984,SP1QFE\n"); - append_str(&ptr, "sp1qfe\\qmgrprxy.dll=8B5848144829E1BC985EA4C3D8CA7E3F,000600060A280621,17408,SP1QFE\n"); - append_str(&ptr, "sp1qfe\\winhttp.dll=3EC6F518114606CA59D4160322077437,000500010A280615,331776,SP1QFE\n"); - append_str(&ptr, "sp1qfe\\xpob2res.dll=DB83156B9F496F20D1EA70E4ABEC0166,000500010A280622,158720,SP1QFE\n"); - - WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); + WriteFile(hf, data, size, &dwNumberOfBytesWritten, NULL); CloseHandle(hf); } @@ -136,6 +148,7 @@ static void test_SetupGetInfInformation(void) PSP_INF_INFORMATION info; CHAR inf_filename[MAX_PATH]; CHAR inf_one[MAX_PATH], inf_two[MAX_PATH]; + LPSTR revfile; DWORD size; HINF hinf; BOOL ret; @@ -149,11 +162,20 @@ static void test_SetupGetInfInformation(void) SetLastError(0xbeefcafe); ret = SetupGetInfInformationA(NULL, INFINFO_INF_SPEC_IS_HINF, NULL, 0, &size); ok(ret == FALSE, "Expected SetupGetInfInformation to fail\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, + ok(GetLastError() == ERROR_INVALID_HANDLE || + broken(GetLastError() == ERROR_BAD_PATHNAME) || /* win95 */ + broken(GetLastError() == ERROR_FILE_NOT_FOUND) || /* win98 */ + broken(GetLastError() == ERROR_PATH_NOT_FOUND) || /* NT4 */ + broken(GetLastError() == ERROR_INVALID_NAME) || /* win2k */ + broken(GetLastError() == ERROR_GENERAL_SYNTAX), /* another win2k */ "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); ok(size == 0xdeadbeef, "Expected size to remain unchanged\n"); /* try an invalid inf filename */ + /* do not use NULL as absolute inf filename on win9x (crash) */ + if ((GetLastError() != ERROR_BAD_PATHNAME) && /* win95 */ + (GetLastError() != ERROR_FILE_NOT_FOUND)) /* win98 */ + { size = 0xdeadbeef; SetLastError(0xbeefcafe); ret = SetupGetInfInformationA(NULL, INFINFO_INF_NAME_IS_ABSOLUTE, NULL, 0, &size); @@ -161,8 +183,9 @@ static void test_SetupGetInfInformation(void) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); ok(size == 0xdeadbeef, "Expected size to remain unchanged\n"); + } - create_inf_file(inf_filename); + create_inf_file(inf_filename, inf_data1, sizeof(inf_data1) - 1); /* try an invalid search flag */ size = 0xdeadbeef; @@ -231,22 +254,32 @@ static void test_SetupGetInfInformation(void) ok(check_info_filename(info, inf_filename), "Expected returned filename to be equal\n"); SetupCloseInfFile(hinf); - lstrcpyA(inf_one, WIN_DIR); - lstrcatA(inf_one, "\\inf\\"); - lstrcatA(inf_one, "test.inf"); - create_inf_file(inf_one); - lstrcpyA(inf_two, WIN_DIR); lstrcatA(inf_two, "\\system32\\"); lstrcatA(inf_two, "test.inf"); - create_inf_file(inf_two); + create_inf_file(inf_two, inf_data1, sizeof(inf_data1) - 1); + + HeapFree(GetProcessHeap(), 0, info); + info = alloc_inf_info("test.inf", INFINFO_DEFAULT_SEARCH, &size); + + /* check if system32 is searched for inf */ + ret = SetupGetInfInformationA("test.inf", INFINFO_DEFAULT_SEARCH, info, size, &size); + if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND) + revfile = inf_one; /* Vista */ + else + revfile = inf_two; + + lstrcpyA(inf_one, WIN_DIR); + lstrcatA(inf_one, "\\inf\\"); + lstrcatA(inf_one, "test.inf"); + create_inf_file(inf_one, inf_data1, sizeof(inf_data1) - 1); HeapFree(GetProcessHeap(), 0, info); info = alloc_inf_info("test.inf", INFINFO_DEFAULT_SEARCH, &size); /* test the INFINFO_DEFAULT_SEARCH search flag */ ret = SetupGetInfInformationA("test.inf", INFINFO_DEFAULT_SEARCH, info, size, &size); - ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); + ok(ret == TRUE, "Expected SetupGetInfInformation to succeed: %d\n", GetLastError()); ok(check_info_filename(info, inf_one), "Expected returned filename to be equal\n"); HeapFree(GetProcessHeap(), 0, info); @@ -255,7 +288,9 @@ static void test_SetupGetInfInformation(void) /* test the INFINFO_REVERSE_DEFAULT_SEARCH search flag */ ret = SetupGetInfInformationA("test.inf", INFINFO_REVERSE_DEFAULT_SEARCH, info, size, &size); ok(ret == TRUE, "Expected SetupGetInfInformation to succeed\n"); - ok(check_info_filename(info, inf_two), "Expected returned filename to be equal\n"); + ok(check_info_filename(info, revfile), "Expected returned filename to be equal\n"); + + HeapFree(GetProcessHeap(), 0, info); DeleteFileA(inf_filename); DeleteFileA(inf_one); @@ -274,7 +309,7 @@ static void test_SetupGetSourceFileLocation(void) lstrcatA(inf_filename, "\\"); lstrcatA(inf_filename, "test.inf"); - create_inf_file(inf_filename); + create_inf_file(inf_filename, inf_data1, sizeof(inf_data1) - 1); hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); @@ -292,7 +327,7 @@ static void test_SetupGetSourceFileLocation(void) SetupCloseInfFile(hinf); DeleteFileA(inf_filename); - create_inf_file2(inf_filename); + create_inf_file(inf_filename, inf_data2, sizeof(inf_data2) - 1); SetLastError(0xdeadbeef); hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); @@ -321,7 +356,7 @@ static void test_SetupGetSourceInfo(void) lstrcatA(inf_filename, "\\"); lstrcatA(inf_filename, "test.inf"); - create_inf_file(inf_filename); + create_inf_file(inf_filename, inf_data1, sizeof(inf_data1) - 1); hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); @@ -359,6 +394,7 @@ static void test_SetupGetSourceInfo(void) static void test_SetupGetTargetPath(void) { char buffer[MAX_PATH], inf_filename[MAX_PATH]; + char destfile[MAX_PATH]; DWORD required; HINF hinf; INFCONTEXT ctx; @@ -368,7 +404,7 @@ static void test_SetupGetTargetPath(void) lstrcatA(inf_filename, "\\"); lstrcatA(inf_filename, "test.inf"); - create_inf_file(inf_filename); + create_inf_file(inf_filename, inf_data1, sizeof(inf_data1) - 1); hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); @@ -382,9 +418,86 @@ static void test_SetupGetTargetPath(void) ret = SetupGetTargetPathA(hinf, &ctx, NULL, buffer, sizeof(buffer), &required); ok(ret, "SetupGetTargetPathA failed\n"); - ok(required == 10, "unexpected required size: %d\n", required); - ok(!lstrcmpiA("C:\\LANCOM", buffer), "unexpected result string: %s\n", buffer); + /* Retrieve the system drive from the windows directory. + * (%SystemDrive% is not available on Win9x) + */ + lstrcpyA(destfile, WIN_DIR); + destfile[3] = '\0'; + lstrcatA(destfile, "LANCOM"); + ok(!lstrcmpiA(destfile, buffer), "unexpected result string: %s\n", buffer); + + SetupCloseInfFile(hinf); + DeleteFileA(inf_filename); + + create_inf_file(inf_filename, inf_data3, sizeof(inf_data3) - 1); + + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); + + required = 0; + + ret = SetupGetTargetPathA(hinf, NULL, "CopyAlways.Windir.Files", buffer, sizeof(buffer), &required); + ok(ret, "SetupGetTargetPathA failed\n"); + + lstrcpyA(destfile, WIN_DIR); + + ok(required == lstrlenA(destfile) + 1, "unexpected required size: %d\n", required); + ok(!lstrcmpiA(buffer, destfile), "unexpected path: %s\n", buffer); + + SetupCloseInfFile(hinf); + DeleteFileA(inf_filename); + + create_inf_file(inf_filename, inf_data4, sizeof(inf_data4) - 1); + + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); + + required = 0; + + ret = SetupGetTargetPathA(hinf, NULL, "CopyAlways.System32.Files", buffer, sizeof(buffer), &required); + ok(ret, "SetupGetTargetPathA failed\n"); + + GetSystemDirectoryA(destfile, MAX_PATH); + + ok(required == lstrlenA(destfile) + 1, "unexpected required size: %d\n", required); + ok(!lstrcmpiA(buffer, destfile), "unexpected path: %s\n", buffer); + + SetupCloseInfFile(hinf); + DeleteFileA(inf_filename); + + create_inf_file(inf_filename, inf_data5, sizeof(inf_data5) - 1); + + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); + + required = 0; + + ret = SetupGetTargetPathA(hinf, NULL, "CopyAlways.Windir.Files", buffer, sizeof(buffer), &required); + ok(ret, "SetupGetTargetPathA failed\n"); + + lstrcpyA(destfile, WIN_DIR); + + ok(required == lstrlenA(destfile) + 1, "unexpected required size: %d\n", required); + ok(!lstrcmpiA(buffer, destfile), "unexpected path: %s\n", buffer); + + SetupCloseInfFile(hinf); + DeleteFileA(inf_filename); + + create_inf_file(inf_filename, inf_data6, sizeof(inf_data6) - 1); + + hinf = SetupOpenInfFileA(inf_filename, NULL, INF_STYLE_WIN4, NULL); + ok(hinf != INVALID_HANDLE_VALUE, "could not open inf file\n"); + + required = 0; + + ret = SetupGetTargetPathA(hinf, NULL, "CopyAlways.Windir.Files", buffer, sizeof(buffer), &required); + ok(ret, "SetupGetTargetPathA failed\n"); + + lstrcpyA(destfile, WIN_DIR); + + ok(required == lstrlenA(destfile) + 1, "unexpected required size: %d\n", required); + ok(!lstrcmpiA(buffer, destfile), "unexpected path: %s\n", buffer); SetupCloseInfFile(hinf); DeleteFileA(inf_filename); diff --git a/rostests/winetests/setupapi/setupapi.rbuild b/rostests/winetests/setupapi/setupapi.rbuild index 11bc062bb00..e8567fdabcd 100644 --- a/rostests/winetests/setupapi/setupapi.rbuild +++ b/rostests/winetests/setupapi/setupapi.rbuild @@ -1,11 +1,9 @@ - . - + ntdll - kernel32 advapi32 setupapi user32 @@ -18,4 +16,3 @@ stringtable.c testlist.c - diff --git a/rostests/winetests/setupapi/stringtable.c b/rostests/winetests/setupapi/stringtable.c index 4eca3318553..59c3f17a327 100644 --- a/rostests/winetests/setupapi/stringtable.c +++ b/rostests/winetests/setupapi/stringtable.c @@ -37,10 +37,13 @@ #define ST_CASE_SENSITIVE_COMPARE 0x00000001 static DWORD (WINAPI *pStringTableAddString)(HSTRING_TABLE, LPWSTR, DWORD); +static DWORD (WINAPI *pStringTableAddStringEx)(HSTRING_TABLE, LPWSTR, DWORD, LPVOID, DWORD); static VOID (WINAPI *pStringTableDestroy)(HSTRING_TABLE); static HSTRING_TABLE (WINAPI *pStringTableDuplicate)(HSTRING_TABLE hStringTable); static HSTRING_TABLE (WINAPI *pStringTableInitialize)(VOID); +static HSTRING_TABLE (WINAPI *pStringTableInitializeEx)(DWORD, DWORD); static DWORD (WINAPI *pStringTableLookUpString)(HSTRING_TABLE, LPWSTR, DWORD); +static DWORD (WINAPI *pStringTableLookUpStringEx)(HSTRING_TABLE, LPWSTR, DWORD, LPVOID, DWORD); static LPWSTR (WINAPI *pStringTableStringFromId)(HSTRING_TABLE, DWORD); #if 0 static BOOL (WINAPI *pStringTableStringFromIdEx)(HSTRING_TABLE, DWORD, LPWSTR, LPDWORD); @@ -51,8 +54,6 @@ HMODULE hdll; static WCHAR string[] = {'s','t','r','i','n','g',0}; static WCHAR String[] = {'S','t','r','i','n','g',0}; static WCHAR foo[] = {'f','o','o',0}; -DWORD hstring, hString, hfoo; /* Handles pointing to our strings */ -HANDLE table, table2; /* Handles pointing to our tables */ static void load_it_up(void) { @@ -62,10 +63,18 @@ static void load_it_up(void) if (!pStringTableInitialize) pStringTableInitialize = (void*)GetProcAddress(hdll, "pSetupStringTableInitialize"); + pStringTableInitializeEx = (void*)GetProcAddress(hdll, "StringTableInitializeEx"); + if (!pStringTableInitializeEx) + pStringTableInitializeEx = (void*)GetProcAddress(hdll, "pSetupStringTableInitializeEx"); + pStringTableAddString = (void*)GetProcAddress(hdll, "StringTableAddString"); if (!pStringTableAddString) pStringTableAddString = (void*)GetProcAddress(hdll, "pSetupStringTableAddString"); + pStringTableAddStringEx = (void*)GetProcAddress(hdll, "StringTableAddStringEx"); + if (!pStringTableAddStringEx) + pStringTableAddStringEx = (void*)GetProcAddress(hdll, "pSetupStringTableAddStringEx"); + pStringTableDuplicate = (void*)GetProcAddress(hdll, "StringTableDuplicate"); if (!pStringTableDuplicate) pStringTableDuplicate = (void*)GetProcAddress(hdll, "pSetupStringTableDuplicate"); @@ -78,20 +87,22 @@ static void load_it_up(void) if (!pStringTableLookUpString) pStringTableLookUpString = (void*)GetProcAddress(hdll, "pSetupStringTableLookUpString"); + pStringTableLookUpStringEx = (void*)GetProcAddress(hdll, "StringTableLookUpStringEx"); + if (!pStringTableLookUpStringEx) + pStringTableLookUpStringEx = (void*)GetProcAddress(hdll, "pSetupStringTableLookUpStringEx"); + pStringTableStringFromId = (void*)GetProcAddress(hdll, "StringTableStringFromId"); if (!pStringTableStringFromId) pStringTableStringFromId = (void*)GetProcAddress(hdll, "pSetupStringTableStringFromId"); } -static void test_StringTableInitialize(void) -{ - table=pStringTableInitialize(); - ok(table!=NULL,"Failed to Initialize String Table\n"); -} - static void test_StringTableAddString(void) { - DWORD retval; + DWORD retval, hstring, hString, hfoo; + HANDLE table; + + table=pStringTableInitialize(); + ok(table != NULL, "failed to initialize string table\n"); /* case insensitive */ hstring=pStringTableAddString(table,string,0); @@ -108,18 +119,71 @@ static void test_StringTableAddString(void) /* case sensitive */ hString=pStringTableAddString(table,String,ST_CASE_SENSITIVE_COMPARE); ok(hstring!=hString,"String handle and string share same ID %x in Table\n", hstring); + + pStringTableDestroy(table); +} + +static void test_StringTableAddStringEx(void) +{ + DWORD retval, hstring, hString, hfoo; + HANDLE table; + + table = pStringTableInitialize(); + ok(table != NULL,"Failed to Initialize String Table\n"); + + /* case insensitive */ + hstring = pStringTableAddStringEx(table, string, 0, NULL, 0); + ok(hstring != ~0u, "Failed to add string to String Table\n"); + + retval = pStringTableAddStringEx(table, String, 0, NULL, 0); + ok(retval != ~0u, "Failed to add String to String Table\n"); + ok(hstring == retval, "string handle %x != String handle %x in String Table\n", hstring, retval); + + hfoo = pStringTableAddStringEx(table, foo, 0, NULL, 0); + ok(hfoo != ~0u, "Failed to add foo to String Table\n"); + ok(hfoo != hstring, "foo and string share the same ID %x in String Table\n", hfoo); + + /* case sensitive */ + hString = pStringTableAddStringEx(table, String, ST_CASE_SENSITIVE_COMPARE, NULL, 0); + ok(hstring != hString, "String handle and string share same ID %x in Table\n", hstring); + + pStringTableDestroy(table); } static void test_StringTableDuplicate(void) { + HANDLE table, table2; + + table = pStringTableInitialize(); + ok(table != NULL,"Failed to Initialize String Table\n"); + table2=pStringTableDuplicate(table); ok(table2!=NULL,"Failed to duplicate String Table\n"); + + pStringTableDestroy(table); + pStringTableDestroy(table2); } static void test_StringTableLookUpString(void) { - DWORD retval, retval2; + DWORD retval, retval2, hstring, hString, hfoo; + HANDLE table, table2; + table = pStringTableInitialize(); + ok(table != NULL,"failed to initialize string table\n"); + + hstring = pStringTableAddString(table, string, 0); + ok(hstring != ~0u, "failed to add 'string' to string table\n"); + + hString = pStringTableAddString(table, String, 0); + ok(hString != ~0u,"failed to add 'String' to string table\n"); + + hfoo = pStringTableAddString(table, foo, 0); + ok(hfoo != ~0u, "failed to add 'foo' to string table\n"); + + table2 = pStringTableDuplicate(table); + ok(table2 != NULL, "Failed to duplicate String Table\n"); + /* case insensitive */ retval=pStringTableLookUpString(table,string,0); ok(retval!=-1,"Failed find string in String Table 1\n"); @@ -149,16 +213,109 @@ static void test_StringTableLookUpString(void) retval=pStringTableLookUpString(table,string,ST_CASE_SENSITIVE_COMPARE); retval2=pStringTableLookUpString(table,String,ST_CASE_SENSITIVE_COMPARE); ok(retval!=retval2,"Lookup of string equals String in Table 1\n"); - ok(retval2==hString, + ok(retval==hString, "Lookup for String (%x) does not match previous handle (%x) in String Table 1\n", retval, hString); + + pStringTableDestroy(table); + pStringTableDestroy(table2); +} + +static void test_StringTableLookUpStringEx(void) +{ + static WCHAR uilevel[] = {'U','I','L','E','V','E','L',0}; + DWORD retval, retval2, hstring, hString, hfoo, data; + HANDLE table, table2; + char buffer[4]; + + table = pStringTableInitialize(); + ok(table != NULL,"Failed to Initialize String Table\n"); + + hstring = pStringTableAddString(table, string, 0); + ok(hstring != ~0u, "failed to add 'string' to string table\n"); + + hString = pStringTableAddString(table, String, 0); + ok(hString != ~0u,"failed to add 'String' to string table\n"); + + hfoo = pStringTableAddString(table, foo, 0); + ok(hfoo != ~0u, "failed to add 'foo' to string table\n"); + + table2 = pStringTableDuplicate(table); + ok(table2 != NULL, "Failed to duplicate String Table\n"); + + /* case insensitive */ + retval = pStringTableLookUpStringEx(table, string, 0, NULL, 0); + ok(retval != ~0u, "Failed find string in String Table 1\n"); + ok(retval == hstring, + "Lookup for string (%x) does not match previous handle (%x) in String Table 1\n", + retval, hstring); + + retval = pStringTableLookUpStringEx(table2, string, 0, NULL, 0); + ok(retval != ~0u, "Failed find string in String Table 2\n"); + + retval = pStringTableLookUpStringEx(table, String, 0, NULL, 0); + ok(retval != ~0u, "Failed find String in String Table 1\n"); + + retval = pStringTableLookUpStringEx(table2, String, 0, NULL, 0); + ok(retval != ~0u, "Failed find String in String Table 2\n"); + + retval=pStringTableLookUpStringEx(table, foo, 0, NULL, 0); + ok(retval != ~0u, "Failed find foo in String Table 1\n"); + ok(retval == hfoo, + "Lookup for foo (%x) does not match previous handle (%x) in String Table 1\n", + retval, hfoo); + + retval = pStringTableLookUpStringEx(table2, foo, 0, NULL, 0); + ok(retval != ~0u, "Failed find foo in String Table 2\n"); + + /* case sensitive */ + retval = pStringTableLookUpStringEx(table, string,ST_CASE_SENSITIVE_COMPARE, NULL, 0); + retval2 = pStringTableLookUpStringEx(table, String, ST_CASE_SENSITIVE_COMPARE, NULL, 0); + ok(retval != retval2, "Lookup of string equals String in Table 1\n"); + ok(retval == hString, + "Lookup for String (%x) does not match previous handle (%x) in String Table 1\n", + retval, hString); + + pStringTableDestroy(table); + + table = pStringTableInitializeEx(0x1000, 0); + ok(table != NULL, "failed to initialize string table\n"); + + data = 0xaaaaaaaa; + retval = pStringTableAddStringEx(table, uilevel, 0x5, &data, sizeof(data)); + ok(retval != ~0u, "failed to add 'UILEVEL' to string table\n"); + + memset(buffer, 0x55, sizeof(buffer)); + retval = pStringTableLookUpStringEx(table, uilevel, ST_CASE_SENSITIVE_COMPARE, buffer, 0); + ok(retval != ~0u, "failed find 'UILEVEL' in string table\n"); + ok(memcmp(buffer, &data, 4), "unexpected data\n"); + + memset(buffer, 0x55, sizeof(buffer)); + retval = pStringTableLookUpStringEx(table, uilevel, ST_CASE_SENSITIVE_COMPARE, buffer, 2); + ok(retval != ~0u, "failed find 'UILEVEL' in string table\n"); + ok(!memcmp(buffer, &data, 2), "unexpected data\n"); + + memset(buffer, 0x55, sizeof(buffer)); + retval = pStringTableLookUpStringEx(table, uilevel, ST_CASE_SENSITIVE_COMPARE, buffer, sizeof(buffer)); + ok(retval != ~0u, "failed find 'UILEVEL' in string table\n"); + ok(!memcmp(buffer, &data, 4), "unexpected data\n"); + + pStringTableDestroy(table); } static void test_StringTableStringFromId(void) { - WCHAR *string2, *string3; + HANDLE table; + DWORD hstring; + WCHAR *string2; int result; + table = pStringTableInitialize(); + ok(table != NULL,"Failed to Initialize String Table\n"); + + hstring = pStringTableAddString(table, string, 0); + ok(hstring != ~0u,"failed to add 'string' to string table\n"); + /* correct */ string2=pStringTableStringFromId(table,pStringTableLookUpString(table,string,0)); ok(string2!=NULL,"Failed to look up string by ID from String Table\n"); @@ -166,25 +323,17 @@ static void test_StringTableStringFromId(void) result=lstrcmpiW(string, string2); ok(result==0,"StringID %p does not match requested StringID %p\n",string,string2); - /* This should never work */ - string3=pStringTableStringFromId(table,0); - ok(string3!=NULL,"Failed to look up string by ID from String Table\n"); - - result=lstrcmpiW(string, string3); - ok(result!=0,"StringID %p matches requested StringID %p\n",string,string3); + pStringTableDestroy(table); } START_TEST(stringtable) { load_it_up(); - test_StringTableInitialize(); test_StringTableAddString(); + test_StringTableAddStringEx(); test_StringTableDuplicate(); test_StringTableLookUpString(); + test_StringTableLookUpStringEx(); test_StringTableStringFromId(); - - /* assume we can always destroy */ - pStringTableDestroy(table); - pStringTableDestroy(table2); } diff --git a/rostests/winetests/shdocvw/intshcut.c b/rostests/winetests/shdocvw/intshcut.c new file mode 100644 index 00000000000..cf0b2251b93 --- /dev/null +++ b/rostests/winetests/shdocvw/intshcut.c @@ -0,0 +1,224 @@ +/* + * Unit tests to document InternetShortcut's behaviour + * + * Copyright 2008 Damjan Jovanovic + * + * 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 + */ + +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winerror.h" + +#include "shlobj.h" +#include "shobjidl.h" +#include "shlguid.h" +#include "ole2.h" +#include "initguid.h" +#include "isguids.h" +#include "intshcut.h" + +#include "wine/test.h" + +static HRESULT WINAPI Unknown_QueryInterface(IUnknown *pUnknown, REFIID riid, void **ppvObject) +{ + if (IsEqualGUID(&IID_IUnknown, riid)) + { + *ppvObject = pUnknown; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI Unknown_AddRef(IUnknown *pUnknown) +{ + return 2; +} + +static ULONG WINAPI Unknown_Release(IUnknown *pUnknown) +{ + return 1; +} + +static IUnknownVtbl unknownVtbl = { + Unknown_QueryInterface, + Unknown_AddRef, + Unknown_Release +}; + +static IUnknown unknown = { + &unknownVtbl +}; + +static const char *printGUID(const GUID *guid) +{ + static char guidSTR[39]; + + if (!guid) return NULL; + + sprintf(guidSTR, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + return guidSTR; +} + +static void test_Aggregability(void) +{ + HRESULT hr; + IUnknown *pUnknown = NULL; + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown); + ok(SUCCEEDED(hr), "could not create instance of CLSID_InternetShortcut with IID_IUnknown, hr = 0x%x\n", hr); + if (pUnknown) + IUnknown_Release(pUnknown); + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&pUnknown); + ok(SUCCEEDED(hr), "could not create instance of CLSID_InternetShortcut with IID_IUniformResourceLocatorA, hr = 0x%x\n", hr); + if (pUnknown) + IUnknown_Release(pUnknown); + + hr = CoCreateInstance(&CLSID_InternetShortcut, &unknown, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown); + ok(FAILED(hr), "aggregation didn't fail like it should, hr = 0x%x\n", hr); + if (pUnknown) + IUnknown_Release(pUnknown); +} + +static void can_query_interface(IUnknown *pUnknown, REFIID riid) +{ + HRESULT hr; + IUnknown *newInterface; + hr = IUnknown_QueryInterface(pUnknown, riid, (void**)&newInterface); + ok(SUCCEEDED(hr), "interface %s could not be queried\n", printGUID(riid)); + if (SUCCEEDED(hr)) + IUnknown_Release(newInterface); +} + +static void test_QueryInterface(void) +{ + HRESULT hr; + IUnknown *pUnknown; + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown); + if (SUCCEEDED(hr)) + { + can_query_interface(pUnknown, &IID_IUniformResourceLocatorA); + can_query_interface(pUnknown, &IID_IUniformResourceLocatorW); + can_query_interface(pUnknown, &IID_IPersistFile); + IUnknown_Release(pUnknown); + } + else + skip("could not create a CLSID_InternetShortcut for QueryInterface tests, hr=0x%x\n", hr); +} + +static CHAR *set_and_get_url(IUniformResourceLocatorA *urlA, LPCSTR input, DWORD flags) +{ + HRESULT hr; + hr = urlA->lpVtbl->SetURL(urlA, input, flags); + if (SUCCEEDED(hr)) + { + CHAR *output; + hr = urlA->lpVtbl->GetURL(urlA, &output); + if (SUCCEEDED(hr)) + return output; + else + skip("GetUrl failed, hr=0x%x\n", hr); + } + else + skip("SetUrl (%s, 0x%x) failed, hr=0x%x\n", input, flags, hr); + return NULL; +} + +static void check_string_transform(IUniformResourceLocatorA *urlA, LPCSTR input, DWORD flags, LPCSTR expectedOutput) +{ + CHAR *output = set_and_get_url(urlA, input, flags); + if (output != NULL) + { + ok(lstrcmpA(output, expectedOutput) == 0, "unexpected URL change %s -> %s (expected %s)\n", + input, output, expectedOutput); + CoTaskMemFree(output); + } +} + +static void test_NullURLs(void) +{ + HRESULT hr; + IUniformResourceLocatorA *urlA; + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA); + if (SUCCEEDED(hr)) + { + LPSTR url = NULL; + + hr = urlA->lpVtbl->GetURL(urlA, &url); + ok(SUCCEEDED(hr), "getting uninitialized URL unexpectedly failed, hr=0x%x\n", hr); + ok(url == NULL, "uninitialized URL is not NULL but %s\n", url); + + hr = urlA->lpVtbl->SetURL(urlA, NULL, 0); + ok(SUCCEEDED(hr), "setting NULL URL unexpectedly failed, hr=0x%x\n", hr); + + hr = urlA->lpVtbl->GetURL(urlA, &url); + ok(SUCCEEDED(hr), "getting NULL URL unexpectedly failed, hr=0x%x\n", hr); + ok(url == NULL, "URL unexpectedly not NULL but %s\n", url); + + urlA->lpVtbl->Release(urlA); + } + else + skip("could not create a CLSID_InternetShortcut for NullURL tests, hr=0x%x\n", hr); +} + +static void test_SetURLFlags(void) +{ + HRESULT hr; + IUniformResourceLocatorA *urlA; + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA); + if (SUCCEEDED(hr)) + { + check_string_transform(urlA, "somerandomstring", 0, "somerandomstring"); + check_string_transform(urlA, "www.winehq.org", 0, "www.winehq.org"); + + todo_wine + { + check_string_transform(urlA, "www.winehq.org", IURL_SETURL_FL_GUESS_PROTOCOL, "http://www.winehq.org/"); + check_string_transform(urlA, "ftp.winehq.org", IURL_SETURL_FL_GUESS_PROTOCOL, "ftp://ftp.winehq.org/"); + } + + urlA->lpVtbl->Release(urlA); + } + else + skip("could not create a CLSID_InternetShortcut for SetUrl tests, hr=0x%x\n", hr); +} + +static void test_InternetShortcut(void) +{ + test_Aggregability(); + test_QueryInterface(); + test_NullURLs(); + test_SetURLFlags(); +} + +START_TEST(intshcut) +{ + OleInitialize(NULL); + test_InternetShortcut(); + OleUninitialize(); +} diff --git a/rostests/winetests/shdocvw/shdocvw.c b/rostests/winetests/shdocvw/shdocvw.c new file mode 100644 index 00000000000..17ea8d08625 --- /dev/null +++ b/rostests/winetests/shdocvw/shdocvw.c @@ -0,0 +1,361 @@ +/* + * Unit tests for misc shdocvw functions + * + * Copyright 2008 Detlef Riekenberg + * + * 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 + */ + + +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wininet.h" +#include "winnls.h" + +#include "wine/test.h" + +/* ################ */ + +static HMODULE hshdocvw; +static HRESULT (WINAPI *pURLSubRegQueryA)(LPCSTR, LPCSTR, DWORD, LPVOID, DWORD, DWORD); +static DWORD (WINAPI *pParseURLFromOutsideSourceA)(LPCSTR, LPSTR, LPDWORD, LPDWORD); +static DWORD (WINAPI *pParseURLFromOutsideSourceW)(LPCWSTR, LPWSTR, LPDWORD, LPDWORD); + +static CHAR appdata[] = "AppData"; +static CHAR common_appdata[] = "Common AppData"; +static CHAR default_page_url[] = "Default_Page_URL"; +static CHAR does_not_exist[] = "does_not_exist"; +static CHAR regpath_iemain[] = "Software\\Microsoft\\Internet Explorer\\Main"; +static CHAR regpath_shellfolders[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; +static CHAR start_page[] = "Start Page"; + +/* ################ */ + +static const struct { + const char *url; + const char *newurl; + DWORD len; +} ParseURL_table[] = { + {"http://www.winehq.org", "http://www.winehq.org/", 22}, + {"www.winehq.org", "http://www.winehq.org/", 22}, + {"winehq.org", "http://winehq.org/", 18}, + {"ftp.winehq.org", "ftp://ftp.winehq.org/", 21}, + {"http://winehq.org", "http://winehq.org/", 18}, + {"https://winehq.org", "https://winehq.org/", 19}, + {"https://www.winehq.org", "https://www.winehq.org/", 23}, + {"ftp://winehq.org", "ftp://winehq.org/", 17}, + {"ftp://ftp.winehq.org", "ftp://ftp.winehq.org/", 21}, + {"about:blank", "about:blank", 11}, + {"about:home", "about:home", 10}, + {"about:mozilla", "about:mozilla", 13}, + /* a space at the start is not allowed */ + {" http://www.winehq.org", "http://%20http://www.winehq.org", 31} + +}; + +/* ################ */ + +static void init_functions(void) +{ + hshdocvw = LoadLibraryA("shdocvw.dll"); + pURLSubRegQueryA = (void *) GetProcAddress(hshdocvw, (LPSTR) 151); + pParseURLFromOutsideSourceA = (void *) GetProcAddress(hshdocvw, (LPSTR) 169); + pParseURLFromOutsideSourceW = (void *) GetProcAddress(hshdocvw, (LPSTR) 170); +} + +/* ################ */ + +static void test_URLSubRegQueryA(void) +{ + CHAR buffer[INTERNET_MAX_URL_LENGTH]; + HRESULT hr; + DWORD used; + DWORD len; + + if (!pURLSubRegQueryA) { + skip("URLSubRegQueryA not found\n"); + return; + } + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + /* called by inetcpl.cpl */ + hr = pURLSubRegQueryA(regpath_iemain, default_page_url, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + ok(hr == E_FAIL || hr == S_OK, "got 0x%x (expected E_FAIL or S_OK)\n", hr); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + /* called by inetcpl.cpl */ + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + len = lstrlenA(buffer); + /* respect privacy: do not dump the url */ + ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, len); + + /* test buffer length: just large enough */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len+1, -1); + used = lstrlenA(buffer); + /* respect privacy: do not dump the url */ + ok((hr == S_OK) && (used == len), + "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len); + + /* no space for terminating 0: result is truncated */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len, -1); + used = lstrlenA(buffer); + ok((hr == S_OK) && (used == len - 1), + "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len - 1); + + /* no space for the complete result: truncate another char */ + if (len > 1) { + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len-1, -1); + used = lstrlenA(buffer); + ok((hr == S_OK) && (used == (len - 2)), + "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len - 2); + } + + /* only space for the terminating 0: function still succeded */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, 1, -1); + used = lstrlenA(buffer); + ok((hr == S_OK) && !used, + "got 0x%x and %d (expected S_OK and 0)\n", hr, used); + + /* size of buffer is 0, but the function still succeed. + buffer[0] is cleared in IE 5.01 and IE 5.5 (Buffer Overflow) */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, 0, -1); + used = lstrlenA(buffer); + ok( (hr == S_OK) && + ((used == INTERNET_MAX_URL_LENGTH - 1) || broken(used == 0)) , + "got 0x%x and %d (expected S_OK and INTERNET_MAX_URL_LENGTH - 1)\n", + hr, used); + + /* still succeed without a buffer for the result */ + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, NULL, 0, -1); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + + /* still succeed, when a length is given without a buffer */ + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, NULL, INTERNET_MAX_URL_LENGTH, -1); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + + /* this value does not exist */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, does_not_exist, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + /* random bytes are copied to the buffer */ + ok((hr == E_FAIL), "got 0x%x (expected E_FAIL)\n", hr); + + /* the third parameter is ignored. Is it really a type? (data is REG_SZ) */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_DWORD, buffer, INTERNET_MAX_URL_LENGTH, -1); + used = lstrlenA(buffer); + ok((hr == S_OK) && (used == len), + "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len); + + /* the function works for HKCU and HKLM */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_shellfolders, appdata, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + used = lstrlenA(buffer); + ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, used); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_shellfolders, common_appdata, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + used = lstrlenA(buffer); + ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, used); + + /* todo: what does the last parameter mean? */ +} + +/* ################ */ + +static void test_ParseURLFromOutsideSourceA(void) +{ + CHAR buffer[INTERNET_MAX_URL_LENGTH]; + DWORD dummy; + DWORD maxlen; + DWORD len; + DWORD res; + int i; + + if (!pParseURLFromOutsideSourceA) { + skip("ParseURLFromOutsideSourceA not found\n"); + return; + } + + for(i = 0; i < sizeof(ParseURL_table)/sizeof(ParseURL_table[0]); i++) { + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = sizeof(buffer); + dummy = 0; + /* on success, len+1 is returned. No idea, if someone depend on this */ + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); + /* len does not include the terminating 0, when buffer is large enough */ + ok( res != 0 && len == ParseURL_table[i].len && + !lstrcmpA(buffer, ParseURL_table[i].newurl), + "#%d: got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + i, res, len, buffer, ParseURL_table[i].len, ParseURL_table[i].newurl); + + + /* use the size test only for the first examples */ + if (i > 4) continue; + + maxlen = len; + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen + 1; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); + ok( res != 0 && len == ParseURL_table[i].len && + !lstrcmpA(buffer, ParseURL_table[i].newurl), + "#%d (+1): got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + i, res, len, buffer, ParseURL_table[i].len, ParseURL_table[i].newurl); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); + /* len includes the terminating 0, when the buffer is too small */ + ok( res == 0 && len == ParseURL_table[i].len + 1, + "#%d (==): got %d and %d (expected '0' and %d)\n", + i, res, len, ParseURL_table[i].len + 1); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen-1; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); + /* len includes the terminating 0 on XP SP1 and before, when the buffer is too small */ + ok( res == 0 && (len == ParseURL_table[i].len || len == ParseURL_table[i].len + 1), + "#%d (-1): got %d and %d (expected '0' and %d or %d)\n", + i, res, len, ParseURL_table[i].len, ParseURL_table[i].len + 1); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen+1; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, NULL, &len, &dummy); + /* len does not include the terminating 0, when buffer is NULL */ + ok( res == 0 && len == ParseURL_table[i].len, + "#%d (buffer): got %d and %d (expected '0' and %d)\n", + i, res, len, ParseURL_table[i].len); + + if (0) { + /* that test crash on native shdocvw */ + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, NULL, &dummy); + } + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen+1; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, NULL); + ok( res != 0 && len == ParseURL_table[i].len && + !lstrcmpA(buffer, ParseURL_table[i].newurl), + "#%d (unknown): got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + i, res, len, buffer, ParseURL_table[i].len, ParseURL_table[i].newurl); + } +} + +/* ################ */ + +static void test_ParseURLFromOutsideSourceW(void) +{ + WCHAR urlW[INTERNET_MAX_URL_LENGTH]; + WCHAR bufferW[INTERNET_MAX_URL_LENGTH]; + CHAR bufferA[INTERNET_MAX_URL_LENGTH]; + DWORD maxlen; + DWORD dummy; + DWORD len; + DWORD res; + + if (!pParseURLFromOutsideSourceW) { + skip("ParseURLFromOutsideSourceW not found\n"); + return; + } + MultiByteToWideChar(CP_ACP, 0, ParseURL_table[0].url, -1, urlW, INTERNET_MAX_URL_LENGTH); + + memset(bufferA, '#', sizeof(bufferA)-1); + bufferA[sizeof(bufferA) - 1] = '\0'; + MultiByteToWideChar(CP_ACP, 0, bufferA, -1, bufferW, INTERNET_MAX_URL_LENGTH); + + /* len is in characters */ + len = sizeof(bufferW)/sizeof(bufferW[0]); + dummy = 0; + res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL); + ok( res != 0 && len == ParseURL_table[0].len && + !lstrcmpA(bufferA, ParseURL_table[0].newurl), + "got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + res, len, bufferA, ParseURL_table[0].len, ParseURL_table[0].newurl); + + + maxlen = len; + + memset(bufferA, '#', sizeof(bufferA)-1); + bufferA[sizeof(bufferA) - 1] = '\0'; + MultiByteToWideChar(CP_ACP, 0, bufferA, -1, bufferW, INTERNET_MAX_URL_LENGTH); + len = maxlen+1; + dummy = 0; + res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL); + /* len does not include the terminating 0, when buffer is large enough */ + ok( res != 0 && len == ParseURL_table[0].len && + !lstrcmpA(bufferA, ParseURL_table[0].newurl), + "+1: got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + res, len, bufferA, ParseURL_table[0].len, ParseURL_table[0].newurl); + + len = maxlen; + dummy = 0; + res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); + /* len includes the terminating 0, when the buffer is too small */ + ok( res == 0 && len == ParseURL_table[0].len + 1, + "==: got %d and %d (expected '0' and %d)\n", + res, len, ParseURL_table[0].len + 1); + + len = maxlen - 1; + dummy = 0; + res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); + /* len includes the terminating 0 on XP SP1 and before, when the buffer is too small */ + ok( res == 0 && (len == ParseURL_table[0].len || len == ParseURL_table[0].len + 1), + "-1: got %d and %d (expected '0' and %d or %d)\n", + res, len, ParseURL_table[0].len, ParseURL_table[0].len + 1); + +} + +/* ################ */ + +START_TEST(shdocvw) +{ + init_functions(); + test_URLSubRegQueryA(); + test_ParseURLFromOutsideSourceA(); + test_ParseURLFromOutsideSourceW(); + FreeLibrary(hshdocvw); +} diff --git a/rostests/winetests/shdocvw/shdocvw.rbuild b/rostests/winetests/shdocvw/shdocvw.rbuild new file mode 100644 index 00000000000..181826f91e0 --- /dev/null +++ b/rostests/winetests/shdocvw/shdocvw.rbuild @@ -0,0 +1,21 @@ + + + + + . + + intshcut.c + shdocvw.c + shortcut.c + webbrowser.c + testlist.c + wine + gdi32 + shell32 + ole32 + oleaut32 + user32 + advapi32 + ntdll + + diff --git a/rostests/winetests/shdocvw/shortcut.c b/rostests/winetests/shdocvw/shortcut.c new file mode 100644 index 00000000000..5a740dc7dfd --- /dev/null +++ b/rostests/winetests/shdocvw/shortcut.c @@ -0,0 +1,231 @@ +/* + * Unit tests to document shdocvw's 'Shell Instance Objects' features + * + * Copyright 2005 Michael Jung + * + * 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 + */ + +/* At least since Windows 2000 it's possible to add FolderShortcut objects + * by creating some registry entries. Those objects, which refer to some + * point in the filesystem, can be registered in the shell namespace like other + * shell namespace extensions. Icons, names and filesystem location can be + * configured. This is documented at http://www.virtualplastic.net/html/ui_shell.html + * You can also google for a tool called "ShellObjectEditor" by "Tropical + * Technologies". This mechanism would be cool for wine, since we could + * map Gnome's virtual devices to FolderShortcuts and have them appear in the + * file dialogs. These unit tests are meant to document how this mechanism + * works on windows. + * + * Search MSDN for "Creating Shell Extensions with Shell Instance Objects" for + * more documentation.*/ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" + +#include "shlobj.h" +#include "shobjidl.h" +#include "shlguid.h" +#include "ole2.h" + +#include "wine/test.h" + +/* The following definitions and helper functions are meant to make the de-/registration + * of the various necessary registry keys easier. */ + +struct registry_value { + const char *szName; + const DWORD dwType; + const char *szValue; + const DWORD dwValue; +}; + +#define REG_VALUE_ADDR(x) ((x->dwType==REG_SZ)?(const BYTE *)x->szValue:(const BYTE *)&x->dwValue) +#define REG_VALUE_SIZE(x) ((x->dwType==REG_SZ)?strlen(x->szValue)+1:sizeof(DWORD)) + +struct registry_key { + const char *szName; + const struct registry_value *pValues; + const unsigned int cValues; + const struct registry_key *pSubKeys; + const unsigned int cSubKeys; +}; + +static const struct registry_value ShellFolder_values[] = { + { "WantsFORPARSING", REG_SZ, "", 0 }, + { "Attributes", REG_DWORD, NULL, 0xF8000100 } +}; + +static const struct registry_value Instance_values[] = { + { "CLSID", REG_SZ, "{0AFACED1-E828-11D1-9187-B532F1E9575D}", 0 } +}; + +static const struct registry_value InitPropertyBag_values[] = { + { "Attributes", REG_DWORD, NULL, 0x00000015 }, + { "Target", REG_SZ, "C:\\", 0 } +}; + +static const struct registry_key Instance_keys[] = { + { "InitPropertyBag", InitPropertyBag_values, 2, NULL, 0 } +}; + +static const struct registry_value InProcServer32_values[] = { + { NULL, REG_SZ, "shdocvw.dll", 0 }, + { "ThreadingModel", REG_SZ, "Apartment", 0 } +}; + +static const struct registry_value DefaultIcon_values[] = { + { NULL, REG_SZ,"shell32.dll,8", 0 } +}; + +static const struct registry_key ShortcutCLSID_keys[] = { + { "DefaultIcon", DefaultIcon_values, 1, NULL, 0 }, + { "InProcServer32", InProcServer32_values, 2, NULL, 0 }, + { "Instance", Instance_values, 1, Instance_keys, 1 }, + { "ShellFolder", ShellFolder_values, 2, NULL, 0 } +}; + +static const struct registry_value ShortcutCLSID_values[] = { + { NULL, REG_SZ, "WineTest", 0 } +}; + +static const struct registry_key HKEY_CLASSES_ROOT_keys[] = { + { "CLSID\\{9B352EBF-2765-45C1-B4C6-85CC7F7ABC64}", ShortcutCLSID_values, 1, ShortcutCLSID_keys, 4} +}; + +/* register_keys - helper function, which recursively creates the registry keys and values in + * parameter 'keys' in the registry under hRootKey. */ +static BOOL register_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys) { + HKEY hKey; + unsigned int iKey, iValue; + + for (iKey = 0; iKey < numKeys; iKey++) { + if (ERROR_SUCCESS == RegCreateKeyExA(hRootKey, keys[iKey].szName, 0, NULL, 0, + KEY_WRITE, NULL, &hKey, NULL)) + { + for (iValue = 0; iValue < keys[iKey].cValues; iValue++) { + const struct registry_value * value = &keys[iKey].pValues[iValue]; + if (ERROR_SUCCESS != RegSetValueExA(hKey, value->szName, 0, value->dwType, + REG_VALUE_ADDR(value), REG_VALUE_SIZE(value))) + { + RegCloseKey(hKey); + return FALSE; + } + } + + if (!register_keys(hKey, keys[iKey].pSubKeys, keys[iKey].cSubKeys)) { + RegCloseKey(hKey); + return FALSE; + } + + RegCloseKey(hKey); + } + } + + return TRUE; +} + +/* unregister_keys - clean up after register_keys */ +static void unregister_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys) { + HKEY hKey; + unsigned int iKey; + + for (iKey = 0; iKey < numKeys; iKey++) { + if (ERROR_SUCCESS == RegOpenKeyExA(hRootKey, keys[iKey].szName, 0, DELETE, &hKey)) { + unregister_keys(hKey, keys[iKey].pSubKeys, keys[iKey].cSubKeys); + RegCloseKey(hKey); + } + RegDeleteKeyA(hRootKey, keys[iKey].szName); + } +} + +static void test_ShortcutFolder(void) { + LPSHELLFOLDER pDesktopFolder, pWineTestFolder; + IPersistFolder3 *pWineTestPersistFolder; + LPITEMIDLIST pidlWineTestFolder, pidlCurFolder; + HRESULT hr; + CLSID clsid; + const CLSID CLSID_WineTest = + { 0x9b352ebf, 0x2765, 0x45c1, { 0xb4, 0xc6, 0x85, 0xcc, 0x7f, 0x7a, 0xbc, 0x64 } }; + WCHAR wszWineTestFolder[] = { + ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-', + 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 }; + + /* First, we register all the necessary registry keys/values for our 'WineTest' + * shell object. */ + register_keys(HKEY_CLASSES_ROOT, HKEY_CLASSES_ROOT_keys, 1); + + hr = SHGetDesktopFolder(&pDesktopFolder); + ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr); + if (FAILED(hr)) goto cleanup; + + /* Convert the wszWineTestFolder string to an ITEMIDLIST. */ + hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL, + &pidlWineTestFolder, NULL); + todo_wine + { + ok (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), + "Expected %08x, got %08x\n", HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), hr); + } + if (FAILED(hr)) { + IShellFolder_Release(pDesktopFolder); + goto cleanup; + } + + /* FIXME: these tests are never run */ + + /* Bind to a WineTest folder object. There has to be some support for this in shdocvw.dll. + * This isn't implemented in wine yet.*/ + hr = IShellFolder_BindToObject(pDesktopFolder, pidlWineTestFolder, NULL, &IID_IShellFolder, + (LPVOID*)&pWineTestFolder); + IShellFolder_Release(pDesktopFolder); + ILFree(pidlWineTestFolder); + ok (SUCCEEDED(hr), "IShellFolder::BindToObject(WineTestFolder) failed! hr = %08x\n", hr); + if (FAILED(hr)) goto cleanup; + + hr = IShellFolder_QueryInterface(pWineTestFolder, &IID_IPersistFolder3, (LPVOID*)&pWineTestPersistFolder); + ok (SUCCEEDED(hr), "IShellFolder::QueryInterface(IPersistFolder3) failed! hr = %08x\n", hr); + IShellFolder_Release(pWineTestFolder); + if (FAILED(hr)) goto cleanup; + + /* The resulting folder object has the FolderShortcut CLSID, instead of it's own. */ + hr = IPersistFolder3_GetClassID(pWineTestPersistFolder, &clsid); + ok (SUCCEEDED(hr), "IPersist::GetClassID failed! hr = %08x\n", hr); + ok (IsEqualCLSID(&CLSID_FolderShortcut, &clsid), "GetClassId returned wrong CLSID!\n"); + + pidlCurFolder = (LPITEMIDLIST)0xdeadbeef; + hr = IPersistFolder3_GetCurFolder(pWineTestPersistFolder, &pidlCurFolder); + ok (SUCCEEDED(hr), "IPersistFolder3::GetCurFolder failed! hr = %08x\n", hr); + ok (pidlCurFolder->mkid.cb == 20 && ((LPSHITEMID)((BYTE*)pidlCurFolder+20))->cb == 0 && + IsEqualCLSID(&CLSID_WineTest, (REFCLSID)((LPBYTE)pidlCurFolder+4)), + "GetCurFolder returned unexpected pidl!\n"); + + IPersistFolder3_Release(pWineTestPersistFolder); + +cleanup: + unregister_keys(HKEY_CLASSES_ROOT, HKEY_CLASSES_ROOT_keys, 1); +} + +START_TEST(shortcut) +{ + OleInitialize(NULL); + test_ShortcutFolder(); + OleUninitialize(); +} diff --git a/rostests/winetests/shdocvw/testlist.c b/rostests/winetests/shdocvw/testlist.c new file mode 100644 index 00000000000..18ce563f47a --- /dev/null +++ b/rostests/winetests/shdocvw/testlist.c @@ -0,0 +1,22 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_intshcut(void); +extern void func_shdocvw(void); +extern void func_shortcut(void); +extern void func_protocol(void); +extern void func_webbrowser(void); + +const struct test winetest_testlist[] = +{ + { "intshcut", func_intshcut }, + { "shdocvw", func_shdocvw }, + { "shortcut", func_shortcut }, + { "webbrowser", func_webbrowser }, + { 0, 0 } +}; diff --git a/rostests/winetests/shdocvw/webbrowser.c b/rostests/winetests/shdocvw/webbrowser.c new file mode 100644 index 00000000000..fe7df890de8 --- /dev/null +++ b/rostests/winetests/shdocvw/webbrowser.c @@ -0,0 +1,2400 @@ +/* + * Copyright 2006 Jacek Caban for CodeWeavers + * + * 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 + */ + +#define COBJMACROS +#define CONST_VTABLE + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "initguid.h" +#include "ole2.h" +#include "exdisp.h" +#include "htiframe.h" +#include "mshtmhst.h" +#include "mshtmcid.h" +#include "mshtml.h" +#include "idispids.h" +#include "olectl.h" +#include "mshtmdid.h" +#include "shobjidl.h" +#include "shlguid.h" +#include "exdispid.h" +#include "mimeinfo.h" + +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED_BROKEN(func) \ + do { \ + ok(called_ ## func || broken(!called_ ## func), "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CLEAR_CALLED(func) \ + expect_ ## func = called_ ## func = FALSE + +DEFINE_EXPECT(GetContainer); +DEFINE_EXPECT(Site_GetWindow); +DEFINE_EXPECT(ShowObject); +DEFINE_EXPECT(CanInPlaceActivate); +DEFINE_EXPECT(OnInPlaceActivate); +DEFINE_EXPECT(OnUIActivate); +DEFINE_EXPECT(GetWindowContext); +DEFINE_EXPECT(Frame_GetWindow); +DEFINE_EXPECT(Frame_SetActiveObject); +DEFINE_EXPECT(UIWindow_SetActiveObject); +DEFINE_EXPECT(SetMenu); +DEFINE_EXPECT(Invoke_AMBIENT_USERMODE); +DEFINE_EXPECT(Invoke_AMBIENT_DLCONTROL); +DEFINE_EXPECT(Invoke_AMBIENT_USERAGENT); +DEFINE_EXPECT(Invoke_AMBIENT_PALETTE); +DEFINE_EXPECT(Invoke_AMBIENT_SILENT); +DEFINE_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); +DEFINE_EXPECT(Invoke_STATUSTEXTCHANGE); +DEFINE_EXPECT(Invoke_PROPERTYCHANGE); +DEFINE_EXPECT(Invoke_DOWNLOADBEGIN); +DEFINE_EXPECT(Invoke_BEFORENAVIGATE2); +DEFINE_EXPECT(Invoke_SETSECURELOCKICON); +DEFINE_EXPECT(Invoke_FILEDOWNLOAD); +DEFINE_EXPECT(Invoke_COMMANDSTATECHANGE); +DEFINE_EXPECT(Invoke_DOWNLOADCOMPLETE); +DEFINE_EXPECT(Invoke_ONMENUBAR); +DEFINE_EXPECT(Invoke_ONADDRESSBAR); +DEFINE_EXPECT(Invoke_ONSTATUSBAR); +DEFINE_EXPECT(Invoke_ONTOOLBAR); +DEFINE_EXPECT(Invoke_ONFULLSCREEN); +DEFINE_EXPECT(Invoke_ONTHEATERMODE); +DEFINE_EXPECT(Invoke_WINDOWSETRESIZABLE); +DEFINE_EXPECT(Invoke_TITLECHANGE); +DEFINE_EXPECT(Invoke_NAVIGATECOMPLETE2); +DEFINE_EXPECT(Invoke_PROGRESSCHANGE); +DEFINE_EXPECT(Invoke_DOCUMENTCOMPLETE); +DEFINE_EXPECT(Invoke_282); +DEFINE_EXPECT(EnableModeless_TRUE); +DEFINE_EXPECT(EnableModeless_FALSE); +DEFINE_EXPECT(GetHostInfo); +DEFINE_EXPECT(GetOptionKeyPath); +DEFINE_EXPECT(GetOverridesKeyPath); +DEFINE_EXPECT(SetStatusText); +DEFINE_EXPECT(UpdateUI); +DEFINE_EXPECT(Exec_SETDOWNLOADSTATE_0); +DEFINE_EXPECT(Exec_SETDOWNLOADSTATE_1); +DEFINE_EXPECT(Exec_SETPROGRESSMAX); +DEFINE_EXPECT(Exec_SETPROGRESSPOS); +DEFINE_EXPECT(QueryStatus_SETPROGRESSTEXT); +DEFINE_EXPECT(QueryStatus_STOP); +DEFINE_EXPECT(DocHost_EnableModeless_TRUE); +DEFINE_EXPECT(DocHost_EnableModeless_FALSE); +DEFINE_EXPECT(GetDropTarget); + +static const WCHAR wszItem[] = {'i','t','e','m',0}; +static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0}; +static const WCHAR emptyW[] = {0}; + +static VARIANT_BOOL exvb; +static IWebBrowser2 *wb; + +static HWND container_hwnd, shell_embedding_hwnd; +static BOOL is_downloading = FALSE; + +static const char *debugstr_w(LPCWSTR str) +{ + static char buf[1024]; + if(!str) + return "(null)"; + WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); + return buf; +} + +static const char *debugstr_guid(REFIID riid) +{ + static char buf[50]; + + sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], + riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4], + riid->Data4[5], riid->Data4[6], riid->Data4[7]); + + return buf; +} + +#define test_LocationURL(a,b) _test_LocationURL(__LINE__,a,b) +static void _test_LocationURL(unsigned line, IUnknown *unk, LPCWSTR exurl) +{ + IWebBrowser2 *wb; + BSTR url = (void*)0xdeadbeef; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&wb); + ok(hres == S_OK, "Could not get IWebBrowser2 interface: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IWebBrowser2_get_LocationURL(wb, &url); + ok_(__FILE__,line) (hres == (*exurl ? S_OK : S_FALSE), "get_LocationURL failed: %08x\n", hres); + ok_(__FILE__,line) (!lstrcmpW(url, exurl), "unexpected URL: %s\n", debugstr_w(url)); + + SysFreeString(url); + IWebBrowser2_Release(wb); +} + +static HRESULT QueryInterface(REFIID,void**); + +static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, + REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface) +{ + return 2; +} + +static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface) +{ + return 1; +} + +static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +{ + ok(!pguidCmdGroup, "pguidCmdGroup != MULL\n"); + ok(cCmds == 1, "cCmds=%d, expected 1\n", cCmds); + ok(!pCmdText, "pCmdText != NULL\n"); + + switch(prgCmds[0].cmdID) { + case OLECMDID_STOP: + CHECK_EXPECT2(QueryStatus_STOP); + prgCmds[0].cmdf = OLECMDF_SUPPORTED; + return S_OK; + case OLECMDID_SETPROGRESSTEXT: + CHECK_EXPECT(QueryStatus_SETPROGRESSTEXT); + prgCmds[0].cmdf = OLECMDF_ENABLED; + return S_OK; + default: + ok(0, "unexpected command %d\n", prgCmds[0].cmdID); + } + + return E_FAIL; +} + +static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + if(!pguidCmdGroup) { + switch(nCmdID) { + case OLECMDID_SETPROGRESSMAX: + CHECK_EXPECT2(Exec_SETPROGRESSMAX); + ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER, "nCmdexecopts=%08x\n", nCmdexecopt); + ok(pvaIn != NULL, "pvaIn == NULL\n"); + if(pvaIn) + ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d, expected VT_I4\n", V_VT(pvaIn)); + ok(pvaOut == NULL, "pvaOut=%p, expected NULL\n", pvaOut); + return S_OK; + case OLECMDID_SETPROGRESSPOS: + CHECK_EXPECT2(Exec_SETPROGRESSPOS); + ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER, "nCmdexecopts=%08x\n", nCmdexecopt); + ok(pvaIn != NULL, "pvaIn == NULL\n"); + if(pvaIn) + ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d, expected VT_I4\n", V_VT(pvaIn)); + ok(pvaOut == NULL, "pvaOut=%p, expected NULL\n", pvaOut); + return S_OK; + case OLECMDID_SETDOWNLOADSTATE: + if(is_downloading) + ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER || !nCmdexecopt, + "nCmdexecopts=%08x\n", nCmdexecopt); + else + ok(!nCmdexecopt, "nCmdexecopts=%08x\n", nCmdexecopt); + ok(pvaOut == NULL, "pvaOut=%p\n", pvaOut); + ok(pvaIn != NULL, "pvaIn == NULL\n"); + ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d\n", V_VT(pvaIn)); + switch(V_I4(pvaIn)) { + case 0: + CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_0); + break; + case 1: + CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_1); + break; + default: + ok(0, "unexpevted V_I4(pvaIn)=%d\n", V_I4(pvaIn)); + } + return S_OK; + default: + ok(0, "unexpected nsCmdID %d\n", nCmdID); + } + }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) { + switch(nCmdID) { + case 24: /* TODO */ + case 25: /* IE5 */ + case 37: /* TODO */ + case 39: /* TODO */ + case 66: /* TODO */ + case 67: /* TODO */ + case 69: /* TODO */ + return E_FAIL; + default: + ok(0, "unexpected nCmdID %d\n", nCmdID); + } + }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) { + switch(nCmdID) { + case 105: /* TODO */ + return E_FAIL; + default: + ok(0, "unexpected nCmdID %d\n", nCmdID); + } + }else { + ok(0, "unexpected pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup)); + } + + return E_FAIL; +} + +static IOleCommandTargetVtbl OleCommandTargetVtbl = { + OleCommandTarget_QueryInterface, + OleCommandTarget_AddRef, + OleCommandTarget_Release, + OleCommandTarget_QueryStatus, + OleCommandTarget_Exec +}; + +static IOleCommandTarget OleCommandTarget = { &OleCommandTargetVtbl }; + +static HRESULT WINAPI OleContainer_QueryInterface(IOleContainer *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_ITargetContainer, riid)) + return E_NOINTERFACE; /* TODO */ + + if(IsEqualGUID(&IID_IOleCommandTarget, riid)) { + *ppv = &OleCommandTarget; + return S_OK; + } + + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI OleContainer_AddRef(IOleContainer *iface) +{ + return 2; +} + +static ULONG WINAPI OleContainer_Release(IOleContainer *iface) +{ + return 1; +} + +static HRESULT WINAPI OleContainer_ParseDisplayName(IOleContainer *iface, IBindCtx *pbc, + LPOLESTR pszDiaplayName, ULONG *pchEaten, IMoniker **ppmkOut) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI OleContainer_EnumObjects(IOleContainer *iface, DWORD grfFlags, + IEnumUnknown **ppenum) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI OleContainer_LockContainer(IOleContainer *iface, BOOL fLock) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IOleContainerVtbl OleContainerVtbl = { + OleContainer_QueryInterface, + OleContainer_AddRef, + OleContainer_Release, + OleContainer_ParseDisplayName, + OleContainer_EnumObjects, + OleContainer_LockContainer +}; + +static IOleContainer OleContainer = { &OleContainerVtbl }; + +static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI Dispatch_AddRef(IDispatch *iface) +{ + return 2; +} + +static ULONG WINAPI Dispatch_Release(IDispatch *iface) +{ + return 1; +} + +static HRESULT WINAPI Dispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Dispatch_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Dispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(IsEqualGUID(&IID_NULL, riid), "riid != IID_NULL\n"); + ok(pDispParams != NULL, "pDispParams == NULL\n"); + ok(pExcepInfo == NULL, "pExcepInfo=%p, expected NULL\n", pExcepInfo); + ok(V_VT(pVarResult) == VT_EMPTY, "V_VT(pVarResult)=%d\n", V_VT(pVarResult)); + ok(wFlags == DISPATCH_PROPERTYGET, "wFlags=%08x, expected DISPATCH_PROPERTYGET\n", wFlags); + ok(pDispParams->rgvarg == NULL, "pDispParams->rgvarg = %p\n", pDispParams->rgvarg); + ok(pDispParams->rgdispidNamedArgs == NULL, + "pDispParams->rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs); + ok(pDispParams->cArgs == 0, "pDispParams->cArgs = %d\n", pDispParams->cArgs); + ok(pDispParams->cNamedArgs == 0, "pDispParams->cNamedArgs = %d\n", pDispParams->cNamedArgs); + + switch(dispIdMember) { + case DISPID_AMBIENT_USERMODE: + CHECK_EXPECT2(Invoke_AMBIENT_USERMODE); + return E_FAIL; + case DISPID_AMBIENT_DLCONTROL: + CHECK_EXPECT(Invoke_AMBIENT_DLCONTROL); + ok(puArgErr != NULL, "puArgErr=%p\n", puArgErr); + return E_FAIL; + case DISPID_AMBIENT_USERAGENT: + CHECK_EXPECT(Invoke_AMBIENT_USERAGENT); + ok(puArgErr != NULL, "puArgErr=%p\n", puArgErr); + return E_FAIL; + case DISPID_AMBIENT_PALETTE: + CHECK_EXPECT(Invoke_AMBIENT_PALETTE); + ok(puArgErr != NULL, "puArgErr=%p\n", puArgErr); + return E_FAIL; + case DISPID_AMBIENT_OFFLINEIFNOTCONNECTED: + CHECK_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + ok(puArgErr == NULL, "puArgErr=%p\n", puArgErr); + V_VT(pVarResult) = VT_BOOL; + V_BOOL(pVarResult) = VARIANT_FALSE; + return S_OK; + case DISPID_AMBIENT_SILENT: + CHECK_EXPECT(Invoke_AMBIENT_SILENT); + ok(puArgErr == NULL, "puArgErr=%p\n", puArgErr); + V_VT(pVarResult) = VT_BOOL; + V_BOOL(pVarResult) = VARIANT_FALSE; + return S_OK; + } + + ok(0, "unexpected dispIdMember %d\n", dispIdMember); + return E_NOTIMPL; +} + +static IDispatchVtbl DispatchVtbl = { + Dispatch_QueryInterface, + Dispatch_AddRef, + Dispatch_Release, + Dispatch_GetTypeInfoCount, + Dispatch_GetTypeInfo, + Dispatch_GetIDsOfNames, + Dispatch_Invoke +}; + +static IDispatch Dispatch = { &DispatchVtbl }; + +static HRESULT WINAPI WebBrowserEvents2_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&DIID_DWebBrowserEvents2, riid)) { + *ppv = iface; + return S_OK; + } + + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +#define test_invoke_bool(p,s) _test_invoke_bool(__LINE__,p,s) +static void _test_invoke_bool(unsigned line, const DISPPARAMS *params, BOOL strict) +{ + ok_(__FILE__,line) (params->rgvarg != NULL, "rgvarg == NULL\n"); + ok_(__FILE__,line) (params->cArgs == 1, "cArgs=%d, expected 1\n", params->cArgs); + ok_(__FILE__,line) (V_VT(params->rgvarg) == VT_BOOL, "V_VT(arg)=%d\n", V_VT(params->rgvarg)); + if(strict) + ok_(__FILE__,line) (V_BOOL(params->rgvarg) == exvb, "V_VT(arg)=%x, expected %x\n", + V_BOOL(params->rgvarg), exvb); + else + ok_(__FILE__,line) (!V_BOOL(params->rgvarg) == !exvb, "V_VT(arg)=%x, expected %x\n", + V_BOOL(params->rgvarg), exvb); +} + +static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const VARIANT *flags, + const VARIANT *frame, const VARIANT *post_data, const VARIANT *headers, const VARIANT *cancel) +{ + ok(V_VT(disp) == VT_DISPATCH, "V_VT(disp)=%d, expected VT_DISPATCH\n", V_VT(disp)); + ok(V_DISPATCH(disp) != NULL, "V_DISPATCH(disp) == NULL\n"); + ok(V_DISPATCH(disp) == (IDispatch*)wb, "V_DISPATCH(disp)=%p, wb=%p\n", V_DISPATCH(disp), wb); + + ok(V_VT(url) == (VT_BYREF|VT_VARIANT), "V_VT(url)=%x, expected VT_BYREF|VT_VARIANT\n", V_VT(url)); + ok(V_VARIANTREF(url) != NULL, "V_VARIANTREF(url) == NULL)\n"); + if(V_VARIANTREF(url)) { + ok(V_VT(V_VARIANTREF(url)) == VT_BSTR, "V_VT(V_VARIANTREF(url))=%d, expected VT_BSTR\n", + V_VT(V_VARIANTREF(url))); + ok(V_BSTR(V_VARIANTREF(url)) != NULL, "V_BSTR(V_VARIANTREF(url)) == NULL\n"); + ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), about_blankW), "unexpected url %s\n", + debugstr_w(V_BSTR(V_VARIANTREF(url)))); + } + + ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(flags)); + ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(flags)); + ok(V_VARIANTREF(flags) != NULL, "V_VARIANTREF(flags) == NULL)\n"); + if(V_VARIANTREF(flags)) { + ok(V_VT(V_VARIANTREF(flags)) == VT_I4, "V_VT(V_VARIANTREF(flags))=%d, expected VT_I4\n", + V_VT(V_VARIANTREF(flags))); + ok(V_I4(V_VARIANTREF(flags)) == 0, "V_I4(V_VARIANTREF(flags)) = %d, expected 0\n", + V_I4(V_VARIANTREF(flags))); + } + + ok(V_VT(frame) == (VT_BYREF|VT_VARIANT), "V_VT(frame)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(frame)); + ok(V_VT(frame) == (VT_BYREF|VT_VARIANT), "V_VT(frame)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(frame)); + ok(V_VARIANTREF(frame) != NULL, "V_VARIANTREF(frame) == NULL)\n"); + if(V_VARIANTREF(frame)) { + ok(V_VT(V_VARIANTREF(frame)) == VT_BSTR, "V_VT(V_VARIANTREF(frame))=%d, expected VT_BSTR\n", + V_VT(V_VARIANTREF(frame))); + ok(V_BSTR(V_VARIANTREF(frame)) == NULL, "V_BSTR(V_VARIANTREF(frame)) = %p, expected NULL\n", + V_BSTR(V_VARIANTREF(frame))); + } + + ok(V_VT(post_data) == (VT_BYREF|VT_VARIANT), "V_VT(post_data)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(post_data)); + ok(V_VT(post_data) == (VT_BYREF|VT_VARIANT), "V_VT(post_data)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(post_data)); + ok(V_VARIANTREF(post_data) != NULL, "V_VARIANTREF(post_data) == NULL)\n"); + if(V_VARIANTREF(post_data)) { + ok(V_VT(V_VARIANTREF(post_data)) == (VT_VARIANT|VT_BYREF), + "V_VT(V_VARIANTREF(post_data))=%d, expected VT_VARIANT|VT_BYREF\n", + V_VT(V_VARIANTREF(post_data))); + ok(V_VARIANTREF(V_VARIANTREF(post_data)) != NULL, + "V_VARIANTREF(V_VARIANTREF(post_data)) == NULL\n"); + if(V_VARIANTREF(V_VARIANTREF(post_data))) { + ok(V_VT(V_VARIANTREF(V_VARIANTREF(post_data))) == VT_EMPTY, + "V_VT(V_VARIANTREF(V_VARIANTREF(post_data))) = %d, expected VT_EMPTY\n", + V_VT(V_VARIANTREF(V_VARIANTREF(post_data)))); + + if(V_VT(V_VARIANTREF(V_VARIANTREF(post_data))) == (VT_UI1|VT_ARRAY)) { + const SAFEARRAY *sa = V_ARRAY(V_VARIANTREF(V_VARIANTREF(post_data))); + + ok(sa->cDims == 1, "sa->cDims = %d, expected 1\n", sa->cDims); + ok(sa->fFeatures == 0, "sa->fFeatures = %d, expected 0\n", sa->fFeatures); + } + } + } + + ok(V_VT(headers) == (VT_BYREF|VT_VARIANT), "V_VT(headers)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(headers)); + ok(V_VARIANTREF(headers) != NULL, "V_VARIANTREF(headers) == NULL)\n"); + if(V_VARIANTREF(headers)) { + ok(V_VT(V_VARIANTREF(headers)) == VT_BSTR, "V_VT(V_VARIANTREF(headers))=%d, expected VT_BSTR\n", + V_VT(V_VARIANTREF(headers))); + ok(V_BSTR(V_VARIANTREF(headers)) == NULL, "V_BSTR(V_VARIANTREF(heders)) = %p, expected NULL\n", + V_BSTR(V_VARIANTREF(headers))); + } + + ok(V_VT(cancel) == (VT_BYREF|VT_BOOL), "V_VT(cancel)=%x, expected VT_BYREF|VT_BOOL\n", + V_VT(cancel)); + ok(V_BOOLREF(cancel) != NULL, "V_BOOLREF(pDispParams->rgvarg[0] == NULL)\n"); + if(V_BOOLREF(cancel)) + ok(*V_BOOLREF(cancel) == VARIANT_FALSE, "*V_BOOLREF(calcel) = %x, expected VARIANT_FALSE\n", + *V_BOOLREF(cancel)); +} + +static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(IsEqualGUID(&IID_NULL, riid), "riid != IID_NULL\n"); + ok(pDispParams != NULL, "pDispParams == NULL\n"); + ok(pExcepInfo == NULL, "pExcepInfo=%p, expected NULL\n", pExcepInfo); + ok(pVarResult == NULL, "pVarResult=%p\n", pVarResult); + ok(wFlags == DISPATCH_METHOD, "wFlags=%08x, expected DISPATCH_METHOD\n", wFlags); + ok(pDispParams->rgdispidNamedArgs == NULL, + "pDispParams->rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs); + ok(pDispParams->cNamedArgs == 0, "pDispParams->cNamedArgs = %d\n", pDispParams->cNamedArgs); + + switch(dispIdMember) { + case DISPID_STATUSTEXTCHANGE: + CHECK_EXPECT2(Invoke_STATUSTEXTCHANGE); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 1, "cArgs=%d, expected 1\n", pDispParams->cArgs); + ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(pDispParams->rgvarg)=%d, expected VT_BSTR\n", + V_VT(pDispParams->rgvarg)); + /* TODO: Check text */ + break; + + case DISPID_PROPERTYCHANGE: + CHECK_EXPECT2(Invoke_PROPERTYCHANGE); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 1, "cArgs=%d, expected 1\n", pDispParams->cArgs); + /* TODO: Check args */ + break; + + case DISPID_DOWNLOADBEGIN: + CHECK_EXPECT(Invoke_DOWNLOADBEGIN); + + ok(pDispParams->rgvarg == NULL, "rgvarg=%p, expected NULL\n", pDispParams->rgvarg); + ok(pDispParams->cArgs == 0, "cArgs=%d, expected 0\n", pDispParams->cArgs); + break; + + case DISPID_BEFORENAVIGATE2: + CHECK_EXPECT(Invoke_BEFORENAVIGATE2); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 7, "cArgs=%d, expected 7\n", pDispParams->cArgs); + test_OnBeforeNavigate(pDispParams->rgvarg+6, pDispParams->rgvarg+5, pDispParams->rgvarg+4, + pDispParams->rgvarg+3, pDispParams->rgvarg+2, pDispParams->rgvarg+1, + pDispParams->rgvarg); + break; + + case DISPID_SETSECURELOCKICON: + CHECK_EXPECT2(Invoke_SETSECURELOCKICON); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 1, "cArgs=%d, expected 1\n", pDispParams->cArgs); + /* TODO: Check args */ + break; + + case DISPID_FILEDOWNLOAD: + CHECK_EXPECT(Invoke_FILEDOWNLOAD); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 2, "cArgs=%d, expected 2\n", pDispParams->cArgs); + /* TODO: Check args */ + break; + + case DISPID_COMMANDSTATECHANGE: + CHECK_EXPECT2(Invoke_COMMANDSTATECHANGE); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 2, "cArgs=%d, expected 2\n", pDispParams->cArgs); + /* TODO: Check args */ + break; + + case DISPID_DOWNLOADCOMPLETE: + CHECK_EXPECT(Invoke_DOWNLOADCOMPLETE); + + ok(pDispParams->rgvarg == NULL, "rgvarg=%p, expected NULL\n", pDispParams->rgvarg); + ok(pDispParams->cArgs == 0, "cArgs=%d, expected 0\n", pDispParams->cArgs); + break; + + case DISPID_ONMENUBAR: + CHECK_EXPECT(Invoke_ONMENUBAR); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_ONADDRESSBAR: + CHECK_EXPECT(Invoke_ONADDRESSBAR); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_ONSTATUSBAR: + CHECK_EXPECT(Invoke_ONSTATUSBAR); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_ONTOOLBAR: + CHECK_EXPECT(Invoke_ONTOOLBAR); + test_invoke_bool(pDispParams, FALSE); + break; + + case DISPID_ONFULLSCREEN: + CHECK_EXPECT(Invoke_ONFULLSCREEN); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_ONTHEATERMODE: + CHECK_EXPECT(Invoke_ONTHEATERMODE); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_WINDOWSETRESIZABLE: + CHECK_EXPECT(Invoke_WINDOWSETRESIZABLE); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_TITLECHANGE: + CHECK_EXPECT2(Invoke_TITLECHANGE); + /* FIXME */ + break; + + case DISPID_NAVIGATECOMPLETE2: + CHECK_EXPECT(Invoke_NAVIGATECOMPLETE2); + /* FIXME */ + break; + + case DISPID_PROGRESSCHANGE: + CHECK_EXPECT(Invoke_PROGRESSCHANGE); + /* FIXME */ + break; + + case DISPID_DOCUMENTCOMPLETE: + CHECK_EXPECT(Invoke_DOCUMENTCOMPLETE); + /* FIXME */ + break; + + case 282: /* FIXME */ + CHECK_EXPECT2(Invoke_282); + break; + + default: + ok(0, "unexpected dispIdMember %d\n", dispIdMember); + } + + return S_OK; +} + +static IDispatchVtbl WebBrowserEvents2Vtbl = { + WebBrowserEvents2_QueryInterface, + Dispatch_AddRef, + Dispatch_Release, + Dispatch_GetTypeInfoCount, + Dispatch_GetTypeInfo, + Dispatch_GetIDsOfNames, + WebBrowserEvents2_Invoke +}; + +static IDispatch WebBrowserEvents2 = { &WebBrowserEvents2Vtbl }; + +static HRESULT WINAPI ClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI ClientSite_AddRef(IOleClientSite *iface) +{ + return 2; +} + +static ULONG WINAPI ClientSite_Release(IOleClientSite *iface) +{ + return 1; +} + +static HRESULT WINAPI ClientSite_SaveObject(IOleClientSite *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ClientSite_GetMoniker(IOleClientSite *iface, DWORD dwAssign, DWORD dwWhichMoniker, + IMoniker **ppmon) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ClientSite_GetContainer(IOleClientSite *iface, IOleContainer **ppContainer) +{ + CHECK_EXPECT(GetContainer); + + ok(ppContainer != NULL, "ppContainer == NULL\n"); + if(ppContainer) + *ppContainer = &OleContainer; + + return S_OK; +} + +static HRESULT WINAPI ClientSite_ShowObject(IOleClientSite *iface) +{ + CHECK_EXPECT(ShowObject); + return S_OK; +} + +static HRESULT WINAPI ClientSite_OnShowWindow(IOleClientSite *iface, BOOL fShow) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ClientSite_RequestNewObjectLayout(IOleClientSite *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IOleClientSiteVtbl ClientSiteVtbl = { + ClientSite_QueryInterface, + ClientSite_AddRef, + ClientSite_Release, + ClientSite_SaveObject, + ClientSite_GetMoniker, + ClientSite_GetContainer, + ClientSite_ShowObject, + ClientSite_OnShowWindow, + ClientSite_RequestNewObjectLayout +}; + +static IOleClientSite ClientSite = { &ClientSiteVtbl }; + +static HRESULT WINAPI InPlaceUIWindow_QueryInterface(IOleInPlaceFrame *iface, + REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI InPlaceUIWindow_AddRef(IOleInPlaceFrame *iface) +{ + return 2; +} + +static ULONG WINAPI InPlaceUIWindow_Release(IOleInPlaceFrame *iface) +{ + return 1; +} + +static HRESULT WINAPI InPlaceUIWindow_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd) +{ + CHECK_EXPECT(Frame_GetWindow); + ok(phwnd != NULL, "phwnd == NULL\n"); + if(phwnd) + *phwnd = container_hwnd; + return S_OK; +} + +static HRESULT WINAPI InPlaceUIWindow_ContextSensitiveHelp(IOleInPlaceFrame *iface, BOOL fEnterMode) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceUIWindow_GetBorder(IOleInPlaceFrame *iface, LPRECT lprectBorder) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceUIWindow_RequestBorderSpace(IOleInPlaceFrame *iface, + LPCBORDERWIDTHS pborderwidths) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceUIWindow_SetBorderSpace(IOleInPlaceFrame *iface, + LPCBORDERWIDTHS pborderwidths) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceUIWindow_SetActiveObject(IOleInPlaceFrame *iface, + IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + CHECK_EXPECT(UIWindow_SetActiveObject); + ok(pActiveObject != NULL, "pActiveObject = NULL\n"); + ok(!lstrcmpW(pszObjName, wszItem), "unexpected pszObjName\n"); + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_SetActiveObject(IOleInPlaceFrame *iface, + IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + CHECK_EXPECT(Frame_SetActiveObject); + ok(pActiveObject != NULL, "pActiveObject = NULL\n"); + ok(!lstrcmpW(pszObjName, wszItem), "unexpected pszObjName\n"); + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_InsertMenus(IOleInPlaceFrame *iface, HMENU hmenuShared, + LPOLEMENUGROUPWIDTHS lpMenuWidths) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_SetMenu(IOleInPlaceFrame *iface, HMENU hmenuShared, + HOLEMENU holemenu, HWND hwndActiveObject) +{ + CHECK_EXPECT(SetMenu); + ok(hmenuShared == NULL, "hmenuShared=%p\n", hmenuShared); + ok(holemenu == NULL, "holemenu=%p\n", holemenu); + ok(hwndActiveObject == shell_embedding_hwnd, "hwndActiveObject=%p, expected %p\n", + hwndActiveObject, shell_embedding_hwnd); + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_RemoveMenus(IOleInPlaceFrame *iface, HMENU hmenuShared) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_SetStatusText(IOleInPlaceFrame *iface, LPCOLESTR pszStatusText) +{ + CHECK_EXPECT2(SetStatusText); + /* FIXME: Check pszStatusText */ + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_EnableModeless(IOleInPlaceFrame *iface, BOOL fEnable) +{ + if(fEnable) + CHECK_EXPECT2(EnableModeless_TRUE); + else + CHECK_EXPECT2(EnableModeless_FALSE); + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_TranslateAccelerator(IOleInPlaceFrame *iface, LPMSG lpmsg, WORD wID) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IOleInPlaceFrameVtbl InPlaceUIWindowVtbl = { + InPlaceUIWindow_QueryInterface, + InPlaceUIWindow_AddRef, + InPlaceUIWindow_Release, + InPlaceUIWindow_GetWindow, + InPlaceUIWindow_ContextSensitiveHelp, + InPlaceUIWindow_GetBorder, + InPlaceUIWindow_RequestBorderSpace, + InPlaceUIWindow_SetBorderSpace, + InPlaceUIWindow_SetActiveObject, +}; + +static IOleInPlaceUIWindow InPlaceUIWindow = { (IOleInPlaceUIWindowVtbl*)&InPlaceUIWindowVtbl }; + +static const IOleInPlaceFrameVtbl InPlaceFrameVtbl = { + InPlaceUIWindow_QueryInterface, + InPlaceUIWindow_AddRef, + InPlaceUIWindow_Release, + InPlaceFrame_GetWindow, + InPlaceUIWindow_ContextSensitiveHelp, + InPlaceUIWindow_GetBorder, + InPlaceUIWindow_RequestBorderSpace, + InPlaceUIWindow_SetBorderSpace, + InPlaceFrame_SetActiveObject, + InPlaceFrame_InsertMenus, + InPlaceFrame_SetMenu, + InPlaceFrame_RemoveMenus, + InPlaceFrame_SetStatusText, + InPlaceFrame_EnableModeless, + InPlaceFrame_TranslateAccelerator +}; + +static IOleInPlaceFrame InPlaceFrame = { &InPlaceFrameVtbl }; + +static HRESULT WINAPI InPlaceSite_QueryInterface(IOleInPlaceSiteEx *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI InPlaceSite_AddRef(IOleInPlaceSiteEx *iface) +{ + return 2; +} + +static ULONG WINAPI InPlaceSite_Release(IOleInPlaceSiteEx *iface) +{ + return 1; +} + +static HRESULT WINAPI InPlaceSite_GetWindow(IOleInPlaceSiteEx *iface, HWND *phwnd) +{ + CHECK_EXPECT(Site_GetWindow); + ok(phwnd != NULL, "phwnd == NULL\n"); + if(phwnd) + *phwnd = container_hwnd; + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_ContextSensitiveHelp(IOleInPlaceSiteEx *iface, BOOL fEnterMode) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_CanInPlaceActivate(IOleInPlaceSiteEx *iface) +{ + CHECK_EXPECT(CanInPlaceActivate); + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceActivate(IOleInPlaceSiteEx *iface) +{ + CHECK_EXPECT(OnInPlaceActivate); + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_OnUIActivate(IOleInPlaceSiteEx *iface) +{ + CHECK_EXPECT(OnUIActivate); + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_GetWindowContext(IOleInPlaceSiteEx *iface, + IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, + LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) +{ + static const RECT pos_rect = {2,1,1002,901}; + static const RECT clip_rect = {10,10,990,890}; + + CHECK_EXPECT(GetWindowContext); + + ok(ppFrame != NULL, "ppFrame = NULL\n"); + if(ppFrame) + *ppFrame = &InPlaceFrame; + + ok(ppDoc != NULL, "ppDoc = NULL\n"); + if(ppDoc) + *ppDoc = &InPlaceUIWindow; + + ok(lprcPosRect != NULL, "lprcPosRect = NULL\n"); + if(lprcPosRect) + memcpy(lprcPosRect, &pos_rect, sizeof(RECT)); + + ok(lprcClipRect != NULL, "lprcClipRect = NULL\n"); + if(lprcClipRect) + memcpy(lprcClipRect, &clip_rect, sizeof(RECT)); + + ok(lpFrameInfo != NULL, "lpFrameInfo = NULL\n"); + if(lpFrameInfo) { + lpFrameInfo->cb = sizeof(*lpFrameInfo); + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->hwndFrame = container_hwnd; + lpFrameInfo->haccel = NULL; + lpFrameInfo->cAccelEntries = 0; + } + + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_Scroll(IOleInPlaceSiteEx *iface, SIZE scrollExtant) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnUIDeactivate(IOleInPlaceSiteEx *iface, BOOL fUndoable) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceDeactivate(IOleInPlaceSiteEx *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_DiscardUndoState(IOleInPlaceSiteEx *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_DeactivateAndUndo(IOleInPlaceSiteEx *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnPosRectChange(IOleInPlaceSiteEx *iface, LPCRECT lprcPosRect) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceActivateEx(IOleInPlaceSiteEx *iface, + BOOL *pNoRedraw, DWORD dwFlags) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceDeactivateEx(IOleInPlaceSiteEx *iface, + BOOL fNoRedraw) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_RequestUIActivate(IOleInPlaceSiteEx *iface) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static const IOleInPlaceSiteExVtbl InPlaceSiteExVtbl = { + InPlaceSite_QueryInterface, + InPlaceSite_AddRef, + InPlaceSite_Release, + InPlaceSite_GetWindow, + InPlaceSite_ContextSensitiveHelp, + InPlaceSite_CanInPlaceActivate, + InPlaceSite_OnInPlaceActivate, + InPlaceSite_OnUIActivate, + InPlaceSite_GetWindowContext, + InPlaceSite_Scroll, + InPlaceSite_OnUIDeactivate, + InPlaceSite_OnInPlaceDeactivate, + InPlaceSite_DiscardUndoState, + InPlaceSite_DeactivateAndUndo, + InPlaceSite_OnPosRectChange, + InPlaceSite_OnInPlaceActivateEx, + InPlaceSite_OnInPlaceDeactivateEx, + InPlaceSite_RequestUIActivate +}; + +static IOleInPlaceSiteEx InPlaceSite = { &InPlaceSiteExVtbl }; + +static HRESULT WINAPI DocHostUIHandler_QueryInterface(IDocHostUIHandler2 *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI DocHostUIHandler_AddRef(IDocHostUIHandler2 *iface) +{ + return 2; +} + +static ULONG WINAPI DocHostUIHandler_Release(IDocHostUIHandler2 *iface) +{ + return 1; +} + +static HRESULT WINAPI DocHostUIHandler_ShowContextMenu(IDocHostUIHandler2 *iface, DWORD dwID, POINT *ppt, + IUnknown *pcmdtReserved, IDispatch *pdicpReserved) +{ + ok(0, "unexpected call %d %p %p %p\n", dwID, ppt, pcmdtReserved, pdicpReserved); + return S_FALSE; +} + +static HRESULT WINAPI DocHostUIHandler_GetHostInfo(IDocHostUIHandler2 *iface, DOCHOSTUIINFO *pInfo) +{ + CHECK_EXPECT2(GetHostInfo); + ok(pInfo != NULL, "pInfo=NULL\n"); + if(pInfo) { + ok(pInfo->cbSize == sizeof(DOCHOSTUIINFO) || broken(!pInfo->cbSize), "pInfo->cbSize=%u\n", pInfo->cbSize); + ok(!pInfo->dwFlags, "pInfo->dwFlags=%08x, expected 0\n", pInfo->dwFlags); + ok(!pInfo->dwDoubleClick, "pInfo->dwDoubleClick=%08x, expected 0\n", pInfo->dwDoubleClick); + ok(!pInfo->pchHostCss, "pInfo->pchHostCss=%p, expected NULL\n", pInfo->pchHostCss); + ok(!pInfo->pchHostNS, "pInfo->pchhostNS=%p, expected NULL\n", pInfo->pchHostNS); + } + return E_FAIL; +} + +static HRESULT WINAPI DocHostUIHandler_ShowUI(IDocHostUIHandler2 *iface, DWORD dwID, + IOleInPlaceActiveObject *pActiveObject, IOleCommandTarget *pCommandTarget, + IOleInPlaceFrame *pFrame, IOleInPlaceUIWindow *pDoc) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_HideUI(IDocHostUIHandler2 *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_UpdateUI(IDocHostUIHandler2 *iface) +{ + CHECK_EXPECT(UpdateUI); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_EnableModeless(IDocHostUIHandler2 *iface, BOOL fEnable) +{ + if(fEnable) + CHECK_EXPECT(DocHost_EnableModeless_TRUE); + else + CHECK_EXPECT(DocHost_EnableModeless_FALSE); + + return S_OK; +} + +static HRESULT WINAPI DocHostUIHandler_OnDocWindowActivate(IDocHostUIHandler2 *iface, BOOL fActivate) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_OnFrameWindowActivate(IDocHostUIHandler2 *iface, BOOL fActivate) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_ResizeBorder(IDocHostUIHandler2 *iface, LPCRECT prcBorder, + IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_TranslateAccelerator(IDocHostUIHandler2 *iface, LPMSG lpMsg, + const GUID *pguidCmdGroup, DWORD nCmdID) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_GetOptionKeyPath(IDocHostUIHandler2 *iface, + LPOLESTR *pchKey, DWORD dw) +{ + CHECK_EXPECT(GetOptionKeyPath); + ok(pchKey != NULL, "pchKey==NULL\n"); + if(pchKey) + ok(*pchKey == NULL, "*pchKey=%p\n", *pchKey); + ok(!dw, "dw=%x\n", dw); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_GetDropTarget(IDocHostUIHandler2 *iface, + IDropTarget *pDropTarget, IDropTarget **ppDropTarget) +{ + CHECK_EXPECT(GetDropTarget); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_GetExternal(IDocHostUIHandler2 *iface, IDispatch **ppDispatch) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_TranslateUrl(IDocHostUIHandler2 *iface, DWORD dwTranslate, + OLECHAR *pchURLIn, OLECHAR **ppchURLOut) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_FilterDataObject(IDocHostUIHandler2 *iface, IDataObject *pDO, + IDataObject **ppPORet) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_GetOverrideKeyPath(IDocHostUIHandler2 *iface, + LPOLESTR *pchKey, DWORD dw) +{ + CHECK_EXPECT(GetOverridesKeyPath); + ok(pchKey != NULL, "pchKey==NULL\n"); + if(pchKey) + ok(*pchKey == NULL, "*pchKey=%p\n", *pchKey); + ok(!dw, "dw=%x\n", dw); + return E_NOTIMPL; +} + +static const IDocHostUIHandler2Vtbl DocHostUIHandlerVtbl = { + DocHostUIHandler_QueryInterface, + DocHostUIHandler_AddRef, + DocHostUIHandler_Release, + DocHostUIHandler_ShowContextMenu, + DocHostUIHandler_GetHostInfo, + DocHostUIHandler_ShowUI, + DocHostUIHandler_HideUI, + DocHostUIHandler_UpdateUI, + DocHostUIHandler_EnableModeless, + DocHostUIHandler_OnDocWindowActivate, + DocHostUIHandler_OnFrameWindowActivate, + DocHostUIHandler_ResizeBorder, + DocHostUIHandler_TranslateAccelerator, + DocHostUIHandler_GetOptionKeyPath, + DocHostUIHandler_GetDropTarget, + DocHostUIHandler_GetExternal, + DocHostUIHandler_TranslateUrl, + DocHostUIHandler_FilterDataObject, + DocHostUIHandler_GetOverrideKeyPath +}; + +static IDocHostUIHandler2 DocHostUIHandler = { &DocHostUIHandlerVtbl }; + + +static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, + REFGUID guidService, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if (IsEqualGUID(&SID_STopLevelBrowser, guidService)) + trace("Service SID_STopLevelBrowser\n"); + else if (IsEqualGUID(&SID_SEditCommandTarget, guidService)) + trace("Service SID_SEditCommandTarget\n"); + else if (IsEqualGUID(&IID_ITargetFrame2, guidService)) + trace("Service IID_ITargetFrame2\n"); + else if (IsEqualGUID(&SID_SInternetSecurityManager, guidService)) + trace("Service SID_SInternetSecurityManager\n"); + else if (IsEqualGUID(&SID_SOleUndoManager, guidService)) + trace("Service SID_SOleUndoManager\n"); + else if (IsEqualGUID(&SID_IMimeInfo, guidService)) + trace("Service SID_IMimeInfo\n"); + else if (IsEqualGUID(&SID_STopWindow, guidService)) + trace("Service SID_STopWindow\n"); + + /* 30D02401-6A81-11D0-8274-00C04FD5AE38 Explorer Bar: Search */ + /* D1E7AFEC-6A2E-11D0-8C78-00C04FD918B4 no info */ + /* A9227C3C-7F8E-11D0-8CB0-00A0C92DBFE8 no info */ + /* 371EA634-DC5C-11D1-BA57-00C04FC2040E one reference to IVersionHost */ + /* 3050F429-98B5-11CF-BB82-00AA00BDCE0B IID_IElementBehaviorFactory */ + /* 6D12FE80-7911-11CF-9534-0000C05BAE0B SID_DefView */ + /* AD7F6C62-F6BD-11D2-959B-006097C553C8 no info */ + /* 53A2D5B1-D2FC-11D0-84E0-006097C9987D no info */ + /* 3050F312-98B5-11CF-BB82-00AA00BDCE0B HTMLFrameBaseClass */ + /* 639447BD-B2D3-44B9-9FB0-510F23CB45E4 no info */ + /* 20C46561-8491-11CF-960C-0080C7F4EE85 no info */ + + else + trace("Service %s not supported\n", debugstr_guid(guidService)); + + return E_NOINTERFACE; +} + + +static const IServiceProviderVtbl ServiceProviderVtbl = { + ServiceProvider_QueryInterface, + ServiceProvider_AddRef, + ServiceProvider_Release, + ServiceProvider_QueryService +}; + +static IServiceProvider ServiceProvider = { &ServiceProviderVtbl }; + + +static HRESULT QueryInterface(REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid) + || IsEqualGUID(&IID_IOleClientSite, riid)) + *ppv = &ClientSite; + else if(IsEqualGUID(&IID_IOleWindow, riid) + || IsEqualGUID(&IID_IOleInPlaceSite, riid) + || IsEqualGUID(&IID_IOleInPlaceSiteEx, riid)) + *ppv = &InPlaceSite; + else if(IsEqualGUID(&IID_IDocHostUIHandler, riid) + || IsEqualGUID(&IID_IDocHostUIHandler2, riid)) + *ppv = &DocHostUIHandler; + else if(IsEqualGUID(&IID_IDispatch, riid)) + *ppv = &Dispatch; + else if(IsEqualGUID(&IID_IServiceProvider, riid)) + *ppv = &ServiceProvider; + else if(IsEqualGUID(&IID_IDocHostShowUI, riid)) + trace("interface IID_IDocHostShowUI\n"); + else if(IsEqualGUID(&IID_IOleControlSite, riid)) + trace("interface IID_IOleControlSite\n"); + else if(IsEqualGUID(&IID_IOleCommandTarget, riid)) + trace("interface IID_IOleCommandTarget\n"); + + /* B6EA2050-048A-11D1-82B9-00C04FB9942E IAxWinHostWindow */ + + else + { + /* are there more interfaces, that a host can support? */ + trace("%s: interface not supported\n", debugstr_guid(riid)); + } + + return (*ppv) ? S_OK : E_NOINTERFACE; +} + +static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +static HWND create_container_window(void) +{ + static const WCHAR wszWebBrowserContainer[] = + {'W','e','b','B','r','o','w','s','e','r','C','o','n','t','a','i','n','e','r',0}; + static WNDCLASSEXW wndclass = { + sizeof(WNDCLASSEXW), + 0, + wnd_proc, + 0, 0, NULL, NULL, NULL, NULL, NULL, + wszWebBrowserContainer, + NULL + }; + + RegisterClassExW(&wndclass); + return CreateWindowW(wszWebBrowserContainer, wszWebBrowserContainer, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, NULL, NULL, NULL, NULL); +} + +static void test_DoVerb(IUnknown *unk) +{ + IOleObject *oleobj; + RECT rect = {0,0,1000,1000}; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj); + ok(hres == S_OK, "QueryInterface(IID_OleObject) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + SET_EXPECT(CanInPlaceActivate); + SET_EXPECT(Site_GetWindow); + SET_EXPECT(OnInPlaceActivate); + SET_EXPECT(GetWindowContext); + SET_EXPECT(ShowObject); + SET_EXPECT(GetContainer); + SET_EXPECT(Frame_GetWindow); + SET_EXPECT(OnUIActivate); + SET_EXPECT(Frame_SetActiveObject); + SET_EXPECT(UIWindow_SetActiveObject); + SET_EXPECT(SetMenu); + + hres = IOleObject_DoVerb(oleobj, OLEIVERB_SHOW, NULL, &ClientSite, + 0, (HWND)0xdeadbeef, &rect); + ok(hres == S_OK, "DoVerb failed: %08x\n", hres); + + CHECK_CALLED(CanInPlaceActivate); + CHECK_CALLED(Site_GetWindow); + CHECK_CALLED(OnInPlaceActivate); + CHECK_CALLED(GetWindowContext); + CHECK_CALLED(ShowObject); + CHECK_CALLED(GetContainer); + CHECK_CALLED(Frame_GetWindow); + CHECK_CALLED(OnUIActivate); + CHECK_CALLED(Frame_SetActiveObject); + CHECK_CALLED(UIWindow_SetActiveObject); + CHECK_CALLED(SetMenu); + + hres = IOleObject_DoVerb(oleobj, OLEIVERB_SHOW, NULL, &ClientSite, + 0, (HWND)0xdeadbeef, &rect); + ok(hres == S_OK, "DoVerb failed: %08x\n", hres); + + IOleObject_Release(oleobj); +} + +static void test_GetMiscStatus(IOleObject *oleobj) +{ + DWORD st, i; + HRESULT hres; + + for(i=0; i<10; i++) { + st = 0xdeadbeef; + hres = IOleObject_GetMiscStatus(oleobj, i, &st); + ok(hres == S_OK, "GetMiscStatus failed: %08x\n", hres); + ok(st == (OLEMISC_SETCLIENTSITEFIRST|OLEMISC_ACTIVATEWHENVISIBLE|OLEMISC_INSIDEOUT + |OLEMISC_CANTLINKINSIDE|OLEMISC_RECOMPOSEONRESIZE), + "st=%08x, expected OLEMISC_SETCLIENTSITEFIRST|OLEMISC_ACTIVATEWHENVISIBLE|" + "OLEMISC_INSIDEOUT|OLEMISC_CANTLINKINSIDE|OLEMISC_RECOMPOSEONRESIZE)\n", st); + } +} + +static void test_SetHostNames(IOleObject *oleobj) +{ + HRESULT hres; + + static const WCHAR test_appW[] = {'t','e','s','t',' ','a','p','p',0}; + + hres = IOleObject_SetHostNames(oleobj, test_appW, (void*)0xdeadbeef); + ok(hres == S_OK, "SetHostNames failed: %08x\n", hres); +} + +static void test_ClientSite(IUnknown *unk, IOleClientSite *client) +{ + IOleObject *oleobj; + IOleInPlaceObject *inplace; + HWND hwnd; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj); + ok(hres == S_OK, "QueryInterface(IID_OleObject) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + test_GetMiscStatus(oleobj); + test_SetHostNames(oleobj); + + hres = IUnknown_QueryInterface(unk, &IID_IOleInPlaceObject, (void**)&inplace); + ok(hres == S_OK, "QueryInterface(IID_OleInPlaceObject) failed: %08x\n", hres); + if(FAILED(hres)) { + IOleObject_Release(oleobj); + return; + } + + hres = IOleInPlaceObject_GetWindow(inplace, &hwnd); + ok(hres == S_OK, "GetWindow failed: %08x\n", hres); + ok((hwnd == NULL) ^ (client == NULL), "unexpected hwnd %p\n", hwnd); + + if(client) { + SET_EXPECT(GetContainer); + SET_EXPECT(Site_GetWindow); + SET_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + SET_EXPECT(Invoke_AMBIENT_SILENT); + }else if(!is_downloading) { + SET_EXPECT(Invoke_DOWNLOADCOMPLETE); + SET_EXPECT(Exec_SETDOWNLOADSTATE_0); + SET_EXPECT(Invoke_COMMANDSTATECHANGE); + } + + hres = IOleObject_SetClientSite(oleobj, client); + ok(hres == S_OK, "SetClientSite failed: %08x\n", hres); + + if(client) { + CHECK_CALLED(GetContainer); + CHECK_CALLED(Site_GetWindow); + CHECK_CALLED(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + CHECK_CALLED(Invoke_AMBIENT_SILENT); + }else if(!is_downloading) { + todo_wine CHECK_CALLED(Invoke_DOWNLOADCOMPLETE); + todo_wine CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); + todo_wine CHECK_CALLED(Invoke_COMMANDSTATECHANGE); + } + + hres = IOleInPlaceObject_GetWindow(inplace, &hwnd); + ok(hres == S_OK, "GetWindow failed: %08x\n", hres); + ok((hwnd == NULL) == (client == NULL), "unexpected hwnd %p\n", hwnd); + + shell_embedding_hwnd = hwnd; + + test_SetHostNames(oleobj); + + IOleInPlaceObject_Release(inplace); + IOleObject_Release(oleobj); +} + +static void test_ClassInfo(IUnknown *unk) +{ + IProvideClassInfo2 *class_info; + GUID guid; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IProvideClassInfo2, (void**)&class_info); + ok(hres == S_OK, "QueryInterface(IID_IProvideClassInfo) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IProvideClassInfo2_GetGUID(class_info, GUIDKIND_DEFAULT_SOURCE_DISP_IID, &guid); + ok(hres == S_OK, "GetGUID failed: %08x\n", hres); + ok(IsEqualGUID(&DIID_DWebBrowserEvents2, &guid), "wrong guid\n"); + + hres = IProvideClassInfo2_GetGUID(class_info, 0, &guid); + ok(hres == E_FAIL, "GetGUID failed: %08x, expected E_FAIL\n", hres); + ok(IsEqualGUID(&IID_NULL, &guid), "wrong guid\n"); + + hres = IProvideClassInfo2_GetGUID(class_info, 2, &guid); + ok(hres == E_FAIL, "GetGUID failed: %08x, expected E_FAIL\n", hres); + ok(IsEqualGUID(&IID_NULL, &guid), "wrong guid\n"); + + hres = IProvideClassInfo2_GetGUID(class_info, GUIDKIND_DEFAULT_SOURCE_DISP_IID, NULL); + ok(hres == E_POINTER, "GetGUID failed: %08x, expected E_POINTER\n", hres); + + hres = IProvideClassInfo2_GetGUID(class_info, 0, NULL); + ok(hres == E_POINTER, "GetGUID failed: %08x, expected E_POINTER\n", hres); + + IProvideClassInfo2_Release(class_info); +} + +static void test_ie_funcs(IUnknown *unk) +{ + IWebBrowser2 *wb; + IDispatch *disp; + VARIANT_BOOL b; + int i; + LONG hwnd; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&wb); + ok(hres == S_OK, "Could not get IWebBrowser2 interface: %08x\n", hres); + if(FAILED(hres)) + return; + + /* HWND */ + + hwnd = 0xdeadbeef; + hres = IWebBrowser2_get_HWND(wb, &hwnd); + ok(hres == E_FAIL, "get_HWND failed: %08x, expected E_FAIL\n", hres); + ok(hwnd == 0, "unexpected hwnd %x\n", hwnd); + + /* MenuBar */ + + hres = IWebBrowser2_get_MenuBar(wb, &b); + ok(hres == S_OK, "get_MenuBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONMENUBAR); + hres = IWebBrowser2_put_MenuBar(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_MenuBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONMENUBAR); + + hres = IWebBrowser2_get_MenuBar(wb, &b); + ok(hres == S_OK, "get_MenuBar failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONMENUBAR); + hres = IWebBrowser2_put_MenuBar(wb, (exvb = 100)); + ok(hres == S_OK, "put_MenuBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONMENUBAR); + + hres = IWebBrowser2_get_MenuBar(wb, &b); + ok(hres == S_OK, "get_MenuBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + /* AddressBar */ + + hres = IWebBrowser2_get_AddressBar(wb, &b); + ok(hres == S_OK, "get_AddressBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONADDRESSBAR); + hres = IWebBrowser2_put_AddressBar(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_AddressBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONADDRESSBAR); + + hres = IWebBrowser2_get_AddressBar(wb, &b); + ok(hres == S_OK, "get_MenuBar failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONADDRESSBAR); + hres = IWebBrowser2_put_AddressBar(wb, (exvb = 100)); + ok(hres == S_OK, "put_AddressBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONADDRESSBAR); + + hres = IWebBrowser2_get_AddressBar(wb, &b); + ok(hres == S_OK, "get_AddressBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONADDRESSBAR); + hres = IWebBrowser2_put_AddressBar(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_MenuBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONADDRESSBAR); + + /* StatusBar */ + + hres = IWebBrowser2_get_StatusBar(wb, &b); + ok(hres == S_OK, "get_StatusBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONSTATUSBAR); + hres = IWebBrowser2_put_StatusBar(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_StatusBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONSTATUSBAR); + + hres = IWebBrowser2_get_StatusBar(wb, &b); + ok(hres == S_OK, "get_StatusBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONSTATUSBAR); + hres = IWebBrowser2_put_StatusBar(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_StatusBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONSTATUSBAR); + + hres = IWebBrowser2_get_StatusBar(wb, &b); + ok(hres == S_OK, "get_StatusBar failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONSTATUSBAR); + hres = IWebBrowser2_put_StatusBar(wb, (exvb = 100)); + ok(hres == S_OK, "put_StatusBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONSTATUSBAR); + + hres = IWebBrowser2_get_StatusBar(wb, &b); + ok(hres == S_OK, "get_StatusBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + /* ToolBar */ + + hres = IWebBrowser2_get_ToolBar(wb, &i); + ok(hres == S_OK, "get_ToolBar failed: %08x\n", hres); + ok(i, "i=%x\n", i); + + SET_EXPECT(Invoke_ONTOOLBAR); + hres = IWebBrowser2_put_ToolBar(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_ToolBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTOOLBAR); + + hres = IWebBrowser2_get_ToolBar(wb, &i); + ok(hres == S_OK, "get_ToolBar failed: %08x\n", hres); + ok(i == VARIANT_FALSE, "b=%x\n", i); + + SET_EXPECT(Invoke_ONTOOLBAR); + hres = IWebBrowser2_put_ToolBar(wb, (exvb = 100)); + ok(hres == S_OK, "put_ToolBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTOOLBAR); + + hres = IWebBrowser2_get_ToolBar(wb, &i); + ok(hres == S_OK, "get_ToolBar failed: %08x\n", hres); + ok(i, "i=%x\n", i); + + SET_EXPECT(Invoke_ONTOOLBAR); + hres = IWebBrowser2_put_ToolBar(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_ToolBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTOOLBAR); + + /* FullScreen */ + + hres = IWebBrowser2_get_FullScreen(wb, &b); + ok(hres == S_OK, "get_FullScreen failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONFULLSCREEN); + hres = IWebBrowser2_put_FullScreen(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_FullScreen failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONFULLSCREEN); + + hres = IWebBrowser2_get_FullScreen(wb, &b); + ok(hres == S_OK, "get_FullScreen failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONFULLSCREEN); + hres = IWebBrowser2_put_FullScreen(wb, (exvb = 100)); + ok(hres == S_OK, "put_FullScreen failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONFULLSCREEN); + + hres = IWebBrowser2_get_FullScreen(wb, &b); + ok(hres == S_OK, "get_FullScreen failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONFULLSCREEN); + hres = IWebBrowser2_put_FullScreen(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_FullScreen failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONFULLSCREEN); + + /* TheaterMode */ + + hres = IWebBrowser2_get_TheaterMode(wb, &b); + ok(hres == S_OK, "get_TheaterMode failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONTHEATERMODE); + hres = IWebBrowser2_put_TheaterMode(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_TheaterMode failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTHEATERMODE); + + hres = IWebBrowser2_get_TheaterMode(wb, &b); + ok(hres == S_OK, "get_TheaterMode failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONTHEATERMODE); + hres = IWebBrowser2_put_TheaterMode(wb, (exvb = 100)); + ok(hres == S_OK, "put_TheaterMode failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTHEATERMODE); + + hres = IWebBrowser2_get_TheaterMode(wb, &b); + ok(hres == S_OK, "get_TheaterMode failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONTHEATERMODE); + hres = IWebBrowser2_put_TheaterMode(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_TheaterMode failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTHEATERMODE); + + /* Resizable */ + + b = 0x100; + hres = IWebBrowser2_get_Resizable(wb, &b); + ok(hres == E_NOTIMPL, "get_Resizable failed: %08x\n", hres); + ok(b == 0x100, "b=%x\n", b); + + SET_EXPECT(Invoke_WINDOWSETRESIZABLE); + hres = IWebBrowser2_put_Resizable(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK || broken(hres == E_NOTIMPL), "put_Resizable failed: %08x\n", hres); + CHECK_CALLED_BROKEN(Invoke_WINDOWSETRESIZABLE); + + SET_EXPECT(Invoke_WINDOWSETRESIZABLE); + hres = IWebBrowser2_put_Resizable(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK || broken(hres == E_NOTIMPL), "put_Resizable failed: %08x\n", hres); + CHECK_CALLED_BROKEN(Invoke_WINDOWSETRESIZABLE); + + hres = IWebBrowser2_get_Resizable(wb, &b); + ok(hres == E_NOTIMPL, "get_Resizable failed: %08x\n", hres); + ok(b == 0x100, "b=%x\n", b); + + /* Application */ + + disp = NULL; + hres = IWebBrowser2_get_Application(wb, &disp); + ok(hres == S_OK, "get_Application failed: %08x\n", hres); + ok(disp == (void*)wb, "disp=%p, expected %p\n", disp, wb); + if(disp) + IDispatch_Release(disp); + + hres = IWebBrowser2_get_Application(wb, NULL); + ok(hres == E_POINTER, "get_Application failed: %08x, expected E_POINTER\n", hres); + + /* Quit */ + + hres = IWebBrowser2_Quit(wb); + ok(hres == E_FAIL, "Quit failed: %08x, expected E_FAIL\n", hres); + + IWebBrowser2_Release(wb); +} + +static void test_Silent(IWebBrowser2 *wb, IOleControl *control, BOOL is_clientsite) +{ + VARIANT_BOOL b; + HRESULT hres; + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + hres = IWebBrowser2_put_Silent(wb, VARIANT_TRUE); + ok(hres == S_OK, "set_Silent failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + hres = IWebBrowser2_put_Silent(wb, 100); + ok(hres == S_OK, "set_Silent failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + hres = IWebBrowser2_put_Silent(wb, VARIANT_FALSE); + ok(hres == S_OK, "set_Silent failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + if(is_clientsite) { + hres = IWebBrowser2_put_Silent(wb, VARIANT_TRUE); + ok(hres == S_OK, "set_Silent failed: %08x\n", hres); + + SET_EXPECT(Invoke_AMBIENT_SILENT); + } + + hres = IOleControl_OnAmbientPropertyChange(control, DISPID_AMBIENT_SILENT); + ok(hres == S_OK, "OnAmbientPropertyChange failed %08x\n", hres); + + if(is_clientsite) + CHECK_CALLED(Invoke_AMBIENT_SILENT); + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); +} + +static void test_Offline(IWebBrowser2 *wb, IOleControl *control, BOOL is_clientsite) +{ + VARIANT_BOOL b; + HRESULT hres; + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + hres = IWebBrowser2_put_Offline(wb, VARIANT_TRUE); + ok(hres == S_OK, "set_Offline failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + hres = IWebBrowser2_put_Offline(wb, 100); + ok(hres == S_OK, "set_Offline failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + hres = IWebBrowser2_put_Offline(wb, VARIANT_FALSE); + ok(hres == S_OK, "set_Offline failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + if(is_clientsite) { + hres = IWebBrowser2_put_Offline(wb, VARIANT_TRUE); + ok(hres == S_OK, "set_Offline failed: %08x\n", hres); + + SET_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + } + + hres = IOleControl_OnAmbientPropertyChange(control, DISPID_AMBIENT_OFFLINEIFNOTCONNECTED); + ok(hres == S_OK, "OnAmbientPropertyChange failed %08x\n", hres); + + if(is_clientsite) + CHECK_CALLED(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); +} + +static void test_ambient_unknown(IWebBrowser2 *wb, IOleControl *control, BOOL is_clientsite) +{ + HRESULT hres; + + SET_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + SET_EXPECT(Invoke_AMBIENT_SILENT); + SET_EXPECT(Invoke_AMBIENT_USERMODE); + SET_EXPECT(Invoke_AMBIENT_DLCONTROL); + SET_EXPECT(Invoke_AMBIENT_USERAGENT); + SET_EXPECT(Invoke_AMBIENT_PALETTE); + + hres = IOleControl_OnAmbientPropertyChange(control, DISPID_UNKNOWN); + ok(hres == S_OK, "OnAmbientPropertyChange failed %08x\n", hres); + + CHECK_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + CHECK_EXPECT(Invoke_AMBIENT_SILENT); + CHECK_EXPECT(Invoke_AMBIENT_USERMODE); + CHECK_EXPECT(Invoke_AMBIENT_DLCONTROL); + CHECK_EXPECT(Invoke_AMBIENT_USERAGENT); + CHECK_EXPECT(Invoke_AMBIENT_PALETTE); + + CLEAR_CALLED(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + CLEAR_CALLED(Invoke_AMBIENT_SILENT); + CLEAR_CALLED(Invoke_AMBIENT_USERMODE); + CLEAR_CALLED(Invoke_AMBIENT_DLCONTROL); + CLEAR_CALLED(Invoke_AMBIENT_USERAGENT); + CLEAR_CALLED(Invoke_AMBIENT_PALETTE); +} + +static void test_wb_funcs(IUnknown *unk, BOOL is_clientsite) +{ + IWebBrowser2 *wb; + IOleControl *control; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&wb); + ok(hres == S_OK, "Could not get IWebBrowser2 interface: %08x\n", hres); + + hres = IUnknown_QueryInterface(unk, &IID_IOleControl, (void**)&control); + ok(hres == S_OK, "Could not get IOleControl interface: %08x\n", hres); + + test_Silent(wb, control, is_clientsite); + test_Offline(wb, control, is_clientsite); + test_ambient_unknown(wb, control, is_clientsite); + + IWebBrowser_Release(wb); + IOleControl_Release(control); +} + +static void test_GetControlInfo(IUnknown *unk) +{ + IOleControl *control; + CONTROLINFO info; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IOleControl, (void**)&control); + ok(hres == S_OK, "Could not get IOleControl: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IOleControl_GetControlInfo(control, &info); + ok(hres == E_NOTIMPL, "GetControlInfo failed: %08x, exxpected E_NOTIMPL\n", hres); + hres = IOleControl_GetControlInfo(control, NULL); + ok(hres == E_NOTIMPL, "GetControlInfo failed: %08x, exxpected E_NOTIMPL\n", hres); + + IOleControl_Release(control); +} + +static void test_Extent(IUnknown *unk) +{ + IOleObject *oleobj; + SIZE size, expected; + HRESULT hres; + DWORD dpi_x; + DWORD dpi_y; + HDC hdc; + + /* default aspect ratio is 96dpi / 96dpi */ + hdc = GetDC(0); + dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); + dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(0, hdc); + if (dpi_x != 96 || dpi_y != 96) + trace("dpi: %d / %d\n", dpi_y, dpi_y); + + hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj); + ok(hres == S_OK, "Could not get IOleObkect: %08x\n", hres); + if(FAILED(hres)) + return; + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, DVASPECT_CONTENT, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + /* Default size is 50x20 pixels, in himetric units */ + expected.cx = MulDiv( 50, 2540, dpi_x ); + expected.cy = MulDiv( 20, 2540, dpi_y ); + ok(size.cx == expected.cx && size.cy == expected.cy, "size = {%d %d} (expected %d %d)\n", + size.cx, size.cy, expected.cx, expected.cy ); + + size.cx = 800; + size.cy = 700; + hres = IOleObject_SetExtent(oleobj, DVASPECT_CONTENT, &size); + ok(hres == S_OK, "SetExtent failed: %08x\n", hres); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, DVASPECT_CONTENT, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 800 && size.cy == 700, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, 0, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 800 && size.cy == 700, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = 900; + size.cy = 800; + hres = IOleObject_SetExtent(oleobj, 0, &size); + ok(hres == S_OK, "SetExtent failed: %08x\n", hres); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, 0, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 900 && size.cy == 800, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, 0xdeadbeef, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 900 && size.cy == 800, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = 1000; + size.cy = 900; + hres = IOleObject_SetExtent(oleobj, 0xdeadbeef, &size); + ok(hres == S_OK, "SetExtent failed: %08x\n", hres); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, 0xdeadbeef, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 1000 && size.cy == 900, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, DVASPECT_CONTENT, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 1000 && size.cy == 900, "size = {%d %d}\n", size.cx, size.cy); + + IOleObject_Release(oleobj); +} + +static void test_ConnectionPoint(IUnknown *unk, BOOL init) +{ + IConnectionPointContainer *container; + IConnectionPoint *point; + HRESULT hres; + + static DWORD dw = 100; + + hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container); + ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IConnectionPointContainer_FindConnectionPoint(container, &DIID_DWebBrowserEvents2, &point); + IConnectionPointContainer_Release(container); + ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres); + if(FAILED(hres)) + return; + + if(init) { + hres = IConnectionPoint_Advise(point, (IUnknown*)&WebBrowserEvents2, &dw); + ok(hres == S_OK, "Advise failed: %08x\n", hres); + ok(dw == 1, "dw=%d, expected 1\n", dw); + }else { + hres = IConnectionPoint_Unadvise(point, dw); + ok(hres == S_OK, "Unadvise failed: %08x\n", hres); + } + + IConnectionPoint_Release(point); +} + +static void test_Navigate2(IUnknown *unk) +{ + IWebBrowser2 *webbrowser; + VARIANT url; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&webbrowser); + ok(hres == S_OK, "QueryInterface(IID_IWebBrowser) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + test_LocationURL(unk, emptyW); + + V_VT(&url) = VT_BSTR; + V_BSTR(&url) = SysAllocString(about_blankW); + + SET_EXPECT(Invoke_AMBIENT_USERMODE); + SET_EXPECT(Invoke_PROPERTYCHANGE); + SET_EXPECT(Invoke_BEFORENAVIGATE2); + SET_EXPECT(Invoke_DOWNLOADBEGIN); + SET_EXPECT(Exec_SETDOWNLOADSTATE_1); + SET_EXPECT(EnableModeless_FALSE); + SET_EXPECT(Invoke_STATUSTEXTCHANGE); + SET_EXPECT(SetStatusText); + SET_EXPECT(GetHostInfo); + SET_EXPECT(Invoke_AMBIENT_DLCONTROL); + SET_EXPECT(Invoke_AMBIENT_USERAGENT); + SET_EXPECT(Invoke_AMBIENT_PALETTE); + SET_EXPECT(GetOptionKeyPath); + SET_EXPECT(GetOverridesKeyPath); + SET_EXPECT(QueryStatus_SETPROGRESSTEXT); + SET_EXPECT(Exec_SETPROGRESSMAX); + SET_EXPECT(Exec_SETPROGRESSPOS); + SET_EXPECT(Invoke_SETSECURELOCKICON); + SET_EXPECT(Invoke_FILEDOWNLOAD); + SET_EXPECT(Exec_SETDOWNLOADSTATE_0); + SET_EXPECT(Invoke_COMMANDSTATECHANGE); + SET_EXPECT(EnableModeless_TRUE); + + hres = IWebBrowser2_Navigate2(webbrowser, &url, NULL, NULL, NULL, NULL); + ok(hres == S_OK, "Navigate2 failed: %08x\n", hres); + + CHECK_CALLED(Invoke_AMBIENT_USERMODE); + todo_wine CHECK_CALLED(Invoke_PROPERTYCHANGE); + CHECK_CALLED(Invoke_BEFORENAVIGATE2); + todo_wine CHECK_CALLED(Invoke_DOWNLOADBEGIN); + todo_wine CHECK_CALLED(Exec_SETDOWNLOADSTATE_1); + CHECK_CALLED(EnableModeless_FALSE); + CHECK_CALLED(Invoke_STATUSTEXTCHANGE); + CHECK_CALLED(SetStatusText); + CHECK_CALLED(GetHostInfo); + CHECK_CALLED(Invoke_AMBIENT_DLCONTROL); + CHECK_CALLED(Invoke_AMBIENT_USERAGENT); + CHECK_CALLED(Invoke_AMBIENT_PALETTE); + CHECK_CALLED(GetOptionKeyPath); + CHECK_CALLED_BROKEN(GetOverridesKeyPath); + todo_wine CHECK_CALLED(QueryStatus_SETPROGRESSTEXT); + todo_wine CHECK_CALLED(Exec_SETPROGRESSMAX); + todo_wine CHECK_CALLED(Exec_SETPROGRESSPOS); + todo_wine CHECK_CALLED_BROKEN(Invoke_SETSECURELOCKICON); + todo_wine CHECK_CALLED_BROKEN(Invoke_FILEDOWNLOAD); + todo_wine CHECK_CALLED(Invoke_COMMANDSTATECHANGE); + todo_wine CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); + CHECK_CALLED(EnableModeless_TRUE); + + VariantClear(&url); + IWebBrowser2_Release(webbrowser); +} + +static void test_download(void) +{ + MSG msg; + + is_downloading = TRUE; + + SET_EXPECT(Exec_SETPROGRESSMAX); + SET_EXPECT(Exec_SETPROGRESSPOS); + SET_EXPECT(Exec_SETDOWNLOADSTATE_1); + SET_EXPECT(DocHost_EnableModeless_FALSE); + SET_EXPECT(DocHost_EnableModeless_TRUE); + SET_EXPECT(Invoke_SETSECURELOCKICON); + SET_EXPECT(Invoke_282); + SET_EXPECT(EnableModeless_FALSE); + SET_EXPECT(Invoke_COMMANDSTATECHANGE); + SET_EXPECT(Invoke_STATUSTEXTCHANGE); + SET_EXPECT(SetStatusText); + SET_EXPECT(EnableModeless_TRUE); + SET_EXPECT(QueryStatus_STOP); + SET_EXPECT(Exec_SETDOWNLOADSTATE_0); + SET_EXPECT(Invoke_TITLECHANGE); + SET_EXPECT(Invoke_NAVIGATECOMPLETE2); + SET_EXPECT(GetDropTarget); + SET_EXPECT(Invoke_PROGRESSCHANGE); + SET_EXPECT(Invoke_DOCUMENTCOMPLETE); + + while(!called_Invoke_DOCUMENTCOMPLETE && GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + todo_wine CHECK_CALLED(Exec_SETPROGRESSMAX); + todo_wine CHECK_CALLED(Exec_SETPROGRESSPOS); + todo_wine CHECK_CALLED(Exec_SETDOWNLOADSTATE_1); + CLEAR_CALLED(DocHost_EnableModeless_FALSE); /* IE 7 */ + CLEAR_CALLED(DocHost_EnableModeless_TRUE); /* IE 7 */ + todo_wine CHECK_CALLED(Invoke_SETSECURELOCKICON); + CLEAR_CALLED(Invoke_282); /* IE 7 */ + todo_wine CHECK_CALLED(EnableModeless_FALSE); + todo_wine CHECK_CALLED(Invoke_COMMANDSTATECHANGE); + todo_wine CHECK_CALLED(Invoke_STATUSTEXTCHANGE); + todo_wine CHECK_CALLED(SetStatusText); + todo_wine CHECK_CALLED(EnableModeless_TRUE); + todo_wine CHECK_CALLED(QueryStatus_STOP); + todo_wine CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); + todo_wine CHECK_CALLED(Invoke_TITLECHANGE); + CHECK_CALLED(Invoke_NAVIGATECOMPLETE2); + todo_wine CHECK_CALLED(GetDropTarget); + todo_wine CHECK_CALLED(Invoke_PROGRESSCHANGE); + CHECK_CALLED(Invoke_DOCUMENTCOMPLETE); +} + +static void test_olecmd(IUnknown *unk, BOOL loaded) +{ + IOleCommandTarget *cmdtrg; + OLECMD cmds[3]; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IOleCommandTarget, (void**)&cmdtrg); + ok(hres == S_OK, "Could not get IOleCommandTarget iface: %08x\n", hres); + if(FAILED(hres)) + return; + + cmds[0].cmdID = OLECMDID_SPELL; + cmds[0].cmdf = 0xdeadbeef; + cmds[1].cmdID = OLECMDID_REFRESH; + cmds[1].cmdf = 0xdeadbeef; + hres = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 2, cmds, NULL); + if(loaded) { + ok(hres == S_OK, "QueryStatus failed: %08x\n", hres); + ok(cmds[0].cmdf == OLECMDF_SUPPORTED, "OLECMDID_SPELL cmdf = %x\n", cmds[0].cmdf); + ok(cmds[1].cmdf == (OLECMDF_ENABLED|OLECMDF_SUPPORTED), + "OLECMDID_REFRESH cmdf = %x\n", cmds[1].cmdf); + }else { + ok(hres == 0x80040104, "QueryStatus failed: %08x\n", hres); + ok(cmds[0].cmdf == 0xdeadbeef, "OLECMDID_SPELL cmdf = %x\n", cmds[0].cmdf); + ok(cmds[1].cmdf == 0xdeadbeef, "OLECMDID_REFRESH cmdf = %x\n", cmds[0].cmdf); + } + + IOleCommandTarget_Release(cmdtrg); +} + +static void test_IServiceProvider(IUnknown *unk) +{ + IServiceProvider *servprov = (void*)0xdeadbeef; + HRESULT hres; + IUnknown *ret = NULL; + static const IID IID_IBrowserService2 = + {0x68BD21CC,0x438B,0x11d2,{0xA5,0x60,0x00,0xA0,0xC,0x2D,0xBF,0xE8}}; + + hres = IUnknown_QueryInterface(unk, &IID_IServiceProvider, (void**)&servprov); + ok(hres == S_OK, "QueryInterface returned %08x, expected S_OK\n", hres); + if(FAILED(hres)) + return; + + hres = IServiceProvider_QueryService(servprov, &SID_STopLevelBrowser, &IID_IBrowserService2, (LPVOID*)&ret); + ok(hres == E_FAIL, "QueryService returned %08x, expected E_FAIL\n", hres); + ok(ret == NULL, "ret returned %p, expected NULL\n", ret); + if(hres == S_OK) + { + IUnknown_Release(ret); + } + + IServiceProvider_Release(servprov); +} + +static void test_QueryInterface(IUnknown *unk) +{ + IQuickActivate *qa = (IQuickActivate*)0xdeadbeef; + IRunnableObject *runnable = (IRunnableObject*)0xdeadbeef; + IPerPropertyBrowsing *propbrowse = (void*)0xdeadbeef; + IOleInPlaceSite *inplace = (void*)0xdeadbeef; + IOleCache *cache = (void*)0xdeadbeef; + IObjectWithSite *site = (void*)0xdeadbeef; + IViewObjectEx *viewex = (void*)0xdeadbeef; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IQuickActivate, (void**)&qa); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(qa == NULL, "qa=%p, expected NULL\n", qa); + + hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&runnable); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(runnable == NULL, "runnable=%p, expected NULL\n", runnable); + + hres = IUnknown_QueryInterface(unk, &IID_IPerPropertyBrowsing, (void**)&propbrowse); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(propbrowse == NULL, "propbrowse=%p, expected NULL\n", propbrowse); + + hres = IUnknown_QueryInterface(unk, &IID_IOleCache, (void**)&cache); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(cache == NULL, "cache=%p, expected NULL\n", cache); + + hres = IUnknown_QueryInterface(unk, &IID_IOleInPlaceSite, (void**)&inplace); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(inplace == NULL, "inplace=%p, expected NULL\n", inplace); + + hres = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void**)&site); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(site == NULL, "site=%p, expected NULL\n", site); + + hres = IUnknown_QueryInterface(unk, &IID_IViewObjectEx, (void**)&viewex); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(viewex == NULL, "viewex=%p, expected NULL\n", viewex); + +} + +static void test_WebBrowser(BOOL do_download) +{ + IUnknown *unk = NULL; + ULONG ref; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_WebBrowser, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "CoCreateInterface failed: %08x\n", hres); + if(FAILED(hres)) + return; + + is_downloading = FALSE; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&wb); + ok(hres == S_OK, "Could not get IWebBrowser2 iface: %08x\n", hres); + + test_QueryInterface(unk); + test_ClassInfo(unk); + test_LocationURL(unk, emptyW); + test_ConnectionPoint(unk, TRUE); + test_ClientSite(unk, &ClientSite); + test_Extent(unk); + test_wb_funcs(unk, TRUE); + test_DoVerb(unk); + test_olecmd(unk, FALSE); + test_Navigate2(unk); + + if(do_download) { + test_download(); + test_olecmd(unk, TRUE); + } + + test_ClientSite(unk, NULL); + test_ie_funcs(unk); + test_GetControlInfo(unk); + test_wb_funcs(unk, FALSE); + test_ConnectionPoint(unk, FALSE); + test_IServiceProvider(unk); + + IWebBrowser2_Release(wb); + ref = IUnknown_Release(unk); + ok(ref == 0, "ref=%d, expected 0\n", ref); +} + +static void gecko_installer_workaround(BOOL disable) +{ + HKEY hkey; + DWORD res; + + static BOOL has_url = FALSE; + static char url[2048]; + + if(!disable && !has_url) + return; + + res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey); + if(res != ERROR_SUCCESS) + return; + + if(disable) { + DWORD type, size = sizeof(url); + + res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size); + if(res == ERROR_SUCCESS && type == REG_SZ) + has_url = TRUE; + + RegDeleteValue(hkey, "GeckoUrl"); + }else { + RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1); + } + + RegCloseKey(hkey); +} + +START_TEST(webbrowser) +{ + gecko_installer_workaround(TRUE); + + container_hwnd = create_container_window(); + + OleInitialize(NULL); + + trace("Testing WebBrowser (no download)...\n"); + test_WebBrowser(FALSE); + trace("Testing WebBrowser...\n"); + test_WebBrowser(TRUE); + + OleUninitialize(); + + gecko_installer_workaround(FALSE); +} diff --git a/rostests/winetests/shell32/appbar.c b/rostests/winetests/shell32/appbar.c new file mode 100644 index 00000000000..5e5dfafbd22 --- /dev/null +++ b/rostests/winetests/shell32/appbar.c @@ -0,0 +1,444 @@ +/* Unit tests for appbars + * + * Copyright 2008 Vincent Povirk for CodeWeavers + * + * 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 + */ + +#include +#include + +#include + +#include "wine/test.h" + +#define MSG_APPBAR WM_APP + +static const CHAR testwindow_class[] = "testwindow"; + +static HMONITOR (WINAPI *pMonitorFromWindow)(HWND, DWORD); + +typedef BOOL (*boolean_function)(void); + +struct testwindow_info +{ + HWND hwnd; + BOOL registered; + BOOL to_be_deleted; + RECT desired_rect; + UINT edge; + RECT allocated_rect; +}; + +static struct testwindow_info windows[3]; + +static int expected_bottom; + +static void testwindow_setpos(HWND hwnd) +{ + struct testwindow_info* info = (struct testwindow_info*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + APPBARDATA abd; + BOOL ret; + + ok(info != NULL, "got unexpected ABN_POSCHANGED notification\n"); + + if (!info || !info->registered) + { + return; + } + + if (info->to_be_deleted) + { + win_skip("Some Win95 and NT4 systems send messages to removed taskbars\n"); + return; + } + + abd.cbSize = sizeof(abd); + abd.hWnd = hwnd; + abd.uEdge = info->edge; + abd.rc = info->desired_rect; + ret = SHAppBarMessage(ABM_QUERYPOS, &abd); + ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret); + switch (info->edge) + { + case ABE_BOTTOM: + ok(info->desired_rect.top == abd.rc.top, "ABM_QUERYPOS changed top of rect from %i to %i\n", info->desired_rect.top, abd.rc.top); + abd.rc.top = abd.rc.bottom - (info->desired_rect.bottom - info->desired_rect.top); + break; + case ABE_LEFT: + ok(info->desired_rect.right == abd.rc.right, "ABM_QUERYPOS changed right of rect from %i to %i\n", info->desired_rect.right, abd.rc.right); + abd.rc.right = abd.rc.left + (info->desired_rect.right - info->desired_rect.left); + break; + case ABE_RIGHT: + ok(info->desired_rect.left == abd.rc.left, "ABM_QUERYPOS changed left of rect from %i to %i\n", info->desired_rect.left, abd.rc.left); + abd.rc.left = abd.rc.right - (info->desired_rect.right - info->desired_rect.left); + break; + case ABE_TOP: + ok(info->desired_rect.bottom == abd.rc.bottom, "ABM_QUERYPOS changed bottom of rect from %i to %i\n", info->desired_rect.bottom, abd.rc.bottom); + abd.rc.bottom = abd.rc.top + (info->desired_rect.bottom - info->desired_rect.top); + break; + } + + ret = SHAppBarMessage(ABM_SETPOS, &abd); + ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret); + + info->allocated_rect = abd.rc; + MoveWindow(hwnd, abd.rc.left, abd.rc.top, abd.rc.right-abd.rc.left, abd.rc.bottom-abd.rc.top, TRUE); +} + +static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch(msg) + { + case MSG_APPBAR: + { + switch(wparam) + { + case ABN_POSCHANGED: + testwindow_setpos(hwnd); + break; + } + return 0; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +/* process pending messages until a condition is true or 3 seconds pass */ +static void do_events_until(boolean_function test) +{ + MSG msg; + UINT_PTR timerid; + BOOL timedout=FALSE; + + timerid = SetTimer(0, 0, 3000, NULL); + + while (1) + { + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.hwnd == 0 && msg.message == WM_TIMER && msg.wParam == timerid) + timedout = TRUE; + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + if (timedout || test()) + break; + WaitMessage(); + } + + KillTimer(0, timerid); +} + +/* process any pending messages */ +static void do_events(void) +{ + MSG msg; + + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } +} + +static BOOL no_appbars_intersect(void) +{ + int i, j; + RECT rc; + + for (i=0; i<2; i++) + { + for (j=i+1; j<3; j++) + { + if (windows[i].registered && windows[j].registered && + IntersectRect(&rc, &windows[i].allocated_rect, &windows[j].allocated_rect)) + return FALSE; + } + } + return TRUE; +} + +static BOOL got_expected_bottom(void) +{ + return (no_appbars_intersect() && windows[1].allocated_rect.bottom == expected_bottom); +} + +static void register_testwindow_class(void) +{ + WNDCLASSEXA cls; + + ZeroMemory(&cls, sizeof(cls)); + cls.cbSize = sizeof(cls); + cls.style = 0; + cls.lpfnWndProc = testwindow_wndproc; + cls.hInstance = NULL; + cls.hCursor = LoadCursor(0, IDC_ARROW); + cls.hbrBackground = (HBRUSH) COLOR_WINDOW; + cls.lpszClassName = testwindow_class; + + RegisterClassExA(&cls); +} + +#define test_window_rects(a, b) \ + ok(!IntersectRect(&rc, &windows[a].allocated_rect, &windows[b].allocated_rect), \ + "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n", \ + windows[a].allocated_rect.left, windows[a].allocated_rect.top, windows[a].allocated_rect.right, windows[a].allocated_rect.bottom, \ + windows[b].allocated_rect.left, windows[b].allocated_rect.top, windows[b].allocated_rect.right, windows[b].allocated_rect.bottom) + +static void test_setpos(void) +{ + APPBARDATA abd; + RECT rc; + int screen_width, screen_height; + BOOL ret; + int org_bottom1; + + screen_width = GetSystemMetrics(SM_CXSCREEN); + screen_height = GetSystemMetrics(SM_CYSCREEN); + + /* create and register windows[0] */ + windows[0].hwnd = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, + testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, + NULL, NULL, NULL, NULL); + ok(windows[0].hwnd != NULL, "couldn't create window\n"); + do_events(); + abd.cbSize = sizeof(abd); + abd.hWnd = windows[0].hwnd; + abd.uCallbackMessage = MSG_APPBAR; + ret = SHAppBarMessage(ABM_NEW, &abd); + ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret); + + /* ABM_NEW should return FALSE if the window is already registered */ + ret = SHAppBarMessage(ABM_NEW, &abd); + ok(ret == FALSE, "SHAppBarMessage returned %i\n", ret); + do_events(); + + /* dock windows[0] to the bottom of the screen */ + windows[0].registered = TRUE; + windows[0].to_be_deleted = FALSE; + windows[0].edge = ABE_BOTTOM; + windows[0].desired_rect.left = 0; + windows[0].desired_rect.right = screen_width; + windows[0].desired_rect.top = screen_height - 15; + windows[0].desired_rect.bottom = screen_height; + SetWindowLongPtr(windows[0].hwnd, GWLP_USERDATA, (LONG_PTR)&windows[0]); + testwindow_setpos(windows[0].hwnd); + do_events(); + + /* create and register windows[1] */ + windows[1].hwnd = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, + testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, + NULL, NULL, NULL, NULL); + ok(windows[1].hwnd != NULL, "couldn't create window\n"); + abd.hWnd = windows[1].hwnd; + ret = SHAppBarMessage(ABM_NEW, &abd); + ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret); + + /* dock windows[1] to the bottom of the screen */ + windows[1].registered = TRUE; + windows[1].to_be_deleted = FALSE; + windows[1].edge = ABE_BOTTOM; + windows[1].desired_rect.left = 0; + windows[1].desired_rect.right = screen_width; + windows[1].desired_rect.top = screen_height - 10; + windows[1].desired_rect.bottom = screen_height; + SetWindowLongPtr(windows[1].hwnd, GWLP_USERDATA, (LONG_PTR)&windows[1]); + testwindow_setpos(windows[1].hwnd); + + /* the windows are adjusted to they don't overlap */ + do_events_until(no_appbars_intersect); + test_window_rects(0, 1); + + /* make windows[0] larger, forcing windows[1] to move out of its way */ + windows[0].desired_rect.top = screen_height - 20; + testwindow_setpos(windows[0].hwnd); + do_events_until(no_appbars_intersect); + test_window_rects(0, 1); + + /* create and register windows[2] */ + windows[2].hwnd = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, + testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, + NULL, NULL, NULL, NULL); + ok(windows[2].hwnd != NULL, "couldn't create window\n"); + do_events(); + + abd.hWnd = windows[2].hwnd; + ret = SHAppBarMessage(ABM_NEW, &abd); + ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret); + + /* dock windows[2] to the bottom of the screen */ + windows[2].registered = TRUE; + windows[2].to_be_deleted = FALSE; + windows[2].edge = ABE_BOTTOM; + windows[2].desired_rect.left = 0; + windows[2].desired_rect.right = screen_width; + windows[2].desired_rect.top = screen_height - 10; + windows[2].desired_rect.bottom = screen_height; + SetWindowLongPtr(windows[2].hwnd, GWLP_USERDATA, (LONG_PTR)&windows[2]); + testwindow_setpos(windows[2].hwnd); + + do_events_until(no_appbars_intersect); + test_window_rects(0, 1); + test_window_rects(0, 2); + test_window_rects(1, 2); + + /* move windows[2] to the right side of the screen */ + windows[2].edge = ABE_RIGHT; + windows[2].desired_rect.left = screen_width - 15; + windows[2].desired_rect.right = screen_width; + windows[2].desired_rect.top = 0; + windows[2].desired_rect.bottom = screen_height; + testwindow_setpos(windows[2].hwnd); + + do_events_until(no_appbars_intersect); + test_window_rects(0, 1); + test_window_rects(0, 2); + test_window_rects(1, 2); + + /* move windows[1] to the top of the screen */ + windows[1].edge = ABE_TOP; + windows[1].desired_rect.left = 0; + windows[1].desired_rect.right = screen_width; + windows[1].desired_rect.top = 0; + windows[1].desired_rect.bottom = 15; + testwindow_setpos(windows[1].hwnd); + + do_events_until(no_appbars_intersect); + test_window_rects(0, 1); + test_window_rects(0, 2); + test_window_rects(1, 2); + + /* move windows[1] back to the bottom of the screen */ + windows[1].edge = ABE_BOTTOM; + windows[1].desired_rect.left = 0; + windows[1].desired_rect.right = screen_width; + windows[1].desired_rect.top = screen_height - 10; + windows[1].desired_rect.bottom = screen_height; + testwindow_setpos(windows[1].hwnd); + + do_events_until(no_appbars_intersect); + test_window_rects(0, 1); + test_window_rects(0, 2); + test_window_rects(1, 2); + + /* removing windows[0] will cause windows[1] to move down into its space */ + expected_bottom = max(windows[0].allocated_rect.bottom, windows[1].allocated_rect.bottom); + org_bottom1 = windows[1].allocated_rect.bottom; + ok(windows[0].allocated_rect.bottom > windows[1].allocated_rect.bottom, + "Expected windows[0] to be lower than windows[1]\n"); + + abd.hWnd = windows[0].hwnd; + windows[0].to_be_deleted = TRUE; + ret = SHAppBarMessage(ABM_REMOVE, &abd); + ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret); + windows[0].registered = FALSE; + DestroyWindow(windows[0].hwnd); + + do_events_until(got_expected_bottom); + + if (windows[1].allocated_rect.bottom == org_bottom1) + win_skip("Some broken Vista boxes don't move the higher appbar down\n"); + else + ok(windows[1].allocated_rect.bottom == expected_bottom, + "windows[1]'s bottom is %i, expected %i\n", + windows[1].allocated_rect.bottom, expected_bottom); + + test_window_rects(1, 2); + + /* remove the other windows */ + abd.hWnd = windows[1].hwnd; + windows[1].to_be_deleted = TRUE; + ret = SHAppBarMessage(ABM_REMOVE, &abd); + ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret); + windows[1].registered = FALSE; + DestroyWindow(windows[1].hwnd); + + abd.hWnd = windows[2].hwnd; + windows[2].to_be_deleted = TRUE; + ret = SHAppBarMessage(ABM_REMOVE, &abd); + ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret); + windows[2].registered = FALSE; + DestroyWindow(windows[2].hwnd); +} + +static void test_appbarget(void) +{ + APPBARDATA abd; + HWND hwnd, foregnd, unset_hwnd; + UINT_PTR ret; + + memset(&abd, 0xcc, sizeof(abd)); + memset(&unset_hwnd, 0xcc, sizeof(unset_hwnd)); + abd.cbSize = sizeof(abd); + abd.uEdge = ABE_BOTTOM; + + hwnd = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); + ok(hwnd == NULL || IsWindow(hwnd), "ret %p which is not a window\n", hwnd); + ok(abd.hWnd == unset_hwnd, "hWnd overwritten %p\n",abd.hWnd); + + if (!pMonitorFromWindow) + { + win_skip("MonitorFromWindow is not available\n"); + } + else + { + /* Presumably one can pass a hwnd with ABM_GETAUTOHIDEBAR to specify a monitor. + Pass the foreground window and check */ + foregnd = GetForegroundWindow(); + if(foregnd) + { + abd.hWnd = foregnd; + hwnd = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); + ok(hwnd == NULL || IsWindow(hwnd), "ret %p which is not a window\n", hwnd); + ok(abd.hWnd == foregnd, "hWnd overwritten\n"); + if(hwnd) + { + HMONITOR appbar_mon, foregnd_mon; + appbar_mon = pMonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + foregnd_mon = pMonitorFromWindow(foregnd, MONITOR_DEFAULTTONEAREST); + ok(appbar_mon == foregnd_mon, "Windows on different monitors\n"); + } + } + } + + memset(&abd, 0xcc, sizeof(abd)); + abd.cbSize = sizeof(abd); + ret = SHAppBarMessage(ABM_GETTASKBARPOS, &abd); + if(ret) + { + ok(abd.hWnd == (HWND)0xcccccccc, "hWnd overwritten\n"); + ok(abd.uEdge <= ABE_BOTTOM || + broken(abd.uEdge == 0xcccccccc), /* Some Win95 and NT4 */ + "uEdge not returned\n"); + ok(abd.rc.left != 0xcccccccc, "rc not updated\n"); + } + + return; +} + +START_TEST(appbar) +{ + HMODULE huser32; + + huser32 = GetModuleHandleA("user32.dll"); + pMonitorFromWindow = (void*)GetProcAddress(huser32, "MonitorFromWindow"); + + register_testwindow_class(); + + test_setpos(); + test_appbarget(); +} diff --git a/rostests/winetests/shell32/autocomplete.c b/rostests/winetests/shell32/autocomplete.c new file mode 100644 index 00000000000..20315c749ea --- /dev/null +++ b/rostests/winetests/shell32/autocomplete.c @@ -0,0 +1,136 @@ +/* + * Tests for autocomplete + * + * Copyright 2008 Jan de Mooij + * + * 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 + */ + +#define COBJMACROS + +#include +#include + +#include "windows.h" +#include "shobjidl.h" +#include "shlguid.h" +#include "initguid.h" +#include "shldisp.h" + +static HWND hMainWnd, hEdit; +static HINSTANCE hinst; +static int killfocus_count; + +static BOOL test_init(void) { + HRESULT r; + IAutoComplete* ac; + IUnknown *acSource; + + /* AutoComplete instance */ + r = CoCreateInstance(&CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, + &IID_IAutoComplete, (LPVOID*)&ac); + if (r == REGDB_E_CLASSNOTREG) + { + win_skip("CLSID_AutoComplete is not registered\n"); + return FALSE; + } + ok(SUCCEEDED(r), "no IID_IAutoComplete (0x%08x)\n", r); + + /* AutoComplete source */ + r = CoCreateInstance(&CLSID_ACLMulti, NULL, CLSCTX_INPROC_SERVER, + &IID_IACList, (LPVOID*)&acSource); + if (r == REGDB_E_CLASSNOTREG) + { + win_skip("CLSID_ACLMulti is not registered\n"); + return FALSE; + } + ok(SUCCEEDED(r), "no IID_IACList (0x%08x)\n", r); + + /* bind to edit control */ + r = IAutoComplete_Init(ac, hEdit, acSource, NULL, NULL); + ok(SUCCEEDED(r), "Init failed (0x%08x)\n", r); + + return TRUE; +} +static void test_killfocus(void) { + /* Test if WM_KILLFOCUS messages are handled properly by checking if + * the parent receives an EN_KILLFOCUS message. */ + SetFocus(hEdit); + killfocus_count = 0; + SetFocus(0); + ok(killfocus_count == 1, "Expected one EN_KILLFOCUS message, got: %d\n", killfocus_count); +} +static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + switch(msg) { + case WM_CREATE: + /* create edit control */ + hEdit = CreateWindowEx(0, "EDIT", "Some text", 0, 10, 10, 300, 300, + hWnd, NULL, hinst, NULL); + ok(hEdit != NULL, "Can't create edit control\n"); + break; + case WM_COMMAND: + if(HIWORD(wParam) == EN_KILLFOCUS) + killfocus_count++; + break; + } + return DefWindowProcA(hWnd, msg, wParam, lParam); +} +static void createMainWnd(void) { + WNDCLASSA wc; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandleA(NULL); + wc.hIcon = NULL; + wc.hCursor = LoadCursorA(NULL, IDC_IBEAM); + wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); + wc.lpszMenuName = NULL; + wc.lpszClassName = "MyTestWnd"; + wc.lpfnWndProc = MyWndProc; + RegisterClassA(&wc); + + hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0); +} +START_TEST(autocomplete) { + HRESULT r; + MSG msg; + + r = CoInitialize(NULL); + ok(SUCCEEDED(r), "CoInitialize failed (0x%08x). Tests aborted.\n", r); + if (FAILED(r)) + return; + + createMainWnd(); + + if(!ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n")) + return; + + if (!test_init()) + goto cleanup; + test_killfocus(); + + PostQuitMessage(0); + while(GetMessageA(&msg,0,0,0)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + +cleanup: + DestroyWindow(hEdit); + DestroyWindow(hMainWnd); + + CoUninitialize(); +} diff --git a/rostests/winetests/shell32/generated.c b/rostests/winetests/shell32/generated.c index 7e8d2811cd6..4410131dd68 100755 --- a/rostests/winetests/shell32/generated.c +++ b/rostests/winetests/shell32/generated.c @@ -1,4 +1,4 @@ -/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* File generated automatically from tools/winapi/tests.dat; do not edit! */ /* This file can be copied, modified and distributed without restriction. */ /* @@ -34,22 +34,14 @@ * Windows API extension */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) -# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) -#elif defined(__GNUC__) -# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) -#else -/* FIXME: Not sure if is possible to do without compiler extension */ -#endif - #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) #elif defined(__GNUC__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* - * FIXME: Not sure if is possible to do without compiler extension - * (if type is not just a name that is, if so the normal) + * FIXME: May not be possible without a compiler extension + * (if type is not just a name that is, otherwise the normal * TYPE_ALIGNMENT can be used) */ #endif @@ -66,1179 +58,1818 @@ * Test helper macros */ -#ifdef FIELD_ALIGNMENT -# define TEST_FIELD_ALIGNMENT(type, field, align) \ - ok(FIELD_ALIGNMENT(type, field) == align, \ - "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ - (int)FIELD_ALIGNMENT(type, field)) +#ifdef _WIN64 + +# define TEST_TYPE_SIZE(type, size) +# define TEST_TYPE_ALIGN(type, align) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) +# define TEST_FIELD_OFFSET(type, field, offset) + #else -# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) + +# define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); + +# ifdef TYPE_ALIGNMENT +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +#else +# define TEST_TYPE_ALIGN(type, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) \ - ok(FIELD_OFFSET(type, field) == offset, \ - "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ - (long int)FIELD_OFFSET(type, field)) - -#ifdef _TYPE_ALIGNMENT -#define TEST__TYPE_ALIGNMENT(type, align) \ - ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +# ifdef _TYPE_ALIGNMENT +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else -# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) #endif -#ifdef TYPE_ALIGNMENT -#define TEST_TYPE_ALIGNMENT(type, align) \ - ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) -#else -# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); + #endif -#define TEST_TYPE_SIZE(type, size) \ - ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) +#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) +#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) +#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0); +#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0); -/*********************************************************************** - * Test macros - */ - -#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ - TEST_TYPE_SIZE(field_type, field_size); \ - TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ - TEST_FIELD_OFFSET(type, field_name, field_offset); \ - -#define TEST_TYPE(type, size, align) \ - TEST_TYPE_ALIGNMENT(type, align); \ - TEST_TYPE_SIZE(type, size) - -#define TEST_TYPE_POINTER(type, size, align) \ - TEST__TYPE_ALIGNMENT(*(type)0, align); \ - TEST_TYPE_SIZE(*(type)0, size) - -#define TEST_TYPE_SIGNED(type) \ - ok((type) -1 < 0, "(" #type ") -1 < 0\n"); - -#define TEST_TYPE_UNSIGNED(type) \ - ok((type) -1 > 0, "(" #type ") -1 > 0\n"); static void test_pack_BLOB(void) { /* BLOB (pack 4) */ - TEST_TYPE(BLOB, 8, 4); - TEST_FIELD(BLOB, ULONG, cbSize, 0, 4, 4); - TEST_FIELD(BLOB, BYTE *, pBlobData, 4, 4, 4); + TEST_TYPE_SIZE (BLOB, 8) + TEST_TYPE_ALIGN (BLOB, 4) + TEST_FIELD_SIZE (BLOB, cbSize, 4) + TEST_FIELD_ALIGN (BLOB, cbSize, 4) + TEST_FIELD_OFFSET(BLOB, cbSize, 0) + TEST_FIELD_SIZE (BLOB, pBlobData, 4) + TEST_FIELD_ALIGN (BLOB, pBlobData, 4) + TEST_FIELD_OFFSET(BLOB, pBlobData, 4) } static void test_pack_BSTR(void) { /* BSTR */ - TEST_TYPE(BSTR, 4, 4); - TEST_TYPE_POINTER(BSTR, 2, 2); + TEST_TYPE_SIZE (BSTR, 4) + TEST_TYPE_ALIGN (BSTR, 4) + TEST_TARGET_SIZE (BSTR, 2) + TEST_TARGET_ALIGN(BSTR, 2) } static void test_pack_BSTRBLOB(void) { /* BSTRBLOB (pack 4) */ - TEST_TYPE(BSTRBLOB, 8, 4); - TEST_FIELD(BSTRBLOB, ULONG, cbSize, 0, 4, 4); - TEST_FIELD(BSTRBLOB, BYTE *, pData, 4, 4, 4); + TEST_TYPE_SIZE (BSTRBLOB, 8) + TEST_TYPE_ALIGN (BSTRBLOB, 4) + TEST_FIELD_SIZE (BSTRBLOB, cbSize, 4) + TEST_FIELD_ALIGN (BSTRBLOB, cbSize, 4) + TEST_FIELD_OFFSET(BSTRBLOB, cbSize, 0) + TEST_FIELD_SIZE (BSTRBLOB, pData, 4) + TEST_FIELD_ALIGN (BSTRBLOB, pData, 4) + TEST_FIELD_OFFSET(BSTRBLOB, pData, 4) } static void test_pack_BYTE_BLOB(void) { /* BYTE_BLOB (pack 4) */ - TEST_TYPE(BYTE_BLOB, 8, 4); - TEST_FIELD(BYTE_BLOB, unsigned long, clSize, 0, 4, 4); - TEST_FIELD(BYTE_BLOB, byte[1], abData, 4, 1, 1); + TEST_TYPE_SIZE (BYTE_BLOB, 8) + TEST_TYPE_ALIGN (BYTE_BLOB, 4) + TEST_FIELD_SIZE (BYTE_BLOB, clSize, 4) + TEST_FIELD_ALIGN (BYTE_BLOB, clSize, 4) + TEST_FIELD_OFFSET(BYTE_BLOB, clSize, 0) + TEST_FIELD_SIZE (BYTE_BLOB, abData, 1) + TEST_FIELD_ALIGN (BYTE_BLOB, abData, 1) + TEST_FIELD_OFFSET(BYTE_BLOB, abData, 4) } static void test_pack_BYTE_SIZEDARR(void) { /* BYTE_SIZEDARR (pack 4) */ - TEST_TYPE(BYTE_SIZEDARR, 8, 4); - TEST_FIELD(BYTE_SIZEDARR, unsigned long, clSize, 0, 4, 4); - TEST_FIELD(BYTE_SIZEDARR, byte *, pData, 4, 4, 4); + TEST_TYPE_SIZE (BYTE_SIZEDARR, 8) + TEST_TYPE_ALIGN (BYTE_SIZEDARR, 4) + TEST_FIELD_SIZE (BYTE_SIZEDARR, clSize, 4) + TEST_FIELD_ALIGN (BYTE_SIZEDARR, clSize, 4) + TEST_FIELD_OFFSET(BYTE_SIZEDARR, clSize, 0) + TEST_FIELD_SIZE (BYTE_SIZEDARR, pData, 4) + TEST_FIELD_ALIGN (BYTE_SIZEDARR, pData, 4) + TEST_FIELD_OFFSET(BYTE_SIZEDARR, pData, 4) } static void test_pack_CLIPDATA(void) { /* CLIPDATA (pack 4) */ - TEST_TYPE(CLIPDATA, 12, 4); - TEST_FIELD(CLIPDATA, ULONG, cbSize, 0, 4, 4); - TEST_FIELD(CLIPDATA, long, ulClipFmt, 4, 4, 4); - TEST_FIELD(CLIPDATA, BYTE *, pClipData, 8, 4, 4); + TEST_TYPE_SIZE (CLIPDATA, 12) + TEST_TYPE_ALIGN (CLIPDATA, 4) + TEST_FIELD_SIZE (CLIPDATA, cbSize, 4) + TEST_FIELD_ALIGN (CLIPDATA, cbSize, 4) + TEST_FIELD_OFFSET(CLIPDATA, cbSize, 0) + TEST_FIELD_SIZE (CLIPDATA, ulClipFmt, 4) + TEST_FIELD_ALIGN (CLIPDATA, ulClipFmt, 4) + TEST_FIELD_OFFSET(CLIPDATA, ulClipFmt, 4) + TEST_FIELD_SIZE (CLIPDATA, pClipData, 4) + TEST_FIELD_ALIGN (CLIPDATA, pClipData, 4) + TEST_FIELD_OFFSET(CLIPDATA, pClipData, 8) } static void test_pack_CLIPFORMAT(void) { /* CLIPFORMAT */ - TEST_TYPE(CLIPFORMAT, 2, 2); - TEST_TYPE_UNSIGNED(CLIPFORMAT); + TEST_TYPE_SIZE (CLIPFORMAT, 2) + TEST_TYPE_ALIGN (CLIPFORMAT, 2) + TEST_TYPE_UNSIGNED(CLIPFORMAT) } static void test_pack_COAUTHIDENTITY(void) { /* COAUTHIDENTITY (pack 4) */ - TEST_TYPE(COAUTHIDENTITY, 28, 4); - TEST_FIELD(COAUTHIDENTITY, USHORT *, User, 0, 4, 4); - TEST_FIELD(COAUTHIDENTITY, ULONG, UserLength, 4, 4, 4); - TEST_FIELD(COAUTHIDENTITY, USHORT *, Domain, 8, 4, 4); - TEST_FIELD(COAUTHIDENTITY, ULONG, DomainLength, 12, 4, 4); - TEST_FIELD(COAUTHIDENTITY, USHORT *, Password, 16, 4, 4); - TEST_FIELD(COAUTHIDENTITY, ULONG, PasswordLength, 20, 4, 4); - TEST_FIELD(COAUTHIDENTITY, ULONG, Flags, 24, 4, 4); + TEST_TYPE_SIZE (COAUTHIDENTITY, 28) + TEST_TYPE_ALIGN (COAUTHIDENTITY, 4) + TEST_FIELD_SIZE (COAUTHIDENTITY, User, 4) + TEST_FIELD_ALIGN (COAUTHIDENTITY, User, 4) + TEST_FIELD_OFFSET(COAUTHIDENTITY, User, 0) + TEST_FIELD_SIZE (COAUTHIDENTITY, UserLength, 4) + TEST_FIELD_ALIGN (COAUTHIDENTITY, UserLength, 4) + TEST_FIELD_OFFSET(COAUTHIDENTITY, UserLength, 4) + TEST_FIELD_SIZE (COAUTHIDENTITY, Domain, 4) + TEST_FIELD_ALIGN (COAUTHIDENTITY, Domain, 4) + TEST_FIELD_OFFSET(COAUTHIDENTITY, Domain, 8) + TEST_FIELD_SIZE (COAUTHIDENTITY, DomainLength, 4) + TEST_FIELD_ALIGN (COAUTHIDENTITY, DomainLength, 4) + TEST_FIELD_OFFSET(COAUTHIDENTITY, DomainLength, 12) + TEST_FIELD_SIZE (COAUTHIDENTITY, Password, 4) + TEST_FIELD_ALIGN (COAUTHIDENTITY, Password, 4) + TEST_FIELD_OFFSET(COAUTHIDENTITY, Password, 16) + TEST_FIELD_SIZE (COAUTHIDENTITY, PasswordLength, 4) + TEST_FIELD_ALIGN (COAUTHIDENTITY, PasswordLength, 4) + TEST_FIELD_OFFSET(COAUTHIDENTITY, PasswordLength, 20) + TEST_FIELD_SIZE (COAUTHIDENTITY, Flags, 4) + TEST_FIELD_ALIGN (COAUTHIDENTITY, Flags, 4) + TEST_FIELD_OFFSET(COAUTHIDENTITY, Flags, 24) } static void test_pack_COAUTHINFO(void) { /* COAUTHINFO (pack 4) */ - TEST_TYPE(COAUTHINFO, 28, 4); - TEST_FIELD(COAUTHINFO, DWORD, dwAuthnSvc, 0, 4, 4); - TEST_FIELD(COAUTHINFO, DWORD, dwAuthzSvc, 4, 4, 4); - TEST_FIELD(COAUTHINFO, LPWSTR, pwszServerPrincName, 8, 4, 4); - TEST_FIELD(COAUTHINFO, DWORD, dwAuthnLevel, 12, 4, 4); - TEST_FIELD(COAUTHINFO, DWORD, dwImpersonationLevel, 16, 4, 4); - TEST_FIELD(COAUTHINFO, COAUTHIDENTITY *, pAuthIdentityData, 20, 4, 4); - TEST_FIELD(COAUTHINFO, DWORD, dwCapabilities, 24, 4, 4); + TEST_TYPE_SIZE (COAUTHINFO, 28) + TEST_TYPE_ALIGN (COAUTHINFO, 4) + TEST_FIELD_SIZE (COAUTHINFO, dwAuthnSvc, 4) + TEST_FIELD_ALIGN (COAUTHINFO, dwAuthnSvc, 4) + TEST_FIELD_OFFSET(COAUTHINFO, dwAuthnSvc, 0) + TEST_FIELD_SIZE (COAUTHINFO, dwAuthzSvc, 4) + TEST_FIELD_ALIGN (COAUTHINFO, dwAuthzSvc, 4) + TEST_FIELD_OFFSET(COAUTHINFO, dwAuthzSvc, 4) + TEST_FIELD_SIZE (COAUTHINFO, pwszServerPrincName, 4) + TEST_FIELD_ALIGN (COAUTHINFO, pwszServerPrincName, 4) + TEST_FIELD_OFFSET(COAUTHINFO, pwszServerPrincName, 8) + TEST_FIELD_SIZE (COAUTHINFO, dwAuthnLevel, 4) + TEST_FIELD_ALIGN (COAUTHINFO, dwAuthnLevel, 4) + TEST_FIELD_OFFSET(COAUTHINFO, dwAuthnLevel, 12) + TEST_FIELD_SIZE (COAUTHINFO, dwImpersonationLevel, 4) + TEST_FIELD_ALIGN (COAUTHINFO, dwImpersonationLevel, 4) + TEST_FIELD_OFFSET(COAUTHINFO, dwImpersonationLevel, 16) + TEST_FIELD_SIZE (COAUTHINFO, pAuthIdentityData, 4) + TEST_FIELD_ALIGN (COAUTHINFO, pAuthIdentityData, 4) + TEST_FIELD_OFFSET(COAUTHINFO, pAuthIdentityData, 20) + TEST_FIELD_SIZE (COAUTHINFO, dwCapabilities, 4) + TEST_FIELD_ALIGN (COAUTHINFO, dwCapabilities, 4) + TEST_FIELD_OFFSET(COAUTHINFO, dwCapabilities, 24) } static void test_pack_DATE(void) { /* DATE */ - TEST_TYPE(DATE, 8, 8); + TEST_TYPE_SIZE (DATE, 8) + TEST_TYPE_ALIGN (DATE, 8) } static void test_pack_DOUBLE(void) { /* DOUBLE */ - TEST_TYPE(DOUBLE, 8, 8); + TEST_TYPE_SIZE (DOUBLE, 8) + TEST_TYPE_ALIGN (DOUBLE, 8) } static void test_pack_DWORD_SIZEDARR(void) { /* DWORD_SIZEDARR (pack 4) */ - TEST_TYPE(DWORD_SIZEDARR, 8, 4); - TEST_FIELD(DWORD_SIZEDARR, unsigned long, clSize, 0, 4, 4); - TEST_FIELD(DWORD_SIZEDARR, unsigned long *, pData, 4, 4, 4); + TEST_TYPE_SIZE (DWORD_SIZEDARR, 8) + TEST_TYPE_ALIGN (DWORD_SIZEDARR, 4) + TEST_FIELD_SIZE (DWORD_SIZEDARR, clSize, 4) + TEST_FIELD_ALIGN (DWORD_SIZEDARR, clSize, 4) + TEST_FIELD_OFFSET(DWORD_SIZEDARR, clSize, 0) + TEST_FIELD_SIZE (DWORD_SIZEDARR, pData, 4) + TEST_FIELD_ALIGN (DWORD_SIZEDARR, pData, 4) + TEST_FIELD_OFFSET(DWORD_SIZEDARR, pData, 4) } static void test_pack_FLAGGED_BYTE_BLOB(void) { /* FLAGGED_BYTE_BLOB (pack 4) */ - TEST_TYPE(FLAGGED_BYTE_BLOB, 12, 4); - TEST_FIELD(FLAGGED_BYTE_BLOB, unsigned long, fFlags, 0, 4, 4); - TEST_FIELD(FLAGGED_BYTE_BLOB, unsigned long, clSize, 4, 4, 4); - TEST_FIELD(FLAGGED_BYTE_BLOB, byte[1], abData, 8, 1, 1); + TEST_TYPE_SIZE (FLAGGED_BYTE_BLOB, 12) + TEST_TYPE_ALIGN (FLAGGED_BYTE_BLOB, 4) + TEST_FIELD_SIZE (FLAGGED_BYTE_BLOB, fFlags, 4) + TEST_FIELD_ALIGN (FLAGGED_BYTE_BLOB, fFlags, 4) + TEST_FIELD_OFFSET(FLAGGED_BYTE_BLOB, fFlags, 0) + TEST_FIELD_SIZE (FLAGGED_BYTE_BLOB, clSize, 4) + TEST_FIELD_ALIGN (FLAGGED_BYTE_BLOB, clSize, 4) + TEST_FIELD_OFFSET(FLAGGED_BYTE_BLOB, clSize, 4) + TEST_FIELD_SIZE (FLAGGED_BYTE_BLOB, abData, 1) + TEST_FIELD_ALIGN (FLAGGED_BYTE_BLOB, abData, 1) + TEST_FIELD_OFFSET(FLAGGED_BYTE_BLOB, abData, 8) } static void test_pack_FLAGGED_WORD_BLOB(void) { /* FLAGGED_WORD_BLOB (pack 4) */ - TEST_TYPE(FLAGGED_WORD_BLOB, 12, 4); - TEST_FIELD(FLAGGED_WORD_BLOB, unsigned long, fFlags, 0, 4, 4); - TEST_FIELD(FLAGGED_WORD_BLOB, unsigned long, clSize, 4, 4, 4); - TEST_FIELD(FLAGGED_WORD_BLOB, unsigned short[1], asData, 8, 2, 2); + TEST_TYPE_SIZE (FLAGGED_WORD_BLOB, 12) + TEST_TYPE_ALIGN (FLAGGED_WORD_BLOB, 4) + TEST_FIELD_SIZE (FLAGGED_WORD_BLOB, fFlags, 4) + TEST_FIELD_ALIGN (FLAGGED_WORD_BLOB, fFlags, 4) + TEST_FIELD_OFFSET(FLAGGED_WORD_BLOB, fFlags, 0) + TEST_FIELD_SIZE (FLAGGED_WORD_BLOB, clSize, 4) + TEST_FIELD_ALIGN (FLAGGED_WORD_BLOB, clSize, 4) + TEST_FIELD_OFFSET(FLAGGED_WORD_BLOB, clSize, 4) + TEST_FIELD_SIZE (FLAGGED_WORD_BLOB, asData, 2) + TEST_FIELD_ALIGN (FLAGGED_WORD_BLOB, asData, 2) + TEST_FIELD_OFFSET(FLAGGED_WORD_BLOB, asData, 8) } static void test_pack_HMETAFILEPICT(void) { /* HMETAFILEPICT */ - TEST_TYPE(HMETAFILEPICT, 4, 4); + TEST_TYPE_SIZE (HMETAFILEPICT, 4) + TEST_TYPE_ALIGN (HMETAFILEPICT, 4) } static void test_pack_HYPER_SIZEDARR(void) { /* HYPER_SIZEDARR (pack 4) */ - TEST_TYPE(HYPER_SIZEDARR, 8, 4); - TEST_FIELD(HYPER_SIZEDARR, unsigned long, clSize, 0, 4, 4); - TEST_FIELD(HYPER_SIZEDARR, hyper *, pData, 4, 4, 4); + TEST_TYPE_SIZE (HYPER_SIZEDARR, 8) + TEST_TYPE_ALIGN (HYPER_SIZEDARR, 4) + TEST_FIELD_SIZE (HYPER_SIZEDARR, clSize, 4) + TEST_FIELD_ALIGN (HYPER_SIZEDARR, clSize, 4) + TEST_FIELD_OFFSET(HYPER_SIZEDARR, clSize, 0) + TEST_FIELD_SIZE (HYPER_SIZEDARR, pData, 4) + TEST_FIELD_ALIGN (HYPER_SIZEDARR, pData, 4) + TEST_FIELD_OFFSET(HYPER_SIZEDARR, pData, 4) } static void test_pack_LPBLOB(void) { /* LPBLOB */ - TEST_TYPE(LPBLOB, 4, 4); + TEST_TYPE_SIZE (LPBLOB, 4) + TEST_TYPE_ALIGN (LPBLOB, 4) } static void test_pack_LPBSTR(void) { /* LPBSTR */ - TEST_TYPE(LPBSTR, 4, 4); - TEST_TYPE_POINTER(LPBSTR, 4, 4); + TEST_TYPE_SIZE (LPBSTR, 4) + TEST_TYPE_ALIGN (LPBSTR, 4) + TEST_TARGET_SIZE (LPBSTR, 4) + TEST_TARGET_ALIGN(LPBSTR, 4) } static void test_pack_LPBSTRBLOB(void) { /* LPBSTRBLOB */ - TEST_TYPE(LPBSTRBLOB, 4, 4); + TEST_TYPE_SIZE (LPBSTRBLOB, 4) + TEST_TYPE_ALIGN (LPBSTRBLOB, 4) } static void test_pack_LPCOLESTR(void) { /* LPCOLESTR */ - TEST_TYPE(LPCOLESTR, 4, 4); - TEST_TYPE_POINTER(LPCOLESTR, 2, 2); + TEST_TYPE_SIZE (LPCOLESTR, 4) + TEST_TYPE_ALIGN (LPCOLESTR, 4) + TEST_TARGET_SIZE (LPCOLESTR, 2) + TEST_TARGET_ALIGN(LPCOLESTR, 2) } static void test_pack_LPCY(void) { /* LPCY */ - TEST_TYPE(LPCY, 4, 4); + TEST_TYPE_SIZE (LPCY, 4) + TEST_TYPE_ALIGN (LPCY, 4) } static void test_pack_LPDECIMAL(void) { /* LPDECIMAL */ - TEST_TYPE(LPDECIMAL, 4, 4); + TEST_TYPE_SIZE (LPDECIMAL, 4) + TEST_TYPE_ALIGN (LPDECIMAL, 4) } static void test_pack_LPOLESTR(void) { /* LPOLESTR */ - TEST_TYPE(LPOLESTR, 4, 4); - TEST_TYPE_POINTER(LPOLESTR, 2, 2); + TEST_TYPE_SIZE (LPOLESTR, 4) + TEST_TYPE_ALIGN (LPOLESTR, 4) + TEST_TARGET_SIZE (LPOLESTR, 2) + TEST_TARGET_ALIGN(LPOLESTR, 2) } static void test_pack_OLECHAR(void) { /* OLECHAR */ - TEST_TYPE(OLECHAR, 2, 2); + TEST_TYPE_SIZE (OLECHAR, 2) + TEST_TYPE_ALIGN (OLECHAR, 2) } static void test_pack_PROPID(void) { /* PROPID */ - TEST_TYPE(PROPID, 4, 4); + TEST_TYPE_SIZE (PROPID, 4) + TEST_TYPE_ALIGN (PROPID, 4) } static void test_pack_RemHBITMAP(void) { /* RemHBITMAP (pack 4) */ - TEST_TYPE(RemHBITMAP, 8, 4); - TEST_FIELD(RemHBITMAP, unsigned long, cbData, 0, 4, 4); - TEST_FIELD(RemHBITMAP, byte[1], data, 4, 1, 1); + TEST_TYPE_SIZE (RemHBITMAP, 8) + TEST_TYPE_ALIGN (RemHBITMAP, 4) + TEST_FIELD_SIZE (RemHBITMAP, cbData, 4) + TEST_FIELD_ALIGN (RemHBITMAP, cbData, 4) + TEST_FIELD_OFFSET(RemHBITMAP, cbData, 0) + TEST_FIELD_SIZE (RemHBITMAP, data, 1) + TEST_FIELD_ALIGN (RemHBITMAP, data, 1) + TEST_FIELD_OFFSET(RemHBITMAP, data, 4) } static void test_pack_RemHENHMETAFILE(void) { /* RemHENHMETAFILE (pack 4) */ - TEST_TYPE(RemHENHMETAFILE, 8, 4); - TEST_FIELD(RemHENHMETAFILE, unsigned long, cbData, 0, 4, 4); - TEST_FIELD(RemHENHMETAFILE, byte[1], data, 4, 1, 1); + TEST_TYPE_SIZE (RemHENHMETAFILE, 8) + TEST_TYPE_ALIGN (RemHENHMETAFILE, 4) + TEST_FIELD_SIZE (RemHENHMETAFILE, cbData, 4) + TEST_FIELD_ALIGN (RemHENHMETAFILE, cbData, 4) + TEST_FIELD_OFFSET(RemHENHMETAFILE, cbData, 0) + TEST_FIELD_SIZE (RemHENHMETAFILE, data, 1) + TEST_FIELD_ALIGN (RemHENHMETAFILE, data, 1) + TEST_FIELD_OFFSET(RemHENHMETAFILE, data, 4) } static void test_pack_RemHGLOBAL(void) { /* RemHGLOBAL (pack 4) */ - TEST_TYPE(RemHGLOBAL, 12, 4); - TEST_FIELD(RemHGLOBAL, long, fNullHGlobal, 0, 4, 4); - TEST_FIELD(RemHGLOBAL, unsigned long, cbData, 4, 4, 4); - TEST_FIELD(RemHGLOBAL, byte[1], data, 8, 1, 1); + TEST_TYPE_SIZE (RemHGLOBAL, 12) + TEST_TYPE_ALIGN (RemHGLOBAL, 4) + TEST_FIELD_SIZE (RemHGLOBAL, fNullHGlobal, 4) + TEST_FIELD_ALIGN (RemHGLOBAL, fNullHGlobal, 4) + TEST_FIELD_OFFSET(RemHGLOBAL, fNullHGlobal, 0) + TEST_FIELD_SIZE (RemHGLOBAL, cbData, 4) + TEST_FIELD_ALIGN (RemHGLOBAL, cbData, 4) + TEST_FIELD_OFFSET(RemHGLOBAL, cbData, 4) + TEST_FIELD_SIZE (RemHGLOBAL, data, 1) + TEST_FIELD_ALIGN (RemHGLOBAL, data, 1) + TEST_FIELD_OFFSET(RemHGLOBAL, data, 8) } static void test_pack_RemHMETAFILEPICT(void) { /* RemHMETAFILEPICT (pack 4) */ - TEST_TYPE(RemHMETAFILEPICT, 20, 4); - TEST_FIELD(RemHMETAFILEPICT, long, mm, 0, 4, 4); - TEST_FIELD(RemHMETAFILEPICT, long, xExt, 4, 4, 4); - TEST_FIELD(RemHMETAFILEPICT, long, yExt, 8, 4, 4); - TEST_FIELD(RemHMETAFILEPICT, unsigned long, cbData, 12, 4, 4); - TEST_FIELD(RemHMETAFILEPICT, byte[1], data, 16, 1, 1); + TEST_TYPE_SIZE (RemHMETAFILEPICT, 20) + TEST_TYPE_ALIGN (RemHMETAFILEPICT, 4) + TEST_FIELD_SIZE (RemHMETAFILEPICT, mm, 4) + TEST_FIELD_ALIGN (RemHMETAFILEPICT, mm, 4) + TEST_FIELD_OFFSET(RemHMETAFILEPICT, mm, 0) + TEST_FIELD_SIZE (RemHMETAFILEPICT, xExt, 4) + TEST_FIELD_ALIGN (RemHMETAFILEPICT, xExt, 4) + TEST_FIELD_OFFSET(RemHMETAFILEPICT, xExt, 4) + TEST_FIELD_SIZE (RemHMETAFILEPICT, yExt, 4) + TEST_FIELD_ALIGN (RemHMETAFILEPICT, yExt, 4) + TEST_FIELD_OFFSET(RemHMETAFILEPICT, yExt, 8) + TEST_FIELD_SIZE (RemHMETAFILEPICT, cbData, 4) + TEST_FIELD_ALIGN (RemHMETAFILEPICT, cbData, 4) + TEST_FIELD_OFFSET(RemHMETAFILEPICT, cbData, 12) + TEST_FIELD_SIZE (RemHMETAFILEPICT, data, 1) + TEST_FIELD_ALIGN (RemHMETAFILEPICT, data, 1) + TEST_FIELD_OFFSET(RemHMETAFILEPICT, data, 16) } static void test_pack_RemHPALETTE(void) { /* RemHPALETTE (pack 4) */ - TEST_TYPE(RemHPALETTE, 8, 4); - TEST_FIELD(RemHPALETTE, unsigned long, cbData, 0, 4, 4); - TEST_FIELD(RemHPALETTE, byte[1], data, 4, 1, 1); + TEST_TYPE_SIZE (RemHPALETTE, 8) + TEST_TYPE_ALIGN (RemHPALETTE, 4) + TEST_FIELD_SIZE (RemHPALETTE, cbData, 4) + TEST_FIELD_ALIGN (RemHPALETTE, cbData, 4) + TEST_FIELD_OFFSET(RemHPALETTE, cbData, 0) + TEST_FIELD_SIZE (RemHPALETTE, data, 1) + TEST_FIELD_ALIGN (RemHPALETTE, data, 1) + TEST_FIELD_OFFSET(RemHPALETTE, data, 4) } static void test_pack_SCODE(void) { /* SCODE */ - TEST_TYPE(SCODE, 4, 4); + TEST_TYPE_SIZE (SCODE, 4) + TEST_TYPE_ALIGN (SCODE, 4) } static void test_pack_UP_BYTE_BLOB(void) { /* UP_BYTE_BLOB */ - TEST_TYPE(UP_BYTE_BLOB, 4, 4); - TEST_TYPE_POINTER(UP_BYTE_BLOB, 8, 4); + TEST_TYPE_SIZE (UP_BYTE_BLOB, 4) + TEST_TYPE_ALIGN (UP_BYTE_BLOB, 4) + TEST_TARGET_SIZE (UP_BYTE_BLOB, 8) + TEST_TARGET_ALIGN(UP_BYTE_BLOB, 4) } static void test_pack_UP_FLAGGED_BYTE_BLOB(void) { /* UP_FLAGGED_BYTE_BLOB */ - TEST_TYPE(UP_FLAGGED_BYTE_BLOB, 4, 4); - TEST_TYPE_POINTER(UP_FLAGGED_BYTE_BLOB, 12, 4); + TEST_TYPE_SIZE (UP_FLAGGED_BYTE_BLOB, 4) + TEST_TYPE_ALIGN (UP_FLAGGED_BYTE_BLOB, 4) + TEST_TARGET_SIZE (UP_FLAGGED_BYTE_BLOB, 12) + TEST_TARGET_ALIGN(UP_FLAGGED_BYTE_BLOB, 4) } static void test_pack_UP_FLAGGED_WORD_BLOB(void) { /* UP_FLAGGED_WORD_BLOB */ - TEST_TYPE(UP_FLAGGED_WORD_BLOB, 4, 4); - TEST_TYPE_POINTER(UP_FLAGGED_WORD_BLOB, 12, 4); + TEST_TYPE_SIZE (UP_FLAGGED_WORD_BLOB, 4) + TEST_TYPE_ALIGN (UP_FLAGGED_WORD_BLOB, 4) + TEST_TARGET_SIZE (UP_FLAGGED_WORD_BLOB, 12) + TEST_TARGET_ALIGN(UP_FLAGGED_WORD_BLOB, 4) } static void test_pack_VARIANT_BOOL(void) { /* VARIANT_BOOL */ - TEST_TYPE(VARIANT_BOOL, 2, 2); - TEST_TYPE_SIGNED(VARIANT_BOOL); + TEST_TYPE_SIZE (VARIANT_BOOL, 2) + TEST_TYPE_ALIGN (VARIANT_BOOL, 2) + TEST_TYPE_SIGNED(VARIANT_BOOL) } static void test_pack_VARTYPE(void) { /* VARTYPE */ - TEST_TYPE(VARTYPE, 2, 2); - TEST_TYPE_UNSIGNED(VARTYPE); + TEST_TYPE_SIZE (VARTYPE, 2) + TEST_TYPE_ALIGN (VARTYPE, 2) + TEST_TYPE_UNSIGNED(VARTYPE) } static void test_pack_WORD_SIZEDARR(void) { /* WORD_SIZEDARR (pack 4) */ - TEST_TYPE(WORD_SIZEDARR, 8, 4); - TEST_FIELD(WORD_SIZEDARR, unsigned long, clSize, 0, 4, 4); - TEST_FIELD(WORD_SIZEDARR, unsigned short *, pData, 4, 4, 4); + TEST_TYPE_SIZE (WORD_SIZEDARR, 8) + TEST_TYPE_ALIGN (WORD_SIZEDARR, 4) + TEST_FIELD_SIZE (WORD_SIZEDARR, clSize, 4) + TEST_FIELD_ALIGN (WORD_SIZEDARR, clSize, 4) + TEST_FIELD_OFFSET(WORD_SIZEDARR, clSize, 0) + TEST_FIELD_SIZE (WORD_SIZEDARR, pData, 4) + TEST_FIELD_ALIGN (WORD_SIZEDARR, pData, 4) + TEST_FIELD_OFFSET(WORD_SIZEDARR, pData, 4) } static void test_pack_remoteMETAFILEPICT(void) { /* remoteMETAFILEPICT (pack 4) */ - TEST_TYPE(remoteMETAFILEPICT, 16, 4); - TEST_FIELD(remoteMETAFILEPICT, long, mm, 0, 4, 4); - TEST_FIELD(remoteMETAFILEPICT, long, xExt, 4, 4, 4); - TEST_FIELD(remoteMETAFILEPICT, long, yExt, 8, 4, 4); - TEST_FIELD(remoteMETAFILEPICT, userHMETAFILE *, hMF, 12, 4, 4); + TEST_TYPE_SIZE (remoteMETAFILEPICT, 16) + TEST_TYPE_ALIGN (remoteMETAFILEPICT, 4) + TEST_FIELD_SIZE (remoteMETAFILEPICT, mm, 4) + TEST_FIELD_ALIGN (remoteMETAFILEPICT, mm, 4) + TEST_FIELD_OFFSET(remoteMETAFILEPICT, mm, 0) + TEST_FIELD_SIZE (remoteMETAFILEPICT, xExt, 4) + TEST_FIELD_ALIGN (remoteMETAFILEPICT, xExt, 4) + TEST_FIELD_OFFSET(remoteMETAFILEPICT, xExt, 4) + TEST_FIELD_SIZE (remoteMETAFILEPICT, yExt, 4) + TEST_FIELD_ALIGN (remoteMETAFILEPICT, yExt, 4) + TEST_FIELD_OFFSET(remoteMETAFILEPICT, yExt, 8) + TEST_FIELD_SIZE (remoteMETAFILEPICT, hMF, 4) + TEST_FIELD_ALIGN (remoteMETAFILEPICT, hMF, 4) + TEST_FIELD_OFFSET(remoteMETAFILEPICT, hMF, 12) } static void test_pack_userBITMAP(void) { /* userBITMAP (pack 4) */ - TEST_TYPE(userBITMAP, 28, 4); - TEST_FIELD(userBITMAP, LONG, bmType, 0, 4, 4); - TEST_FIELD(userBITMAP, LONG, bmWidth, 4, 4, 4); - TEST_FIELD(userBITMAP, LONG, bmHeight, 8, 4, 4); - TEST_FIELD(userBITMAP, LONG, bmWidthBytes, 12, 4, 4); - TEST_FIELD(userBITMAP, WORD, bmPlanes, 16, 2, 2); - TEST_FIELD(userBITMAP, WORD, bmBitsPixel, 18, 2, 2); - TEST_FIELD(userBITMAP, ULONG, cbSize, 20, 4, 4); - TEST_FIELD(userBITMAP, byte[1], pBuffer, 24, 1, 1); + TEST_TYPE_SIZE (userBITMAP, 28) + TEST_TYPE_ALIGN (userBITMAP, 4) + TEST_FIELD_SIZE (userBITMAP, bmType, 4) + TEST_FIELD_ALIGN (userBITMAP, bmType, 4) + TEST_FIELD_OFFSET(userBITMAP, bmType, 0) + TEST_FIELD_SIZE (userBITMAP, bmWidth, 4) + TEST_FIELD_ALIGN (userBITMAP, bmWidth, 4) + TEST_FIELD_OFFSET(userBITMAP, bmWidth, 4) + TEST_FIELD_SIZE (userBITMAP, bmHeight, 4) + TEST_FIELD_ALIGN (userBITMAP, bmHeight, 4) + TEST_FIELD_OFFSET(userBITMAP, bmHeight, 8) + TEST_FIELD_SIZE (userBITMAP, bmWidthBytes, 4) + TEST_FIELD_ALIGN (userBITMAP, bmWidthBytes, 4) + TEST_FIELD_OFFSET(userBITMAP, bmWidthBytes, 12) + TEST_FIELD_SIZE (userBITMAP, bmPlanes, 2) + TEST_FIELD_ALIGN (userBITMAP, bmPlanes, 2) + TEST_FIELD_OFFSET(userBITMAP, bmPlanes, 16) + TEST_FIELD_SIZE (userBITMAP, bmBitsPixel, 2) + TEST_FIELD_ALIGN (userBITMAP, bmBitsPixel, 2) + TEST_FIELD_OFFSET(userBITMAP, bmBitsPixel, 18) + TEST_FIELD_SIZE (userBITMAP, cbSize, 4) + TEST_FIELD_ALIGN (userBITMAP, cbSize, 4) + TEST_FIELD_OFFSET(userBITMAP, cbSize, 20) + TEST_FIELD_SIZE (userBITMAP, pBuffer, 1) + TEST_FIELD_ALIGN (userBITMAP, pBuffer, 1) + TEST_FIELD_OFFSET(userBITMAP, pBuffer, 24) } static void test_pack_userCLIPFORMAT(void) { /* userCLIPFORMAT (pack 4) */ - TEST_FIELD(userCLIPFORMAT, long, fContext, 0, 4, 4); + TEST_FIELD_SIZE (userCLIPFORMAT, fContext, 4) + TEST_FIELD_ALIGN (userCLIPFORMAT, fContext, 4) + TEST_FIELD_OFFSET(userCLIPFORMAT, fContext, 0) } static void test_pack_userHBITMAP(void) { /* userHBITMAP (pack 4) */ - TEST_FIELD(userHBITMAP, long, fContext, 0, 4, 4); + TEST_FIELD_SIZE (userHBITMAP, fContext, 4) + TEST_FIELD_ALIGN (userHBITMAP, fContext, 4) + TEST_FIELD_OFFSET(userHBITMAP, fContext, 0) } static void test_pack_userHENHMETAFILE(void) { /* userHENHMETAFILE (pack 4) */ - TEST_FIELD(userHENHMETAFILE, long, fContext, 0, 4, 4); + TEST_FIELD_SIZE (userHENHMETAFILE, fContext, 4) + TEST_FIELD_ALIGN (userHENHMETAFILE, fContext, 4) + TEST_FIELD_OFFSET(userHENHMETAFILE, fContext, 0) } static void test_pack_userHGLOBAL(void) { /* userHGLOBAL (pack 4) */ - TEST_FIELD(userHGLOBAL, long, fContext, 0, 4, 4); + TEST_FIELD_SIZE (userHGLOBAL, fContext, 4) + TEST_FIELD_ALIGN (userHGLOBAL, fContext, 4) + TEST_FIELD_OFFSET(userHGLOBAL, fContext, 0) } static void test_pack_userHMETAFILE(void) { /* userHMETAFILE (pack 4) */ - TEST_FIELD(userHMETAFILE, long, fContext, 0, 4, 4); + TEST_FIELD_SIZE (userHMETAFILE, fContext, 4) + TEST_FIELD_ALIGN (userHMETAFILE, fContext, 4) + TEST_FIELD_OFFSET(userHMETAFILE, fContext, 0) } static void test_pack_userHMETAFILEPICT(void) { /* userHMETAFILEPICT (pack 4) */ - TEST_FIELD(userHMETAFILEPICT, long, fContext, 0, 4, 4); + TEST_FIELD_SIZE (userHMETAFILEPICT, fContext, 4) + TEST_FIELD_ALIGN (userHMETAFILEPICT, fContext, 4) + TEST_FIELD_OFFSET(userHMETAFILEPICT, fContext, 0) } static void test_pack_userHPALETTE(void) { /* userHPALETTE (pack 4) */ - TEST_FIELD(userHPALETTE, long, fContext, 0, 4, 4); + TEST_FIELD_SIZE (userHPALETTE, fContext, 4) + TEST_FIELD_ALIGN (userHPALETTE, fContext, 4) + TEST_FIELD_OFFSET(userHPALETTE, fContext, 0) } static void test_pack_wireBSTR(void) { /* wireBSTR */ - TEST_TYPE(wireBSTR, 4, 4); - TEST_TYPE_POINTER(wireBSTR, 12, 4); + TEST_TYPE_SIZE (wireBSTR, 4) + TEST_TYPE_ALIGN (wireBSTR, 4) + TEST_TARGET_SIZE (wireBSTR, 12) + TEST_TARGET_ALIGN(wireBSTR, 4) } static void test_pack_wireCLIPFORMAT(void) { /* wireCLIPFORMAT */ - TEST_TYPE(wireCLIPFORMAT, 4, 4); + TEST_TYPE_SIZE (wireCLIPFORMAT, 4) + TEST_TYPE_ALIGN (wireCLIPFORMAT, 4) } static void test_pack_wireHBITMAP(void) { /* wireHBITMAP */ - TEST_TYPE(wireHBITMAP, 4, 4); + TEST_TYPE_SIZE (wireHBITMAP, 4) + TEST_TYPE_ALIGN (wireHBITMAP, 4) } static void test_pack_wireHENHMETAFILE(void) { /* wireHENHMETAFILE */ - TEST_TYPE(wireHENHMETAFILE, 4, 4); + TEST_TYPE_SIZE (wireHENHMETAFILE, 4) + TEST_TYPE_ALIGN (wireHENHMETAFILE, 4) } static void test_pack_wireHGLOBAL(void) { /* wireHGLOBAL */ - TEST_TYPE(wireHGLOBAL, 4, 4); + TEST_TYPE_SIZE (wireHGLOBAL, 4) + TEST_TYPE_ALIGN (wireHGLOBAL, 4) } static void test_pack_wireHMETAFILE(void) { /* wireHMETAFILE */ - TEST_TYPE(wireHMETAFILE, 4, 4); + TEST_TYPE_SIZE (wireHMETAFILE, 4) + TEST_TYPE_ALIGN (wireHMETAFILE, 4) } static void test_pack_wireHMETAFILEPICT(void) { /* wireHMETAFILEPICT */ - TEST_TYPE(wireHMETAFILEPICT, 4, 4); + TEST_TYPE_SIZE (wireHMETAFILEPICT, 4) + TEST_TYPE_ALIGN (wireHMETAFILEPICT, 4) } static void test_pack_wireHPALETTE(void) { /* wireHPALETTE */ - TEST_TYPE(wireHPALETTE, 4, 4); + TEST_TYPE_SIZE (wireHPALETTE, 4) + TEST_TYPE_ALIGN (wireHPALETTE, 4) } static void test_pack_CLSID(void) { /* CLSID */ - TEST_TYPE(CLSID, 16, 4); + TEST_TYPE_SIZE (CLSID, 16) + TEST_TYPE_ALIGN (CLSID, 4) } static void test_pack_FMTID(void) { /* FMTID */ - TEST_TYPE(FMTID, 16, 4); -} - -static void test_pack_GUID(void) -{ - /* GUID (pack 4) */ - TEST_TYPE(GUID, 16, 4); - TEST_FIELD(GUID, unsigned long, Data1, 0, 4, 4); - TEST_FIELD(GUID, unsigned short, Data2, 4, 2, 2); - TEST_FIELD(GUID, unsigned short, Data3, 6, 2, 2); - TEST_FIELD(GUID, unsigned char[ 8 ], Data4, 8, 8, 1); + TEST_TYPE_SIZE (FMTID, 16) + TEST_TYPE_ALIGN (FMTID, 4) } static void test_pack_IID(void) { /* IID */ - TEST_TYPE(IID, 16, 4); -} - -static void test_pack_LPGUID(void) -{ - /* LPGUID */ - TEST_TYPE(LPGUID, 4, 4); - TEST_TYPE_POINTER(LPGUID, 16, 4); + TEST_TYPE_SIZE (IID, 16) + TEST_TYPE_ALIGN (IID, 4) } static void test_pack_APPBARDATA(void) { /* APPBARDATA (pack 1) */ - TEST_TYPE(APPBARDATA, 36, 1); - TEST_FIELD(APPBARDATA, DWORD, cbSize, 0, 4, 1); - TEST_FIELD(APPBARDATA, HWND, hWnd, 4, 4, 1); - TEST_FIELD(APPBARDATA, UINT, uCallbackMessage, 8, 4, 1); - TEST_FIELD(APPBARDATA, UINT, uEdge, 12, 4, 1); - TEST_FIELD(APPBARDATA, RECT, rc, 16, 16, 1); - TEST_FIELD(APPBARDATA, LPARAM, lParam, 32, 4, 1); + TEST_TYPE_SIZE (APPBARDATA, 36) + TEST_TYPE_ALIGN (APPBARDATA, 1) + TEST_FIELD_SIZE (APPBARDATA, cbSize, 4) + TEST_FIELD_ALIGN (APPBARDATA, cbSize, 1) + TEST_FIELD_OFFSET(APPBARDATA, cbSize, 0) + TEST_FIELD_SIZE (APPBARDATA, hWnd, 4) + TEST_FIELD_ALIGN (APPBARDATA, hWnd, 1) + TEST_FIELD_OFFSET(APPBARDATA, hWnd, 4) + TEST_FIELD_SIZE (APPBARDATA, uCallbackMessage, 4) + TEST_FIELD_ALIGN (APPBARDATA, uCallbackMessage, 1) + TEST_FIELD_OFFSET(APPBARDATA, uCallbackMessage, 8) + TEST_FIELD_SIZE (APPBARDATA, uEdge, 4) + TEST_FIELD_ALIGN (APPBARDATA, uEdge, 1) + TEST_FIELD_OFFSET(APPBARDATA, uEdge, 12) + TEST_FIELD_SIZE (APPBARDATA, rc, 16) + TEST_FIELD_ALIGN (APPBARDATA, rc, 1) + TEST_FIELD_OFFSET(APPBARDATA, rc, 16) + TEST_FIELD_SIZE (APPBARDATA, lParam, 4) + TEST_FIELD_ALIGN (APPBARDATA, lParam, 1) + TEST_FIELD_OFFSET(APPBARDATA, lParam, 32) } static void test_pack_DRAGINFOA(void) { /* DRAGINFOA (pack 1) */ - TEST_TYPE(DRAGINFOA, 24, 1); - TEST_FIELD(DRAGINFOA, UINT, uSize, 0, 4, 1); - TEST_FIELD(DRAGINFOA, POINT, pt, 4, 8, 1); - TEST_FIELD(DRAGINFOA, BOOL, fNC, 12, 4, 1); - TEST_FIELD(DRAGINFOA, LPSTR, lpFileList, 16, 4, 1); - TEST_FIELD(DRAGINFOA, DWORD, grfKeyState, 20, 4, 1); + TEST_TYPE_SIZE (DRAGINFOA, 24) + TEST_TYPE_ALIGN (DRAGINFOA, 1) + TEST_FIELD_SIZE (DRAGINFOA, uSize, 4) + TEST_FIELD_ALIGN (DRAGINFOA, uSize, 1) + TEST_FIELD_OFFSET(DRAGINFOA, uSize, 0) + TEST_FIELD_SIZE (DRAGINFOA, pt, 8) + TEST_FIELD_ALIGN (DRAGINFOA, pt, 1) + TEST_FIELD_OFFSET(DRAGINFOA, pt, 4) + TEST_FIELD_SIZE (DRAGINFOA, fNC, 4) + TEST_FIELD_ALIGN (DRAGINFOA, fNC, 1) + TEST_FIELD_OFFSET(DRAGINFOA, fNC, 12) + TEST_FIELD_SIZE (DRAGINFOA, lpFileList, 4) + TEST_FIELD_ALIGN (DRAGINFOA, lpFileList, 1) + TEST_FIELD_OFFSET(DRAGINFOA, lpFileList, 16) + TEST_FIELD_SIZE (DRAGINFOA, grfKeyState, 4) + TEST_FIELD_ALIGN (DRAGINFOA, grfKeyState, 1) + TEST_FIELD_OFFSET(DRAGINFOA, grfKeyState, 20) } static void test_pack_DRAGINFOW(void) { /* DRAGINFOW (pack 1) */ - TEST_TYPE(DRAGINFOW, 24, 1); - TEST_FIELD(DRAGINFOW, UINT, uSize, 0, 4, 1); - TEST_FIELD(DRAGINFOW, POINT, pt, 4, 8, 1); - TEST_FIELD(DRAGINFOW, BOOL, fNC, 12, 4, 1); - TEST_FIELD(DRAGINFOW, LPWSTR, lpFileList, 16, 4, 1); - TEST_FIELD(DRAGINFOW, DWORD, grfKeyState, 20, 4, 1); + TEST_TYPE_SIZE (DRAGINFOW, 24) + TEST_TYPE_ALIGN (DRAGINFOW, 1) + TEST_FIELD_SIZE (DRAGINFOW, uSize, 4) + TEST_FIELD_ALIGN (DRAGINFOW, uSize, 1) + TEST_FIELD_OFFSET(DRAGINFOW, uSize, 0) + TEST_FIELD_SIZE (DRAGINFOW, pt, 8) + TEST_FIELD_ALIGN (DRAGINFOW, pt, 1) + TEST_FIELD_OFFSET(DRAGINFOW, pt, 4) + TEST_FIELD_SIZE (DRAGINFOW, fNC, 4) + TEST_FIELD_ALIGN (DRAGINFOW, fNC, 1) + TEST_FIELD_OFFSET(DRAGINFOW, fNC, 12) + TEST_FIELD_SIZE (DRAGINFOW, lpFileList, 4) + TEST_FIELD_ALIGN (DRAGINFOW, lpFileList, 1) + TEST_FIELD_OFFSET(DRAGINFOW, lpFileList, 16) + TEST_FIELD_SIZE (DRAGINFOW, grfKeyState, 4) + TEST_FIELD_ALIGN (DRAGINFOW, grfKeyState, 1) + TEST_FIELD_OFFSET(DRAGINFOW, grfKeyState, 20) } static void test_pack_FILEOP_FLAGS(void) { /* FILEOP_FLAGS */ - TEST_TYPE(FILEOP_FLAGS, 2, 2); - TEST_TYPE_UNSIGNED(FILEOP_FLAGS); + TEST_TYPE_SIZE (FILEOP_FLAGS, 2) + TEST_TYPE_ALIGN (FILEOP_FLAGS, 2) + TEST_TYPE_UNSIGNED(FILEOP_FLAGS) } static void test_pack_LPDRAGINFOA(void) { /* LPDRAGINFOA */ - TEST_TYPE(LPDRAGINFOA, 4, 4); - TEST_TYPE_POINTER(LPDRAGINFOA, 24, 1); + TEST_TYPE_SIZE (LPDRAGINFOA, 4) + TEST_TYPE_ALIGN (LPDRAGINFOA, 4) + TEST_TARGET_SIZE (LPDRAGINFOA, 24) + TEST_TARGET_ALIGN(LPDRAGINFOA, 1) } static void test_pack_LPDRAGINFOW(void) { /* LPDRAGINFOW */ - TEST_TYPE(LPDRAGINFOW, 4, 4); - TEST_TYPE_POINTER(LPDRAGINFOW, 24, 1); + TEST_TYPE_SIZE (LPDRAGINFOW, 4) + TEST_TYPE_ALIGN (LPDRAGINFOW, 4) + TEST_TARGET_SIZE (LPDRAGINFOW, 24) + TEST_TARGET_ALIGN(LPDRAGINFOW, 1) } static void test_pack_LPSHELLEXECUTEINFOA(void) { /* LPSHELLEXECUTEINFOA */ - TEST_TYPE(LPSHELLEXECUTEINFOA, 4, 4); + TEST_TYPE_SIZE (LPSHELLEXECUTEINFOA, 4) + TEST_TYPE_ALIGN (LPSHELLEXECUTEINFOA, 4) } static void test_pack_LPSHELLEXECUTEINFOW(void) { /* LPSHELLEXECUTEINFOW */ - TEST_TYPE(LPSHELLEXECUTEINFOW, 4, 4); + TEST_TYPE_SIZE (LPSHELLEXECUTEINFOW, 4) + TEST_TYPE_ALIGN (LPSHELLEXECUTEINFOW, 4) } static void test_pack_LPSHFILEOPSTRUCTA(void) { /* LPSHFILEOPSTRUCTA */ - TEST_TYPE(LPSHFILEOPSTRUCTA, 4, 4); - TEST_TYPE_POINTER(LPSHFILEOPSTRUCTA, 30, 1); + TEST_TYPE_SIZE (LPSHFILEOPSTRUCTA, 4) + TEST_TYPE_ALIGN (LPSHFILEOPSTRUCTA, 4) + TEST_TARGET_SIZE (LPSHFILEOPSTRUCTA, 30) + TEST_TARGET_ALIGN(LPSHFILEOPSTRUCTA, 1) } static void test_pack_LPSHFILEOPSTRUCTW(void) { /* LPSHFILEOPSTRUCTW */ - TEST_TYPE(LPSHFILEOPSTRUCTW, 4, 4); - TEST_TYPE_POINTER(LPSHFILEOPSTRUCTW, 30, 1); + TEST_TYPE_SIZE (LPSHFILEOPSTRUCTW, 4) + TEST_TYPE_ALIGN (LPSHFILEOPSTRUCTW, 4) + TEST_TARGET_SIZE (LPSHFILEOPSTRUCTW, 30) + TEST_TARGET_ALIGN(LPSHFILEOPSTRUCTW, 1) } static void test_pack_LPSHNAMEMAPPINGA(void) { /* LPSHNAMEMAPPINGA */ - TEST_TYPE(LPSHNAMEMAPPINGA, 4, 4); - TEST_TYPE_POINTER(LPSHNAMEMAPPINGA, 16, 1); + TEST_TYPE_SIZE (LPSHNAMEMAPPINGA, 4) + TEST_TYPE_ALIGN (LPSHNAMEMAPPINGA, 4) + TEST_TARGET_SIZE (LPSHNAMEMAPPINGA, 16) + TEST_TARGET_ALIGN(LPSHNAMEMAPPINGA, 1) } static void test_pack_LPSHNAMEMAPPINGW(void) { /* LPSHNAMEMAPPINGW */ - TEST_TYPE(LPSHNAMEMAPPINGW, 4, 4); - TEST_TYPE_POINTER(LPSHNAMEMAPPINGW, 16, 1); + TEST_TYPE_SIZE (LPSHNAMEMAPPINGW, 4) + TEST_TYPE_ALIGN (LPSHNAMEMAPPINGW, 4) + TEST_TARGET_SIZE (LPSHNAMEMAPPINGW, 16) + TEST_TARGET_ALIGN(LPSHNAMEMAPPINGW, 1) } static void test_pack_NOTIFYICONDATAA(void) { /* NOTIFYICONDATAA (pack 1) */ - TEST_FIELD(NOTIFYICONDATAA, DWORD, cbSize, 0, 4, 1); - TEST_FIELD(NOTIFYICONDATAA, HWND, hWnd, 4, 4, 1); - TEST_FIELD(NOTIFYICONDATAA, UINT, uID, 8, 4, 1); - TEST_FIELD(NOTIFYICONDATAA, UINT, uFlags, 12, 4, 1); - TEST_FIELD(NOTIFYICONDATAA, UINT, uCallbackMessage, 16, 4, 1); - TEST_FIELD(NOTIFYICONDATAA, HICON, hIcon, 20, 4, 1); - TEST_FIELD(NOTIFYICONDATAA, CHAR[128], szTip, 24, 128, 1); - TEST_FIELD(NOTIFYICONDATAA, DWORD, dwState, 152, 4, 1); - TEST_FIELD(NOTIFYICONDATAA, DWORD, dwStateMask, 156, 4, 1); - TEST_FIELD(NOTIFYICONDATAA, CHAR[256], szInfo, 160, 256, 1); + TEST_FIELD_SIZE (NOTIFYICONDATAA, cbSize, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, cbSize, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, cbSize, 0) + TEST_FIELD_SIZE (NOTIFYICONDATAA, hWnd, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, hWnd, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, hWnd, 4) + TEST_FIELD_SIZE (NOTIFYICONDATAA, uID, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, uID, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, uID, 8) + TEST_FIELD_SIZE (NOTIFYICONDATAA, uFlags, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, uFlags, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, uFlags, 12) + TEST_FIELD_SIZE (NOTIFYICONDATAA, uCallbackMessage, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, uCallbackMessage, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, uCallbackMessage, 16) + TEST_FIELD_SIZE (NOTIFYICONDATAA, hIcon, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, hIcon, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, hIcon, 20) + TEST_FIELD_SIZE (NOTIFYICONDATAA, szTip, 128) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, szTip, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, szTip, 24) + TEST_FIELD_SIZE (NOTIFYICONDATAA, dwState, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, dwState, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, dwState, 152) + TEST_FIELD_SIZE (NOTIFYICONDATAA, dwStateMask, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, dwStateMask, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, dwStateMask, 156) + TEST_FIELD_SIZE (NOTIFYICONDATAA, szInfo, 256) + TEST_FIELD_ALIGN (NOTIFYICONDATAA, szInfo, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAA, szInfo, 160) } static void test_pack_NOTIFYICONDATAW(void) { /* NOTIFYICONDATAW (pack 1) */ - TEST_FIELD(NOTIFYICONDATAW, DWORD, cbSize, 0, 4, 1); - TEST_FIELD(NOTIFYICONDATAW, HWND, hWnd, 4, 4, 1); - TEST_FIELD(NOTIFYICONDATAW, UINT, uID, 8, 4, 1); - TEST_FIELD(NOTIFYICONDATAW, UINT, uFlags, 12, 4, 1); - TEST_FIELD(NOTIFYICONDATAW, UINT, uCallbackMessage, 16, 4, 1); - TEST_FIELD(NOTIFYICONDATAW, HICON, hIcon, 20, 4, 1); - TEST_FIELD(NOTIFYICONDATAW, WCHAR[128], szTip, 24, 256, 1); - TEST_FIELD(NOTIFYICONDATAW, DWORD, dwState, 280, 4, 1); - TEST_FIELD(NOTIFYICONDATAW, DWORD, dwStateMask, 284, 4, 1); - TEST_FIELD(NOTIFYICONDATAW, WCHAR[256], szInfo, 288, 512, 1); + TEST_FIELD_SIZE (NOTIFYICONDATAW, cbSize, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, cbSize, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, cbSize, 0) + TEST_FIELD_SIZE (NOTIFYICONDATAW, hWnd, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, hWnd, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, hWnd, 4) + TEST_FIELD_SIZE (NOTIFYICONDATAW, uID, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, uID, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, uID, 8) + TEST_FIELD_SIZE (NOTIFYICONDATAW, uFlags, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, uFlags, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, uFlags, 12) + TEST_FIELD_SIZE (NOTIFYICONDATAW, uCallbackMessage, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, uCallbackMessage, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, uCallbackMessage, 16) + TEST_FIELD_SIZE (NOTIFYICONDATAW, hIcon, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, hIcon, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, hIcon, 20) + TEST_FIELD_SIZE (NOTIFYICONDATAW, szTip, 256) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, szTip, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, szTip, 24) + TEST_FIELD_SIZE (NOTIFYICONDATAW, dwState, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, dwState, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, dwState, 280) + TEST_FIELD_SIZE (NOTIFYICONDATAW, dwStateMask, 4) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, dwStateMask, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, dwStateMask, 284) + TEST_FIELD_SIZE (NOTIFYICONDATAW, szInfo, 512) + TEST_FIELD_ALIGN (NOTIFYICONDATAW, szInfo, 1) + TEST_FIELD_OFFSET(NOTIFYICONDATAW, szInfo, 288) } static void test_pack_PAPPBARDATA(void) { /* PAPPBARDATA */ - TEST_TYPE(PAPPBARDATA, 4, 4); - TEST_TYPE_POINTER(PAPPBARDATA, 36, 1); + TEST_TYPE_SIZE (PAPPBARDATA, 4) + TEST_TYPE_ALIGN (PAPPBARDATA, 4) + TEST_TARGET_SIZE (PAPPBARDATA, 36) + TEST_TARGET_ALIGN(PAPPBARDATA, 1) } static void test_pack_PNOTIFYICONDATAA(void) { /* PNOTIFYICONDATAA */ - TEST_TYPE(PNOTIFYICONDATAA, 4, 4); + TEST_TYPE_SIZE (PNOTIFYICONDATAA, 4) + TEST_TYPE_ALIGN (PNOTIFYICONDATAA, 4) } static void test_pack_PNOTIFYICONDATAW(void) { /* PNOTIFYICONDATAW */ - TEST_TYPE(PNOTIFYICONDATAW, 4, 4); + TEST_TYPE_SIZE (PNOTIFYICONDATAW, 4) + TEST_TYPE_ALIGN (PNOTIFYICONDATAW, 4) } static void test_pack_PRINTEROP_FLAGS(void) { /* PRINTEROP_FLAGS */ - TEST_TYPE(PRINTEROP_FLAGS, 2, 2); - TEST_TYPE_UNSIGNED(PRINTEROP_FLAGS); + TEST_TYPE_SIZE (PRINTEROP_FLAGS, 2) + TEST_TYPE_ALIGN (PRINTEROP_FLAGS, 2) + TEST_TYPE_UNSIGNED(PRINTEROP_FLAGS) } static void test_pack_SHELLEXECUTEINFOA(void) { /* SHELLEXECUTEINFOA (pack 1) */ - TEST_FIELD(SHELLEXECUTEINFOA, DWORD, cbSize, 0, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, ULONG, fMask, 4, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, HWND, hwnd, 8, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpVerb, 12, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpFile, 16, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpParameters, 20, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpDirectory, 24, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, INT, nShow, 28, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, HINSTANCE, hInstApp, 32, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, LPVOID, lpIDList, 36, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpClass, 40, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, HKEY, hkeyClass, 44, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOA, DWORD, dwHotKey, 48, 4, 1); + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, cbSize, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, cbSize, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, cbSize, 0) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, fMask, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, fMask, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, fMask, 4) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, hwnd, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, hwnd, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, hwnd, 8) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, lpVerb, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, lpVerb, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, lpVerb, 12) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, lpFile, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, lpFile, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, lpFile, 16) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, lpParameters, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, lpParameters, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, lpParameters, 20) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, lpDirectory, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, lpDirectory, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, lpDirectory, 24) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, nShow, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, nShow, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, nShow, 28) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, hInstApp, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, hInstApp, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, hInstApp, 32) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, lpIDList, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, lpIDList, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, lpIDList, 36) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, lpClass, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, lpClass, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, lpClass, 40) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, hkeyClass, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, hkeyClass, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, hkeyClass, 44) + TEST_FIELD_SIZE (SHELLEXECUTEINFOA, dwHotKey, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOA, dwHotKey, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOA, dwHotKey, 48) } static void test_pack_SHELLEXECUTEINFOW(void) { /* SHELLEXECUTEINFOW (pack 1) */ - TEST_FIELD(SHELLEXECUTEINFOW, DWORD, cbSize, 0, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, ULONG, fMask, 4, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, HWND, hwnd, 8, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpVerb, 12, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpFile, 16, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpParameters, 20, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpDirectory, 24, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, INT, nShow, 28, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, HINSTANCE, hInstApp, 32, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, LPVOID, lpIDList, 36, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpClass, 40, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, HKEY, hkeyClass, 44, 4, 1); - TEST_FIELD(SHELLEXECUTEINFOW, DWORD, dwHotKey, 48, 4, 1); + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, cbSize, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, cbSize, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, cbSize, 0) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, fMask, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, fMask, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, fMask, 4) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, hwnd, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, hwnd, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, hwnd, 8) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, lpVerb, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, lpVerb, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, lpVerb, 12) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, lpFile, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, lpFile, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, lpFile, 16) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, lpParameters, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, lpParameters, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, lpParameters, 20) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, lpDirectory, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, lpDirectory, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, lpDirectory, 24) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, nShow, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, nShow, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, nShow, 28) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, hInstApp, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, hInstApp, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, hInstApp, 32) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, lpIDList, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, lpIDList, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, lpIDList, 36) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, lpClass, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, lpClass, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, lpClass, 40) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, hkeyClass, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, hkeyClass, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, hkeyClass, 44) + TEST_FIELD_SIZE (SHELLEXECUTEINFOW, dwHotKey, 4) + TEST_FIELD_ALIGN (SHELLEXECUTEINFOW, dwHotKey, 1) + TEST_FIELD_OFFSET(SHELLEXECUTEINFOW, dwHotKey, 48) } static void test_pack_SHFILEINFOA(void) { /* SHFILEINFOA (pack 1) */ - TEST_TYPE(SHFILEINFOA, 352, 1); - TEST_FIELD(SHFILEINFOA, HICON, hIcon, 0, 4, 1); - TEST_FIELD(SHFILEINFOA, int, iIcon, 4, 4, 1); - TEST_FIELD(SHFILEINFOA, DWORD, dwAttributes, 8, 4, 1); - TEST_FIELD(SHFILEINFOA, CHAR[MAX_PATH], szDisplayName, 12, 260, 1); - TEST_FIELD(SHFILEINFOA, CHAR[80], szTypeName, 272, 80, 1); + TEST_TYPE_SIZE (SHFILEINFOA, 352) + TEST_TYPE_ALIGN (SHFILEINFOA, 1) + TEST_FIELD_SIZE (SHFILEINFOA, hIcon, 4) + TEST_FIELD_ALIGN (SHFILEINFOA, hIcon, 1) + TEST_FIELD_OFFSET(SHFILEINFOA, hIcon, 0) + TEST_FIELD_SIZE (SHFILEINFOA, iIcon, 4) + TEST_FIELD_ALIGN (SHFILEINFOA, iIcon, 1) + TEST_FIELD_OFFSET(SHFILEINFOA, iIcon, 4) + TEST_FIELD_SIZE (SHFILEINFOA, dwAttributes, 4) + TEST_FIELD_ALIGN (SHFILEINFOA, dwAttributes, 1) + TEST_FIELD_OFFSET(SHFILEINFOA, dwAttributes, 8) + TEST_FIELD_SIZE (SHFILEINFOA, szDisplayName, 260) + TEST_FIELD_ALIGN (SHFILEINFOA, szDisplayName, 1) + TEST_FIELD_OFFSET(SHFILEINFOA, szDisplayName, 12) + TEST_FIELD_SIZE (SHFILEINFOA, szTypeName, 80) + TEST_FIELD_ALIGN (SHFILEINFOA, szTypeName, 1) + TEST_FIELD_OFFSET(SHFILEINFOA, szTypeName, 272) } static void test_pack_SHFILEINFOW(void) { /* SHFILEINFOW (pack 1) */ - TEST_TYPE(SHFILEINFOW, 692, 1); - TEST_FIELD(SHFILEINFOW, HICON, hIcon, 0, 4, 1); - TEST_FIELD(SHFILEINFOW, int, iIcon, 4, 4, 1); - TEST_FIELD(SHFILEINFOW, DWORD, dwAttributes, 8, 4, 1); - TEST_FIELD(SHFILEINFOW, WCHAR[MAX_PATH], szDisplayName, 12, 520, 1); - TEST_FIELD(SHFILEINFOW, WCHAR[80], szTypeName, 532, 160, 1); + TEST_TYPE_SIZE (SHFILEINFOW, 692) + TEST_TYPE_ALIGN (SHFILEINFOW, 1) + TEST_FIELD_SIZE (SHFILEINFOW, hIcon, 4) + TEST_FIELD_ALIGN (SHFILEINFOW, hIcon, 1) + TEST_FIELD_OFFSET(SHFILEINFOW, hIcon, 0) + TEST_FIELD_SIZE (SHFILEINFOW, iIcon, 4) + TEST_FIELD_ALIGN (SHFILEINFOW, iIcon, 1) + TEST_FIELD_OFFSET(SHFILEINFOW, iIcon, 4) + TEST_FIELD_SIZE (SHFILEINFOW, dwAttributes, 4) + TEST_FIELD_ALIGN (SHFILEINFOW, dwAttributes, 1) + TEST_FIELD_OFFSET(SHFILEINFOW, dwAttributes, 8) + TEST_FIELD_SIZE (SHFILEINFOW, szDisplayName, 520) + TEST_FIELD_ALIGN (SHFILEINFOW, szDisplayName, 1) + TEST_FIELD_OFFSET(SHFILEINFOW, szDisplayName, 12) + TEST_FIELD_SIZE (SHFILEINFOW, szTypeName, 160) + TEST_FIELD_ALIGN (SHFILEINFOW, szTypeName, 1) + TEST_FIELD_OFFSET(SHFILEINFOW, szTypeName, 532) } static void test_pack_SHFILEOPSTRUCTA(void) { /* SHFILEOPSTRUCTA (pack 1) */ - TEST_TYPE(SHFILEOPSTRUCTA, 30, 1); - TEST_FIELD(SHFILEOPSTRUCTA, HWND, hwnd, 0, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTA, UINT, wFunc, 4, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTA, LPCSTR, pFrom, 8, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTA, LPCSTR, pTo, 12, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTA, FILEOP_FLAGS, fFlags, 16, 2, 1); - TEST_FIELD(SHFILEOPSTRUCTA, BOOL, fAnyOperationsAborted, 18, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTA, LPVOID, hNameMappings, 22, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTA, LPCSTR, lpszProgressTitle, 26, 4, 1); + TEST_TYPE_SIZE (SHFILEOPSTRUCTA, 30) + TEST_TYPE_ALIGN (SHFILEOPSTRUCTA, 1) + TEST_FIELD_SIZE (SHFILEOPSTRUCTA, hwnd, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTA, hwnd, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTA, hwnd, 0) + TEST_FIELD_SIZE (SHFILEOPSTRUCTA, wFunc, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTA, wFunc, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTA, wFunc, 4) + TEST_FIELD_SIZE (SHFILEOPSTRUCTA, pFrom, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTA, pFrom, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTA, pFrom, 8) + TEST_FIELD_SIZE (SHFILEOPSTRUCTA, pTo, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTA, pTo, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTA, pTo, 12) + TEST_FIELD_SIZE (SHFILEOPSTRUCTA, fFlags, 2) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTA, fFlags, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTA, fFlags, 16) + TEST_FIELD_SIZE (SHFILEOPSTRUCTA, fAnyOperationsAborted, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTA, fAnyOperationsAborted, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTA, fAnyOperationsAborted, 18) + TEST_FIELD_SIZE (SHFILEOPSTRUCTA, hNameMappings, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTA, hNameMappings, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTA, hNameMappings, 22) + TEST_FIELD_SIZE (SHFILEOPSTRUCTA, lpszProgressTitle, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTA, lpszProgressTitle, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTA, lpszProgressTitle, 26) } static void test_pack_SHFILEOPSTRUCTW(void) { /* SHFILEOPSTRUCTW (pack 1) */ - TEST_TYPE(SHFILEOPSTRUCTW, 30, 1); - TEST_FIELD(SHFILEOPSTRUCTW, HWND, hwnd, 0, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTW, UINT, wFunc, 4, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTW, LPCWSTR, pFrom, 8, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTW, LPCWSTR, pTo, 12, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTW, FILEOP_FLAGS, fFlags, 16, 2, 1); - TEST_FIELD(SHFILEOPSTRUCTW, BOOL, fAnyOperationsAborted, 18, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTW, LPVOID, hNameMappings, 22, 4, 1); - TEST_FIELD(SHFILEOPSTRUCTW, LPCWSTR, lpszProgressTitle, 26, 4, 1); + TEST_TYPE_SIZE (SHFILEOPSTRUCTW, 30) + TEST_TYPE_ALIGN (SHFILEOPSTRUCTW, 1) + TEST_FIELD_SIZE (SHFILEOPSTRUCTW, hwnd, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTW, hwnd, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTW, hwnd, 0) + TEST_FIELD_SIZE (SHFILEOPSTRUCTW, wFunc, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTW, wFunc, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTW, wFunc, 4) + TEST_FIELD_SIZE (SHFILEOPSTRUCTW, pFrom, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTW, pFrom, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTW, pFrom, 8) + TEST_FIELD_SIZE (SHFILEOPSTRUCTW, pTo, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTW, pTo, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTW, pTo, 12) + TEST_FIELD_SIZE (SHFILEOPSTRUCTW, fFlags, 2) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTW, fFlags, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTW, fFlags, 16) + TEST_FIELD_SIZE (SHFILEOPSTRUCTW, fAnyOperationsAborted, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTW, fAnyOperationsAborted, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTW, fAnyOperationsAborted, 18) + TEST_FIELD_SIZE (SHFILEOPSTRUCTW, hNameMappings, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTW, hNameMappings, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTW, hNameMappings, 22) + TEST_FIELD_SIZE (SHFILEOPSTRUCTW, lpszProgressTitle, 4) + TEST_FIELD_ALIGN (SHFILEOPSTRUCTW, lpszProgressTitle, 1) + TEST_FIELD_OFFSET(SHFILEOPSTRUCTW, lpszProgressTitle, 26) } static void test_pack_SHNAMEMAPPINGA(void) { /* SHNAMEMAPPINGA (pack 1) */ - TEST_TYPE(SHNAMEMAPPINGA, 16, 1); - TEST_FIELD(SHNAMEMAPPINGA, LPSTR, pszOldPath, 0, 4, 1); - TEST_FIELD(SHNAMEMAPPINGA, LPSTR, pszNewPath, 4, 4, 1); - TEST_FIELD(SHNAMEMAPPINGA, int, cchOldPath, 8, 4, 1); - TEST_FIELD(SHNAMEMAPPINGA, int, cchNewPath, 12, 4, 1); + TEST_TYPE_SIZE (SHNAMEMAPPINGA, 16) + TEST_TYPE_ALIGN (SHNAMEMAPPINGA, 1) + TEST_FIELD_SIZE (SHNAMEMAPPINGA, pszOldPath, 4) + TEST_FIELD_ALIGN (SHNAMEMAPPINGA, pszOldPath, 1) + TEST_FIELD_OFFSET(SHNAMEMAPPINGA, pszOldPath, 0) + TEST_FIELD_SIZE (SHNAMEMAPPINGA, pszNewPath, 4) + TEST_FIELD_ALIGN (SHNAMEMAPPINGA, pszNewPath, 1) + TEST_FIELD_OFFSET(SHNAMEMAPPINGA, pszNewPath, 4) + TEST_FIELD_SIZE (SHNAMEMAPPINGA, cchOldPath, 4) + TEST_FIELD_ALIGN (SHNAMEMAPPINGA, cchOldPath, 1) + TEST_FIELD_OFFSET(SHNAMEMAPPINGA, cchOldPath, 8) + TEST_FIELD_SIZE (SHNAMEMAPPINGA, cchNewPath, 4) + TEST_FIELD_ALIGN (SHNAMEMAPPINGA, cchNewPath, 1) + TEST_FIELD_OFFSET(SHNAMEMAPPINGA, cchNewPath, 12) } static void test_pack_SHNAMEMAPPINGW(void) { /* SHNAMEMAPPINGW (pack 1) */ - TEST_TYPE(SHNAMEMAPPINGW, 16, 1); - TEST_FIELD(SHNAMEMAPPINGW, LPWSTR, pszOldPath, 0, 4, 1); - TEST_FIELD(SHNAMEMAPPINGW, LPWSTR, pszNewPath, 4, 4, 1); - TEST_FIELD(SHNAMEMAPPINGW, int, cchOldPath, 8, 4, 1); - TEST_FIELD(SHNAMEMAPPINGW, int, cchNewPath, 12, 4, 1); + TEST_TYPE_SIZE (SHNAMEMAPPINGW, 16) + TEST_TYPE_ALIGN (SHNAMEMAPPINGW, 1) + TEST_FIELD_SIZE (SHNAMEMAPPINGW, pszOldPath, 4) + TEST_FIELD_ALIGN (SHNAMEMAPPINGW, pszOldPath, 1) + TEST_FIELD_OFFSET(SHNAMEMAPPINGW, pszOldPath, 0) + TEST_FIELD_SIZE (SHNAMEMAPPINGW, pszNewPath, 4) + TEST_FIELD_ALIGN (SHNAMEMAPPINGW, pszNewPath, 1) + TEST_FIELD_OFFSET(SHNAMEMAPPINGW, pszNewPath, 4) + TEST_FIELD_SIZE (SHNAMEMAPPINGW, cchOldPath, 4) + TEST_FIELD_ALIGN (SHNAMEMAPPINGW, cchOldPath, 1) + TEST_FIELD_OFFSET(SHNAMEMAPPINGW, cchOldPath, 8) + TEST_FIELD_SIZE (SHNAMEMAPPINGW, cchNewPath, 4) + TEST_FIELD_ALIGN (SHNAMEMAPPINGW, cchNewPath, 1) + TEST_FIELD_OFFSET(SHNAMEMAPPINGW, cchNewPath, 12) } static void test_pack_ITEMIDLIST(void) { /* ITEMIDLIST (pack 1) */ - TEST_TYPE(ITEMIDLIST, 3, 1); - TEST_FIELD(ITEMIDLIST, SHITEMID, mkid, 0, 3, 1); + TEST_TYPE_SIZE (ITEMIDLIST, 3) + TEST_TYPE_ALIGN (ITEMIDLIST, 1) + TEST_FIELD_SIZE (ITEMIDLIST, mkid, 3) + TEST_FIELD_ALIGN (ITEMIDLIST, mkid, 1) + TEST_FIELD_OFFSET(ITEMIDLIST, mkid, 0) } static void test_pack_LPCITEMIDLIST(void) { /* LPCITEMIDLIST */ - TEST_TYPE(LPCITEMIDLIST, 4, 4); - TEST_TYPE_POINTER(LPCITEMIDLIST, 3, 1); + TEST_TYPE_SIZE (LPCITEMIDLIST, 4) + TEST_TYPE_ALIGN (LPCITEMIDLIST, 4) + TEST_TARGET_SIZE (LPCITEMIDLIST, 3) + TEST_TARGET_ALIGN(LPCITEMIDLIST, 1) } static void test_pack_LPCSHITEMID(void) { /* LPCSHITEMID */ - TEST_TYPE(LPCSHITEMID, 4, 4); - TEST_TYPE_POINTER(LPCSHITEMID, 3, 1); + TEST_TYPE_SIZE (LPCSHITEMID, 4) + TEST_TYPE_ALIGN (LPCSHITEMID, 4) + TEST_TARGET_SIZE (LPCSHITEMID, 3) + TEST_TARGET_ALIGN(LPCSHITEMID, 1) } static void test_pack_LPITEMIDLIST(void) { /* LPITEMIDLIST */ - TEST_TYPE(LPITEMIDLIST, 4, 4); + TEST_TYPE_SIZE (LPITEMIDLIST, 4) + TEST_TYPE_ALIGN (LPITEMIDLIST, 4) } static void test_pack_LPSHELLDETAILS(void) { /* LPSHELLDETAILS */ - TEST_TYPE(LPSHELLDETAILS, 4, 4); + TEST_TYPE_SIZE (LPSHELLDETAILS, 4) + TEST_TYPE_ALIGN (LPSHELLDETAILS, 4) } static void test_pack_LPSHITEMID(void) { /* LPSHITEMID */ - TEST_TYPE(LPSHITEMID, 4, 4); + TEST_TYPE_SIZE (LPSHITEMID, 4) + TEST_TYPE_ALIGN (LPSHITEMID, 4) } static void test_pack_LPSTRRET(void) { /* LPSTRRET */ - TEST_TYPE(LPSTRRET, 4, 4); + TEST_TYPE_SIZE (LPSTRRET, 4) + TEST_TYPE_ALIGN (LPSTRRET, 4) } static void test_pack_SHELLDETAILS(void) { /* SHELLDETAILS (pack 1) */ - TEST_FIELD(SHELLDETAILS, int, fmt, 0, 4, 1); - TEST_FIELD(SHELLDETAILS, int, cxChar, 4, 4, 1); + TEST_FIELD_SIZE (SHELLDETAILS, fmt, 4) + TEST_FIELD_ALIGN (SHELLDETAILS, fmt, 1) + TEST_FIELD_OFFSET(SHELLDETAILS, fmt, 0) + TEST_FIELD_SIZE (SHELLDETAILS, cxChar, 4) + TEST_FIELD_ALIGN (SHELLDETAILS, cxChar, 1) + TEST_FIELD_OFFSET(SHELLDETAILS, cxChar, 4) } static void test_pack_SHITEMID(void) { /* SHITEMID (pack 1) */ - TEST_TYPE(SHITEMID, 3, 1); - TEST_FIELD(SHITEMID, WORD, cb, 0, 2, 1); - TEST_FIELD(SHITEMID, BYTE[1], abID, 2, 1, 1); + TEST_TYPE_SIZE (SHITEMID, 3) + TEST_TYPE_ALIGN (SHITEMID, 1) + TEST_FIELD_SIZE (SHITEMID, cb, 2) + TEST_FIELD_ALIGN (SHITEMID, cb, 1) + TEST_FIELD_OFFSET(SHITEMID, cb, 0) + TEST_FIELD_SIZE (SHITEMID, abID, 1) + TEST_FIELD_ALIGN (SHITEMID, abID, 1) + TEST_FIELD_OFFSET(SHITEMID, abID, 2) } static void test_pack_STRRET(void) { /* STRRET (pack 4) */ - TEST_FIELD(STRRET, UINT, uType, 0, 4, 4); + TEST_FIELD_SIZE (STRRET, uType, 4) + TEST_FIELD_ALIGN (STRRET, uType, 4) + TEST_FIELD_OFFSET(STRRET, uType, 0) } static void test_pack_AUTO_SCROLL_DATA(void) { /* AUTO_SCROLL_DATA (pack 1) */ - TEST_TYPE(AUTO_SCROLL_DATA, 48, 1); - TEST_FIELD(AUTO_SCROLL_DATA, int, iNextSample, 0, 4, 1); - TEST_FIELD(AUTO_SCROLL_DATA, DWORD, dwLastScroll, 4, 4, 1); - TEST_FIELD(AUTO_SCROLL_DATA, BOOL, bFull, 8, 4, 1); - TEST_FIELD(AUTO_SCROLL_DATA, POINT[NUM_POINTS], pts, 12, 24, 1); - TEST_FIELD(AUTO_SCROLL_DATA, DWORD[NUM_POINTS], dwTimes, 36, 12, 1); + TEST_TYPE_SIZE (AUTO_SCROLL_DATA, 48) + TEST_TYPE_ALIGN (AUTO_SCROLL_DATA, 1) + TEST_FIELD_SIZE (AUTO_SCROLL_DATA, iNextSample, 4) + TEST_FIELD_ALIGN (AUTO_SCROLL_DATA, iNextSample, 1) + TEST_FIELD_OFFSET(AUTO_SCROLL_DATA, iNextSample, 0) + TEST_FIELD_SIZE (AUTO_SCROLL_DATA, dwLastScroll, 4) + TEST_FIELD_ALIGN (AUTO_SCROLL_DATA, dwLastScroll, 1) + TEST_FIELD_OFFSET(AUTO_SCROLL_DATA, dwLastScroll, 4) + TEST_FIELD_SIZE (AUTO_SCROLL_DATA, bFull, 4) + TEST_FIELD_ALIGN (AUTO_SCROLL_DATA, bFull, 1) + TEST_FIELD_OFFSET(AUTO_SCROLL_DATA, bFull, 8) + TEST_FIELD_SIZE (AUTO_SCROLL_DATA, pts, 24) + TEST_FIELD_ALIGN (AUTO_SCROLL_DATA, pts, 1) + TEST_FIELD_OFFSET(AUTO_SCROLL_DATA, pts, 12) + TEST_FIELD_SIZE (AUTO_SCROLL_DATA, dwTimes, 12) + TEST_FIELD_ALIGN (AUTO_SCROLL_DATA, dwTimes, 1) + TEST_FIELD_OFFSET(AUTO_SCROLL_DATA, dwTimes, 36) } static void test_pack_BFFCALLBACK(void) { /* BFFCALLBACK */ - TEST_TYPE(BFFCALLBACK, 4, 4); + TEST_TYPE_SIZE (BFFCALLBACK, 4) + TEST_TYPE_ALIGN (BFFCALLBACK, 4) } static void test_pack_BROWSEINFOA(void) { /* BROWSEINFOA (pack 8) */ - TEST_TYPE(BROWSEINFOA, 32, 4); - TEST_FIELD(BROWSEINFOA, HWND, hwndOwner, 0, 4, 4); - TEST_FIELD(BROWSEINFOA, LPCITEMIDLIST, pidlRoot, 4, 4, 4); - TEST_FIELD(BROWSEINFOA, LPSTR, pszDisplayName, 8, 4, 4); - TEST_FIELD(BROWSEINFOA, LPCSTR, lpszTitle, 12, 4, 4); - TEST_FIELD(BROWSEINFOA, UINT, ulFlags, 16, 4, 4); - TEST_FIELD(BROWSEINFOA, BFFCALLBACK, lpfn, 20, 4, 4); - TEST_FIELD(BROWSEINFOA, LPARAM, lParam, 24, 4, 4); - TEST_FIELD(BROWSEINFOA, INT, iImage, 28, 4, 4); + TEST_TYPE_SIZE (BROWSEINFOA, 32) + TEST_TYPE_ALIGN (BROWSEINFOA, 4) + TEST_FIELD_SIZE (BROWSEINFOA, hwndOwner, 4) + TEST_FIELD_ALIGN (BROWSEINFOA, hwndOwner, 4) + TEST_FIELD_OFFSET(BROWSEINFOA, hwndOwner, 0) + TEST_FIELD_SIZE (BROWSEINFOA, pidlRoot, 4) + TEST_FIELD_ALIGN (BROWSEINFOA, pidlRoot, 4) + TEST_FIELD_OFFSET(BROWSEINFOA, pidlRoot, 4) + TEST_FIELD_SIZE (BROWSEINFOA, pszDisplayName, 4) + TEST_FIELD_ALIGN (BROWSEINFOA, pszDisplayName, 4) + TEST_FIELD_OFFSET(BROWSEINFOA, pszDisplayName, 8) + TEST_FIELD_SIZE (BROWSEINFOA, lpszTitle, 4) + TEST_FIELD_ALIGN (BROWSEINFOA, lpszTitle, 4) + TEST_FIELD_OFFSET(BROWSEINFOA, lpszTitle, 12) + TEST_FIELD_SIZE (BROWSEINFOA, ulFlags, 4) + TEST_FIELD_ALIGN (BROWSEINFOA, ulFlags, 4) + TEST_FIELD_OFFSET(BROWSEINFOA, ulFlags, 16) + TEST_FIELD_SIZE (BROWSEINFOA, lpfn, 4) + TEST_FIELD_ALIGN (BROWSEINFOA, lpfn, 4) + TEST_FIELD_OFFSET(BROWSEINFOA, lpfn, 20) + TEST_FIELD_SIZE (BROWSEINFOA, lParam, 4) + TEST_FIELD_ALIGN (BROWSEINFOA, lParam, 4) + TEST_FIELD_OFFSET(BROWSEINFOA, lParam, 24) + TEST_FIELD_SIZE (BROWSEINFOA, iImage, 4) + TEST_FIELD_ALIGN (BROWSEINFOA, iImage, 4) + TEST_FIELD_OFFSET(BROWSEINFOA, iImage, 28) } static void test_pack_BROWSEINFOW(void) { /* BROWSEINFOW (pack 8) */ - TEST_TYPE(BROWSEINFOW, 32, 4); - TEST_FIELD(BROWSEINFOW, HWND, hwndOwner, 0, 4, 4); - TEST_FIELD(BROWSEINFOW, LPCITEMIDLIST, pidlRoot, 4, 4, 4); - TEST_FIELD(BROWSEINFOW, LPWSTR, pszDisplayName, 8, 4, 4); - TEST_FIELD(BROWSEINFOW, LPCWSTR, lpszTitle, 12, 4, 4); - TEST_FIELD(BROWSEINFOW, UINT, ulFlags, 16, 4, 4); - TEST_FIELD(BROWSEINFOW, BFFCALLBACK, lpfn, 20, 4, 4); - TEST_FIELD(BROWSEINFOW, LPARAM, lParam, 24, 4, 4); - TEST_FIELD(BROWSEINFOW, INT, iImage, 28, 4, 4); + TEST_TYPE_SIZE (BROWSEINFOW, 32) + TEST_TYPE_ALIGN (BROWSEINFOW, 4) + TEST_FIELD_SIZE (BROWSEINFOW, hwndOwner, 4) + TEST_FIELD_ALIGN (BROWSEINFOW, hwndOwner, 4) + TEST_FIELD_OFFSET(BROWSEINFOW, hwndOwner, 0) + TEST_FIELD_SIZE (BROWSEINFOW, pidlRoot, 4) + TEST_FIELD_ALIGN (BROWSEINFOW, pidlRoot, 4) + TEST_FIELD_OFFSET(BROWSEINFOW, pidlRoot, 4) + TEST_FIELD_SIZE (BROWSEINFOW, pszDisplayName, 4) + TEST_FIELD_ALIGN (BROWSEINFOW, pszDisplayName, 4) + TEST_FIELD_OFFSET(BROWSEINFOW, pszDisplayName, 8) + TEST_FIELD_SIZE (BROWSEINFOW, lpszTitle, 4) + TEST_FIELD_ALIGN (BROWSEINFOW, lpszTitle, 4) + TEST_FIELD_OFFSET(BROWSEINFOW, lpszTitle, 12) + TEST_FIELD_SIZE (BROWSEINFOW, ulFlags, 4) + TEST_FIELD_ALIGN (BROWSEINFOW, ulFlags, 4) + TEST_FIELD_OFFSET(BROWSEINFOW, ulFlags, 16) + TEST_FIELD_SIZE (BROWSEINFOW, lpfn, 4) + TEST_FIELD_ALIGN (BROWSEINFOW, lpfn, 4) + TEST_FIELD_OFFSET(BROWSEINFOW, lpfn, 20) + TEST_FIELD_SIZE (BROWSEINFOW, lParam, 4) + TEST_FIELD_ALIGN (BROWSEINFOW, lParam, 4) + TEST_FIELD_OFFSET(BROWSEINFOW, lParam, 24) + TEST_FIELD_SIZE (BROWSEINFOW, iImage, 4) + TEST_FIELD_ALIGN (BROWSEINFOW, iImage, 4) + TEST_FIELD_OFFSET(BROWSEINFOW, iImage, 28) } static void test_pack_CABINETSTATE(void) { /* CABINETSTATE (pack 1) */ - TEST_TYPE(CABINETSTATE, 12, 1); - TEST_FIELD(CABINETSTATE, WORD, cLength, 0, 2, 1); - TEST_FIELD(CABINETSTATE, WORD, nVersion, 2, 2, 1); - TEST_FIELD(CABINETSTATE, UINT, fMenuEnumFilter, 8, 4, 1); + TEST_TYPE_SIZE (CABINETSTATE, 12) + TEST_TYPE_ALIGN (CABINETSTATE, 1) + TEST_FIELD_SIZE (CABINETSTATE, cLength, 2) + TEST_FIELD_ALIGN (CABINETSTATE, cLength, 1) + TEST_FIELD_OFFSET(CABINETSTATE, cLength, 0) + TEST_FIELD_SIZE (CABINETSTATE, nVersion, 2) + TEST_FIELD_ALIGN (CABINETSTATE, nVersion, 1) + TEST_FIELD_OFFSET(CABINETSTATE, nVersion, 2) + TEST_FIELD_SIZE (CABINETSTATE, fMenuEnumFilter, 4) + TEST_FIELD_ALIGN (CABINETSTATE, fMenuEnumFilter, 1) + TEST_FIELD_OFFSET(CABINETSTATE, fMenuEnumFilter, 8) } static void test_pack_CIDA(void) { /* CIDA (pack 1) */ - TEST_TYPE(CIDA, 8, 1); - TEST_FIELD(CIDA, UINT, cidl, 0, 4, 1); - TEST_FIELD(CIDA, UINT[1], aoffset, 4, 4, 1); + TEST_TYPE_SIZE (CIDA, 8) + TEST_TYPE_ALIGN (CIDA, 1) + TEST_FIELD_SIZE (CIDA, cidl, 4) + TEST_FIELD_ALIGN (CIDA, cidl, 1) + TEST_FIELD_OFFSET(CIDA, cidl, 0) + TEST_FIELD_SIZE (CIDA, aoffset, 4) + TEST_FIELD_ALIGN (CIDA, aoffset, 1) + TEST_FIELD_OFFSET(CIDA, aoffset, 4) } static void test_pack_CSFV(void) { /* CSFV (pack 1) */ - TEST_FIELD(CSFV, UINT, cbSize, 0, 4, 1); - TEST_FIELD(CSFV, IShellFolder*, pshf, 4, 4, 1); - TEST_FIELD(CSFV, IShellView*, psvOuter, 8, 4, 1); - TEST_FIELD(CSFV, LPCITEMIDLIST, pidl, 12, 4, 1); - TEST_FIELD(CSFV, LONG, lEvents, 16, 4, 1); - TEST_FIELD(CSFV, LPFNVIEWCALLBACK, pfnCallback, 20, 4, 1); + TEST_FIELD_SIZE (CSFV, cbSize, 4) + TEST_FIELD_ALIGN (CSFV, cbSize, 1) + TEST_FIELD_OFFSET(CSFV, cbSize, 0) + TEST_FIELD_SIZE (CSFV, pshf, 4) + TEST_FIELD_ALIGN (CSFV, pshf, 1) + TEST_FIELD_OFFSET(CSFV, pshf, 4) + TEST_FIELD_SIZE (CSFV, psvOuter, 4) + TEST_FIELD_ALIGN (CSFV, psvOuter, 1) + TEST_FIELD_OFFSET(CSFV, psvOuter, 8) + TEST_FIELD_SIZE (CSFV, pidl, 4) + TEST_FIELD_ALIGN (CSFV, pidl, 1) + TEST_FIELD_OFFSET(CSFV, pidl, 12) + TEST_FIELD_SIZE (CSFV, lEvents, 4) + TEST_FIELD_ALIGN (CSFV, lEvents, 1) + TEST_FIELD_OFFSET(CSFV, lEvents, 16) + TEST_FIELD_SIZE (CSFV, pfnCallback, 4) + TEST_FIELD_ALIGN (CSFV, pfnCallback, 1) + TEST_FIELD_OFFSET(CSFV, pfnCallback, 20) } static void test_pack_DROPFILES(void) { /* DROPFILES (pack 1) */ - TEST_TYPE(DROPFILES, 20, 1); - TEST_FIELD(DROPFILES, DWORD, pFiles, 0, 4, 1); - TEST_FIELD(DROPFILES, POINT, pt, 4, 8, 1); - TEST_FIELD(DROPFILES, BOOL, fNC, 12, 4, 1); - TEST_FIELD(DROPFILES, BOOL, fWide, 16, 4, 1); + TEST_TYPE_SIZE (DROPFILES, 20) + TEST_TYPE_ALIGN (DROPFILES, 1) + TEST_FIELD_SIZE (DROPFILES, pFiles, 4) + TEST_FIELD_ALIGN (DROPFILES, pFiles, 1) + TEST_FIELD_OFFSET(DROPFILES, pFiles, 0) + TEST_FIELD_SIZE (DROPFILES, pt, 8) + TEST_FIELD_ALIGN (DROPFILES, pt, 1) + TEST_FIELD_OFFSET(DROPFILES, pt, 4) + TEST_FIELD_SIZE (DROPFILES, fNC, 4) + TEST_FIELD_ALIGN (DROPFILES, fNC, 1) + TEST_FIELD_OFFSET(DROPFILES, fNC, 12) + TEST_FIELD_SIZE (DROPFILES, fWide, 4) + TEST_FIELD_ALIGN (DROPFILES, fWide, 1) + TEST_FIELD_OFFSET(DROPFILES, fWide, 16) } static void test_pack_FILEDESCRIPTORA(void) { /* FILEDESCRIPTORA (pack 1) */ - TEST_TYPE(FILEDESCRIPTORA, 332, 1); - TEST_FIELD(FILEDESCRIPTORA, DWORD, dwFlags, 0, 4, 1); - TEST_FIELD(FILEDESCRIPTORA, CLSID, clsid, 4, 16, 1); - TEST_FIELD(FILEDESCRIPTORA, SIZEL, sizel, 20, 8, 1); - TEST_FIELD(FILEDESCRIPTORA, POINTL, pointl, 28, 8, 1); - TEST_FIELD(FILEDESCRIPTORA, DWORD, dwFileAttributes, 36, 4, 1); - TEST_FIELD(FILEDESCRIPTORA, FILETIME, ftCreationTime, 40, 8, 1); - TEST_FIELD(FILEDESCRIPTORA, FILETIME, ftLastAccessTime, 48, 8, 1); - TEST_FIELD(FILEDESCRIPTORA, FILETIME, ftLastWriteTime, 56, 8, 1); - TEST_FIELD(FILEDESCRIPTORA, DWORD, nFileSizeHigh, 64, 4, 1); - TEST_FIELD(FILEDESCRIPTORA, DWORD, nFileSizeLow, 68, 4, 1); - TEST_FIELD(FILEDESCRIPTORA, CHAR[MAX_PATH], cFileName, 72, 260, 1); + TEST_TYPE_SIZE (FILEDESCRIPTORA, 332) + TEST_TYPE_ALIGN (FILEDESCRIPTORA, 1) + TEST_FIELD_SIZE (FILEDESCRIPTORA, dwFlags, 4) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, dwFlags, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, dwFlags, 0) + TEST_FIELD_SIZE (FILEDESCRIPTORA, clsid, 16) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, clsid, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, clsid, 4) + TEST_FIELD_SIZE (FILEDESCRIPTORA, sizel, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, sizel, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, sizel, 20) + TEST_FIELD_SIZE (FILEDESCRIPTORA, pointl, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, pointl, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, pointl, 28) + TEST_FIELD_SIZE (FILEDESCRIPTORA, dwFileAttributes, 4) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, dwFileAttributes, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, dwFileAttributes, 36) + TEST_FIELD_SIZE (FILEDESCRIPTORA, ftCreationTime, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, ftCreationTime, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, ftCreationTime, 40) + TEST_FIELD_SIZE (FILEDESCRIPTORA, ftLastAccessTime, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, ftLastAccessTime, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, ftLastAccessTime, 48) + TEST_FIELD_SIZE (FILEDESCRIPTORA, ftLastWriteTime, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, ftLastWriteTime, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, ftLastWriteTime, 56) + TEST_FIELD_SIZE (FILEDESCRIPTORA, nFileSizeHigh, 4) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, nFileSizeHigh, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, nFileSizeHigh, 64) + TEST_FIELD_SIZE (FILEDESCRIPTORA, nFileSizeLow, 4) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, nFileSizeLow, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, nFileSizeLow, 68) + TEST_FIELD_SIZE (FILEDESCRIPTORA, cFileName, 260) + TEST_FIELD_ALIGN (FILEDESCRIPTORA, cFileName, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORA, cFileName, 72) } static void test_pack_FILEDESCRIPTORW(void) { /* FILEDESCRIPTORW (pack 1) */ - TEST_TYPE(FILEDESCRIPTORW, 592, 1); - TEST_FIELD(FILEDESCRIPTORW, DWORD, dwFlags, 0, 4, 1); - TEST_FIELD(FILEDESCRIPTORW, CLSID, clsid, 4, 16, 1); - TEST_FIELD(FILEDESCRIPTORW, SIZEL, sizel, 20, 8, 1); - TEST_FIELD(FILEDESCRIPTORW, POINTL, pointl, 28, 8, 1); - TEST_FIELD(FILEDESCRIPTORW, DWORD, dwFileAttributes, 36, 4, 1); - TEST_FIELD(FILEDESCRIPTORW, FILETIME, ftCreationTime, 40, 8, 1); - TEST_FIELD(FILEDESCRIPTORW, FILETIME, ftLastAccessTime, 48, 8, 1); - TEST_FIELD(FILEDESCRIPTORW, FILETIME, ftLastWriteTime, 56, 8, 1); - TEST_FIELD(FILEDESCRIPTORW, DWORD, nFileSizeHigh, 64, 4, 1); - TEST_FIELD(FILEDESCRIPTORW, DWORD, nFileSizeLow, 68, 4, 1); - TEST_FIELD(FILEDESCRIPTORW, WCHAR[MAX_PATH], cFileName, 72, 520, 1); + TEST_TYPE_SIZE (FILEDESCRIPTORW, 592) + TEST_TYPE_ALIGN (FILEDESCRIPTORW, 1) + TEST_FIELD_SIZE (FILEDESCRIPTORW, dwFlags, 4) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, dwFlags, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, dwFlags, 0) + TEST_FIELD_SIZE (FILEDESCRIPTORW, clsid, 16) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, clsid, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, clsid, 4) + TEST_FIELD_SIZE (FILEDESCRIPTORW, sizel, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, sizel, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, sizel, 20) + TEST_FIELD_SIZE (FILEDESCRIPTORW, pointl, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, pointl, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, pointl, 28) + TEST_FIELD_SIZE (FILEDESCRIPTORW, dwFileAttributes, 4) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, dwFileAttributes, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, dwFileAttributes, 36) + TEST_FIELD_SIZE (FILEDESCRIPTORW, ftCreationTime, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, ftCreationTime, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, ftCreationTime, 40) + TEST_FIELD_SIZE (FILEDESCRIPTORW, ftLastAccessTime, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, ftLastAccessTime, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, ftLastAccessTime, 48) + TEST_FIELD_SIZE (FILEDESCRIPTORW, ftLastWriteTime, 8) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, ftLastWriteTime, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, ftLastWriteTime, 56) + TEST_FIELD_SIZE (FILEDESCRIPTORW, nFileSizeHigh, 4) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, nFileSizeHigh, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, nFileSizeHigh, 64) + TEST_FIELD_SIZE (FILEDESCRIPTORW, nFileSizeLow, 4) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, nFileSizeLow, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, nFileSizeLow, 68) + TEST_FIELD_SIZE (FILEDESCRIPTORW, cFileName, 520) + TEST_FIELD_ALIGN (FILEDESCRIPTORW, cFileName, 1) + TEST_FIELD_OFFSET(FILEDESCRIPTORW, cFileName, 72) } static void test_pack_FILEGROUPDESCRIPTORA(void) { /* FILEGROUPDESCRIPTORA (pack 1) */ - TEST_TYPE(FILEGROUPDESCRIPTORA, 336, 1); - TEST_FIELD(FILEGROUPDESCRIPTORA, UINT, cItems, 0, 4, 1); - TEST_FIELD(FILEGROUPDESCRIPTORA, FILEDESCRIPTORA[1], fgd, 4, 332, 1); + TEST_TYPE_SIZE (FILEGROUPDESCRIPTORA, 336) + TEST_TYPE_ALIGN (FILEGROUPDESCRIPTORA, 1) + TEST_FIELD_SIZE (FILEGROUPDESCRIPTORA, cItems, 4) + TEST_FIELD_ALIGN (FILEGROUPDESCRIPTORA, cItems, 1) + TEST_FIELD_OFFSET(FILEGROUPDESCRIPTORA, cItems, 0) + TEST_FIELD_SIZE (FILEGROUPDESCRIPTORA, fgd, 332) + TEST_FIELD_ALIGN (FILEGROUPDESCRIPTORA, fgd, 1) + TEST_FIELD_OFFSET(FILEGROUPDESCRIPTORA, fgd, 4) } static void test_pack_FILEGROUPDESCRIPTORW(void) { /* FILEGROUPDESCRIPTORW (pack 1) */ - TEST_TYPE(FILEGROUPDESCRIPTORW, 596, 1); - TEST_FIELD(FILEGROUPDESCRIPTORW, UINT, cItems, 0, 4, 1); - TEST_FIELD(FILEGROUPDESCRIPTORW, FILEDESCRIPTORW[1], fgd, 4, 592, 1); + TEST_TYPE_SIZE (FILEGROUPDESCRIPTORW, 596) + TEST_TYPE_ALIGN (FILEGROUPDESCRIPTORW, 1) + TEST_FIELD_SIZE (FILEGROUPDESCRIPTORW, cItems, 4) + TEST_FIELD_ALIGN (FILEGROUPDESCRIPTORW, cItems, 1) + TEST_FIELD_OFFSET(FILEGROUPDESCRIPTORW, cItems, 0) + TEST_FIELD_SIZE (FILEGROUPDESCRIPTORW, fgd, 592) + TEST_FIELD_ALIGN (FILEGROUPDESCRIPTORW, fgd, 1) + TEST_FIELD_OFFSET(FILEGROUPDESCRIPTORW, fgd, 4) } static void test_pack_LPBROWSEINFOA(void) { /* LPBROWSEINFOA */ - TEST_TYPE(LPBROWSEINFOA, 4, 4); - TEST_TYPE_POINTER(LPBROWSEINFOA, 32, 4); + TEST_TYPE_SIZE (LPBROWSEINFOA, 4) + TEST_TYPE_ALIGN (LPBROWSEINFOA, 4) + TEST_TARGET_SIZE (LPBROWSEINFOA, 32) + TEST_TARGET_ALIGN(LPBROWSEINFOA, 4) } static void test_pack_LPBROWSEINFOW(void) { /* LPBROWSEINFOW */ - TEST_TYPE(LPBROWSEINFOW, 4, 4); - TEST_TYPE_POINTER(LPBROWSEINFOW, 32, 4); + TEST_TYPE_SIZE (LPBROWSEINFOW, 4) + TEST_TYPE_ALIGN (LPBROWSEINFOW, 4) + TEST_TARGET_SIZE (LPBROWSEINFOW, 32) + TEST_TARGET_ALIGN(LPBROWSEINFOW, 4) } static void test_pack_LPCABINETSTATE(void) { /* LPCABINETSTATE */ - TEST_TYPE(LPCABINETSTATE, 4, 4); - TEST_TYPE_POINTER(LPCABINETSTATE, 12, 1); + TEST_TYPE_SIZE (LPCABINETSTATE, 4) + TEST_TYPE_ALIGN (LPCABINETSTATE, 4) + TEST_TARGET_SIZE (LPCABINETSTATE, 12) + TEST_TARGET_ALIGN(LPCABINETSTATE, 1) } static void test_pack_LPCSFV(void) { /* LPCSFV */ - TEST_TYPE(LPCSFV, 4, 4); + TEST_TYPE_SIZE (LPCSFV, 4) + TEST_TYPE_ALIGN (LPCSFV, 4) } static void test_pack_LPDROPFILES(void) { /* LPDROPFILES */ - TEST_TYPE(LPDROPFILES, 4, 4); - TEST_TYPE_POINTER(LPDROPFILES, 20, 1); + TEST_TYPE_SIZE (LPDROPFILES, 4) + TEST_TYPE_ALIGN (LPDROPFILES, 4) + TEST_TARGET_SIZE (LPDROPFILES, 20) + TEST_TARGET_ALIGN(LPDROPFILES, 1) } static void test_pack_LPFILEDESCRIPTORA(void) { /* LPFILEDESCRIPTORA */ - TEST_TYPE(LPFILEDESCRIPTORA, 4, 4); - TEST_TYPE_POINTER(LPFILEDESCRIPTORA, 332, 1); + TEST_TYPE_SIZE (LPFILEDESCRIPTORA, 4) + TEST_TYPE_ALIGN (LPFILEDESCRIPTORA, 4) + TEST_TARGET_SIZE (LPFILEDESCRIPTORA, 332) + TEST_TARGET_ALIGN(LPFILEDESCRIPTORA, 1) } static void test_pack_LPFILEDESCRIPTORW(void) { /* LPFILEDESCRIPTORW */ - TEST_TYPE(LPFILEDESCRIPTORW, 4, 4); - TEST_TYPE_POINTER(LPFILEDESCRIPTORW, 592, 1); + TEST_TYPE_SIZE (LPFILEDESCRIPTORW, 4) + TEST_TYPE_ALIGN (LPFILEDESCRIPTORW, 4) + TEST_TARGET_SIZE (LPFILEDESCRIPTORW, 592) + TEST_TARGET_ALIGN(LPFILEDESCRIPTORW, 1) } static void test_pack_LPFILEGROUPDESCRIPTORA(void) { /* LPFILEGROUPDESCRIPTORA */ - TEST_TYPE(LPFILEGROUPDESCRIPTORA, 4, 4); - TEST_TYPE_POINTER(LPFILEGROUPDESCRIPTORA, 336, 1); + TEST_TYPE_SIZE (LPFILEGROUPDESCRIPTORA, 4) + TEST_TYPE_ALIGN (LPFILEGROUPDESCRIPTORA, 4) + TEST_TARGET_SIZE (LPFILEGROUPDESCRIPTORA, 336) + TEST_TARGET_ALIGN(LPFILEGROUPDESCRIPTORA, 1) } static void test_pack_LPFILEGROUPDESCRIPTORW(void) { /* LPFILEGROUPDESCRIPTORW */ - TEST_TYPE(LPFILEGROUPDESCRIPTORW, 4, 4); - TEST_TYPE_POINTER(LPFILEGROUPDESCRIPTORW, 596, 1); + TEST_TYPE_SIZE (LPFILEGROUPDESCRIPTORW, 4) + TEST_TYPE_ALIGN (LPFILEGROUPDESCRIPTORW, 4) + TEST_TARGET_SIZE (LPFILEGROUPDESCRIPTORW, 596) + TEST_TARGET_ALIGN(LPFILEGROUPDESCRIPTORW, 1) } static void test_pack_LPFNVIEWCALLBACK(void) { /* LPFNVIEWCALLBACK */ - TEST_TYPE(LPFNVIEWCALLBACK, 4, 4); + TEST_TYPE_SIZE (LPFNVIEWCALLBACK, 4) + TEST_TYPE_ALIGN (LPFNVIEWCALLBACK, 4) } static void test_pack_LPIDA(void) { /* LPIDA */ - TEST_TYPE(LPIDA, 4, 4); - TEST_TYPE_POINTER(LPIDA, 8, 1); + TEST_TYPE_SIZE (LPIDA, 4) + TEST_TYPE_ALIGN (LPIDA, 4) + TEST_TARGET_SIZE (LPIDA, 8) + TEST_TARGET_ALIGN(LPIDA, 1) } static void test_pack_LPQCMINFO(void) { /* LPQCMINFO */ - TEST_TYPE(LPQCMINFO, 4, 4); - TEST_TYPE_POINTER(LPQCMINFO, 20, 4); + TEST_TYPE_SIZE (LPQCMINFO, 4) + TEST_TYPE_ALIGN (LPQCMINFO, 4) + TEST_TARGET_SIZE (LPQCMINFO, 20) + TEST_TARGET_ALIGN(LPQCMINFO, 4) } static void test_pack_LPSHChangeDWORDAsIDList(void) { /* LPSHChangeDWORDAsIDList */ - TEST_TYPE(LPSHChangeDWORDAsIDList, 4, 4); - TEST_TYPE_POINTER(LPSHChangeDWORDAsIDList, 12, 1); + TEST_TYPE_SIZE (LPSHChangeDWORDAsIDList, 4) + TEST_TYPE_ALIGN (LPSHChangeDWORDAsIDList, 4) + TEST_TARGET_SIZE (LPSHChangeDWORDAsIDList, 12) + TEST_TARGET_ALIGN(LPSHChangeDWORDAsIDList, 1) } static void test_pack_LPSHChangeProductKeyAsIDList(void) { /* LPSHChangeProductKeyAsIDList */ - TEST_TYPE(LPSHChangeProductKeyAsIDList, 4, 4); - TEST_TYPE_POINTER(LPSHChangeProductKeyAsIDList, 82, 1); + TEST_TYPE_SIZE (LPSHChangeProductKeyAsIDList, 4) + TEST_TYPE_ALIGN (LPSHChangeProductKeyAsIDList, 4) + TEST_TARGET_SIZE (LPSHChangeProductKeyAsIDList, 82) + TEST_TARGET_ALIGN(LPSHChangeProductKeyAsIDList, 1) } static void test_pack_LPSHDESCRIPTIONID(void) { /* LPSHDESCRIPTIONID */ - TEST_TYPE(LPSHDESCRIPTIONID, 4, 4); - TEST_TYPE_POINTER(LPSHDESCRIPTIONID, 20, 4); + TEST_TYPE_SIZE (LPSHDESCRIPTIONID, 4) + TEST_TYPE_ALIGN (LPSHDESCRIPTIONID, 4) + TEST_TARGET_SIZE (LPSHDESCRIPTIONID, 20) + TEST_TARGET_ALIGN(LPSHDESCRIPTIONID, 4) } static void test_pack_LPSHELLFLAGSTATE(void) { /* LPSHELLFLAGSTATE */ - TEST_TYPE(LPSHELLFLAGSTATE, 4, 4); - TEST_TYPE_POINTER(LPSHELLFLAGSTATE, 4, 1); + TEST_TYPE_SIZE (LPSHELLFLAGSTATE, 4) + TEST_TYPE_ALIGN (LPSHELLFLAGSTATE, 4) + TEST_TARGET_SIZE (LPSHELLFLAGSTATE, 4) + TEST_TARGET_ALIGN(LPSHELLFLAGSTATE, 1) } static void test_pack_LPSHELLSTATE(void) { /* LPSHELLSTATE */ - TEST_TYPE(LPSHELLSTATE, 4, 4); - TEST_TYPE_POINTER(LPSHELLSTATE, 32, 1); + TEST_TYPE_SIZE (LPSHELLSTATE, 4) + TEST_TYPE_ALIGN (LPSHELLSTATE, 4) + TEST_TARGET_SIZE (LPSHELLSTATE, 32) + TEST_TARGET_ALIGN(LPSHELLSTATE, 1) } static void test_pack_LPTBINFO(void) { /* LPTBINFO */ - TEST_TYPE(LPTBINFO, 4, 4); - TEST_TYPE_POINTER(LPTBINFO, 8, 4); + TEST_TYPE_SIZE (LPTBINFO, 4) + TEST_TYPE_ALIGN (LPTBINFO, 4) + TEST_TARGET_SIZE (LPTBINFO, 8) + TEST_TARGET_ALIGN(LPTBINFO, 4) } static void test_pack_PBROWSEINFOA(void) { /* PBROWSEINFOA */ - TEST_TYPE(PBROWSEINFOA, 4, 4); - TEST_TYPE_POINTER(PBROWSEINFOA, 32, 4); + TEST_TYPE_SIZE (PBROWSEINFOA, 4) + TEST_TYPE_ALIGN (PBROWSEINFOA, 4) + TEST_TARGET_SIZE (PBROWSEINFOA, 32) + TEST_TARGET_ALIGN(PBROWSEINFOA, 4) } static void test_pack_PBROWSEINFOW(void) { /* PBROWSEINFOW */ - TEST_TYPE(PBROWSEINFOW, 4, 4); - TEST_TYPE_POINTER(PBROWSEINFOW, 32, 4); + TEST_TYPE_SIZE (PBROWSEINFOW, 4) + TEST_TYPE_ALIGN (PBROWSEINFOW, 4) + TEST_TARGET_SIZE (PBROWSEINFOW, 32) + TEST_TARGET_ALIGN(PBROWSEINFOW, 4) } static void test_pack_QCMINFO(void) { /* QCMINFO (pack 8) */ - TEST_TYPE(QCMINFO, 20, 4); - TEST_FIELD(QCMINFO, HMENU, hmenu, 0, 4, 4); - TEST_FIELD(QCMINFO, UINT, indexMenu, 4, 4, 4); - TEST_FIELD(QCMINFO, UINT, idCmdFirst, 8, 4, 4); - TEST_FIELD(QCMINFO, UINT, idCmdLast, 12, 4, 4); - TEST_FIELD(QCMINFO, QCMINFO_IDMAP const*, pIdMap, 16, 4, 4); + TEST_TYPE_SIZE (QCMINFO, 20) + TEST_TYPE_ALIGN (QCMINFO, 4) + TEST_FIELD_SIZE (QCMINFO, hmenu, 4) + TEST_FIELD_ALIGN (QCMINFO, hmenu, 4) + TEST_FIELD_OFFSET(QCMINFO, hmenu, 0) + TEST_FIELD_SIZE (QCMINFO, indexMenu, 4) + TEST_FIELD_ALIGN (QCMINFO, indexMenu, 4) + TEST_FIELD_OFFSET(QCMINFO, indexMenu, 4) + TEST_FIELD_SIZE (QCMINFO, idCmdFirst, 4) + TEST_FIELD_ALIGN (QCMINFO, idCmdFirst, 4) + TEST_FIELD_OFFSET(QCMINFO, idCmdFirst, 8) + TEST_FIELD_SIZE (QCMINFO, idCmdLast, 4) + TEST_FIELD_ALIGN (QCMINFO, idCmdLast, 4) + TEST_FIELD_OFFSET(QCMINFO, idCmdLast, 12) + TEST_FIELD_SIZE (QCMINFO, pIdMap, 4) + TEST_FIELD_ALIGN (QCMINFO, pIdMap, 4) + TEST_FIELD_OFFSET(QCMINFO, pIdMap, 16) } static void test_pack_QCMINFO_IDMAP(void) { /* QCMINFO_IDMAP (pack 8) */ - TEST_TYPE(QCMINFO_IDMAP, 12, 4); - TEST_FIELD(QCMINFO_IDMAP, UINT, nMaxIds, 0, 4, 4); - TEST_FIELD(QCMINFO_IDMAP, QCMINFO_IDMAP_PLACEMENT[1], pIdList, 4, 8, 4); + TEST_TYPE_SIZE (QCMINFO_IDMAP, 12) + TEST_TYPE_ALIGN (QCMINFO_IDMAP, 4) + TEST_FIELD_SIZE (QCMINFO_IDMAP, nMaxIds, 4) + TEST_FIELD_ALIGN (QCMINFO_IDMAP, nMaxIds, 4) + TEST_FIELD_OFFSET(QCMINFO_IDMAP, nMaxIds, 0) + TEST_FIELD_SIZE (QCMINFO_IDMAP, pIdList, 8) + TEST_FIELD_ALIGN (QCMINFO_IDMAP, pIdList, 4) + TEST_FIELD_OFFSET(QCMINFO_IDMAP, pIdList, 4) } static void test_pack_QCMINFO_IDMAP_PLACEMENT(void) { /* QCMINFO_IDMAP_PLACEMENT (pack 8) */ - TEST_TYPE(QCMINFO_IDMAP_PLACEMENT, 8, 4); - TEST_FIELD(QCMINFO_IDMAP_PLACEMENT, UINT, id, 0, 4, 4); - TEST_FIELD(QCMINFO_IDMAP_PLACEMENT, UINT, fFlags, 4, 4, 4); + TEST_TYPE_SIZE (QCMINFO_IDMAP_PLACEMENT, 8) + TEST_TYPE_ALIGN (QCMINFO_IDMAP_PLACEMENT, 4) + TEST_FIELD_SIZE (QCMINFO_IDMAP_PLACEMENT, id, 4) + TEST_FIELD_ALIGN (QCMINFO_IDMAP_PLACEMENT, id, 4) + TEST_FIELD_OFFSET(QCMINFO_IDMAP_PLACEMENT, id, 0) + TEST_FIELD_SIZE (QCMINFO_IDMAP_PLACEMENT, fFlags, 4) + TEST_FIELD_ALIGN (QCMINFO_IDMAP_PLACEMENT, fFlags, 4) + TEST_FIELD_OFFSET(QCMINFO_IDMAP_PLACEMENT, fFlags, 4) } static void test_pack_SHChangeDWORDAsIDList(void) { /* SHChangeDWORDAsIDList (pack 1) */ - TEST_TYPE(SHChangeDWORDAsIDList, 12, 1); - TEST_FIELD(SHChangeDWORDAsIDList, USHORT, cb, 0, 2, 1); - TEST_FIELD(SHChangeDWORDAsIDList, DWORD, dwItem1, 2, 4, 1); - TEST_FIELD(SHChangeDWORDAsIDList, DWORD, dwItem2, 6, 4, 1); - TEST_FIELD(SHChangeDWORDAsIDList, USHORT, cbZero, 10, 2, 1); + TEST_TYPE_SIZE (SHChangeDWORDAsIDList, 12) + TEST_TYPE_ALIGN (SHChangeDWORDAsIDList, 1) + TEST_FIELD_SIZE (SHChangeDWORDAsIDList, cb, 2) + TEST_FIELD_ALIGN (SHChangeDWORDAsIDList, cb, 1) + TEST_FIELD_OFFSET(SHChangeDWORDAsIDList, cb, 0) + TEST_FIELD_SIZE (SHChangeDWORDAsIDList, dwItem1, 4) + TEST_FIELD_ALIGN (SHChangeDWORDAsIDList, dwItem1, 1) + TEST_FIELD_OFFSET(SHChangeDWORDAsIDList, dwItem1, 2) + TEST_FIELD_SIZE (SHChangeDWORDAsIDList, dwItem2, 4) + TEST_FIELD_ALIGN (SHChangeDWORDAsIDList, dwItem2, 1) + TEST_FIELD_OFFSET(SHChangeDWORDAsIDList, dwItem2, 6) + TEST_FIELD_SIZE (SHChangeDWORDAsIDList, cbZero, 2) + TEST_FIELD_ALIGN (SHChangeDWORDAsIDList, cbZero, 1) + TEST_FIELD_OFFSET(SHChangeDWORDAsIDList, cbZero, 10) } static void test_pack_SHChangeNotifyEntry(void) { /* SHChangeNotifyEntry (pack 1) */ - TEST_TYPE(SHChangeNotifyEntry, 8, 1); - TEST_FIELD(SHChangeNotifyEntry, LPCITEMIDLIST, pidl, 0, 4, 1); - TEST_FIELD(SHChangeNotifyEntry, BOOL, fRecursive, 4, 4, 1); + TEST_TYPE_SIZE (SHChangeNotifyEntry, 8) + TEST_TYPE_ALIGN (SHChangeNotifyEntry, 1) + TEST_FIELD_SIZE (SHChangeNotifyEntry, pidl, 4) + TEST_FIELD_ALIGN (SHChangeNotifyEntry, pidl, 1) + TEST_FIELD_OFFSET(SHChangeNotifyEntry, pidl, 0) + TEST_FIELD_SIZE (SHChangeNotifyEntry, fRecursive, 4) + TEST_FIELD_ALIGN (SHChangeNotifyEntry, fRecursive, 1) + TEST_FIELD_OFFSET(SHChangeNotifyEntry, fRecursive, 4) } static void test_pack_SHChangeProductKeyAsIDList(void) { /* SHChangeProductKeyAsIDList (pack 1) */ - TEST_TYPE(SHChangeProductKeyAsIDList, 82, 1); - TEST_FIELD(SHChangeProductKeyAsIDList, USHORT, cb, 0, 2, 1); - TEST_FIELD(SHChangeProductKeyAsIDList, WCHAR[39], wszProductKey, 2, 78, 1); - TEST_FIELD(SHChangeProductKeyAsIDList, USHORT, cbZero, 80, 2, 1); + TEST_TYPE_SIZE (SHChangeProductKeyAsIDList, 82) + TEST_TYPE_ALIGN (SHChangeProductKeyAsIDList, 1) + TEST_FIELD_SIZE (SHChangeProductKeyAsIDList, cb, 2) + TEST_FIELD_ALIGN (SHChangeProductKeyAsIDList, cb, 1) + TEST_FIELD_OFFSET(SHChangeProductKeyAsIDList, cb, 0) + TEST_FIELD_SIZE (SHChangeProductKeyAsIDList, wszProductKey, 78) + TEST_FIELD_ALIGN (SHChangeProductKeyAsIDList, wszProductKey, 1) + TEST_FIELD_OFFSET(SHChangeProductKeyAsIDList, wszProductKey, 2) + TEST_FIELD_SIZE (SHChangeProductKeyAsIDList, cbZero, 2) + TEST_FIELD_ALIGN (SHChangeProductKeyAsIDList, cbZero, 1) + TEST_FIELD_OFFSET(SHChangeProductKeyAsIDList, cbZero, 80) } static void test_pack_SHDESCRIPTIONID(void) { /* SHDESCRIPTIONID (pack 8) */ - TEST_TYPE(SHDESCRIPTIONID, 20, 4); - TEST_FIELD(SHDESCRIPTIONID, DWORD, dwDescriptionId, 0, 4, 4); - TEST_FIELD(SHDESCRIPTIONID, CLSID, clsid, 4, 16, 4); + TEST_TYPE_SIZE (SHDESCRIPTIONID, 20) + TEST_TYPE_ALIGN (SHDESCRIPTIONID, 4) + TEST_FIELD_SIZE (SHDESCRIPTIONID, dwDescriptionId, 4) + TEST_FIELD_ALIGN (SHDESCRIPTIONID, dwDescriptionId, 4) + TEST_FIELD_OFFSET(SHDESCRIPTIONID, dwDescriptionId, 0) + TEST_FIELD_SIZE (SHDESCRIPTIONID, clsid, 16) + TEST_FIELD_ALIGN (SHDESCRIPTIONID, clsid, 4) + TEST_FIELD_OFFSET(SHDESCRIPTIONID, clsid, 4) } static void test_pack_SHELLFLAGSTATE(void) { /* SHELLFLAGSTATE (pack 1) */ - TEST_TYPE(SHELLFLAGSTATE, 4, 1); + TEST_TYPE_SIZE (SHELLFLAGSTATE, 4) + TEST_TYPE_ALIGN (SHELLFLAGSTATE, 1) } static void test_pack_SHELLSTATE(void) { /* SHELLSTATE (pack 1) */ - TEST_TYPE(SHELLSTATE, 32, 1); - TEST_FIELD(SHELLSTATE, DWORD, dwWin95Unused, 4, 4, 1); - TEST_FIELD(SHELLSTATE, UINT, uWin95Unused, 8, 4, 1); - TEST_FIELD(SHELLSTATE, LONG, lParamSort, 12, 4, 1); - TEST_FIELD(SHELLSTATE, int, iSortDirection, 16, 4, 1); - TEST_FIELD(SHELLSTATE, UINT, version, 20, 4, 1); - TEST_FIELD(SHELLSTATE, UINT, uNotUsed, 24, 4, 1); -} - -static void test_pack_SHELLVIEWID(void) -{ - /* SHELLVIEWID */ - TEST_TYPE(SHELLVIEWID, 16, 4); + TEST_TYPE_SIZE (SHELLSTATE, 32) + TEST_TYPE_ALIGN (SHELLSTATE, 1) + TEST_FIELD_SIZE (SHELLSTATE, dwWin95Unused, 4) + TEST_FIELD_ALIGN (SHELLSTATE, dwWin95Unused, 1) + TEST_FIELD_OFFSET(SHELLSTATE, dwWin95Unused, 4) + TEST_FIELD_SIZE (SHELLSTATE, uWin95Unused, 4) + TEST_FIELD_ALIGN (SHELLSTATE, uWin95Unused, 1) + TEST_FIELD_OFFSET(SHELLSTATE, uWin95Unused, 8) + TEST_FIELD_SIZE (SHELLSTATE, lParamSort, 4) + TEST_FIELD_ALIGN (SHELLSTATE, lParamSort, 1) + TEST_FIELD_OFFSET(SHELLSTATE, lParamSort, 12) + TEST_FIELD_SIZE (SHELLSTATE, iSortDirection, 4) + TEST_FIELD_ALIGN (SHELLSTATE, iSortDirection, 1) + TEST_FIELD_OFFSET(SHELLSTATE, iSortDirection, 16) + TEST_FIELD_SIZE (SHELLSTATE, version, 4) + TEST_FIELD_ALIGN (SHELLSTATE, version, 1) + TEST_FIELD_OFFSET(SHELLSTATE, version, 20) + TEST_FIELD_SIZE (SHELLSTATE, uNotUsed, 4) + TEST_FIELD_ALIGN (SHELLSTATE, uNotUsed, 1) + TEST_FIELD_OFFSET(SHELLSTATE, uNotUsed, 24) } static void test_pack_TBINFO(void) { /* TBINFO (pack 8) */ - TEST_TYPE(TBINFO, 8, 4); - TEST_FIELD(TBINFO, UINT, cbuttons, 0, 4, 4); - TEST_FIELD(TBINFO, UINT, uFlags, 4, 4, 4); + TEST_TYPE_SIZE (TBINFO, 8) + TEST_TYPE_ALIGN (TBINFO, 4) + TEST_FIELD_SIZE (TBINFO, cbuttons, 4) + TEST_FIELD_ALIGN (TBINFO, cbuttons, 4) + TEST_FIELD_OFFSET(TBINFO, cbuttons, 0) + TEST_FIELD_SIZE (TBINFO, uFlags, 4) + TEST_FIELD_ALIGN (TBINFO, uFlags, 4) + TEST_FIELD_OFFSET(TBINFO, uFlags, 4) } static void test_pack(void) @@ -1275,7 +1906,6 @@ static void test_pack(void) test_pack_FLAGGED_BYTE_BLOB(); test_pack_FLAGGED_WORD_BLOB(); test_pack_FMTID(); - test_pack_GUID(); test_pack_HMETAFILEPICT(); test_pack_HYPER_SIZEDARR(); test_pack_IID(); @@ -1300,7 +1930,6 @@ static void test_pack(void) test_pack_LPFILEGROUPDESCRIPTORA(); test_pack_LPFILEGROUPDESCRIPTORW(); test_pack_LPFNVIEWCALLBACK(); - test_pack_LPGUID(); test_pack_LPIDA(); test_pack_LPITEMIDLIST(); test_pack_LPOLESTR(); @@ -1348,7 +1977,6 @@ static void test_pack(void) test_pack_SHELLEXECUTEINFOW(); test_pack_SHELLFLAGSTATE(); test_pack_SHELLSTATE(); - test_pack_SHELLVIEWID(); test_pack_SHFILEINFOA(); test_pack_SHFILEINFOW(); test_pack_SHFILEOPSTRUCTA(); @@ -1385,5 +2013,9 @@ static void test_pack(void) START_TEST(generated) { +#ifdef _WIN64 + ok(0, "The type size / alignment tests don't support Win64 yet\n"); +#else test_pack(); +#endif } diff --git a/rostests/winetests/shell32/rsrc.rc b/rostests/winetests/shell32/rsrc.rc new file mode 100644 index 00000000000..00c949bcae7 --- /dev/null +++ b/rostests/winetests/shell32/rsrc.rc @@ -0,0 +1,28 @@ +/* String resource for shlfolder test. + * + * Copyright 2008 Vincent Povirk for CodeWeavers + * + * 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 + */ + +#include "windef.h" +#include "winuser.h" + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +STRINGTABLE +{ + 1 "Folder Name Resource" +} diff --git a/rostests/winetests/shell32/shell32.rbuild b/rostests/winetests/shell32/shell32.rbuild index 9d1110eeec7..5d7c99a5aa1 100644 --- a/rostests/winetests/shell32/shell32.rbuild +++ b/rostests/winetests/shell32/shell32.rbuild @@ -3,10 +3,8 @@ . - - 0x600 - 0x501 - 0x501 + + 0x0501 wine shell32 ole32 @@ -15,9 +13,10 @@ user32 gdi32 advapi32 - kernel32 uuid ntdll + appbar.c + autocomplete.c generated.c shelllink.c shellpath.c @@ -28,5 +27,7 @@ systray.c testlist.c shfldr_netplaces.c + shfldr_special.c + rsrc.rc diff --git a/rostests/winetests/shell32/shelllink.c b/rostests/winetests/shell32/shelllink.c index a331b109869..2f20200c67a 100755 --- a/rostests/winetests/shell32/shelllink.c +++ b/rostests/winetests/shell32/shelllink.c @@ -24,7 +24,8 @@ #define COBJMACROS -#include +#include "initguid.h" +#include "windows.h" #include "shlguid.h" #include "shobjidl.h" #include "shlobj.h" @@ -32,23 +33,28 @@ #include "shell32_test.h" +#ifndef SLDF_HAS_LOGO3ID +# define SLDF_HAS_LOGO3ID 0x00000800 /* not available in the Vista SDK */ +#endif typedef void (WINAPI *fnILFree)(LPITEMIDLIST); typedef BOOL (WINAPI *fnILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST); typedef HRESULT (WINAPI *fnSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*); +typedef HRESULT (WINAPI *fnSHDefExtractIconA)(LPCSTR, int, UINT, HICON*, HICON*, UINT); static fnILFree pILFree; static fnILIsEqual pILIsEqual; static fnSHILCreateFromPath pSHILCreateFromPath; +static fnSHDefExtractIconA pSHDefExtractIconA; static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR, LPSTR, DWORD); +static DWORD (WINAPI *pGetShortPathNameA)(LPCSTR, LPSTR, DWORD); static const GUID _IID_IShellLinkDataList = { 0x45e2b4ae, 0xb1c3, 0x11d0, { 0xb9, 0x2f, 0x00, 0xa0, 0xc9, 0x03, 0x12, 0xe1 } }; -static const WCHAR lnkfile[]= { 'C',':','\\','t','e','s','t','.','l','n','k',0 }; static const WCHAR notafile[]= { 'C',':','\\','n','o','n','e','x','i','s','t','e','n','t','\\','f','i','l','e',0 }; @@ -67,7 +73,7 @@ static LPITEMIDLIST path_to_pidl(const char* path) HMODULE hdll=GetModuleHandleA("shell32.dll"); pSHSimpleIDListFromPathAW=(void*)GetProcAddress(hdll, (char*)162); if (!pSHSimpleIDListFromPathAW) - trace("SHSimpleIDListFromPathAW not found in shell32.dll\n"); + win_skip("SHSimpleIDListFromPathAW not found in shell32.dll\n"); } pidl=NULL; @@ -86,9 +92,7 @@ static LPITEMIDLIST path_to_pidl(const char* path) MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len); r=pSHILCreateFromPath(pathW, &pidl, NULL); - todo_wine { ok(SUCCEEDED(r), "SHILCreateFromPath failed (0x%08x)\n", r); - } HeapFree(GetProcessHeap(), 0, pathW); } return pidl; @@ -103,6 +107,7 @@ static void test_get_set(void) { HRESULT r; IShellLinkA *sl; + IShellLinkW *slW = NULL; char mypath[MAX_PATH]; char buffer[INFOTIPSIZE]; LPITEMIDLIST pidl, tmp_pidl; @@ -113,7 +118,7 @@ static void test_get_set(void) r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkA, (LPVOID*)&sl); ok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08x)\n", r); - if (!SUCCEEDED(r)) + if (FAILED(r)) return; /* Test Getting / Setting the description */ @@ -152,6 +157,19 @@ static void test_get_set(void) ok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r); ok(*buffer=='\0', "GetPath returned '%s'\n", buffer); + CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + &IID_IShellLinkW, (LPVOID*)&slW); + if (!slW) + skip("SetPath with NULL parameter crashes on Win9x\n"); + else + { + IShellLinkW_Release(slW); + r = IShellLinkA_SetPath(sl, NULL); + ok(r==E_INVALIDARG || + broken(r==S_OK), /* Some Win95 and NT4 */ + "SetPath failed (0x%08x)\n", r); + } + r = IShellLinkA_SetPath(sl, ""); ok(r==S_OK, "SetPath failed (0x%08x)\n", r); @@ -170,9 +188,9 @@ static void test_get_set(void) ok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r); ok(lstrcmpi(buffer,str)==0, "GetPath returned '%s'\n", buffer); - /* Get some a real path to play with */ - r=GetModuleFileName(NULL, mypath, sizeof(mypath)); - ok(r>=0 && rdescription) @@ -401,12 +424,12 @@ static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo) r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkA, (LPVOID*)&sl); lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08x)\n", r); - if (!SUCCEEDED(r)) + if (FAILED(r)) return; r = IShellLinkA_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf); lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08x)\n", r); - if (!SUCCEEDED(r)) + if (FAILED(r)) { IShellLinkA_Release(sl); return; @@ -415,7 +438,7 @@ static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo) r = IPersistFile_Load(pf, path, STGM_READ); lok(SUCCEEDED(r), "load failed (0x%08x)\n", r); IPersistFile_Release(pf); - if (!SUCCEEDED(r)) + if (FAILED(r)) { IShellLinkA_Release(sl); return; @@ -493,6 +516,10 @@ static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo) static void test_load_save(void) { + WCHAR lnkfile[MAX_PATH]; + char lnkfileA[MAX_PATH]; + static const char lnkfileA_name[] = "\\test.lnk"; + lnk_desc_t desc; char mypath[MAX_PATH]; char mydir[MAX_PATH]; @@ -501,6 +528,17 @@ static void test_load_save(void) HANDLE hf; DWORD r; + if (!pGetLongPathNameA) + { + win_skip("GetLongPathNameA is not available\n"); + return; + } + + /* Don't used a fixed path for the test.lnk file */ + GetTempPathA(MAX_PATH, lnkfileA); + lstrcatA(lnkfileA, lnkfileA_name); + MultiByteToWideChar(CP_ACP, 0, lnkfileA, -1, lnkfile, MAX_PATH); + /* Save an empty .lnk file */ memset(&desc, 0, sizeof(desc)); create_lnk(lnkfile, &desc, 0); @@ -533,10 +571,13 @@ static void test_load_save(void) if (p) *p='\0'; + /* IShellLink returns path in long form */ + if (!pGetLongPathNameA(mypath, realpath, MAX_PATH)) strcpy( realpath, mypath ); + /* Overwrite the existing lnk file and point it to existing files */ desc.description="test 2"; desc.workdir=mydir; - desc.path=mypath; + desc.path=realpath; desc.pidl=NULL; desc.arguments="/option1 /option2 \"Some string\""; desc.showcmd=SW_SHOWNORMAL; @@ -565,11 +606,6 @@ static void test_load_save(void) /* Create a temporary non-executable file */ r=GetTempPath(sizeof(mypath), mypath); ok(r','p','l','T',']','j','I','{','j','f','(', - '=','1','&','L','[','-','8','1','-',']',':',':',0 }; + '8','6','3','}',':','2','6',',','!','!','g','x','s','f','(','N','g',']', + 'q','F','`','H','{','L','s','A','C','C','E','S','S','F','i','l','e','s', + '>','p','l','T',']','j','I','{','j','f','(','=','1','&','L','[','-','8', + '1','-',']',':',':',0 }; static const WCHAR comp[] = { '2','6',',','!','!','g','x','s','f','(','N','g',']','q','F','`','H','{', 'L','s','A','C','C','E','S','S','F','i','l','e','s','>','p','l','T',']', @@ -633,19 +683,24 @@ static void test_datalink(void) r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl ); - ok( r == S_OK || r == E_NOINTERFACE, "CoCreateInstance failed (0x%08x)\n", r); + ok( r == S_OK || + broken(r == E_NOINTERFACE), /* Win9x */ + "CoCreateInstance failed (0x%08x)\n", r); if (!sl) { - skip("no shelllink\n"); + win_skip("no shelllink\n"); return; } r = IShellLinkW_QueryInterface( sl, &_IID_IShellLinkDataList, (LPVOID*) &dl ); - ok(r == S_OK, "IShellLinkW_QueryInterface failed (0x%08x)\n", r); + ok( r == S_OK || + broken(r == E_NOINTERFACE), /* NT4 */ + "IShellLinkW_QueryInterface failed (0x%08x)\n", r); if (!dl) { - skip("no datalink interface\n"); + win_skip("no datalink interface\n"); + IShellLinkW_Release( sl ); return; } @@ -659,6 +714,9 @@ static void test_datalink(void) ok( r == E_FAIL, "CopyDataBlock failed\n"); ok( dar == NULL, "should be null\n"); + r = IShellLinkW_SetPath(sl, NULL); + ok(r == E_INVALIDARG, "set path failed\n"); + r = IShellLinkW_SetPath(sl, lnk); ok(r == S_OK, "set path failed\n"); @@ -670,7 +728,8 @@ static void test_datalink(void) flags = 0; r = IShellLinkDataList_GetFlags( dl, &flags ); ok( r == S_OK, "GetFlags failed\n"); - ok( flags == (SLDF_HAS_DARWINID|SLDF_HAS_LOGO3ID), + /* SLDF_HAS_LOGO3ID is no longer supported on Vista+, filter it out */ + ok( (flags & (~ SLDF_HAS_LOGO3ID)) == SLDF_HAS_DARWINID, "GetFlags returned wrong flags\n"); dar = NULL; @@ -686,6 +745,34 @@ static void test_datalink(void) IShellLinkW_Release( sl ); } +static void test_shdefextracticon(void) +{ + HICON hiconlarge=NULL, hiconsmall=NULL; + HRESULT res; + + if (!pSHDefExtractIconA) + { + win_skip("SHDefExtractIconA is unavailable\n"); + return; + } + + res = pSHDefExtractIconA("shell32.dll", 0, 0, &hiconlarge, &hiconsmall, MAKELONG(16,24)); + ok(SUCCEEDED(res), "SHDefExtractIconA failed, res=%x\n", res); + ok(hiconlarge != NULL, "got null hiconlarge\n"); + ok(hiconsmall != NULL, "got null hiconsmall\n"); + DestroyIcon(hiconlarge); + DestroyIcon(hiconsmall); + + hiconsmall = NULL; + res = pSHDefExtractIconA("shell32.dll", 0, 0, NULL, &hiconsmall, MAKELONG(16,24)); + ok(SUCCEEDED(res), "SHDefExtractIconA failed, res=%x\n", res); + ok(hiconsmall != NULL, "got null hiconsmall\n"); + DestroyIcon(hiconsmall); + + res = pSHDefExtractIconA("shell32.dll", 0, 0, NULL, NULL, MAKELONG(16,24)); + ok(SUCCEEDED(res), "SHDefExtractIconA failed, res=%x\n", res); +} + START_TEST(shelllink) { HRESULT r; @@ -695,17 +782,20 @@ START_TEST(shelllink) pILFree = (fnILFree) GetProcAddress(hmod, (LPSTR)155); pILIsEqual = (fnILIsEqual) GetProcAddress(hmod, (LPSTR)21); pSHILCreateFromPath = (fnSHILCreateFromPath) GetProcAddress(hmod, (LPSTR)28); + pSHDefExtractIconA = (fnSHDefExtractIconA) GetProcAddress(hmod, "SHDefExtractIconA"); pGetLongPathNameA = (void *)GetProcAddress(hkernel32, "GetLongPathNameA"); + pGetShortPathNameA = (void *)GetProcAddress(hkernel32, "GetShortPathNameA"); r = CoInitialize(NULL); ok(SUCCEEDED(r), "CoInitialize failed (0x%08x)\n", r); - if (!SUCCEEDED(r)) + if (FAILED(r)) return; test_get_set(); test_load_save(); test_datalink(); + test_shdefextracticon(); CoUninitialize(); } diff --git a/rostests/winetests/shell32/shellpath.c b/rostests/winetests/shell32/shellpath.c index a6bbcaefba7..c31fe355891 100644 --- a/rostests/winetests/shell32/shellpath.c +++ b/rostests/winetests/shell32/shellpath.c @@ -19,9 +19,6 @@ * This is a test program for the SHGet{Special}Folder{Path|Location} functions * of shell32, that get either a filesystem path or a LPITEMIDLIST (shell * namespace) path for a given folder (CSIDL value). - * - * FIXME: - * - Need to verify on more systems. */ #define COBJMACROS @@ -33,6 +30,7 @@ #include "shlguid.h" #include "shlobj.h" #include "shlwapi.h" +#include "initguid.h" #include "wine/test.h" /* CSIDL_MYDOCUMENTS is now the same as CSIDL_PERSONAL, but what we want @@ -45,6 +43,9 @@ #endif /* from pidl.h, not included here: */ +#ifndef PT_CPL /* Guess, Win7 uses this for CSIDL_CONTROLS */ +#define PT_CPL 0x01 /* no path */ +#endif #ifndef PT_GUID #define PT_GUID 0x1f /* no path */ #endif @@ -60,6 +61,9 @@ #ifndef PT_FOLDER #define PT_FOLDER 0x31 /* has path */ #endif +#ifndef PT_FOLDERW +#define PT_FOLDERW 0x35 /* has path */ +#endif #ifndef PT_WORKGRP #define PT_WORKGRP 0x41 /* no path */ #endif @@ -75,7 +79,8 @@ static GUID CLSID_CommonDocuments = { 0x0000000c, 0x0000, 0x0000, { 0x00, 0x00, struct shellExpectedValues { int folder; - BYTE pidlType; + int numTypes; + const BYTE *types; }; static HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO *); @@ -87,73 +92,89 @@ static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *); static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST); static int (WINAPI *pSHFileOperationA)(LPSHFILEOPSTRUCTA); static HRESULT (WINAPI *pSHGetMalloc)(LPMALLOC *); +static UINT (WINAPI *pGetSystemWow64DirectoryA)(LPSTR,UINT); static DLLVERSIONINFO shellVersion = { 0 }; static LPMALLOC pMalloc; +static const BYTE guidType[] = { PT_GUID }; +static const BYTE controlPanelType[] = { PT_SHELLEXT, PT_GUID, PT_CPL }; +static const BYTE folderType[] = { PT_FOLDER, PT_FOLDERW }; +static const BYTE favoritesType[] = { PT_FOLDER, PT_FOLDERW, 0, PT_IESPECIAL2 /* Win98 */ }; +static const BYTE folderOrSpecialType[] = { PT_FOLDER, PT_IESPECIAL2 }; +static const BYTE personalType[] = { PT_FOLDER, PT_GUID, PT_DRIVE, 0xff /* Win9x */, + PT_IESPECIAL2 /* Win98 */, 0 /* Vista */ }; +/* FIXME: don't know the type of 0x71 returned by Vista/2008 for printers */ +static const BYTE printersType[] = { PT_YAGUID, PT_SHELLEXT, 0x71 }; +static const BYTE ieSpecialType[] = { PT_IESPECIAL2 }; +static const BYTE shellExtType[] = { PT_SHELLEXT }; +static const BYTE workgroupType[] = { PT_WORKGRP }; +#define DECLARE_TYPE(x, y) { x, sizeof(y) / sizeof(y[0]), y } static const struct shellExpectedValues requiredShellValues[] = { - { CSIDL_BITBUCKET, PT_GUID }, - { CSIDL_CONTROLS, PT_SHELLEXT }, - { CSIDL_COOKIES, PT_FOLDER }, - { CSIDL_DESKTOPDIRECTORY, PT_FOLDER }, - { CSIDL_DRIVES, PT_GUID }, - { CSIDL_FAVORITES, PT_FOLDER }, - { CSIDL_FONTS, PT_FOLDER }, + DECLARE_TYPE(CSIDL_BITBUCKET, guidType), + DECLARE_TYPE(CSIDL_CONTROLS, controlPanelType), + DECLARE_TYPE(CSIDL_COOKIES, folderType), + DECLARE_TYPE(CSIDL_DESKTOPDIRECTORY, folderType), + DECLARE_TYPE(CSIDL_DRIVES, guidType), + DECLARE_TYPE(CSIDL_FAVORITES, favoritesType), + DECLARE_TYPE(CSIDL_FONTS, folderOrSpecialType), /* FIXME: the following fails in Wine, returns type PT_FOLDER - { CSIDL_HISTORY, PT_IESPECIAL2 }, + DECLARE_TYPE(CSIDL_HISTORY, ieSpecialType), */ - { CSIDL_INTERNET, PT_GUID }, - { CSIDL_NETHOOD, PT_FOLDER }, - { CSIDL_NETWORK, PT_GUID }, - { CSIDL_PRINTERS, PT_YAGUID }, - { CSIDL_PRINTHOOD, PT_FOLDER }, - { CSIDL_PROGRAMS, PT_FOLDER }, - { CSIDL_RECENT, PT_FOLDER }, - { CSIDL_SENDTO, PT_FOLDER }, - { CSIDL_STARTMENU, PT_FOLDER }, - { CSIDL_STARTUP, PT_FOLDER }, - { CSIDL_TEMPLATES, PT_FOLDER }, + DECLARE_TYPE(CSIDL_INTERNET, guidType), + DECLARE_TYPE(CSIDL_NETHOOD, folderType), + DECLARE_TYPE(CSIDL_NETWORK, guidType), + DECLARE_TYPE(CSIDL_PERSONAL, personalType), + DECLARE_TYPE(CSIDL_PRINTERS, printersType), + DECLARE_TYPE(CSIDL_PRINTHOOD, folderType), + DECLARE_TYPE(CSIDL_PROGRAMS, folderType), + DECLARE_TYPE(CSIDL_RECENT, folderOrSpecialType), + DECLARE_TYPE(CSIDL_SENDTO, folderType), + DECLARE_TYPE(CSIDL_STARTMENU, folderType), + DECLARE_TYPE(CSIDL_STARTUP, folderType), + DECLARE_TYPE(CSIDL_TEMPLATES, folderType), }; static const struct shellExpectedValues optionalShellValues[] = { /* FIXME: the following only semi-succeed; they return NULL PIDLs on XP.. hmm. - { CSIDL_ALTSTARTUP, PT_FOLDER }, - { CSIDL_COMMON_ALTSTARTUP, PT_FOLDER }, - { CSIDL_COMMON_OEM_LINKS, PT_FOLDER }, + DECLARE_TYPE(CSIDL_ALTSTARTUP, folderType), + DECLARE_TYPE(CSIDL_COMMON_ALTSTARTUP, folderType), + DECLARE_TYPE(CSIDL_COMMON_OEM_LINKS, folderType), */ /* Windows NT-only: */ - { CSIDL_COMMON_DESKTOPDIRECTORY, PT_FOLDER }, - { CSIDL_COMMON_DOCUMENTS, PT_SHELLEXT }, - { CSIDL_COMMON_FAVORITES, PT_FOLDER }, - { CSIDL_COMMON_PROGRAMS, PT_FOLDER }, - { CSIDL_COMMON_STARTMENU, PT_FOLDER }, - { CSIDL_COMMON_STARTUP, PT_FOLDER }, - { CSIDL_COMMON_TEMPLATES, PT_FOLDER }, + DECLARE_TYPE(CSIDL_COMMON_DESKTOPDIRECTORY, folderType), + DECLARE_TYPE(CSIDL_COMMON_DOCUMENTS, shellExtType), + DECLARE_TYPE(CSIDL_COMMON_FAVORITES, folderType), + DECLARE_TYPE(CSIDL_COMMON_PROGRAMS, folderType), + DECLARE_TYPE(CSIDL_COMMON_STARTMENU, folderType), + DECLARE_TYPE(CSIDL_COMMON_STARTUP, folderType), + DECLARE_TYPE(CSIDL_COMMON_TEMPLATES, folderType), /* first appearing in shell32 version 4.71: */ - { CSIDL_APPDATA, PT_FOLDER }, + DECLARE_TYPE(CSIDL_APPDATA, folderType), /* first appearing in shell32 version 4.72: */ - { CSIDL_INTERNET_CACHE, PT_IESPECIAL2 }, + DECLARE_TYPE(CSIDL_INTERNET_CACHE, ieSpecialType), /* first appearing in shell32 version 5.0: */ - { CSIDL_ADMINTOOLS, PT_FOLDER }, - { CSIDL_COMMON_APPDATA, PT_FOLDER }, - { CSIDL_LOCAL_APPDATA, PT_FOLDER }, - { OLD_CSIDL_MYDOCUMENTS, PT_FOLDER }, - { CSIDL_MYMUSIC, PT_FOLDER }, - { CSIDL_MYPICTURES, PT_FOLDER }, - { CSIDL_MYVIDEO, PT_FOLDER }, - { CSIDL_PROFILE, PT_FOLDER }, - { CSIDL_PROGRAM_FILES, PT_FOLDER }, - { CSIDL_PROGRAM_FILESX86, PT_FOLDER }, - { CSIDL_PROGRAM_FILES_COMMON, PT_FOLDER }, - { CSIDL_PROGRAM_FILES_COMMONX86, PT_FOLDER }, - { CSIDL_SYSTEM, PT_FOLDER }, - { CSIDL_WINDOWS, PT_FOLDER }, + DECLARE_TYPE(CSIDL_ADMINTOOLS, folderType), + DECLARE_TYPE(CSIDL_COMMON_APPDATA, folderType), + DECLARE_TYPE(CSIDL_LOCAL_APPDATA, folderType), + DECLARE_TYPE(OLD_CSIDL_MYDOCUMENTS, folderType), + DECLARE_TYPE(CSIDL_MYMUSIC, folderType), + DECLARE_TYPE(CSIDL_MYPICTURES, folderType), + DECLARE_TYPE(CSIDL_MYVIDEO, folderType), + DECLARE_TYPE(CSIDL_PROFILE, folderType), + DECLARE_TYPE(CSIDL_PROGRAM_FILES, folderType), + DECLARE_TYPE(CSIDL_PROGRAM_FILESX86, folderType), + DECLARE_TYPE(CSIDL_PROGRAM_FILES_COMMON, folderType), + DECLARE_TYPE(CSIDL_PROGRAM_FILES_COMMONX86, folderType), + DECLARE_TYPE(CSIDL_SYSTEM, folderType), + DECLARE_TYPE(CSIDL_WINDOWS, folderType), /* first appearing in shell32 6.0: */ - { CSIDL_CDBURN_AREA, PT_FOLDER }, - { CSIDL_COMMON_MUSIC, PT_FOLDER }, - { CSIDL_COMMON_PICTURES, PT_FOLDER }, - { CSIDL_COMMON_VIDEO, PT_FOLDER }, - { CSIDL_COMPUTERSNEARME, PT_WORKGRP }, - { CSIDL_RESOURCES, PT_FOLDER }, - { CSIDL_RESOURCES_LOCALIZED, PT_FOLDER }, + DECLARE_TYPE(CSIDL_CDBURN_AREA, folderType), + DECLARE_TYPE(CSIDL_COMMON_MUSIC, folderType), + DECLARE_TYPE(CSIDL_COMMON_PICTURES, folderType), + DECLARE_TYPE(CSIDL_COMMON_VIDEO, folderType), + DECLARE_TYPE(CSIDL_COMPUTERSNEARME, workgroupType), + DECLARE_TYPE(CSIDL_RESOURCES, folderType), + DECLARE_TYPE(CSIDL_RESOURCES_LOCALIZED, folderType), }; +#undef DECLARE_TYPE static void loadShell32(void) { @@ -188,8 +209,7 @@ static void loadShell32(void) { shellVersion.cbSize = sizeof(shellVersion); pDllGetVersion(&shellVersion); - if (winetest_interactive) - printf("shell32 version is %d.%d\n", + trace("shell32 version is %d.%d\n", shellVersion.dwMajorVersion, shellVersion.dwMinorVersion); } #undef GET_PROC @@ -272,10 +292,8 @@ static const char *getFolderName(int folder) } } -static const char *printGUID(const GUID *guid) +static const char *printGUID(const GUID *guid, char * guidSTR) { - static char guidSTR[39]; - if (!guid) return NULL; sprintf(guidSTR, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", @@ -302,15 +320,8 @@ static void testSHGetFolderLocationInvalidArgs(void) /* check a bogus user token: */ pidl = NULL; hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, (HANDLE)2, 0, &pidl); - ok(hr == E_FAIL, - "SHGetFolderLocation(NULL, CSIDL_FAVORITES, 2, 0, &pidl) returned 0x%08x, expected E_FAIL\n", hr); - if (SUCCEEDED(hr)) - IMalloc_Free(pMalloc, pidl); - /* check reserved is not zero: */ - pidl = NULL; - hr = pSHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 1, &pidl); - ok(hr == E_INVALIDARG, - "SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 1, &pidl) returned 0x%08x, expected E_INVALIDARG\n", hr); + ok(hr == E_FAIL || hr == E_HANDLE, + "SHGetFolderLocation(NULL, CSIDL_FAVORITES, 2, 0, &pidl) returned 0x%08x, expected E_FAIL or E_HANDLE\n", hr); if (SUCCEEDED(hr)) IMalloc_Free(pMalloc, pidl); /* a NULL pidl pointer crashes, so don't test it */ @@ -340,7 +351,9 @@ static void testSHGetFolderPathInvalidArgs(void) /* expect 2's a bogus handle, especially since we didn't open it */ hr = pSHGetFolderPathA(NULL, CSIDL_DESKTOP, (HANDLE)2, SHGFP_TYPE_DEFAULT, path); - ok(hr == E_FAIL, + ok(hr == E_FAIL || + hr == E_HANDLE || /* Windows Vista and 2008 */ + broken(hr == S_OK), /* Windows 2000 and Me */ "SHGetFolderPathA(NULL, CSIDL_DESKTOP, 2, SHGFP_TYPE_DEFAULT, path) returned 0x%08x, expected E_FAIL\n", hr); hr = pSHGetFolderPathA(NULL, 0xeeee, NULL, SHGFP_TYPE_DEFAULT, path); ok(hr == E_INVALIDARG, @@ -379,7 +392,7 @@ static void testApiParameters(void) } /* Returns the folder's PIDL type, or 0xff if one can't be found. */ -static BYTE testSHGetFolderLocation(BOOL optional, int folder) +static BYTE testSHGetFolderLocation(int folder) { LPITEMIDLIST pidl; HRESULT hr; @@ -390,12 +403,8 @@ static BYTE testSHGetFolderLocation(BOOL optional, int folder) pidl = NULL; hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl); - ok(SUCCEEDED(hr) || optional, - "SHGetFolderLocation(NULL, %s, NULL, 0, &pidl) failed: 0x%08x\n", getFolderName(folder), hr); if (SUCCEEDED(hr)) { - ok(pidl != NULL, - "SHGetFolderLocation(NULL, %s, NULL, 0, &pidl) succeeded, but returned pidl is NULL\n", getFolderName(folder)); if (pidl) { LPITEMIDLIST pidlLast = pILFindLastID(pidl); @@ -411,7 +420,7 @@ static BYTE testSHGetFolderLocation(BOOL optional, int folder) } /* Returns the folder's PIDL type, or 0xff if one can't be found. */ -static BYTE testSHGetSpecialFolderLocation(BOOL optional, int folder) +static BYTE testSHGetSpecialFolderLocation(int folder) { LPITEMIDLIST pidl; HRESULT hr; @@ -422,12 +431,8 @@ static BYTE testSHGetSpecialFolderLocation(BOOL optional, int folder) pidl = NULL; hr = pSHGetSpecialFolderLocation(NULL, folder, &pidl); - ok(SUCCEEDED(hr) || optional, - "SHGetSpecialFolderLocation(NULL, %s, &pidl) failed: 0x%08x\n", getFolderName(folder), hr); if (SUCCEEDED(hr)) { - ok(pidl != NULL, - "SHGetSpecialFolderLocation(NULL, %s, &pidl) succeeded, but returned pidl is NULL\n", getFolderName(folder)); if (pidl) { LPITEMIDLIST pidlLast = pILFindLastID(pidl); @@ -477,17 +482,27 @@ static void testShellValues(const struct shellExpectedValues testEntries[], for (i = 0; i < numEntries; i++) { BYTE type; + int j; + BOOL foundTypeMatch = FALSE; - type = testSHGetFolderLocation(optional, testEntries[i].folder); - ok(type == testEntries[i].pidlType || optional, - "%s has type %d (0x%02x), expected %d (0x%02x)\n", - getFolderName(testEntries[i].folder), type, type, - testEntries[i].pidlType, testEntries[i].pidlType); - type = testSHGetSpecialFolderLocation(optional, testEntries[i].folder); - ok(type == testEntries[i].pidlType || optional, - "%s has type %d (0x%02x), expected %d (0x%02x)\n", - getFolderName(testEntries[i].folder), type, type, - testEntries[i].pidlType, testEntries[i].pidlType); + if (pSHGetFolderLocation) + { + type = testSHGetFolderLocation(testEntries[i].folder); + for (j = 0; !foundTypeMatch && j < testEntries[i].numTypes; j++) + if (testEntries[i].types[j] == type) + foundTypeMatch = TRUE; + ok(foundTypeMatch || optional || broken(type == 0xff) /* Win9x */, + "%s has unexpected type %d (0x%02x)\n", + getFolderName(testEntries[i].folder), type, type); + } + type = testSHGetSpecialFolderLocation(testEntries[i].folder); + for (j = 0, foundTypeMatch = FALSE; !foundTypeMatch && + j < testEntries[i].numTypes; j++) + if (testEntries[i].types[j] == type) + foundTypeMatch = TRUE; + ok(foundTypeMatch || optional || broken(type == 0xff) /* Win9x */, + "%s has unexpected type %d (0x%02x)\n", + getFolderName(testEntries[i].folder), type, type); switch (type) { case PT_FOLDER: @@ -530,7 +545,7 @@ static void matchSpecialFolderPathToEnv(int folder, const char *envVar) * fail if it isn't--that check should already have been done. * Fails if the returned PIDL is a GUID whose value does not match guid. */ -static void matchGUID(int folder, const GUID *guid) +static void matchGUID(int folder, const GUID *guid, const GUID *guid_alt) { LPITEMIDLIST pidl; HRESULT hr; @@ -548,10 +563,18 @@ static void matchGUID(int folder, const GUID *guid) pidlLast->mkid.abID[0] == PT_GUID)) { GUID *shellGuid = (GUID *)(pidlLast->mkid.abID + 2); + char shellGuidStr[39], guidStr[39], guid_altStr[39]; + if (!guid_alt) ok(IsEqualIID(shellGuid, guid), "%s: got GUID %s, expected %s\n", getFolderName(folder), - printGUID(shellGuid), printGUID(guid)); + printGUID(shellGuid, shellGuidStr), printGUID(guid, guidStr)); + else + ok(IsEqualIID(shellGuid, guid) || + IsEqualIID(shellGuid, guid_alt), + "%s: got GUID %s, expected %s or %s\n", getFolderName(folder), + printGUID(shellGuid, shellGuidStr), printGUID(guid, guidStr), + printGUID(guid_alt, guid_altStr)); } IMalloc_Free(pMalloc, pidl); } @@ -561,56 +584,31 @@ static void testDesktop(void) { testSHGetFolderPath(FALSE, CSIDL_DESKTOP); testSHGetSpecialFolderPath(FALSE, CSIDL_DESKTOP); - /* Test the desktop; even though SHITEMID should always contain abID of at - * least one type, when cb is 0 its value is undefined. So don't check - * what the returned type is, just make sure it exists. - */ - testSHGetFolderLocation(FALSE, CSIDL_DESKTOP); - testSHGetSpecialFolderLocation(FALSE, CSIDL_DESKTOP); -} - -static void testPersonal(void) -{ - BYTE type; - - /* The pidl may be a real folder, or a virtual directory, or a drive if the - * home directory is set to the root directory of a drive. - */ - type = testSHGetFolderLocation(FALSE, CSIDL_PERSONAL); - ok(type == PT_FOLDER || type == PT_GUID || type == PT_DRIVE, - "CSIDL_PERSONAL returned invalid type 0x%02x, " - "expected PT_FOLDER or PT_GUID\n", type); - if (type == PT_FOLDER) - testSHGetFolderPath(FALSE, CSIDL_PERSONAL); - type = testSHGetSpecialFolderLocation(FALSE, CSIDL_PERSONAL); - ok(type == PT_FOLDER || type == PT_GUID || type == PT_DRIVE, - "CSIDL_PERSONAL returned invalid type 0x%02x, " - "expected PT_FOLDER or PT_GUID\n", type); - if (type == PT_FOLDER) - testSHGetSpecialFolderPath(FALSE, CSIDL_PERSONAL); } /* Checks the PIDL type of all the known values. */ static void testPidlTypes(void) { testDesktop(); - testPersonal(); testShellValues(requiredShellValues, ARRAY_SIZE(requiredShellValues), FALSE); testShellValues(optionalShellValues, ARRAY_SIZE(optionalShellValues), TRUE); } +/* FIXME: Should be in shobjidl.idl */ +DEFINE_GUID(CLSID_NetworkExplorerFolder, 0xF02C1A0D, 0xBE21, 0x4350, 0x88, 0xB0, 0x73, 0x67, 0xFC, 0x96, 0xEF, 0x3C); + /* Verifies various shell virtual folders have the correct well-known GUIDs. */ static void testGUIDs(void) { - matchGUID(CSIDL_BITBUCKET, &CLSID_RecycleBin); - matchGUID(CSIDL_CONTROLS, &CLSID_ControlPanel); - matchGUID(CSIDL_DRIVES, &CLSID_MyComputer); - matchGUID(CSIDL_INTERNET, &CLSID_Internet); - matchGUID(CSIDL_NETWORK, &CLSID_NetworkPlaces); - matchGUID(CSIDL_PERSONAL, &CLSID_MyDocuments); - matchGUID(CSIDL_COMMON_DOCUMENTS, &CLSID_CommonDocuments); + matchGUID(CSIDL_BITBUCKET, &CLSID_RecycleBin, NULL); + matchGUID(CSIDL_CONTROLS, &CLSID_ControlPanel, NULL); + matchGUID(CSIDL_DRIVES, &CLSID_MyComputer, NULL); + matchGUID(CSIDL_INTERNET, &CLSID_Internet, NULL); + matchGUID(CSIDL_NETWORK, &CLSID_NetworkPlaces, &CLSID_NetworkExplorerFolder); /* Vista and higher */ + matchGUID(CSIDL_PERSONAL, &CLSID_MyDocuments, NULL); + matchGUID(CSIDL_COMMON_DOCUMENTS, &CLSID_CommonDocuments, NULL); } /* Verifies various shell paths match the environment variables to which they @@ -671,8 +669,8 @@ static void testWinDir(void) } } -/* Verifies the shell path for CSIDL_SYSTEM and CSIDL_SYSTEMX86 matches the - * return from GetSystemDirectory. If SHGetSpecialFolderPath fails, no harm, +/* Verifies the shell path for CSIDL_SYSTEM matches the return from + * GetSystemDirectory. If SHGetSpecialFolderPath fails, no harm, * no foul--not every shell32 version supports CSIDL_SYSTEM. */ static void testSystemDir(void) @@ -690,9 +688,10 @@ static void testSystemDir(void) "GetSystemDirectory returns %s SHGetSpecialFolderPath returns %s\n", systemDir, systemShellPath); } - /* check CSIDL_SYSTEMX86; note that this isn't always present, so don't - * worry if it fails - */ + + if (!pGetSystemWow64DirectoryA || !pGetSystemWow64DirectoryA(systemDir, sizeof(systemDir))) + GetSystemDirectoryA(systemDir, sizeof(systemDir)); + myPathRemoveBackslashA(systemDir); if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEMX86, FALSE)) { myPathRemoveBackslashA(systemShellPath); @@ -723,7 +722,7 @@ static void testNonExistentPath1(void) { HRESULT hr; LPITEMIDLIST pidl; - char path[MAX_PATH]; + char *p, path[MAX_PATH]; /* test some failure cases first: */ hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL, @@ -733,16 +732,16 @@ static void testNonExistentPath1(void) pidl = NULL; hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, NULL, 0, &pidl); - ok(hr == E_FAIL, - "SHGetFolderLocation returned 0x%08x, expected E_FAIL\n", hr); + ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "SHGetFolderLocation returned 0x%08x\n", hr); if (SUCCEEDED(hr) && pidl) IMalloc_Free(pMalloc, pidl); ok(!pSHGetSpecialFolderPathA(NULL, path, CSIDL_FAVORITES, FALSE), "SHGetSpecialFolderPath succeeded, expected failure\n"); pidl = NULL; hr = pSHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl); - ok(hr == E_FAIL, "SHGetFolderLocation returned 0x%08x, expected E_FAIL\n", - hr); + ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), + "SHGetFolderLocation returned 0x%08x\n", hr); if (SUCCEEDED(hr) && pidl) IMalloc_Free(pMalloc, pidl); /* now test success: */ @@ -752,8 +751,7 @@ static void testNonExistentPath1(void) { BOOL ret; - if (winetest_interactive) - printf("CSIDL_FAVORITES was changed to %s\n", path); + trace("CSIDL_FAVORITES was changed to %s\n", path); ret = CreateDirectoryA(path, NULL); ok(!ret, "CreateDirectoryA succeeded but should have failed " @@ -763,6 +761,13 @@ static void testNonExistentPath1(void) "CreateDirectoryA failed with %d, " "expected ERROR_ALREADY_EXISTS\n", GetLastError()); + p = path + strlen(path); + strcpy(p, "\\desktop.ini"); + DeleteFileA(path); + *p = 0; + SetFileAttributesA( path, FILE_ATTRIBUTE_NORMAL ); + ret = RemoveDirectoryA(path); + ok( ret, "failed to remove %s error %u\n", path, GetLastError() ); } ok(SUCCEEDED(hr), "SHGetFolderPath(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, " @@ -831,15 +836,13 @@ static void testNonExistentPath(void) memcpy(modifiedPath, originalPath, len); modifiedPath[len++] = '2'; modifiedPath[len++] = '\0'; - if (winetest_interactive) - printf("Changing CSIDL_FAVORITES to %s\n", modifiedPath); + trace("Changing CSIDL_FAVORITES to %s\n", modifiedPath); if (!RegSetValueExA(key, "Favorites", 0, type, (LPBYTE)modifiedPath, len)) { char buffer[MAX_PATH+20]; STARTUPINFOA startup; PROCESS_INFORMATION info; - HRESULT hr; sprintf(buffer, "%s tests/shellpath.c 1", selfname); memset(&startup, 0, sizeof(startup)); @@ -850,14 +853,8 @@ static void testNonExistentPath(void) &startup, &info); winetest_wait_child_process( info.hProcess ); - /* Query the path to be able to delete it below */ - hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL, - SHGFP_TYPE_CURRENT, modifiedPath); - ok(SUCCEEDED(hr), "SHGetFolderPathA failed: 0x%08x\n", hr); - /* restore original values: */ - if (winetest_interactive) - printf("Restoring CSIDL_FAVORITES to %s\n", originalPath); + trace("Restoring CSIDL_FAVORITES to %s\n", originalPath); RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) originalPath, strlen(originalPath) + 1); RegFlushKey(key); @@ -871,21 +868,13 @@ static void testNonExistentPath(void) &startup, &info); ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "child process termination\n"); - - strcpy(buffer, modifiedPath); - strcat(buffer, "\\desktop.ini"); - DeleteFileA(buffer); - RemoveDirectoryA(modifiedPath); } } - else if (winetest_interactive) - printf("RegQueryValueExA(key, Favorites, ...) failed\n"); + else skip("RegQueryValueExA(key, Favorites, ...) failed\n"); if (key) RegCloseKey(key); } - else if (winetest_interactive) - printf("RegOpenKeyExA(HKEY_CURRENT_USER, %s, ...) failed\n", - userShellFolders); + else skip("RegOpenKeyExA(HKEY_CURRENT_USER, %s, ...) failed\n", userShellFolders); } START_TEST(shellpath) @@ -893,11 +882,17 @@ START_TEST(shellpath) if (!init()) return; loadShell32(); + pGetSystemWow64DirectoryA = (void *)GetProcAddress( GetModuleHandleA("kernel32.dll"), + "GetSystemWow64DirectoryA" ); if (myARGC >= 3) doChild(myARGV[2]); else { + /* Report missing functions once */ + if (!pSHGetFolderLocation) + win_skip("SHGetFolderLocation is not available\n"); + /* first test various combinations of parameters: */ testApiParameters(); diff --git a/rostests/winetests/shell32/shfldr_special.c b/rostests/winetests/shell32/shfldr_special.c new file mode 100644 index 00000000000..06533ba8b95 --- /dev/null +++ b/rostests/winetests/shell32/shfldr_special.c @@ -0,0 +1,127 @@ +/* + * Tests for special shell folders + * + * Copyright 2008 Robert Shearman for CodeWeavers + * Copyright 2008 Owen Rudge + * + * 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 + */ + +#include +#include + +#define COBJMACROS +#define WIN32_LEAN_AND_MEAN +#include +#include "shellapi.h" +#include "shlobj.h" + +#include "wine/test.h" + +/* Tests for My Network Places */ +static void test_parse_for_entire_network(void) +{ + static WCHAR my_network_places_path[] = { + ':',':','{','2','0','8','D','2','C','6','0','-','3','A','E','A','-', + '1','0','6','9','-','A','2','D','7','-','0','8','0','0','2','B','3','0','3','0','9','D','}', 0 }; + static WCHAR entire_network_path[] = { + ':',':','{','2','0','8','D','2','C','6','0','-','3','A','E','A','-', + '1','0','6','9','-','A','2','D','7','-','0','8','0','0','2','B','3','0','3','0','9','D', + '}','\\','E','n','t','i','r','e','N','e','t','w','o','r','k',0 }; + IShellFolder *psfDesktop; + HRESULT hr; + DWORD eaten = 0xdeadbeef; + LPITEMIDLIST pidl; + DWORD attr = ~0; + DWORD expected_attr; + + hr = SHGetDesktopFolder(&psfDesktop); + ok(hr == S_OK, "SHGetDesktopFolder failed with error 0x%x\n", hr); + + hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, my_network_places_path, &eaten, &pidl, &attr); + ok(hr == S_OK, "IShellFolder_ParseDisplayName failed with error 0x%x\n", hr); + todo_wine + ok(eaten == 0xdeadbeef, "eaten should not have been set to %u\n", eaten); + expected_attr = SFGAO_HASSUBFOLDER|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANRENAME|SFGAO_CANLINK; + todo_wine + ok((attr == expected_attr) || /* Win9x, NT4 */ + (attr == (expected_attr | SFGAO_STREAM)) || /* W2K */ + (attr == (expected_attr | SFGAO_CANDELETE)) || /* XP, W2K3 */ + (attr == (expected_attr | SFGAO_CANDELETE | SFGAO_NONENUMERATED)), /* Vista */ + "Unexpected attributes : %08x\n", attr); + + ILFree(pidl); + + /* Start clean again */ + eaten = 0xdeadbeef; + attr = ~0; + + hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, entire_network_path, &eaten, &pidl, &attr); + if (hr == HRESULT_FROM_WIN32(ERROR_BAD_NET_NAME) || + hr == HRESULT_FROM_WIN32(ERROR_NO_NET_OR_BAD_PATH) || + hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)) + { + win_skip("'EntireNetwork' is not available on Win9x, NT4 and Vista\n"); + return; + } + ok(hr == S_OK, "IShellFolder_ParseDisplayName failed with error 0x%x\n", hr); + todo_wine + ok(eaten == 0xdeadbeef, "eaten should not have been set to %u\n", eaten); + expected_attr = SFGAO_HASSUBFOLDER|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|SFGAO_HASPROPSHEET|SFGAO_CANLINK; + todo_wine + ok(attr == expected_attr || /* winme, nt4 */ + attr == (expected_attr | SFGAO_STREAM) || /* win2k */ + attr == (expected_attr | SFGAO_STORAGEANCESTOR), /* others */ + "attr should be 0x%x, not 0x%x\n", expected_attr, attr); + + ILFree(pidl); +} + +/* Tests for Control Panel */ +static void test_parse_for_control_panel(void) +{ + /* path of My Computer\Control Panel */ + static WCHAR control_panel_path[] = { + ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}','\\', + ':',':','{','2','1','E','C','2','0','2','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','D','-','0','8','0','0','2','B','3','0','3','0','9','D','}', 0 }; + IShellFolder *psfDesktop; + HRESULT hr; + DWORD eaten = 0xdeadbeef; + LPITEMIDLIST pidl; + DWORD attr = ~0; + + hr = SHGetDesktopFolder(&psfDesktop); + ok(hr == S_OK, "SHGetDesktopFolder failed with error 0x%x\n", hr); + + hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, control_panel_path, &eaten, &pidl, &attr); + ok(hr == S_OK, "IShellFolder_ParseDisplayName failed with error 0x%x\n", hr); + todo_wine ok(eaten == 0xdeadbeef, "eaten should not have been set to %u\n", eaten); + todo_wine + ok((attr == (SFGAO_CANLINK | SFGAO_FOLDER)) || /* Win9x, NT4 */ + (attr == (SFGAO_CANLINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_STREAM)) || /* W2K */ + (attr == (SFGAO_CANLINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER)) || /* W2K, XP, W2K3 */ + (attr == (SFGAO_CANLINK | SFGAO_NONENUMERATED)) || /* Vista */ + (attr == SFGAO_CANLINK), /* Vista, W2K8 */ + "Unexpected attributes : %08x\n", attr); + + ILFree(pidl); +} + + +START_TEST(shfldr_special) +{ + test_parse_for_entire_network(); + test_parse_for_control_panel(); +} diff --git a/rostests/winetests/shell32/shlexec.c b/rostests/winetests/shell32/shlexec.c index 4b1bf1b6483..fa5a2162027 100755 --- a/rostests/winetests/shell32/shlexec.c +++ b/rostests/winetests/shell32/shlexec.c @@ -32,12 +32,13 @@ * we could check */ -#include -#include - /* Needed to get SEE_MASK_NOZONECHECKS with the PSDK */ #define NTDDI_WINXPSP1 0x05010100 #define NTDDI_VERSION NTDDI_WINXPSP1 +#define _WIN32_WINNT 0x0501 + +#include +#include #include "wtypes.h" #include "winbase.h" @@ -55,6 +56,7 @@ static char** myARGV; static char tmpdir[MAX_PATH]; static char child_file[MAX_PATH]; static DLLVERSIONINFO dllver; +static BOOL skip_noassoc_tests = FALSE; /*** @@ -89,7 +91,7 @@ static void strcat_param(char* str, const char* param) static char shell_call[2048]=""; static int shell_execute(LPCSTR operation, LPCSTR file, LPCSTR parameters, LPCSTR directory) { - int rc; + INT_PTR rc; strcpy(shell_call, "ShellExecute("); strcat_param(shell_call, operation); @@ -110,14 +112,24 @@ static int shell_execute(LPCSTR operation, LPCSTR file, LPCSTR parameters, LPCST * association it displays the 'Open With' dialog and I could not find * a flag to prevent this. */ - rc=(int)ShellExecute(NULL, operation, file, parameters, directory, - SW_SHOWNORMAL); + rc=(INT_PTR)ShellExecute(NULL, operation, file, parameters, directory, SW_SHOWNORMAL); if (rc > 32) { int wait_rc; wait_rc=WaitForSingleObject(hEvent, 5000); - ok(wait_rc==WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait_rc); + if (wait_rc == WAIT_TIMEOUT) + { + HWND wnd = FindWindowA("#32770", "Windows"); + if (wnd != NULL) + { + SendMessage(wnd, WM_CLOSE, 0, 0); + win_skip("Skipping shellexecute of file with unassociated extension\n"); + skip_noassoc_tests = TRUE; + rc = SE_ERR_NOASSOC; + } + } + ok(wait_rc==WAIT_OBJECT_0 || rc <= 32, "WaitForSingleObject returned %d\n", wait_rc); } /* The child process may have changed the result file, so let profile * functions know about it @@ -134,7 +146,7 @@ static int shell_execute_ex(DWORD mask, LPCSTR operation, LPCSTR file, { SHELLEXECUTEINFO sei; BOOL success; - int rc; + INT_PTR rc; strcpy(shell_call, "ShellExecuteEx("); strcat_param(shell_call, operation); @@ -167,9 +179,9 @@ static int shell_execute_ex(DWORD mask, LPCSTR operation, LPCSTR file, DeleteFile(child_file); SetLastError(0xcafebabe); success=ShellExecuteEx(&sei); - rc=(int)sei.hInstApp; + rc=(INT_PTR)sei.hInstApp; ok((success && rc > 32) || (!success && rc <= 32), - "%s rc=%d and hInstApp=%d is not allowed\n", shell_call, success, rc); + "%s rc=%d and hInstApp=%ld is not allowed\n", shell_call, success, rc); if (rc > 32) { @@ -200,7 +212,7 @@ static int shell_execute_ex(DWORD mask, LPCSTR operation, LPCSTR file, * ***/ -static void create_test_association(const char* extension) +static BOOL create_test_association(const char* extension) { HKEY hkey, hkey_shell; char class[MAX_PATH]; @@ -209,19 +221,25 @@ static void create_test_association(const char* extension) sprintf(class, "shlexec%s", extension); rc=RegCreateKeyEx(HKEY_CLASSES_ROOT, extension, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, NULL); - assert(rc==ERROR_SUCCESS); + if (rc != ERROR_SUCCESS) + return FALSE; + rc=RegSetValueEx(hkey, NULL, 0, REG_SZ, (LPBYTE) class, strlen(class)+1); - assert(rc==ERROR_SUCCESS); + ok(rc==ERROR_SUCCESS, "RegSetValueEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc); CloseHandle(hkey); rc=RegCreateKeyEx(HKEY_CLASSES_ROOT, class, 0, NULL, 0, KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS, NULL, &hkey, NULL); - assert(rc==ERROR_SUCCESS); + ok(rc==ERROR_SUCCESS, "RegCreateKeyEx '%s' failed, expected ERROR_SUCCESS, got %d\n", class, rc); + rc=RegCreateKeyEx(hkey, "shell", 0, NULL, 0, KEY_CREATE_SUB_KEY, NULL, &hkey_shell, NULL); - assert(rc==ERROR_SUCCESS); + ok(rc==ERROR_SUCCESS, "RegCreateKeyEx 'shell' failed, expected ERROR_SUCCESS, got %d\n", rc); + CloseHandle(hkey); CloseHandle(hkey_shell); + + return TRUE; } /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */ @@ -327,11 +345,11 @@ static void create_test_verb_dde(const char* extension, const char* verb, } else { - cmd=malloc(strlen(argv0)+10+strlen(child_file)+2+strlen(cmdtail)+1); + cmd=HeapAlloc(GetProcessHeap(), 0, strlen(argv0)+10+strlen(child_file)+2+strlen(cmdtail)+1); sprintf(cmd,"%s shlexec \"%s\" %s", argv0, child_file, cmdtail); rc=RegSetValueEx(hkey_cmd, NULL, 0, REG_SZ, (LPBYTE)cmd, strlen(cmd)+1); assert(rc==ERROR_SUCCESS); - free(cmd); + HeapFree(GetProcessHeap(), 0, cmd); } if (ddeexec) @@ -456,11 +474,67 @@ static void childPrintf(HANDLE h, const char* fmt, ...) WriteFile(h, buffer, strlen(buffer), &w, NULL); } +static DWORD ddeInst; +static HSZ hszTopic; +static char ddeExec[MAX_PATH], ddeApplication[MAX_PATH]; +static BOOL post_quit_on_execute; + +static HDDEDATA CALLBACK ddeCb(UINT uType, UINT uFmt, HCONV hConv, + HSZ hsz1, HSZ hsz2, HDDEDATA hData, + ULONG_PTR dwData1, ULONG_PTR dwData2) +{ + DWORD size = 0; + + if (winetest_debug > 2) + trace("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n", + uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2); + + switch (uType) + { + case XTYP_CONNECT: + if (!DdeCmpStringHandles(hsz1, hszTopic)) + { + size = DdeQueryString(ddeInst, hsz2, ddeApplication, MAX_PATH, CP_WINANSI); + assert(size < MAX_PATH); + return (HDDEDATA)TRUE; + } + return (HDDEDATA)FALSE; + + case XTYP_EXECUTE: + size = DdeGetData(hData, (LPBYTE)ddeExec, MAX_PATH, 0L); + assert(size < MAX_PATH); + DdeFreeDataHandle(hData); + if (post_quit_on_execute) + PostQuitMessage(0); + return (HDDEDATA)DDE_FACK; + + default: + return NULL; + } +} + +/* + * This is just to make sure the child won't run forever stuck in a GetMessage() + * loop when DDE fails for some reason. + */ +static void CALLBACK childTimeout(HWND wnd, UINT msg, UINT_PTR timer, DWORD time) +{ + trace("childTimeout called\n"); + + PostQuitMessage(0); +} + static void doChild(int argc, char** argv) { char* filename; - HANDLE hFile; + HANDLE hFile, map; int i; + int rc; + HSZ hszApplication; + UINT_PTR timer; + HANDLE dde_ready; + MSG msg; + char *shared_block; filename=argv[2]; hFile=CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); @@ -478,6 +552,51 @@ static void doChild(int argc, char** argv) trace("argvA%d=%s\n", i, argv[i]); childPrintf(hFile, "argvA%d=%s\r\n", i, encodeA(argv[i])); } + + map = OpenFileMappingA(FILE_MAP_READ, FALSE, "winetest_shlexec_dde_map"); + if (map != NULL) + { + shared_block = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 4096); + CloseHandle(map); + if (shared_block[0] != '\0' || shared_block[1] != '\0') + { + post_quit_on_execute = TRUE; + ddeInst = 0; + rc = DdeInitializeA(&ddeInst, ddeCb, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES | + CBF_FAIL_POKES | CBF_FAIL_REQUESTS, 0L); + assert(rc == DMLERR_NO_ERROR); + hszApplication = DdeCreateStringHandleA(ddeInst, shared_block, CP_WINANSI); + hszTopic = DdeCreateStringHandleA(ddeInst, shared_block + strlen(shared_block) + 1, CP_WINANSI); + assert(hszApplication && hszTopic); + assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_REGISTER | DNS_FILTEROFF)); + + timer = SetTimer(NULL, 0, 2500, childTimeout); + + dde_ready = CreateEvent(NULL, FALSE, FALSE, "winetest_shlexec_dde_ready"); + SetEvent(dde_ready); + CloseHandle(dde_ready); + + while (GetMessage(&msg, NULL, 0, 0)) + DispatchMessage(&msg); + + KillTimer(NULL, timer); + assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_UNREGISTER)); + assert(DdeFreeStringHandle(ddeInst, hszTopic)); + assert(DdeFreeStringHandle(ddeInst, hszApplication)); + assert(DdeUninitialize(ddeInst)); + } + else + { + dde_ready = CreateEvent(NULL, FALSE, FALSE, "winetest_shlexec_dde_ready"); + SetEvent(dde_ready); + CloseHandle(dde_ready); + } + + UnmapViewOfFile(shared_block); + + childPrintf(hFile, "ddeExec=%s\r\n", encodeA(ddeExec)); + } + CloseHandle(hFile); init_event(filename); @@ -581,7 +700,79 @@ static int _okChildInt(const char* file, int line, const char* key, int expected #define okChildPath(key, expected) _okChildPath(__FILE__, __LINE__, (key), (expected)) #define okChildInt(key, expected) _okChildInt(__FILE__, __LINE__, (key), (expected)) +/*** + * + * GetLongPathNameA equivalent that supports Win95 and WinNT + * + ***/ +static DWORD get_long_path_name(const char* shortpath, char* longpath, DWORD longlen) +{ + char tmplongpath[MAX_PATH]; + const char* p; + DWORD sp = 0, lp = 0; + DWORD tmplen; + WIN32_FIND_DATAA wfd; + HANDLE goit; + + if (!shortpath || !shortpath[0]) + return 0; + + if (shortpath[1] == ':') + { + tmplongpath[0] = shortpath[0]; + tmplongpath[1] = ':'; + lp = sp = 2; + } + + while (shortpath[sp]) + { + /* check for path delimiters and reproduce them */ + if (shortpath[sp] == '\\' || shortpath[sp] == '/') + { + if (!lp || tmplongpath[lp-1] != '\\') + { + /* strip double "\\" */ + tmplongpath[lp++] = '\\'; + } + tmplongpath[lp] = 0; /* terminate string */ + sp++; + continue; + } + + p = shortpath + sp; + if (sp == 0 && p[0] == '.' && (p[1] == '/' || p[1] == '\\')) + { + tmplongpath[lp++] = *p++; + tmplongpath[lp++] = *p++; + } + for (; *p && *p != '/' && *p != '\\'; p++); + tmplen = p - (shortpath + sp); + lstrcpyn(tmplongpath + lp, shortpath + sp, tmplen + 1); + /* Check if the file exists and use the existing file name */ + goit = FindFirstFileA(tmplongpath, &wfd); + if (goit == INVALID_HANDLE_VALUE) + return 0; + FindClose(goit); + strcpy(tmplongpath + lp, wfd.cFileName); + lp += strlen(tmplongpath + lp); + sp += tmplen; + } + tmplen = strlen(shortpath) - 1; + if ((shortpath[tmplen] == '/' || shortpath[tmplen] == '\\') && + (tmplongpath[lp - 1] != '/' && tmplongpath[lp - 1] != '\\')) + tmplongpath[lp++] = shortpath[tmplen]; + tmplongpath[lp] = 0; + + tmplen = strlen(tmplongpath) + 1; + if (tmplen <= longlen) + { + strcpy(longpath, tmplongpath); + tmplen--; /* length without 0 */ + } + + return tmplen; +} /*** * @@ -620,8 +811,8 @@ typedef struct static filename_tests_t filename_tests[]= { /* Test bad / nonexistent filenames */ - {NULL, "%s\\nonexistent.shlexec", 0x11, SE_ERR_FNF}, - {NULL, "%s\\nonexistent.noassoc", 0x11, SE_ERR_FNF}, + {NULL, "%s\\nonexistent.shlexec", 0x0, SE_ERR_FNF}, + {NULL, "%s\\nonexistent.noassoc", 0x0, SE_ERR_FNF}, /* Standard tests */ {NULL, "%s\\test file.shlexec", 0x0, 33}, @@ -637,7 +828,7 @@ static filename_tests_t filename_tests[]= {NULL, "%s\\test file.shlexec.noassoc", 0x0, SE_ERR_NOASSOC}, /* Test alternate verbs */ - {"LowerL", "%s\\nonexistent.shlexec", 0x11, SE_ERR_FNF}, + {"LowerL", "%s\\nonexistent.shlexec", 0x0, SE_ERR_FNF}, {"LowerL", "%s\\test file.noassoc", 0x0, SE_ERR_NOASSOC}, {"QuotedLowerL", "%s\\test file.shlexec", 0x0, 33}, @@ -671,6 +862,15 @@ static void test_filename(void) test=filename_tests; while (test->basename) { + BOOL quotedfile = FALSE; + + if (skip_noassoc_tests && test->rc == SE_ERR_NOASSOC) + { + win_skip("Skipping shellexecute of file with unassociated extension\n"); + test++; + continue; + } + sprintf(filename, test->basename, tmpdir); if (strchr(filename, '/')) { @@ -689,6 +889,8 @@ static void test_filename(void) else { char quoted[MAX_PATH + 2]; + + quotedfile = TRUE; sprintf(quoted, "\"%s\"", filename); rc=shell_execute(test->verb, quoted, NULL, NULL); } @@ -696,7 +898,9 @@ static void test_filename(void) rc=33; if ((test->todo & 0x1)==0) { - ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(rc==test->rc || + broken(quotedfile && rc == 2), /* NT4 */ + "%s failed: rc=%d err=%d\n", shell_call, rc, GetLastError()); } else todo_wine @@ -828,45 +1032,56 @@ static void test_find_executable(void) char filename[MAX_PATH]; char command[MAX_PATH]; const filename_tests_t* test; - int rc; + INT_PTR rc; - create_test_association(".sfe"); + if (!create_test_association(".sfe")) + { + skip("Unable to create association for '.sfe'\n"); + return; + } create_test_verb(".sfe", "Open", 1, "%1"); /* Don't test FindExecutable(..., NULL), it always crashes */ strcpy(command, "your word"); - rc=(int)FindExecutableA(NULL, NULL, command); - ok(rc == SE_ERR_FNF || rc > 32 /* nt4 */, "FindExecutable(NULL) returned %d\n", rc); + if (0) /* Can crash on Vista! */ + { + rc=(INT_PTR)FindExecutableA(NULL, NULL, command); + ok(rc == SE_ERR_FNF || rc > 32 /* nt4 */, "FindExecutable(NULL) returned %ld\n", rc); ok(strcmp(command, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command); + } strcpy(command, "your word"); - rc=(int)FindExecutableA(tmpdir, NULL, command); - ok(rc == SE_ERR_NOASSOC /* >= win2000 */ || rc > 32 /* win98, nt4 */, "FindExecutable(NULL) returned %d\n", rc); + rc=(INT_PTR)FindExecutableA(tmpdir, NULL, command); + ok(rc == SE_ERR_NOASSOC /* >= win2000 */ || rc > 32 /* win98, nt4 */, "FindExecutable(NULL) returned %ld\n", rc); ok(strcmp(command, "your word") != 0, "FindExecutable(NULL) returned command=[%s]\n", command); sprintf(filename, "%s\\test file.sfe", tmpdir); - rc=(int)FindExecutableA(filename, NULL, command); - ok(rc > 32, "FindExecutable(%s) returned %d\n", filename, rc); + rc=(INT_PTR)FindExecutableA(filename, NULL, command); + ok(rc > 32, "FindExecutable(%s) returned %ld\n", filename, rc); /* Depending on the platform, command could be '%1' or 'test file.sfe' */ - rc=(int)FindExecutableA("test file.sfe", tmpdir, command); - ok(rc > 32, "FindExecutable(%s) returned %d\n", filename, rc); + rc=(INT_PTR)FindExecutableA("test file.sfe", tmpdir, command); + ok(rc > 32, "FindExecutable(%s) returned %ld\n", filename, rc); - rc=(int)FindExecutableA("test file.sfe", NULL, command); - todo_wine ok(rc == SE_ERR_FNF, "FindExecutable(%s) returned %d\n", filename, rc); + rc=(INT_PTR)FindExecutableA("test file.sfe", NULL, command); + ok(rc == SE_ERR_FNF, "FindExecutable(%s) returned %ld\n", filename, rc); delete_test_association(".sfe"); - create_test_association(".shl"); + if (!create_test_association(".shl")) + { + skip("Unable to create association for '.shl'\n"); + return; + } create_test_verb(".shl", "Open", 0, "Open"); sprintf(filename, "%s\\test file.shl", tmpdir); - rc=(int)FindExecutableA(filename, NULL, command); - ok(rc == SE_ERR_FNF /* NT4 */ || rc > 32, "FindExecutable(%s) returned %d\n", filename, rc); + rc=(INT_PTR)FindExecutableA(filename, NULL, command); + ok(rc == SE_ERR_FNF /* NT4 */ || rc > 32, "FindExecutable(%s) returned %ld\n", filename, rc); sprintf(filename, "%s\\test file.shlfoo", tmpdir); - rc=(int)FindExecutableA(filename, NULL, command); + rc=(INT_PTR)FindExecutableA(filename, NULL, command); delete_test_association(".shl"); @@ -901,16 +1116,16 @@ static void test_find_executable(void) } /* Win98 does not '\0'-terminate command! */ memset(command, '\0', sizeof(command)); - rc=(int)FindExecutableA(filename, NULL, command); + rc=(INT_PTR)FindExecutableA(filename, NULL, command); if (rc > 32) rc=33; if ((test->todo & 0x10)==0) { - ok(rc==test->rc, "FindExecutable(%s) failed: rc=%d\n", filename, rc); + ok(rc==test->rc, "FindExecutable(%s) failed: rc=%ld\n", filename, rc); } else todo_wine { - ok(rc==test->rc, "FindExecutable(%s) failed: rc=%d\n", filename, rc); + ok(rc==test->rc, "FindExecutable(%s) failed: rc=%ld\n", filename, rc); } if (rc > 32) { @@ -963,7 +1178,8 @@ static void test_lnks(void) GetLastError()); okChildInt("argcA", 5); okChildString("argvA3", "Open"); - sprintf(filename, "%s\\test file.shlexec", tmpdir); + sprintf(params, "%s\\test file.shlexec", tmpdir); + get_long_path_name(params, filename, sizeof(filename)); okChildPath("argvA4", filename); sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir); @@ -1063,6 +1279,8 @@ static void test_exes(void) okChildInt("argcA", 4); okChildString("argvA3", "Exec"); + if (! skip_noassoc_tests) + { sprintf(filename, "%s\\test file.noassoc", tmpdir); if (CopyFile(argv0, filename, FALSE)) { @@ -1072,6 +1290,11 @@ static void test_exes(void) } } } + else + { + win_skip("Skipping shellexecute of file with unassociated extension\n"); + } +} static void test_exes_long(void) { @@ -1094,6 +1317,8 @@ static void test_exes_long(void) okChildInt("argcA", 4); okChildString("argvA3", longparam); + if (! skip_noassoc_tests) + { sprintf(filename, "%s\\test file.noassoc", tmpdir); if (CopyFile(argv0, filename, FALSE)) { @@ -1103,6 +1328,11 @@ static void test_exes_long(void) } } } + else + { + win_skip("Skipping shellexecute of file with unassociated extension\n"); + } +} typedef struct { @@ -1114,115 +1344,123 @@ typedef struct int expectedArgs; const char* expectedDdeExec; int todo; - int rc; } dde_tests_t; static dde_tests_t dde_tests[] = { /* Test passing and not passing command-line * argument, no DDE */ - {"", NULL, NULL, NULL, NULL, FALSE, "", 0x0, 33}, - {"\"%1\"", NULL, NULL, NULL, NULL, TRUE, "", 0x0, 33}, + {"", NULL, NULL, NULL, NULL, FALSE, "", 0x0}, + {"\"%1\"", NULL, NULL, NULL, NULL, TRUE, "", 0x0}, /* Test passing and not passing command-line * argument, with DDE */ - {"", "[open(\"%1\")]", "shlexec", "dde", NULL, FALSE, "[open(\"%s\")]", 0x0, 33}, - {"\"%1\"", "[open(\"%1\")]", "shlexec", "dde", NULL, TRUE, "[open(\"%s\")]", 0x0, 33}, + {"", "[open(\"%1\")]", "shlexec", "dde", NULL, FALSE, "[open(\"%s\")]", 0x0}, + {"\"%1\"", "[open(\"%1\")]", "shlexec", "dde", NULL, TRUE, "[open(\"%s\")]", 0x0}, /* Test unquoted %1 in command and ddeexec * (test filename has space) */ - {"%1", "[open(%1)]", "shlexec", "dde", NULL, 2, "[open(%s)]", 0x0, 33}, + {"%1", "[open(%1)]", "shlexec", "dde", NULL, 2, "[open(%s)]", 0x0}, /* Test ifexec precedence over ddeexec */ - {"", "[open(\"%1\")]", "shlexec", "dde", "[ifexec(\"%1\")]", FALSE, "[ifexec(\"%s\")]", 0x0, 33}, + {"", "[open(\"%1\")]", "shlexec", "dde", "[ifexec(\"%1\")]", FALSE, "[ifexec(\"%s\")]", 0x0}, /* Test default DDE topic */ - {"", "[open(\"%1\")]", "shlexec", NULL, NULL, FALSE, "[open(\"%s\")]", 0x0, 33}, + {"", "[open(\"%1\")]", "shlexec", NULL, NULL, FALSE, "[open(\"%s\")]", 0x0}, /* Test default DDE application */ - {"", "[open(\"%1\")]", NULL, "dde", NULL, FALSE, "[open(\"%s\")]", 0x0, 33}, + {"", "[open(\"%1\")]", NULL, "dde", NULL, FALSE, "[open(\"%s\")]", 0x0}, - {NULL, NULL, NULL, NULL, NULL, 0, 0x0, 0} + {NULL, NULL, NULL, NULL, NULL, 0, 0x0} }; -static DWORD ddeInst; -static HSZ hszTopic; -static char ddeExec[MAX_PATH], ddeApplication[MAX_PATH]; -static BOOL denyNextConnection; - -static HDDEDATA CALLBACK ddeCb(UINT uType, UINT uFmt, HCONV hConv, - HSZ hsz1, HSZ hsz2, HDDEDATA hData, - ULONG_PTR dwData1, ULONG_PTR dwData2) +static DWORD WINAPI hooked_WaitForInputIdle(HANDLE process, DWORD timeout) { - DWORD size = 0; + HANDLE dde_ready; + DWORD wait_result; - if (winetest_debug > 2) - trace("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n", - uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2); + dde_ready = CreateEventA(NULL, FALSE, FALSE, "winetest_shlexec_dde_ready"); + wait_result = WaitForSingleObject(dde_ready, timeout); + CloseHandle(dde_ready); - switch (uType) + return wait_result; +} + +/* + * WaitForInputIdle() will normally return immediately for console apps. That's + * a problem for us because ShellExecute will assume that an app is ready to + * receive DDE messages after it has called WaitForInputIdle() on that app. + * To work around that we install our own version of WaitForInputIdle() that + * will wait for the child to explicitly tell us that it is ready. We do that + * by changing the entry for WaitForInputIdle() in the shell32 import address + * table. + */ +static void hook_WaitForInputIdle(void *new_func) +{ + char *base; + PIMAGE_NT_HEADERS nt_headers; + DWORD import_directory_rva; + PIMAGE_IMPORT_DESCRIPTOR import_descriptor; + + base = (char *) GetModuleHandleA("shell32.dll"); + nt_headers = (PIMAGE_NT_HEADERS)(base + ((PIMAGE_DOS_HEADER) base)->e_lfanew); + import_directory_rva = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + + /* Search for the correct imported module by walking the import descriptors */ + import_descriptor = (PIMAGE_IMPORT_DESCRIPTOR)(base + import_directory_rva); + while (U(*import_descriptor).OriginalFirstThunk != 0) { - case XTYP_CONNECT: - if (!DdeCmpStringHandles(hsz1, hszTopic)) + char *import_module_name; + + import_module_name = base + import_descriptor->Name; + if (lstrcmpiA(import_module_name, "user32.dll") == 0 || + lstrcmpiA(import_module_name, "user32") == 0) { - if (denyNextConnection) - denyNextConnection = FALSE; - else + PIMAGE_THUNK_DATA int_entry; + PIMAGE_THUNK_DATA iat_entry; + + /* The import name table and import address table are two parallel + * arrays. We need the import name table to find the imported + * routine and the import address table to patch the address, so + * walk them side by side */ + int_entry = (PIMAGE_THUNK_DATA)(base + U(*import_descriptor).OriginalFirstThunk); + iat_entry = (PIMAGE_THUNK_DATA)(base + import_descriptor->FirstThunk); + while (int_entry->u1.Ordinal != 0) { - size = DdeQueryString(ddeInst, hsz2, ddeApplication, MAX_PATH, CP_WINANSI); - assert(size < MAX_PATH); - return (HDDEDATA)TRUE; + if (! IMAGE_SNAP_BY_ORDINAL(int_entry->u1.Ordinal)) + { + PIMAGE_IMPORT_BY_NAME import_by_name; + import_by_name = (PIMAGE_IMPORT_BY_NAME)(base + int_entry->u1.AddressOfData); + if (lstrcmpA((char *) import_by_name->Name, "WaitForInputIdle") == 0) + { + /* Found the correct routine in the correct imported module. Patch it. */ + DWORD old_prot; + VirtualProtect(&iat_entry->u1.Function, sizeof(ULONG_PTR), PAGE_READWRITE, &old_prot); + iat_entry->u1.Function = (ULONG_PTR) new_func; + VirtualProtect(&iat_entry->u1.Function, sizeof(ULONG_PTR), old_prot, &old_prot); + break; } } - return (HDDEDATA)FALSE; - - case XTYP_EXECUTE: - size = DdeGetData(hData, (LPBYTE)ddeExec, MAX_PATH, 0L); - assert(size < MAX_PATH); - DdeFreeDataHandle(hData); - return (HDDEDATA)DDE_FACK; - - default: - return NULL; + int_entry++; + iat_entry++; } + break; } -typedef struct -{ - char *filename; - DWORD threadIdParent; -} dde_thread_info_t; - -static DWORD CALLBACK ddeThread(LPVOID arg) -{ - dde_thread_info_t *info = (dde_thread_info_t *)arg; - assert(info && info->filename); - PostThreadMessage(info->threadIdParent, - WM_QUIT, - shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, info->filename, NULL, NULL), - 0L); - ExitThread(0); + import_descriptor++; +} } -/* ShellExecute won't successfully send DDE commands to console applications after starting them, - * so we run a DDE server in this application, deny the first connection request to make - * ShellExecute start the application, and then process the next DDE connection in this application - * to see the execute command that is sent. */ static void test_dde(void) { char filename[MAX_PATH], defApplication[MAX_PATH]; - HSZ hszApplication; - dde_thread_info_t info = { filename, GetCurrentThreadId() }; const dde_tests_t* test; char params[1024]; - DWORD threadId; - MSG msg; int rc; + HANDLE map; + char *shared_block; - ddeInst = 0; - rc = DdeInitializeA(&ddeInst, ddeCb, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES | - CBF_FAIL_POKES | CBF_FAIL_REQUESTS, 0L); - assert(rc == DMLERR_NO_ERROR); + hook_WaitForInputIdle((void *) hooked_WaitForInputIdle); sprintf(filename, "%s\\test file.sde", tmpdir); @@ -1230,35 +1468,45 @@ static void test_dde(void) strcpy(defApplication, strrchr(argv0, '\\')+1); *strchr(defApplication, '.') = 0; + map = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, + 4096, "winetest_shlexec_dde_map"); + shared_block = MapViewOfFile(map, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 4096); + test = dde_tests; while (test->command) { - create_test_association(".sde"); + if (!create_test_association(".sde")) + { + skip("Unable to create association for '.sfe'\n"); + return; + } create_test_verb_dde(".sde", "Open", 0, test->command, test->ddeexec, test->application, test->topic, test->ifexec); - hszApplication = DdeCreateStringHandleA(ddeInst, test->application ? - test->application : defApplication, CP_WINANSI); - hszTopic = DdeCreateStringHandleA(ddeInst, test->topic ? test->topic : SZDDESYS_TOPIC, - CP_WINANSI); - assert(hszApplication && hszTopic); - assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_REGISTER)); - denyNextConnection = TRUE; + + if (test->application != NULL || test->topic != NULL) + { + strcpy(shared_block, test->application ? test->application : defApplication); + strcpy(shared_block + strlen(shared_block) + 1, test->topic ? test->topic : SZDDESYS_TOPIC); + } + else + { + shared_block[0] = '\0'; + shared_block[1] = '\0'; + } ddeExec[0] = 0; - assert(CreateThread(NULL, 0, ddeThread, (LPVOID)&info, 0, &threadId)); - while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); - rc = msg.wParam > 32 ? 33 : msg.wParam; + rc = shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, filename, NULL, NULL); if ((test->todo & 0x1)==0) { - ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(32 < rc, "%s failed: rc=%d err=%d\n", shell_call, rc, GetLastError()); } else todo_wine { - ok(rc==test->rc, "%s failed: rc=%d err=%d\n", shell_call, + ok(32 < rc, "%s failed: rc=%d err=%d\n", shell_call, rc, GetLastError()); } - if (rc == 33) + if (32 < rc) { if ((test->todo & 0x2)==0) { @@ -1282,25 +1530,22 @@ static void test_dde(void) if ((test->todo & 0x8) == 0) { sprintf(params, test->expectedDdeExec, filename); - ok(StrCmpPath(params, ddeExec) == 0, - "ddeexec expected '%s', got '%s'\n", params, ddeExec); + okChildPath("ddeExec", params); } else todo_wine { sprintf(params, test->expectedDdeExec, filename); - ok(StrCmpPath(params, ddeExec) == 0, - "ddeexec expected '%s', got '%s'\n", params, ddeExec); + okChildPath("ddeExec", params); } } - assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_UNREGISTER)); - assert(DdeFreeStringHandle(ddeInst, hszTopic)); - assert(DdeFreeStringHandle(ddeInst, hszApplication)); delete_test_association(".sde"); test++; } - assert(DdeUninitialize(ddeInst)); + UnmapViewOfFile(shared_block); + CloseHandle(map); + hook_WaitForInputIdle((void *) WaitForInputIdle); } #define DDE_DEFAULT_APP_VARIANTS 2 @@ -1354,6 +1599,23 @@ static dde_default_app_tests_t dde_default_app_tests[] = {NULL, {NULL}, 0, {0}} }; +typedef struct +{ + char *filename; + DWORD threadIdParent; +} dde_thread_info_t; + +static DWORD CALLBACK ddeThread(LPVOID arg) +{ + dde_thread_info_t *info = arg; + assert(info && info->filename); + PostThreadMessage(info->threadIdParent, + WM_QUIT, + shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, info->filename, NULL, NULL), + 0L); + ExitThread(0); +} + static void test_dde_default_app(void) { char filename[MAX_PATH]; @@ -1365,6 +1627,7 @@ static void test_dde_default_app(void) MSG msg; int rc, which = 0; + post_quit_on_execute = FALSE; ddeInst = 0; rc = DdeInitializeA(&ddeInst, ddeCb, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES | CBF_FAIL_POKES | CBF_FAIL_REQUESTS, 0L); @@ -1383,18 +1646,21 @@ static void test_dde_default_app(void) test = dde_default_app_tests; while (test->command) { - create_test_association(".sde"); + if (!create_test_association(".sde")) + { + skip("Unable to create association for '.sde'\n"); + return; + } sprintf(params, test->command, tmpdir); create_test_verb_dde(".sde", "Open", 1, params, "[test]", NULL, "shlexec", NULL); - denyNextConnection = FALSE; ddeApplication[0] = 0; /* No application will be run as we will respond to the first DDE event, * so don't wait for it */ SetEvent(hEvent); - assert(CreateThread(NULL, 0, ddeThread, (LPVOID)&info, 0, &threadId)); + assert(CreateThread(NULL, 0, ddeThread, &info, 0, &threadId)); while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); rc = msg.wParam > 32 ? 33 : msg.wParam; @@ -1479,7 +1745,7 @@ static void init_test(void) r = CoInitialize(NULL); ok(SUCCEEDED(r), "CoInitialize failed (0x%08x)\n", r); - if (!SUCCEEDED(r)) + if (FAILED(r)) exit(1); rc=GetModuleFileName(NULL, argv0, sizeof(argv0)); @@ -1491,8 +1757,13 @@ static void init_test(void) "unable to find argv0!\n"); } - GetTempPathA(sizeof(tmpdir)/sizeof(*tmpdir), tmpdir); - assert(GetTempFileNameA(tmpdir, "wt", 0, child_file)!=0); + GetTempPathA(sizeof(filename), filename); + GetTempFileNameA(filename, "wt", 0, tmpdir); + DeleteFileA( tmpdir ); + rc = CreateDirectoryA( tmpdir, NULL ); + ok( rc, "failed to create %s err %u\n", tmpdir, GetLastError() ); + rc = GetTempFileNameA(tmpdir, "wt", 0, child_file); + assert(rc != 0); init_event(child_file); /* Set up the test files */ @@ -1543,7 +1814,11 @@ static void init_test(void) create_lnk(lnkfile, &desc, 0); /* Create a basic association suitable for most tests */ - create_test_association(".shlexec"); + if (!create_test_association(".shlexec")) + { + skip("Unable to create association for '.shlexec'\n"); + return; + } create_test_verb(".shlexec", "Open", 0, "Open \"%1\""); create_test_verb(".shlexec", "NoQuotes", 0, "NoQuotes %1"); create_test_verb(".shlexec", "LowerL", 0, "LowerL %l"); @@ -1562,10 +1837,13 @@ static void cleanup_test(void) while (*testfile) { sprintf(filename, *testfile, tmpdir); + /* Make sure we can delete the files ('test file.noassoc' is read-only now) */ + SetFileAttributes(filename, FILE_ATTRIBUTE_NORMAL); DeleteFile(filename); testfile++; } DeleteFile(child_file); + RemoveDirectoryA(tmpdir); /* Delete the test association */ delete_test_association(".shlexec"); @@ -1575,6 +1853,79 @@ static void cleanup_test(void) CoUninitialize(); } +static void test_commandline(void) +{ + static const WCHAR one[] = {'o','n','e',0}; + static const WCHAR two[] = {'t','w','o',0}; + static const WCHAR three[] = {'t','h','r','e','e',0}; + static const WCHAR four[] = {'f','o','u','r',0}; + + static const WCHAR fmt1[] = {'%','s',' ','%','s',' ','%','s',' ','%','s',0}; + static const WCHAR fmt2[] = {' ','%','s',' ','%','s',' ','%','s',' ','%','s',0}; + static const WCHAR fmt3[] = {'%','s','=','%','s',' ','%','s','=','\"','%','s','\"',0}; + static const WCHAR fmt4[] = {'\"','%','s','\"',' ','\"','%','s',' ','%','s','\"',' ','%','s',0}; + static const WCHAR fmt5[] = {'\\','\"','%','s','\"',' ','%','s','=','\"','%','s','\\','\"',' ','\"','%','s','\\','\"',0}; + static const WCHAR fmt6[] = {0}; + + static const WCHAR chkfmt1[] = {'%','s','=','%','s',0}; + static const WCHAR chkfmt2[] = {'%','s',' ','%','s',0}; + static const WCHAR chkfmt3[] = {'\\','\"','%','s','\"',0}; + static const WCHAR chkfmt4[] = {'%','s','=','%','s','\"',' ','%','s','\"',0}; + WCHAR cmdline[255]; + LPWSTR *args = (LPWSTR*)0xdeadcafe; + INT numargs = -1; + + wsprintfW(cmdline,fmt1,one,two,three,four); + args=CommandLineToArgvW(cmdline,&numargs); + if (args == NULL && numargs == -1) + { + win_skip("CommandLineToArgvW not implemented, skipping\n"); + return; + } + ok(numargs == 4, "expected 4 args, got %i\n",numargs); + ok(lstrcmpW(args[0],one)==0,"arg0 is not as expected\n"); + ok(lstrcmpW(args[1],two)==0,"arg1 is not as expected\n"); + ok(lstrcmpW(args[2],three)==0,"arg2 is not as expected\n"); + ok(lstrcmpW(args[3],four)==0,"arg3 is not as expected\n"); + + wsprintfW(cmdline,fmt2,one,two,three,four); + args=CommandLineToArgvW(cmdline,&numargs); + ok(numargs == 5, "expected 5 args, got %i\n",numargs); + ok(args[0][0]==0,"arg0 is not as expected\n"); + ok(lstrcmpW(args[1],one)==0,"arg1 is not as expected\n"); + ok(lstrcmpW(args[2],two)==0,"arg2 is not as expected\n"); + ok(lstrcmpW(args[3],three)==0,"arg3 is not as expected\n"); + ok(lstrcmpW(args[4],four)==0,"arg4 is not as expected\n"); + + wsprintfW(cmdline,fmt3,one,two,three,four); + args=CommandLineToArgvW(cmdline,&numargs); + ok(numargs == 2, "expected 2 args, got %i\n",numargs); + wsprintfW(cmdline,chkfmt1,one,two); + ok(lstrcmpW(args[0],cmdline)==0,"arg0 is not as expected\n"); + wsprintfW(cmdline,chkfmt1,three,four); + ok(lstrcmpW(args[1],cmdline)==0,"arg1 is not as expected\n"); + + wsprintfW(cmdline,fmt4,one,two,three,four); + args=CommandLineToArgvW(cmdline,&numargs); + ok(numargs == 3, "expected 3 args, got %i\n",numargs); + ok(lstrcmpW(args[0],one)==0,"arg0 is not as expected\n"); + wsprintfW(cmdline,chkfmt2,two,three); + ok(lstrcmpW(args[1],cmdline)==0,"arg1 is not as expected\n"); + ok(lstrcmpW(args[2],four)==0,"arg2 is not as expected\n"); + + wsprintfW(cmdline,fmt5,one,two,three,four); + args=CommandLineToArgvW(cmdline,&numargs); + ok(numargs == 2, "expected 2 args, got %i\n",numargs); + wsprintfW(cmdline,chkfmt3,one); + todo_wine ok(lstrcmpW(args[0],cmdline)==0,"arg0 is not as expected\n"); + wsprintfW(cmdline,chkfmt4,two,three,four); + todo_wine ok(lstrcmpW(args[1],cmdline)==0,"arg1 is not as expected\n"); + + wsprintfW(cmdline,fmt6); + args=CommandLineToArgvW(cmdline,&numargs); + ok(numargs == 1, "expected 1 args, got %i\n",numargs); +} + START_TEST(shlexec) { @@ -1594,6 +1945,7 @@ START_TEST(shlexec) test_exes_long(); test_dde(); test_dde_default_app(); + test_commandline(); cleanup_test(); } diff --git a/rostests/winetests/shell32/shlfileop.c b/rostests/winetests/shell32/shlfileop.c index df4bd411d1e..c24a6f2bf0d 100644 --- a/rostests/winetests/shell32/shlfileop.c +++ b/rostests/winetests/shell32/shlfileop.c @@ -32,15 +32,31 @@ #define FOF_NORECURSION 0x1000 #endif +/* Error codes could be pre-Win32 */ +#define DE_SAMEFILE 0x71 +#define DE_MANYSRC1DEST 0x72 +#define DE_DIFFDIR 0x73 +#define DE_OPCANCELLED 0x75 +#define DE_DESTSUBTREE 0x76 +#define DE_INVALIDFILES 0x7C +#define DE_DESTSAMETREE 0x7D +#define DE_FLDDESTISFILE 0x7E +#define DE_FILEDESTISFLD 0x80 +#define expect_retval(ret, ret_prewin32)\ + ok(retval == ret ||\ + broken(retval == ret_prewin32),\ + "Expected %d, got %d\n", ret, retval) + static CHAR CURR_DIR[MAX_PATH]; -static const WCHAR UNICODE_PATH[] = {'c',':','\\',0x00c4,'\0','\0'}; - /* "c:\Ä", or "c:\A" with diaeresis */ +static const WCHAR UNICODE_PATH[] = {'c',':','\\',0x00ae,'\0','\0'}; + /* "c:\®" can be used in all codepages */ /* Double-null termination needed for pFrom field of SHFILEOPSTRUCT */ static HMODULE hshell32; static int (WINAPI *pSHCreateDirectoryExA)(HWND, LPCSTR, LPSECURITY_ATTRIBUTES); static int (WINAPI *pSHCreateDirectoryExW)(HWND, LPCWSTR, LPSECURITY_ATTRIBUTES); static int (WINAPI *pSHFileOperationW)(LPSHFILEOPSTRUCTW); +static DWORD_PTR (WINAPI *pSHGetFileInfoW)(LPCWSTR, DWORD , SHFILEINFOW*, UINT, UINT); static int (WINAPI *pSHPathPrepareForWriteA)(HWND, IUnknown*, LPCSTR, DWORD); static int (WINAPI *pSHPathPrepareForWriteW)(HWND, IUnknown*, LPCWSTR, DWORD); @@ -50,6 +66,7 @@ static void InitFunctionPointers(void) pSHCreateDirectoryExA = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExA"); pSHCreateDirectoryExW = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExW"); pSHFileOperationW = (void*)GetProcAddress(hshell32, "SHFileOperationW"); + pSHGetFileInfoW = (void*)GetProcAddress(hshell32, "SHGetFileInfoW"); pSHPathPrepareForWriteA = (void*)GetProcAddress(hshell32, "SHPathPrepareForWriteA"); pSHPathPrepareForWriteW = (void*)GetProcAddress(hshell32, "SHPathPrepareForWriteW"); } @@ -81,6 +98,17 @@ static BOOL file_exists(const CHAR *name) return GetFileAttributesA(name) != INVALID_FILE_ATTRIBUTES; } +static BOOL dir_exists(const CHAR *name) +{ + DWORD attr; + BOOL dir; + + attr = GetFileAttributesA(name); + dir = ((attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY); + + return ((attr != INVALID_FILE_ATTRIBUTES) && dir); +} + static BOOL file_existsW(LPCWSTR name) { return GetFileAttributesW(name) != INVALID_FILE_ATTRIBUTES; @@ -154,24 +182,63 @@ static void clean_after_shfo_tests(void) static void test_get_file_info(void) { DWORD rc, rc2; - SHFILEINFO shfi, shfi2; + SHFILEINFOA shfi, shfi2; + SHFILEINFOW shfiw; char notepad[MAX_PATH]; + /* Test whether fields of SHFILEINFOA are always cleared */ + memset(&shfi, 0xcf, sizeof(shfi)); + rc=SHGetFileInfoA("", 0, &shfi, sizeof(shfi), 0); + ok(rc == 1, "SHGetFileInfoA('' | 0) should return 1, got 0x%x\n", rc); + todo_wine ok(shfi.hIcon == 0, "SHGetFileInfoA('' | 0) did not clear hIcon\n"); + todo_wine ok(shfi.szDisplayName[0] == 0, "SHGetFileInfoA('' | 0) did not clear szDisplayName[0]\n"); + todo_wine ok(shfi.szTypeName[0] == 0, "SHGetFileInfoA('' | 0) did not clear szTypeName[0]\n"); + ok(shfi.iIcon == 0xcfcfcfcf || + broken(shfi.iIcon != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */ + "SHGetFileInfoA('' | 0) should not clear iIcon\n"); + ok(shfi.dwAttributes == 0xcfcfcfcf || + broken(shfi.dwAttributes != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */ + "SHGetFileInfoA('' | 0) should not clear dwAttributes\n"); + + if (pSHGetFileInfoW) + { + HANDLE unset_icon; + /* Test whether fields of SHFILEINFOW are always cleared */ + memset(&shfiw, 0xcf, sizeof(shfiw)); + memset(&unset_icon, 0xcf, sizeof(unset_icon)); + rc=pSHGetFileInfoW(NULL, 0, &shfiw, sizeof(shfiw), 0); + ok(!rc, "SHGetFileInfoW(NULL | 0) should fail\n"); + ok(shfiw.hIcon == unset_icon, "SHGetFileInfoW(NULL | 0) should not clear hIcon\n"); + ok(shfiw.szDisplayName[0] == 0xcfcf, "SHGetFileInfoW(NULL | 0) should not clear szDisplayName[0]\n"); + ok(shfiw.szTypeName[0] == 0xcfcf, "SHGetFileInfoW(NULL | 0) should not clear szTypeName[0]\n"); + ok(shfiw.iIcon == 0xcfcfcfcf, "SHGetFileInfoW(NULL | 0) should not clear iIcon\n"); + ok(shfiw.dwAttributes == 0xcfcfcfcf, "SHGetFileInfoW(NULL | 0) should not clear dwAttributes\n"); + } + else + win_skip("SHGetFileInfoW is not available\n"); + + /* Test some flag combinations that MSDN claims are not allowed, * but which work anyway */ - shfi.dwAttributes=0xdeadbeef; + memset(&shfi, 0xcf, sizeof(shfi)); rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_ATTRIBUTES | SHGFI_USEFILEATTRIBUTES); - todo_wine ok(rc, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) failed\n"); + ok(rc == 1, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) should return 1, got 0x%x\n", rc); if (rc) - ok(shfi.dwAttributes != 0xdeadbeef, "dwFileAttributes is not set\n"); + ok(shfi.dwAttributes != 0xcfcfcfcf, "dwFileAttributes is not set\n"); + todo_wine ok(shfi.hIcon == 0, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) did not clear hIcon\n"); + todo_wine ok(shfi.szDisplayName[0] == 0, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) did not clear szDisplayName[0]\n"); + todo_wine ok(shfi.szTypeName[0] == 0, "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) did not clear szTypeName[0]\n"); + ok(shfi.iIcon == 0xcfcfcfcf || + broken(shfi.iIcon != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */ + "SHGetFileInfoA(c:\\nonexistent | SHGFI_ATTRIBUTES) should not clear iIcon\n"); rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_EXETYPE | SHGFI_USEFILEATTRIBUTES); - todo_wine ok(rc == 1, "SHGetFileInfoA(c:\\nonexistent | SHGFI_EXETYPE) returned %d\n", rc); + todo_wine ok(rc == 1, "SHGetFileInfoA(c:\\nonexistent | SHGFI_EXETYPE) should return 1, got 0x%x\n", rc); /* Test SHGFI_USEFILEATTRIBUTES support */ strcpy(shfi.szDisplayName, "dummy"); @@ -179,7 +246,7 @@ static void test_get_file_info(void) rc=SHGetFileInfoA("c:\\nonexistent", FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES); - ok(rc, "SHGetFileInfoA(c:\\nonexistent) failed\n"); + ok(rc == 1, "SHGetFileInfoA(c:\\nonexistent) should return 1, got 0x%x\n", rc); if (rc) { ok(strcpy(shfi.szDisplayName, "dummy") != 0, "SHGetFileInfoA(c:\\nonexistent) displayname is not set\n"); @@ -196,13 +263,13 @@ static void test_get_file_info(void) rc=SHGetFileInfoA(notepad, GetFileAttributes(notepad), &shfi, sizeof(shfi), SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES); - ok(rc, "SHGetFileInfoA(%s, SHGFI_USEFILEATTRIBUTES) failed\n", notepad); + ok(rc == 1, "SHGetFileInfoA(%s, SHGFI_USEFILEATTRIBUTES) should return 1, got 0x%x\n", notepad, rc); strcpy(shfi2.szDisplayName, "dummy"); shfi2.iIcon=0xdeadbeef; rc2=SHGetFileInfoA(notepad, 0, &shfi2, sizeof(shfi2), SHGFI_ICONLOCATION); - ok(rc2, "SHGetFileInfoA(%s) failed\n", notepad); + ok(rc2 == 1, "SHGetFileInfoA(%s) failed %x\n", notepad, rc2); if (rc && rc2) { ok(lstrcmpi(shfi2.szDisplayName, shfi.szDisplayName) == 0, "wrong display name %s != %s\n", shfi.szDisplayName, shfi2.szDisplayName); @@ -216,18 +283,211 @@ static void test_get_file_info(void) rc=SHGetFileInfoA("test4.txt", GetFileAttributes("test4.txt"), &shfi, sizeof(shfi), SHGFI_ICONLOCATION | SHGFI_USEFILEATTRIBUTES); - ok(rc, "SHGetFileInfoA(test4.txt/, SHGFI_USEFILEATTRIBUTES) failed\n"); + ok(rc == 1, "SHGetFileInfoA(test4.txt/, SHGFI_USEFILEATTRIBUTES) should return 1, got 0x%x\n", rc); strcpy(shfi2.szDisplayName, "dummy"); shfi2.iIcon=0xdeadbeef; rc2=SHGetFileInfoA("test4.txt", 0, &shfi2, sizeof(shfi2), SHGFI_ICONLOCATION); - ok(rc2, "SHGetFileInfoA(test4.txt/) failed\n"); + ok(rc2 == 1, "SHGetFileInfoA(test4.txt/) should return 1, got 0x%x\n", rc2); if (rc && rc2) { ok(lstrcmpi(shfi2.szDisplayName, shfi.szDisplayName) == 0, "wrong display name %s != %s\n", shfi.szDisplayName, shfi2.szDisplayName); ok(shfi2.iIcon == shfi.iIcon, "wrong icon index %d != %d\n", shfi.iIcon, shfi2.iIcon); } + /* with drive root directory */ + strcpy(shfi.szDisplayName, "dummy"); + strcpy(shfi.szTypeName, "dummy"); + shfi.hIcon=(HICON) 0xdeadbeef; + shfi.iIcon=0xdeadbeef; + shfi.dwAttributes=0xdeadbeef; + rc=SHGetFileInfoA("c:\\", 0, &shfi, sizeof(shfi), + SHGFI_TYPENAME | SHGFI_DISPLAYNAME | SHGFI_ICON | SHGFI_SMALLICON); + ok(rc == 1, "SHGetFileInfoA(c:\\) should return 1, got 0x%x\n", rc); + ok(lstrcmp(shfi.szDisplayName, "dummy") != 0, "display name was expected to change\n"); + ok(lstrcmp(shfi.szTypeName, "dummy") != 0, "type name was expected to change\n"); + ok(shfi.hIcon != (HICON) 0xdeadbeef, "hIcon was expected to change\n"); + ok(shfi.iIcon != 0xdeadbeef, "iIcon was expected to change\n"); +} + +static void test_get_file_info_iconlist(void) +{ + /* Test retrieving a handle to the system image list, and + * what that returns for hIcon + */ + HRESULT hr; + HIMAGELIST hSysImageList; + LPITEMIDLIST pidList; + SHFILEINFOA shInfoa; + SHFILEINFOW shInfow; + + hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidList); + if (FAILED(hr)) { + skip("can't get desktop pidl\n"); + return; + } + + memset(&shInfoa, 0xcf, sizeof(shInfoa)); + hSysImageList = (HIMAGELIST) SHGetFileInfoA((const char *)pidList, 0, + &shInfoa, sizeof(shInfoa), + SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_PIDL); + ok((hSysImageList != INVALID_HANDLE_VALUE) && (hSysImageList > (HIMAGELIST) 0xffff), "Can't get handle for CSIDL_DESKTOP imagelist\n"); + todo_wine ok(shInfoa.hIcon == 0, "SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear hIcon\n"); + todo_wine ok(shInfoa.szTypeName[0] == 0, "SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear szTypeName[0]\n"); + ok(shInfoa.iIcon != 0xcfcfcfcf, "SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) should set iIcon\n"); + ok(shInfoa.dwAttributes == 0xcfcfcfcf || + shInfoa.dwAttributes == 0 || /* Vista */ + broken(shInfoa.dwAttributes != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */ + "SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL), unexpected dwAttributes\n"); + CloseHandle(hSysImageList); + + if (!pSHGetFileInfoW) + { + win_skip("SHGetFileInfoW is not available\n"); + ILFree(pidList); + return; + } + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hSysImageList = (HIMAGELIST) pSHGetFileInfoW((const WCHAR *)pidList, 0, + &shInfow, sizeof(shInfow), + SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_PIDL); + if (!hSysImageList) + { + win_skip("SHGetFileInfoW is not implemented\n"); + return; + } + ok((hSysImageList != INVALID_HANDLE_VALUE) && (hSysImageList > (HIMAGELIST) 0xffff), "Can't get handle for CSIDL_DESKTOP imagelist\n"); + todo_wine ok(shInfow.hIcon == 0, "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear hIcon\n"); + ok(shInfow.szTypeName[0] == 0, "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear szTypeName[0]\n"); + ok(shInfow.iIcon != 0xcfcfcfcf, "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) should set iIcon\n"); + ok(shInfow.dwAttributes == 0xcfcfcfcf || + shInfoa.dwAttributes == 0, /* Vista */ + "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) unexpected dwAttributes\n"); + CloseHandle(hSysImageList); + + /* Various suposidly invalid flag testing */ + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON); + ok(hr != 0, "SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n"); + ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf || + shInfoa.dwAttributes==0, /* Vista */ + "unexpected dwAttributes\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON); + ok(hr != 0, " SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n"); + ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n"); + ok(shInfow.hIcon!=(HICON)0xcfcfcfcf && shInfow.hIcon!=0,"hIcon invalid\n"); + if (shInfow.hIcon!=(HICON)0xcfcfcfcf) DestroyIcon(shInfow.hIcon); + todo_wine ok(shInfow.dwAttributes==0,"dwAttributes not set\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON); + ok(hr != 0, "SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON Failed\n"); + ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n"); + ok(shInfow.hIcon!=(HICON)0xcfcfcfcf && shInfow.hIcon!=0,"hIcon invalid\n"); + if (shInfow.hIcon != (HICON)0xcfcfcfcf) DestroyIcon(shInfow.hIcon); + todo_wine ok(shInfow.dwAttributes==0,"dwAttributes not set\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON); + ok(hr != 0, "SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON Failed\n"); + ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf || + shInfoa.dwAttributes==0, /* Vista */ + "unexpected dwAttributes\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_OPENICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON); + ok(hr != 0, "SHGFI_OPENICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n"); + todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON); + ok(hr != 0, "SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n"); + todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON); + ok(hr != 0, "SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n"); + todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON| + SHGFI_ATTRIBUTES); + ok(hr != 0, "SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_ATTRIBUTES Failed\n"); + ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n"); + ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON| + SHGFI_EXETYPE); + todo_wine ok(hr != 0, "SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_EXETYPE Failed\n"); + ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf || + shInfoa.dwAttributes==0, /* Vista */ + "unexpected dwAttributes\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_EXETYPE); + todo_wine ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_EXETYPE Failed\n"); + todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_ATTRIBUTES); + ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_ATTRIBUTES Failed\n"); + todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n"); + ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL| + SHGFI_ATTRIBUTES); + ok(hr != 0, "SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_ATTRIBUTES Failed\n"); + ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n"); + ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE); + todo_wine ok(hr != 0, "SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE Failed\n"); + ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf || + shInfoa.dwAttributes==0, /* Vista */ + "unexpected dwAttributes\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE); + todo_wine ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE Failed\n"); + todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n"); + ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n"); + + memset(&shInfow, 0xcf, sizeof(shInfow)); + hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow), + SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_ATTRIBUTES); + ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_ATTRIBUTES Failed\n"); + todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n"); + ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n"); + + ILFree(pidList); } @@ -266,23 +526,25 @@ static void test_delete(void) shfo.hwnd = NULL; shfo.wFunc = FO_DELETE; shfo.pFrom = buf; - shfo.pTo = "\0"; + shfo.pTo = NULL; shfo.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT; shfo.hNameMappings = NULL; shfo.lpszProgressTitle = NULL; ok(!SHFileOperationA(&shfo), "Deletion was not successful\n"); - ok(file_exists("test4.txt"), "Directory should not have been removed\n"); + ok(dir_exists("test4.txt"), "Directory should not have been removed\n"); ok(!file_exists("test1.txt"), "File should have been removed\n"); + ok(!file_exists("test2.txt"), "File should have been removed\n"); + ok(!file_exists("test3.txt"), "File should have been removed\n"); ret = SHFileOperationA(&shfo); - ok(!ret, "Directory exists, but is not removed, ret=%d\n", ret); - ok(file_exists("test4.txt"), "Directory should not have been removed\n"); + ok(ret == ERROR_SUCCESS, "Directory exists, but is not removed, ret=%d\n", ret); + ok(dir_exists("test4.txt"), "Directory should not have been removed\n"); shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; ok(!SHFileOperationA(&shfo), "Directory is not removed\n"); - ok(!file_exists("test4.txt"), "Directory should have been removed\n"); + ok(!dir_exists("test4.txt"), "Directory should have been removed\n"); ret = SHFileOperationA(&shfo); ok(!ret, "The requested file does not exist, ret=%d\n", ret); @@ -292,13 +554,13 @@ static void test_delete(void) buf[strlen(buf) + 1] = '\0'; ok(MoveFileA("test1.txt", "test4.txt\\test1.txt"), "Filling the subdirectory failed\n"); ok(!SHFileOperationA(&shfo), "Directory is not removed\n"); - ok(!file_exists("test4.txt"), "Directory is not removed\n"); + ok(!dir_exists("test4.txt"), "Directory is not removed\n"); init_shfo_tests(); shfo.pFrom = "test1.txt\0test4.txt\0"; ok(!SHFileOperationA(&shfo), "Directory and a file are not removed\n"); ok(!file_exists("test1.txt"), "The file should have been removed\n"); - ok(!file_exists("test4.txt"), "Directory should have been removed\n"); + ok(!dir_exists("test4.txt"), "Directory should have been removed\n"); ok(file_exists("test2.txt"), "This file should not have been removed\n"); /* FOF_FILESONLY does not delete a dir matching a wildcard */ @@ -308,17 +570,21 @@ static void test_delete(void) ok(!SHFileOperation(&shfo), "Failed to delete files\n"); ok(!file_exists("test1.txt"), "test1.txt should have been removed\n"); ok(!file_exists("test_5.txt"), "test_5.txt should have been removed\n"); - ok(file_exists("test4.txt"), "test4.txt should not have been removed\n"); + ok(dir_exists("test4.txt"), "test4.txt should not have been removed\n"); /* FOF_FILESONLY only deletes a dir if explicitly specified */ init_shfo_tests(); shfo.pFrom = "test_?.txt\0test4.txt\0"; ok(!SHFileOperation(&shfo), "Failed to delete files and directory\n"); - ok(!file_exists("test4.txt"), "test4.txt should have been removed\n"); + ok(!dir_exists("test4.txt") || + broken(dir_exists("test4.txt")), /* NT4 */ + "test4.txt should have been removed\n"); ok(!file_exists("test_5.txt"), "test_5.txt should have been removed\n"); ok(file_exists("test1.txt"), "test1.txt should not have been removed\n"); /* try to delete an invalid filename */ + if (0) { + /* this crashes on win9x */ init_shfo_tests(); shfo.pFrom = "\0"; shfo.fFlags &= ~FOF_FILESONLY; @@ -327,32 +593,56 @@ static void test_delete(void) ok(ret == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", ret); ok(!shfo.fAnyOperationsAborted, "Expected no aborted operations\n"); ok(file_exists("test1.txt"), "Expected test1.txt to exist\n"); + } /* try an invalid function */ init_shfo_tests(); shfo.pFrom = "test1.txt\0"; shfo.wFunc = 0; ret = SHFileOperation(&shfo); - ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret); + ok(ret == ERROR_INVALID_PARAMETER || + broken(ret == ERROR_SUCCESS), /* Win9x, NT4 */ + "Expected ERROR_INVALID_PARAMETER, got %d\n", ret); ok(file_exists("test1.txt"), "Expected test1.txt to exist\n"); /* try an invalid list, only one null terminator */ + if (0) { + /* this crashes on win9x */ init_shfo_tests(); shfo.pFrom = ""; shfo.wFunc = FO_DELETE; ret = SHFileOperation(&shfo); ok(ret == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", ret); ok(file_exists("test1.txt"), "Expected test1.txt to exist\n"); + } + + /* delete a nonexistent file */ + shfo.pFrom = "nonexistent.txt\0"; + shfo.wFunc = FO_DELETE; + ret = SHFileOperation(&shfo); + todo_wine + ok(ret == 1026 || + ret == ERROR_FILE_NOT_FOUND || /* Vista */ + broken(ret == ERROR_SUCCESS), /* NT4 */ + "Expected 1026 or ERROR_FILE_NOT_FOUND, got %d\n", ret); /* delete a dir, and then a file inside the dir, same as * deleting a nonexistent file */ + if (ret != ERROR_FILE_NOT_FOUND) + { + /* Vista would throw up a dialog box that we can't suppress */ init_shfo_tests(); shfo.pFrom = "testdir2\0testdir2\\one.txt\0"; ret = SHFileOperation(&shfo); - ok(ret == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", ret); - ok(!file_exists("testdir2"), "Expected testdir2 to not exist\n"); + ok(ret == ERROR_PATH_NOT_FOUND || + broken(ret == ERROR_SUCCESS), /* NT4 */ + "Expected ERROR_PATH_NOT_FOUND, got %d\n", ret); + ok(!dir_exists("testdir2"), "Expected testdir2 to not exist\n"); ok(!file_exists("testdir2\\one.txt"), "Expected testdir2\\one.txt to not exist\n"); + } + else + skip("Test would show a dialog box\n"); /* try the FOF_NORECURSION flag, continues deleting subdirs */ init_shfo_tests(); @@ -361,7 +651,7 @@ static void test_delete(void) ret = SHFileOperation(&shfo); ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret); ok(!file_exists("testdir2\\one.txt"), "Expected testdir2\\one.txt to not exist\n"); - ok(!file_exists("testdir2\\nested"), "Expected testdir2\\nested to exist\n"); + ok(!dir_exists("testdir2\\nested"), "Expected testdir2\\nested to not exist\n"); } /* tests the FO_RENAME action */ @@ -382,20 +672,34 @@ static void test_rename(void) set_curr_dir_path(from, "test1.txt\0"); set_curr_dir_path(to, "test4.txt\0"); - ok(SHFileOperationA(&shfo), "File is not renamed moving to other directory " - "when specifying directory name only\n"); - ok(file_exists("test1.txt"), "The file is removed\n"); + retval = SHFileOperationA(&shfo); + ok(retval == ERROR_ALREADY_EXISTS || + retval == DE_FILEDESTISFLD || /* Vista */ + broken(retval == ERROR_INVALID_NAME), /* Win9x, NT4 */ + "Expected ERROR_ALREADY_EXISTS or DE_FILEDESTISFLD, got %d\n", retval); + ok(file_exists("test1.txt"), "The file is renamed\n"); set_curr_dir_path(from, "test3.txt\0"); set_curr_dir_path(to, "test4.txt\\test1.txt\0"); - ok(!SHFileOperationA(&shfo), "File is renamed moving to other directory\n"); + retval = SHFileOperationA(&shfo); + if (retval == DE_DIFFDIR) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(!file_exists("test4.txt\\test1.txt"), "The file is renamed\n"); + } + else + { + ok(retval == ERROR_SUCCESS, "File is renamed moving to other directory\n"); ok(file_exists("test4.txt\\test1.txt"), "The file is not renamed\n"); + } set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0"); - retval = SHFileOperationA(&shfo); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */ - ok(!retval || retval == ERROR_GEN_FAILURE || retval == ERROR_INVALID_TARGET_HANDLE, - "Can't rename many files, retval = %d\n", retval); + retval = SHFileOperationA(&shfo); + ok(retval == ERROR_GEN_FAILURE || + retval == DE_MANYSRC1DEST || /* Vista */ + broken(retval == ERROR_SUCCESS), /* Win9x */ + "Expected ERROR_GEN_FAILURE or DE_MANYSRC1DEST , got %d\n", retval); ok(file_exists("test1.txt"), "The file is renamed - many files are specified\n"); memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA)); @@ -403,74 +707,103 @@ static void test_rename(void) set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0"); - retval = SHFileOperationA(&shfo2); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */ - ok(!retval || retval == ERROR_GEN_FAILURE || retval == ERROR_INVALID_TARGET_HANDLE, - "Can't rename many files, retval = %d\n", retval); + retval = SHFileOperationA(&shfo2); + ok(retval == ERROR_GEN_FAILURE || + retval == DE_MANYSRC1DEST || /* Vista */ + broken(retval == ERROR_SUCCESS), /* Win9x */ + "Expected ERROR_GEN_FAILURE or DE_MANYSRC1DEST files, got %d\n", retval); ok(file_exists("test1.txt"), "The file is not renamed - many files are specified\n"); set_curr_dir_path(from, "test1.txt\0"); set_curr_dir_path(to, "test6.txt\0"); retval = SHFileOperationA(&shfo); - ok(!retval, "Rename file failed, retval = %d\n", retval); + ok(retval == ERROR_SUCCESS, "Rename file failed, retval = %d\n", retval); ok(!file_exists("test1.txt"), "The file is not renamed\n"); ok(file_exists("test6.txt"), "The file is not renamed\n"); set_curr_dir_path(from, "test6.txt\0"); set_curr_dir_path(to, "test1.txt\0"); retval = SHFileOperationA(&shfo); - ok(!retval, "Rename file back failed, retval = %d\n", retval); + ok(retval == ERROR_SUCCESS, "Rename file back failed, retval = %d\n", retval); set_curr_dir_path(from, "test4.txt\0"); set_curr_dir_path(to, "test6.txt\0"); retval = SHFileOperationA(&shfo); - ok(!retval, "Rename dir failed, retval = %d\n", retval); - ok(!file_exists("test4.txt"), "The dir is not renamed\n"); - ok(file_exists("test6.txt"), "The dir is not renamed\n"); + ok(retval == ERROR_SUCCESS, "Rename dir failed, retval = %d\n", retval); + ok(!dir_exists("test4.txt"), "The dir is not renamed\n"); + ok(dir_exists("test6.txt"), "The dir is not renamed\n"); set_curr_dir_path(from, "test6.txt\0"); set_curr_dir_path(to, "test4.txt\0"); retval = SHFileOperationA(&shfo); - ok(!retval, "Rename dir back failed, retval = %d\n", retval); + ok(retval == ERROR_SUCCESS, "Rename dir back failed, retval = %d\n", retval); + ok(dir_exists("test4.txt"), "The dir is not renamed\n"); /* try to rename more than one file to a single file */ shfo.pFrom = "test1.txt\0test2.txt\0"; shfo.pTo = "a.txt\0"; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_GEN_FAILURE, "Expected ERROR_GEN_FAILURE, got %d\n", retval); + ok(retval == ERROR_GEN_FAILURE || + retval == DE_MANYSRC1DEST || /* Vista */ + broken(retval == ERROR_SUCCESS), /* Win9x */ + "Expected ERROR_GEN_FAILURE or DE_MANYSRC1DEST, got %d\n", retval); ok(file_exists("test1.txt"), "Expected test1.txt to exist\n"); ok(file_exists("test2.txt"), "Expected test2.txt to exist\n"); + ok(!file_exists("a.txt"), "Expected a.txt to not exist\n"); /* pFrom doesn't exist */ shfo.pFrom = "idontexist\0"; shfo.pTo = "newfile\0"; retval = SHFileOperationA(&shfo); - ok(retval == 1026, "Expected 1026, got %d\n", retval); + ok(retval == 1026 || + retval == ERROR_FILE_NOT_FOUND || /* Vista */ + broken(retval == ERROR_SUCCESS), /* NT4 */ + "Expected 1026 or ERROR_FILE_NOT_FOUND, got %d\n", retval); ok(!file_exists("newfile"), "Expected newfile to not exist\n"); /* pTo already exist */ shfo.pFrom = "test1.txt\0"; shfo.pTo = "test2.txt\0"; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_ALREADY_EXISTS, "Expected ERROR_ALREADY_EXISTS, got %d\n", retval); + if (retval == ERROR_SUCCESS) + { + /* Vista and W2K8 (broken or new behavior ?) */ + createTestFile("test1.txt"); + } + else + { + ok(retval == ERROR_ALREADY_EXISTS || + broken(retval == DE_OPCANCELLED) || /* NT4 */ + broken(retval == ERROR_INVALID_NAME), /* Win9x */ + "Expected ERROR_ALREADY_EXISTS, got %d\n", retval); + } /* pFrom is valid, but pTo is empty */ shfo.pFrom = "test1.txt\0"; shfo.pTo = "\0"; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + ok(retval == ERROR_CANCELLED || + retval == DE_DIFFDIR || /* Vista */ + broken(retval == DE_OPCANCELLED) || /* Win9x */ + broken(retval == 65652), /* NT4 */ + "Expected ERROR_CANCELLED or DE_DIFFDIR\n"); ok(file_exists("test1.txt"), "Expected test1.txt to exist\n"); /* pFrom is empty */ shfo.pFrom = "\0"; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", retval); + ok(retval == ERROR_ACCESS_DENIED || + retval == DE_MANYSRC1DEST || /* Vista */ + broken(retval == ERROR_SUCCESS), /* Win9x */ + "Expected ERROR_ACCESS_DENIED or DE_MANYSRC1DEST, got %d\n", retval); /* pFrom is NULL, commented out because it crashes on nt 4.0 */ -#if 0 + if (0) + { shfo.pFrom = NULL; retval = SHFileOperationA(&shfo); ok(retval == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", retval); -#endif +} } /* tests the FO_COPY action */ @@ -482,6 +815,7 @@ static void test_copy(void) FILEOP_FLAGS tmp_flags; DWORD retval; LPSTR ptr; + BOOL on_nt4 = FALSE; shfo.hwnd = NULL; shfo.wFunc = FO_COPY; @@ -493,9 +827,23 @@ static void test_copy(void) set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0"); - ok(SHFileOperationA(&shfo), "Can't copy many files\n"); - ok(!file_exists("test6.txt"), "The file is not copied - many files are " + retval = SHFileOperationA(&shfo); + if (dir_exists("test6.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("test6.txt\\test1.txt"), "The file is not copied - many files " + "are specified as a target\n"); + DeleteFileA("test6.txt\\test2.txt"); + RemoveDirectoryA("test6.txt\\test4.txt"); + RemoveDirectoryA("test6.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(!file_exists("test6.txt"), "The file is copied - many files are " "specified as a target\n"); + } memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA)); shfo2.fFlags |= FOF_MULTIDESTFILES; @@ -503,7 +851,7 @@ static void test_copy(void) set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0"); ok(!SHFileOperationA(&shfo2), "Can't copy many files\n"); - ok(file_exists("test6.txt"), "The file is copied - many files are " + ok(file_exists("test6.txt"), "The file is not copied - many files are " "specified as a target\n"); DeleteFileA("test6.txt"); DeleteFileA("test7.txt"); @@ -512,9 +860,24 @@ static void test_copy(void) /* number of sources do not correspond to number of targets */ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); set_curr_dir_path(to, "test6.txt\0test7.txt\0"); - ok(SHFileOperationA(&shfo2), "Can't copy many files\n"); - ok(!file_exists("test6.txt"), "The file is not copied - many files are " + retval = SHFileOperationA(&shfo2); + if (dir_exists("test6.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == DE_DESTSAMETREE, "Expected DE_DESTSAMETREE, got %d\n", retval); + ok(DeleteFileA("test6.txt\\test1.txt"), "The file is not copied - many files " + "are specified as a target\n"); + RemoveDirectoryA("test6.txt"); + ok(DeleteFileA("test7.txt\\test2.txt"), "The file is not copied - many files " + "are specified as a target\n"); + RemoveDirectoryA("test7.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(!file_exists("test6.txt"), "The file is copied - many files are " "specified as a target\n"); + } set_curr_dir_path(from, "test1.txt\0"); set_curr_dir_path(to, "test4.txt\0"); @@ -557,13 +920,15 @@ static void test_copy(void) ok(!file_exists("testdir2\\test1.txt"), "The file is not copied yet\n"); ok(!file_exists("testdir2\\test2.txt"), "The file is not copied yet\n"); retval = SHFileOperationA(&shfo); - if (!retval) + if (retval == ERROR_SUCCESS) /* Win 95/NT returns success but copies only the files up to the nonexistent source */ ok(file_exists("testdir2\\test1.txt"), "The file is not copied\n"); else { - /* Win 98/ME/2K/XP fail the entire operation with return code 1026 if one source file does not exist */ - ok(retval == 1026, "Files are copied to other directory\n"); + /* Failure if one source file does not exist */ + ok(retval == 1026 || /* Win 98/ME/2K/XP */ + retval == ERROR_FILE_NOT_FOUND, /* Vista and W2K8 */ + "Files are copied to other directory\n"); ok(!file_exists("testdir2\\test1.txt"), "The file is copied\n"); } ok(!file_exists("testdir2\\test2.txt"), "The file is copied\n"); @@ -595,15 +960,26 @@ static void test_copy(void) init_shfo_tests(); shfo.pFrom = from; shfo.pTo = to; + /* suppress the error-dialog in win9x here */ + shfo.fFlags |= FOF_NOERRORUI; set_curr_dir_path(from, "test1.txt\0test2.txt\0"); set_curr_dir_path(to, "test3.txt\0"); retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + if (retval == DE_FLDDESTISFILE) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(shfo.fAnyOperationsAborted, "Expected aborted operations\n"); + } ok(!file_exists("test3.txt\\test2.txt"), "Expected test3.txt\\test2.txt to not exist\n"); /* try to copy many files to nonexistent directory */ DeleteFile(to); + shfo.fFlags &= ~FOF_NOERRORUI; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); @@ -617,27 +993,61 @@ static void test_copy(void) shfo.pTo = "testdir2\\a.txt\0testdir2\\b.txt\0testdir2\\c.txt\0testdir2\\d.txt\0"; shfo.fFlags |= FOF_NOERRORUI | FOF_MULTIDESTFILES; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); - ok(shfo.fAnyOperationsAborted, "Expected aborted operations\n"); + if (dir_exists("testdir2\\a.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFile("testdir2\\a.txt\\test1.txt"), "Expected testdir2\\a.txt\\test1.txt to exist\n"); + RemoveDirectory("testdir2\\a.txt"); + ok(DeleteFile("testdir2\\b.txt\\test2.txt"), "Expected testdir2\\b.txt\\test2.txt to exist\n"); + RemoveDirectory("testdir2\\b.txt"); + ok(DeleteFile("testdir2\\c.txt\\test3.txt"), "Expected testdir2\\c.txt\\test3.txt to exist\n"); + RemoveDirectory("testdir2\\c.txt"); + ok(!file_exists("testdir2\\d.txt"), "Expected testdir2\\d.txt to not exist\n"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(shfo.fAnyOperationsAborted || + broken(!shfo.fAnyOperationsAborted), /* NT4 */ + "Expected aborted operations\n"); ok(!file_exists("testdir2\\a.txt"), "Expected testdir2\\a.txt to not exist\n"); + } /* send in FOF_MULTIDESTFILES with too many destination files */ shfo.pFrom = "test1.txt\0test2.txt\0test3.txt\0"; shfo.pTo = "e.txt\0f.txt\0"; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); - ok(shfo.fAnyOperationsAborted, "Expected aborted operations\n"); + if (dir_exists("e.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == DE_SAMEFILE, "Expected DE_SAMEFILE, got %d\n", retval); + ok(DeleteFile("e.txt\\test1.txt"), "Expected e.txt\\test1.txt to exist\n"); + RemoveDirectory("e.txt"); + ok(DeleteFile("f.txt\\test2.txt"), "Expected f.txt\\test2.txt to exist\n"); + RemoveDirectory("f.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(shfo.fAnyOperationsAborted || + broken(!shfo.fAnyOperationsAborted), /* NT4 */ + "Expected aborted operations\n"); ok(!file_exists("e.txt"), "Expected e.txt to not exist\n"); + } /* use FOF_MULTIDESTFILES with files and a source directory */ shfo.pFrom = "test1.txt\0test2.txt\0test4.txt\0"; shfo.pTo = "testdir2\\a.txt\0testdir2\\b.txt\0testdir2\\c.txt\0"; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(retval == ERROR_SUCCESS || + broken(retval == 0x100a1), /* WinMe */ + "Expected ERROR_SUCCESS, got %d\n", retval); ok(DeleteFile("testdir2\\a.txt"), "Expected testdir2\\a.txt to exist\n"); ok(DeleteFile("testdir2\\b.txt"), "Expected testdir2\\b.txt to exist\n"); + if (retval == ERROR_SUCCESS) ok(RemoveDirectory("testdir2\\c.txt"), "Expected testdir2\\c.txt to exist\n"); /* try many dest files without FOF_MULTIDESTFILES flag */ @@ -646,15 +1056,29 @@ static void test_copy(void) shfo.fAnyOperationsAborted = FALSE; shfo.fFlags &= ~FOF_MULTIDESTFILES; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + if (dir_exists("a.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFile("a.txt\\test1.txt"), "Expected a.txt\\test1.txt to exist\n"); + ok(DeleteFile("a.txt\\test2.txt"), "Expected a.txt\\test2.txt to exist\n"); + ok(DeleteFile("a.txt\\test3.txt"), "Expected a.txt\\test3.txt to exist\n"); + RemoveDirectory("a.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(!file_exists("a.txt"), "Expected a.txt to not exist\n"); + } /* try a glob */ shfo.pFrom = "test?.txt\0"; shfo.pTo = "testdir2\0"; shfo.fFlags &= ~FOF_MULTIDESTFILES; retval = SHFileOperation(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(retval == ERROR_SUCCESS || + broken(retval == 0x100a1), /* WinMe */ + "Expected ERROR_SUCCESS, got %d\n", retval); ok(file_exists("testdir2\\test1.txt"), "Expected testdir2\\test1.txt to exist\n"); /* try a glob with FOF_FILESONLY */ @@ -665,7 +1089,7 @@ static void test_copy(void) retval = SHFileOperation(&shfo); ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); ok(file_exists("testdir2\\test1.txt"), "Expected testdir2\\test1.txt to exist\n"); - ok(!file_exists("testdir2\\test4.txt"), "Expected testdir2\\test4.txt to not exist\n"); + ok(!dir_exists("testdir2\\test4.txt"), "Expected testdir2\\test4.txt to not exist\n"); /* try a glob with FOF_MULTIDESTFILES and the same number * of dest files that we would expect @@ -676,9 +1100,24 @@ static void test_copy(void) shfo.fFlags &= ~FOF_FILESONLY; shfo.fFlags |= FOF_MULTIDESTFILES; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); - ok(shfo.fAnyOperationsAborted, "Expected aborted operations\n"); + if (dir_exists("testdir2\\a.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFile("testdir2\\a.txt\\test1.txt"), "Expected testdir2\\a.txt\\test1.txt to exist\n"); + ok(DeleteFile("testdir2\\a.txt\\test2.txt"), "Expected testdir2\\a.txt\\test2.txt to exist\n"); + ok(DeleteFile("testdir2\\a.txt\\test3.txt"), "Expected testdir2\\a.txt\\test3.txt to exist\n"); + ok(RemoveDirectory("testdir2\\a.txt\\test4.txt"), "Expected testdir2\\a.txt\\test4.txt to exist\n"); + RemoveDirectory("testdir2\\a.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(shfo.fAnyOperationsAborted || + broken(!shfo.fAnyOperationsAborted), /* NT4 */ + "Expected aborted operations\n"); ok(!file_exists("testdir2\\a.txt"), "Expected testdir2\\test1.txt to not exist\n"); + } ok(!RemoveDirectory("b.txt"), "b.txt should not exist\n"); /* copy one file to two others, second is ignored */ @@ -688,27 +1127,66 @@ static void test_copy(void) shfo.pTo = "b.txt\0c.txt\0"; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); + if (retval == DE_OPCANCELLED) + { + /* NT4 fails and doesn't copy any files */ + ok(!file_exists("b.txt"), "Expected b.txt to not exist\n"); + /* Needed to skip some tests */ + win_skip("Skipping some tests on NT4\n"); + on_nt4 = TRUE; + } + else + { ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); ok(DeleteFile("b.txt"), "Expected b.txt to exist\n"); + } ok(!DeleteFile("c.txt"), "Expected c.txt to not exist\n"); /* copy two file to three others, all fail */ shfo.pFrom = "test1.txt\0test2.txt\0"; shfo.pTo = "b.txt\0c.txt\0d.txt\0"; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); - ok(shfo.fAnyOperationsAborted, "Expected operations to be aborted\n"); + if (dir_exists("b.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFile("b.txt\\test1.txt"), "Expected b.txt\\test1.txt to exist\n"); + RemoveDirectory("b.txt"); + ok(DeleteFile("c.txt\\test2.txt"), "Expected c.txt\\test2.txt to exist\n"); + RemoveDirectory("c.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(shfo.fAnyOperationsAborted || + broken(!shfo.fAnyOperationsAborted), /* NT4 */ + "Expected aborted operations\n"); ok(!DeleteFile("b.txt"), "Expected b.txt to not exist\n"); + } /* copy one file and one directory to three others */ shfo.pFrom = "test1.txt\0test4.txt\0"; shfo.pTo = "b.txt\0c.txt\0d.txt\0"; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); - ok(shfo.fAnyOperationsAborted, "Expected operations to be aborted\n"); + if (dir_exists("b.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFile("b.txt\\test1.txt"), "Expected b.txt\\test1.txt to exist\n"); + RemoveDirectory("b.txt"); + ok(RemoveDirectory("c.txt\\test4.txt"), "Expected c.txt\\test4.txt to exist\n"); + RemoveDirectory("c.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(shfo.fAnyOperationsAborted || + broken(!shfo.fAnyOperationsAborted), /* NT4 */ + "Expected aborted operations\n"); ok(!DeleteFile("b.txt"), "Expected b.txt to not exist\n"); ok(!DeleteFile("c.txt"), "Expected c.txt to not exist\n"); + } /* copy a directory with a file beneath it, plus some files */ createTestFile("test4.txt\\a.txt"); @@ -717,26 +1195,50 @@ static void test_copy(void) shfo.fFlags &= ~FOF_MULTIDESTFILES; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); - ok(DeleteFile("testdir2\\test1.txt"), "Expected newdir\\test1.txt to exist\n"); + ok(retval == ERROR_SUCCESS || + broken(retval == 0x100a1), /* WinMe */ + "Expected ERROR_SUCCESS, got %d\n", retval); + if (retval == ERROR_SUCCESS) + { + ok(DeleteFile("testdir2\\test1.txt"), "Expected testdir2\\test1.txt to exist\n"); ok(DeleteFile("testdir2\\test4.txt\\a.txt"), "Expected a.txt to exist\n"); ok(RemoveDirectory("testdir2\\test4.txt"), "Expected testdir2\\test4.txt to exist\n"); + } /* copy one directory and a file in that dir to another dir */ shfo.pFrom = "test4.txt\0test4.txt\\a.txt\0"; shfo.pTo = "testdir2\0"; retval = SHFileOperation(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(retval == ERROR_SUCCESS || + broken(retval == 0x100a1), /* WinMe */ + "Expected ERROR_SUCCESS, got %d\n", retval); + if (retval == ERROR_SUCCESS) + { ok(DeleteFile("testdir2\\test4.txt\\a.txt"), "Expected a.txt to exist\n"); ok(DeleteFile("testdir2\\a.txt"), "Expected testdir2\\a.txt to exist\n"); + } /* copy a file in a directory first, and then the directory to a nonexistent dir */ shfo.pFrom = "test4.txt\\a.txt\0test4.txt\0"; shfo.pTo = "nonexistent\0"; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); - ok(shfo.fAnyOperationsAborted, "Expected operations to be aborted\n"); + if (dir_exists("nonexistent")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFile("nonexistent\\test4.txt\\a.txt"), "Expected nonexistent\\test4.txt\\a.txt to exist\n"); + RemoveDirectory("nonexistent\\test4.txt"); + ok(DeleteFile("nonexistent\\a.txt"), "Expected nonexistent\\a.txt to exist\n"); + RemoveDirectory("nonexistent"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(shfo.fAnyOperationsAborted || + broken(!shfo.fAnyOperationsAborted), /* NT4 */ + "Expected aborted operations\n"); ok(!file_exists("nonexistent\\test4.txt"), "Expected nonexistent\\test4.txt to not exist\n"); + } DeleteFile("test4.txt\\a.txt"); /* destination is same as source file */ @@ -745,10 +1247,17 @@ static void test_copy(void) shfo.fAnyOperationsAborted = FALSE; shfo.fFlags = FOF_NOERRORUI | FOF_MULTIDESTFILES; retval = SHFileOperation(&shfo); - ok(retval == ERROR_NO_MORE_SEARCH_HANDLES, - "Expected ERROR_NO_MORE_SEARCH_HANDLES, got %d\n", retval); - ok(!shfo.fAnyOperationsAborted, "Expected no operations to be aborted\n"); + if (retval == DE_OPCANCELLED) + { + /* NT4 fails and doesn't copy any files */ + ok(!file_exists("b.txt"), "Expected b.txt to not exist\n"); + } + else + { + ok(retval == DE_SAMEFILE, "Expected DE_SAMEFILE, got %d\n", retval); ok(DeleteFile("b.txt"), "Expected b.txt to exist\n"); + } + ok(!shfo.fAnyOperationsAborted, "Expected no operations to be aborted\n"); ok(!file_exists("c.txt"), "Expected c.txt to not exist\n"); /* destination is same as source directory */ @@ -756,8 +1265,18 @@ static void test_copy(void) shfo.pTo = "b.txt\0test4.txt\0c.txt\0"; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + if (retval == DE_OPCANCELLED) + { + /* NT4 fails and doesn't copy any files */ + ok(!file_exists("b.txt"), "Expected b.txt to not exist\n"); + } + else + { + ok(retval == ERROR_SUCCESS || + retval == DE_DESTSAMETREE, /* Vista */ + "Expected ERROR_SUCCESS or DE_DESTSAMETREE, got %d\n", retval); ok(DeleteFile("b.txt"), "Expected b.txt to exist\n"); + } ok(!file_exists("c.txt"), "Expected c.txt to not exist\n"); /* copy a directory into itself, error displayed in UI */ @@ -766,7 +1285,9 @@ static void test_copy(void) shfo.fFlags &= ~FOF_MULTIDESTFILES; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(retval == ERROR_SUCCESS || + retval == DE_DESTSUBTREE, /* Vista */ + "Expected ERROR_SUCCESS or DE_DESTSUBTREE, got %d\n", retval); ok(!RemoveDirectory("test4.txt\\newdir"), "Expected test4.txt\\newdir to not exist\n"); /* copy a directory to itself, error displayed in UI */ @@ -774,7 +1295,9 @@ static void test_copy(void) shfo.pTo = "test4.txt\0"; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(retval == ERROR_SUCCESS || + retval == DE_DESTSUBTREE, /* Vista */ + "Expected ERROR_SUCCESS or DE_DESTSUBTREE, got %d\n", retval); /* copy a file into a directory, and the directory into itself */ shfo.pFrom = "test1.txt\0test4.txt\0"; @@ -782,7 +1305,9 @@ static void test_copy(void) shfo.fAnyOperationsAborted = FALSE; shfo.fFlags |= FOF_NOCONFIRMATION; retval = SHFileOperation(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(retval == ERROR_SUCCESS || + retval == DE_DESTSUBTREE, /* Vista */ + "Expected ERROR_SUCCESS or DE_DESTSUBTREE, got %d\n", retval); ok(DeleteFile("test4.txt\\test1.txt"), "Expected test4.txt\\test1.txt to exist\n"); /* copy a file to a file, and the directory into itself */ @@ -790,28 +1315,46 @@ static void test_copy(void) shfo.pTo = "test4.txt\\a.txt\0"; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + if (dir_exists("test4.txt\\a.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == DE_DESTSUBTREE, "Expected DE_DESTSUBTREE, got %d\n", retval); + ok(DeleteFile("test4.txt\\a.txt\\test1.txt"), "Expected test4.txt\\a.txt\\test1.txt to exist\n"); + RemoveDirectory("test4.txt\\a.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(!file_exists("test4.txt\\a.txt"), "Expected test4.txt\\a.txt to not exist\n"); + } /* copy a nonexistent file to a nonexistent directory */ shfo.pFrom = "e.txt\0"; shfo.pTo = "nonexistent\0"; shfo.fAnyOperationsAborted = FALSE; retval = SHFileOperation(&shfo); - ok(retval == 1026, "Expected 1026, got %d\n", retval); + ok(retval == 1026 || + retval == ERROR_FILE_NOT_FOUND || /* Vista */ + broken(retval == ERROR_SUCCESS), /* NT4 */ + "Expected 1026 or ERROR_FILE_NOT_FOUND, got %d\n", retval); ok(!file_exists("nonexistent\\e.txt"), "Expected nonexistent\\e.txt to not exist\n"); ok(!file_exists("nonexistent"), "Expected nonexistent to not exist\n"); /* Overwrite tests */ clean_after_shfo_tests(); init_shfo_tests(); + if (!on_nt4) + { + /* NT4 would throw up some dialog boxes and doesn't copy files that are needed + * in subsequent tests. + */ shfo.fFlags = FOF_NOCONFIRMATION; shfo.pFrom = "test1.txt\0"; shfo.pTo = "test2.txt\0"; shfo.fAnyOperationsAborted = FALSE; /* without FOF_NOCONFIRMATION the confirmation is Yes/No */ retval = SHFileOperation(&shfo); - ok(retval == 0, "Expected 0, got %d\n", retval); + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); ok(file_has_content("test2.txt", "test1.txt\n"), "The file was not copied\n"); shfo.pFrom = "test3.txt\0test1.txt\0"; @@ -819,7 +1362,7 @@ static void test_copy(void) shfo.fFlags = FOF_NOCONFIRMATION | FOF_MULTIDESTFILES; /* without FOF_NOCONFIRMATION the confirmation is Yes/Yes to All/No/Cancel */ retval = SHFileOperation(&shfo); - ok(retval == 0, "Expected 0, got %d\n", retval); + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); ok(file_has_content("test2.txt", "test3.txt\n"), "The file was not copied\n"); shfo.pFrom = "one.txt\0"; @@ -829,43 +1372,69 @@ static void test_copy(void) retval = SHFileOperation(&shfo); ok(retval == 0, "Expected 0, got %d\n", retval); ok(file_has_content("testdir2\\one.txt", "test1.txt\n"), "The file was not copied\n"); + } createTestFile("test4.txt\\test1.txt"); shfo.pFrom = "test4.txt\0"; shfo.pTo = "testdir2\0"; + /* WinMe needs FOF_NOERRORUI */ + shfo.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI; + retval = SHFileOperation(&shfo); + ok(retval == ERROR_SUCCESS || + broken(retval == 0x100a1), /* WinMe */ + "Expected ERROR_SUCCESS, got %d\n", retval); shfo.fFlags = FOF_NOCONFIRMATION; - ok(!SHFileOperation(&shfo), "First SHFileOperation failed\n"); + if (ERROR_SUCCESS) + { createTestFile("test4.txt\\.\\test1.txt"); /* modify the content of the file */ /* without FOF_NOCONFIRMATION the confirmation is "This folder already contains a folder named ..." */ retval = SHFileOperation(&shfo); ok(retval == 0, "Expected 0, got %d\n", retval); ok(file_has_content("testdir2\\test4.txt\\test1.txt", "test4.txt\\.\\test1.txt\n"), "The file was not copied\n"); + } createTestFile("one.txt"); - /* no double-NULL terminator for pFrom */ - memset(from, 'a', MAX_PATH); + /* pFrom contains bogus 2nd name longer than MAX_PATH */ + memset(from, 'a', MAX_PATH*2); + memset(from+MAX_PATH*2, 0, 2); lstrcpyA(from, "one.txt"); shfo.pFrom = from; shfo.pTo = "two.txt\0"; shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); - ok(retval == 1148 || retval == 1026, "Expected 1148 or 1026, got %d\n", retval); + ok(retval == 1148 || retval == 1026 || + retval == ERROR_ACCESS_DENIED || /* win2k */ + retval == DE_INVALIDFILES, /* Vista */ + "Unexpected return value, got %d\n", retval); ok(DeleteFileA("one.txt"), "Expected file to exist\n"); + if (dir_exists("two.txt")) + /* Vista and W2K8 (broken or new behavior ?) */ + ok(RemoveDirectory("two.txt"), "Expected two.txt to exist\n"); + else ok(!DeleteFileA("two.txt"), "Expected file to not exist\n"); createTestFile("one.txt"); - /* no double-NULL terminator for pTo */ - memset(to, 'a', MAX_PATH); + /* pTo contains bogus 2nd name longer than MAX_PATH */ + memset(to, 'a', MAX_PATH*2); + memset(to+MAX_PATH*2, 0, 2); lstrcpyA(to, "two.txt"); shfo.pFrom = "one.txt\0"; shfo.pTo = to; shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); + if (retval == DE_OPCANCELLED) + { + /* NT4 fails and doesn't copy any files */ + ok(!file_exists("two.txt"), "Expected two.txt to not exist\n"); + } + else + { ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("two.txt"), "Expected file to exist\n"); + } ok(DeleteFileA("one.txt"), "Expected file to exist\n"); - ok(DeleteFileA("two.txt"), "Expected file to exist\n"); createTestFile("one.txt"); @@ -874,69 +1443,108 @@ static void test_copy(void) shfo.pTo = "two.txt\0three.txt\0"; shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); + if (retval == DE_OPCANCELLED) + { + /* NT4 fails and doesn't copy any files */ + ok(!file_exists("two.txt"), "Expected two.txt to not exist\n"); + } + else + { ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("two.txt"), "Expected file to exist\n"); + } ok(DeleteFileA("one.txt"), "Expected file to exist\n"); - ok(DeleteFileA("two.txt"), "Expected file to exist\n"); createTestFile("one.txt"); - /* no double-NULL terminator for pFrom and pTo */ - memset(from, 'a', MAX_PATH); - memset(to, 'a', MAX_PATH); + /* both pFrom and pTo contain bogus 2nd names longer than MAX_PATH */ + memset(from, 'a', MAX_PATH*2); + memset(from+MAX_PATH*2, 0, 2); + memset(to, 'a', MAX_PATH*2); + memset(to+MAX_PATH*2, 0, 2); lstrcpyA(from, "one.txt"); lstrcpyA(to, "two.txt"); shfo.pFrom = from; shfo.pTo = to; shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); - ok(retval == 1148 || retval == 1026, "Expected 1148 or 1026, got %d\n", retval); + ok(retval == 1148 || retval == 1026 || + retval == ERROR_ACCESS_DENIED || /* win2k */ + retval == DE_INVALIDFILES, /* Vista */ + "Unexpected return value, got %d\n", retval); ok(DeleteFileA("one.txt"), "Expected file to exist\n"); + if (dir_exists("two.txt")) + /* Vista and W2K8 (broken or new behavior ?) */ + ok(RemoveDirectory("two.txt"), "Expected two.txt to exist\n"); + else ok(!DeleteFileA("two.txt"), "Expected file to not exist\n"); createTestFile("one.txt"); - /* no double-NULL terminator for pTo, FOF_MULTIDESTFILES */ - memset(to, 'a', MAX_PATH); + /* pTo contains bogus 2nd name longer than MAX_PATH, FOF_MULTIDESTFILES */ + memset(to, 'a', MAX_PATH*2); + memset(to+MAX_PATH*2, 0, 2); lstrcpyA(to, "two.txt"); shfo.pFrom = "one.txt\0"; shfo.pTo = to; shfo.fFlags = FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); + if (retval == DE_OPCANCELLED) + { + /* NT4 fails and doesn't copy any files */ + ok(!file_exists("two.txt"), "Expected two.txt to not exist\n"); + } + else + { ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("two.txt"), "Expected file to exist\n"); + } ok(DeleteFileA("one.txt"), "Expected file to exist\n"); - ok(DeleteFileA("two.txt"), "Expected file to exist\n"); createTestFile("one.txt"); createTestFile("two.txt"); - /* no double-NULL terminator for pTo, + /* pTo contains bogus 2nd name longer than MAX_PATH, * multiple source files, * dest directory does not exist */ memset(to, 'a', 2 * MAX_PATH); + memset(to+MAX_PATH*2, 0, 2); lstrcpyA(to, "threedir"); shfo.pFrom = "one.txt\0two.txt\0"; shfo.pTo = to; shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + if (dir_exists("threedir")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("threedir\\one.txt"), "Expected file to exist\n"); + ok(DeleteFileA("threedir\\two.txt"), "Expected file to exist\n"); + ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(!DeleteFileA("threedir\\one.txt"), "Expected file to not exist\n"); ok(!DeleteFileA("threedir\\two.txt"), "Expected file to not exist\n"); + ok(!DeleteFileA("threedir"), "Expected file to not exist\n"); + ok(!RemoveDirectoryA("threedir"), "Expected dir to not exist\n"); + } ok(DeleteFileA("one.txt"), "Expected file to exist\n"); ok(DeleteFileA("two.txt"), "Expected file to exist\n"); - ok(!DeleteFileA("threedir"), "Expected file to not exist\n"); - ok(!RemoveDirectoryA("threedir"), "Expected dir to not exist\n"); createTestFile("one.txt"); createTestFile("two.txt"); CreateDirectoryA("threedir", NULL); - /* no double-NULL terminator for pTo, + /* pTo contains bogus 2nd name longer than MAX_PATH, * multiple source files, * dest directory does exist */ memset(to, 'a', 2 * MAX_PATH); + memset(to+MAX_PATH*2, 0, 2); lstrcpyA(to, "threedir"); shfo.pFrom = "one.txt\0two.txt\0"; shfo.pTo = to; @@ -949,14 +1557,18 @@ static void test_copy(void) ok(DeleteFileA("two.txt"), "Expected file to exist\n"); ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n"); + if (0) { + /* this crashes on win9x */ createTestFile("one.txt"); createTestFile("two.txt"); - /* no double-NULL terminator for pTo, + /* pTo contains bogus 2nd name longer than MAX_PATH, * multiple source files, FOF_MULTIDESTFILES * dest dir does not exist */ + memset(to, 'a', 2 * MAX_PATH); + memset(to+MAX_PATH*2, 0, 2); lstrcpyA(to, "threedir"); shfo.pFrom = "one.txt\0two.txt\0"; shfo.pTo = to; @@ -974,16 +1586,19 @@ static void test_copy(void) /* file exists in win2k */ DeleteFileA("threedir"); + } + createTestFile("one.txt"); createTestFile("two.txt"); CreateDirectoryA("threedir", NULL); - /* no double-NULL terminator for pTo, + /* pTo contains bogus 2nd name longer than MAX_PATH, * multiple source files, FOF_MULTIDESTFILES * dest dir does exist */ memset(to, 'a', 2 * MAX_PATH); + memset(to+MAX_PATH*2, 0, 2); lstrcpyA(to, "threedir"); ptr = to + lstrlenA(to) + 1; lstrcpyA(ptr, "fourdir"); @@ -993,13 +1608,23 @@ static void test_copy(void) FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); - ok(DeleteFileA("threedir\\one.txt"), "Expected file to exist\n"); - ok(DeleteFileA("threedir\\two.txt"), "Expected file to exist\n"); ok(DeleteFileA("one.txt"), "Expected file to exist\n"); ok(DeleteFileA("two.txt"), "Expected file to exist\n"); - ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n"); + ok(DeleteFileA("threedir\\one.txt"), "Expected file to exist\n"); + if (dir_exists("fourdir")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(!DeleteFileA("threedir\\two.txt"), "Expected file to not exist\n"); + ok(DeleteFileA("fourdir\\two.txt"), "Expected file to exist\n"); + RemoveDirectoryA("fourdir"); + } + else + { + ok(DeleteFileA("threedir\\two.txt"), "Expected file to exist\n"); ok(!DeleteFileA("fourdir"), "Expected file to not exist\n"); ok(!RemoveDirectoryA("fourdir"), "Expected dir to not exist\n"); + } + ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n"); createTestFile("one.txt"); createTestFile("two.txt"); @@ -1014,14 +1639,22 @@ static void test_copy(void) shfo.fFlags = FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + ok(retval == ERROR_CANCELLED || + retval == DE_FILEDESTISFLD || /* Vista */ + broken(retval == DE_OPCANCELLED), /* Win9x, NT4 */ + "Expected ERROR_CANCELLED or DE_FILEDESTISFLD. got %d\n", retval); + if (file_exists("threedir\\threedir")) + { + /* NT4 */ + ok(DeleteFileA("threedir\\threedir"), "Expected file to exist\n"); + } ok(!DeleteFileA("threedir\\one.txt"), "Expected file to not exist\n"); ok(!DeleteFileA("threedir\\two.txt"), "Expected file to not exist\n"); ok(DeleteFileA("one.txt"), "Expected file to exist\n"); ok(DeleteFileA("two.txt"), "Expected file to exist\n"); ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n"); ok(!DeleteFileA("fourdir"), "Expected file to not exist\n"); - ok(!RemoveDirectoryA("fourdir"), "Expected dit to not exist\n"); + ok(!RemoveDirectoryA("fourdir"), "Expected dir to not exist\n"); createTestFile("one.txt"); createTestFile("two.txt"); @@ -1037,13 +1670,23 @@ static void test_copy(void) FOF_SILENT | FOF_NOERRORUI; retval = SHFileOperation(&shfo); ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); - ok(DeleteFileA("threedir\\one.txt"), "Expected file to exist\n"); - ok(DeleteFileA("threedir\\two.txt"), "Expected file to exist\n"); ok(DeleteFileA("one.txt"), "Expected file to exist\n"); ok(DeleteFileA("two.txt"), "Expected file to exist\n"); - ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n"); + ok(DeleteFileA("threedir\\one.txt"), "Expected file to exist\n"); + if (dir_exists("fourdir")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(!DeleteFileA("threedir\\two.txt"), "Expected file to not exist\n"); + ok(DeleteFileA("fourdir\\two.txt"), "Expected file to exist\n"); + RemoveDirectoryA("fourdir"); + } + else + { + ok(DeleteFileA("threedir\\two.txt"), "Expected file to exist\n"); ok(!DeleteFileA("fourdir"), "Expected file to not exist\n"); ok(!RemoveDirectoryA("fourdir"), "Expected dit to not exist\n"); + } + ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n"); ok(!DeleteFileA("five"), "Expected file to not exist\n"); ok(!RemoveDirectoryA("five"), "Expected dit to not exist\n"); @@ -1108,108 +1751,204 @@ static void test_move(void) set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0"); ok(!SHFileOperationA(&shfo2), "Move many files\n"); - ok(file_exists("test6.txt"), "The file is moved - many files are " + ok(DeleteFileA("test6.txt"), "The file is not moved - many files are " "specified as a target\n"); - DeleteFileA("test6.txt"); - DeleteFileA("test7.txt"); - RemoveDirectoryA("test8.txt"); + ok(DeleteFileA("test7.txt"), "The file is not moved\n"); + ok(RemoveDirectoryA("test8.txt"), "The directory is not moved\n"); init_shfo_tests(); /* number of sources do not correspond to number of targets */ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); set_curr_dir_path(to, "test6.txt\0test7.txt\0"); - ok(SHFileOperationA(&shfo2), "Can't move many files\n"); + retval = SHFileOperationA(&shfo2); + if (dir_exists("test6.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == DE_DESTSAMETREE, "Expected DE_DESTSAMETREE, got %d\n", retval); + ok(DeleteFileA("test6.txt\\test1.txt"), "The file is not moved\n"); + RemoveDirectoryA("test6.txt"); + ok(DeleteFileA("test7.txt\\test2.txt"), "The file is not moved\n"); + RemoveDirectoryA("test7.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(!file_exists("test6.txt"), "The file is not moved - many files are " "specified as a target\n"); + } init_shfo_tests(); set_curr_dir_path(from, "test3.txt\0"); set_curr_dir_path(to, "test4.txt\\test1.txt\0"); - ok(!SHFileOperationA(&shfo), "File is moved moving to other directory\n"); - ok(file_exists("test4.txt\\test1.txt"), "The file is moved\n"); + ok(!SHFileOperationA(&shfo), "Can't move file to other directory\n"); + ok(file_exists("test4.txt\\test1.txt"), "The file is not moved\n"); set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0"); set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0"); - ok(SHFileOperationA(&shfo), "Cannot move many files\n"); - ok(file_exists("test1.txt"), "The file is not moved. Many files are specified\n"); - ok(file_exists("test4.txt"), "The directory is not moved. Many files are specified\n"); + retval = SHFileOperationA(&shfo); + if (dir_exists("test6.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("test6.txt\\test1.txt"), "The file is not moved. Many files are specified\n"); + ok(DeleteFileA("test6.txt\\test2.txt"), "The file is not moved. Many files are specified\n"); + ok(DeleteFileA("test6.txt\\test4.txt\\test1.txt"), "The file is not moved. Many files are specified\n"); + ok(RemoveDirectoryA("test6.txt\\test4.txt"), "The directory is not moved. Many files are specified\n"); + RemoveDirectoryA("test6.txt"); + init_shfo_tests(); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + ok(file_exists("test1.txt"), "The file is moved. Many files are specified\n"); + ok(dir_exists("test4.txt"), "The directory is moved. Many files are specified\n"); + } set_curr_dir_path(from, "test1.txt\0"); set_curr_dir_path(to, "test6.txt\0"); - ok(!SHFileOperationA(&shfo), "Move file\n"); - ok(!file_exists("test1.txt"), "The file is moved\n"); - ok(file_exists("test6.txt"), "The file is moved\n"); + ok(!SHFileOperationA(&shfo), "Move file failed\n"); + ok(!file_exists("test1.txt"), "The file is not moved\n"); + ok(file_exists("test6.txt"), "The file is not moved\n"); set_curr_dir_path(from, "test6.txt\0"); set_curr_dir_path(to, "test1.txt\0"); - ok(!SHFileOperationA(&shfo), "Move file back\n"); + ok(!SHFileOperationA(&shfo), "Move file back failed\n"); set_curr_dir_path(from, "test4.txt\0"); set_curr_dir_path(to, "test6.txt\0"); - ok(!SHFileOperationA(&shfo), "Move dir\n"); - ok(!file_exists("test4.txt"), "The dir is moved\n"); - ok(file_exists("test6.txt"), "The dir is moved\n"); + ok(!SHFileOperationA(&shfo), "Move dir failed\n"); + ok(!dir_exists("test4.txt"), "The dir is not moved\n"); + ok(dir_exists("test6.txt"), "The dir is moved\n"); set_curr_dir_path(from, "test6.txt\0"); set_curr_dir_path(to, "test4.txt\0"); - ok(!SHFileOperationA(&shfo), "Move dir back\n"); + ok(!SHFileOperationA(&shfo), "Move dir back failed\n"); /* move one file to two others */ init_shfo_tests(); shfo.pFrom = "test1.txt\0"; shfo.pTo = "a.txt\0b.txt\0"; retval = SHFileOperationA(&shfo); + if (retval == DE_OPCANCELLED) + { + /* NT4 fails and doesn't move any files */ + ok(!file_exists("a.txt"), "Expected a.txt to not exist\n"); + DeleteFileA("test1.txt"); + } + else + { ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); ok(!file_exists("test1.txt"), "Expected test1.txt to not exist\n"); ok(DeleteFile("a.txt"), "Expected a.txt to exist\n"); + } ok(!file_exists("b.txt"), "Expected b.txt to not exist\n"); /* move two files to one other */ shfo.pFrom = "test2.txt\0test3.txt\0"; shfo.pTo = "test1.txt\0"; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + if (dir_exists("test1.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("test1.txt\\test2.txt"), "Expected test1.txt\\test2.txt to exist\n"); + ok(DeleteFileA("test1.txt\\test3.txt"), "Expected test1.txt\\test3.txt to exist\n"); + RemoveDirectoryA("test1.txt"); + createTestFile("test2.txt"); + createTestFile("test3.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(!file_exists("test1.txt"), "Expected test1.txt to not exist\n"); ok(file_exists("test2.txt"), "Expected test2.txt to exist\n"); ok(file_exists("test3.txt"), "Expected test3.txt to exist\n"); + } /* move a directory into itself */ shfo.pFrom = "test4.txt\0"; shfo.pTo = "test4.txt\\b.txt\0"; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(retval == ERROR_SUCCESS || + retval == DE_DESTSUBTREE, /* Vista */ + "Expected ERROR_SUCCESS or DE_DESTSUBTREE, got %d\n", retval); ok(!RemoveDirectory("test4.txt\\b.txt"), "Expected test4.txt\\b.txt to not exist\n"); - ok(file_exists("test4.txt"), "Expected test4.txt to exist\n"); + ok(dir_exists("test4.txt"), "Expected test4.txt to exist\n"); /* move many files without FOF_MULTIDESTFILES */ shfo.pFrom = "test2.txt\0test3.txt\0"; shfo.pTo = "d.txt\0e.txt\0"; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + if (dir_exists("d.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("d.txt\\test2.txt"), "Expected d.txt\\test2.txt to exist\n"); + ok(DeleteFileA("d.txt\\test3.txt"), "Expected d.txt\\test3.txt to exist\n"); + RemoveDirectoryA("d.txt"); + createTestFile("test2.txt"); + createTestFile("test3.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(!DeleteFile("d.txt"), "Expected d.txt to not exist\n"); ok(!DeleteFile("e.txt"), "Expected e.txt to not exist\n"); + } /* number of sources != number of targets */ shfo.pTo = "d.txt\0"; shfo.fFlags |= FOF_MULTIDESTFILES; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); + if (dir_exists("d.txt")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == DE_SAMEFILE, + "Expected DE_SAMEFILE, got %d\n", retval); + ok(DeleteFileA("d.txt\\test2.txt"), "Expected d.txt\\test2.txt to exist\n"); + ok(!file_exists("d.txt\\test3.txt"), "Expected d.txt\\test3.txt to not exist\n"); + RemoveDirectoryA("d.txt"); + createTestFile("test2.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); ok(!DeleteFile("d.txt"), "Expected d.txt to not exist\n"); + } /* FO_MOVE does not create dest directories */ shfo.pFrom = "test2.txt\0"; shfo.pTo = "dir1\\dir2\\test2.txt\0"; retval = SHFileOperationA(&shfo); - ok(retval == ERROR_CANCELLED, "Expected ERROR_CANCELLED, got %d\n", retval); - ok(!file_exists("dir1"), "Expected dir1 to not exist\n"); + if (dir_exists("dir1")) + { + /* Vista and W2K8 (broken or new behavior ?) */ + ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); + ok(DeleteFileA("dir1\\dir2\\test2.txt"), "Expected dir1\\dir2\\test2.txt to exist\n"); + RemoveDirectoryA("dir1\\dir2"); + RemoveDirectoryA("dir1"); + createTestFile("test2.txt"); + } + else + { + expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* Win9x, NT4 */); + } /* try to overwrite an existing file */ shfo.pTo = "test3.txt\0"; retval = SHFileOperationA(&shfo); + if (retval == DE_OPCANCELLED) + { + /* NT4 fails and doesn't move any files */ + ok(file_exists("test2.txt"), "Expected test2.txt to exist\n"); + } + else + { ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval); ok(!file_exists("test2.txt"), "Expected test2.txt to not exist\n"); ok(file_exists("test3.txt"), "Expected test3.txt to exist\n"); } +} static void test_sh_create_dir(void) { @@ -1218,7 +1957,7 @@ static void test_sh_create_dir(void) if(!pSHCreateDirectoryExA) { - trace("skipping SHCreateDirectoryExA tests\n"); + win_skip("skipping SHCreateDirectoryExA tests\n"); return; } @@ -1239,10 +1978,11 @@ static void test_sh_path_prepare(void) { HRESULT res; CHAR path[MAX_PATH]; + CHAR UNICODE_PATH_A[MAX_PATH]; if(!pSHPathPrepareForWriteA) { - trace("skipping SHPathPrepareForWriteA tests\n"); + win_skip("skipping SHPathPrepareForWriteA tests\n"); return; } @@ -1270,16 +2010,25 @@ static void test_sh_path_prepare(void) /* file exists, SHPPFW_NONE */ set_curr_dir_path(path, "test1.txt\0"); res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE); - ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY), "res == 0x%08x, expected HRESULT_FROM_WIN32(ERROR_DIRECTORY)\n", res); + ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) || + res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */ + res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */ + "Unexpected result : 0x%08x\n", res); /* file exists, SHPPFW_DIRCREATE */ res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE); - ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY), "res == 0x%08x, expected HRESULT_FROM_WIN32(ERROR_DIRECTORY)\n", res); + ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) || + res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */ + res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */ + "Unexpected result : 0x%08x\n", res); /* file exists, SHPPFW_NONE, trailing \ */ set_curr_dir_path(path, "test1.txt\\\0"); res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE); - ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY), "res == 0x%08x, expected HRESULT_FROM_WIN32(ERROR_DIRECTORY)\n", res); + ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) || + res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */ + res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */ + "Unexpected result : 0x%08x\n", res); /* relative path exists, SHPPFW_DIRCREATE */ res = pSHPathPrepareForWriteA(0, 0, ".\\testdir2", SHPPFW_DIRCREATE); @@ -1318,19 +2067,22 @@ static void test_sh_path_prepare(void) if(!pSHPathPrepareForWriteW) { - skip("Skipping SHPathPrepareForWriteW tests\n"); + win_skip("Skipping SHPathPrepareForWriteW tests\n"); return; } + WideCharToMultiByte(CP_ACP, 0, UNICODE_PATH, -1, UNICODE_PATH_A, sizeof(UNICODE_PATH_A), NULL, NULL); + /* unicode directory doesn't exist, SHPPFW_NONE */ + RemoveDirectoryA(UNICODE_PATH_A); res = pSHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_NONE); ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == %08x, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res); - ok(!file_existsW(UNICODE_PATH), "unicode path was created but shouldn't be\n"); - RemoveDirectoryW(UNICODE_PATH); + ok(!file_exists(UNICODE_PATH_A), "unicode path was created but shouldn't be\n"); + RemoveDirectoryA(UNICODE_PATH_A); /* unicode directory doesn't exist, SHPPFW_DIRCREATE */ res = pSHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_DIRCREATE); ok(res == S_OK, "res == %08x, expected S_OK\n", res); - ok(file_existsW(UNICODE_PATH), "unicode path should've been created\n"); + ok(file_exists(UNICODE_PATH_A), "unicode path should've been created\n"); /* unicode directory exists, SHPPFW_NONE */ res = pSHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_NONE); @@ -1339,7 +2091,63 @@ static void test_sh_path_prepare(void) /* unicode directory exists, SHPPFW_DIRCREATE */ res = pSHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_DIRCREATE); ok(res == S_OK, "ret == %08x, expected S_OK\n", res); - RemoveDirectoryW(UNICODE_PATH); + RemoveDirectoryA(UNICODE_PATH_A); +} + +static void test_sh_new_link_info(void) +{ + BOOL ret, mustcopy=TRUE; + CHAR linkto[MAX_PATH]; + CHAR destdir[MAX_PATH]; + CHAR result[MAX_PATH]; + CHAR result2[MAX_PATH]; + + /* source file does not exist */ + set_curr_dir_path(linkto, "nosuchfile.txt\0"); + set_curr_dir_path(destdir, "testdir2\0"); + ret = SHGetNewLinkInfoA(linkto, destdir, result, &mustcopy, 0); + ok(ret == FALSE || + broken(ret == lstrlenA(result) + 1), /* NT4 */ + "SHGetNewLinkInfoA succeeded\n"); + ok(mustcopy == FALSE, "mustcopy should be FALSE\n"); + + /* dest dir does not exist */ + set_curr_dir_path(linkto, "test1.txt\0"); + set_curr_dir_path(destdir, "nosuchdir\0"); + ret = SHGetNewLinkInfoA(linkto, destdir, result, &mustcopy, 0); + ok(ret == TRUE || + broken(ret == lstrlenA(result) + 1), /* NT4 */ + "SHGetNewLinkInfoA failed, err=%i\n", GetLastError()); + ok(mustcopy == FALSE, "mustcopy should be FALSE\n"); + + /* source file exists */ + set_curr_dir_path(linkto, "test1.txt\0"); + set_curr_dir_path(destdir, "testdir2\0"); + ret = SHGetNewLinkInfoA(linkto, destdir, result, &mustcopy, 0); + ok(ret == TRUE || + broken(ret == lstrlenA(result) + 1), /* NT4 */ + "SHGetNewLinkInfoA failed, err=%i\n", GetLastError()); + ok(mustcopy == FALSE, "mustcopy should be FALSE\n"); + ok(CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, destdir, + lstrlenA(destdir), result, lstrlenA(destdir)) == CSTR_EQUAL, + "%s does not start with %s\n", result, destdir); + ok(lstrlenA(result) > 4 && lstrcmpiA(result+lstrlenA(result)-4, ".lnk") == 0, + "%s does not end with .lnk\n", result); + + /* preferred target name already exists */ + createTestFile(result); + ret = SHGetNewLinkInfoA(linkto, destdir, result2, &mustcopy, 0); + ok(ret == TRUE || + broken(ret == lstrlenA(result2) + 1), /* NT4 */ + "SHGetNewLinkInfoA failed, err=%i\n", GetLastError()); + ok(mustcopy == FALSE, "mustcopy should be FALSE\n"); + ok(CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, destdir, + lstrlenA(destdir), result2, lstrlenA(destdir)) == CSTR_EQUAL, + "%s does not start with %s\n", result2, destdir); + ok(lstrlenA(result2) > 4 && lstrcmpiA(result2+lstrlenA(result2)-4, ".lnk") == 0, + "%s does not end with .lnk\n", result2); + ok(lstrcmpiA(result, result2) != 0, "%s and %s are the same\n", result, result2); + DeleteFileA(result); } static void test_unicode(void) @@ -1423,6 +2231,7 @@ START_TEST(shlfileop) init_shfo_tests(); test_get_file_info(); + test_get_file_info_iconlist(); clean_after_shfo_tests(); init_shfo_tests(); @@ -1448,5 +2257,9 @@ START_TEST(shlfileop) test_sh_path_prepare(); clean_after_shfo_tests(); + init_shfo_tests(); + test_sh_new_link_info(); + clean_after_shfo_tests(); + test_unicode(); } diff --git a/rostests/winetests/shell32/shlfolder.c b/rostests/winetests/shell32/shlfolder.c index 5c43d3820c0..903c0894f9b 100644 --- a/rostests/winetests/shell32/shlfolder.c +++ b/rostests/winetests/shell32/shlfolder.c @@ -46,11 +46,15 @@ static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEM static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR); static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR); static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR); +static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL); static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL); static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT); static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST); static void (WINAPI *pILFree)(LPITEMIDLIST); static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST); +static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**); +static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST); + static void init_function_pointers(void) { @@ -62,10 +66,13 @@ static void init_function_pointers(void) pSHGetFolderPathA = (void*)GetProcAddress(hmod, "SHGetFolderPathA"); pSHGetFolderPathAndSubDirA = (void*)GetProcAddress(hmod, "SHGetFolderPathAndSubDirA"); pSHGetPathFromIDListW = (void*)GetProcAddress(hmod, "SHGetPathFromIDListW"); + pSHGetSpecialFolderPathA = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathA"); pSHGetSpecialFolderPathW = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathW"); pILFindLastID = (void *)GetProcAddress(hmod, (LPCSTR)16); pILFree = (void*)GetProcAddress(hmod, (LPSTR)155); pILIsEqual = (void*)GetProcAddress(hmod, (LPSTR)21); + pSHCreateShellItem = (void*)GetProcAddress(hmod, "SHCreateShellItem"); + pILCombine = (void*)GetProcAddress(hmod, (LPSTR)25); hmod = GetModuleHandleA("shlwapi.dll"); pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW"); @@ -80,6 +87,8 @@ static void test_ParseDisplayName(void) IShellFolder *IDesktopFolder; static const char *cNonExistDir1A = "c:\\nonexist_subdir"; static const char *cNonExistDir2A = "c:\\\\nonexist_subdir"; + static const char *cInetTestA = "http:\\yyy"; + static const char *cInetTest2A = "xx:yyy"; DWORD res; WCHAR cTestDirW [MAX_PATH] = {0}; ITEMIDLIST *newPIDL; @@ -88,6 +97,30 @@ static void test_ParseDisplayName(void) hr = SHGetDesktopFolder(&IDesktopFolder); if(hr != S_OK) return; + MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH); + hr = IShellFolder_ParseDisplayName(IDesktopFolder, + NULL, NULL, cTestDirW, NULL, &newPIDL, 0); + todo_wine ok((SUCCEEDED(hr) || broken(hr == E_FAIL) /* NT4 */), + "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr); + if (SUCCEEDED(hr)) + { + ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type " + "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]); + IMalloc_Free(ppM, newPIDL); + } + + MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH); + hr = IShellFolder_ParseDisplayName(IDesktopFolder, + NULL, NULL, cTestDirW, NULL, &newPIDL, 0); + todo_wine ok((SUCCEEDED(hr) || broken(hr == E_FAIL) /* NT4 */), + "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr); + if (SUCCEEDED(hr)) + { + ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type " + "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]); + IMalloc_Free(ppM, newPIDL); + } + res = GetFileAttributesA(cNonExistDir1A); if(res != INVALID_FILE_ATTRIBUTES) return; @@ -119,8 +152,10 @@ static void test_ParseDisplayName(void) ok(SUCCEEDED(hr), "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr); if (FAILED(hr)) goto finished; - ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31, "Last pidl should be of type " - "PT_FOLDER, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]); + ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 || + pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */ + "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n", + pILFindLastID(newPIDL)->mkid.abID[0]); IMalloc_Free(ppM, newPIDL); finished: @@ -230,18 +265,24 @@ static void test_EnumObjects(IShellFolder *iFolder) for (i = 0; i < 5; i++) { SFGAOF flags; +#define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY /* Native returns all flags no matter what we ask for */ flags = SFGAO_CANCOPY; hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags); flags &= SFGAO_testfor; ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr); - ok(flags == (attrs[i]), "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]); + ok(flags == (attrs[i]) || + flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */ + flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */ + "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]); flags = SFGAO_testfor; hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags); flags &= SFGAO_testfor; ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr); - ok(flags == attrs[i], "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]); + ok(flags == attrs[i] || + flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */ + "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]); } for (i=0;i<5;i++) @@ -356,7 +397,7 @@ static void test_GetDisplayName(void) BOOL result; HRESULT hr; HANDLE hTestFile; - WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH], wszTestDir[MAX_PATH]; + WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH]; char szTestFile[MAX_PATH], szTestDir[MAX_PATH]; DWORD attr; STRRET strret; @@ -365,6 +406,7 @@ static void test_GetDisplayName(void) SHITEMID emptyitem = { 0, { 0 } }; LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem; LPCITEMIDLIST pidlLast; + static const CHAR szFileName[] = "winetest.foo"; static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 }; static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 }; @@ -376,17 +418,18 @@ static void test_GetDisplayName(void) * no functional difference in this respect. */ - if(!pSHGetSpecialFolderPathW) return; + if(!pSHGetSpecialFolderPathA) { + win_skip("SHGetSpecialFolderPathA is not available\n"); + return; + } /* First creating a directory in MyDocuments and a file in this directory. */ - result = pSHGetSpecialFolderPathW(NULL, wszTestDir, CSIDL_PERSONAL, FALSE); - ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError()); + result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE); + ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError()); if (!result) return; - myPathAddBackslashW(wszTestDir); - lstrcatW(wszTestDir, wszDirName); /* Use ANSI file functions so this works on Windows 9x */ - WideCharToMultiByte(CP_ACP, 0, wszTestDir, -1, szTestDir, MAX_PATH, 0, 0); + lstrcatA(szTestDir, "\\winetest"); CreateDirectoryA(szTestDir, NULL); attr=GetFileAttributesA(szTestDir); if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY)) @@ -395,11 +438,9 @@ static void test_GetDisplayName(void) return; } - lstrcpyW(wszTestFile, wszTestDir); - myPathAddBackslashW(wszTestFile); - lstrcatW(wszTestFile, wszFileName); - WideCharToMultiByte(CP_ACP, 0, wszTestFile, -1, szTestFile, MAX_PATH, 0, 0); - + lstrcpyA(szTestFile, szTestDir); + lstrcatA(szTestFile, "\\"); + lstrcatA(szTestFile, szFileName); hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError()); if (hTestFile == INVALID_HANDLE_VALUE) return; @@ -410,6 +451,8 @@ static void test_GetDisplayName(void) ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr); if (FAILED(hr)) return; + MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH); + hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL); ok(SUCCEEDED(hr), "Desktop->ParseDisplayName failed! hr = %08x\n", hr); if (FAILED(hr)) { @@ -417,23 +460,45 @@ static void test_GetDisplayName(void) return; } - /* WinXP stores the filenames as both ANSI and UNICODE in the pidls */ pidlLast = pILFindLastID(pidlTestFile); - ok(pidlLast->mkid.cb >=76, "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb); + ok(pidlLast->mkid.cb >=76 || + broken(pidlLast->mkid.cb == 28) || /* W2K */ + broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */ + "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb); + if (pidlLast->mkid.cb >= 28) { + ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName), + "Filename should be stored as ansi-string at this position!\n"); + } + /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */ if (pidlLast->mkid.cb >= 76) { - ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName), - "WinXP stores the filename as a wchar-string at this position!\n"); + ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) || + (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)), /* Vista */ + "Filename should be stored as wchar-string at this position!\n"); } /* It seems as if we cannot bind to regular files on windows, but only directories. */ hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile); - todo_wine { ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hr = %08x\n", hr); } + todo_wine + ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hr == E_NOTIMPL || /* Vista */ + broken(SUCCEEDED(hr)), /* Win9x, W2K */ + "hr = %08x\n", hr); if (SUCCEEDED(hr)) { IShellFolder_Release(psfFile); } + if (!pSHBindToParent) + { + win_skip("SHBindToParent is missing\n"); + DeleteFileA(szTestFile); + RemoveDirectoryA(szTestDir); + return; + } + /* Some tests for IShellFolder::SetNameOf */ + if (pSHGetFolderPathAndSubDirA) + { hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast); ok(SUCCEEDED(hr), "SHBindToParent failed! hr = %08x\n", hr); if (SUCCEEDED(hr)) { @@ -444,6 +509,8 @@ static void test_GetDisplayName(void) /* The pidl returned through the last parameter of SetNameOf is a simple one. */ hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew); ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08x\n", hr); + if (hr == S_OK) + { ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0, "pidl returned from SetNameOf should be simple!\n"); @@ -459,8 +526,13 @@ static void test_GetDisplayName(void) ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08x\n", hr); pILFree(pidlNew); + } + IShellFolder_Release(psfPersonal); } + } + else + win_skip("Avoid needs of interaction on Win2k\n"); /* Deleting the file and the directory */ DeleteFileA(szTestFile); @@ -474,8 +546,6 @@ static void test_GetDisplayName(void) ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n"); } - if(!pSHBindToParent) return; - /* SHBindToParent fails, if called with a NULL PIDL. */ hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast); ok (FAILED(hr), "SHBindToParent(NULL) should fail!\n"); @@ -554,7 +624,8 @@ static void test_CallForAttributes(void) hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL, &pidlMyDocuments, NULL); - ok (SUCCEEDED(hr), + ok (SUCCEEDED(hr) || + broken(hr == E_INVALIDARG), /* Win95, NT4 */ "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr); if (FAILED(hr)) { IShellFolder_Release(psfDesktop); @@ -645,22 +716,41 @@ static void test_GetAttributesOf(void) LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem; LPITEMIDLIST pidlMyComputer; DWORD dwFlags; - static const DWORD dwDesktopFlags = /* As observed on WinXP SP2 */ - SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | - SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER; - static const DWORD dwMyComputerFlags = /* As observed on WinXP SP2 */ - SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | - SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER; + static const DWORD desktopFlags[] = { + /* WinXP */ + SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR | + SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER, + /* Win2k */ + SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR | + SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER, + /* WinMe, Win9x, WinNT*/ + SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR | + SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER + }; + static const DWORD myComputerFlags[] = { + /* WinXP */ + SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | + SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER, + /* Win2k */ + SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM | + SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER, + /* WinMe, Win9x, WinNT */ + SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | + SFGAO_FOLDER | SFGAO_HASSUBFOLDER, + /* Win95, WinNT when queried directly */ + SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | + SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER + }; WCHAR wszMyComputer[] = { ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-', 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 }; char cCurrDirA [MAX_PATH] = {0}; WCHAR cCurrDirW [MAX_PATH]; static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0}; - static const WCHAR cBackSlash[] = {'\\',0}; IShellFolder *IDesktopFolder, *testIShellFolder; ITEMIDLIST *newPIDL; - int len; + int len, i; + BOOL foundFlagsMatch; hr = SHGetDesktopFolder(&psfDesktop); ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr); @@ -670,15 +760,25 @@ static void test_GetAttributesOf(void) dwFlags = 0xffffffff; hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags); ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr); - ok (dwFlags == dwDesktopFlags, "Wrong Desktop attributes: %08x, expected: %08x\n", - dwFlags, dwDesktopFlags); + for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch && + i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++) + { + if (desktopFlags[i] == dwFlags) + foundFlagsMatch = TRUE; + } + ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags); /* .. or with no itemidlist at all. */ dwFlags = 0xffffffff; hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags); ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr); - ok (dwFlags == dwDesktopFlags, "Wrong Desktop attributes: %08x, expected: %08x\n", - dwFlags, dwDesktopFlags); + for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch && + i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++) + { + if (desktopFlags[i] == dwFlags) + foundFlagsMatch = TRUE; + } + ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags); /* Testing the attributes of the MyComputer shellfolder */ hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL); @@ -688,18 +788,20 @@ static void test_GetAttributesOf(void) return; } - /* WinXP SP2 sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop + /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop * folder object. It doesn't do this, if MyComputer is queried directly (see below). - * SFGAO_CANLINK is the same as DROPEFFECT_LINK, which MSDN says means: "Drag source - * should create a link to the original data". You can't create links on MyComputer on - * Windows, so this flag shouldn't be set. Seems like a bug in Windows. As long as nobody - * depends on this bug, we probably shouldn't imitate it. */ dwFlags = 0xffffffff; hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags); ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr); - ok ((dwFlags & ~(DWORD)SFGAO_CANLINK) == dwMyComputerFlags, - "Wrong MyComputer attributes: %08x, expected: %08x\n", dwFlags, dwMyComputerFlags); + for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch && + i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++) + { + if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags) + foundFlagsMatch = TRUE; + } + todo_wine + ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags); hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer); ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr); @@ -708,29 +810,38 @@ static void test_GetAttributesOf(void) if (FAILED(hr)) return; hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags); - todo_wine {ok (hr == E_INVALIDARG, "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr); } + todo_wine + ok (hr == E_INVALIDARG || + broken(SUCCEEDED(hr)), /* W2K and earlier */ + "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr); dwFlags = 0xffffffff; hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags); ok (SUCCEEDED(hr), "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr); - todo_wine { ok (dwFlags == dwMyComputerFlags, - "Wrong MyComputer attributes: %08x, expected: %08x\n", dwFlags, dwMyComputerFlags); } + for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch && + i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++) + { + if (myComputerFlags[i] == dwFlags) + foundFlagsMatch = TRUE; + } + todo_wine + ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags); IShellFolder_Release(psfMyComputer); - /* create test directory */ - CreateFilesFolders(); - GetCurrentDirectoryA(MAX_PATH, cCurrDirA); len = lstrlenA(cCurrDirA); if (len == 0) { - trace("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n"); + win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n"); return; } - if(cCurrDirA[len-1] == '\\') + if (len > 3 && cCurrDirA[len-1] == '\\') cCurrDirA[len-1] = 0; + /* create test directory */ + CreateFilesFolders(); + MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH); hr = SHGetDesktopFolder(&IDesktopFolder); @@ -758,8 +869,10 @@ static void test_GetAttributesOf(void) IMalloc_Free(ppM, newPIDL); /* append testdirectory name to path */ - lstrcatW(cCurrDirW, cBackSlash); - lstrcatW(cCurrDirW, cTestDirW); + if (cCurrDirA[len-1] == '\\') + cCurrDirA[len-1] = 0; + lstrcatA(cCurrDirA, "\\testdir"); + MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH); hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0); ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr); @@ -804,7 +917,7 @@ static void test_SHGetPathFromIDList(void) if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW) { - skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n"); + win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n"); return; } @@ -820,6 +933,15 @@ static void test_SHGetPathFromIDList(void) ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError()); if (!result) return; + /* Check if we are on Win9x */ + SetLastError(0xdeadbeef); + lstrcmpiW(wszDesktop, wszDesktop); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Most W-calls are not implemented\n"); + return; + } + result = pSHGetPathFromIDListW(pidlEmpty, wszPath); ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError()); if (!result) return; @@ -842,7 +964,9 @@ static void test_SHGetPathFromIDList(void) wszPath[1] = '\0'; result = pSHGetPathFromIDListW(pidlMyComputer, wszPath); ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n"); - ok (GetLastError()==0xdeadbeef, "SHGetPathFromIDListW shouldn't set last error! Last error: %u\n", GetLastError()); + ok (GetLastError()==0xdeadbeef || + GetLastError()==ERROR_SUCCESS, /* Vista and higher */ + "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError()); ok (!wszPath[0], "Expected empty path\n"); if (result) { IShellFolder_Release(psfDesktop); @@ -919,8 +1043,8 @@ static void test_EnumObjects_and_CompareIDs(void) ITEMIDLIST *newPIDL; IShellFolder *IDesktopFolder, *testIShellFolder; char cCurrDirA [MAX_PATH] = {0}; - WCHAR cCurrDirW [MAX_PATH]; - static const WCHAR cTestDirW[] = {'\\','t','e','s','t','d','i','r',0}; + static const CHAR cTestDirA[] = "\\testdir"; + WCHAR cTestDirW[MAX_PATH]; int len; HRESULT hr; @@ -928,21 +1052,21 @@ static void test_EnumObjects_and_CompareIDs(void) len = lstrlenA(cCurrDirA); if(len == 0) { - trace("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n"); + win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n"); return; } if(cCurrDirA[len-1] == '\\') cCurrDirA[len-1] = 0; - MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH); - lstrcatW(cCurrDirW, cTestDirW); + lstrcatA(cCurrDirA, cTestDirA); + MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH); hr = SHGetDesktopFolder(&IDesktopFolder); ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr); CreateFilesFolders(); - hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0); + hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0); ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr); hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder); @@ -998,9 +1122,15 @@ static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPC 'A','t','t','r','i','b','u','t','e','s',0 }; static const WCHAR wszResolveLinkFlags[] = { 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 }; + static const WCHAR wszTargetKnownFolder[] = { + 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 }; + static const WCHAR wszCLSID[] = { + 'C','L','S','I','D',0 }; if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) { - ok(V_VT(pVar) == VT_I4, "Wrong variant type for 'TargetSpecialFolder' property!\n"); + ok(V_VT(pVar) == VT_I4 || + broken(V_VT(pVar) == VT_BSTR), /* Win2k */ + "Wrong variant type for 'TargetSpecialFolder' property!\n"); return E_INVALIDARG; } @@ -1014,7 +1144,9 @@ static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPC WCHAR wszPath[MAX_PATH]; BOOL result; - ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'Target' property!\n"); + ok(V_VT(pVar) == VT_BSTR || + broken(V_VT(pVar) == VT_EMPTY), /* Win2k */ + "Wrong variant type for 'Target' property!\n"); if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG; result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE); @@ -1033,7 +1165,19 @@ static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPC return S_OK; } - ok(FALSE, "PropertyBag was asked for unknown property (vt=%d)!\n", V_VT(pVar)); + if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) { + ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n"); + /* TODO */ + return E_INVALIDARG; +} + + if (!lstrcmpW(pszPropName, wszCLSID)) { + ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n"); + /* TODO */ + return E_INVALIDARG; + } + + ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar)); return E_INVALIDARG; } @@ -1082,14 +1226,27 @@ static void test_FolderShortcut(void) { static const GUID CLSID_UnixDosFolder = {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}}; - if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) return; + if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) { + win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n"); + return; + } + if (!pSHGetFolderPathAndSubDirA) + { + win_skip("FolderShortcut test doesn't work on Win2k\n"); + return; + } + /* These tests basically show, that CLSID_FolderShortcuts are initialized * via their IPersistPropertyBag interface. And that the target folder * is taken from the IPropertyBag's 'Target' property. */ hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER, &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag); + if (hr == REGDB_E_CLASSNOTREG) { + win_skip("CLSID_FolderShortcut is not implemented\n"); + return; + } ok (SUCCEEDED(hr), "CoCreateInstance failed! hr = 0x%08x\n", hr); if (FAILED(hr)) return; @@ -1263,7 +1420,12 @@ static void test_ITEMIDLIST_format(void) { ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError()); if (!bResult) return; + SetLastError(0xdeadbeef); bResult = SetCurrentDirectoryW(wszPersonal); + if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + win_skip("Most W-calls are not implemented\n"); + return; + } ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError()); if (!bResult) return; @@ -1321,10 +1483,14 @@ static void test_ITEMIDLIST_format(void) { * this nasty short/long filename stuff. So we'll probably stay with our * current habbit of storing the long filename here, which seems to work * just fine. */ - todo_wine { ok(pidlFile->mkid.abID[18] == '~', "Should be derived 8.3 name!\n"); } + todo_wine + ok(pidlFile->mkid.abID[18] == '~' || + broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */ + "Should be derived 8.3 name!\n"); if (i == 0) /* First file name has an even number of chars. No need for alignment. */ - ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0', + ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' || + broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */ "Alignment byte, where there shouldn't be!\n"); if (i == 1) /* Second file name has an uneven number of chars => alignment byte */ @@ -1333,8 +1499,10 @@ static void test_ITEMIDLIST_format(void) { /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */ cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD)); - ok (cbOffset >= sizeof(struct FileStructA) && - cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW), + ok ((cbOffset >= sizeof(struct FileStructA) && + cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) || + broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */ + broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */ "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset); if (cbOffset >= sizeof(struct FileStructA) && @@ -1360,7 +1528,8 @@ static void test_ITEMIDLIST_format(void) { pFileStructA->uFileTime == pFileStructW->uTime2, "Last write time should match last access time!\n"); - ok (!lstrcmpW(wszFile[i], pFileStructW->wszName), + ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) || + !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)), /* Vista */ "The filename should be stored in unicode at this position!\n"); } } @@ -1382,38 +1551,35 @@ static void testSHGetFolderPathAndSubDirA(void) static char toolongpath[MAX_PATH+1]; if(!pSHGetFolderPathA) { - skip("SHGetFolderPathA not present!\n"); + win_skip("SHGetFolderPathA not present!\n"); return; } - if(!SUCCEEDED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata))) + if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata))) { - skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n"); + win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n"); return; } sprintf(testpath, "%s\\%s", appdata, winetemp); delret = RemoveDirectoryA(testpath); if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) { - skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError()); + win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError()); return; } sprintf(testpath, "%s\\%s", appdata, wine); delret = RemoveDirectoryA(testpath); if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) { - skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError()); + win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError()); return; } - for(i=0; i< MAX_PATH; i++) - toolongpath[i] = '0' + i % 10; - toolongpath[MAX_PATH] = '\0'; /* test invalid second parameter */ ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath); ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret); - /* test invalid forth parameter */ - ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, wine, testpath); + /* test fourth parameter */ + ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath); switch(ret) { case S_OK: /* winvista */ ok(!strncmp(appdata, testpath, strlen(appdata)), @@ -1443,6 +1609,9 @@ static void testSHGetFolderPathAndSubDirA(void) ok(S_OK == ret, "expected S_OK, got %x\n", ret); ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath); + for(i=0; i< MAX_PATH; i++) + toolongpath[i] = '0' + i % 10; + toolongpath[MAX_PATH] = '\0'; ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath); ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret, "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret); @@ -1475,6 +1644,277 @@ static void testSHGetFolderPathAndSubDirA(void) RemoveDirectoryA(testpath); } +static void test_LocalizedNames(void) +{ + static char cCurrDirA[MAX_PATH]; + WCHAR cCurrDirW[MAX_PATH], tempbufW[25]; + IShellFolder *IDesktopFolder, *testIShellFolder; + ITEMIDLIST *newPIDL; + int len; + HRESULT hr; + static char resourcefile[MAX_PATH]; + DWORD res; + HANDLE file; + STRRET strret; + + static const char desktopini_contents1[] = + "[.ShellClassInfo]\r\n" + "LocalizedResourceName=@"; + static const char desktopini_contents2[] = + ",-1\r\n"; + static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0}; + static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0}; + + /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */ + CreateDirectoryA(".\\testfolder", NULL); + + SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM); + + GetModuleFileNameA(NULL, resourcefile, MAX_PATH); + + file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError()); + ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) && + WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) && + WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL), + "WriteFile failed %i\n", GetLastError()); + CloseHandle(file); + + /* get IShellFolder for parent */ + GetCurrentDirectoryA(MAX_PATH, cCurrDirA); + len = lstrlenA(cCurrDirA); + + if (len == 0) { + win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n"); + goto cleanup; + } + if(cCurrDirA[len-1] == '\\') + cCurrDirA[len-1] = 0; + + MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH); + + hr = SHGetDesktopFolder(&IDesktopFolder); + ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr); + + hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0); + ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr); + + hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder); + ok(hr == S_OK, "BindToObject failed %08x\n", hr); + + IMalloc_Free(ppM, newPIDL); + + /* windows reads the display name from the resource */ + hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0); + ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr); + + hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret); + ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr); + + if (SUCCEEDED(hr) && pStrRetToBufW) + { + hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR)); + ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr); + todo_wine + ok (!lstrcmpiW(tempbufW, folderdisplayW) || + broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */ + "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW)); + } + + /* editing name is also read from the resource */ + hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret); + ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr); + + if (SUCCEEDED(hr) && pStrRetToBufW) + { + hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR)); + ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr); + todo_wine + ok (!lstrcmpiW(tempbufW, folderdisplayW) || + broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */ + "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW)); + } + + /* parsing name is unchanged */ + hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret); + ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr); + + if (SUCCEEDED(hr) && pStrRetToBufW) + { + hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR)); + ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr); + ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW)); + } + + IShellFolder_Release(IDesktopFolder); + IShellFolder_Release(testIShellFolder); + + IMalloc_Free(ppM, newPIDL); + +cleanup: + DeleteFileA(".\\testfolder\\desktop.ini"); + SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM); + RemoveDirectoryA(".\\testfolder"); +} + +static void test_SHCreateShellItem(void) +{ + IShellItem *shellitem, *shellitem2; + IPersistIDList *persistidl; + LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test; + HRESULT ret; + char curdirA[MAX_PATH]; + WCHAR curdirW[MAX_PATH]; + IShellFolder *desktopfolder=NULL, *currentfolder=NULL; + static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0}; + + GetCurrentDirectoryA(MAX_PATH, curdirA); + + if (!lstrlenA(curdirA)) + { + win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n"); + return; + } + + MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH); + + ret = SHGetDesktopFolder(&desktopfolder); + ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret); + + ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL); + ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret); + + ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder); + ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret); + + CreateTestFile(".\\testfile"); + + ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL); + ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret); + + pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile); + + ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem); + ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret); + + if (0) /* crashes on Windows XP */ + { + pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL); + pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem); + pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem); + pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem); + } + + ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem); + ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl); + ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IPersistIDList_GetIDList(persistidl, &pidl_test); + ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n"); + pILFree(pidl_test); + } + IPersistIDList_Release(persistidl); + } + IShellItem_Release(shellitem); + } + + ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem); + ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl); + ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IPersistIDList_GetIDList(persistidl, &pidl_test); + ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n"); + pILFree(pidl_test); + } + IPersistIDList_Release(persistidl); + } + + ret = IShellItem_GetParent(shellitem, &shellitem2); + ok(SUCCEEDED(ret), "GetParent returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl); + ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IPersistIDList_GetIDList(persistidl, &pidl_test); + ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n"); + pILFree(pidl_test); + } + IPersistIDList_Release(persistidl); + } + IShellItem_Release(shellitem2); + } + + IShellItem_Release(shellitem); + } + + ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem); + ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl); + ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IPersistIDList_GetIDList(persistidl, &pidl_test); + ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n"); + pILFree(pidl_test); + } + IPersistIDList_Release(persistidl); + } + IShellItem_Release(shellitem); + } + + /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */ + ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem); + ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl); + ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ret = IPersistIDList_GetIDList(persistidl, &pidl_test); + ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret); + if (SUCCEEDED(ret)) + { + ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n"); + pILFree(pidl_test); + } + IPersistIDList_Release(persistidl); + } + IShellItem_Release(shellitem); + } + + DeleteFileA(".\\testfile"); + pILFree(pidl_abstestfile); + pILFree(pidl_testfile); + pILFree(pidl_cwd); + IShellFolder_Release(currentfolder); + IShellFolder_Release(desktopfolder); +} START_TEST(shlfolder) { @@ -1495,7 +1935,12 @@ START_TEST(shlfolder) if(pSHGetFolderPathAndSubDirA) testSHGetFolderPathAndSubDirA(); else - skip("SHGetFolderPathAndSubDirA not present\n"); + win_skip("SHGetFolderPathAndSubDirA not present\n"); + test_LocalizedNames(); + if(pSHCreateShellItem) + test_SHCreateShellItem(); + else + win_skip("SHCreateShellItem not present\n"); OleUninitialize(); } diff --git a/rostests/winetests/shell32/string.c b/rostests/winetests/shell32/string.c index c748f350e95..1d55ecf9221 100755 --- a/rostests/winetests/shell32/string.c +++ b/rostests/winetests/shell32/string.c @@ -37,7 +37,7 @@ static HRESULT (WINAPI *pStrRetToStrNAW)(LPVOID,DWORD,LPSTRRET,const ITEMIDLIST static WCHAR *CoDupStrW(const char* src) { INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); - WCHAR* szTemp = (WCHAR*)CoTaskMemAlloc(len * sizeof(WCHAR)); + WCHAR* szTemp = CoTaskMemAlloc(len * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len); return szTemp; } @@ -110,4 +110,6 @@ START_TEST(string) else test_StrRetToStringNA(); } + + CoUninitialize(); } diff --git a/rostests/winetests/shell32/systray.c b/rostests/winetests/shell32/systray.c index c672d671b59..6a5ea9b05bb 100644 --- a/rostests/winetests/shell32/systray.c +++ b/rostests/winetests/shell32/systray.c @@ -27,11 +27,11 @@ static HWND hMainWnd; static BOOL (WINAPI *pShell_NotifyIconW)(DWORD,PNOTIFYICONDATAW); -static HMONITOR (WINAPI *pMonitorFromWindow)(HWND, DWORD); -void test_cbsize(void) +static void test_cbsize(void) { NOTIFYICONDATAA nidA; + BOOL ret; if (pShell_NotifyIconW) { @@ -44,16 +44,20 @@ void test_cbsize(void) nidW.uFlags = NIF_ICON|NIF_MESSAGE; nidW.hIcon = LoadIcon(NULL, IDI_APPLICATION); nidW.uCallbackMessage = WM_USER+17; - ok(pShell_NotifyIconW(NIM_ADD, &nidW), "NIM_ADD failed!\n"); - + ret = pShell_NotifyIconW(NIM_ADD, &nidW); + if (ret) + { /* using an invalid cbSize does work */ nidW.cbSize = 3; nidW.hWnd = hMainWnd; nidW.uID = 1; - ok(pShell_NotifyIconW(NIM_DELETE, &nidW), "NIM_DELETE failed!\n"); + ret = pShell_NotifyIconW(NIM_DELETE, &nidW); + ok( ret || broken(!ret), /* nt4 */ "NIM_DELETE failed!\n"); /* as icon doesn't exist anymore - now there will be an error */ nidW.cbSize = sizeof(nidW); - ok(!pShell_NotifyIconW(NIM_DELETE, &nidW), "The icon was not deleted\n"); + ok(!pShell_NotifyIconW(NIM_DELETE, &nidW) != !ret, "The icon was not deleted\n"); + } + else win_skip( "Shell_NotifyIconW not working\n" ); /* win9x */ } /* same for Shell_NotifyIconA */ @@ -70,65 +74,11 @@ void test_cbsize(void) nidA.cbSize = 3; nidA.hWnd = hMainWnd; nidA.uID = 1; - ok(Shell_NotifyIconA(NIM_DELETE, &nidA), "NIM_DELETE failed!\n"); + ret = Shell_NotifyIconA(NIM_DELETE, &nidA); + ok( ret || broken(!ret), /* win9x */ "NIM_DELETE failed!\n"); /* as icon doesn't exist anymore - now there will be an error */ nidA.cbSize = sizeof(nidA); - ok(!Shell_NotifyIconA(NIM_DELETE, &nidA), "The icon was not deleted\n"); -} - -static void test_SHAppBarMessage(void) -{ - APPBARDATA abd; - HWND hwnd, foregnd; - UINT_PTR ret; - - memset(&abd, 0xcc, sizeof(abd)); - abd.cbSize = sizeof(abd); - abd.uEdge = ABE_BOTTOM; - - hwnd = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); - ok(hwnd == NULL || IsWindow(hwnd), "ret %p which is not a window\n", hwnd); - ok(abd.hWnd == (HWND)0xcccccccc, "hWnd overwritten\n"); - - if (!pMonitorFromWindow) - { - skip("MonitorFromWindow is not available\n"); - } - else - { - /* Presumably one can pass a hwnd with ABM_GETAUTOHIDEBAR to specify a monitor. - Pass the foreground window and check */ - foregnd = GetForegroundWindow(); - if(foregnd) - { - abd.hWnd = foregnd; - hwnd = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); - ok(hwnd == NULL || IsWindow(hwnd), "ret %p which is not a window\n", hwnd); - ok(abd.hWnd == foregnd, "hWnd overwritten\n"); - if(hwnd) - { - HMONITOR appbar_mon, foregnd_mon; - appbar_mon = pMonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); - foregnd_mon = pMonitorFromWindow(foregnd, MONITOR_DEFAULTTONEAREST); - ok(appbar_mon == foregnd_mon, "Windows on different monitors\n"); - } - } - } - - memset(&abd, 0xcc, sizeof(abd)); - abd.cbSize = sizeof(abd); - ret = SHAppBarMessage(ABM_GETTASKBARPOS, &abd); - if(ret) - { - ok(abd.hWnd == (HWND)0xcccccccc, "hWnd overwritten\n"); -todo_wine -{ - ok(abd.uEdge >= ABE_LEFT && abd.uEdge <= ABE_BOTTOM, "uEdge not returned\n"); - ok(abd.rc.left != 0xcccccccc, "rc not updated\n"); -} - } - - return; + ok(!Shell_NotifyIconA(NIM_DELETE, &nidA) != !ret, "The icon was not deleted\n"); } START_TEST(systray) @@ -136,14 +86,11 @@ START_TEST(systray) WNDCLASSA wc; MSG msg; RECT rc; - HMODULE huser32, hshell32; + HMODULE hshell32; hshell32 = GetModuleHandleA("shell32.dll"); pShell_NotifyIconW = (void*)GetProcAddress(hshell32, "Shell_NotifyIconW"); - huser32 = GetModuleHandleA("user32.dll"); - pMonitorFromWindow = (void*)GetProcAddress(huser32, "MonitorFromWindow"); - wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; @@ -169,6 +116,4 @@ START_TEST(systray) DispatchMessageA(&msg); } DestroyWindow(hMainWnd); - - test_SHAppBarMessage(); } diff --git a/rostests/winetests/shell32/testlist.c b/rostests/winetests/shell32/testlist.c index 7de794d42cf..0c78417d4f6 100644 --- a/rostests/winetests/shell32/testlist.c +++ b/rostests/winetests/shell32/testlist.c @@ -6,10 +6,13 @@ #define STANDALONE #include "wine/test.h" +extern void func_appbar(void); +extern void func_autocomplete(void); extern void func_generated(void); extern void func_shelllink(void); extern void func_shellpath(void); extern void func_shfldr_netplaces(void); +extern void func_shfldr_special(void); extern void func_shlexec(void); extern void func_shlfileop(void); extern void func_shlfolder(void); @@ -18,10 +21,13 @@ extern void func_systray(void); const struct test winetest_testlist[] = { + { "appbar", func_appbar }, + { "autocomplete", func_autocomplete }, { "generated", func_generated }, { "shelllink", func_shelllink }, { "shellpath", func_shellpath }, { "shfldr_netplaces", func_shfldr_netplaces }, + { "shfldr_special", func_shfldr_special }, { "shlexec", func_shlexec }, { "shlfileop", func_shlfileop }, { "shlfolder", func_shlfolder }, diff --git a/rostests/winetests/shlwapi/assoc.c b/rostests/winetests/shlwapi/assoc.c new file mode 100644 index 00000000000..3799ecc957a --- /dev/null +++ b/rostests/winetests/shlwapi/assoc.c @@ -0,0 +1,248 @@ +/* Unit test suite for SHLWAPI IQueryAssociations functions + * + * Copyright 2008 Google (Lei Zhang) + * + * 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 + */ + +#include + +#include "wine/test.h" +#include "shlwapi.h" + +#define expect(expected, got) ok ( expected == got, "Expected %d, got %d\n", expected, got) +#define expect_hr(expected, got) ok ( expected == got, "Expected %08x, got %08x\n", expected, got) + +static HRESULT (WINAPI *pAssocQueryStringA)(ASSOCF,ASSOCSTR,LPCSTR,LPCSTR,LPSTR,LPDWORD) = NULL; +static HRESULT (WINAPI *pAssocQueryStringW)(ASSOCF,ASSOCSTR,LPCWSTR,LPCWSTR,LPWSTR,LPDWORD) = NULL; + +/* Every version of Windows with IE should have this association? */ +static const WCHAR dotHtml[] = { '.','h','t','m','l',0 }; +static const WCHAR badBad[] = { 'b','a','d','b','a','d',0 }; +static const WCHAR dotBad[] = { '.','b','a','d',0 }; +static const WCHAR open[] = { 'o','p','e','n',0 }; +static const WCHAR invalid[] = { 'i','n','v','a','l','i','d',0 }; + +static void test_getstring_bad(void) +{ + HRESULT hr; + DWORD len; + + if (!pAssocQueryStringW) + { + win_skip("AssocQueryStringW() is missing\n"); + return; + } + + hr = pAssocQueryStringW(0, ASSOCSTR_EXECUTABLE, NULL, open, NULL, &len); + expect_hr(E_INVALIDARG, hr); + hr = pAssocQueryStringW(0, ASSOCSTR_EXECUTABLE, badBad, open, NULL, &len); + ok(hr == E_FAIL || + hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION), /* Win9x/WinMe/NT4/W2K/Vista/W2K8 */ + "Unexpected result : %08x\n", hr); + hr = pAssocQueryStringW(0, ASSOCSTR_EXECUTABLE, dotBad, open, NULL, &len); + ok(hr == E_FAIL || + hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION), /* Win9x/WinMe/NT4/W2K/Vista/W2K8 */ + "Unexpected result : %08x\n", hr); + hr = pAssocQueryStringW(0, ASSOCSTR_EXECUTABLE, dotHtml, invalid, NULL, + &len); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION), /* Win9x/WinMe/NT4/W2K/Vista/W2K8 */ + "Unexpected result : %08x\n", hr); + hr = pAssocQueryStringW(0, ASSOCSTR_EXECUTABLE, dotHtml, open, NULL, NULL); + ok(hr == E_UNEXPECTED || + hr == E_INVALIDARG, /* Win9x/WinMe/NT4/W2K/Vista/W2K8 */ + "Unexpected result : %08x\n", hr); + + hr = pAssocQueryStringW(0, ASSOCSTR_FRIENDLYAPPNAME, NULL, open, NULL, &len); + expect_hr(E_INVALIDARG, hr); + hr = pAssocQueryStringW(0, ASSOCSTR_FRIENDLYAPPNAME, badBad, open, NULL, + &len); + ok(hr == E_FAIL || + hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION), /* Win9x/WinMe/NT4/W2K/Vista/W2K8 */ + "Unexpected result : %08x\n", hr); + hr = pAssocQueryStringW(0, ASSOCSTR_FRIENDLYAPPNAME, dotBad, open, NULL, + &len); + ok(hr == E_FAIL || + hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION), /* Win9x/WinMe/NT4/W2K/Vista/W2K8 */ + "Unexpected result : %08x\n", hr); + hr = pAssocQueryStringW(0, ASSOCSTR_FRIENDLYAPPNAME, dotHtml, invalid, NULL, + &len); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) || /* W2K/Vista/W2K8 */ + hr == E_FAIL, /* Win9x/WinMe/NT4 */ + "Unexpected result : %08x\n", hr); + hr = pAssocQueryStringW(0, ASSOCSTR_FRIENDLYAPPNAME, dotHtml, open, NULL, + NULL); + ok(hr == E_UNEXPECTED || + hr == E_INVALIDARG, /* Win9x/WinMe/NT4/W2K/Vista/W2K8 */ + "Unexpected result : %08x\n", hr); +} + +static void test_getstring_basic(void) +{ + HRESULT hr; + WCHAR * friendlyName; + WCHAR * executableName; + DWORD len, len2, slen; + + if (!pAssocQueryStringW) + { + win_skip("AssocQueryStringW() is missing\n"); + return; + } + + hr = pAssocQueryStringW(0, ASSOCSTR_EXECUTABLE, dotHtml, open, NULL, &len); + expect_hr(S_FALSE, hr); + if (hr != S_FALSE) + { + skip("failed to get initial len\n"); + return; + } + + executableName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + len * sizeof(WCHAR)); + if (!executableName) + { + skip("failed to allocate memory\n"); + return; + } + + len2 = len; + hr = pAssocQueryStringW(0, ASSOCSTR_EXECUTABLE, dotHtml, open, + executableName, &len2); + expect_hr(S_OK, hr); + slen = lstrlenW(executableName) + 1; + expect(len, len2); + expect(len, slen); + + hr = pAssocQueryStringW(0, ASSOCSTR_FRIENDLYAPPNAME, dotHtml, open, NULL, + &len); + ok(hr == S_FALSE || + hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* Win9x/NT4 */ + "Unexpected result : %08x\n", hr); + if (hr != S_FALSE) + { + HeapFree(GetProcessHeap(), 0, executableName); + skip("failed to get initial len\n"); + return; + } + + friendlyName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + len * sizeof(WCHAR)); + if (!friendlyName) + { + HeapFree(GetProcessHeap(), 0, executableName); + skip("failed to allocate memory\n"); + return; + } + + len2 = len; + hr = pAssocQueryStringW(0, ASSOCSTR_FRIENDLYAPPNAME, dotHtml, open, + friendlyName, &len2); + expect_hr(S_OK, hr); + slen = lstrlenW(friendlyName) + 1; + expect(len, len2); + expect(len, slen); + + HeapFree(GetProcessHeap(), 0, executableName); + HeapFree(GetProcessHeap(), 0, friendlyName); +} + +static void test_getstring_no_extra(void) +{ + LONG ret; + HKEY hkey; + HRESULT hr; + static const CHAR dotWinetest[] = { + '.','w','i','n','e','t','e','s','t',0 + }; + static const CHAR winetestfile[] = { + 'w','i','n','e','t','e','s','t', 'f','i','l','e',0 + }; + static const CHAR winetestfileAction[] = { + 'w','i','n','e','t','e','s','t','f','i','l','e', + '\\','s','h','e','l','l', + '\\','f','o','o', + '\\','c','o','m','m','a','n','d',0 + }; + static const CHAR action[] = { + 'n','o','t','e','p','a','d','.','e','x','e',0 + }; + CHAR buf[MAX_PATH]; + DWORD len = MAX_PATH; + + if (!pAssocQueryStringA) + { + win_skip("AssocQueryStringA() is missing\n"); + return; + } + + buf[0] = '\0'; + ret = RegCreateKeyA(HKEY_CLASSES_ROOT, dotWinetest, &hkey); + if (ret != ERROR_SUCCESS) { + skip("failed to create dotWinetest key\n"); + return; + } + + ret = RegSetValueA(hkey, NULL, REG_SZ, winetestfile, lstrlenA(winetestfile)); + RegCloseKey(hkey); + if (ret != ERROR_SUCCESS) + { + skip("failed to set dotWinetest key\n"); + goto cleanup; + } + + ret = RegCreateKeyA(HKEY_CLASSES_ROOT, winetestfileAction, &hkey); + if (ret != ERROR_SUCCESS) + { + skip("failed to create winetestfileAction key\n"); + goto cleanup; + } + + ret = RegSetValueA(hkey, NULL, REG_SZ, action, lstrlenA(action)); + RegCloseKey(hkey); + if (ret != ERROR_SUCCESS) + { + skip("failed to set winetestfileAction key\n"); + goto cleanup; + } + + hr = pAssocQueryStringA(0, ASSOCSTR_EXECUTABLE, dotWinetest, NULL, buf, &len); + ok(hr == S_OK || + hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP and W2K3 */ + "Unexpected result : %08x\n", hr); + hr = pAssocQueryStringA(0, ASSOCSTR_EXECUTABLE, dotWinetest, "foo", buf, &len); + expect_hr(S_OK, hr); + ok(strstr(buf, action) != NULL, + "got '%s' (Expected result to include 'notepad.exe')\n", buf); + +cleanup: + SHDeleteKeyA(HKEY_CLASSES_ROOT, dotWinetest); + SHDeleteKeyA(HKEY_CLASSES_ROOT, winetestfile); + +} + +START_TEST(assoc) +{ + HMODULE hshlwapi; + hshlwapi = GetModuleHandleA("shlwapi.dll"); + pAssocQueryStringA = (void*)GetProcAddress(hshlwapi, "AssocQueryStringA"); + pAssocQueryStringW = (void*)GetProcAddress(hshlwapi, "AssocQueryStringW"); + + test_getstring_bad(); + test_getstring_basic(); + test_getstring_no_extra(); +} diff --git a/rostests/winetests/shlwapi/clist.c b/rostests/winetests/shlwapi/clist.c index 5f94b4ff6cc..84a05e6f26f 100755 --- a/rostests/winetests/shlwapi/clist.c +++ b/rostests/winetests/shlwapi/clist.c @@ -116,7 +116,7 @@ static HRESULT WINAPI Read(_IDummyStream* This, LPVOID lpMem, ULONG ulSize, else { unsigned int i; - char* buff = (char*)lpMem; + char* buff = lpMem; /* Read item data */ if (!This->item->ulSize) diff --git a/rostests/winetests/shlwapi/clsid.c b/rostests/winetests/shlwapi/clsid.c index 74ad6e50b87..98a8c6d4c01 100755 --- a/rostests/winetests/shlwapi/clsid.c +++ b/rostests/winetests/shlwapi/clsid.c @@ -24,12 +24,12 @@ #include "winerror.h" #include "winnls.h" #include "winuser.h" +#include "initguid.h" #include "shlguid.h" #include "shobjidl.h" #include "olectl.h" -#define INITGUID -#include "initguid.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); /* This GUID has been removed from the PSDK */ DEFINE_OLEGUID(WINE_IID_IDelayedRelease, 0x000214EDL, 0, 0); @@ -107,6 +107,7 @@ static void test_ClassIDs(void) DWORD dwLen; BOOL bRet; int i = 0; + int is_vista = 0; if (!pSHLWAPI_269 || !pSHLWAPI_23) return; @@ -114,7 +115,8 @@ static void test_ClassIDs(void) while (*guids) { dwLen = pSHLWAPI_23(*guids, szBuff, 256); - ok(dwLen == 39, "wrong size for id %d\n", i); + if (!i && dwLen == S_OK) is_vista = 1; /* seems to return an HRESULT on vista */ + ok(dwLen == (is_vista ? S_OK : 39), "wrong size %u for id %d\n", dwLen, i); bRet = pSHLWAPI_269(szBuff, &guid); ok(bRet != FALSE, "created invalid string '%s'\n", szBuff); @@ -128,7 +130,7 @@ static void test_ClassIDs(void) /* Test endianess */ dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 256); - ok(dwLen == 39, "wrong size for IID_Endianess\n"); + ok(dwLen == (is_vista ? S_OK : 39), "wrong size %u for IID_Endianess\n", dwLen); ok(!strcmp(szBuff, "{01020304-0506-0708-090A-0B0C0D0E0F0A}"), "Endianess Broken, got '%s'\n", szBuff); @@ -136,17 +138,17 @@ static void test_ClassIDs(void) /* test lengths */ szBuff[0] = ':'; dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 0); - ok(dwLen == 0, "accepted bad length\n"); + ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n"); ok(szBuff[0] == ':', "wrote to buffer with no length\n"); szBuff[0] = ':'; dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 38); - ok(dwLen == 0, "accepted bad length\n"); + ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n"); ok(szBuff[0] == ':', "wrote to buffer with no length\n"); szBuff[0] = ':'; dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 39); - ok(dwLen == 39, "rejected ok length\n"); + ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n"); ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n"); /* Test string */ @@ -155,7 +157,7 @@ static void test_ClassIDs(void) ok(bRet == FALSE, "accepted invalid string\n"); dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 39); - ok(dwLen == 39, "rejected ok length\n"); + ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n"); ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n"); } diff --git a/rostests/winetests/shlwapi/generated.c b/rostests/winetests/shlwapi/generated.c index 6d50fbcf32e..b5e21f27c81 100755 --- a/rostests/winetests/shlwapi/generated.c +++ b/rostests/winetests/shlwapi/generated.c @@ -1,4 +1,4 @@ -/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* File generated automatically from tools/winapi/tests.dat; do not edit! */ /* This file can be copied, modified and distributed without restriction. */ /* @@ -32,22 +32,14 @@ * Windows API extension */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) -# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) -#elif defined(__GNUC__) -# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) -#else -/* FIXME: Not sure if is possible to do without compiler extension */ -#endif - #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) #elif defined(__GNUC__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* - * FIXME: Not sure if is possible to do without compiler extension - * (if type is not just a name that is, if so the normal) + * FIXME: May not be possible without a compiler extension + * (if type is not just a name that is, otherwise the normal * TYPE_ALIGNMENT can be used) */ #endif @@ -64,104 +56,109 @@ * Test helper macros */ -#ifdef FIELD_ALIGNMENT -# define TEST_FIELD_ALIGNMENT(type, field, align) \ - ok(FIELD_ALIGNMENT(type, field) == align, \ - "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ - (int)FIELD_ALIGNMENT(type, field)) +#ifdef _WIN64 + +# define TEST_TYPE_SIZE(type, size) +# define TEST_TYPE_ALIGN(type, align) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) +# define TEST_FIELD_OFFSET(type, field, offset) + #else -# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) + +# define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); + +# ifdef TYPE_ALIGNMENT +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +#else +# define TEST_TYPE_ALIGN(type, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) \ - ok(FIELD_OFFSET(type, field) == offset, \ - "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ - (long int)FIELD_OFFSET(type, field)) - -#ifdef _TYPE_ALIGNMENT -#define TEST__TYPE_ALIGNMENT(type, align) \ - ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +# ifdef _TYPE_ALIGNMENT +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else -# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) #endif -#ifdef TYPE_ALIGNMENT -#define TEST_TYPE_ALIGNMENT(type, align) \ - ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) -#else -# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); + #endif -#define TEST_TYPE_SIZE(type, size) \ - ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) +#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) +#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) +#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0); +#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0); -/*********************************************************************** - * Test macros - */ - -#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ - TEST_TYPE_SIZE(field_type, field_size); \ - TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ - TEST_FIELD_OFFSET(type, field_name, field_offset); \ - -#define TEST_TYPE(type, size, align) \ - TEST_TYPE_ALIGNMENT(type, align); \ - TEST_TYPE_SIZE(type, size) - -#define TEST_TYPE_POINTER(type, size, align) \ - TEST__TYPE_ALIGNMENT(*(type)0, align); \ - TEST_TYPE_SIZE(*(type)0, size) - -#define TEST_TYPE_SIGNED(type) \ - ok((type) -1 < 0, "(" #type ") -1 < 0\n"); - -#define TEST_TYPE_UNSIGNED(type) \ - ok((type) -1 > 0, "(" #type ") -1 > 0\n"); static void test_pack_ASSOCF(void) { /* ASSOCF */ - TEST_TYPE(ASSOCF, 4, 4); - TEST_TYPE_UNSIGNED(ASSOCF); + TEST_TYPE_SIZE (ASSOCF, 4) + TEST_TYPE_ALIGN (ASSOCF, 4) + TEST_TYPE_UNSIGNED(ASSOCF) } static void test_pack_DLLGETVERSIONPROC(void) { /* DLLGETVERSIONPROC */ - TEST_TYPE(DLLGETVERSIONPROC, 4, 4); + TEST_TYPE_SIZE (DLLGETVERSIONPROC, 4) + TEST_TYPE_ALIGN (DLLGETVERSIONPROC, 4) } static void test_pack_DLLVERSIONINFO(void) { /* DLLVERSIONINFO (pack 8) */ - TEST_TYPE(DLLVERSIONINFO, 20, 4); - TEST_FIELD(DLLVERSIONINFO, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(DLLVERSIONINFO, DWORD, dwMajorVersion, 4, 4, 4); - TEST_FIELD(DLLVERSIONINFO, DWORD, dwMinorVersion, 8, 4, 4); - TEST_FIELD(DLLVERSIONINFO, DWORD, dwBuildNumber, 12, 4, 4); - TEST_FIELD(DLLVERSIONINFO, DWORD, dwPlatformID, 16, 4, 4); + TEST_TYPE_SIZE (DLLVERSIONINFO, 20) + TEST_TYPE_ALIGN (DLLVERSIONINFO, 4) + TEST_FIELD_SIZE (DLLVERSIONINFO, cbSize, 4) + TEST_FIELD_ALIGN (DLLVERSIONINFO, cbSize, 4) + TEST_FIELD_OFFSET(DLLVERSIONINFO, cbSize, 0) + TEST_FIELD_SIZE (DLLVERSIONINFO, dwMajorVersion, 4) + TEST_FIELD_ALIGN (DLLVERSIONINFO, dwMajorVersion, 4) + TEST_FIELD_OFFSET(DLLVERSIONINFO, dwMajorVersion, 4) + TEST_FIELD_SIZE (DLLVERSIONINFO, dwMinorVersion, 4) + TEST_FIELD_ALIGN (DLLVERSIONINFO, dwMinorVersion, 4) + TEST_FIELD_OFFSET(DLLVERSIONINFO, dwMinorVersion, 8) + TEST_FIELD_SIZE (DLLVERSIONINFO, dwBuildNumber, 4) + TEST_FIELD_ALIGN (DLLVERSIONINFO, dwBuildNumber, 4) + TEST_FIELD_OFFSET(DLLVERSIONINFO, dwBuildNumber, 12) + TEST_FIELD_SIZE (DLLVERSIONINFO, dwPlatformID, 4) + TEST_FIELD_ALIGN (DLLVERSIONINFO, dwPlatformID, 4) + TEST_FIELD_OFFSET(DLLVERSIONINFO, dwPlatformID, 16) } static void test_pack_DLLVERSIONINFO2(void) { /* DLLVERSIONINFO2 (pack 8) */ - TEST_TYPE(DLLVERSIONINFO2, 32, 8); - TEST_FIELD(DLLVERSIONINFO2, DLLVERSIONINFO, info1, 0, 20, 4); - TEST_FIELD(DLLVERSIONINFO2, DWORD, dwFlags, 20, 4, 4); - TEST_FIELD(DLLVERSIONINFO2, ULONGLONG, ullVersion, 24, 8, 8); + TEST_TYPE_SIZE (DLLVERSIONINFO2, 32) + TEST_TYPE_ALIGN (DLLVERSIONINFO2, 8) + TEST_FIELD_SIZE (DLLVERSIONINFO2, info1, 20) + TEST_FIELD_ALIGN (DLLVERSIONINFO2, info1, 4) + TEST_FIELD_OFFSET(DLLVERSIONINFO2, info1, 0) + TEST_FIELD_SIZE (DLLVERSIONINFO2, dwFlags, 4) + TEST_FIELD_ALIGN (DLLVERSIONINFO2, dwFlags, 4) + TEST_FIELD_OFFSET(DLLVERSIONINFO2, dwFlags, 20) + TEST_FIELD_SIZE (DLLVERSIONINFO2, ullVersion, 8) + TEST_FIELD_ALIGN (DLLVERSIONINFO2, ullVersion, 8) + TEST_FIELD_OFFSET(DLLVERSIONINFO2, ullVersion, 24) } static void test_pack_HUSKEY(void) { /* HUSKEY */ - TEST_TYPE(HUSKEY, 4, 4); + TEST_TYPE_SIZE (HUSKEY, 4) + TEST_TYPE_ALIGN (HUSKEY, 4) } static void test_pack_PHUSKEY(void) { /* PHUSKEY */ - TEST_TYPE(PHUSKEY, 4, 4); - TEST_TYPE_POINTER(PHUSKEY, 4, 4); + TEST_TYPE_SIZE (PHUSKEY, 4) + TEST_TYPE_ALIGN (PHUSKEY, 4) + TEST_TARGET_SIZE (PHUSKEY, 4) + TEST_TARGET_ALIGN(PHUSKEY, 4) } static void test_pack(void) @@ -176,5 +173,9 @@ static void test_pack(void) START_TEST(generated) { +#ifdef _WIN64 + ok(0, "The type size / alignment tests don't support Win64 yet\n"); +#else test_pack(); +#endif } diff --git a/rostests/winetests/shlwapi/istream.c b/rostests/winetests/shlwapi/istream.c index 05a0e5a4a50..df69db93681 100644 --- a/rostests/winetests/shlwapi/istream.c +++ b/rostests/winetests/shlwapi/istream.c @@ -209,8 +209,12 @@ static void test_SHCreateStreamOnFileA(DWORD mode, DWORD stgm) /* invalid arguments */ stream = NULL; + /* NT: ERROR_PATH_NOT_FOUND, 9x: ERROR_BAD_PATHNAME */ ret = (*pSHCreateStreamOnFileA)(NULL, mode | stgm, &stream); - ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), got 0x%08x\n", ret); + ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || + ret == HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), + "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)" + "or HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); #if 0 /* This test crashes on WinXP SP2 */ @@ -290,27 +294,35 @@ static void test_SHCreateStreamOnFileW(DWORD mode, DWORD stgm) HRESULT ret; ULONG refcount; WCHAR test_file[MAX_PATH]; - static const WCHAR testW_txt[] = { '\\', 't', 'e', 's', 't', 'W', '.', 't', 'x', 't', '\0' }; + CHAR test_fileA[MAX_PATH]; + static const CHAR testW_txt[] = "\\testW.txt"; trace("SHCreateStreamOnFileW: testing mode %d, STGM flags %08x\n", mode, stgm); /* Don't used a fixed path for the testW.txt file */ - GetTempPathW(MAX_PATH, test_file); - lstrcatW(test_file, testW_txt); + GetTempPathA(MAX_PATH, test_fileA); + lstrcatA(test_fileA, testW_txt); + MultiByteToWideChar(CP_ACP, 0, test_fileA, -1, test_file, MAX_PATH); /* invalid arguments */ + if (0) + { + /* Crashes on NT4 */ stream = NULL; ret = (*pSHCreateStreamOnFileW)(NULL, mode | stgm, &stream); ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */ ret == E_INVALIDARG /* Vista */, "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); + } -#if 0 /* This test crashes on WinXP SP2 */ + if (0) + { + /* This test crashes on WinXP SP2 */ ret = (*pSHCreateStreamOnFileW)(test_file, mode | stgm, NULL); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); -#endif + } stream = NULL; ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CONVERT | stgm, &stream); @@ -373,7 +385,9 @@ static void test_SHCreateStreamOnFileW(DWORD mode, DWORD stgm) refcount = IStream_Release(stream); ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount); - ok(DeleteFileW(test_file), "SHCreateStreamOnFileW: could not delete the test file, got error %d\n", GetLastError()); + ok(DeleteFileA(test_fileA), + "SHCreateStreamOnFileW: could not delete the test file, got error %d\n", + GetLastError()); } } @@ -385,32 +399,44 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) HRESULT ret; ULONG refcount; WCHAR test_file[MAX_PATH]; - static const WCHAR testEx_txt[] = { '\\', 't', 'e', 's', 't', 'E','x', '.', 't', 'x', 't', '\0' }; + CHAR test_fileA[MAX_PATH]; + static const CHAR testEx_txt[] = "\\testEx.txt"; trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode, stgm); /* Don't used a fixed path for the testEx.txt file */ - GetTempPathW(MAX_PATH, test_file); - lstrcatW(test_file, testEx_txt); + GetTempPathA(MAX_PATH, test_fileA); + lstrcatA(test_fileA, testEx_txt); + MultiByteToWideChar(CP_ACP, 0, test_fileA, -1, test_file, MAX_PATH); /* invalid arguments */ + if (0) + { + /* Crashes on NT4 */ stream = NULL; ret = (*pSHCreateStreamOnFileEx)(NULL, mode, 0, FALSE, NULL, &stream); ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */ ret == E_INVALIDARG /* Vista */, "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret); ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); + } stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, template, &stream); - ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); + ok( ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), + "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or " + "HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); -#if 0 /* This test crashes on WinXP SP2 */ + if (0) + { + /* This test crashes on WinXP SP2 */ ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, NULL, NULL); ok(ret == E_INVALIDARG, "SHCreateStreamOnFileEx: expected E_INVALIDARG, got 0x%08x\n", ret); -#endif + } /* file does not exist */ @@ -425,12 +451,22 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) return; } } else { - ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); + ok( ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), + "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or " + "HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got 0x%08x\n", ret); } ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); stream = NULL; ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream); + /* not supported on win9x */ + if (broken(ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) && stream == NULL)) { + skip("Not supported\n"); + DeleteFileA(test_fileA); + return; + } + ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); @@ -440,7 +476,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) refcount = IStream_Release(stream); ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); - ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError()); + ok(DeleteFileA(test_fileA), + "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", + GetLastError()); } stream = NULL; @@ -454,7 +492,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) refcount = IStream_Release(stream); ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); - ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError()); + ok(DeleteFileA(test_fileA), + "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", + GetLastError()); } stream = NULL; @@ -514,7 +554,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); } - ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError()); + ok(DeleteFileA(test_fileA), + "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", + GetLastError()); } diff --git a/rostests/winetests/shlwapi/ordinal.c b/rostests/winetests/shlwapi/ordinal.c index f5286f02f45..3a50219278e 100755 --- a/rostests/winetests/shlwapi/ordinal.c +++ b/rostests/winetests/shlwapi/ordinal.c @@ -42,13 +42,19 @@ static void test_GetAcceptLanguagesA(void) DWORD buffersize, buffersize2, exactsize; char buffer[100]; - if (!pGetAcceptLanguagesA) + if (!pGetAcceptLanguagesA) { + win_skip("GetAcceptLanguagesA is not available\n"); return; + } buffersize = sizeof(buffer); memset(buffer, 0, sizeof(buffer)); SetLastError(ERROR_SUCCESS); retval = pGetAcceptLanguagesA( buffer, &buffersize); + if (!retval && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + win_skip("GetAcceptLanguagesA is not implemented\n"); + return; + } trace("GetAcceptLanguagesA: retval %08x, size %08x, buffer (%s)," " last error %u\n", retval, buffersize, buffer, GetLastError()); if(retval != S_OK) { @@ -58,28 +64,31 @@ static void test_GetAcceptLanguagesA(void) ok( (ERROR_NO_IMPERSONATION_TOKEN == GetLastError()) || (ERROR_CLASS_DOES_NOT_EXIST == GetLastError()) || (ERROR_PROC_NOT_FOUND == GetLastError()) || - (ERROR_CALL_NOT_IMPLEMENTED == GetLastError()) || (ERROR_SUCCESS == GetLastError()), "last error set to %u\n", GetLastError()); exactsize = strlen(buffer); SetLastError(ERROR_SUCCESS); retval = pGetAcceptLanguagesA( NULL, NULL); - ok(retval == E_FAIL, + ok(retval == E_FAIL || + retval == E_INVALIDARG, /* w2k8 */ "function result wrong: got %08x; expected E_FAIL\n", retval); ok(ERROR_SUCCESS == GetLastError(), "last error set to %u\n", GetLastError()); buffersize = sizeof(buffer); SetLastError(ERROR_SUCCESS); retval = pGetAcceptLanguagesA( NULL, &buffersize); - ok(retval == E_FAIL, + ok(retval == E_FAIL || + retval == E_INVALIDARG, /* w2k8 */ "function result wrong: got %08x; expected E_FAIL\n", retval); - ok(buffersize == sizeof(buffer), - "buffersize was changed (2nd parameter; not on Win2k)\n"); + ok(buffersize == sizeof(buffer) || + buffersize == 0, /* w2k8*/ + "buffersize was changed and is not 0; size (%d))\n", buffersize); ok(ERROR_SUCCESS == GetLastError(), "last error set to %u\n", GetLastError()); SetLastError(ERROR_SUCCESS); retval = pGetAcceptLanguagesA( buffer, NULL); - ok(retval == E_FAIL, + ok(retval == E_FAIL || + retval == E_INVALIDARG, /* w2k8 */ "function result wrong: got %08x; expected E_FAIL\n", retval); ok(ERROR_SUCCESS == GetLastError(), "last error set to %u\n", GetLastError()); @@ -87,7 +96,8 @@ static void test_GetAcceptLanguagesA(void) memset(buffer, 0, sizeof(buffer)); SetLastError(ERROR_SUCCESS); retval = pGetAcceptLanguagesA( buffer, &buffersize); - ok(retval == E_FAIL, + ok(retval == E_FAIL || + retval == E_INVALIDARG, /* w2k8 */ "function result wrong: got %08x; expected E_FAIL\n", retval); ok(buffersize == 0, "buffersize wrong(changed) got %08x; expected 0 (2nd parameter; not on Win2k)\n", buffersize); @@ -100,9 +110,9 @@ static void test_GetAcceptLanguagesA(void) switch(retval) { case 0L: if(buffersize == exactsize) { - ok( (ERROR_SUCCESS == GetLastError()) || (ERROR_CALL_NOT_IMPLEMENTED == GetLastError()) || + ok( (ERROR_SUCCESS == GetLastError()) || (ERROR_PROC_NOT_FOUND == GetLastError()) || (ERROR_NO_IMPERSONATION_TOKEN == GetLastError()), - "last error wrong: got %u; expected ERROR_SUCCESS(NT4)/ERROR_CALL_NOT_IMPLEMENTED(98/ME)/" + "last error wrong: got %u; expected ERROR_SUCCESS(NT4)/" "ERROR_PROC_NOT_FOUND(NT4)/ERROR_NO_IMPERSONATION_TOKEN(XP)\n", GetLastError()); ok(exactsize == strlen(buffer), "buffer content (length) wrong: got %08x, expected %08x\n", lstrlenA(buffer), exactsize); @@ -219,7 +229,7 @@ static void test_alloc_shared(void) hmem=pSHAllocShared(&val,4,procid); ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %u\n", GetLastError()); - p=(int*)pSHLockShared(hmem,procid); + p=pSHLockShared(hmem,procid); ok(p!=NULL,"SHLockShared failed: %u\n", GetLastError()); if (p!=NULL) ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val); @@ -363,12 +373,32 @@ static void test_GetShellSecurityDescriptor(void) pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475); + if(!pGetShellSecurityDescriptor) + { + win_skip("GetShellSecurityDescriptor not available\n"); + return; + } + psd = pGetShellSecurityDescriptor(NULL, 2); - ok(psd==NULL, "GetShellSecurityDescriptor should fail\n"); + ok(psd==NULL || + broken(psd==INVALID_HANDLE_VALUE), /* IE5 */ + "GetShellSecurityDescriptor should fail\n"); psd = pGetShellSecurityDescriptor(rgsup, 0); ok(psd==NULL, "GetShellSecurityDescriptor should fail\n"); + SetLastError(0xdeadbeef); psd = pGetShellSecurityDescriptor(rgsup, 2); + if (psd == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + /* The previous calls to GetShellSecurityDescriptor don't set the last error */ + win_skip("GetShellSecurityDescriptor is not implemented\n"); + return; + } + if (psd==INVALID_HANDLE_VALUE) + { + win_skip("GetShellSecurityDescriptor is broken on IE5\n"); + return; + } ok(psd!=NULL, "GetShellSecurityDescriptor failed\n"); if (psd!=NULL) { @@ -441,7 +471,7 @@ static void test_SHPackDispParams(void) HRESULT hres; if(!pSHPackDispParams) - skip("SHPackSidpParams not available\n"); + win_skip("SHPackSidpParams not available\n"); memset(¶ms, 0xc0, sizeof(params)); memset(vars, 0xc0, sizeof(vars)); @@ -452,7 +482,7 @@ static void test_SHPackDispParams(void) ok(params.rgdispidNamedArgs == NULL, "params.rgdispidNamedArgs = %p\n", params.rgdispidNamedArgs); ok(params.rgvarg == vars, "params.rgvarg = %p\n", params.rgvarg); ok(V_VT(vars) == VT_I4, "V_VT(var) = %d\n", V_VT(vars)); - ok(V_DISPATCH(vars) == (void*)0xdeadbeef, "failed\n"); + ok(V_I4(vars) == 0xdeadbeef, "failed %x\n", V_I4(vars)); memset(¶ms, 0xc0, sizeof(params)); hres = pSHPackDispParams(¶ms, NULL, 0, 0); diff --git a/rostests/winetests/shlwapi/path.c b/rostests/winetests/shlwapi/path.c index e6b6548247d..e8deaebe1cc 100755 --- a/rostests/winetests/shlwapi/path.c +++ b/rostests/winetests/shlwapi/path.c @@ -82,7 +82,26 @@ static struct { {"foo.bar", FALSE}, {"bogusscheme:", TRUE}, {"http:partial", TRUE}, - {"www.winehq.org", FALSE} + {"www.winehq.org", FALSE}, + /* More examples that the user might enter as the browser start page */ + {"winehq.org", FALSE}, + {"ftp.winehq.org", FALSE}, + {"http://winehq.org", TRUE}, + {"http://www.winehq.org", TRUE}, + {"https://winehq.org", TRUE}, + {"https://www.winehq.org", TRUE}, + {"ftp://winehq.org", TRUE}, + {"ftp://ftp.winehq.org", TRUE}, + {"file://does_not_exist.txt", TRUE}, + {"about:blank", TRUE}, + {"about:home", TRUE}, + {"about:mozilla", TRUE}, + /* scheme is case independent */ + {"HTTP://www.winehq.org", TRUE}, + /* a space at the start is not allowed */ + {" http://www.winehq.org", FALSE}, + {"", FALSE}, + {NULL, FALSE} }; struct { @@ -271,64 +290,36 @@ static void test_PathIsValidCharA(void) BOOL ret; unsigned int c; - ret = pPathIsValidCharA( 0x7f, 0 ); - ok ( !ret, "PathIsValidCharA succeeded: 0x%08x\n", (DWORD)ret ); - - ret = pPathIsValidCharA( 0x7f, 1 ); - ok ( !ret, "PathIsValidCharA succeeded: 0x%08x\n", (DWORD)ret ); - for (c = 0; c < 0x7f; c++) { ret = pPathIsValidCharA( c, ~0U ); - ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff), - "PathIsValidCharA failed: 0x%02x got 0x%08x expected 0x%08x\n", - c, (DWORD)ret, SHELL_charclass[c] ); + ok ( ret || !SHELL_charclass[c], "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret ); } for (c = 0x7f; c <= 0xff; c++) { ret = pPathIsValidCharA( c, ~0U ); - ok ( ret == 0x00000100, - "PathIsValidCharA failed: 0x%02x got 0x%08x expected 0x00000100\n", - c, (DWORD)ret ); + ok ( ret, "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret ); } } static void test_PathIsValidCharW(void) { BOOL ret; - unsigned int c, err_count = 0; - - ret = pPathIsValidCharW( 0x7f, 0 ); - ok ( !ret, "PathIsValidCharW succeeded: 0x%08x\n", (DWORD)ret ); - - ret = pPathIsValidCharW( 0x7f, 1 ); - ok ( !ret, "PathIsValidCharW succeeded: 0x%08x\n", (DWORD)ret ); + unsigned int c; for (c = 0; c < 0x7f; c++) { ret = pPathIsValidCharW( c, ~0U ); - ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff), - "PathIsValidCharW failed: 0x%02x got 0x%08x expected 0x%08x\n", - c, (DWORD)ret, SHELL_charclass[c] ); + ok ( ret || !SHELL_charclass[c], "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret ); } for (c = 0x007f; c <= 0xffff; c++) { ret = pPathIsValidCharW( c, ~0U ); - ok ( ret == 0x00000100, - "PathIsValidCharW failed: 0x%02x got 0x%08x expected 0x00000100\n", - c, (DWORD)ret ); - if (ret != 0x00000100) - { - if(++err_count > 100 ) { - trace("skipping rest of PathIsValidCharW tests " - "because of the current number of errors\n"); - break; + ok ( ret, "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret ); } } - } -} static void test_PathMakePretty(void) { @@ -401,8 +392,12 @@ static void test_PathCombineW(void) /* Some NULL */ wszString2[0] = 'a'; wszString = pPathCombineW(wszString2, NULL, NULL); - ok (wszString == NULL, "Expected a NULL return\n"); - ok (wszString2[0] == 0, "Destination string not empty\n"); + ok (wszString == NULL || + broken(wszString[0] == 'a'), /* Win95 and some W2K */ + "Expected a NULL return\n"); + ok (wszString2[0] == 0 || + broken(wszString2[0] == 'a'), /* Win95 and some W2K */ + "Destination string not empty\n"); HeapFree(GetProcessHeap(), 0, wszString2); @@ -415,7 +410,9 @@ static void test_PathCombineW(void) wszString = pPathCombineW(wbuf, wstr1, wstr2); ok(wszString == NULL, "Expected a NULL return\n"); - ok(wbuf[0] == 0, "Buffer contains data\n"); + ok(wbuf[0] == 0 || + broken(wbuf[0] == 0xbfbf), /* Win95 and some W2K */ + "Buffer contains data\n"); /* PathCombineW can be used in place */ wstr1[3] = 0; @@ -474,7 +471,9 @@ static void test_PathCombineA(void) lstrcpyA(dest, "control"); str = PathCombineA(dest, "", ""); ok(str == dest, "Expected str == dest, got %p\n", str); - ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str); + ok(!lstrcmp(str, "\\") || + broken(!lstrcmp(str, "control")), /* Win95 and some W2K */ + "Expected \\, got %s\n", str); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); /* try NULL directory */ @@ -490,15 +489,23 @@ static void test_PathCombineA(void) lstrcpyA(dest, "control"); str = PathCombineA(dest, NULL, ""); ok(str == dest, "Expected str == dest, got %p\n", str); - ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str); - ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); + ok(!lstrcmp(str, "\\") || + broken(!lstrcmp(str, "one\\two\\three")), /* Win95 and some W2K */ + "Expected \\, got %s\n", str); + ok(GetLastError() == 0xdeadbeef || + broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win95 */ + "Expected 0xdeadbeef, got %d\n", GetLastError()); /* try NULL directory and file part */ SetLastError(0xdeadbeef); lstrcpyA(dest, "control"); str = PathCombineA(dest, NULL, NULL); - ok(str == NULL, "Expected str == NULL, got %p\n", str); - ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest)); + ok(str == NULL || + broken(str != NULL), /* Win95 and some W2K */ + "Expected str == NULL, got %p\n", str); + ok(lstrlenA(dest) == 0 || + broken(!lstrcmp(dest, "control")), /* Win95 and some W2K */ + "Expected 0 length, got %i\n", lstrlenA(dest)); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); /* try directory without backslash */ @@ -586,7 +593,9 @@ static void test_PathCombineA(void) lstrcpyA(dest, "control"); str = PathCombineA(dest, "C:\\", too_long); ok(str == NULL, "Expected str == NULL, got %p\n", str); - ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest)); + ok(lstrlenA(dest) == 0 || + broken(!lstrcmp(dest, "control")), /* Win95 and some W2K */ + "Expected 0 length, got %i\n", lstrlenA(dest)); todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); /* try a directory longer than MAX_PATH */ @@ -594,7 +603,9 @@ static void test_PathCombineA(void) lstrcpyA(dest, "control"); str = PathCombineA(dest, too_long, "one\\two\\three"); ok(str == NULL, "Expected str == NULL, got %p\n", str); - ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest)); + ok(lstrlenA(dest) == 0 || + broken(!lstrcmp(dest, "control")), /* Win95 and some W2K */ + "Expected 0 length, got %i\n", lstrlenA(dest)); todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); memset(one, 'b', HALF_LEN); @@ -607,7 +618,9 @@ static void test_PathCombineA(void) lstrcpyA(dest, "control"); str = PathCombineA(dest, one, two); ok(str == NULL, "Expected str == NULL, got %p\n", str); - ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest)); + ok(lstrlenA(dest) == 0 || + broken(!lstrcmp(dest, "control")), /* Win95 and some W2K */ + "Expected 0 length, got %i\n", lstrlenA(dest)); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); } @@ -773,7 +786,9 @@ static void test_PathAppendA(void) res = PathAppendA(too_long, "two\\three"); ok(!res, "Expected failure\n"); todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(lstrlen(too_long) == 0, "Expected length of too_long to be zero, got %i\n", lstrlen(too_long)); + ok(lstrlen(too_long) == 0 || + broken(lstrlen(too_long) == (LONG_LEN - 1)), /* Win95 and some W2K */ + "Expected length of too_long to be zero, got %i\n", lstrlen(too_long)); /* pszMore is too long */ lstrcpy(path, "C:\\one"); @@ -783,7 +798,9 @@ static void test_PathAppendA(void) res = PathAppendA(path, too_long); ok(!res, "Expected failure\n"); todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(lstrlen(path) == 0, "Expected length of path to be zero, got %i\n", lstrlen(path)); + ok(lstrlen(path) == 0 || + broken(!lstrcmp(path, "C:\\one")), /* Win95 and some W2K */ + "Expected length of path to be zero, got %i\n", lstrlen(path)); /* both params combined are too long */ memset(one, 'a', HALF_LEN); @@ -793,13 +810,15 @@ static void test_PathAppendA(void) SetLastError(0xdeadbeef); res = PathAppendA(one, two); ok(!res, "Expected failure\n"); - ok(lstrlen(one) == 0, "Expected length of one to be zero, got %i\n", lstrlen(one)); + ok(lstrlen(one) == 0 || + broken(lstrlen(one) == (HALF_LEN - 1)), /* Win95 and some W2K */ + "Expected length of one to be zero, got %i\n", lstrlen(one)); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); } static void test_PathCanonicalizeA(void) { - char dest[MAX_PATH]; + char dest[LONG_LEN + MAX_PATH]; char too_long[LONG_LEN]; BOOL res; @@ -819,7 +838,9 @@ static void test_PathCanonicalizeA(void) res = PathCanonicalizeA(dest, ""); ok(res, "Expected success\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(!lstrcmp(dest, "\\"), "Expected \\, got %s\n", dest); + ok(!lstrcmp(dest, "\\") || + broken(!lstrcmp(dest, "test")), /* Win95 and some W2K */ + "Expected \\, got %s\n", dest); /* try a NULL dest */ SetLastError(0xdeadbeef); @@ -891,7 +912,9 @@ static void test_PathCanonicalizeA(void) res = PathCanonicalizeA(dest, "C:\\one/.\\two\\.."); ok(res, "Expected success\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(!lstrcmp(dest, "C:\\one/."), "Expected C:\\one/., got %s\n", dest); + ok(!lstrcmp(dest, "C:\\one/.") || + !lstrcmp(dest, "C:\\one/"), /* Vista */ + "Expected \"C:\\one/.\" or \"C:\\one/\", got \"%s\"\n", dest); /* try forward slashes with change dirs * NOTE: if there is a forward slash in between two backslashes, @@ -910,10 +933,13 @@ static void test_PathCanonicalizeA(void) lstrcpy(dest, "test"); SetLastError(0xdeadbeef); res = PathCanonicalizeA(dest, too_long); - ok(!res, "Expected failure\n"); + ok(!res || + broken(res), /* Win95, some W2K and XP-SP1 */ + "Expected failure\n"); todo_wine { - ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_FILENAME_EXCED_RANGE /* Vista */, + "Expected 0xdeadbeef or ERROR_FILENAME_EXCED_RANGE, got %d\n", GetLastError()); } ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long)); } @@ -1012,7 +1038,9 @@ static void test_PathBuildRootA(void) lstrcpy(path, "aaaaaaaaa"); root = PathBuildRootA(path, -1); ok(root == path, "Expected root == path, got %p\n", root); - ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path); + ok(!lstrcmp(path, "aaaaaaaaa") || + lstrlenA(path) == 0, /* Vista */ + "Expected aaaaaaaaa or empty string, got %s\n", path); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); /* test a drive number greater than 25 */ @@ -1020,7 +1048,9 @@ static void test_PathBuildRootA(void) lstrcpy(path, "aaaaaaaaa"); root = PathBuildRootA(path, 26); ok(root == path, "Expected root == path, got %p\n", root); - ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path); + ok(!lstrcmp(path, "aaaaaaaaa") || + lstrlenA(path) == 0, /* Vista */ + "Expected aaaaaaaaa or empty string, got %s\n", path); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); /* length of path is less than 4 */ diff --git a/rostests/winetests/shlwapi/shlwapi.rbuild b/rostests/winetests/shlwapi/shlwapi.rbuild index ac5bc5ef854..cd5cffd19a3 100644 --- a/rostests/winetests/shlwapi/shlwapi.rbuild +++ b/rostests/winetests/shlwapi/shlwapi.rbuild @@ -3,8 +3,8 @@ . - 0x600 - 0x600 + + assoc.c clist.c clsid.c generated.c @@ -21,7 +21,6 @@ advapi32 ole32 oleaut32 - kernel32 ntdll diff --git a/rostests/winetests/shlwapi/shreg.c b/rostests/winetests/shlwapi/shreg.c index 77a47e2240c..2c61e3539c4 100755 --- a/rostests/winetests/shlwapi/shreg.c +++ b/rostests/winetests/shlwapi/shreg.c @@ -31,7 +31,7 @@ /* Keys used for testing */ #define REG_TEST_KEY "Software\\Wine\\Test" -#define REG_CURRENT_VERSION "Software\\Microsoft\\Windows\\CurrentVersion" +#define REG_CURRENT_VERSION "Software\\Microsoft\\Windows\\CurrentVersion\\explorer" static HMODULE hshlwapi; typedef DWORD (WINAPI *SHCopyKeyA_func)(HKEY,LPCSTR,HKEY,DWORD); @@ -122,8 +122,12 @@ static void test_SHGetValue(void) dwType = -1; dwRet = SHGetValueA(HKEY_CURRENT_USER, REG_TEST_KEY, "Test1", &dwType, buf, &dwSize); ok( ERROR_SUCCESS == dwRet, "SHGetValueA failed, ret=%u\n", dwRet); - ok( 0 == strcmp(sExpTestpath1, buf), "Comparing of (%s) with (%s) failed\n", buf, sExpTestpath1); - ok( REG_SZ == dwType, "Expected REG_SZ, got (%u)\n", dwType); + ok( 0 == strcmp(sExpTestpath1, buf) || + broken(0 == strcmp(sTestpath1, buf)), /* IE4.x */ + "Comparing of (%s) with (%s) failed\n", buf, sExpTestpath1); + ok( REG_SZ == dwType || + broken(REG_EXPAND_SZ == dwType), /* IE4.x */ + "Expected REG_SZ, got (%u)\n", dwType); strcpy(buf, sEmptyBuffer); dwSize = MAX_PATH; @@ -196,7 +200,9 @@ static void test_SHQUeryValueEx(void) dwSize = 6; dwRet = SHQueryValueExA( hKey, "Test3", NULL, NULL, NULL, &dwSize); ok( ERROR_SUCCESS == dwRet, "%s failed, ret=%u\n", sTestedFunction, dwRet); - ok( dwSize >= nUsedBuffer2, "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); + ok( dwSize >= nUsedBuffer2 || + broken(dwSize == (strlen(sTestpath2) + 1)), /* < IE4.x */ + "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); /* * Case 1 string shrinks during expanding @@ -208,7 +214,9 @@ static void test_SHQUeryValueEx(void) ok( ERROR_MORE_DATA == dwRet, "Expected ERROR_MORE_DATA, got (%u)\n", dwRet); ok( 0 == strcmp(sEmptyBuffer, buf) , "Comparing (%s) with (%s) failed\n", buf, sEmptyBuffer); ok( dwSize == nUsedBuffer1, "Buffer sizes (%u) and (%u) are not equal\n", dwSize, nUsedBuffer1); - ok( REG_SZ == dwType , "Expected REG_SZ, got (%u)\n", dwType); + ok( REG_SZ == dwType || + broken(REG_EXPAND_SZ == dwType), /* < IE6 */ + "Expected REG_SZ, got (%u)\n", dwType); /* * string grows during expanding @@ -220,8 +228,12 @@ static void test_SHQUeryValueEx(void) dwRet = SHQueryValueExA( hKey, "Test3", NULL, &dwType, buf, &dwSize); ok( ERROR_MORE_DATA == dwRet, "Expected ERROR_MORE_DATA, got (%u)\n", dwRet); ok( 0 == strcmp(sEmptyBuffer, buf) , "Comparing (%s) with (%s) failed\n", buf, sEmptyBuffer); - ok( dwSize >= nUsedBuffer2, "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); - ok( REG_SZ == dwType , "Expected REG_SZ, got (%u)\n", dwType); + ok( dwSize >= nUsedBuffer2 || + broken(dwSize == (strlen(sTestpath2) + 1)), /* < IE6 */ + "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); + ok( REG_SZ == dwType || + broken(REG_EXPAND_SZ == dwType), /* < IE6 */ + "Expected REG_SZ, got (%u)\n", dwType); /* * string grows during expanding @@ -233,7 +245,10 @@ static void test_SHQUeryValueEx(void) dwSize = strlen(sEnvvar2) - 2; dwType = -1; dwRet = SHQueryValueExA( hKey, "Test3", NULL, &dwType, buf, &dwSize); - ok( ERROR_MORE_DATA == dwRet, "Expected ERROR_MORE_DATA, got (%u)\n", dwRet); + ok( ERROR_MORE_DATA == dwRet || + broken(ERROR_ENVVAR_NOT_FOUND == dwRet) || /* IE5.5 */ + broken(ERROR_SUCCESS == dwRet), /* < IE5.5*/ + "Expected ERROR_MORE_DATA, got (%u)\n", dwRet); todo_wine { @@ -241,7 +256,9 @@ static void test_SHQUeryValueEx(void) "Expected empty or unexpanded string (win98), got (%s)\n", buf); } - ok( dwSize >= nUsedBuffer2, "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); + ok( dwSize >= nUsedBuffer2 || + broken(dwSize == (strlen("") + 1)), /* < IE 5.5 */ + "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); ok( REG_SZ == dwType , "Expected REG_SZ, got (%u)\n", dwType); /* @@ -254,15 +271,22 @@ static void test_SHQUeryValueEx(void) dwSize = nExpLen2 - 4; dwType = -1; dwRet = SHQueryValueExA( hKey, "Test3", NULL, &dwType, buf, &dwSize); - ok( ERROR_MORE_DATA == dwRet, "Expected ERROR_MORE_DATA, got (%u)\n", dwRet); + ok( ERROR_MORE_DATA == dwRet || + broken(ERROR_ENVVAR_NOT_FOUND == dwRet) || /* IE5.5 */ + broken(ERROR_SUCCESS == dwRet), /* < IE5.5 */ + "Expected ERROR_MORE_DATA, got (%u)\n", dwRet); todo_wine { - ok( (0 == strcmp("", buf)) || (0 == strcmp(sEnvvar2, buf)), + ok( (0 == strcmp("", buf)) || (0 == strcmp(sEnvvar2, buf)) || + broken(0 == strcmp(sTestpath2, buf)), /* IE 5.5 */ "Expected empty or first part of the string \"%s\", got \"%s\"\n", sEnvvar2, buf); } - ok( dwSize >= nUsedBuffer2, "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); + ok( dwSize >= nUsedBuffer2 || + broken(dwSize == (strlen(sEnvvar2) + 1)) || /* IE4.01 SP1 (W98) and IE5 (W98SE) */ + broken(dwSize == (strlen("") + 1)), /* IE4.01 (NT4) and IE5.x (W2K) */ + "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); ok( REG_SZ == dwType , "Expected REG_SZ, got (%u)\n", dwType); /* @@ -273,7 +297,9 @@ static void test_SHQUeryValueEx(void) dwType = -1; dwRet = SHQueryValueExA( hKey, "Test3", NULL, &dwType, NULL, &dwSize); ok( ERROR_SUCCESS == dwRet, "%s failed, ret=%u\n", sTestedFunction, dwRet); - ok( dwSize >= nUsedBuffer2, "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); + ok( dwSize >= nUsedBuffer2 || + broken(dwSize == (strlen(sTestpath2) + 1)), /* IE4.01 SP1 (Win98) */ + "Buffer size (%u) should be >= (%u)\n", dwSize, nUsedBuffer2); ok( REG_SZ == dwType , "Expected REG_SZ, got (%u)\n", dwType); RegCloseKey(hKey); @@ -284,6 +310,12 @@ static void test_SHCopyKey(void) HKEY hKeySrc, hKeyDst; DWORD dwRet; + if (!pSHCopyKeyA) + { + win_skip("SHCopyKeyA is not available\n"); + return; + } + /* Delete existing destination sub keys */ hKeyDst = NULL; if (!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination", &hKeyDst) && hKeyDst) @@ -305,22 +337,19 @@ static void test_SHCopyKey(void) if (dwRet || !hKeySrc) { ok( 0, "Source couldn't be opened, RegOpenKeyA returned (%u)\n", dwRet); + RegCloseKey(hKeyDst); return; } - - if (pSHCopyKeyA) - { dwRet = (*pSHCopyKeyA)(hKeySrc, NULL, hKeyDst, 0); ok ( ERROR_SUCCESS == dwRet, "Copy failed, ret=(%u)\n", dwRet); - } RegCloseKey(hKeySrc); RegCloseKey(hKeyDst); /* Check we copied the sub keys, i.e. something that's on every windows system (including Wine) */ hKeyDst = NULL; - dwRet = RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination\\Setup", &hKeyDst); + dwRet = RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination\\Shell Folders", &hKeyDst); if (dwRet || !hKeyDst) { ok ( 0, "Copy couldn't be opened, RegOpenKeyA returned (%u)\n", dwRet); @@ -328,7 +357,7 @@ static void test_SHCopyKey(void) } /* And the we copied the values too */ - ok(!SHQueryValueExA(hKeyDst, "BootDir", NULL, NULL, NULL, NULL), "SHQueryValueExA failed\n"); + ok(!SHQueryValueExA(hKeyDst, "Common AppData", NULL, NULL, NULL, NULL), "SHQueryValueExA failed\n"); RegCloseKey(hKeyDst); } diff --git a/rostests/winetests/shlwapi/string.c b/rostests/winetests/shlwapi/string.c index 79a645c2e71..edba21b59fa 100755 --- a/rostests/winetests/shlwapi/string.c +++ b/rostests/winetests/shlwapi/string.c @@ -35,6 +35,11 @@ ok(ret == val, "Unexpected value of '" #expr "': " #fmt " instead of " #val "\n", ret); \ } while (0); +#define expect_eq2(expr, val1, val2, type, fmt) do { \ + type ret = expr; \ + ok(ret == val1 || ret == val2, "Unexpected value of '" #expr "': " #fmt " instead of " #val1 " or " #val2 "\n", ret); \ +} while (0); + static BOOL (WINAPI *pIntlStrEqWorkerA)(BOOL,LPCSTR,LPCSTR,int); static BOOL (WINAPI *pIntlStrEqWorkerW)(BOOL,LPCWSTR,LPCWSTR,int); static DWORD (WINAPI *pSHAnsiToAnsi)(LPCSTR,LPSTR,int); @@ -198,9 +203,8 @@ static void test_StrChrA(void) for (count = 32; count < 128; count++) { LPSTR result = StrChrA(string+32, count); - ok(result - string == count, - "found char '%c' in wrong place: got %d, expected %d\n", - count, result - string, count); + INT pos = result - string; + ok(pos == count, "found char '%c' in wrong place: got %d, expected %d\n", count, pos, count); } for (count = 32; count < 128; count++) @@ -335,9 +339,8 @@ static void test_StrRChrW(void) for (count = 32; count < 128; count++) { LPWSTR result = StrRChrW(string+32, NULL, count); - ok(result - string == count, - "found char %d in wrong place: got %d, expected %d\n", - count, result - string, count); + INT pos = result - string; + ok(pos == count, "found char %d in wrong place: got %d, expected %d\n", count, pos, count); } for (count = 32; count < 128; count++) @@ -481,7 +484,7 @@ static void test_StrDupA(void) if (lpszStr) { ok(!strcmp(result->byte_size_64, lpszStr), "Copied string wrong\n"); - LocalFree((HLOCAL)lpszStr); + LocalFree(lpszStr); } result++; } @@ -491,7 +494,7 @@ static void test_StrDupA(void) */ lpszStr = StrDupA(NULL); ok(lpszStr == NULL || *lpszStr == '\0', "NULL string returned %p\n", lpszStr); - LocalFree((HLOCAL)lpszStr); + LocalFree(lpszStr); } static void test_StrFormatByteSize64A(void) @@ -501,7 +504,7 @@ static void test_StrFormatByteSize64A(void) if (!pStrFormatByteSize64A) { - skip("StrFormatByteSize64A() is not available. Tests skipped\n"); + win_skip("StrFormatByteSize64A() is not available\n"); return; } @@ -525,7 +528,7 @@ static void test_StrFormatKBSizeW(void) if (!pStrFormatKBSizeW) { - skip("StrFormatKBSizeW() is not available. Tests skipped\n"); + win_skip("StrFormatKBSizeW() is not available\n"); return; } @@ -547,7 +550,7 @@ static void test_StrFormatKBSizeA(void) if (!pStrFormatKBSizeA) { - skip("StrFormatKBSizeA() is not available. Tests skipped\n"); + win_skip("StrFormatKBSizeA() is not available\n"); return; } @@ -593,7 +596,7 @@ static void test_StrCmpA(void) ok(!pStrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n"); } else - skip("StrIsIntlEqualA() is not available. Tests skipped\n"); + win_skip("StrIsIntlEqualA() is not available\n"); if (pIntlStrEqWorkerA) { @@ -601,7 +604,7 @@ static void test_StrCmpA(void) ok(!pIntlStrEqWorkerA(TRUE, str1, str2, 5), "pIntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n"); } else - skip("IntlStrEqWorkerA() is not available. Tests skipped\n"); + win_skip("IntlStrEqWorkerA() is not available\n"); } static void test_StrCmpW(void) @@ -620,7 +623,7 @@ static void test_StrCmpW(void) ok(!pStrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n"); } else - skip("StrIsIntlEqualW() is not available. Tests skipped\n"); + win_skip("StrIsIntlEqualW() is not available\n"); if (pIntlStrEqWorkerW) { @@ -628,7 +631,7 @@ static void test_StrCmpW(void) ok(!pIntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n"); } else - skip("IntlStrEqWorkerW() is not available. Tests skipped\n"); + win_skip("IntlStrEqWorkerW() is not available\n"); } static WCHAR *CoDupStrW(const char* src) @@ -649,7 +652,7 @@ static void test_StrRetToBSTR(void) if (!pStrRetToBSTR) { - skip("StrRetToBSTR() is not available. Tests skipped\n"); + win_skip("StrRetToBSTR() is not available\n"); return; } @@ -659,7 +662,6 @@ static void test_StrRetToBSTR(void) ret = pStrRetToBSTR(&strret, NULL, &bstr); ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW), "STRRET_WSTR: dup failed, ret=0x%08x, bstr %p\n", ret, bstr); - if (bstr) SysFreeString(bstr); strret.uType = STRRET_CSTR; @@ -667,7 +669,6 @@ static void test_StrRetToBSTR(void) ret = pStrRetToBSTR(&strret, NULL, &bstr); ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW), "STRRET_CSTR: dup failed, ret=0x%08x, bstr %p\n", ret, bstr); - if (bstr) SysFreeString(bstr); strret.uType = STRRET_OFFSET; @@ -676,7 +677,6 @@ static void test_StrRetToBSTR(void) ret = pStrRetToBSTR(&strret, iidl, &bstr); ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW), "STRRET_OFFSET: dup failed, ret=0x%08x, bstr %p\n", ret, bstr); - if (bstr) SysFreeString(bstr); /* Native crashes if str is NULL */ @@ -690,7 +690,7 @@ static void test_StrCpyNXA(void) if (!pStrCpyNXA) { - skip("StrCpyNXA() is not available. Tests skipped\n"); + win_skip("StrCpyNXA() is not available\n"); return; } @@ -711,7 +711,7 @@ static void test_StrCpyNXW(void) if (!pStrCpyNXW) { - skip("StrCpyNXW() is not available. Tests skipped\n"); + win_skip("StrCpyNXW() is not available\n"); return; } @@ -768,7 +768,7 @@ static void test_SHAnsiToAnsi(void) if (!pSHAnsiToAnsi) { - skip("SHAnsiToAnsi() is not available. Tests skipped\n"); + win_skip("SHAnsiToAnsi() is not available\n"); return; } @@ -789,7 +789,7 @@ static void test_SHUnicodeToUnicode(void) if (!pSHUnicodeToUnicode) { - skip("SHUnicodeToUnicode() is not available. Tests skipped\n"); + win_skip("SHUnicodeToUnicode() is not available\n"); return; } @@ -829,7 +829,7 @@ static void test_StrXXX_overflows(void) expect_eq(buf[100], '\xbf', CHAR, "%x"); } else - skip("StrCatBuffA() is not available. Tests skipped\n"); + win_skip("StrCatBuffA() is not available\n"); memset(wbuf, 0xbf, sizeof(wbuf)); expect_eq(StrCpyNW(wbuf, wstr1, 10), wbuf, PWCHAR, "%p"); @@ -843,53 +843,53 @@ static void test_StrXXX_overflows(void) expect_eq(wbuf[100], (WCHAR)0xbfbf, WCHAR, "%x"); } else - skip("StrCatBuffW() is not available. Tests skipped\n"); + win_skip("StrCatBuffW() is not available\n"); if (pStrRetToBufW) { memset(wbuf, 0xbf, sizeof(wbuf)); strret.uType = STRRET_WSTR; U(strret).pOleStr = StrDupW(wstr1); - expect_eq(pStrRetToBufW(&strret, NULL, wbuf, 10), S_OK, HRESULT, "%x"); + expect_eq2(pStrRetToBufW(&strret, NULL, wbuf, 10), S_OK, HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) /* Vista */, HRESULT, "%x"); expect_eq(wbuf[9], 0, WCHAR, "%x"); expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); } else - skip("StrRetToBufW() is not available. Tests skipped\n"); + win_skip("StrRetToBufW() is not available\n"); if (pStrRetToBufA) { memset(buf, 0xbf, sizeof(buf)); strret.uType = STRRET_CSTR; StrCpyN(U(strret).cStr, str1, MAX_PATH); - expect_eq(pStrRetToBufA(&strret, NULL, buf, 10), S_OK, HRESULT, "%x"); + expect_eq2(pStrRetToBufA(&strret, NULL, buf, 10), S_OK, HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) /* Vista */, HRESULT, "%x"); expect_eq(buf[9], 0, CHAR, "%x"); expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x"); } else - skip("StrRetToBufA() is not available. Tests skipped\n"); + win_skip("StrRetToBufA() is not available\n"); if (pwnsprintfA) { memset(buf, 0xbf, sizeof(buf)); ret = pwnsprintfA(buf, 10, "%s", str1); - todo_wine ok(ret == 9, "Unexpected wsnprintfA return %d, expected 9\n", ret); + ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wsnprintfA return %d, expected 9 or -1\n", ret); expect_eq(buf[9], 0, CHAR, "%x"); expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x"); } else - skip("wnsprintfA() is not available. Tests skipped\n"); + win_skip("wnsprintfA() is not available\n"); if (pwnsprintfW) { memset(wbuf, 0xbf, sizeof(wbuf)); ret = pwnsprintfW(wbuf, 10, fmt, wstr1); - todo_wine ok(ret == 9, "Unexpected wsnprintfW return %d, expected 9\n", ret); + ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wsnprintfW return %d, expected 9 or -1\n", ret); expect_eq(wbuf[9], 0, WCHAR, "%x"); expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); } else - skip("wnsprintfW() is not available. Tests skipped\n"); + win_skip("wnsprintfW() is not available\n"); } START_TEST(string) diff --git a/rostests/winetests/shlwapi/url.c b/rostests/winetests/shlwapi/url.c index 3b0633aa9bb..f135f2a1e19 100644 --- a/rostests/winetests/shlwapi/url.c +++ b/rostests/winetests/shlwapi/url.c @@ -1,7 +1,7 @@ /* Unit test suite for Path functions * * Copyright 2002 Matthew Mastracci - * Copyright 2007 Detlef Riekenberg + * Copyright 2007,2008 Detlef Riekenberg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -40,6 +40,35 @@ static const CHAR winehqA[] = {'h','t','t','p',':','/','/','w','w','w','.','w', /* ################ */ +static const CHAR untouchedA[] = "untouched"; + +#define TEST_APPLY_MAX_LENGTH INTERNET_MAX_URL_LENGTH + +typedef struct _TEST_URL_APPLY { + const char * url; + DWORD flags; + HRESULT res; + DWORD newlen; + const char * newurl; +} TEST_URL_APPLY; + +static const TEST_URL_APPLY TEST_APPLY[] = { + {"www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 21, "http://www.winehq.org"}, + {"www.winehq.org", URL_APPLY_GUESSSCHEME, S_OK, 21, "http://www.winehq.org"}, + {"www.winehq.org", URL_APPLY_DEFAULT, S_OK, 21, "http://www.winehq.org"}, + {"ftp.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 20, "ftp://ftp.winehq.org"}, + {"ftp.winehq.org", URL_APPLY_GUESSSCHEME, S_OK, 20, "ftp://ftp.winehq.org"}, + {"ftp.winehq.org", URL_APPLY_DEFAULT, S_OK, 21, "http://ftp.winehq.org"}, + {"winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 17, "http://winehq.org"}, + {"winehq.org", URL_APPLY_GUESSSCHEME, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, + {"winehq.org", URL_APPLY_DEFAULT, S_OK, 17, "http://winehq.org"}, + {"", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 7, "http://"}, + {"", URL_APPLY_GUESSSCHEME, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, + {"", URL_APPLY_DEFAULT, S_OK, 7, "http://"} +}; + +/* ################ */ + typedef struct _TEST_URL_CANONICALIZE { const char *url; DWORD flags; @@ -103,7 +132,7 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { {"res:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "res:///c:\\tests\\foo bar", TRUE}, {"A", 0, S_OK, "A", FALSE}, {"/uri-res/N2R?urn:sha1:B3K", URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY /*0x82000000*/, S_OK, "/uri-res/N2R?urn:sha1:B3K", TRUE} /*LimeWire online installer calls this*/, - {"", 0, S_OK, "", FALSE} + {"http:www.winehq.org/dir/../index.html", 0, S_OK, "http:www.winehq.org/index.html"}, }; /* ################ */ @@ -233,6 +262,29 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = { {"foo:today", "bar:calendar", 0, S_OK, "bar:calendar"}, {"foo:/today", "foo:calendar", 0, S_OK, "foo:/calendar"}, {"foo:/today/", "foo:calendar", 0, S_OK, "foo:/today/calendar"}, + {"mk:@MSITStore:dir/test.chm::dir/index.html", "image.jpg", 0, S_OK, "mk:@MSITStore:dir/test.chm::dir/image.jpg"}, + {"mk:@MSITStore:dir/test.chm::dir/dir2/index.html", "../image.jpg", 0, S_OK, "mk:@MSITStore:dir/test.chm::dir/image.jpg"}, + /* UrlCombine case 2 tests. Schemes do not match */ + {"outbind://xxxxxxxxx","http://wine1/dir",0, S_OK,"http://wine1/dir"}, + {"xxxx://xxxxxxxxx","http://wine2/dir",0, S_OK,"http://wine2/dir"}, + {"ftp://xxxxxxxxx/","http://wine3/dir",0, S_OK,"http://wine3/dir"}, + {"outbind://xxxxxxxxx","http://wine4/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"http://wine4/dir"}, + {"xxx://xxxxxxxxx","http://wine5/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"http://wine5/dir"}, + {"ftp://xxxxxxxxx/","http://wine6/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"http://wine6/dir"}, + {"http://xxxxxxxxx","outbind://wine7/dir",0, S_OK,"outbind://wine7/dir"}, + {"xxx://xxxxxxxxx","ftp://wine8/dir",0, S_OK,"ftp://wine8/dir"}, + {"ftp://xxxxxxxxx/","xxx://wine9/dir",0, S_OK,"xxx://wine9/dir"}, + {"http://xxxxxxxxx","outbind://wine10/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"outbind://wine10/dir"}, + {"xxx://xxxxxxxxx","ftp://wine11/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"ftp://wine11/dir"}, + {"ftp://xxxxxxxxx/","xxx://wine12/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"xxx://wine12/dir"}, + {"http://xxxxxxxxx","outbind:wine13/dir",0, S_OK,"outbind:wine13/dir"}, + {"xxx://xxxxxxxxx","ftp:wine14/dir",0, S_OK,"ftp:wine14/dir"}, + {"ftp://xxxxxxxxx/","xxx:wine15/dir",0, S_OK,"xxx:wine15/dir"}, + {"outbind://xxxxxxxxx/","http:wine16/dir",0, S_OK,"http:wine16/dir"}, + {"http://xxxxxxxxx","outbind:wine17/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"outbind:wine17/dir"}, + {"xxx://xxxxxxxxx","ftp:wine18/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"ftp:wine18/dir"}, + {"ftp://xxxxxxxxx/","xxx:wine19/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"xxx:wine19/dir"}, + {"outbind://xxxxxxxxx/","http:wine20/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"http:wine20/dir"} }; /* ################ */ @@ -264,7 +316,8 @@ static struct { const char *expect; } TEST_URL_UNESCAPE[] = { {"file://foo/bar", "file://foo/bar"}, - {"file://fo%20o%5Ca/bar", "file://fo o\\a/bar"} + {"file://fo%20o%5Ca/bar", "file://fo o\\a/bar"}, + {"file://%24%25foobar", "file://$%foobar"} }; /* ################ */ @@ -335,6 +388,79 @@ static void FreeWideString(LPWSTR wszString) /* ########################### */ +static void test_UrlApplyScheme(void) +{ + CHAR newurl[TEST_APPLY_MAX_LENGTH]; + WCHAR urlW[TEST_APPLY_MAX_LENGTH]; + WCHAR newurlW[TEST_APPLY_MAX_LENGTH]; + HRESULT res; + DWORD len; + DWORD i; + + for(i = 0; i < sizeof(TEST_APPLY)/sizeof(TEST_APPLY[0]); i++) { + len = TEST_APPLY_MAX_LENGTH; + lstrcpyA(newurl, untouchedA); + res = UrlApplySchemeA(TEST_APPLY[i].url, newurl, &len, TEST_APPLY[i].flags); + ok( res == TEST_APPLY[i].res, + "#%dA: got HRESULT 0x%x (expected 0x%x)\n", i, res, TEST_APPLY[i].res); + + ok( len == TEST_APPLY[i].newlen, + "#%dA: got len %d (expected %d)\n", i, len, TEST_APPLY[i].newlen); + + ok( !lstrcmpA(newurl, TEST_APPLY[i].newurl), + "#%dA: got '%s' (expected '%s')\n", i, newurl, TEST_APPLY[i].newurl); + + /* returned length is in character */ + len = TEST_APPLY_MAX_LENGTH; + lstrcpyA(newurl, untouchedA); + MultiByteToWideChar(CP_ACP, 0, newurl, -1, newurlW, len); + MultiByteToWideChar(CP_ACP, 0, TEST_APPLY[i].url, -1, urlW, len); + + res = UrlApplySchemeW(urlW, newurlW, &len, TEST_APPLY[i].flags); + WideCharToMultiByte(CP_ACP, 0, newurlW, -1, newurl, TEST_APPLY_MAX_LENGTH, NULL, NULL); + ok( res == TEST_APPLY[i].res, + "#%dW: got HRESULT 0x%x (expected 0x%x)\n", i, res, TEST_APPLY[i].res); + + ok( len == TEST_APPLY[i].newlen, + "#%dW: got len %d (expected %d)\n", i, len, TEST_APPLY[i].newlen); + + ok( !lstrcmpA(newurl, TEST_APPLY[i].newurl), + "#%dW: got '%s' (expected '%s')\n", i, newurl, TEST_APPLY[i].newurl); + + } + + /* buffer too small */ + lstrcpyA(newurl, untouchedA); + len = lstrlenA(TEST_APPLY[0].newurl); + res = UrlApplySchemeA(TEST_APPLY[0].url, newurl, &len, TEST_APPLY[0].flags); + ok(res == E_POINTER, "got HRESULT 0x%x (expected E_POINTER)\n", res); + /* The returned length include the space for the terminating 0 */ + i = lstrlenA(TEST_APPLY[0].newurl)+1; + ok(len == i, "got len %d (expected %d)\n", len, i); + ok(!lstrcmpA(newurl, untouchedA), "got '%s' (expected '%s')\n", newurl, untouchedA); + + /* NULL as parameter. The length and the buffer are not modified */ + lstrcpyA(newurl, untouchedA); + len = TEST_APPLY_MAX_LENGTH; + res = UrlApplySchemeA(NULL, newurl, &len, TEST_APPLY[0].flags); + ok(res == E_INVALIDARG, "got HRESULT 0x%x (expected E_INVALIDARG)\n", res); + ok(len == TEST_APPLY_MAX_LENGTH, "got len %d\n", len); + ok(!lstrcmpA(newurl, untouchedA), "got '%s' (expected '%s')\n", newurl, untouchedA); + + len = TEST_APPLY_MAX_LENGTH; + res = UrlApplySchemeA(TEST_APPLY[0].url, NULL, &len, TEST_APPLY[0].flags); + ok(res == E_INVALIDARG, "got HRESULT 0x%x (expected E_INVALIDARG)\n", res); + ok(len == TEST_APPLY_MAX_LENGTH, "got len %d\n", len); + + lstrcpyA(newurl, untouchedA); + res = UrlApplySchemeA(TEST_APPLY[0].url, newurl, NULL, TEST_APPLY[0].flags); + ok(res == E_INVALIDARG, "got HRESULT 0x%x (expected E_INVALIDARG)\n", res); + ok(!lstrcmpA(newurl, untouchedA), "got '%s' (expected '%s')\n", newurl, untouchedA); + +} + +/* ########################### */ + static void hash_url(const char* szUrl) { LPCSTR szTestUrl = szUrl; @@ -441,19 +567,23 @@ static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectRe } -static void test_url_canonicalize(int index, const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl, BOOL todo) +static void test_url_canonicalize(int index, const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, HRESULT dwExpectReturnAlt, const char *szExpectUrl, BOOL todo) { CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH]; WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH]; LPWSTR wszUrl = GetWideString(szUrl); LPWSTR wszExpectUrl = GetWideString(szExpectUrl); LPWSTR wszConvertedUrl; + HRESULT ret; DWORD dwSize; dwSize = INTERNET_MAX_URL_LENGTH; ok(UrlCanonicalizeA(szUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer, index %d\n", index); - ok(UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeA didn't return 0x%08x, index %d\n", dwExpectReturn, index); + ret = UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags); + ok(ret == dwExpectReturn || ret == dwExpectReturnAlt, + "UrlCanonicalizeA failed: expected=0x%08x or 0x%08x, got=0x%08x, index %d\n", + dwExpectReturn, dwExpectReturnAlt, ret, index); if (todo) todo_wine ok(strcmp(szReturnUrl,szExpectUrl)==0, "UrlCanonicalizeA dwFlags 0x%08x url '%s' Expected \"%s\", but got \"%s\", index %d\n", dwFlags, szUrl, szExpectUrl, szReturnUrl, index); @@ -562,11 +692,12 @@ static void test_UrlCanonicalizeA(void) "got 0x%x with %u and size %u for '%s' and %u (expected 'S_OK' and size %u)\n", hr, GetLastError(), dwSize, szReturnUrl, lstrlenA(szReturnUrl), urllen); + test_url_canonicalize(-1, "", 0, S_OK, S_FALSE /* Vista/win2k8 */, "", FALSE); /* test url-modification */ for(i=0; i + . + + util.c + testlist.c + wine + snmpapi + ntdll + diff --git a/rostests/winetests/snmpapi/testlist.c b/rostests/winetests/snmpapi/testlist.c new file mode 100644 index 00000000000..a329488a0cc --- /dev/null +++ b/rostests/winetests/snmpapi/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_util(void); + +const struct test winetest_testlist[] = +{ + { "util", func_util }, + { 0, 0 } +}; diff --git a/rostests/winetests/snmpapi/util.c b/rostests/winetests/snmpapi/util.c new file mode 100644 index 00000000000..64c75010445 --- /dev/null +++ b/rostests/winetests/snmpapi/util.c @@ -0,0 +1,579 @@ +/* + * Copyright 2007 Hans Leidekker + * + * 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 + */ + +#include + +#include + +#include +#include + +static INT (WINAPI *pSnmpUtilAsnAnyCpy)(AsnAny*, AsnAny*); +static VOID (WINAPI *pSnmpUtilAsnAnyFree)(AsnAny*); +static INT (WINAPI *pSnmpUtilOctetsCmp)(AsnOctetString*, AsnOctetString*); +static INT (WINAPI *pSnmpUtilOctetsCpy)(AsnOctetString*, AsnOctetString*); +static VOID (WINAPI *pSnmpUtilOctetsFree)(AsnOctetString*); +static INT (WINAPI *pSnmpUtilOctetsNCmp)(AsnOctetString*, AsnOctetString*, UINT); + +static void InitFunctionPtrs(void) +{ + HMODULE hSnmpapi = GetModuleHandle("snmpapi.dll"); + +#define SNMPAPI_GET_PROC(func) \ + p ## func = (void*)GetProcAddress(hSnmpapi, #func); \ + if(!p ## func) \ + trace("GetProcAddress(%s) failed\n", #func); + + SNMPAPI_GET_PROC(SnmpUtilAsnAnyCpy) + SNMPAPI_GET_PROC(SnmpUtilAsnAnyFree) + SNMPAPI_GET_PROC(SnmpUtilOctetsCmp) + SNMPAPI_GET_PROC(SnmpUtilOctetsCpy) + SNMPAPI_GET_PROC(SnmpUtilOctetsFree) + SNMPAPI_GET_PROC(SnmpUtilOctetsNCmp) + +#undef SNMPAPI_GET_PROC +} + +static void test_SnmpUtilOidToA(void) +{ + LPSTR ret; + static UINT ids1[] = { 1,3,6,1,4,1,311 }; + static UINT ids2[] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }; + static UINT ids3[] = { 0xffffffff }; + static AsnObjectIdentifier oid0 = { 0, ids1 }; + static AsnObjectIdentifier oid1 = { 7, ids1 }; + static AsnObjectIdentifier oid2 = { 256, ids2 }; + static AsnObjectIdentifier oid3 = { 257, ids2 }; + static AsnObjectIdentifier oid4 = { 258, ids2 }; + static AsnObjectIdentifier oid5 = { 1, ids3 }; + static const char expect0[] = ""; + static const char expect0_alt[] = "NUL"; + static const char expect1[] = "1.3.6.1.4.1.311"; + static const char expect2[] = + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1"; + static const char expect3[] = + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1"; + static const char expect3_alt[] = + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1." + "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1"; + static const char expect4[] = "-1"; + + /* This crashes under win98 */ + if(0) + { + ret = SnmpUtilOidToA(NULL); + ok(ret != NULL, "SnmpUtilOidToA failed\n"); + ok(!strcmp(ret, expect0), "SnmpUtilOidToA failed got\n%s\n expected\n%s\n", + ret, expect1); + } + + ret = SnmpUtilOidToA(&oid0); + ok(ret != NULL, "SnmpUtilOidToA failed\n"); + ok(!strcmp(ret, expect0) || + broken(!strcmp(ret, expect0_alt)), /* Win98, WinMe, NT4 */ + "SnmpUtilOidToA failed got\n%s\n expected\n%s\n", + ret, expect0); + + ret = SnmpUtilOidToA(&oid1); + ok(ret != NULL, "SnmpUtilOidToA failed\n"); + ok(!strcmp(ret, expect1), "SnmpUtilOidToA failed got\n%s\n expected\n%s\n", + ret, expect1); + + ret = SnmpUtilOidToA(&oid2); + ok(ret != NULL, "SnmpUtilOidToA failed\n"); + ok(!strcmp(ret, expect2), "SnmpUtilOidToA failed got\n%s\n expected\n%s\n", + ret, expect2); + + ret = SnmpUtilOidToA(&oid3); + ok(ret != NULL, "SnmpUtilOidToA failed\n"); + ok(!strcmp(ret, expect3), "SnmpUtilOidToA failed got\n%s\n expected\n%s\n", + ret, expect3); + + ret = SnmpUtilOidToA(&oid4); + ok(ret != NULL, "SnmpUtilOidToA failed\n"); + ok(!strcmp(ret, expect3) || + broken(!strcmp(ret, expect3_alt)), /* Win98, WinMe, NT4 */ + "SnmpUtilOidToA failed got\n%s\n expected\n%s\n", + ret, expect3); + + ret = SnmpUtilOidToA(&oid5); + ok(ret != NULL, "SnmpUtilOidToA failed\n"); + ok(!strcmp(ret, expect4), "SnmpUtilOidToA failed got\n%s\n expected\n%s\n", + ret, expect4); +} + +static void test_SnmpUtilAsnAnyCpyFree(void) +{ + INT ret; + static AsnAny dst, src = { ASN_INTEGER, { 1 } }; + + if (0) { /* these crash on XP */ + ret = pSnmpUtilAsnAnyCpy(NULL, NULL); + ok(!ret, "SnmpUtilAsnAnyCpy succeeded\n"); + + ret = pSnmpUtilAsnAnyCpy(&dst, NULL); + ok(!ret, "SnmpUtilAsnAnyCpy succeeded\n"); + + ret = pSnmpUtilAsnAnyCpy(NULL, &src); + ok(!ret, "SnmpUtilAsnAnyCpy succeeded\n"); + } + + ret = pSnmpUtilAsnAnyCpy(&dst, &src); + ok(ret, "SnmpUtilAsnAnyCpy failed\n"); + ok(!memcmp(&src, &dst, sizeof(AsnAny)), "SnmpUtilAsnAnyCpy failed\n"); + + if (0) { /* crashes on XP */ + pSnmpUtilAsnAnyFree(NULL); + } + pSnmpUtilAsnAnyFree(&dst); + ok(dst.asnType == ASN_NULL, "SnmpUtilAsnAnyFree failed\n"); + ok(dst.asnValue.number == 1, "SnmpUtilAsnAnyFree failed\n"); +} + +static void test_SnmpUtilOctetsCpyFree(void) +{ + INT ret; + static BYTE stream[] = { '1', '2', '3', '4' }; + static AsnOctetString dst, src = { stream, 4, TRUE }; + + ret = pSnmpUtilOctetsCpy(NULL, NULL); + ok(!ret, "SnmpUtilOctetsCpy succeeded\n"); + + memset(&dst, 1, sizeof(AsnOctetString)); + ret = pSnmpUtilOctetsCpy(&dst, NULL); + ok(ret, "SnmpUtilOctetsCpy failed\n"); + ok(dst.length == 0, "SnmpUtilOctetsCpy failed\n"); + ok(dst.stream == NULL, "SnmpUtilOctetsCpy failed\n"); + ok(dst.dynamic == FALSE, "SnmpUtilOctetsCpy failed\n"); + + ret = pSnmpUtilOctetsCpy(NULL, &src); + ok(!ret, "SnmpUtilOctetsCpy succeeded\n"); + + memset(&dst, 0, sizeof(AsnOctetString)); + ret = pSnmpUtilOctetsCpy(&dst, &src); + ok(ret, "SnmpUtilOctetsCpy failed\n"); + ok(src.length == dst.length, "SnmpUtilOctetsCpy failed\n"); + ok(!memcmp(src.stream, dst.stream, dst.length), "SnmpUtilOctetsCpy failed\n"); + ok(dst.dynamic == TRUE, "SnmpUtilOctetsCpy failed\n"); + + pSnmpUtilOctetsFree(NULL); + pSnmpUtilOctetsFree(&dst); + ok(dst.stream == NULL, "SnmpUtilOctetsFree failed\n"); + ok(dst.length == 0, "SnmpUtilOctetsFree failed\n"); + ok(dst.dynamic == FALSE, "SnmpUtilOctetsFree failed\n"); +} + +static void test_SnmpUtilOidCpyFree(void) +{ + INT ret; + static UINT ids[] = { 1, 3, 6, 1, 4, 1, 311 }; + static AsnObjectIdentifier dst, src = { sizeof(ids) / sizeof(ids[0]), ids }; + + /* These crashes under win98 */ + if(0) + { + ret = SnmpUtilOidCpy(NULL, NULL); + ok(!ret, "SnmpUtilOidCpy succeeded\n"); + + memset(&dst, 1, sizeof(AsnObjectIdentifier)); + ret = SnmpUtilOidCpy(&dst, NULL); + ok(ret, "SnmpUtilOidCpy failed\n"); + ok(dst.idLength == 0, "SnmpUtilOidCpy failed\n"); + ok(dst.ids == NULL, "SnmpUtilOidCpy failed\n"); + + ret = SnmpUtilOidCpy(NULL, &src); + ok(!ret, "SnmpUtilOidCpy succeeded\n"); + } + + memset(&dst, 0, sizeof(AsnObjectIdentifier)); + ret = SnmpUtilOidCpy(&dst, &src); + ok(ret, "SnmpUtilOidCpy failed\n"); + ok(src.idLength == dst.idLength, "SnmpUtilOidCpy failed\n"); + ok(!memcmp(src.ids, dst.ids, dst.idLength * sizeof(UINT)), "SnmpUtilOidCpy failed\n"); + SnmpUtilOidFree(&dst); + + /* These crashes under win98 */ + if(0) + { + ret = SnmpUtilOidCpy(NULL, NULL); + ok(!ret, "SnmpUtilOidCpy succeeded\n"); + + memset(&dst, 1, sizeof(AsnObjectIdentifier)); + ret = SnmpUtilOidCpy(&dst, NULL); + ok(ret, "SnmpUtilOidCpy failed\n"); + ok(dst.idLength == 0, "SnmpUtilOidCpy failed\n"); + ok(dst.ids == NULL, "SnmpUtilOidCpy failed\n"); + + ret = SnmpUtilOidCpy(NULL, &src); + ok(!ret, "SnmpUtilOidCpy succeeded\n"); + } + + memset(&dst, 0, sizeof(AsnObjectIdentifier)); + ret = SnmpUtilOidCpy(&dst, &src); + ok(ret, "SnmpUtilOidCpy failed\n"); + ok(src.idLength == dst.idLength, "SnmpUtilOidCpy failed\n"); + ok(!memcmp(src.ids, dst.ids, dst.idLength * sizeof(UINT)), "SnmpUtilOidCpy failed\n"); + + /* This crashes under win98 */ + if(0) + { + SnmpUtilOidFree(NULL); + } + SnmpUtilOidFree(&dst); + ok(dst.idLength == 0, "SnmpUtilOidFree failed\n"); + ok(dst.ids == NULL, "SnmpUtilOidFree failed\n"); +} + +static void test_SnmpUtilOctetsNCmp(void) +{ + INT ret; + static BYTE stream1[] = { '1', '2', '3', '4' }; + static BYTE stream2[] = { '5', '6', '7', '8' }; + static AsnOctetString octets1 = { stream1, 4, FALSE }; + static AsnOctetString octets2 = { stream2, 4, FALSE }; + + ret = pSnmpUtilOctetsNCmp(NULL, NULL, 0); + ok(!ret, "SnmpUtilOctetsNCmp succeeded\n"); + + ret = pSnmpUtilOctetsNCmp(NULL, NULL, 1); + ok(!ret, "SnmpUtilOctetsNCmp succeeded\n"); + + ret = pSnmpUtilOctetsNCmp(&octets1, NULL, 0); + ok(!ret, "SnmpUtilOctetsNCmp succeeded\n"); + + ret = pSnmpUtilOctetsNCmp(&octets1, NULL, 1); + ok(!ret, "SnmpUtilOctetsNCmp succeeded\n"); + + ret = pSnmpUtilOctetsNCmp(NULL, &octets2, 0); + ok(!ret, "SnmpUtilOctetsNCmp succeeded\n"); + + ret = pSnmpUtilOctetsNCmp(NULL, &octets2, 1); + ok(!ret, "SnmpUtilOctetsNCmp succeeded\n"); + + ret = pSnmpUtilOctetsNCmp(&octets1, &octets1, 0); + ok(!ret, "SnmpUtilOctetsNCmp failed\n"); + + ret = pSnmpUtilOctetsNCmp(&octets1, &octets1, 4); + ok(!ret, "SnmpUtilOctetsNCmp failed\n"); + + ret = pSnmpUtilOctetsNCmp(&octets1, &octets2, 4); + ok(ret == -4, "SnmpUtilOctetsNCmp failed\n"); + + ret = pSnmpUtilOctetsNCmp(&octets2, &octets1, 4); + ok(ret == 4, "SnmpUtilOctetsNCmp failed\n"); +} + +static void test_SnmpUtilOctetsCmp(void) +{ + INT ret; + static BYTE stream1[] = { '1', '2', '3' }; + static BYTE stream2[] = { '1', '2', '3', '4' }; + static AsnOctetString octets1 = { stream1, 3, FALSE }; + static AsnOctetString octets2 = { stream2, 4, FALSE }; + + if (0) { /* these crash on XP */ + ret = pSnmpUtilOctetsCmp(NULL, NULL); + ok(!ret, "SnmpUtilOctetsCmp succeeded\n"); + + ret = pSnmpUtilOctetsCmp(&octets1, NULL); + ok(!ret, "SnmpUtilOctetsCmp succeeded\n"); + + ret = pSnmpUtilOctetsCmp(NULL, &octets2); + ok(!ret, "SnmpUtilOctetsCmp succeeded\n"); + } + + ret = pSnmpUtilOctetsCmp(&octets2, &octets1); + ok(ret == 1, "SnmpUtilOctetsCmp failed\n"); + + ret = pSnmpUtilOctetsCmp(&octets1, &octets2); + ok(ret < 0, "SnmpUtilOctetsCmp failed\n"); +} + +static void test_SnmpUtilOidNCmp(void) +{ + INT ret; + static UINT ids1[] = { 1, 2, 3, 4 }; + static UINT ids2[] = { 5, 6, 7, 8 }; + static AsnObjectIdentifier oid1 = { 4, ids1 }; + static AsnObjectIdentifier oid2 = { 4, ids2 }; + + /* This crashes under win98 */ + if(0) + { + ret = SnmpUtilOidNCmp(NULL, NULL, 0); + ok(!ret, "SnmpUtilOidNCmp succeeded\n"); + + ret = SnmpUtilOidNCmp(NULL, NULL, 1); + ok(!ret, "SnmpUtilOidNCmp succeeded\n"); + + ret = SnmpUtilOidNCmp(&oid1, NULL, 0); + ok(!ret, "SnmpUtilOidNCmp succeeded\n"); + + ret = SnmpUtilOidNCmp(&oid1, NULL, 1); + ok(!ret, "SnmpUtilOidNCmp succeeded\n"); + + ret = SnmpUtilOidNCmp(NULL, &oid2, 0); + ok(!ret, "SnmpUtilOidNCmp succeeded\n"); + + ret = SnmpUtilOidNCmp(NULL, &oid2, 1); + ok(!ret, "SnmpUtilOidNCmp succeeded\n"); + } + + ret = SnmpUtilOidNCmp(&oid1, &oid1, 0); + ok(!ret, "SnmpUtilOidNCmp failed\n"); + + ret = SnmpUtilOidNCmp(&oid1, &oid1, 4); + ok(!ret, "SnmpUtilOidNCmp failed\n"); + + ret = SnmpUtilOidNCmp(&oid1, &oid2, 4); + ok(ret < 0, "SnmpUtilOidNCmp failed: %d\n", ret); + + ret = SnmpUtilOidNCmp(&oid2, &oid1, 4); + ok(ret > 0, "SnmpUtilOidNCmp failed: %d\n", ret); + + oid1.idLength = 3; + memcpy(oid1.ids, oid2.ids, sizeof(UINT) * 4); + ret = SnmpUtilOidNCmp(&oid1, &oid1, 4); + ok(!ret, "SnmpUtilOidNCmp failed: %d\n", ret); + ret = SnmpUtilOidNCmp(&oid2, &oid1, 4); + ok(ret > 0, "SnmpUtilOidNCmp failed: %d\n", ret); + ret = SnmpUtilOidNCmp(&oid1, &oid2, 4); + ok(ret < 0, "SnmpUtilOidNCmp failed: %d\n", ret); + + ret = SnmpUtilOidNCmp(&oid1, &oid2, 2); + ok(!ret, "SnmpUtilOidNCmp failed: %d\n", ret); + ret = SnmpUtilOidNCmp(&oid2, &oid1, 2); + ok(!ret, "SnmpUtilOidNCmp failed: %d\n", ret); +} + +static void test_SnmpUtilOidCmp(void) +{ + INT ret; + static UINT ids1[] = { 1, 2, 3 }; + static UINT ids2[] = { 1, 2, 3, 4 }; + static AsnObjectIdentifier oid1 = { 3, ids1 }; + static AsnObjectIdentifier oid2 = { 4, ids2 }; + + if (0) { /* these crash on XP */ + ret = SnmpUtilOidCmp(NULL, NULL); + ok(!ret, "SnmpUtilOidCmp succeeded\n"); + + ret = SnmpUtilOidCmp(&oid1, NULL); + ok(!ret, "SnmpUtilOidCmp succeeded\n"); + + ret = SnmpUtilOidCmp(NULL, &oid2); + ok(!ret, "SnmpUtilOidCmp succeeded\n"); + } + + ret = SnmpUtilOidCmp(&oid2, &oid1); + ok(ret > 0, "SnmpUtilOidCmp failed\n"); + + ret = SnmpUtilOidCmp(&oid1, &oid2); + ok(ret < 0, "SnmpUtilOidCmp failed\n"); +} + +static void test_SnmpUtilOidAppend(void) +{ + INT ret; + UINT *ids1; + static UINT ids2[] = { 4, 5, 6 }; + static AsnObjectIdentifier oid1; + static AsnObjectIdentifier oid2 = { 3, ids2 }; + + ids1 = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(UINT)); + ids1[0] = 1; + ids1[1] = 2; + ids1[2] = 3; + + oid1.idLength = 3; + oid1.ids = ids1; + + /* This crashes under win98 */ + if(0) + { + ret = SnmpUtilOidAppend(NULL, NULL); + ok(!ret, "SnmpUtilOidAppend succeeded\n"); + + ret = SnmpUtilOidAppend(&oid1, NULL); + ok(ret, "SnmpUtilOidAppend failed\n"); + + ret = SnmpUtilOidAppend(NULL, &oid2); + ok(!ret, "SnmpUtilOidAppend succeeded\n"); + } + + ret = SnmpUtilOidAppend(&oid1, &oid2); + ok(ret, "SnmpUtilOidAppend failed\n"); + ok(oid1.idLength == 6, "SnmpUtilOidAppend failed\n"); + ok(!memcmp(&oid1.ids[3], ids2, 3 * sizeof(UINT)), + "SnmpUtilOidAppend failed\n"); + + HeapFree(GetProcessHeap(), 0, ids1); +} + +static void test_SnmpUtilVarBindCpyFree(void) +{ + INT ret; + static UINT ids[] = { 1, 3, 6, 1, 4, 1, 311 }; + static SnmpVarBind dst, src = { { 7, ids }, { ASN_INTEGER, { 1 } } }; + + /* This crashes under win98 */ + if(0) + { + ret = SnmpUtilVarBindCpy(NULL, NULL); + ok(!ret, "SnmpUtilVarBindCpy succeeded\n"); + + memset(&dst, 0, sizeof(SnmpVarBind)); + ret = SnmpUtilVarBindCpy(&dst, NULL); + ok(ret, "SnmpUtilVarBindCpy failed\n"); + ok(dst.name.idLength == 0, "SnmpUtilVarBindCpy failed\n"); + ok(dst.name.ids == NULL, "SnmpUtilVarBindCpy failed\n"); + ok(dst.value.asnType == ASN_NULL, "SnmpUtilVarBindCpy failed\n"); + ok(dst.value.asnValue.number == 0, "SnmpUtilVarBindCpy failed\n"); + + ret = SnmpUtilVarBindCpy(NULL, &src); + ok(!ret, "SnmpUtilVarBindCpy succeeded\n"); + } + + memset(&dst, 0, sizeof(SnmpVarBind)); + ret = SnmpUtilVarBindCpy(&dst, &src); + ok(ret, "SnmpUtilVarBindCpy failed\n"); + ok(src.name.idLength == dst.name.idLength, "SnmpUtilVarBindCpy failed\n"); + ok(!memcmp(src.name.ids, dst.name.ids, dst.name.idLength * sizeof(UINT)), + "SnmpUtilVarBindCpy failed\n"); + ok(!memcmp(&src.value, &dst.value, sizeof(AsnObjectSyntax)), + "SnmpUtilVarBindCpy failed\n"); + + /* This crashes under win98 */ + if(0) + { + SnmpUtilVarBindFree(NULL); + } + SnmpUtilVarBindFree(&dst); + ok(dst.name.idLength == 0, "SnmpUtilVarBindFree failed\n"); + ok(dst.name.ids == NULL, "SnmpUtilVarBindFree failed\n"); + ok(dst.value.asnType == ASN_NULL, "SnmpUtilVarBindFree failed\n"); + ok(dst.value.asnValue.number == 1, "SnmpUtilVarBindFree failed\n"); +} + +static void test_SnmpUtilVarBindListCpyFree(void) +{ + INT ret; + static UINT ids[] = { 1, 3, 6, 1, 4, 1, 311 }; + static SnmpVarBind src = { { 7, ids }, { ASN_INTEGER, { 1 } } }; + static SnmpVarBindList dst_list, src_list = { &src, 1 }; + + if (0) { /* these crash on XP */ + ret = SnmpUtilVarBindListCpy(NULL, NULL); + ok(!ret, "SnmpUtilVarBindCpy succeeded\n"); + + ret = SnmpUtilVarBindListCpy(NULL, &src_list); + ok(!ret, "SnmpUtilVarBindListCpy succeeded\n"); + } + + /* This crashes under win98 */ + if(0) + { + memset(&dst_list, 0xff, sizeof(SnmpVarBindList)); + ret = SnmpUtilVarBindListCpy(&dst_list, NULL); + ok(ret, "SnmpUtilVarBindListCpy failed\n"); + ok(dst_list.list == NULL, "SnmpUtilVarBindListCpy failed\n"); + ok(dst_list.len == 0, "SnmpUtilVarBindListCpy failed\n"); + } + + ret = SnmpUtilVarBindListCpy(&dst_list, &src_list); + ok(ret, "SnmpUtilVarBindListCpy failed\n"); + ok(src_list.len == dst_list.len, "SnmpUtilVarBindListCpy failed\n"); + ok(src_list.list->name.idLength == dst_list.list->name.idLength, + "SnmpUtilVarBindListCpy failed\n"); + ok(!memcmp(src_list.list->name.ids, dst_list.list->name.ids, + dst_list.list->name.idLength * sizeof(UINT)), + "SnmpUtilVarBindListCpy failed\n"); + ok(!memcmp(&src_list.list->value, &dst_list.list->value, sizeof(AsnAny)), + "SnmpUtilVarBindListCpy failed\n"); + + if (0) { /* crashes on XP */ + SnmpUtilVarBindListFree(NULL); + } + SnmpUtilVarBindListFree(&dst_list); + ok(dst_list.list == NULL, "SnmpUtilVarBindListFree failed\n"); + ok(dst_list.len == 0, "SnmpUtilVarBindListFree failed\n"); +} + +START_TEST(util) +{ + InitFunctionPtrs(); + + test_SnmpUtilOidToA(); + + if (!pSnmpUtilAsnAnyCpy || !pSnmpUtilAsnAnyFree) + win_skip("SnmpUtilAsnAnyCpy and/or SnmpUtilAsnAnyFree not available\n"); + else + test_SnmpUtilAsnAnyCpyFree(); + + if (!pSnmpUtilOctetsCpy || !pSnmpUtilOctetsFree) + win_skip("SnmpUtilOctetsCpy and/or SnmpUtilOctetsFree not available\n"); + else + test_SnmpUtilOctetsCpyFree(); + + test_SnmpUtilOidCpyFree(); + + if (!pSnmpUtilOctetsNCmp) + win_skip("SnmpUtilOctetsNCmp not available\n"); + else + test_SnmpUtilOctetsNCmp(); + + if (!pSnmpUtilOctetsCmp) + win_skip("SnmpUtilOctetsCmp not available\n"); + else + test_SnmpUtilOctetsCmp(); + + test_SnmpUtilOidCmp(); + test_SnmpUtilOidNCmp(); + test_SnmpUtilOidAppend(); + test_SnmpUtilVarBindCpyFree(); + test_SnmpUtilVarBindListCpyFree(); +} diff --git a/rostests/winetests/spoolss/spoolss.c b/rostests/winetests/spoolss/spoolss.c new file mode 100644 index 00000000000..6a2711e1752 --- /dev/null +++ b/rostests/winetests/spoolss/spoolss.c @@ -0,0 +1,211 @@ +/* + * Unit test suite for the Spooler-Service helper DLL + * + * Copyright 2007 Detlef Riekenberg + * + * 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 + * + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/test.h" + + + +/* ##### */ + +static HMODULE hwinspool; + +static HMODULE hspl; +static BOOL (WINAPI * pBuildOtherNamesFromMachineName)(LPWSTR **, LPDWORD); +static DWORD (WINAPI * pSplInitializeWinSpoolDrv)(LPVOID *); + +#define WINSPOOL_TABLESIZE 16 + +static LPVOID fn_spl[WINSPOOL_TABLESIZE]; +static LPVOID fn_w2k[WINSPOOL_TABLESIZE]; +static LPVOID fn_xp[WINSPOOL_TABLESIZE]; +static LPVOID fn_v[WINSPOOL_TABLESIZE]; + +/* ########################### */ + +static LPCSTR load_functions(void) +{ + LPCSTR ptr; + + ptr = "spoolss.dll"; + hspl = LoadLibraryA(ptr); + if (!hspl) return ptr; + + ptr = "BuildOtherNamesFromMachineName"; + pBuildOtherNamesFromMachineName = (void *) GetProcAddress(hspl, ptr); + if (!pBuildOtherNamesFromMachineName) return ptr; + + ptr = "SplInitializeWinSpoolDrv"; + pSplInitializeWinSpoolDrv = (void *) GetProcAddress(hspl, ptr); + if (!pSplInitializeWinSpoolDrv) return ptr; + + + ptr = "winspool.drv"; + hwinspool = LoadLibraryA(ptr); + if (!hwinspool) return ptr; + + memset(fn_w2k, 0xff, sizeof(fn_w2k)); + fn_w2k[0] = (void *) GetProcAddress(hwinspool, "OpenPrinterW"); + fn_w2k[1] = (void *) GetProcAddress(hwinspool, "ClosePrinter"); + fn_w2k[2] = (void *) GetProcAddress(hwinspool, "SpoolerDevQueryPrintW"); + fn_w2k[3] = (void *) GetProcAddress(hwinspool, "SpoolerPrinterEvent"); + fn_w2k[4] = (void *) GetProcAddress(hwinspool, "DocumentPropertiesW"); + fn_w2k[5] = (void *) GetProcAddress(hwinspool, (LPSTR) 212); /* LoadPrinterDriver */ + fn_w2k[6] = (void *) GetProcAddress(hwinspool, "SetDefaultPrinterW"); + fn_w2k[7] = (void *) GetProcAddress(hwinspool, "GetDefaultPrinterW"); + fn_w2k[8] = (void *) GetProcAddress(hwinspool, (LPSTR) 213); /* RefCntLoadDriver */ + fn_w2k[9] = (void *) GetProcAddress(hwinspool, (LPSTR) 214); /* RefCntUnloadDriver */ + fn_w2k[10] = (void *) GetProcAddress(hwinspool, (LPSTR) 215); /* ForceUnloadDriver */ + + memset(fn_xp, 0xff, sizeof(fn_xp)); + fn_xp[0] = (void *) GetProcAddress(hwinspool, "OpenPrinterW"); + fn_xp[1] = (void *) GetProcAddress(hwinspool, "ClosePrinter"); + fn_xp[2] = (void *) GetProcAddress(hwinspool, "SpoolerDevQueryPrintW"); + fn_xp[3] = (void *) GetProcAddress(hwinspool, "SpoolerPrinterEvent"); + fn_xp[4] = (void *) GetProcAddress(hwinspool, "DocumentPropertiesW"); + fn_xp[5] = (void *) GetProcAddress(hwinspool, (LPSTR) 212); /* LoadPrinterDriver */ + fn_xp[6] = (void *) GetProcAddress(hwinspool, (LPSTR) 213); /* RefCntLoadDriver */ + fn_xp[7] = (void *) GetProcAddress(hwinspool, (LPSTR) 214); /* RefCntUnloadDriver */ + fn_xp[8] = (void *) GetProcAddress(hwinspool, (LPSTR) 215); /* ForceUnloadDriver */ + + memset(fn_v, 0xff, sizeof(fn_v)); + fn_v[0] = (void *) GetProcAddress(hwinspool, "OpenPrinterW"); + fn_v[1] = (void *) GetProcAddress(hwinspool, "ClosePrinter"); + fn_v[2] = (void *) GetProcAddress(hwinspool, "SpoolerDevQueryPrintW"); + fn_v[3] = (void *) GetProcAddress(hwinspool, "SpoolerPrinterEvent"); + fn_v[4] = (void *) GetProcAddress(hwinspool, "DocumentPropertiesW"); + fn_v[5] = (void *) GetProcAddress(hwinspool, (LPSTR) 212); /* LoadPrinterDriver */ + fn_v[6] = (void *) GetProcAddress(hwinspool, (LPSTR) 213); /* RefCntLoadDriver */ + fn_v[7] = (void *) GetProcAddress(hwinspool, (LPSTR) 214); /* RefCntUnloadDriver */ + fn_v[8] = (void *) GetProcAddress(hwinspool, (LPSTR) 215); /* ForceUnloadDriver */ + fn_v[9] = (void *) GetProcAddress(hwinspool, (LPSTR) 251); /* 0xfb */ + + return NULL; + +} + +/* ########################### */ + +static void test_BuildOtherNamesFromMachineName(void) +{ + LPWSTR *buffers; + DWORD numentries; + DWORD res; + + buffers = NULL; + numentries = 0; + + SetLastError(0xdeadbeef); + res = pBuildOtherNamesFromMachineName(&buffers, &numentries); + + /* An array with a number of stringpointers is returned (minimum of 3): + entry_#0: "" (empty String) + entry_#1: (this is the same as the computername) + 1 entry per Ethernet adapter : (string with a IPv4 ip-address) + + As of Vista: + + IPv6 fully disabled (lan interfaces, connections, tunnel interfaces and loopback interfaces) + entry_#0: "" (empty String) + entry_#1: (this is the same as the computername) + 1 entry per Ethernet adapter : (string with a IPv4 ip-address) + entry_#x: "::1" + + IPv6 partly disabled (lan interfaces, connections): + entry_#0: "" (empty String) + entry_#1: (this is the same as the computername) + entry_#2: "::1" + 1 entry per Ethernet adapter : (string with a IPv4 ip-address) + + IPv6 fully enabled but not on all lan interfaces: + entry_#0: "" (empty String) + entry_#1: (this is the same as the computername) + 1 entry per IPv6 enabled Ethernet adapter : (string with a Link-local IPv6 ip-address) + 1 entry per IPv4 enabled Ethernet adapter : (string with a IPv4 ip-address) + + IPv6 fully enabled on all lan interfaces: + entry_#0: "" (empty String) + entry_#1: (this is the same as the computername) + 1 entry per IPv6 enabled Ethernet adapter : (string with a Link-local IPv6 ip-address) + entry_#x: Tunnel adapter (string with a Link-local IPv6 ip-address) + 1 entry per IPv4 enabled Ethernet adapter : (string with a IPv4 ip-address) + entry_#y: Tunnel adapter (string with a IPv6 ip-address) + */ + + todo_wine + ok( res && (buffers != NULL) && (numentries >= 3) && (buffers[0] != NULL) && (buffers[0][0] == '\0'), + "got %u with %u and %p,%u (%p:%d)\n", res, GetLastError(), buffers, numentries, + ((numentries > 0) && buffers) ? buffers[0] : NULL, + ((numentries > 0) && buffers && buffers[0]) ? lstrlenW(buffers[0]) : -1); + +} + +/* ########################### */ + +static void test_SplInitializeWinSpoolDrv(VOID) +{ + LPVOID *fn_ref = fn_xp; + DWORD res; + LONG id; + + memset(fn_spl, 0xff, sizeof(fn_spl)); + SetLastError(0xdeadbeef); + res = pSplInitializeWinSpoolDrv(fn_spl); + ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError()); + + /* functions 0 to 5 are the same in "spoolss.dll" from w2k and above */ + if (fn_spl[6] == fn_w2k[6]) { + fn_ref = fn_w2k; + } + if (fn_spl[9] == fn_v[9]) { + fn_ref = fn_v; + } + + id = 0; + while (id < WINSPOOL_TABLESIZE) { + ok( fn_spl[id] == fn_ref[id], + "(#%02u) spoolss: %p (vista: %p, xp: %p, w2k: %p)\n", + id, fn_spl[id], fn_v[id], fn_xp[id], fn_w2k[id]); + id++; + } +} + +/* ########################### */ + +START_TEST(spoolss) +{ + LPCSTR ptr; + + /* spoolss.dll does not exist on win9x */ + ptr = load_functions(); + if (ptr) { + skip("%s not found\n", ptr); + return; + } + + test_BuildOtherNamesFromMachineName(); + test_SplInitializeWinSpoolDrv(); + +} diff --git a/rostests/winetests/spoolss/spoolss.rbuild b/rostests/winetests/spoolss/spoolss.rbuild new file mode 100644 index 00000000000..5747b731b3b --- /dev/null +++ b/rostests/winetests/spoolss/spoolss.rbuild @@ -0,0 +1,8 @@ + + . + + spoolss.c + testlist.c + wine + ntdll + diff --git a/rostests/winetests/spoolss/testlist.c b/rostests/winetests/spoolss/testlist.c new file mode 100644 index 00000000000..c0b8fe11f44 --- /dev/null +++ b/rostests/winetests/spoolss/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_spoolss(void); + +const struct test winetest_testlist[] = +{ + { "spoolss", func_spoolss }, + { 0, 0 } +}; diff --git a/rostests/winetests/twain_32/dsm.c b/rostests/winetests/twain_32/dsm.c new file mode 100644 index 00000000000..0cc82208e38 --- /dev/null +++ b/rostests/winetests/twain_32/dsm.c @@ -0,0 +1,871 @@ +/* Unit test suite for Twain DSM functions + * + * Copyright 2009 Jeremy White, CodeWeavers, Inc. + * + * 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 + * + */ +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winerror.h" +#include "winuser.h" +#include "twain.h" + +#include "wine/test.h" + +static DSMENTRYPROC pDSM_Entry; + +static BOOL dsm_RegisterWindowClasses(void) +{ + WNDCLASSA cls; + + cls.style = 0; + cls.lpfnWndProc = DefWindowProc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "TWAIN_dsm_class"; + if (!RegisterClassA(&cls)) return FALSE; + + return TRUE; +} + + +static void get_condition_code(TW_IDENTITY *appid, TW_IDENTITY *source, TW_STATUS *status) +{ + TW_UINT16 rc; + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_STATUS, MSG_GET, status); + ok(rc == TWRC_SUCCESS, "Condition code not available, rc %d\n", rc); +} + +static BOOL get_onevalue(TW_HANDLE hcontainer, TW_UINT32 *ret, TW_UINT16 *type) +{ + TW_ONEVALUE *onev; + onev = GlobalLock(hcontainer); + if (onev) + { + *ret = onev->Item; + if (type) + *type = onev->ItemType; + GlobalUnlock(hcontainer); + return TRUE; + } + return FALSE; +} + +static TW_HANDLE alloc_and_set_onevalue(TW_UINT32 val, TW_UINT16 type) +{ + TW_HANDLE hcontainer; + TW_ONEVALUE *onev; + hcontainer = GlobalAlloc(0, sizeof(*onev)); + if (hcontainer) + { + onev = GlobalLock(hcontainer); + if (onev) + { + onev->ItemType = type; + onev->Item = val; + GlobalUnlock(hcontainer); + } + else + { + GlobalFree(hcontainer); + hcontainer = 0; + } + } + return hcontainer; +} + +static void check_get(TW_CAPABILITY *pCapability, TW_INT32 actual_support, + TW_UINT32 orig_value, TW_UINT32 default_value, TW_UINT32 *suggested_set_value) +{ + void *p; + if (suggested_set_value) + *suggested_set_value = orig_value + 1; + p = GlobalLock(pCapability->hContainer); + if (p) + { + if (pCapability->ConType == TWON_ONEVALUE) + { + TW_ONEVALUE *onev = p; + ok(onev->Item == orig_value || !(actual_support & TWQC_GETCURRENT), "MSG_GET of 0x%x returned 0x%x, expecting 0x%x\n", + pCapability->Cap, onev->Item, orig_value); + trace("MSG_GET of 0x%x returned val 0x%x, type %d\n", pCapability->Cap, onev->Item, onev->ItemType); + if (suggested_set_value) + *suggested_set_value = onev->Item; + } + else if (pCapability->ConType == TWON_ENUMERATION) + { + int i; + TW_UINT8 *p8; + TW_UINT16 *p16; + TW_UINT32 *p32; + TW_ENUMERATION *enumv = p; + p8 = enumv->ItemList; + p16 = (TW_UINT16 *) p8; + p32 = (TW_UINT32 *) p8; + trace("MSG_GET of 0x%x returned %d items:\n", pCapability->Cap, enumv->NumItems); + for (i = 0; i < enumv->NumItems; i++) + { + if (enumv->ItemType == TWTY_UINT8 || enumv->ItemType == TWTY_INT8) + trace(" %d: 0x%x\n", i, p8[i]); + if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16) + trace(" %d: 0x%x\n", i, p16[i]); + if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32) + trace(" %d: 0x%x\n", i, p32[i]); + } + if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16) + { + ok(p16[enumv->CurrentIndex] == orig_value, + "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETCURRENT (0x%x) do not match.\n", + pCapability->Cap, p16[enumv->CurrentIndex], orig_value); + ok(p16[enumv->DefaultIndex] == default_value, + "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETDEFAULT (0x%x) do not match.\n", + pCapability->Cap, p16[enumv->DefaultIndex], default_value); + if (suggested_set_value) + *suggested_set_value = p16[(enumv->CurrentIndex + 1) % enumv->NumItems]; + } + if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32) + { + ok(p32[enumv->CurrentIndex] == orig_value, + "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETCURRENT (0x%x) do not match.\n", + pCapability->Cap, p32[enumv->CurrentIndex], orig_value); + ok(p32[enumv->DefaultIndex] == default_value, + "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETDEFAULT (0x%x) do not match.\n", + pCapability->Cap, p32[enumv->DefaultIndex], default_value); + if (suggested_set_value) + *suggested_set_value = p32[(enumv->CurrentIndex + 1) % enumv->NumItems]; + } + } + else + trace("MSG_GET on type 0x%x returned type 0x%x, which we didn't check.\n", pCapability->Cap, pCapability->ConType); + GlobalUnlock(pCapability->hContainer); + } +} + +static void test_onevalue_cap(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_UINT16 type, TW_INT32 minimum_support) +{ + TW_UINT16 rc; + TW_UINT16 rtype; + TW_STATUS status; + TW_CAPABILITY cap; + TW_UINT32 orig_value = 0; + TW_UINT32 new_value; + TW_UINT32 default_value = 0; + TW_INT32 actual_support; + + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc != TWRC_SUCCESS) + return; + ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype); + ok((actual_support & minimum_support) == minimum_support, + "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support, + captype, actual_support); + + + if (actual_support & TWQC_GETCURRENT) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + { + ok(get_onevalue(cap.hContainer, &orig_value, &rtype), "Returned cap.hContainer invalid for GETCURRENT on type 0x%x\n", captype); + ok(rtype == type, "Returned GETCURRENT type 0x%x for cap 0x%x is not expected 0x%x\n", rtype, captype, type); + GlobalFree(cap.hContainer); + } + } + + if (actual_support & TWQC_GETDEFAULT) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + { + ok(get_onevalue(cap.hContainer, &default_value, &rtype), "Returned cap.hContainer invalid for GETDEFAULT on type 0x%x\n", captype); + ok(rtype == type, "Returned GETDEFAULT type 0x%x for cap 0x%x is not expected 0x%x\n", rtype, captype, type); + GlobalFree(cap.hContainer); + } + } + + new_value = orig_value; + if (actual_support & TWQC_GET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype); + check_get(&cap, actual_support, orig_value, default_value, &new_value); + if (rc == TWRC_SUCCESS) + GlobalFree(cap.hContainer); + } + + if (actual_support & TWQC_SET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_ONEVALUE; + cap.hContainer = alloc_and_set_onevalue(new_value, type); + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype); + GlobalFree(cap.hContainer); + } + + if (actual_support & TWQC_RESET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + GlobalFree(cap.hContainer); + } +} + +static void test_resolution(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support) +{ + TW_UINT16 rc; + TW_STATUS status; + TW_CAPABILITY cap; + TW_UINT32 val; + TW_UINT16 type; + TW_INT32 actual_support; + TW_FIX32 orig_value = { 0, 0 }; + TW_UINT32 new_value = 0; + TW_FIX32 default_value = { 0, 0 }; + + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc != TWRC_SUCCESS) + return; + ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype); + ok((actual_support & minimum_support) == minimum_support, + "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support, + captype, actual_support); + + + if (actual_support & TWQC_GETCURRENT) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + { + get_onevalue(cap.hContainer, &val, &type); + ok(type == TWTY_FIX32, "GETCURRENT for RESOLUTION is not type FIX32, is type %d\n", type); + memcpy(&orig_value, &val, sizeof(orig_value)); + GlobalFree(cap.hContainer); + } + } + + if (actual_support & TWQC_GETDEFAULT) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + { + get_onevalue(cap.hContainer, &val, &type); + ok(type == TWTY_FIX32, "GETDEFAULT for RESOLUTION is not type FIX32, is type %d\n", type); + memcpy(&default_value, &val, sizeof(default_value)); + GlobalFree(cap.hContainer); + } + } + + if (actual_support & TWQC_GET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + { + TW_RANGE *range; + ok(cap.ConType == TWON_RANGE, "MSG_GET for ICAP_[XY]RESOLUTION did not return TWON_RANGE, but %d\n", cap.ConType); + range = GlobalLock(cap.hContainer); + trace("MSG_GET of 0x%x returned [ItemType %d|MinValue %d|MaxValue %d|StepSize %d|DefaultValue %d|CurrentValue %d]:\n", + cap.Cap, range->ItemType, range->MinValue, range->MaxValue, range->StepSize, + range->DefaultValue, range->CurrentValue); + for (new_value = range->MinValue; new_value < range->MaxValue; new_value += range->StepSize) + if (new_value != range->CurrentValue) + break; + GlobalUnlock(cap.hContainer); + GlobalFree(cap.hContainer); + } + } + + if (actual_support & TWQC_SET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_ONEVALUE; + cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_FIX32); + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype); + GlobalFree(cap.hContainer); + + } + + if (actual_support & TWQC_RESET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + GlobalFree(cap.hContainer); + } +} + +static void test_physical(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support) +{ + TW_UINT16 rc; + TW_STATUS status; + TW_CAPABILITY cap; + TW_UINT32 val; + TW_UINT16 type; + TW_INT32 actual_support; + + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc != TWRC_SUCCESS) + return; + ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype); + ok((actual_support & minimum_support) == minimum_support, + "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support, + captype, actual_support); + + + if (actual_support & TWQC_GETCURRENT) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + { + get_onevalue(cap.hContainer, &val, &type); + ok(type == TWTY_FIX32, "GETCURRENT for PHYSICALXXX is not type FIX32, is type %d\n", type); + GlobalFree(cap.hContainer); + } + } + + if (actual_support & TWQC_GETDEFAULT) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + { + get_onevalue(cap.hContainer, &val, &type); + ok(type == TWTY_FIX32, "GETDEFAULT for PHYSICALXXX is not type FIX32, is type %d\n", type); + GlobalFree(cap.hContainer); + } + } + + if (actual_support & TWQC_GET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = captype; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype); + if (rc == TWRC_SUCCESS) + { + get_onevalue(cap.hContainer, &val, &type); + ok(type == TWTY_FIX32, "GET for PHYSICALXXX is not type FIX32, is type %d\n", type); + trace("GET for Physical type 0x%x returns 0x%x\n", captype, val); + GlobalFree(cap.hContainer); + } + } + +} + +static void test_supported_sizes(TW_IDENTITY *appid, TW_IDENTITY *source, TW_INT32 minimum_support) +{ + TW_UINT16 rc; + TW_STATUS status; + TW_CAPABILITY cap; + TW_UINT32 val; + TW_UINT16 type; + TW_INT32 actual_support; + TW_UINT32 orig_value = TWSS_NONE; + TW_UINT32 default_value = TWSS_NONE; + TW_UINT32 new_value = TWSS_NONE; + + + memset(&cap, 0, sizeof(cap)); + cap.Cap = ICAP_SUPPORTEDSIZES; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode); + if (rc != TWRC_SUCCESS) + return; + ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on ICAP_SUPPORTEDSIZES\n"); + ok((actual_support & minimum_support) == minimum_support, + "Error: minimum support 0x%x for ICAP_SUPPORTEDSIZES, got 0x%x\n", minimum_support, actual_support); + + if (actual_support & TWQC_GETCURRENT) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = ICAP_SUPPORTEDSIZES; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GETCURRENT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode); + if (rc == TWRC_SUCCESS) + { + get_onevalue(cap.hContainer, &val, &type); + ok(type == TWTY_UINT16, "GETCURRENT for ICAP_SUPPORTEDSIZES is not type UINT16, is type %d\n", type); + trace("Current size is %d\n", val); + GlobalFree(cap.hContainer); + orig_value = val; + } + } + + if (actual_support & TWQC_GETDEFAULT) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = ICAP_SUPPORTEDSIZES; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GETDEFAULT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode); + if (rc == TWRC_SUCCESS) + { + get_onevalue(cap.hContainer, &val, &type); + ok(type == TWTY_UINT16, "GETDEFAULT for PHYSICALXXX is not type TWTY_UINT16, is type %d\n", type); + trace("Default size is %d\n", val); + GlobalFree(cap.hContainer); + default_value = val; + } + } + + if (actual_support & TWQC_GET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = ICAP_SUPPORTEDSIZES; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode); + check_get(&cap, actual_support, orig_value, default_value, &new_value); + } + + if (actual_support & TWQC_SET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = ICAP_SUPPORTEDSIZES; + cap.ConType = TWON_ONEVALUE; + cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_UINT16); + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_SET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode); + GlobalFree(cap.hContainer); + + } + + if (actual_support & TWQC_RESET) + { + memset(&cap, 0, sizeof(cap)); + cap.Cap = ICAP_SUPPORTEDSIZES; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_RESET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode); + if (rc == TWRC_SUCCESS) + GlobalFree(cap.hContainer); + } +} + +static void test_imagelayout(TW_IDENTITY *appid, TW_IDENTITY *source) +{ + TW_UINT16 rc; + TW_STATUS status; + TW_IMAGELAYOUT layout; + + rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_GET, &layout); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode); + if (rc != TWRC_SUCCESS) + return; + trace("ImageLayout [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x|Document %d|Page %d|Frame %d]\n", + layout.Frame.Left.Whole, layout.Frame.Left.Frac, + layout.Frame.Top.Whole, layout.Frame.Top.Frac, + layout.Frame.Right.Whole, layout.Frame.Right.Frac, + layout.Frame.Bottom.Whole, layout.Frame.Bottom.Frac, + layout.DocumentNumber, layout.PageNumber, layout.FrameNumber); + + memset(&layout, 0, sizeof(layout)); + layout.Frame.Left.Whole = 1; + layout.Frame.Right.Whole = 2; + layout.Frame.Top.Whole = 1; + layout.Frame.Bottom.Whole = 2; + rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_SET, &layout); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_SET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode); + if (rc != TWRC_SUCCESS) + return; + + rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_GET, &layout); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS, + "Error [rc %d|cc %d] doing MSG_GET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode); + if (rc != TWRC_SUCCESS) + return; + trace("ImageLayout after set [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x|Document %d|Page %d|Frame %d]\n", + layout.Frame.Left.Whole, layout.Frame.Left.Frac, + layout.Frame.Top.Whole, layout.Frame.Top.Frac, + layout.Frame.Right.Whole, layout.Frame.Right.Frac, + layout.Frame.Bottom.Whole, layout.Frame.Bottom.Frac, + layout.DocumentNumber, layout.PageNumber, layout.FrameNumber); +} + + +static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source) +{ + TW_UINT16 rc; + TW_STATUS status; + TW_CAPABILITY cap; + UINT16 capabilities[CAP_CUSTOMBASE]; + + memset(&cap, 0, sizeof(cap)); + cap.Cap = CAP_SUPPORTEDCAPS; + cap.ConType = TWON_DONTCARE16; + + rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap); + get_condition_code(appid, source, &status); + ok(rc == TWRC_SUCCESS || status.ConditionCode == TWCC_SUCCESS, + "Error obtaining CAP_SUPPORTEDCAPS\n"); + + memset(capabilities, 0, sizeof(capabilities)); + if (rc == TWRC_SUCCESS && cap.ConType == TWON_ARRAY) + { + TW_ARRAY *a; + a = GlobalLock(cap.hContainer); + if (a) + { + if (a->ItemType == TWTY_UINT16) + { + int i; + UINT16 *u = (UINT16 *) a->ItemList; + trace("%d Capabilities:\n", a->NumItems); + for (i = 0; i < a->NumItems; i++) + if (u[i] < sizeof(capabilities) / sizeof(capabilities[0])) + { + capabilities[u[i]] = 1; + trace(" %d: 0x%x\n", i, u[i]); + } + } + GlobalUnlock(cap.hContainer); + } + } + + /* All sources must support: */ + ok(capabilities[CAP_SUPPORTEDCAPS], "CAP_SUPPORTEDCAPS not supported\n"); + ok(capabilities[CAP_XFERCOUNT], "CAP_XFERCOUNT not supported\n"); + if (capabilities[CAP_XFERCOUNT]) + test_onevalue_cap(appid, source, CAP_XFERCOUNT, TWTY_INT16, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + ok(capabilities[CAP_UICONTROLLABLE], "CAP_UICONTROLLABLE not supported\n"); + if (capabilities[CAP_UICONTROLLABLE]) + test_onevalue_cap(appid, source, CAP_UICONTROLLABLE, TWTY_BOOL, TWQC_GET); + + if (source->SupportedGroups & DG_IMAGE) + { + /* + Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY / + MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT on: + */ + ok(capabilities[ICAP_COMPRESSION], "ICAP_COMPRESSION not supported\n"); + if (capabilities[ICAP_COMPRESSION]) + test_onevalue_cap(appid, source, ICAP_COMPRESSION, TWTY_UINT16, + TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT); + todo_wine + ok(capabilities[ICAP_PLANARCHUNKY], "ICAP_PLANARCHUNKY not supported\n"); + ok(capabilities[ICAP_PHYSICALHEIGHT], "ICAP_PHYSICALHEIGHT not supported\n"); + if (capabilities[ICAP_PHYSICALHEIGHT]) + test_physical(appid, source, ICAP_PHYSICALHEIGHT, + TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT); + ok(capabilities[ICAP_PHYSICALWIDTH], "ICAP_PHYSICALWIDTH not supported\n"); + if (capabilities[ICAP_PHYSICALWIDTH]) + test_physical(appid, source, ICAP_PHYSICALWIDTH, + TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT); + ok(capabilities[ICAP_PIXELFLAVOR], "ICAP_PIXELFLAVOR not supported\n"); + if (capabilities[ICAP_PIXELFLAVOR]) + test_onevalue_cap(appid, source, ICAP_PIXELFLAVOR, TWTY_UINT16, + TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT); + + /* + Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY / + MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT, MSG_RESET and MSG_SET on: + */ + ok(capabilities[ICAP_BITDEPTH], "ICAP_BITDEPTH not supported\n"); + if (capabilities[ICAP_BITDEPTH]) + test_onevalue_cap(appid, source, ICAP_BITDEPTH, TWTY_UINT16, + TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT ); + todo_wine + ok(capabilities[ICAP_BITORDER], "ICAP_BITORDER not supported\n"); + ok(capabilities[ICAP_PIXELTYPE], "ICAP_PIXELTYPE not supported\n"); + if (capabilities[ICAP_PIXELTYPE]) + test_onevalue_cap(appid, source, ICAP_PIXELTYPE, TWTY_UINT16, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + ok(capabilities[ICAP_UNITS], "ICAP_UNITS not supported\n"); + if (capabilities[ICAP_UNITS]) + test_onevalue_cap(appid, source, ICAP_UNITS, TWTY_UINT16, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + ok(capabilities[ICAP_XFERMECH], "ICAP_XFERMECH not supported\n"); + if (capabilities[ICAP_XFERMECH]) + test_onevalue_cap(appid, source, ICAP_XFERMECH, TWTY_UINT16, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + ok(capabilities[ICAP_XRESOLUTION], "ICAP_XRESOLUTION not supported\n"); + if (capabilities[ICAP_XRESOLUTION]) + test_resolution(appid, source, ICAP_XRESOLUTION, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + ok(capabilities[ICAP_YRESOLUTION], "ICAP_YRESOLUTION not supported\n"); + if (capabilities[ICAP_YRESOLUTION]) + test_resolution(appid, source, ICAP_YRESOLUTION, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + + /* Optional capabilities */ + if (capabilities[CAP_AUTOFEED]) + test_onevalue_cap(appid, source, CAP_AUTOFEED, TWTY_BOOL, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + if (capabilities[CAP_FEEDERENABLED]) + test_onevalue_cap(appid, source, CAP_FEEDERENABLED, TWTY_BOOL, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + if (capabilities[ICAP_SUPPORTEDSIZES]) + test_supported_sizes(appid, source, + TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET); + + /* Additional tests */ + test_imagelayout(appid, source); + + } +} + +static void test_sources(TW_IDENTITY *appid) +{ + TW_UINT16 rc; + TW_IDENTITY source; + TW_STATUS status; + int scannercount = 0; + + memset(&source, 0, sizeof(source)); + rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &source); + get_condition_code(appid, NULL, &status); + ok( (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) || + (rc == TWRC_FAILURE && status.ConditionCode == TWCC_NODS), + "Get first invalid condition code, rc %d, cc %d\n", rc, status.ConditionCode); + + while (rc == TWRC_SUCCESS) + { + scannercount++; + trace("[Scanner %d|Version %d.%d(%s)|Protocol %d.%d|SupportedGroups 0x%x|Manufacturer %s|Family %s|ProductName %s]\n", + scannercount, + source.Version.MajorNum, source.Version.MinorNum, source.Version.Info, + source.ProtocolMajor, source.ProtocolMinor, source.SupportedGroups, + source.Manufacturer, source.ProductFamily, source.ProductName); + memset(&source, 0, sizeof(source)); + rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &source); + get_condition_code(appid, NULL, &status); + ok(rc == TWRC_SUCCESS || rc == TWRC_ENDOFLIST, "Get next source failed, rc %d, cc %d\n", rc, status.ConditionCode); + } + + memset(&source, 0, sizeof(source)); + rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &source); + get_condition_code(appid, NULL, &status); + ok( (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) || + (rc == TWRC_FAILURE && status.ConditionCode == TWCC_NODS), + "Get default invalid condition code, rc %d, cc %d\n", rc, status.ConditionCode); + + if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) + { + rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source); + get_condition_code(appid, NULL, &status); + + if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) + { + rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &source); + get_condition_code(appid, NULL, &status); + ok(rc == TWRC_SUCCESS, "Close DS Failed, rc %d, cc %d\n", rc, status.ConditionCode); + } + } + + if (winetest_interactive) + { + trace("Interactive, so trying userselect\n"); + memset(&source, 0, sizeof(source)); + rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &source); + get_condition_code(appid, NULL, &status); + ok(rc == TWRC_SUCCESS || rc == TWRC_CANCEL, "Userselect failed, rc %d, cc %d\n", rc, status.ConditionCode); + + if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) + { + rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source); + get_condition_code(appid, NULL, &status); + if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) + { + test_single_source(appid, &source); + rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &source); + get_condition_code(appid, NULL, &status); + ok(rc == TWRC_SUCCESS, "Close DS Failed, rc %d, cc %d\n", rc, status.ConditionCode); + } + } + } + +} + +START_TEST(dsm) +{ + TW_IDENTITY appid; + TW_UINT16 rc; + HANDLE hwnd; + HMODULE htwain; + + if (!dsm_RegisterWindowClasses()) assert(0); + + htwain = LoadLibraryA("twain_32.dll"); + if (! htwain) + { + win_skip("twain_32.dll not available, skipping tests\n"); + return; + } + pDSM_Entry = (void*)GetProcAddress(htwain, "DSM_Entry"); + ok(pDSM_Entry != NULL, "Unable to GetProcAddress DSM_Entry\n"); + if (! pDSM_Entry) + { + win_skip("DSM_Entry not available, skipping tests\n"); + return; + } + + memset(&appid, 0, sizeof(appid)); + appid.Version.Language = TWLG_ENGLISH_USA; + appid.Version.Country = TWCY_USA; + appid.ProtocolMajor = TWON_PROTOCOLMAJOR; + appid.ProtocolMinor = TWON_PROTOCOLMINOR; + appid.SupportedGroups = DG_CONTROL | DG_IMAGE; + + hwnd = CreateWindow("TWAIN_dsm_class", "Twain Test", 0, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, GetModuleHandleA(0), NULL); + + rc = pDSM_Entry(&appid, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF) &hwnd); + ok(rc == TWRC_SUCCESS, "MSG_OPENDSM returned %d\n", rc); + + test_sources(&appid); + + rc = pDSM_Entry(&appid, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, (TW_MEMREF) &hwnd); + ok(rc == TWRC_SUCCESS, "MSG_CLOSEDSM returned %d\n", rc); + + DestroyWindow(hwnd); + FreeLibrary(htwain); +} diff --git a/rostests/winetests/twain_32/testlist.c b/rostests/winetests/twain_32/testlist.c new file mode 100644 index 00000000000..94d282a9e56 --- /dev/null +++ b/rostests/winetests/twain_32/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_dsm(void); + +const struct test winetest_testlist[] = +{ + { "dsm", func_dsm }, + { 0, 0 } +}; diff --git a/rostests/winetests/twain_32/twain_32.rbuild b/rostests/winetests/twain_32/twain_32.rbuild new file mode 100644 index 00000000000..688e6f86a6d --- /dev/null +++ b/rostests/winetests/twain_32/twain_32.rbuild @@ -0,0 +1,10 @@ + + . + + dsm.c + testlist.c + wine + user32 + gdi32 + ntdll + diff --git a/rostests/winetests/urlmon/generated.c b/rostests/winetests/urlmon/generated.c index d29c226ca17..1effb66de75 100644 --- a/rostests/winetests/urlmon/generated.c +++ b/rostests/winetests/urlmon/generated.c @@ -1,4 +1,4 @@ -/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* File generated automatically from tools/winapi/tests.dat; do not edit! */ /* This file can be copied, modified and distributed without restriction. */ /* @@ -30,22 +30,14 @@ * Windows API extension */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) -# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) -#elif defined(__GNUC__) -# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) -#else -/* FIXME: Not sure if is possible to do without compiler extension */ -#endif - #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) #elif defined(__GNUC__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* - * FIXME: Not sure if is possible to do without compiler extension - * (if type is not just a name that is, if so the normal) + * FIXME: May not be possible without a compiler extension + * (if type is not just a name that is, otherwise the normal * TYPE_ALIGNMENT can be used) */ #endif @@ -62,65 +54,51 @@ * Test helper macros */ -#ifdef FIELD_ALIGNMENT -# define TEST_FIELD_ALIGNMENT(type, field, align) \ - ok(FIELD_ALIGNMENT(type, field) == align, \ - "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ - (int)FIELD_ALIGNMENT(type, field)) +#ifdef _WIN64 + +# define TEST_TYPE_SIZE(type, size) +# define TEST_TYPE_ALIGN(type, align) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) +# define TEST_FIELD_OFFSET(type, field, offset) + #else -# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) + +# define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); + +# ifdef TYPE_ALIGNMENT +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +#else +# define TEST_TYPE_ALIGN(type, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) \ - ok(FIELD_OFFSET(type, field) == offset, \ - "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ - (long int)FIELD_OFFSET(type, field)) - -#ifdef _TYPE_ALIGNMENT -#define TEST__TYPE_ALIGNMENT(type, align) \ - ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +# ifdef _TYPE_ALIGNMENT +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else -# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) #endif -#ifdef TYPE_ALIGNMENT -#define TEST_TYPE_ALIGNMENT(type, align) \ - ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) -#else -# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); + #endif -#define TEST_TYPE_SIZE(type, size) \ - ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) +#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) +#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) +#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0); +#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0); -/*********************************************************************** - * Test macros - */ - -#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ - TEST_TYPE_SIZE(field_type, field_size); \ - TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ - TEST_FIELD_OFFSET(type, field_name, field_offset); \ - -#define TEST_TYPE(type, size, align) \ - TEST_TYPE_ALIGNMENT(type, align); \ - TEST_TYPE_SIZE(type, size) - -#define TEST_TYPE_POINTER(type, size, align) \ - TEST__TYPE_ALIGNMENT(*(type)0, align); \ - TEST_TYPE_SIZE(*(type)0, size) - -#define TEST_TYPE_SIGNED(type) \ - ok((type) -1 < 0, "(" #type ") -1 < 0\n"); - -#define TEST_TYPE_UNSIGNED(type) \ - ok((type) -1 > 0, "(" #type ") -1 > 0\n"); static void test_pack_BINDINFO(void) { /* BINDINFO (pack 4) */ - TEST_FIELD(BINDINFO, ULONG, cbSize, 0, 4, 4); - TEST_FIELD(BINDINFO, LPWSTR, szExtraInfo, 4, 4, 4); + TEST_FIELD_SIZE (BINDINFO, cbSize, 4) + TEST_FIELD_ALIGN (BINDINFO, cbSize, 4) + TEST_FIELD_OFFSET(BINDINFO, cbSize, 0) + TEST_FIELD_SIZE (BINDINFO, szExtraInfo, 4) + TEST_FIELD_ALIGN (BINDINFO, szExtraInfo, 4) + TEST_FIELD_OFFSET(BINDINFO, szExtraInfo, 4) } static void test_pack_IBindHost(void) @@ -206,106 +184,162 @@ static void test_pack_IWinInetInfoVtbl(void) static void test_pack_LPBINDHOST(void) { /* LPBINDHOST */ - TEST_TYPE(LPBINDHOST, 4, 4); + TEST_TYPE_SIZE (LPBINDHOST, 4) + TEST_TYPE_ALIGN (LPBINDHOST, 4) } static void test_pack_LPBINDING(void) { /* LPBINDING */ - TEST_TYPE(LPBINDING, 4, 4); + TEST_TYPE_SIZE (LPBINDING, 4) + TEST_TYPE_ALIGN (LPBINDING, 4) } static void test_pack_LPBINDSTATUSCALLBACK(void) { /* LPBINDSTATUSCALLBACK */ - TEST_TYPE(LPBINDSTATUSCALLBACK, 4, 4); + TEST_TYPE_SIZE (LPBINDSTATUSCALLBACK, 4) + TEST_TYPE_ALIGN (LPBINDSTATUSCALLBACK, 4) } static void test_pack_LPIINTERNETPROTOCOLINFO(void) { /* LPIINTERNETPROTOCOLINFO */ - TEST_TYPE(LPIINTERNETPROTOCOLINFO, 4, 4); + TEST_TYPE_SIZE (LPIINTERNETPROTOCOLINFO, 4) + TEST_TYPE_ALIGN (LPIINTERNETPROTOCOLINFO, 4) } static void test_pack_LPIINTERNETSESSION(void) { /* LPIINTERNETSESSION */ - TEST_TYPE(LPIINTERNETSESSION, 4, 4); + TEST_TYPE_SIZE (LPIINTERNETSESSION, 4) + TEST_TYPE_ALIGN (LPIINTERNETSESSION, 4) } static void test_pack_LPPERSISTMONIKER(void) { /* LPPERSISTMONIKER */ - TEST_TYPE(LPPERSISTMONIKER, 4, 4); + TEST_TYPE_SIZE (LPPERSISTMONIKER, 4) + TEST_TYPE_ALIGN (LPPERSISTMONIKER, 4) } static void test_pack_LPREMFORMATETC(void) { /* LPREMFORMATETC */ - TEST_TYPE(LPREMFORMATETC, 4, 4); + TEST_TYPE_SIZE (LPREMFORMATETC, 4) + TEST_TYPE_ALIGN (LPREMFORMATETC, 4) } static void test_pack_LPREMSECURITY_ATTRIBUTES(void) { /* LPREMSECURITY_ATTRIBUTES */ - TEST_TYPE(LPREMSECURITY_ATTRIBUTES, 4, 4); + TEST_TYPE_SIZE (LPREMSECURITY_ATTRIBUTES, 4) + TEST_TYPE_ALIGN (LPREMSECURITY_ATTRIBUTES, 4) } static void test_pack_LPWININETHTTPINFO(void) { /* LPWININETHTTPINFO */ - TEST_TYPE(LPWININETHTTPINFO, 4, 4); + TEST_TYPE_SIZE (LPWININETHTTPINFO, 4) + TEST_TYPE_ALIGN (LPWININETHTTPINFO, 4) } static void test_pack_LPWININETINFO(void) { /* LPWININETINFO */ - TEST_TYPE(LPWININETINFO, 4, 4); + TEST_TYPE_SIZE (LPWININETINFO, 4) + TEST_TYPE_ALIGN (LPWININETINFO, 4) } static void test_pack_PREMSECURITY_ATTRIBUTES(void) { /* PREMSECURITY_ATTRIBUTES */ - TEST_TYPE(PREMSECURITY_ATTRIBUTES, 4, 4); + TEST_TYPE_SIZE (PREMSECURITY_ATTRIBUTES, 4) + TEST_TYPE_ALIGN (PREMSECURITY_ATTRIBUTES, 4) } static void test_pack_REMSECURITY_ATTRIBUTES(void) { /* REMSECURITY_ATTRIBUTES (pack 4) */ - TEST_TYPE(REMSECURITY_ATTRIBUTES, 12, 4); - TEST_FIELD(REMSECURITY_ATTRIBUTES, DWORD, nLength, 0, 4, 4); - TEST_FIELD(REMSECURITY_ATTRIBUTES, DWORD, lpSecurityDescriptor, 4, 4, 4); - TEST_FIELD(REMSECURITY_ATTRIBUTES, BOOL, bInheritHandle, 8, 4, 4); + TEST_TYPE_SIZE (REMSECURITY_ATTRIBUTES, 12) + TEST_TYPE_ALIGN (REMSECURITY_ATTRIBUTES, 4) + TEST_FIELD_SIZE (REMSECURITY_ATTRIBUTES, nLength, 4) + TEST_FIELD_ALIGN (REMSECURITY_ATTRIBUTES, nLength, 4) + TEST_FIELD_OFFSET(REMSECURITY_ATTRIBUTES, nLength, 0) + TEST_FIELD_SIZE (REMSECURITY_ATTRIBUTES, lpSecurityDescriptor, 4) + TEST_FIELD_ALIGN (REMSECURITY_ATTRIBUTES, lpSecurityDescriptor, 4) + TEST_FIELD_OFFSET(REMSECURITY_ATTRIBUTES, lpSecurityDescriptor, 4) + TEST_FIELD_SIZE (REMSECURITY_ATTRIBUTES, bInheritHandle, 4) + TEST_FIELD_ALIGN (REMSECURITY_ATTRIBUTES, bInheritHandle, 4) + TEST_FIELD_OFFSET(REMSECURITY_ATTRIBUTES, bInheritHandle, 8) } static void test_pack_RemBINDINFO(void) { /* RemBINDINFO (pack 4) */ - TEST_TYPE(RemBINDINFO, 72, 4); - TEST_FIELD(RemBINDINFO, ULONG, cbSize, 0, 4, 4); - TEST_FIELD(RemBINDINFO, LPWSTR, szExtraInfo, 4, 4, 4); - TEST_FIELD(RemBINDINFO, DWORD, grfBindInfoF, 8, 4, 4); - TEST_FIELD(RemBINDINFO, DWORD, dwBindVerb, 12, 4, 4); - TEST_FIELD(RemBINDINFO, LPWSTR, szCustomVerb, 16, 4, 4); - TEST_FIELD(RemBINDINFO, DWORD, cbstgmedData, 20, 4, 4); - TEST_FIELD(RemBINDINFO, DWORD, dwOptions, 24, 4, 4); - TEST_FIELD(RemBINDINFO, DWORD, dwOptionsFlags, 28, 4, 4); - TEST_FIELD(RemBINDINFO, DWORD, dwCodePage, 32, 4, 4); - TEST_FIELD(RemBINDINFO, REMSECURITY_ATTRIBUTES, securityAttributes, 36, 12, 4); - TEST_FIELD(RemBINDINFO, IID, iid, 48, 16, 4); - TEST_FIELD(RemBINDINFO, IUnknown *, pUnk, 64, 4, 4); - TEST_FIELD(RemBINDINFO, DWORD, dwReserved, 68, 4, 4); + TEST_TYPE_SIZE (RemBINDINFO, 72) + TEST_TYPE_ALIGN (RemBINDINFO, 4) + TEST_FIELD_SIZE (RemBINDINFO, cbSize, 4) + TEST_FIELD_ALIGN (RemBINDINFO, cbSize, 4) + TEST_FIELD_OFFSET(RemBINDINFO, cbSize, 0) + TEST_FIELD_SIZE (RemBINDINFO, szExtraInfo, 4) + TEST_FIELD_ALIGN (RemBINDINFO, szExtraInfo, 4) + TEST_FIELD_OFFSET(RemBINDINFO, szExtraInfo, 4) + TEST_FIELD_SIZE (RemBINDINFO, grfBindInfoF, 4) + TEST_FIELD_ALIGN (RemBINDINFO, grfBindInfoF, 4) + TEST_FIELD_OFFSET(RemBINDINFO, grfBindInfoF, 8) + TEST_FIELD_SIZE (RemBINDINFO, dwBindVerb, 4) + TEST_FIELD_ALIGN (RemBINDINFO, dwBindVerb, 4) + TEST_FIELD_OFFSET(RemBINDINFO, dwBindVerb, 12) + TEST_FIELD_SIZE (RemBINDINFO, szCustomVerb, 4) + TEST_FIELD_ALIGN (RemBINDINFO, szCustomVerb, 4) + TEST_FIELD_OFFSET(RemBINDINFO, szCustomVerb, 16) + TEST_FIELD_SIZE (RemBINDINFO, cbstgmedData, 4) + TEST_FIELD_ALIGN (RemBINDINFO, cbstgmedData, 4) + TEST_FIELD_OFFSET(RemBINDINFO, cbstgmedData, 20) + TEST_FIELD_SIZE (RemBINDINFO, dwOptions, 4) + TEST_FIELD_ALIGN (RemBINDINFO, dwOptions, 4) + TEST_FIELD_OFFSET(RemBINDINFO, dwOptions, 24) + TEST_FIELD_SIZE (RemBINDINFO, dwOptionsFlags, 4) + TEST_FIELD_ALIGN (RemBINDINFO, dwOptionsFlags, 4) + TEST_FIELD_OFFSET(RemBINDINFO, dwOptionsFlags, 28) + TEST_FIELD_SIZE (RemBINDINFO, dwCodePage, 4) + TEST_FIELD_ALIGN (RemBINDINFO, dwCodePage, 4) + TEST_FIELD_OFFSET(RemBINDINFO, dwCodePage, 32) + TEST_FIELD_SIZE (RemBINDINFO, securityAttributes, 12) + TEST_FIELD_ALIGN (RemBINDINFO, securityAttributes, 4) + TEST_FIELD_OFFSET(RemBINDINFO, securityAttributes, 36) + TEST_FIELD_SIZE (RemBINDINFO, iid, 16) + TEST_FIELD_ALIGN (RemBINDINFO, iid, 4) + TEST_FIELD_OFFSET(RemBINDINFO, iid, 48) + TEST_FIELD_SIZE (RemBINDINFO, pUnk, 4) + TEST_FIELD_ALIGN (RemBINDINFO, pUnk, 4) + TEST_FIELD_OFFSET(RemBINDINFO, pUnk, 64) + TEST_FIELD_SIZE (RemBINDINFO, dwReserved, 4) + TEST_FIELD_ALIGN (RemBINDINFO, dwReserved, 4) + TEST_FIELD_OFFSET(RemBINDINFO, dwReserved, 68) } static void test_pack_RemFORMATETC(void) { /* RemFORMATETC (pack 4) */ - TEST_TYPE(RemFORMATETC, 20, 4); - TEST_FIELD(RemFORMATETC, DWORD, cfFormat, 0, 4, 4); - TEST_FIELD(RemFORMATETC, DWORD, ptd, 4, 4, 4); - TEST_FIELD(RemFORMATETC, DWORD, dwAspect, 8, 4, 4); - TEST_FIELD(RemFORMATETC, LONG, lindex, 12, 4, 4); - TEST_FIELD(RemFORMATETC, DWORD, tymed, 16, 4, 4); + TEST_TYPE_SIZE (RemFORMATETC, 20) + TEST_TYPE_ALIGN (RemFORMATETC, 4) + TEST_FIELD_SIZE (RemFORMATETC, cfFormat, 4) + TEST_FIELD_ALIGN (RemFORMATETC, cfFormat, 4) + TEST_FIELD_OFFSET(RemFORMATETC, cfFormat, 0) + TEST_FIELD_SIZE (RemFORMATETC, ptd, 4) + TEST_FIELD_ALIGN (RemFORMATETC, ptd, 4) + TEST_FIELD_OFFSET(RemFORMATETC, ptd, 4) + TEST_FIELD_SIZE (RemFORMATETC, dwAspect, 4) + TEST_FIELD_ALIGN (RemFORMATETC, dwAspect, 4) + TEST_FIELD_OFFSET(RemFORMATETC, dwAspect, 8) + TEST_FIELD_SIZE (RemFORMATETC, lindex, 4) + TEST_FIELD_ALIGN (RemFORMATETC, lindex, 4) + TEST_FIELD_OFFSET(RemFORMATETC, lindex, 12) + TEST_FIELD_SIZE (RemFORMATETC, tymed, 4) + TEST_FIELD_ALIGN (RemFORMATETC, tymed, 4) + TEST_FIELD_OFFSET(RemFORMATETC, tymed, 16) } static void test_pack(void) @@ -345,5 +379,9 @@ static void test_pack(void) START_TEST(generated) { +#ifdef _WIN64 + ok(0, "The type size / alignment tests don't support Win64 yet\n"); +#else test_pack(); +#endif } diff --git a/rostests/winetests/urlmon/misc.c b/rostests/winetests/urlmon/misc.c index 6d3305e5752..3c903c9425e 100644 --- a/rostests/winetests/urlmon/misc.c +++ b/rostests/winetests/urlmon/misc.c @@ -63,13 +63,6 @@ DEFINE_EXPECT(QI_IInternetProtocolInfo); DEFINE_EXPECT(CreateInstance); DEFINE_EXPECT(unk_Release); -static const char *debugstr_w(LPCWSTR str) -{ - static char buf[1024]; - WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); - return buf; -} - static void test_CreateFormatEnum(void) { IEnumFORMATETC *fenum = NULL, *fenum2 = NULL; @@ -527,7 +520,7 @@ static BYTE data85[] = {'.','S','N','D',0}; static const struct { BYTE *data; DWORD size; - LPCWSTR mime; + LPCWSTR mime, mime_alt; } mime_tests2[] = { {data1, sizeof(data1), mimeTextPlain}, {data2, sizeof(data2), mimeAppOctetStream}, @@ -535,12 +528,12 @@ static const struct { {data4, sizeof(data4), mimeAppOctetStream}, {data5, sizeof(data5), mimeTextPlain}, {data6, sizeof(data6), mimeTextPlain}, - {data7, sizeof(data7), mimeTextHtml}, - {data8, sizeof(data8), mimeTextHtml}, - {data9, sizeof(data9), mimeTextHtml}, - {data10, sizeof(data10), mimeTextHtml}, - {data11, sizeof(data11), mimeTextHtml}, - {data12, sizeof(data12), mimeTextHtml}, + {data7, sizeof(data7), mimeTextHtml, mimeTextPlain /* IE8 */}, + {data8, sizeof(data8), mimeTextHtml, mimeTextPlain /* IE8 */}, + {data9, sizeof(data9), mimeTextHtml, mimeImagePjpeg /* IE8 */}, + {data10, sizeof(data10), mimeTextHtml, mimeTextPlain /* IE8 */}, + {data11, sizeof(data11), mimeTextHtml, mimeTextPlain /* IE8 */}, + {data12, sizeof(data12), mimeTextHtml, mimeTextPlain /* IE8 */}, {data13, sizeof(data13), mimeTextPlain}, {data14, sizeof(data14), mimeTextPlain}, {data15, sizeof(data15), mimeTextPlain}, @@ -554,21 +547,21 @@ static const struct { {data23, sizeof(data23), mimeTextPlain}, {data24, sizeof(data24), mimeImageGif}, {data25, sizeof(data25), mimeImageGif}, - {data26, sizeof(data26), mimeTextHtml}, + {data26, sizeof(data26), mimeTextHtml, mimeImageGif /* IE8 */}, {data27, sizeof(data27), mimeTextPlain}, {data28, sizeof(data28), mimeImageBmp}, {data29, sizeof(data29), mimeImageBmp}, {data30, sizeof(data30), mimeAppOctetStream}, - {data31, sizeof(data31), mimeTextHtml}, + {data31, sizeof(data31), mimeTextHtml, mimeImageBmp /* IE8 */}, {data32, sizeof(data32), mimeAppOctetStream}, {data33, sizeof(data33), mimeAppOctetStream}, {data34, sizeof(data34), mimeImageXPng}, {data35, sizeof(data35), mimeImageXPng}, {data36, sizeof(data36), mimeAppOctetStream}, - {data37, sizeof(data37), mimeTextHtml}, + {data37, sizeof(data37), mimeTextHtml, mimeImageXPng /* IE8 */}, {data38, sizeof(data38), mimeAppOctetStream}, {data39, sizeof(data39), mimeImageTiff}, - {data40, sizeof(data40), mimeTextHtml}, + {data40, sizeof(data40), mimeTextHtml, mimeImageTiff /* IE8 */}, {data41, sizeof(data41), mimeImageTiff}, {data42, sizeof(data42), mimeTextPlain}, {data43, sizeof(data43), mimeAppOctetStream}, @@ -576,43 +569,43 @@ static const struct { {data45, sizeof(data45), mimeTextPlain}, {data46, sizeof(data46), mimeTextPlain}, {data47, sizeof(data47), mimeTextPlain}, - {data48, sizeof(data48), mimeTextHtml}, + {data48, sizeof(data48), mimeTextHtml, mimeVideoAvi /* IE8 */}, {data49, sizeof(data49), mimeVideoAvi}, {data50, sizeof(data50), mimeVideoMpeg}, {data51, sizeof(data51), mimeVideoMpeg}, {data52, sizeof(data52), mimeAppOctetStream}, {data53, sizeof(data53), mimeAppOctetStream}, - {data54, sizeof(data54), mimeTextHtml}, + {data54, sizeof(data54), mimeTextHtml, mimeVideoMpeg /* IE8 */}, {data55, sizeof(data55), mimeAppXGzip}, {data56, sizeof(data56), mimeTextPlain}, - {data57, sizeof(data57), mimeTextHtml}, + {data57, sizeof(data57), mimeTextHtml, mimeAppXGzip /* IE8 */}, {data58, sizeof(data58), mimeAppOctetStream}, {data59, sizeof(data59), mimeAppXZip}, {data60, sizeof(data60), mimeTextPlain}, - {data61, sizeof(data61), mimeTextHtml}, + {data61, sizeof(data61), mimeTextHtml, mimeAppXZip /* IE8 */}, {data62, sizeof(data62), mimeAppJava}, {data63, sizeof(data63), mimeTextPlain}, - {data64, sizeof(data64), mimeTextHtml}, + {data64, sizeof(data64), mimeTextHtml, mimeAppJava /* IE8 */}, {data65, sizeof(data65), mimeAppPdf}, {data66, sizeof(data66), mimeTextPlain}, - {data67, sizeof(data67), mimeTextHtml}, + {data67, sizeof(data67), mimeTextHtml, mimeAppPdf /* IE8 */}, {data68, sizeof(data68), mimeAppXMSDownload}, {data69, sizeof(data69), mimeTextPlain}, - {data70, sizeof(data70), mimeTextHtml}, + {data70, sizeof(data70), mimeTextHtml, mimeAppXMSDownload /* IE8 */}, {data71, sizeof(data71), mimeTextRichtext}, {data72, sizeof(data72), mimeTextPlain}, {data73, sizeof(data73), mimeTextPlain}, - {data74, sizeof(data74), mimeTextHtml}, + {data74, sizeof(data74), mimeTextHtml, mimeTextRichtext /* IE8 */}, {data75, sizeof(data75), mimeAudioWav}, {data76, sizeof(data76), mimeTextPlain}, {data77, sizeof(data77), mimeTextPlain}, - {data78, sizeof(data78), mimeTextHtml}, + {data78, sizeof(data78), mimeTextHtml, mimeTextPlain /* IE8 */}, {data79, sizeof(data79), mimeAppPostscript}, {data80, sizeof(data80), mimeTextPlain}, - {data81, sizeof(data81), mimeTextHtml}, + {data81, sizeof(data81), mimeTextHtml, mimeAppPostscript /* IE8 */}, {data82, sizeof(data82), mimeAudioBasic}, {data83, sizeof(data83), mimeTextPlain}, - {data84, sizeof(data84), mimeTextHtml}, + {data84, sizeof(data84), mimeTextHtml, mimeAudioBasic /* IE8 */}, {data85, sizeof(data85), mimeTextPlain} }; @@ -653,7 +646,7 @@ static void test_FindMimeFromData(void) hres = FindMimeFromData(NULL, NULL, mime_tests2[i].data, mime_tests2[i].size, NULL, 0, &mime, 0); ok(hres == S_OK, "[%d] FindMimeFromData failed: %08x\n", i, hres); - ok(!lstrcmpW(mime, mime_tests2[i].mime), "[%d] wrong mime: %s\n", i, debugstr_w(mime)); + ok(!lstrcmpW(mime, mime_tests2[i].mime), "[%d] wrong mime: %s\n", i, wine_dbgstr_w(mime)); CoTaskMemFree(mime); hres = FindMimeFromData(NULL, NULL, mime_tests2[i].data, mime_tests2[i].size, @@ -672,7 +665,9 @@ static void test_FindMimeFromData(void) if(!lstrcmpW(mimeAppOctetStream, mime_tests2[i].mime) || i == 17) ok(!lstrcmpW(mime, mimeImagePjpeg), "[%d] wrong mime\n", i); else - ok(!lstrcmpW(mime, mime_tests2[i].mime), "[%d] wrong mime\n", i); + ok(!lstrcmpW(mime, mime_tests2[i].mime) || + (mime_tests2[i].mime_alt && !lstrcmpW(mime, mime_tests2[i].mime_alt)), + "[%d] wrong mime, got %s\n", i, wine_dbgstr_w(mime)); CoTaskMemFree(mime); } @@ -713,241 +708,6 @@ static void test_FindMimeFromData(void) ok(hres == E_INVALIDARG, "FindMimeFromData failed: %08x, expected E_INVALIDARG\n", hres); } -static const BYTE secid1[] = {'f','i','l','e',':',0,0,0,0}; -static const BYTE secid5[] = {'h','t','t','p',':','w','w','w','.','w','i','n','e','h','q', - '.','o','r','g',3,0,0,0}; -static const BYTE secid6[] = {'a','b','o','u','t',':','b','l','a','n','k',3,0,0,0}; -static const BYTE secid7[] = {'f','t','p',':','w','i','n','e','h','q','.','o','r','g', - 3,0,0,0}; -static const BYTE secid10[] = - {'f','i','l','e',':','s','o','m','e','%','2','0','f','i','l','e','.','j','p','g',3,0,0,0}; -static const BYTE secid10_2[] = - {'f','i','l','e',':','s','o','m','e',' ','f','i','l','e','.','j','p','g',3,0,0,0}; - -static struct secmgr_test { - LPCWSTR url; - DWORD zone; - HRESULT zone_hres; - DWORD secid_size; - const BYTE *secid; - HRESULT secid_hres; -} secmgr_tests[] = { - {url1, 0, S_OK, sizeof(secid1), secid1, S_OK}, - {url2, 100, 0x80041001, 0, NULL, E_INVALIDARG}, - {url3, 0, S_OK, sizeof(secid1), secid1, S_OK}, - {url5, 3, S_OK, sizeof(secid5), secid5, S_OK}, - {url6, 3, S_OK, sizeof(secid6), secid6, S_OK}, - {url7, 3, S_OK, sizeof(secid7), secid7, S_OK} -}; - -static void test_SecurityManager(void) -{ - int i; - IInternetSecurityManager *secmgr = NULL; - BYTE buf[512]; - DWORD zone, size, policy; - HRESULT hres; - - hres = CoInternetCreateSecurityManager(NULL, &secmgr, 0); - ok(hres == S_OK, "CoInternetCreateSecurityManager failed: %08x\n", hres); - if(FAILED(hres)) - return; - - for(i=0; i < sizeof(secmgr_tests)/sizeof(secmgr_tests[0]); i++) { - zone = 100; - hres = IInternetSecurityManager_MapUrlToZone(secmgr, secmgr_tests[i].url, - &zone, 0); - ok(hres == secmgr_tests[i].zone_hres /* IE <=6 */ - || (FAILED(secmgr_tests[i].zone_hres) && hres == E_INVALIDARG), /* IE7 */ - "[%d] MapUrlToZone failed: %08x, expected %08x\n", - i, hres, secmgr_tests[i].zone_hres); - if(SUCCEEDED(hres)) - ok(zone == secmgr_tests[i].zone, "[%d] zone=%d, expected %d\n", i, zone, - secmgr_tests[i].zone); - else - ok(zone == secmgr_tests[i].zone || zone == -1, "[%d] zone=%d\n", i, zone); - - size = sizeof(buf); - memset(buf, 0xf0, sizeof(buf)); - hres = IInternetSecurityManager_GetSecurityId(secmgr, secmgr_tests[i].url, - buf, &size, 0); - ok(hres == secmgr_tests[i].secid_hres, - "[%d] GetSecurityId failed: %08x, expected %08x\n", - i, hres, secmgr_tests[i].secid_hres); - if(secmgr_tests[i].secid) { - ok(size == secmgr_tests[i].secid_size, "[%d] size=%d, expected %d\n", - i, size, secmgr_tests[i].secid_size); - ok(!memcmp(buf, secmgr_tests[i].secid, size), "[%d] wrong secid\n", i); - } - } - - zone = 100; - hres = IInternetSecurityManager_MapUrlToZone(secmgr, url10, &zone, 0); - ok(hres == S_OK, "MapUrlToZone failed: %08x, expected S_OK\n", hres); - ok(zone == 3, "zone=%d, expected 3\n", zone); - - /* win2k3 translates %20 into a space */ - size = sizeof(buf); - memset(buf, 0xf0, sizeof(buf)); - hres = IInternetSecurityManager_GetSecurityId(secmgr, url10, buf, &size, 0); - ok(hres == S_OK, "GetSecurityId failed: %08x, expected S_OK\n", hres); - ok(size == sizeof(secid10) || - size == sizeof(secid10_2), /* win2k3 */ - "size=%d\n", size); - ok(!memcmp(buf, secid10, size) || - !memcmp(buf, secid10_2, size), /* win2k3 */ - "wrong secid\n"); - - zone = 100; - hres = IInternetSecurityManager_MapUrlToZone(secmgr, NULL, &zone, 0); - ok(hres == E_INVALIDARG, "MapUrlToZone failed: %08x, expected E_INVALIDARG\n", hres); - ok(zone == 100 || zone == -1, "zone=%d\n", zone); - - size = sizeof(buf); - hres = IInternetSecurityManager_GetSecurityId(secmgr, NULL, buf, &size, 0); - ok(hres == E_INVALIDARG, - "GetSecurityId failed: %08x, expected E_INVALIDARG\n", hres); - hres = IInternetSecurityManager_GetSecurityId(secmgr, secmgr_tests[1].url, - NULL, &size, 0); - ok(hres == E_INVALIDARG, - "GetSecurityId failed: %08x, expected E_INVALIDARG\n", hres); - hres = IInternetSecurityManager_GetSecurityId(secmgr, secmgr_tests[1].url, - buf, NULL, 0); - ok(hres == E_INVALIDARG, - "GetSecurityId failed: %08x, expected E_INVALIDARG\n", hres); - - hres = IInternetSecurityManager_ProcessUrlAction(secmgr, NULL, URLACTION_SCRIPT_RUN, (BYTE*)&policy, - sizeof(WCHAR), NULL, 0, 0, 0); - ok(hres == E_INVALIDARG, "ProcessUrlAction failed: %08x, expected E_INVALIDARG\n", hres); - - IInternetSecurityManager_Release(secmgr); -} - -static void test_url_action(IInternetSecurityManager *secmgr, IInternetZoneManager *zonemgr, DWORD action) -{ - DWORD res, size, policy, reg_policy; - char buf[10]; - HKEY hkey; - HRESULT hres; - - res = RegOpenKeyA(HKEY_LOCAL_MACHINE, - "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3", &hkey); - if(res != ERROR_SUCCESS) { - ok(0, "Could not open zone key\n"); - return; - } - - wsprintf(buf, "%X", action); - size = sizeof(DWORD); - res = RegQueryValueExA(hkey, buf, NULL, NULL, (BYTE*)®_policy, &size); - RegCloseKey(hkey); - if(res != ERROR_SUCCESS || size != sizeof(DWORD)) { - policy = 0xdeadbeef; - hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, - sizeof(WCHAR), NULL, 0, 0, 0); - ok(hres == E_FAIL, "ProcessUrlAction(%x) failed: %08x, expected E_FAIL\n", action, hres); - ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); - - policy = 0xdeadbeef; - hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, - sizeof(DWORD), URLZONEREG_DEFAULT); - ok(hres == E_FAIL, "GetZoneActionPolicy failed: %08x, expected E_FAIL\n", hres); - ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); - return; - } - - policy = 0xdeadbeef; - hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, - sizeof(DWORD), URLZONEREG_DEFAULT); - ok(hres == S_OK, "GetZoneActionPolicy failed: %08x\n", hres); - ok(policy == reg_policy, "(%x) policy=%x, expected %x\n", action, policy, reg_policy); - - if(policy != URLPOLICY_QUERY) { - policy = 0xdeadbeef; - hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, - sizeof(WCHAR), NULL, 0, 0, 0); - if(reg_policy == URLPOLICY_DISALLOW) - ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); - else - ok(hres == S_OK, "ProcessUrlAction(%x) failed: %08x\n", action, hres); - ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); - } -} - -static void test_special_url_action(IInternetSecurityManager *secmgr, IInternetZoneManager *zonemgr, DWORD action) -{ - DWORD policy; - HRESULT hres; - - policy = 0xdeadbeef; - hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, - sizeof(DWORD), URLZONEREG_DEFAULT); - ok(hres == S_OK, "GetZoneActionPolicy failed: %08x\n", hres); - ok(policy == URLPOLICY_DISALLOW, "(%x) policy=%x, expected URLPOLIVY_DISALLOW\n", action, policy); - - policy = 0xdeadbeef; - hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url1, action, (BYTE*)&policy, - sizeof(WCHAR), NULL, 0, 0, 0); - ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); -} - -static void test_polices(void) -{ - IInternetZoneManager *zonemgr = NULL; - IInternetSecurityManager *secmgr = NULL; - HRESULT hres; - - hres = CoInternetCreateSecurityManager(NULL, &secmgr, 0); - ok(hres == S_OK, "CoInternetCreateSecurityManager failed: %08x\n", hres); - hres = CoInternetCreateZoneManager(NULL, &zonemgr, 0); - ok(hres == S_OK, "CoInternetCreateZoneManager failed: %08x\n", hres); - - test_url_action(secmgr, zonemgr, URLACTION_SCRIPT_RUN); - test_url_action(secmgr, zonemgr, URLACTION_ACTIVEX_OVERRIDE_OBJECT_SAFETY); - test_url_action(secmgr, zonemgr, URLACTION_CHANNEL_SOFTDIST_PERMISSIONS); - test_url_action(secmgr, zonemgr, 0xdeadbeef); - - test_special_url_action(secmgr, zonemgr, URLACTION_SCRIPT_OVERRIDE_SAFETY); - - IInternetSecurityManager_Release(secmgr); - IInternetZoneManager_Release(zonemgr); -} - -static void test_ZoneManager(void) -{ - IInternetZoneManager *zonemgr = NULL; - BYTE buf[32]; - HRESULT hres; - - hres = CoInternetCreateZoneManager(NULL, &zonemgr, 0); - ok(hres == S_OK, "CoInternetCreateZoneManager failed: %08x\n", hres); - if(FAILED(hres)) - return; - - hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, 0x1a10, buf, - sizeof(DWORD), URLZONEREG_DEFAULT); - ok(hres == S_OK, "GetZoneActionPolicy failed: %08x\n", hres); - ok(*(DWORD*)buf == 1, "policy=%d, expected 1\n", *(DWORD*)buf); - - hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, 0x1a10, NULL, - sizeof(DWORD), URLZONEREG_DEFAULT); - ok(hres == E_INVALIDARG, "GetZoneActionPolicy failed: %08x, expected E_INVALIDARG\n", hres); - - hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, 0x1a10, buf, - 2, URLZONEREG_DEFAULT); - ok(hres == E_INVALIDARG, "GetZoneActionPolicy failed: %08x, expected E_INVALIDARG\n", hres); - - hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, 0x1fff, buf, - sizeof(DWORD), URLZONEREG_DEFAULT); - ok(hres == E_FAIL, "GetZoneActionPolicy failed: %08x, expected E_FAIL\n", hres); - - hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 13, 0x1a10, buf, - sizeof(DWORD), URLZONEREG_DEFAULT); - ok(hres == E_INVALIDARG, "GetZoneActionPolicy failed: %08x, expected E_INVALIDARG\n", hres); - - IInternetZoneManager_Release(zonemgr); -} - static void register_protocols(void) { IInternetSession *session; @@ -1305,18 +1065,20 @@ static void test_ReleaseBindInfo(void) static void test_CopyStgMedium(void) { STGMEDIUM src, dst; + HGLOBAL empty; HRESULT hres; static WCHAR fileW[] = {'f','i','l','e',0}; memset(&src, 0xf0, sizeof(src)); memset(&dst, 0xe0, sizeof(dst)); + memset(&empty, 0xf0, sizeof(empty)); src.tymed = TYMED_NULL; src.pUnkForRelease = NULL; hres = CopyStgMedium(&src, &dst); ok(hres == S_OK, "CopyStgMedium failed: %08x\n", hres); ok(dst.tymed == TYMED_NULL, "tymed=%d\n", dst.tymed); - ok(dst.u.hGlobal == (void*)0xf0f0f0f0, "u=%p\n", dst.u.hGlobal); + ok(dst.u.hGlobal == empty, "u=%p\n", dst.u.hGlobal); ok(!dst.pUnkForRelease, "pUnkForRelease=%p, expected NULL\n", dst.pUnkForRelease); memset(&dst, 0xe0, sizeof(dst)); @@ -1386,9 +1148,11 @@ static void test_UrlMkGetSessionOption(void) ok(encoding == 0xdeadbeef, "encoding = %08x, exepcted 0xdeadbeef\n", encoding); } -static void test_ObtainUserAgentString(void) +static void test_user_agent(void) { static const CHAR expected[] = "Mozilla/4.0 (compatible; MSIE "; + static char test_str[] = "test"; + static char test2_str[] = "test\0test"; static CHAR str[3]; LPSTR str2 = NULL; HRESULT hres; @@ -1420,12 +1184,6 @@ static void test_ObtainUserAgentString(void) ok(size > 0, "size=%d, expected non-zero\n", size); str2 = HeapAlloc(GetProcessHeap(), 0, (size+20)*sizeof(CHAR)); - if (!str2) - { - skip("skipping rest of ObtainUserAgent tests, out of memory\n"); - } - else - { saved = size; hres = ObtainUserAgentString(0, str2, &size); ok(hres == S_OK, "ObtainUserAgentString failed: %08x\n", hres); @@ -1439,7 +1197,84 @@ static void test_ObtainUserAgentString(void) hres = ObtainUserAgentString(0, str2, &size); ok(hres == S_OK, "ObtainUserAgentString failed: %08x\n", hres); ok(size == saved, "size=%d, expected %d\n", size, saved); - } + + size = 0; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, NULL, 0, &size, 0); + ok(hres == E_OUTOFMEMORY, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(size, "size == 0\n"); + + size = 0xdeadbeef; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, NULL, 1000, &size, 0); + ok(hres == E_INVALIDARG, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(size, "size == 0\n"); + + saved = size; + size = 0; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, str2, saved+10, &size, 0); + ok(hres == E_OUTOFMEMORY, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(size == saved, "size = %d, expected %d\n", size, saved); + ok(sizeof(expected) <= strlen(str2) && !memcmp(expected, str2, sizeof(expected)-1), + "user agent was \"%s\", expected to start with \"%s\"\n", + str2, expected); + + size = 0; + str2[0] = 0; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, str2, saved, &size, 0); + ok(hres == E_OUTOFMEMORY, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(size == saved, "size = %d, expected %d\n", size, saved); + ok(sizeof(expected) <= strlen(str2) && !memcmp(expected, str2, sizeof(expected)-1), + "user agent was \"%s\", expected to start with \"%s\"\n", + str2, expected); + + size = saved; + str2[0] = 0; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, str2, saved-1, &size, 0); + ok(hres == E_OUTOFMEMORY, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(size == saved, "size = %d, expected %d\n", size, saved); + ok(!str2[0], "buf changed\n"); + + size = saved; + str2[0] = 0; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, str2, saved, NULL, 0); + ok(hres == E_INVALIDARG, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(!str2[0], "buf changed\n"); + + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, test_str, sizeof(test_str), 0); + ok(hres == S_OK, "UrlMkSetSessionOption failed: %08x\n", hres); + + size = 0; + str2[0] = 0; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, str2, saved, &size, 0); + ok(hres == E_OUTOFMEMORY, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(size == sizeof(test_str) && !memcmp(str2, test_str, sizeof(test_str)), "wrong user agent\n"); + + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, test2_str, sizeof(test2_str), 0); + ok(hres == S_OK, "UrlMkSetSessionOption failed: %08x\n", hres); + + size = 0; + str2[0] = 0; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, str2, saved, &size, 0); + ok(hres == E_OUTOFMEMORY, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(size == sizeof(test_str) && !memcmp(str2, test_str, sizeof(test_str)), "wrong user agent\n"); + + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, test_str, 2, 0); + ok(hres == S_OK, "UrlMkSetSessionOption failed: %08x\n", hres); + + size = 0; + str2[0] = 0; + hres = UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, str2, saved, &size, 0); + ok(hres == E_OUTOFMEMORY, "UrlMkGetSessionOption failed: %08x\n", hres); + ok(size == 3 && !strcmp(str2, "te"), "wrong user agent\n"); + + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, test_str, 0, 0); + ok(hres == E_INVALIDARG, "UrlMkSetSessionOption failed: %08x\n", hres); + + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, NULL, sizeof(test_str), 0); + ok(hres == E_INVALIDARG, "UrlMkSetSessionOption failed: %08x\n", hres); + + hres = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, NULL, 0, 0); + ok(hres == E_INVALIDARG, "UrlMkSetSessionOption failed: %08x\n", hres); + HeapFree(GetProcessHeap(), 0, str2); } @@ -1465,7 +1300,7 @@ static void test_MkParseDisplayNameEx(void) hres = IMoniker_GetDisplayName(mon, NULL, 0, &name); ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres); - ok(!lstrcmpW(name, url9), "wrong display name %s\n", debugstr_w(name)); + ok(!lstrcmpW(name, url9), "wrong display name %s\n", wine_dbgstr_w(name)); CoTaskMemFree(name); hres = IMoniker_IsSystemMoniker(mon, &issys); @@ -1491,6 +1326,14 @@ static void test_MkParseDisplayNameEx(void) IBindCtx_Release(bctx); } +static void test_IsValidURL(void) +{ + HRESULT hr; + + hr = IsValidURL(NULL, 0, 0); + ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); +} + START_TEST(misc) { OleInitialize(NULL); @@ -1503,16 +1346,14 @@ START_TEST(misc) test_CoInternetCompareUrl(); test_CoInternetQueryInfo(); test_FindMimeFromData(); - test_SecurityManager(); - test_polices(); - test_ZoneManager(); test_NameSpace(); test_MimeFilter(); test_ReleaseBindInfo(); test_CopyStgMedium(); test_UrlMkGetSessionOption(); - test_ObtainUserAgentString(); + test_user_agent(); test_MkParseDisplayNameEx(); + test_IsValidURL(); OleUninitialize(); } diff --git a/rostests/winetests/urlmon/protocol.c b/rostests/winetests/urlmon/protocol.c index bc666ebbbb4..222a0d9ff18 100644 --- a/rostests/winetests/urlmon/protocol.c +++ b/rostests/winetests/urlmon/protocol.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Jacek Caban for CodeWeavers + * Copyright 2005-2009 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,8 +29,6 @@ #include "urlmon.h" #include "wininet.h" -#include "initguid.h" - #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -76,13 +74,23 @@ DEFINE_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE); DEFINE_EXPECT(ReportProgress_PROTOCOLCLASSID); DEFINE_EXPECT(ReportProgress_COOKIE_SENT); DEFINE_EXPECT(ReportProgress_REDIRECTING); +DEFINE_EXPECT(ReportProgress_ENCODING); +DEFINE_EXPECT(ReportProgress_ACCEPTRANGES); +DEFINE_EXPECT(ReportProgress_PROXYDETECTING); +DEFINE_EXPECT(ReportProgress_LOADINGMIMEHANDLER); +DEFINE_EXPECT(ReportProgress_DECODING); DEFINE_EXPECT(ReportData); +DEFINE_EXPECT(ReportData2); DEFINE_EXPECT(ReportResult); DEFINE_EXPECT(GetBindString_ACCEPT_MIMES); DEFINE_EXPECT(GetBindString_USER_AGENT); DEFINE_EXPECT(GetBindString_POST_COOKIE); +DEFINE_EXPECT(GetBindString_URL); DEFINE_EXPECT(QueryService_HttpNegotiate); DEFINE_EXPECT(QueryService_InternetProtocol); +DEFINE_EXPECT(QueryService_HttpSecurity); +DEFINE_EXPECT(QueryInterface_IWinInetInfo); +DEFINE_EXPECT(QueryInterface_IWinInetHttpInfo); DEFINE_EXPECT(BeginningTransaction); DEFINE_EXPECT(GetRootSecurityId); DEFINE_EXPECT(OnResponse); @@ -92,9 +100,21 @@ DEFINE_EXPECT(CreateInstance); DEFINE_EXPECT(Start); DEFINE_EXPECT(Terminate); DEFINE_EXPECT(Read); +DEFINE_EXPECT(Read2); DEFINE_EXPECT(SetPriority); DEFINE_EXPECT(LockRequest); DEFINE_EXPECT(UnlockRequest); +DEFINE_EXPECT(MimeFilter_CreateInstance); +DEFINE_EXPECT(MimeFilter_Start); +DEFINE_EXPECT(MimeFilter_ReportProgress); +DEFINE_EXPECT(MimeFilter_ReportData); +DEFINE_EXPECT(MimeFilter_ReportResult); +DEFINE_EXPECT(MimeFilter_Terminate); +DEFINE_EXPECT(MimeFilter_LockRequest); +DEFINE_EXPECT(MimeFilter_UnlockRequest); +DEFINE_EXPECT(MimeFilter_Read); +DEFINE_EXPECT(MimeFilter_Switch); +DEFINE_EXPECT(MimeFilter_Continue); static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0}; static const WCHAR index_url[] = @@ -106,26 +126,30 @@ static const WCHAR text_htmlW[] = {'t','e','x','t','/','h','t','m','l',0}; static const WCHAR hostW[] = {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; static const WCHAR winehq_ipW[] = {'2','0','9','.','4','6','.','2','5','.','1','3','4',0}; static const WCHAR emptyW[] = {0}; +static const WCHAR gzipW[] = {'g','z','i','p',0}; static HRESULT expect_hrResult; static LPCWSTR file_name, http_url, expect_wsz; -static IInternetProtocol *http_protocol = NULL; -static BOOL first_data_notif = FALSE, http_is_first = FALSE, - http_post_test = FALSE; -static int state = 0, prot_state; -static DWORD bindf = 0, ex_priority = 0; -static IInternetProtocol *binding_protocol; +static IInternetProtocol *async_protocol = NULL; +static BOOL first_data_notif, http_is_first, http_post_test; +static int state = 0, prot_state, read_report_data; +static DWORD bindf, ex_priority , pi; +static IInternetProtocol *binding_protocol, *filtered_protocol; static IInternetBindInfo *prot_bind_info; -static IInternetProtocolSink *binding_sink; +static IInternetProtocolSink *binding_sink, *filtered_sink; static void *expect_pv; -static HANDLE event_complete, event_complete2; +static HANDLE event_complete, event_complete2, event_continue, event_continue_done; static BOOL binding_test; -static PROTOCOLDATA protocoldata, *pdata; -static DWORD prot_read; +static PROTOCOLDATA protocoldata, *pdata, continue_protdata; +static DWORD prot_read, pi, filter_state; +static BOOL security_problem; +static BOOL async_read_pending, mimefilter_test, direct_read, wait_for_switch, emulate_prot, short_read; static enum { FILE_TEST, HTTP_TEST, + HTTPS_TEST, + FTP_TEST, MK_TEST, BIND_TEST } tested_protocol; @@ -133,26 +157,25 @@ static enum { static const WCHAR protocol_names[][10] = { {'f','i','l','e',0}, {'h','t','t','p',0}, + {'h','t','t','p','s',0}, + {'f','t','p',0}, {'m','k',0}, {'t','e','s','t',0} }; -static const WCHAR binding_urls[][30] = { +static const WCHAR binding_urls[][130] = { {'f','i','l','e',':','t','e','s','t','.','h','t','m','l',0}, - {'h','t','t','p',':','/','/','t','e','s','t','/','t','e','s','t','.','h','t','m','l',0}, + {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.', + 'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0}, + {'h','t','t','p','s',':','/','/','w','w','w','.','c','o','d','e','w','e','a','v','e','r','s', + '.','c','o','m','/','t','e','s','t','.','h','t','m','l',0}, + {'f','t','p',':','/','/','f','t','p','.','w','i','n','e','h','q','.','o','r','g', + '/','p','u','b','/','o','t','h','e','r', + '/','w','i','n','e','l','o','g','o','.','x','c','f','.','t','a','r','.','b','z','2',0}, {'m','k',':','t','e','s','t',0}, {'t','e','s','t',':','/','/','f','i','l','e','.','h','t','m','l',0} }; -static const char *debugstr_w(LPCWSTR str) -{ - static char buf[512]; - if(!str) - return "(null)"; - WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); - return buf; -} - static const char *debugstr_guid(REFIID riid) { static char buf[50]; @@ -165,6 +188,76 @@ static const char *debugstr_guid(REFIID riid) return buf; } +static int strcmp_wa(LPCWSTR strw, const char *stra) +{ + CHAR buf[512]; + WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); + return lstrcmpA(stra, buf); +} + +/* lstrcmpW is not implemented on Win9x */ +static int strcmp_ww(LPCWSTR strw1, LPCWSTR strw2) +{ + CHAR stra1[512], stra2[512]; + WideCharToMultiByte(CP_ACP, 0, strw1, -1, stra1, MAX_PATH, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, strw2, -1, stra2, MAX_PATH, NULL, NULL); + return lstrcmpA(stra1, stra2); +} + +static HRESULT WINAPI HttpSecurity_QueryInterface(IHttpSecurity *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) + || IsEqualGUID(&IID_IHttpSecurity, riid)) { + *ppv = iface; + return S_OK; + } + + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI HttpSecurity_AddRef(IHttpSecurity *iface) +{ + return 2; +} + +static ULONG WINAPI HttpSecurity_Release(IHttpSecurity *iface) +{ + return 1; +} + +static HRESULT WINAPI HttpSecurity_GetWindow(IHttpSecurity* iface, REFGUID rguidReason, HWND *phwnd) +{ + trace("HttpSecurity_GetWindow\n"); + + return S_FALSE; +} + +static HRESULT WINAPI HttpSecurity_OnSecurityProblem(IHttpSecurity *iface, DWORD dwProblem) +{ + trace("Security problem: %u\n", dwProblem); + ok(dwProblem == ERROR_INTERNET_SEC_CERT_REV_FAILED, "Expected ERROR_INTERNET_SEC_CERT_REV_FAILED got %u\n", dwProblem); + + /* Only retry once */ + if (security_problem) + return E_ABORT; + + security_problem = TRUE; + SET_EXPECT(BeginningTransaction); + + return RPC_E_RETRY; +} + +static IHttpSecurityVtbl HttpSecurityVtbl = { + HttpSecurity_QueryInterface, + HttpSecurity_AddRef, + HttpSecurity_Release, + HttpSecurity_GetWindow, + HttpSecurity_OnSecurityProblem +}; + +static IHttpSecurity http_security = { &HttpSecurityVtbl }; + static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, REFIID riid, void **ppv) { if(IsEqualGUID(&IID_IUnknown, riid) @@ -201,9 +294,9 @@ static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, CHECK_EXPECT(BeginningTransaction); if(binding_test) - ok(!lstrcmpW(szURL, binding_urls[tested_protocol]), "szURL != http_url\n"); + ok(!strcmp_ww(szURL, binding_urls[tested_protocol]), "szURL != http_url\n"); else - ok(!lstrcmpW(szURL, http_url), "szURL != http_url\n"); + ok(!strcmp_ww(szURL, http_url), "szURL != http_url\n"); ok(!dwReserved, "dwReserved=%d, expected 0\n", dwReserved); ok(pszAdditionalHeaders != NULL, "pszAdditionalHeaders == NULL\n"); if(pszAdditionalHeaders) @@ -218,7 +311,7 @@ static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, skip("Out of memory\n"); return E_OUTOFMEMORY; } - lstrcpyW(addl_headers, wszHeaders); + memcpy(addl_headers, wszHeaders, sizeof(wszHeaders)); *pszAdditionalHeaders = addl_headers; } } @@ -303,6 +396,12 @@ static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFG return E_NOINTERFACE; } + if(IsEqualGUID(&IID_IHttpSecurity, guidService)) { + ok(IsEqualGUID(&IID_IHttpSecurity, riid), "unexpected riid\n"); + CHECK_EXPECT(QueryService_HttpSecurity); + return IHttpSecurity_QueryInterface(&http_security, riid, ppv); + } + ok(0, "unexpected service %s\n", debugstr_guid(guidService)); return E_FAIL; } @@ -331,50 +430,101 @@ static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface) return 1; } -static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) +static void call_continue(PROTOCOLDATA *protocol_data) { HRESULT hres; - CHECK_EXPECT(Switch); - ok(pProtocolData != NULL, "pProtocolData == NULL\n"); - - pdata = pProtocolData; - - if(binding_test) { - SetEvent(event_complete); - WaitForSingleObject(event_complete2, INFINITE); - return S_OK; - } - if (!state) { + if(tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST) + CLEAR_CALLED(ReportProgress_COOKIE_SENT); + if(tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST || tested_protocol == FTP_TEST) { if (http_is_first) { - CHECK_CALLED(ReportProgress_FINDINGRESOURCE); - CHECK_CALLED(ReportProgress_CONNECTING); + CLEAR_CALLED(ReportProgress_FINDINGRESOURCE); + CLEAR_CALLED(ReportProgress_CONNECTING); + CLEAR_CALLED(ReportProgress_PROXYDETECTING); } else todo_wine { CHECK_NOT_CALLED(ReportProgress_FINDINGRESOURCE); - CHECK_NOT_CALLED(ReportProgress_CONNECTING); + /* IE7 does call this */ + CLEAR_CALLED(ReportProgress_CONNECTING); } + } + if(tested_protocol == FTP_TEST) + todo_wine CHECK_CALLED(ReportProgress_SENDINGREQUEST); + else if (tested_protocol != HTTPS_TEST) CHECK_CALLED(ReportProgress_SENDINGREQUEST); + if(tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST) { SET_EXPECT(OnResponse); + if(tested_protocol == HTTPS_TEST) + SET_EXPECT(ReportProgress_ACCEPTRANGES); SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); if(bindf & BINDF_NEEDFILE) SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); } + } SET_EXPECT(ReportData); - hres = IInternetProtocol_Continue(http_protocol, pProtocolData); + hres = IInternetProtocol_Continue(async_protocol, protocol_data); ok(hres == S_OK, "Continue failed: %08x\n", hres); + if(tested_protocol == FTP_TEST) + CLEAR_CALLED(ReportData); + else if (! security_problem) CHECK_CALLED(ReportData); if (!state) { + if (! security_problem) + { state = 1; + if(tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST) { CHECK_CALLED(OnResponse); + if(tested_protocol == HTTPS_TEST) + CHECK_CALLED(ReportProgress_ACCEPTRANGES); CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); if(bindf & BINDF_NEEDFILE) CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE); } + } + else + { + security_problem = FALSE; + SET_EXPECT(ReportProgress_CONNECTING); + } + } +} +static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) +{ + if(tested_protocol == FTP_TEST) + CHECK_EXPECT2(Switch); + else + CHECK_EXPECT(Switch); + + ok(pProtocolData != NULL, "pProtocolData == NULL\n"); + if(binding_test) { + ok(pProtocolData != &protocoldata, "pProtocolData == &protocoldata\n"); + ok(pProtocolData->grfFlags == protocoldata.grfFlags, "grfFlags wrong %x/%x\n", + pProtocolData->grfFlags, protocoldata.grfFlags ); + ok(pProtocolData->dwState == protocoldata.dwState, "dwState wrong %x/%x\n", + pProtocolData->dwState, protocoldata.dwState ); + ok(pProtocolData->pData == protocoldata.pData, "pData wrong %p/%p\n", + pProtocolData->pData, protocoldata.pData ); + ok(pProtocolData->cbData == protocoldata.cbData, "cbData wrong %x/%x\n", + pProtocolData->cbData, protocoldata.cbData ); + } + + pdata = pProtocolData; + + if(binding_test) { SetEvent(event_complete); + WaitForSingleObject(event_complete2, INFINITE); + return S_OK; + }if(direct_read) { + continue_protdata = *pProtocolData; + SetEvent(event_continue); + WaitForSingleObject(event_continue_done, INFINITE); + }else { + call_continue(pProtocolData); + SetEvent(event_complete); + } return S_OK; } @@ -385,16 +535,16 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, static const WCHAR null_guid[] = {'{','0','0','0','0','0','0','0','0','-','0','0','0','0','-', '0','0','0','0','-','0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0','}',0}; static const WCHAR text_plain[] = {'t','e','x','t','/','p','l','a','i','n',0}; - static const WCHAR post_host[] = - {'c','r','o','s','s','o','v','e','r','.','c','o','d','e', - 'w','e','a','v','e','r','s','.','c','o','m',0}; - static const WCHAR wszCrossoverIP[] = - {'2','0','9','.','4','6','.','2','5','.','1','3','2',0}; - /* I'm not sure if it's a good idea to hardcode here the IP address... */ switch(ulStatusCode) { case BINDSTATUS_MIMETYPEAVAILABLE: CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + if(tested_protocol != FILE_TEST && !mimefilter_test && (pi & PI_MIMEVERIFICATION)) { + if(!short_read || !direct_read) + CHECK_CALLED(Read); /* set in Continue */ + else if(short_read) + CHECK_CALLED(Read2); /* set in Read */ + } ok(szStatusText != NULL, "szStatusText == NULL\n"); if(szStatusText) { if(tested_protocol == BIND_TEST) @@ -403,7 +553,7 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ok(lstrlenW(text_plain) <= lstrlenW(szStatusText) && !memcmp(szStatusText, text_plain, lstrlenW(text_plain)*sizeof(WCHAR)), "szStatusText != text/plain\n"); - else + else if(!mimefilter_test) ok(lstrlenW(text_htmlW) <= lstrlenW(szStatusText) && !memcmp(szStatusText, text_htmlW, lstrlenW(text_htmlW)*sizeof(WCHAR)), "szStatusText != text/html\n"); @@ -426,36 +576,23 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ok(szStatusText != NULL, "szStatusText == NULL\n"); if(szStatusText) { if(binding_test) - ok(!lstrcmpW(szStatusText, expect_wsz), "unexpected szStatusText\n"); + ok(!strcmp_ww(szStatusText, expect_wsz), "unexpected szStatusText\n"); else if(tested_protocol == FILE_TEST) - ok(!lstrcmpW(szStatusText, file_name), "szStatusText = \"%s\"\n", debugstr_w(szStatusText)); + ok(!strcmp_ww(szStatusText, file_name), "szStatusText = %s\n", wine_dbgstr_w(szStatusText)); else ok(szStatusText != NULL, "szStatusText == NULL\n"); } break; case BINDSTATUS_FINDINGRESOURCE: - CHECK_EXPECT(ReportProgress_FINDINGRESOURCE); + CHECK_EXPECT2(ReportProgress_FINDINGRESOURCE); ok(szStatusText != NULL, "szStatusText == NULL\n"); - if(szStatusText) - { - if (!http_post_test) - ok(!lstrcmpW(szStatusText, hostW), - "szStatustext != \"www.winehq.org\"\n"); - else - ok(!lstrcmpW(szStatusText, post_host), - "szStatustext != \"crossover.codeweavers.com\"\n"); - } break; case BINDSTATUS_CONNECTING: - CHECK_EXPECT(ReportProgress_CONNECTING); + CHECK_EXPECT2(ReportProgress_CONNECTING); ok(szStatusText != NULL, "szStatusText == NULL\n"); - if(szStatusText) - ok(!lstrcmpW(szStatusText, http_post_test ? - wszCrossoverIP : winehq_ipW), - "Unexpected szStatusText\n"); break; case BINDSTATUS_SENDINGREQUEST: - CHECK_EXPECT(ReportProgress_SENDINGREQUEST); + CHECK_EXPECT2(ReportProgress_SENDINGREQUEST); if(tested_protocol == FILE_TEST) { ok(szStatusText != NULL, "szStatusText == NULL\n"); if(szStatusText) @@ -466,12 +603,12 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, CHECK_EXPECT(ReportProgress_VERIFIEDMIMETYPEAVAILABLE); ok(szStatusText != NULL, "szStatusText == NULL\n"); if(szStatusText) - ok(!lstrcmpW(szStatusText, text_htmlW), "szStatusText != text/html\n"); + ok(!strcmp_ww(szStatusText, text_htmlW), "szStatusText != text/html\n"); break; case BINDSTATUS_PROTOCOLCLASSID: CHECK_EXPECT(ReportProgress_PROTOCOLCLASSID); ok(szStatusText != NULL, "szStatusText == NULL\n"); - ok(!lstrcmpW(szStatusText, null_guid), "unexpected szStatusText\n"); + ok(!strcmp_ww(szStatusText, null_guid), "unexpected classid %s\n", wine_dbgstr_w(szStatusText)); break; case BINDSTATUS_COOKIE_SENT: CHECK_EXPECT(ReportProgress_COOKIE_SENT); @@ -479,7 +616,28 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, break; case BINDSTATUS_REDIRECTING: CHECK_EXPECT(ReportProgress_REDIRECTING); - ok(szStatusText == NULL, "szStatusText != NULL\n"); + ok(szStatusText == NULL, "szStatusText = %s\n", wine_dbgstr_w(szStatusText)); + break; + case BINDSTATUS_ENCODING: + CHECK_EXPECT(ReportProgress_ENCODING); + ok(!strcmp_wa(szStatusText, "gzip"), "szStatusText = %s\n", wine_dbgstr_w(szStatusText)); + break; + case BINDSTATUS_ACCEPTRANGES: + CHECK_EXPECT(ReportProgress_ACCEPTRANGES); + ok(!szStatusText, "szStatusText = %s\n", wine_dbgstr_w(szStatusText)); + break; + case BINDSTATUS_PROXYDETECTING: + CHECK_EXPECT(ReportProgress_PROXYDETECTING); + SET_EXPECT(ReportProgress_CONNECTING); + ok(!szStatusText, "szStatusText = %s\n", wine_dbgstr_w(szStatusText)); + break; + case BINDSTATUS_LOADINGMIMEHANDLER: + CHECK_EXPECT(ReportProgress_LOADINGMIMEHANDLER); + ok(!szStatusText, "szStatusText = %s\n", wine_dbgstr_w(szStatusText)); + break; + case BINDSTATUS_DECODING: + CHECK_EXPECT(ReportProgress_DECODING); + ok(!strcmp_ww(szStatusText, gzipW), "szStatusText = %s\n", wine_dbgstr_w(szStatusText)); break; default: ok(0, "Unexpected status %d\n", ulStatusCode); @@ -491,16 +649,92 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) { - if(tested_protocol == FILE_TEST) { + HRESULT hres; + + static int rec_depth; + rec_depth++; + + if(!mimefilter_test && tested_protocol == FILE_TEST) { CHECK_EXPECT2(ReportData); ok(ulProgress == ulProgressMax, "ulProgress (%d) != ulProgressMax (%d)\n", ulProgress, ulProgressMax); ok(ulProgressMax == 13, "ulProgressMax=%d, expected 13\n", ulProgressMax); - ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION), + /* BSCF_SKIPDRAINDATAFORFILEURLS added in IE8 */ + ok((grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION)) || + (grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_SKIPDRAINDATAFORFILEURLS)), "grcfBSCF = %08x\n", grfBSCF); - }else if(!binding_test && tested_protocol == HTTP_TEST) { - if(!(grfBSCF & BSCF_LASTDATANOTIFICATION)) + }else if(direct_read) { + BYTE buf[14096]; + ULONG read; + + if(!read_report_data && rec_depth == 1) { + BOOL reported_all_data = called_ReportData2; + + CHECK_EXPECT2(ReportData); + + if(short_read) { + ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE) + || grfBSCF == BSCF_FIRSTDATANOTIFICATION, /* < IE8 */ + "grcfBSCF = %08x\n", grfBSCF); + CHECK_CALLED(Read); /* Set in Continue */ + first_data_notif = FALSE; + }else if(first_data_notif) { + ok(grfBSCF == BSCF_FIRSTDATANOTIFICATION, "grcfBSCF = %08x\n", grfBSCF); + first_data_notif = FALSE; + }else if(reported_all_data) { + ok(grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION), + "grcfBSCF = %08x\n", grfBSCF); + }else if(!direct_read) { + ok(grfBSCF == BSCF_INTERMEDIATEDATANOTIFICATION, "grcfBSCF = %08x\n", grfBSCF); + } + + do { + read = 0; + if(emulate_prot) + SET_EXPECT(Read); + else + SET_EXPECT(ReportData2); + SET_EXPECT(ReportResult); + hres = IInternetProtocol_Read(binding_test ? binding_protocol : async_protocol, expect_pv = buf, sizeof(buf), &read); + if(hres == S_OK) + ok(read, "read == 0\n"); + if(reported_all_data) { + ok(hres == S_FALSE, "Read failed: %08x, expected S_FALSE\n", hres); + } + if(emulate_prot) + CHECK_CALLED(Read); + if(!reported_all_data && called_ReportData2) { + if(!emulate_prot) + CHECK_CALLED(ReportData2); + CHECK_CALLED(ReportResult); + ok(hres == S_OK, "Read failed: %08x\n", hres); + reported_all_data = TRUE; + }else { + if(!emulate_prot) + CHECK_NOT_CALLED(ReportData2); + CHECK_NOT_CALLED(ReportResult); + } + }while(hres == S_OK); + if(hres == S_FALSE) + wait_for_switch = FALSE; + }else { + CHECK_EXPECT(ReportData2); + + ok(grfBSCF & BSCF_LASTDATANOTIFICATION, "grfBSCF = %08x\n", grfBSCF); + + read = 0xdeadbeef; + if(emulate_prot) + SET_EXPECT(Read2); + hres = IInternetProtocol_Read(binding_test ? binding_protocol : async_protocol, expect_pv = buf, sizeof(buf), &read); + if(emulate_prot) + CHECK_CALLED(Read2); + ok(hres == S_FALSE, "Read returned: %08x, expected E_FALSE\n", hres); + ok(!read, "read = %d\n", read); + } + }else if(!binding_test && (tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST + || tested_protocol == FTP_TEST)) { + if(!(grfBSCF & BSCF_LASTDATANOTIFICATION) || (grfBSCF & BSCF_DATAFULLYAVAILABLE)) CHECK_EXPECT(ReportData); else if (http_post_test) ok(ulProgress == 13, "Read %u bytes instead of 13\n", ulProgress); @@ -508,11 +742,14 @@ static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWOR ok(ulProgress, "ulProgress == 0\n"); if(first_data_notif) { - ok(grfBSCF == BSCF_FIRSTDATANOTIFICATION, "grcfBSCF = %08x\n", grfBSCF); + ok(grfBSCF == BSCF_FIRSTDATANOTIFICATION + || grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE), + "grcfBSCF = %08x\n", grfBSCF); first_data_notif = FALSE; } else { ok(grfBSCF == BSCF_INTERMEDIATEDATANOTIFICATION - || grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION), + || grfBSCF == (BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION) + || broken(grfBSCF == (BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION)), "grcfBSCF = %08x\n", grfBSCF); } @@ -533,23 +770,33 @@ static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWOR } SetEvent(event_complete); } - }else { + }else if(!read_report_data) { BYTE buf[1000]; ULONG read; HRESULT hres; CHECK_EXPECT(ReportData); - if(tested_protocol == BIND_TEST) - return S_OK; - + if(tested_protocol != BIND_TEST) { do { + if(mimefilter_test) + SET_EXPECT(MimeFilter_Read); + else if(rec_depth > 1) + SET_EXPECT(Read2); + else SET_EXPECT(Read); hres = IInternetProtocol_Read(binding_protocol, expect_pv=buf, sizeof(buf), &read); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_Read); + else if(rec_depth > 1) + CHECK_CALLED(Read2); + else CHECK_CALLED(Read); }while(hres == S_OK); } + } + rec_depth--; return S_OK; } @@ -558,14 +805,22 @@ static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HR { CHECK_EXPECT(ReportResult); + if(tested_protocol == FTP_TEST) + ok(hrResult == E_PENDING || hrResult == S_OK, "hrResult = %08x, expected E_PENDING or S_OK\n", hrResult); + else ok(hrResult == expect_hrResult, "hrResult = %08x, expected: %08x\n", hrResult, expect_hrResult); - if(SUCCEEDED(hrResult)) + if(SUCCEEDED(hrResult) || tested_protocol == FTP_TEST) ok(dwError == ERROR_SUCCESS, "dwError = %d, expected ERROR_SUCCESS\n", dwError); else - ok(dwError != ERROR_SUCCESS, "dwError == ERROR_SUCCESS\n"); + ok(dwError != ERROR_SUCCESS || + broken(tested_protocol == MK_TEST), /* Win9x, WinME and NT4 */ + "dwError == ERROR_SUCCESS\n"); ok(!szResult, "szResult != NULL\n"); + if(direct_read) + SET_EXPECT(ReportData); /* checked after main loop */ + return S_OK; } @@ -581,18 +836,134 @@ static IInternetProtocolSinkVtbl protocol_sink_vtbl = { static IInternetProtocolSink protocol_sink = { &protocol_sink_vtbl }; +static HRESULT WINAPI MimeProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static ULONG WINAPI MimeProtocolSink_AddRef(IInternetProtocolSink *iface) +{ + return 2; +} + +static ULONG WINAPI MimeProtocolSink_Release(IInternetProtocolSink *iface) +{ + return 1; +} + +static HRESULT WINAPI MimeProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) +{ + HRESULT hres; + + CHECK_EXPECT(MimeFilter_Switch); + + SET_EXPECT(Switch); + hres = IInternetProtocolSink_Switch(filtered_sink, pProtocolData); + ok(hres == S_OK, "Switch failed: %08x\n", hres); + CHECK_CALLED(Switch); + + return S_OK; +} + +static HRESULT WINAPI MimeProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode, + LPCWSTR szStatusText) +{ + CHECK_EXPECT(MimeFilter_ReportProgress); + return S_OK; +} + +static HRESULT WINAPI MimeProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF, + ULONG ulProgress, ULONG ulProgressMax) +{ + DWORD read = 0; + BYTE buf[8192]; + HRESULT hres; + + CHECK_EXPECT(MimeFilter_ReportData); + + if(!filter_state) { + SET_EXPECT(Read); + hres = IInternetProtocol_Read(filtered_protocol, buf, sizeof(buf), &read); + if(tested_protocol == HTTP_TEST) + ok(hres == S_OK || hres == E_PENDING || hres == S_FALSE, "Read failed: %08x\n", hres); + else + ok(hres == S_OK, "Read failed: %08x\n", hres); + CHECK_CALLED(Read); + + SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + hres = IInternetProtocolSink_ReportProgress(filtered_sink, BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, text_htmlW); + ok(hres == S_OK, "ReportProgress failed: %08x\n", hres); + CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + + /* FIXME: test BINDSTATUS_CACHEFILENAMEAVAILABLE */ + } + + if(!read_report_data) + SET_EXPECT(ReportData); + hres = IInternetProtocolSink_ReportData(filtered_sink, grfBSCF, ulProgress, ulProgressMax); + ok(hres == S_OK, "ReportData failed: %08x\n", hres); + if(!read_report_data) + CHECK_CALLED(ReportData); + + if(!filter_state) + filter_state = 1; + + return S_OK; +} + +static HRESULT WINAPI MimeProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult, + DWORD dwError, LPCWSTR szResult) +{ + HRESULT hres; + + CHECK_EXPECT(MimeFilter_ReportResult); + + ok(hrResult == S_OK, "hrResult = %08x\n", hrResult); + ok(dwError == ERROR_SUCCESS, "dwError = %u\n", dwError); + ok(!szResult, "szResult = %s\n", wine_dbgstr_w(szResult)); + + SET_EXPECT(ReportResult); + hres = IInternetProtocolSink_ReportResult(filtered_sink, hrResult, dwError, szResult); + ok(SUCCEEDED(hres), "ReportResult failed: %08x\n", hres); + CHECK_CALLED(ReportResult); + + return S_OK; +} + +static IInternetProtocolSinkVtbl mime_protocol_sink_vtbl = { + MimeProtocolSink_QueryInterface, + MimeProtocolSink_AddRef, + MimeProtocolSink_Release, + MimeProtocolSink_Switch, + MimeProtocolSink_ReportProgress, + MimeProtocolSink_ReportData, + MimeProtocolSink_ReportResult +}; + +static IInternetProtocolSink mime_protocol_sink = { &mime_protocol_sink_vtbl }; + static HRESULT QueryInterface(REFIID riid, void **ppv) { + static const IID IID_undocumented = {0x58DFC7D0,0x5381,0x43E5,{0x9D,0x72,0x4C,0xDD,0xE4,0xCB,0x0F,0x1A}}; + *ppv = NULL; if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocolSink, riid)) *ppv = &protocol_sink; if(IsEqualGUID(&IID_IServiceProvider, riid)) *ppv = &service_provider; + if(IsEqualGUID(&IID_IUriContainer, riid)) + return E_NOINTERFACE; /* TODO */ + + /* NOTE: IE8 queries for undocumented {58DFC7D0-5381-43E5-9D72-4CDDE4CB0F1A} interface. */ + if(IsEqualGUID(&IID_undocumented, riid)) + return E_NOINTERFACE; if(*ppv) return S_OK; + ok(0, "unexpected call %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } @@ -691,6 +1062,19 @@ static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulS if(pcElFetched) ok(*pcElFetched == 0, "*pcElFetch=%d, expectd 0\n", *pcElFetched); return S_OK; + case BINDSTRING_URL: { + DWORD size; + + CHECK_EXPECT(GetBindString_URL); + ok(cEl == 1, "cEl=%d, expected 1\n", cEl); + ok(*pcElFetched == 0, "*pcElFetch=%d, expectd 0\n", *pcElFetched); + *pcElFetched = 1; + + size = (lstrlenW(binding_urls[tested_protocol])+1)*sizeof(WCHAR); + *ppwzStr = CoTaskMemAlloc(size); + memcpy(*ppwzStr, binding_urls[tested_protocol], size); + return S_OK; + } default: ok(0, "unexpected call\n"); } @@ -749,23 +1133,6 @@ static const IInternetPriorityVtbl InternetPriorityVtbl = { static IInternetPriority InternetPriority = { &InternetPriorityVtbl }; -static HRESULT WINAPI Protocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) -{ - if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) { - *ppv = iface; - return S_OK; - } - - if(IsEqualGUID(&IID_IInternetPriority, riid)) { - *ppv = &InternetPriority; - return S_OK; - } - - ok(0, "unexpected riid %s\n", debugstr_guid(riid)); - *ppv = NULL; - return E_NOINTERFACE; -} - static ULONG WINAPI Protocol_AddRef(IInternetProtocol *iface) { return 2; @@ -776,6 +1143,67 @@ static ULONG WINAPI Protocol_Release(IInternetProtocol *iface) return 1; } +static HRESULT WINAPI Protocol_Abort(IInternetProtocol *iface, HRESULT hrReason, + DWORD dwOptions) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Protocol_Suspend(IInternetProtocol *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Protocol_Resume(IInternetProtocol *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Protocol_Seek(IInternetProtocol *iface, + LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolEmul_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) { + *ppv = iface; + return S_OK; + } + + if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) { + trace("IID_IInternetProtocolEx not supported\n"); + *ppv = NULL; + return E_NOINTERFACE; + } + + if(IsEqualGUID(&IID_IInternetPriority, riid)) { + *ppv = &InternetPriority; + return S_OK; + } + + if(IsEqualGUID(&IID_IWinInetInfo, riid)) { + CHECK_EXPECT(QueryInterface_IWinInetInfo); + *ppv = NULL; + return E_NOINTERFACE; +} + + if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) { + CHECK_EXPECT(QueryInterface_IWinInetHttpInfo); + *ppv = NULL; + return E_NOINTERFACE; +} + + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; +} + static DWORD WINAPI thread_proc(PVOID arg) { HRESULT hres; @@ -808,32 +1236,52 @@ static DWORD WINAPI thread_proc(PVOID arg) CHECK_CALLED(Switch); ok(hres == S_OK, "Switch failed: %08x\n", hres); + if(!short_read) { prot_state = 2; + if(mimefilter_test) + SET_EXPECT(MimeFilter_Switch); + else SET_EXPECT(Switch); hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata); + ok(hres == S_OK, "Switch failed: %08x\n", hres); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_Switch); + else CHECK_CALLED(Switch); - ok(hres == S_OK, "Switch failed: %08x\n", hres); prot_state = 2; + if(mimefilter_test) + SET_EXPECT(MimeFilter_Switch); + else SET_EXPECT(Switch); hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata); + ok(hres == S_OK, "Switch failed: %08x\n", hres); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_Switch); + else CHECK_CALLED(Switch); - ok(hres == S_OK, "Switch failed: %08x\n", hres); prot_state = 3; + if(mimefilter_test) + SET_EXPECT(MimeFilter_Switch); + else SET_EXPECT(Switch); hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata); + ok(hres == S_OK, "Switch failed: %08x\n", hres); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_Switch); + else CHECK_CALLED(Switch); - ok(hres == S_OK, "Switch failed: %08x\n", hres); + } SetEvent(event_complete); return 0; } -static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, +static HRESULT WINAPI ProtocolEmul_Start(IInternetProtocol *iface, LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, - DWORD grfPI, DWORD dwReserved) + DWORD grfPI, HANDLE_PTR dwReserved) { BINDINFO bindinfo, exp_bindinfo; DWORD cbindf = 0; @@ -846,7 +1294,10 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, ok(pOIProtSink != &protocol_sink, "unexpected pOIProtSink\n"); ok(pOIBindInfo != &bind_info, "unexpected pOIBindInfo\n"); ok(!grfPI, "grfPI = %x\n", grfPI); - ok(!dwReserved, "dwReserved = %d\n", dwReserved); + ok(!dwReserved, "dwReserved = %lx\n", dwReserved); + + if(binding_test) + ok(pOIProtSink == binding_sink, "pOIProtSink != binding_sink\n"); memset(&bindinfo, 0, sizeof(bindinfo)); bindinfo.cbSize = sizeof(bindinfo); @@ -865,7 +1316,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, ok(hres == S_OK, "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres); CHECK_CALLED(ReportProgress_SENDINGREQUEST); - if(tested_protocol == HTTP_TEST) { + if(tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST) { IServiceProvider *service_provider; IHttpNegotiate *http_negotiate; IHttpNegotiate2 *http_negotiate2; @@ -873,6 +1324,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, LPWSTR additional_headers = NULL; BYTE sec_id[100]; DWORD fetched = 0, size = 100; + DWORD tid; SET_EXPECT(GetBindString_USER_AGENT); hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_USER_AGENT, @@ -881,7 +1333,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, ok(hres == S_OK, "GetBindString(BINDSTRING_USER_AGETNT) failed: %08x\n", hres); ok(fetched == 1, "fetched = %d, expected 254\n", fetched); ok(ua != NULL, "ua = %p\n", ua); - ok(!lstrcmpW(ua, user_agentW), "unexpected user agent %s\n", debugstr_w(ua)); + ok(!strcmp_ww(ua, user_agentW), "unexpected user agent %s\n", wine_dbgstr_w(ua)); CoTaskMemFree(ua); fetched = 256; @@ -893,7 +1345,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, ok(hres == S_OK, "GetBindString(BINDSTRING_ACCEPT_MIMES) failed: %08x\n", hres); ok(fetched == 1, "fetched = %d, expected 1\n", fetched); - ok(!lstrcmpW(acc_mimeW, accept_mimes[0]), "unexpected mimes %s\n", debugstr_w(accept_mimes[0])); + ok(!strcmp_ww(acc_mimeW, accept_mimes[0]), "unexpected mimes %s\n", wine_dbgstr_w(accept_mimes[0])); hres = IInternetBindInfo_QueryInterface(pOIBindInfo, &IID_IServiceProvider, (void**)&service_provider); @@ -929,7 +1381,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, IServiceProvider_Release(service_provider); - CreateThread(NULL, 0, thread_proc, NULL, 0, NULL); + CreateThread(NULL, 0, thread_proc, NULL, 0, &tid); return S_OK; } @@ -940,17 +1392,35 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres); CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE); + if(mimefilter_test) { + SET_EXPECT(MimeFilter_CreateInstance); + SET_EXPECT(MimeFilter_Start); + SET_EXPECT(ReportProgress_LOADINGMIMEHANDLER); + } SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, - expect_wsz = text_htmlW); + mimefilter_test ? gzipW : (expect_wsz = text_htmlW)); ok(hres == S_OK, "ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE) failed: %08x\n", hres); + if(mimefilter_test) { + CHECK_CALLED(MimeFilter_CreateInstance); + CHECK_CALLED(MimeFilter_Start); + CHECK_CALLED(ReportProgress_LOADINGMIMEHANDLER); + todo_wine CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + }else { CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + } + if(mimefilter_test) + SET_EXPECT(MimeFilter_ReportData); + else SET_EXPECT(ReportData); hres = IInternetProtocolSink_ReportData(pOIProtSink, BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION, 13, 13); ok(hres == S_OK, "ReportData failed: %08x\n", hres); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_ReportData); + else CHECK_CALLED(ReportData); if(tested_protocol == BIND_TEST) { @@ -958,18 +1428,24 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, ok(hres == E_FAIL, "Termiante failed: %08x\n", hres); } + if(mimefilter_test) + SET_EXPECT(MimeFilter_ReportResult); + else SET_EXPECT(ReportResult); hres = IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL); ok(hres == S_OK, "ReportResult failed: %08x\n", hres); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_ReportResult); + else CHECK_CALLED(ReportResult); return S_OK; } -static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface, +static HRESULT WINAPI ProtocolEmul_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) { - DWORD bscf = 0; + DWORD bscf = 0, pr; HRESULT hres; CHECK_EXPECT(Continue); @@ -977,6 +1453,17 @@ static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface, ok(pProtocolData != NULL, "pProtocolData == NULL\n"); if(!pProtocolData || tested_protocol == BIND_TEST) return S_OK; + if(binding_test) { + ok(pProtocolData != &protocoldata, "pProtocolData == &protocoldata\n"); + ok(pProtocolData->grfFlags == protocoldata.grfFlags, "grfFlags wrong %x/%x\n", + pProtocolData->grfFlags, protocoldata.grfFlags ); + ok(pProtocolData->dwState == protocoldata.dwState, "dwState wrong %x/%x\n", + pProtocolData->dwState, protocoldata.dwState ); + ok(pProtocolData->pData == protocoldata.pData, "pData wrong %p/%p\n", + pProtocolData->pData, protocoldata.pData ); + ok(pProtocolData->cbData == protocoldata.cbData, "cbData wrong %x/%x\n", + pProtocolData->cbData, protocoldata.cbData ); + } switch(prot_state) { case 1: { @@ -1002,10 +1489,22 @@ static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface, IHttpNegotiate_Release(http_negotiate); ok(hres == S_OK, "OnResponse failed: %08x\n", hres); + if(mimefilter_test) { + SET_EXPECT(MimeFilter_CreateInstance); + SET_EXPECT(MimeFilter_Start); + SET_EXPECT(ReportProgress_LOADINGMIMEHANDLER); + }else if(!(pi & PI_MIMEVERIFICATION)) { SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + } hres = IInternetProtocolSink_ReportProgress(binding_sink, - BINDSTATUS_MIMETYPEAVAILABLE, text_htmlW); + BINDSTATUS_MIMETYPEAVAILABLE, mimefilter_test ? gzipW : text_htmlW); + if(mimefilter_test) { + CHECK_CALLED(MimeFilter_CreateInstance); + CHECK_CALLED(MimeFilter_Start); + CHECK_CALLED(ReportProgress_LOADINGMIMEHANDLER); + }else if(!(pi & PI_MIMEVERIFICATION)) { CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + } ok(hres == S_OK, "ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE) failed: %08x\n", hres); @@ -1018,111 +1517,368 @@ static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface, break; } + pr = prot_read; + if(mimefilter_test) { + SET_EXPECT(MimeFilter_ReportData); + }else if(pi & PI_MIMEVERIFICATION) { + if(pr < 200) + SET_EXPECT(Read); /* checked in ReportData for short_read */ + if(pr == 200) { + if(!mimefilter_test) + SET_EXPECT(Read); /* checked in BINDSTATUS_MIMETYPEAVAILABLE or ReportData */ + SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + } + if(pr >= 200) SET_EXPECT(ReportData); - hres = IInternetProtocolSink_ReportData(binding_sink, bscf, 100, 400); - CHECK_CALLED(ReportData); + }else { + SET_EXPECT(ReportData); + } + + hres = IInternetProtocolSink_ReportData(binding_sink, bscf, pr, 400); ok(hres == S_OK, "ReportData failed: %08x\n", hres); + if(mimefilter_test) { + SET_EXPECT(MimeFilter_ReportData); + }else if(pi & PI_MIMEVERIFICATION) { + if(!short_read && pr < 200) + CHECK_CALLED(Read); + if(pr == 200) { + CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + } + }else { + CHECK_CALLED(ReportData); + } + if(prot_state == 3) prot_state = 4; return S_OK; } -static HRESULT WINAPI Protocol_Abort(IInternetProtocol *iface, HRESULT hrReason, - DWORD dwOptions) -{ - ok(0, "unexpected call\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI Protocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) +static HRESULT WINAPI ProtocolEmul_Terminate(IInternetProtocol *iface, DWORD dwOptions) { CHECK_EXPECT(Terminate); ok(!dwOptions, "dwOptions=%d\n", dwOptions); return S_OK; } -static HRESULT WINAPI Protocol_Suspend(IInternetProtocol *iface) -{ - ok(0, "unexpected call\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI Protocol_Resume(IInternetProtocol *iface) -{ - ok(0, "unexpected call\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv, +static HRESULT WINAPI ProtocolEmul_Read(IInternetProtocol *iface, void *pv, ULONG cb, ULONG *pcbRead) { - static BOOL b = TRUE; + if(read_report_data) + CHECK_EXPECT2(Read2); + if(mimefilter_test || short_read) { + if(!read_report_data) + CHECK_EXPECT2(Read); + }else if((pi & PI_MIMEVERIFICATION)) { + if(!read_report_data) + CHECK_EXPECT2(Read); + + if(prot_read < 300) { + ok(pv != expect_pv, "pv == expect_pv\n"); + if(prot_read < 300) + ok(cb == 2048-prot_read, "cb=%d\n", cb); + else + ok(cb == 700, "cb=%d\n", cb); + }else { + ok(expect_pv <= pv && (BYTE*)pv < (BYTE*)expect_pv + cb, "pv != expect_pv\n"); +} + }else { + if(!read_report_data) CHECK_EXPECT(Read); ok(pv == expect_pv, "pv != expect_pv\n"); ok(cb == 1000, "cb=%d\n", cb); + ok(!*pcbRead, "*pcbRead = %d\n", *pcbRead); + } ok(pcbRead != NULL, "pcbRead == NULL\n"); - ok(!*pcbRead, "*pcbRead = %d\n", *pcbRead); - if(prot_state == 3) { + if(prot_state == 3 || (short_read && prot_state != 4)) { HRESULT hres; + prot_state = 4; + if(short_read) { + SET_EXPECT(Read2); /* checked in BINDSTATUS_MIMETYPEAVAILABLE */ + SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + } + if(mimefilter_test) + SET_EXPECT(MimeFilter_ReportData); + else if(direct_read) + SET_EXPECT(ReportData2); + read_report_data++; + hres = IInternetProtocolSink_ReportData(binding_sink, + BSCF_LASTDATANOTIFICATION|BSCF_INTERMEDIATEDATANOTIFICATION, 0, 0); + read_report_data--; + ok(hres == S_OK, "ReportData failed: %08x\n", hres); + if(short_read) + CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_ReportData); + else if(direct_read) + CHECK_CALLED(ReportData2); + + if(mimefilter_test) + SET_EXPECT(MimeFilter_ReportResult); + else SET_EXPECT(ReportResult); hres = IInternetProtocolSink_ReportResult(binding_sink, S_OK, ERROR_SUCCESS, NULL); + ok(hres == S_OK, "ReportResult failed: %08x\n", hres); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_ReportResult); + else CHECK_CALLED(ReportResult); + memset(pv, 'x', 100); + prot_read += *pcbRead = 100; + return S_OK; + }if(prot_state == 4) { + *pcbRead = 0; return S_FALSE; } - if((b = !b)) - return tested_protocol == HTTP_TEST ? E_PENDING : S_FALSE; + if((async_read_pending = !async_read_pending)) { + *pcbRead = 0; + return tested_protocol == HTTP_TEST || tested_protocol == HTTPS_TEST ? E_PENDING : S_FALSE; + } memset(pv, 'x', 100); prot_read += *pcbRead = 100; return S_OK; } -static HRESULT WINAPI Protocol_Seek(IInternetProtocol *iface, - LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) -{ - ok(0, "unexpected call\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI Protocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) +static HRESULT WINAPI ProtocolEmul_LockRequest(IInternetProtocol *iface, DWORD dwOptions) { CHECK_EXPECT(LockRequest); ok(dwOptions == 0, "dwOptions=%x\n", dwOptions); return S_OK; } -static HRESULT WINAPI Protocol_UnlockRequest(IInternetProtocol *iface) +static HRESULT WINAPI ProtocolEmul_UnlockRequest(IInternetProtocol *iface) { CHECK_EXPECT(UnlockRequest); return S_OK; } static const IInternetProtocolVtbl ProtocolVtbl = { - Protocol_QueryInterface, + ProtocolEmul_QueryInterface, Protocol_AddRef, Protocol_Release, - Protocol_Start, - Protocol_Continue, + ProtocolEmul_Start, + ProtocolEmul_Continue, Protocol_Abort, - Protocol_Terminate, + ProtocolEmul_Terminate, Protocol_Suspend, Protocol_Resume, - Protocol_Read, + ProtocolEmul_Read, Protocol_Seek, - Protocol_LockRequest, - Protocol_UnlockRequest + ProtocolEmul_LockRequest, + ProtocolEmul_UnlockRequest }; static IInternetProtocol Protocol = { &ProtocolVtbl }; +static HRESULT WINAPI MimeProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) { + *ppv = iface; + return S_OK; + } + + if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) { + *ppv = &mime_protocol_sink; + return S_OK; + } + + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static HRESULT WINAPI MimeProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, + IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, + DWORD grfPI, HANDLE_PTR dwReserved) +{ + PROTOCOLFILTERDATA *data; + LPOLESTR url_str = NULL; + DWORD fetched = 0; + BINDINFO bindinfo; + DWORD cbindf = 0; + HRESULT hres; + + CHECK_EXPECT(MimeFilter_Start); + + ok(!strcmp_ww(szUrl, gzipW), "wrong url %s\n", wine_dbgstr_w(szUrl)); + ok(grfPI == (PI_FILTER_MODE|PI_FORCE_ASYNC), "grfPI=%x, expected PI_FILTER_MODE|PI_FORCE_ASYNC\n", grfPI); + ok(dwReserved, "dwReserved == 0\n"); + ok(pOIProtSink != NULL, "pOIProtSink == NULL\n"); + ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n"); + + if(binding_test) { + ok(pOIProtSink != binding_sink, "pOIProtSink == protocol_sink\n"); + ok(pOIBindInfo == prot_bind_info, "pOIBindInfo != bind_info\n"); + }else { + ok(pOIProtSink == &protocol_sink, "pOIProtSink != protocol_sink\n"); + ok(pOIBindInfo == &bind_info, "pOIBindInfo != bind_info\n"); + } + + data = (void*)dwReserved; + ok(data->cbSize == sizeof(*data), "data->cbSize = %d\n", data->cbSize); + ok(!data->pProtocolSink, "data->pProtocolSink != NULL\n"); + ok(data->pProtocol != NULL, "data->pProtocol == NULL\n"); + ok(!data->pUnk, "data->pUnk != NULL\n"); + ok(!data->dwFilterFlags, "data->dwProtocolFlags = %x\n", data->dwFilterFlags); + if(binding_test) { + IInternetProtocolSink *prot_sink; + + IInternetProtocol_QueryInterface(data->pProtocol, &IID_IInternetProtocolSink, (void**)&prot_sink); + ok(prot_sink == pOIProtSink, "QI(data->pProtocol, IID_IInternetProtocolSink) != pOIProtSink\n"); + IInternetProtocolSink_Release(prot_sink); + + ok(data->pProtocol != binding_protocol, "data->pProtocol == binding_protocol\n"); + + filtered_protocol = data->pProtocol; + IInternetProtocol_AddRef(filtered_protocol); + }else { + IInternetProtocol *prot; + + IInternetProtocol_QueryInterface(data->pProtocol, &IID_IInternetProtocol, (void**)&prot); + ok(prot == async_protocol, "QI(data->pProtocol, IID_IInternetProtocol) != async_protocol\n"); + IInternetProtocol_Release(prot); + + ok(data->pProtocol != async_protocol, "data->pProtocol == async_protocol\n"); + } + + filtered_sink = pOIProtSink; + + SET_EXPECT(ReportProgress_DECODING); + hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DECODING, gzipW); + ok(hres == S_OK, "ReportProgress(BINDSTATUS_DECODING) failed: %08x\n", hres); + CHECK_CALLED(ReportProgress_DECODING); + + SET_EXPECT(GetBindInfo); + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(bindinfo); + hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &cbindf, &bindinfo); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + ok(cbindf == (bindf|BINDF_FROMURLMON), "cbindf = %x, expected %x\n", cbindf, bindf); + CHECK_CALLED(GetBindInfo); + + SET_EXPECT(GetBindString_URL); + hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_URL, &url_str, 1, &fetched); + ok(hres == S_OK, "GetBindString(BINDSTRING_URL) failed: %08x\n", hres); + ok(fetched == 1, "fetched = %d\n", fetched); + ok(!strcmp_ww(url_str, binding_urls[tested_protocol]), "wrong url_str %s\n", wine_dbgstr_w(url_str)); + CoTaskMemFree(url_str); + CHECK_CALLED(GetBindString_URL); + + return S_OK; +} + +static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface, + PROTOCOLDATA *pProtocolData) +{ + CHECK_EXPECT(MimeFilter_Continue); + return E_NOTIMPL; +} + +static HRESULT WINAPI MimeProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) +{ + HRESULT hres; + + CHECK_EXPECT(MimeFilter_Terminate); + + ok(!dwOptions, "dwOptions = %x\n", dwOptions); + + SET_EXPECT(Terminate); + hres = IInternetProtocol_Terminate(filtered_protocol, dwOptions); + ok(hres == S_OK, "Terminate failed: %08x\n", hres); + CHECK_CALLED(Terminate); + + return S_OK; +} + +static HRESULT WINAPI MimeProtocol_Read(IInternetProtocol *iface, void *pv, + ULONG cb, ULONG *pcbRead) +{ + BYTE buf[2096]; + DWORD read = 0; + HRESULT hres; + + CHECK_EXPECT(MimeFilter_Read); + + ok(pv != NULL, "pv == NULL\n"); + ok(cb != 0, "cb == 0\n"); + ok(pcbRead != NULL, "pcbRead == NULL\n"); + + if(read_report_data) + SET_EXPECT(Read2); + else + SET_EXPECT(Read); + hres = IInternetProtocol_Read(filtered_protocol, buf, sizeof(buf), &read); + ok(hres == S_OK || hres == S_FALSE || hres == E_PENDING, "Read failed: %08x\n", hres); + if(read_report_data) + CHECK_CALLED(Read2); + else + CHECK_CALLED(Read); + + if(pcbRead) { + ok(*pcbRead == 0, "*pcbRead=%d, expected 0\n", *pcbRead); + *pcbRead = read; + } + + memset(pv, 'x', read); + return hres; +} + +static HRESULT WINAPI MimeProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) +{ + HRESULT hres; + + CHECK_EXPECT(MimeFilter_LockRequest); + + ok(!dwOptions, "dwOptions = %x\n", dwOptions); + + SET_EXPECT(LockRequest); + hres = IInternetProtocol_LockRequest(filtered_protocol, dwOptions); + ok(hres == S_OK, "LockRequest failed: %08x\n", hres); + CHECK_CALLED(LockRequest); + + return S_OK; +} + +static HRESULT WINAPI MimeProtocol_UnlockRequest(IInternetProtocol *iface) +{ + HRESULT hres; + + CHECK_EXPECT(MimeFilter_UnlockRequest); + + SET_EXPECT(UnlockRequest); + hres = IInternetProtocol_UnlockRequest(filtered_protocol); + ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); + CHECK_CALLED(UnlockRequest); + + return S_OK; +} + +static const IInternetProtocolVtbl MimeProtocolVtbl = { + MimeProtocol_QueryInterface, + Protocol_AddRef, + Protocol_Release, + MimeProtocol_Start, + Protocol_Continue, + Protocol_Abort, + MimeProtocol_Terminate, + Protocol_Suspend, + Protocol_Resume, + MimeProtocol_Read, + Protocol_Seek, + MimeProtocol_LockRequest, + MimeProtocol_UnlockRequest +}; + +static IInternetProtocol MimeProtocol = { &MimeProtocolVtbl }; + static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { ok(0, "unexpected call\n"); @@ -1168,6 +1924,61 @@ static const IClassFactoryVtbl ClassFactoryVtbl = { static IClassFactory ClassFactory = { &ClassFactoryVtbl }; +static HRESULT WINAPI MimeFilter_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) +{ + CHECK_EXPECT(MimeFilter_CreateInstance); + + ok(!outer, "outer = %p\n", outer); + ok(IsEqualGUID(&IID_IInternetProtocol, riid), "unexpected riid %s\n", debugstr_guid(riid)); + + *ppv = &MimeProtocol; + return S_OK; +} + +static const IClassFactoryVtbl MimeFilterCFVtbl = { + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + MimeFilter_CreateInstance, + ClassFactory_LockServer +}; + +static IClassFactory mimefilter_cf = { &MimeFilterCFVtbl }; + +#define TEST_BINDING 0x01 +#define TEST_FILTER 0x02 +#define TEST_FIRST_HTTP 0x04 +#define TEST_DIRECT_READ 0x08 +#define TEST_POST 0x10 +#define TEST_EMULATEPROT 0x20 +#define TEST_SHORT_READ 0x40 + +static void init_test(int prot, DWORD flags) +{ + tested_protocol = prot; + binding_test = (flags & TEST_BINDING) != 0; + first_data_notif = TRUE; + prot_read = 0; + prot_state = 0; + async_read_pending = TRUE; + mimefilter_test = (flags & TEST_FILTER) != 0; + filter_state = 0; + ResetEvent(event_complete); + ResetEvent(event_complete2); + ResetEvent(event_continue); + ResetEvent(event_continue_done); + async_protocol = binding_protocol = filtered_protocol = NULL; + filtered_sink = NULL; + http_is_first = (flags & TEST_FIRST_HTTP) != 0; + first_data_notif = TRUE; + state = 0; + direct_read = (flags & TEST_DIRECT_READ) != 0; + http_post_test = (flags & TEST_POST) != 0; + emulate_prot = (flags & TEST_EMULATEPROT) != 0; + wait_for_switch = TRUE; + short_read = (flags & TEST_SHORT_READ) != 0; +} + static void test_priority(IInternetProtocol *protocol) { IInternetPriority *priority; @@ -1194,7 +2005,7 @@ static void test_priority(IInternetProtocol *protocol) IInternetPriority_Release(priority); } -static void file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL is_first) +static BOOL file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL is_first) { HRESULT hres; @@ -1216,6 +2027,10 @@ static void file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL i expect_hrResult = S_OK; hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0); + if(hres == INET_E_RESOURCE_NOT_FOUND) { + win_skip("Start failed\n"); + return FALSE; + } ok(hres == S_OK, "Start failed: %08x\n", hres); CHECK_CALLED(GetBindInfo); @@ -1232,6 +2047,8 @@ static void file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL i CHECK_CALLED(ReportData); if(is_first) CHECK_CALLED(ReportResult); + + return TRUE; } static void test_file_protocol_url(LPCWSTR url) @@ -1244,7 +2061,7 @@ static void test_file_protocol_url(LPCWSTR url) hres = CoGetClassObject(&CLSID_FileProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres); - if(!SUCCEEDED(hres)) + if(FAILED(hres)) return; hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); @@ -1261,7 +2078,7 @@ static void test_file_protocol_url(LPCWSTR url) ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); if(SUCCEEDED(hres)) { - file_protocol_start(protocol, url, TRUE); + if(file_protocol_start(protocol, url, TRUE)) { hres = IInternetProtocol_Read(protocol, buf, 2, &cb); ok(hres == S_OK, "Read failed: %08x\n", hres); ok(cb == 2, "cb=%u expected 2\n", cb); @@ -1272,14 +2089,16 @@ static void test_file_protocol_url(LPCWSTR url) ok(cb == 0, "cb=%u expected 0\n", cb); hres = IInternetProtocol_UnlockRequest(protocol); ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); + } - file_protocol_start(protocol, url, FALSE); + if(file_protocol_start(protocol, url, FALSE)) { hres = IInternetProtocol_Read(protocol, buf, 2, &cb); ok(hres == S_FALSE, "Read failed: %08x\n", hres); hres = IInternetProtocol_LockRequest(protocol, 0); ok(hres == S_OK, "LockRequest failed: %08x\n", hres); hres = IInternetProtocol_UnlockRequest(protocol); ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); + } IInternetProtocol_Release(protocol); } @@ -1288,7 +2107,7 @@ static void test_file_protocol_url(LPCWSTR url) ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); if(SUCCEEDED(hres)) { - file_protocol_start(protocol, url, TRUE); + if(file_protocol_start(protocol, url, TRUE)) { hres = IInternetProtocol_LockRequest(protocol, 0); ok(hres == S_OK, "LockRequest failed: %08x\n", hres); hres = IInternetProtocol_Terminate(protocol, 0); @@ -1301,6 +2120,7 @@ static void test_file_protocol_url(LPCWSTR url) ok(hres == S_OK, "Read failed: %08x\n", hres); hres = IInternetProtocol_Terminate(protocol, 0); ok(hres == S_OK, "Terminate failed: %08x\n", hres); + } IInternetProtocol_Release(protocol); } @@ -1309,12 +2129,13 @@ static void test_file_protocol_url(LPCWSTR url) ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); if(SUCCEEDED(hres)) { - file_protocol_start(protocol, url, TRUE); + if(file_protocol_start(protocol, url, TRUE)) { hres = IInternetProtocol_Terminate(protocol, 0); ok(hres == S_OK, "Terminate failed: %08x\n", hres); hres = IInternetProtocol_Read(protocol, buf, 2, &cb); ok(hres == S_OK, "Read failed: %08x\n", hres); ok(cb == 2, "cb=%u expected 2\n", cb); + } IInternetProtocol_Release(protocol); } @@ -1411,10 +2232,16 @@ static void test_file_protocol(void) { static const char html_doc[] = ""; trace("Testing file protocol...\n"); - tested_protocol = FILE_TEST; + init_test(FILE_TEST, 0); + SetLastError(0xdeadbeef); file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(!file && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Detected Win9x or WinMe\n"); + return; + } ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n"); if(file == INVALID_HANDLE_VALUE) return; @@ -1475,17 +2302,15 @@ static void test_file_protocol(void) { test_file_protocol_fail(); } -static BOOL http_protocol_start(LPCWSTR url, BOOL is_first) +static BOOL http_protocol_start(LPCWSTR url) { static BOOL got_user_agent = FALSE; HRESULT hres; - first_data_notif = TRUE; - state = 0; - SET_EXPECT(GetBindInfo); if (!(bindf & BINDF_FROMURLMON)) SET_EXPECT(ReportProgress_DIRECTBIND); + if(!got_user_agent) SET_EXPECT(GetBindString_USER_AGENT); SET_EXPECT(GetBindString_ACCEPT_MIMES); SET_EXPECT(QueryService_HttpNegotiate); @@ -1494,7 +2319,7 @@ static BOOL http_protocol_start(LPCWSTR url, BOOL is_first) if (http_post_test) SET_EXPECT(GetBindString_POST_COOKIE); - hres = IInternetProtocol_Start(http_protocol, url, &protocol_sink, &bind_info, 0, 0); + hres = IInternetProtocol_Start(async_protocol, url, &protocol_sink, &bind_info, 0, 0); ok(hres == S_OK, "Start failed: %08x\n", hres); if(FAILED(hres)) return FALSE; @@ -1507,11 +2332,6 @@ static BOOL http_protocol_start(LPCWSTR url, BOOL is_first) CHECK_CALLED(GetBindString_USER_AGENT); got_user_agent = TRUE; } - else todo_wine - { - /* user agent only retrieved once, even with different URLs */ - CHECK_NOT_CALLED(GetBindString_USER_AGENT); - } CHECK_CALLED(GetBindString_ACCEPT_MIMES); CHECK_CALLED(QueryService_HttpNegotiate); CHECK_CALLED(BeginningTransaction); @@ -1523,21 +2343,64 @@ static BOOL http_protocol_start(LPCWSTR url, BOOL is_first) return TRUE; } +static void test_protocol_terminate(IInternetProtocol *protocol) +{ + BYTE buf[3600]; + DWORD cb; + HRESULT hres; + + hres = IInternetProtocol_LockRequest(protocol, 0); + ok(hres == S_OK, "LockRequest failed: %08x\n", hres); + + hres = IInternetProtocol_Read(protocol, buf, 1, &cb); + ok(hres == S_FALSE, "Read failed: %08x\n", hres); + + hres = IInternetProtocol_Terminate(protocol, 0); + ok(hres == S_OK, "Terminate failed: %08x\n", hres); + + /* This wait is to give the internet handles being freed in Terminate + * enough time to actually terminate in all cases. Internet handles + * terminate asynchronously and native reuses the main InternetOpen + * handle. The only case in which this seems to be necessary is on + * wine with native wininet and urlmon, resulting in the next time + * test_http_protocol_url being called the first data notification actually + * being an extra last data notification from the previous connection + * about once out of every ten times. */ + Sleep(100); + + hres = IInternetProtocol_UnlockRequest(protocol); + ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); +} + +static void test_http_info(IInternetProtocol *protocol) +{ + IWinInetHttpInfo *info; + HRESULT hres; + + hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetHttpInfo, (void**)&info); + ok(hres == S_OK, "Could not get IWinInterHttpInfo iface: %08x\n", hres); + + /* TODO */ + + IWinInetHttpInfo_Release(info); +} + /* is_first refers to whether this is the first call to this function * _for this url_ */ -static void test_http_protocol_url(LPCWSTR url, BOOL is_first) +static void test_http_protocol_url(LPCWSTR url, int prot, DWORD flags) { IInternetProtocolInfo *protocol_info; IClassFactory *factory; IUnknown *unk; HRESULT hres; + init_test(prot, flags); http_url = url; - http_is_first = is_first; - hres = CoGetClassObject(&CLSID_HttpProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); + hres = CoGetClassObject(prot == HTTPS_TEST ? &CLSID_HttpSProtocol : &CLSID_HttpProtocol, + CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres); - if(!SUCCEEDED(hres)) + if(FAILED(hres)) return; hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); @@ -1552,18 +2415,25 @@ static void test_http_protocol_url(LPCWSTR url, BOOL is_first) return; hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, - (void**)&http_protocol); + (void**)&async_protocol); ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); if(SUCCEEDED(hres)) { BYTE buf[3600]; DWORD cb; - int *called = (bindf & BINDF_FROMURLMON) ? &called_Switch : &called_ReportData; + ULONG ref; - test_priority(http_protocol); + test_priority(async_protocol); + test_http_info(async_protocol); + SET_EXPECT(ReportProgress_COOKIE_SENT); SET_EXPECT(ReportProgress_FINDINGRESOURCE); SET_EXPECT(ReportProgress_CONNECTING); SET_EXPECT(ReportProgress_SENDINGREQUEST); + SET_EXPECT(ReportProgress_PROXYDETECTING); + if(prot == HTTP_TEST) + SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); + else + SET_EXPECT(QueryService_HttpSecurity); if(!(bindf & BINDF_FROMURLMON)) { SET_EXPECT(OnResponse); SET_EXPECT(ReportProgress_RAWMIMETYPE); @@ -1572,32 +2442,44 @@ static void test_http_protocol_url(LPCWSTR url, BOOL is_first) SET_EXPECT(Switch); } - if(!http_protocol_start(url, is_first)) + if(!http_protocol_start(url)) return; + if(!direct_read) SET_EXPECT(ReportResult); expect_hrResult = S_OK; - hres = IInternetProtocol_Read(http_protocol, buf, 1, &cb); - ok((!*called && hres == E_PENDING && cb==0) || - (*called && hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb); + if(direct_read) { + while(wait_for_switch) { + SET_EXPECT(Switch); + WaitForSingleObject(event_continue, INFINITE); + CHECK_CALLED(Switch); + call_continue(&continue_protdata); + SetEvent(event_continue_done); + } + }else { + hres = IInternetProtocol_Read(async_protocol, buf, 1, &cb); + ok((hres == E_PENDING && cb==0) || + (hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb); WaitForSingleObject(event_complete, INFINITE); if(bindf & BINDF_FROMURLMON) CHECK_CALLED(Switch); else CHECK_CALLED(ReportData); + if(prot == HTTPS_TEST) + CLEAR_CALLED(QueryService_HttpSecurity); while(1) { if(bindf & BINDF_FROMURLMON) SET_EXPECT(Switch); else SET_EXPECT(ReportData); - hres = IInternetProtocol_Read(http_protocol, buf, sizeof(buf), &cb); + hres = IInternetProtocol_Read(async_protocol, buf, sizeof(buf), &cb); if(hres == E_PENDING) { - hres = IInternetProtocol_Read(http_protocol, buf, 1, &cb); - ok((!*called && hres == E_PENDING && cb==0) || - (*called && hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb); + hres = IInternetProtocol_Read(async_protocol, buf, 1, &cb); + ok((hres == E_PENDING && cb==0) || + (hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb); WaitForSingleObject(event_complete, INFINITE); if(bindf & BINDF_FROMURLMON) CHECK_CALLED(Switch); @@ -1613,30 +2495,13 @@ static void test_http_protocol_url(LPCWSTR url, BOOL is_first) } ok(hres == S_FALSE, "Read failed: %08x\n", hres); CHECK_CALLED(ReportResult); + } + if(prot == HTTPS_TEST) + CLEAR_CALLED(ReportProgress_SENDINGREQUEST); - hres = IInternetProtocol_LockRequest(http_protocol, 0); - ok(hres == S_OK, "LockRequest failed: %08x\n", hres); - - hres = IInternetProtocol_Read(http_protocol, buf, 1, &cb); - ok(hres == S_FALSE, "Read failed: %08x\n", hres); - - hres = IInternetProtocol_Terminate(http_protocol, 0); - ok(hres == S_OK, "Terminate failed: %08x\n", hres); - - /* This wait is to give the internet handles being freed in Terminate - * enough time to actually terminate in all cases. Internet handles - * terminate asynchronously and native reuses the main InternetOpen - * handle. The only case in which this seems to be necessary is on - * wine with native wininet and urlmon, resulting in the next time - * test_http_protocol_url being called the first data notification actually - * being an extra last data notification from the previous connection - * about once out of every ten times. */ - Sleep(100); - - hres = IInternetProtocol_UnlockRequest(http_protocol); - ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); - - IInternetProtocol_Release(http_protocol); + test_protocol_terminate(async_protocol); + ref = IInternetProtocol_Release(async_protocol); + ok(!ref, "ref=%x\n", hres); } IClassFactory_Release(factory); @@ -1653,25 +2518,154 @@ static void test_http_protocol(void) 'p','o','s','t','t','e','s','t','.','p','h','p',0}; trace("Testing http protocol (not from urlmon)...\n"); - tested_protocol = HTTP_TEST; bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; - test_http_protocol_url(winehq_url, TRUE); + test_http_protocol_url(winehq_url, HTTP_TEST, TEST_FIRST_HTTP); trace("Testing http protocol (from urlmon)...\n"); bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON; - test_http_protocol_url(winehq_url, FALSE); + test_http_protocol_url(winehq_url, HTTP_TEST, 0); trace("Testing http protocol (to file)...\n"); bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NEEDFILE; - test_http_protocol_url(winehq_url, FALSE); + test_http_protocol_url(winehq_url, HTTP_TEST, 0); trace("Testing http protocol (post data)...\n"); - http_post_test = TRUE; /* Without this flag we get a ReportProgress_CACHEFILENAMEAVAILABLE * notification with BINDVERB_POST */ bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE; - test_http_protocol_url(posttest_url, TRUE); - http_post_test = FALSE; + test_http_protocol_url(posttest_url, HTTP_TEST, TEST_FIRST_HTTP|TEST_POST); + + trace("Testing http protocol (direct read)...\n"); + bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON; + test_http_protocol_url(winehq_url, HTTP_TEST, TEST_DIRECT_READ); +} + +static void test_https_protocol(void) +{ + static const WCHAR codeweavers_url[] = + {'h','t','t','p','s',':','/','/','w','w','w','.','c','o','d','e','w','e','a','v','e','r','s', + '.','c','o','m','/','t','e','s','t','.','h','t','m','l',0}; + + trace("Testing https protocol (from urlmon)...\n"); + bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE; + test_http_protocol_url(codeweavers_url, HTTPS_TEST, TEST_FIRST_HTTP); +} + + +static void test_ftp_protocol(void) +{ + IInternetProtocolInfo *protocol_info; + IClassFactory *factory; + IUnknown *unk; + BYTE buf[4096]; + ULONG ref; + DWORD cb; + HRESULT hres; + + static const WCHAR ftp_urlW[] = {'f','t','p',':','/','/','f','t','p','.','w','i','n','e','h','q','.','o','r','g', + '/','p','u','b','/','o','t','h','e','r','/', + 'w','i','n','e','l','o','g','o','.','x','c','f','.','t','a','r','.','b','z','2',0}; + + trace("Testing ftp protocol...\n"); + + bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE; + state = 0; + tested_protocol = FTP_TEST; + first_data_notif = TRUE; + expect_hrResult = E_PENDING; + + hres = CoGetClassObject(&CLSID_FtpProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); + ok(hres == E_NOINTERFACE, "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n", hres); + + hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory); + ok(hres == S_OK, "Could not get IClassFactory interface\n"); + IUnknown_Release(unk); + if(FAILED(hres)) + return; + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, + (void**)&async_protocol); + IClassFactory_Release(factory); + ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); + + test_priority(async_protocol); + test_http_info(async_protocol); + + SET_EXPECT(GetBindInfo); + SET_EXPECT(ReportProgress_FINDINGRESOURCE); + SET_EXPECT(ReportProgress_CONNECTING); + SET_EXPECT(ReportProgress_SENDINGREQUEST); + SET_EXPECT(Switch); + + hres = IInternetProtocol_Start(async_protocol, ftp_urlW, &protocol_sink, &bind_info, 0, 0); + ok(hres == S_OK, "Start failed: %08x\n", hres); + CHECK_CALLED(GetBindInfo); + + SET_EXPECT(ReportResult); + + hres = IInternetProtocol_Read(async_protocol, buf, 1, &cb); + ok((hres == E_PENDING && cb==0) || + (hres == S_OK && cb==1), "Read failed: %08x (%d bytes)\n", hres, cb); + + WaitForSingleObject(event_complete, INFINITE); + + while(1) { + + hres = IInternetProtocol_Read(async_protocol, buf, sizeof(buf), &cb); + if(hres == E_PENDING) + WaitForSingleObject(event_complete, INFINITE); + else + if(cb == 0) break; + } + + ok(hres == S_FALSE, "Read failed: %08x\n", hres); + CHECK_CALLED(ReportResult); + CHECK_CALLED(Switch); + + test_protocol_terminate(async_protocol); + + ref = IInternetProtocol_Release(async_protocol); + ok(!ref, "ref=%d\n", ref); +} + +static void test_gopher_protocol(void) +{ + IInternetProtocolInfo *protocol_info; + IClassFactory *factory; + IUnknown *unk; + HRESULT hres; + + trace("Testing gopher protocol...\n"); + + hres = CoGetClassObject(&CLSID_GopherProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); + ok(hres == S_OK || + hres == REGDB_E_CLASSNOTREG, /* Gopher protocol has been removed as of Vista */ + "CoGetClassObject failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); + ok(hres == E_NOINTERFACE, "Could not get IInternetProtocolInfo interface: %08x, expected E_NOINTERFACE\n", hres); + + hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory); + ok(hres == S_OK, "Could not get IClassFactory interface\n"); + IUnknown_Release(unk); + if(FAILED(hres)) + return; + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, + (void**)&async_protocol); + IClassFactory_Release(factory); + ok(hres == S_OK, "Could not get IInternetProtocol: %08x\n", hres); + + test_priority(async_protocol); + + IInternetProtocol_Release(async_protocol); } static void test_mk_protocol(void) @@ -1687,7 +2681,7 @@ static void test_mk_protocol(void) static const WCHAR wrong_url2[] = {'m','k',':','/','t','e','s','t','.','h','t','m','l',0}; trace("Testing mk protocol...\n"); - tested_protocol = MK_TEST; + init_test(MK_TEST, 0); hres = CoGetClassObject(&CLSID_MkProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); @@ -1746,10 +2740,11 @@ static void test_mk_protocol(void) static void test_CreateBinding(void) { - IInternetProtocolSink *sink; IInternetProtocol *protocol; IInternetPriority *priority; IInternetSession *session; + IWinInetHttpInfo *http_info; + IWinInetInfo *inet_info; LONG p; BYTE buf[1000]; DWORD read; @@ -1760,8 +2755,7 @@ static void test_CreateBinding(void) static const WCHAR wsz_test[] = {'t','e','s','t',0}; trace("Testing CreateBinding...\n"); - tested_protocol = BIND_TEST; - binding_test = TRUE; + init_test(BIND_TEST, TEST_BINDING); hres = CoInternetGetSession(0, &session, 0); ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres); @@ -1777,7 +2771,7 @@ static void test_CreateBinding(void) hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetBindInfo, (void**)&prot_bind_info); ok(hres == S_OK, "QueryInterface(IID_IInternetBindInfo) failed: %08x\n", hres); - hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolSink, (void**)&sink); + hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolSink, (void**)&binding_sink); ok(hres == S_OK, "Could not get IInternetProtocolSink: %08x\n", hres); hres = IInternetProtocol_Start(protocol, test_url, NULL, &bind_info, 0, 0); @@ -1804,6 +2798,9 @@ static void test_CreateBinding(void) ok(hres == S_OK, "GetPriority failed: %08x\n", hres); ok(p == 100, "p=%d\n", p); + hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&inet_info); + ok(hres == E_NOINTERFACE, "Could not get IWinInetInfo protocol: %08x\n", hres); + SET_EXPECT(QueryService_InternetProtocol); SET_EXPECT(CreateInstance); SET_EXPECT(ReportProgress_PROTOCOLCLASSID); @@ -1820,6 +2817,21 @@ static void test_CreateBinding(void) CHECK_CALLED(SetPriority); CHECK_CALLED(Start); + SET_EXPECT(QueryInterface_IWinInetInfo); + hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&inet_info); + ok(hres == E_NOINTERFACE, "Could not get IWinInetInfo protocol: %08x\n", hres); + CHECK_CALLED(QueryInterface_IWinInetInfo); + + SET_EXPECT(QueryInterface_IWinInetInfo); + hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&inet_info); + ok(hres == E_NOINTERFACE, "Could not get IWinInetInfo protocol: %08x\n", hres); + CHECK_CALLED(QueryInterface_IWinInetInfo); + + SET_EXPECT(QueryInterface_IWinInetHttpInfo); + hres = IInternetProtocol_QueryInterface(protocol, &IID_IWinInetHttpInfo, (void**)&http_info); + ok(hres == E_NOINTERFACE, "Could not get IWinInetInfo protocol: %08x\n", hres); + CHECK_CALLED(QueryInterface_IWinInetHttpInfo); + SET_EXPECT(Read); read = 0xdeadbeef; hres = IInternetProtocol_Read(protocol, expect_pv = buf, sizeof(buf), &read); @@ -1848,50 +2860,52 @@ static void test_CreateBinding(void) CHECK_CALLED(Terminate); SET_EXPECT(Continue); - hres = IInternetProtocolSink_Switch(sink, &protocoldata); + hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata); ok(hres == S_OK, "Switch failed: %08x\n", hres); CHECK_CALLED(Continue); - hres = IInternetProtocolSink_ReportProgress(sink, + hres = IInternetProtocolSink_ReportProgress(binding_sink, BINDSTATUS_CACHEFILENAMEAVAILABLE, expect_wsz = emptyW); ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres); - hres = IInternetProtocolSink_ReportResult(sink, S_OK, ERROR_SUCCESS, NULL); + hres = IInternetProtocolSink_ReportResult(binding_sink, S_OK, ERROR_SUCCESS, NULL); ok(hres == E_FAIL, "ReportResult failed: %08x, expected E_FAIL\n", hres); - hres = IInternetProtocolSink_ReportData(sink, 0, 0, 0); + hres = IInternetProtocolSink_ReportData(binding_sink, 0, 0, 0); ok(hres == S_OK, "ReportData failed: %08x\n", hres); - IInternetProtocolSink_Release(sink); + IInternetProtocolSink_Release(binding_sink); IInternetPriority_Release(priority); IInternetBindInfo_Release(prot_bind_info); IInternetProtocol_Release(protocol); + + hres = IInternetSession_UnregisterNameSpace(session, &ClassFactory, wsz_test); + ok(hres == S_OK, "UnregisterNameSpace failed: %08x\n", hres); + IInternetSession_Release(session); } -static void test_binding(int prot) +static void test_binding(int prot, DWORD grf_pi, DWORD test_flags) { IInternetProtocol *protocol; IInternetSession *session; ULONG ref; HRESULT hres; - trace("Testing %s binding...\n", debugstr_w(protocol_names[prot])); + pi = grf_pi; - tested_protocol = prot; - binding_test = TRUE; - first_data_notif = TRUE; - prot_read = 0; + init_test(prot, test_flags|TEST_BINDING); hres = CoInternetGetSession(0, &session, 0); ok(hres == S_OK, "CoInternetGetSession failed: %08x\n", hres); + if(test_flags & TEST_EMULATEPROT) { hres = IInternetSession_RegisterNameSpace(session, &ClassFactory, &IID_NULL, protocol_names[prot], 0, NULL, 0); ok(hres == S_OK, "RegisterNameSpace failed: %08x\n", hres); + } hres = IInternetSession_CreateBinding(session, NULL, binding_urls[prot], NULL, NULL, &protocol, 0); binding_protocol = protocol; - IInternetSession_Release(session); ok(hres == S_OK, "CreateBinding failed: %08x\n", hres); ok(protocol != NULL, "protocol == NULL\n"); @@ -1909,7 +2923,7 @@ static void test_binding(int prot) SET_EXPECT(Start); expect_hrResult = S_OK; - hres = IInternetProtocol_Start(protocol, binding_urls[prot], &protocol_sink, &bind_info, 0, 0); + hres = IInternetProtocol_Start(protocol, binding_urls[prot], &protocol_sink, &bind_info, pi, 0); ok(hres == S_OK, "Start failed: %08x\n", hres); CHECK_CALLED(QueryService_InternetProtocol); @@ -1918,37 +2932,86 @@ static void test_binding(int prot) CHECK_CALLED(SetPriority); CHECK_CALLED(Start); - if(prot == HTTP_TEST) { + if(prot == HTTP_TEST || prot == HTTPS_TEST) { while(prot_state < 4) { WaitForSingleObject(event_complete, INFINITE); + if(mimefilter_test && filtered_protocol) { SET_EXPECT(Continue); + IInternetProtocol_Continue(filtered_protocol, pdata); + CHECK_CALLED(Continue); + }else { + SET_EXPECT(Continue); IInternetProtocol_Continue(protocol, pdata); CHECK_CALLED(Continue); + } SetEvent(event_complete2); } - + if(direct_read) + CHECK_CALLED(ReportData); /* Set in ReportResult */ WaitForSingleObject(event_complete, INFINITE); }else { + if(mimefilter_test) + SET_EXPECT(MimeFilter_LockRequest); + else SET_EXPECT(LockRequest); hres = IInternetProtocol_LockRequest(protocol, 0); ok(hres == S_OK, "LockRequest failed: %08x\n", hres); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_LockRequest); + else CHECK_CALLED(LockRequest); + if(mimefilter_test) + SET_EXPECT(MimeFilter_UnlockRequest); + else SET_EXPECT(UnlockRequest); hres = IInternetProtocol_UnlockRequest(protocol); ok(hres == S_OK, "UnlockRequest failed: %08x\n", hres); + if(mimefilter_test) + CHECK_CALLED(MimeFilter_UnlockRequest); + else CHECK_CALLED(UnlockRequest); } + if(mimefilter_test) + SET_EXPECT(MimeFilter_Terminate); + else SET_EXPECT(Terminate); hres = IInternetProtocol_Terminate(protocol, 0); ok(hres == S_OK, "Terminate failed: %08x\n", hres); + if(mimefilter_test) + CLEAR_CALLED(MimeFilter_Terminate); + else CHECK_CALLED(Terminate); + if(filtered_protocol) + IInternetProtocol_Release(filtered_protocol); IInternetBindInfo_Release(prot_bind_info); IInternetProtocolSink_Release(binding_sink); ref = IInternetProtocol_Release(protocol); ok(!ref, "ref=%u, expected 0\n", ref); + + if(test_flags & TEST_EMULATEPROT) { + hres = IInternetSession_UnregisterNameSpace(session, &ClassFactory, protocol_names[prot]); + ok(hres == S_OK, "UnregisterNameSpace failed: %08x\n", hres); +} + + IInternetSession_Release(session); +} + +static void register_filter(void) +{ + IInternetSession *session; + HRESULT hres; + + static const WCHAR gzipW[] = {'g','z','i','p',0}; + + CoInternetGetSession(0, &session, 0); + + hres = IInternetSession_RegisterMimeFilter(session, &mimefilter_cf, &IID_IInternetProtocol, gzipW); + ok(hres == S_OK, "RegisterMimeFilter failed: %08x\n", hres); + + IInternetSession_Release(session); } START_TEST(protocol) @@ -1957,16 +3020,37 @@ START_TEST(protocol) event_complete = CreateEvent(NULL, FALSE, FALSE, NULL); event_complete2 = CreateEvent(NULL, FALSE, FALSE, NULL); + event_continue = CreateEvent(NULL, FALSE, FALSE, NULL); + event_continue_done = CreateEvent(NULL, FALSE, FALSE, NULL); + + register_filter(); test_file_protocol(); test_http_protocol(); + test_https_protocol(); + test_ftp_protocol(); + test_gopher_protocol(); test_mk_protocol(); test_CreateBinding(); - test_binding(FILE_TEST); - test_binding(HTTP_TEST); + + bindf &= ~BINDF_FROMURLMON; + trace("Testing file binding (mime verification, emulate prot)...\n"); + test_binding(FILE_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT); + trace("Testing http binding (mime verification, emulate prot)...\n"); + test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT); + trace("Testing http binding (mime verification, emulate prot, short read, direct read)...\n"); + test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_SHORT_READ|TEST_DIRECT_READ); + trace("Testing file binding (mime verification, emulate prot, mime filter)...\n"); + test_binding(FILE_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_FILTER); + trace("Testing http binding (mime verification, emulate prot, mime filter)...\n"); + test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_FILTER); + trace("Testing http binding (mime verification, emulate prot, direct read)...\n"); + test_binding(HTTP_TEST, PI_MIMEVERIFICATION, TEST_EMULATEPROT|TEST_DIRECT_READ); CloseHandle(event_complete); CloseHandle(event_complete2); + CloseHandle(event_continue); + CloseHandle(event_continue_done); OleUninitialize(); } diff --git a/rostests/winetests/urlmon/sec_mgr.c b/rostests/winetests/urlmon/sec_mgr.c new file mode 100644 index 00000000000..62471cf8de5 --- /dev/null +++ b/rostests/winetests/urlmon/sec_mgr.c @@ -0,0 +1,622 @@ +/* + * Copyright 2005-2006 Jacek Caban for CodeWeavers + * Copyright 2009 Detlef Riekenberg + * + * 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 + */ + +#define COBJMACROS +#define CONST_VTABLE +#define NONAMELESSUNION + +/* needed for IInternetZoneManagerEx2 */ +#define _WIN32_IE 0x0700 + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "ole2.h" +#include "urlmon.h" + +#include "initguid.h" + +static const WCHAR url1[] = {'r','e','s',':','/','/','m','s','h','t','m','l','.','d','l','l', + '/','b','l','a','n','k','.','h','t','m',0}; +static const WCHAR url2[] = {'i','n','d','e','x','.','h','t','m',0}; +static const WCHAR url3[] = {'f','i','l','e',':','/','/','c',':','\\','I','n','d','e','x','.','h','t','m',0}; +static const WCHAR url4[] = {'f','i','l','e',':','s','o','m','e','%','2','0','f','i','l','e', + '%','2','e','j','p','g',0}; +static const WCHAR url5[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q', + '.','o','r','g',0}; +static const WCHAR url6[] = {'a','b','o','u','t',':','b','l','a','n','k',0}; +static const WCHAR url7[] = {'f','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/', + 'f','i','l','e','.','t','e','s','t',0}; +static const WCHAR url8[] = {'t','e','s','t',':','1','2','3','a','b','c',0}; +static const WCHAR url9[] = + {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g', + '/','s','i','t','e','/','a','b','o','u','t',0}; +static const WCHAR url10[] = {'f','i','l','e',':','/','/','s','o','m','e','%','2','0','f','i','l','e', + '.','j','p','g',0}; + +static const WCHAR url4e[] = {'f','i','l','e',':','s','o','m','e',' ','f','i','l','e', + '.','j','p','g',0}; + + +static const BYTE secid1[] = {'f','i','l','e',':',0,0,0,0}; +static const BYTE secid5[] = {'h','t','t','p',':','w','w','w','.','w','i','n','e','h','q', + '.','o','r','g',3,0,0,0}; +static const BYTE secid6[] = {'a','b','o','u','t',':','b','l','a','n','k',3,0,0,0}; +static const BYTE secid7[] = {'f','t','p',':','w','i','n','e','h','q','.','o','r','g', + 3,0,0,0}; +static const BYTE secid10[] = + {'f','i','l','e',':','s','o','m','e','%','2','0','f','i','l','e','.','j','p','g',3,0,0,0}; +static const BYTE secid10_2[] = + {'f','i','l','e',':','s','o','m','e',' ','f','i','l','e','.','j','p','g',3,0,0,0}; + +static const GUID CLSID_TestActiveX = + {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x06,0x46}}; + +/* Defined as extern in urlmon.idl, but not exported by uuid.lib */ +const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY = + {0x10200490,0xfa38,0x11d0,{0xac,0x0e,0x00,0xa0,0xc9,0xf,0xff,0xc0}}; + +static struct secmgr_test { + LPCWSTR url; + DWORD zone; + HRESULT zone_hres; + DWORD secid_size; + const BYTE *secid; + HRESULT secid_hres; +} secmgr_tests[] = { + {url1, 0, S_OK, sizeof(secid1), secid1, S_OK}, + {url2, 100, 0x80041001, 0, NULL, E_INVALIDARG}, + {url3, 0, S_OK, sizeof(secid1), secid1, S_OK}, + {url5, 3, S_OK, sizeof(secid5), secid5, S_OK}, + {url6, 3, S_OK, sizeof(secid6), secid6, S_OK}, + {url7, 3, S_OK, sizeof(secid7), secid7, S_OK} +}; + +static void test_SecurityManager(void) +{ + int i; + IInternetSecurityManager *secmgr = NULL; + BYTE buf[512]; + DWORD zone, size, policy; + HRESULT hres; + + hres = CoInternetCreateSecurityManager(NULL, &secmgr, 0); + ok(hres == S_OK, "CoInternetCreateSecurityManager failed: %08x\n", hres); + if(FAILED(hres)) + return; + + for(i=0; i < sizeof(secmgr_tests)/sizeof(secmgr_tests[0]); i++) { + zone = 100; + hres = IInternetSecurityManager_MapUrlToZone(secmgr, secmgr_tests[i].url, + &zone, 0); + ok(hres == secmgr_tests[i].zone_hres /* IE <=6 */ + || (FAILED(secmgr_tests[i].zone_hres) && hres == E_INVALIDARG), /* IE7 */ + "[%d] MapUrlToZone failed: %08x, expected %08x\n", + i, hres, secmgr_tests[i].zone_hres); + if(SUCCEEDED(hres)) + ok(zone == secmgr_tests[i].zone, "[%d] zone=%d, expected %d\n", i, zone, + secmgr_tests[i].zone); + else + ok(zone == secmgr_tests[i].zone || zone == -1, "[%d] zone=%d\n", i, zone); + + size = sizeof(buf); + memset(buf, 0xf0, sizeof(buf)); + hres = IInternetSecurityManager_GetSecurityId(secmgr, secmgr_tests[i].url, + buf, &size, 0); + ok(hres == secmgr_tests[i].secid_hres, + "[%d] GetSecurityId failed: %08x, expected %08x\n", + i, hres, secmgr_tests[i].secid_hres); + if(secmgr_tests[i].secid) { + ok(size == secmgr_tests[i].secid_size, "[%d] size=%d, expected %d\n", + i, size, secmgr_tests[i].secid_size); + ok(!memcmp(buf, secmgr_tests[i].secid, size), "[%d] wrong secid\n", i); + } + } + + zone = 100; + hres = IInternetSecurityManager_MapUrlToZone(secmgr, url10, &zone, 0); + ok(hres == S_OK, "MapUrlToZone failed: %08x, expected S_OK\n", hres); + ok(zone == 3, "zone=%d, expected 3\n", zone); + + /* win2k3 translates %20 into a space */ + size = sizeof(buf); + memset(buf, 0xf0, sizeof(buf)); + hres = IInternetSecurityManager_GetSecurityId(secmgr, url10, buf, &size, 0); + ok(hres == S_OK, "GetSecurityId failed: %08x, expected S_OK\n", hres); + ok(size == sizeof(secid10) || + size == sizeof(secid10_2), /* win2k3 */ + "size=%d\n", size); + ok(!memcmp(buf, secid10, size) || + !memcmp(buf, secid10_2, size), /* win2k3 */ + "wrong secid\n"); + + zone = 100; + hres = IInternetSecurityManager_MapUrlToZone(secmgr, NULL, &zone, 0); + ok(hres == E_INVALIDARG, "MapUrlToZone failed: %08x, expected E_INVALIDARG\n", hres); + ok(zone == 100 || zone == -1, "zone=%d\n", zone); + + size = sizeof(buf); + hres = IInternetSecurityManager_GetSecurityId(secmgr, NULL, buf, &size, 0); + ok(hres == E_INVALIDARG, + "GetSecurityId failed: %08x, expected E_INVALIDARG\n", hres); + hres = IInternetSecurityManager_GetSecurityId(secmgr, secmgr_tests[1].url, + NULL, &size, 0); + ok(hres == E_INVALIDARG, + "GetSecurityId failed: %08x, expected E_INVALIDARG\n", hres); + hres = IInternetSecurityManager_GetSecurityId(secmgr, secmgr_tests[1].url, + buf, NULL, 0); + ok(hres == E_INVALIDARG, + "GetSecurityId failed: %08x, expected E_INVALIDARG\n", hres); + + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, NULL, URLACTION_SCRIPT_RUN, (BYTE*)&policy, + sizeof(WCHAR), NULL, 0, 0, 0); + ok(hres == E_INVALIDARG, "ProcessUrlAction failed: %08x, expected E_INVALIDARG\n", hres); + + IInternetSecurityManager_Release(secmgr); +} + +/* Check if Internet Explorer is configured to run in "Enhanced Security Configuration" (aka hardened mode) */ +/* Note: this code is duplicated in dlls/mshtml/tests/mshtml_test.h and dlls/urlmon/tests/sec_mgr.c */ +static BOOL is_ie_hardened(void) +{ + HKEY zone_map; + DWORD ie_harden, type, size; + + ie_harden = 0; + if(RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ZoneMap", + 0, KEY_QUERY_VALUE, &zone_map) == ERROR_SUCCESS) { + size = sizeof(DWORD); + if (RegQueryValueExA(zone_map, "IEHarden", NULL, &type, (LPBYTE) &ie_harden, &size) != ERROR_SUCCESS || + type != REG_DWORD) { + ie_harden = 0; + } + RegCloseKey(zone_map); + } + + return ie_harden != 0; +} + +static void test_url_action(IInternetSecurityManager *secmgr, IInternetZoneManager *zonemgr, DWORD action) +{ + DWORD res, size, policy, reg_policy; + char buf[10]; + HKEY hkey; + HRESULT hres; + + /* FIXME: HKEY_CURRENT_USER is most of the time the default but this can be changed on a system. + * The test should be changed to cope with that, if need be. + */ + res = RegOpenKeyA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3", &hkey); + if(res != ERROR_SUCCESS) { + ok(0, "Could not open zone key\n"); + return; + } + + wsprintf(buf, "%X", action); + size = sizeof(DWORD); + res = RegQueryValueExA(hkey, buf, NULL, NULL, (BYTE*)®_policy, &size); + RegCloseKey(hkey); + if(res != ERROR_SUCCESS || size != sizeof(DWORD)) { + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, + sizeof(WCHAR), NULL, 0, 0, 0); + ok(hres == E_FAIL || broken(hres == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)), + "(0x%x) got 0x%x (expected E_FAIL)\n", action, hres); + ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); + + policy = 0xdeadbeef; + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == E_FAIL || broken(hres == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)), + "(0x%x) got 0x%x (expected E_FAIL)\n", action, hres); + ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); + return; + } + + policy = 0xdeadbeef; + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == S_OK, "GetZoneActionPolicy failed: %08x\n", hres); + ok(policy == reg_policy, "(%x) policy=%x, expected %x\n", action, policy, reg_policy); + + if(policy != URLPOLICY_QUERY) { + if(winetest_interactive || ! is_ie_hardened()) { + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, + sizeof(WCHAR), NULL, 0, 0, 0); + if(reg_policy == URLPOLICY_DISALLOW) + ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); + else + ok(hres == S_OK, "ProcessUrlAction(%x) failed: %08x\n", action, hres); + ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); + + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, + 2, NULL, 0, 0, 0); + if(reg_policy == URLPOLICY_DISALLOW) + ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); + else + ok(hres == S_OK, "ProcessUrlAction(%x) failed: %08x\n", action, hres); + ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); + + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, + sizeof(DWORD), NULL, 0, 0, 0); + if(reg_policy == URLPOLICY_DISALLOW) + ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); + else + ok(hres == S_OK, "ProcessUrlAction(%x) failed: %08x\n", action, hres); + ok(policy == reg_policy, "(%x) policy=%x\n", action, policy); + + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, + sizeof(WCHAR), (BYTE*)0xdeadbeef, 16, 0, 0); + if(reg_policy == URLPOLICY_DISALLOW) + ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); + else + ok(hres == S_OK, "ProcessUrlAction(%x) failed: %08x\n", action, hres); + ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); + }else { + skip("IE running in Enhanced Security Configuration\n"); + } + } +} + +static void test_special_url_action(IInternetSecurityManager *secmgr, IInternetZoneManager *zonemgr, DWORD action) +{ + DWORD policy; + HRESULT hres; + + policy = 0xdeadbeef; + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == S_OK, "GetZoneActionPolicy failed: %08x\n", hres); + ok(policy == URLPOLICY_DISALLOW, "(%x) policy=%x, expected URLPOLICY_DISALLOW\n", action, policy); + + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url1, action, (BYTE*)&policy, + sizeof(WCHAR), NULL, 0, 0, 0); + ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); + + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url1, action, (BYTE*)&policy, + sizeof(DWORD), NULL, 0, 0, 0); + ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); + ok(policy == URLPOLICY_DISALLOW, "policy = %x\n", policy); +} + +static void test_activex(IInternetSecurityManager *secmgr) +{ + DWORD policy, policy_size; + struct CONFIRMSAFETY cs; + BYTE *ppolicy; + HRESULT hres; + + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url1, URLACTION_ACTIVEX_RUN, (BYTE*)&policy, + sizeof(DWORD), (BYTE*)&CLSID_TestActiveX, sizeof(CLSID), 0, 0); + ok(hres == S_OK, "ProcessUrlAction(URLACTION_ACTIVEX_RUN) failed: %08x\n", hres); + ok(policy == URLPOLICY_ALLOW || policy == URLPOLICY_DISALLOW, "policy = %x\n", policy); + + cs.clsid = CLSID_TestActiveX; + cs.pUnk = (IUnknown*)0xdeadbeef; + cs.dwFlags = 0; + hres = IInternetSecurityManager_QueryCustomPolicy(secmgr, url1, &GUID_CUSTOM_CONFIRMOBJECTSAFETY, + &ppolicy, &policy_size, (BYTE*)&cs, sizeof(cs), 0); + ok(hres == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "QueryCusromPolicy failed: %08x\n", hres); +} + +static void test_polices(void) +{ + IInternetZoneManager *zonemgr = NULL; + IInternetSecurityManager *secmgr = NULL; + HRESULT hres; + + hres = CoInternetCreateSecurityManager(NULL, &secmgr, 0); + ok(hres == S_OK, "CoInternetCreateSecurityManager failed: %08x\n", hres); + hres = CoInternetCreateZoneManager(NULL, &zonemgr, 0); + ok(hres == S_OK, "CoInternetCreateZoneManager failed: %08x\n", hres); + + test_url_action(secmgr, zonemgr, URLACTION_SCRIPT_RUN); + test_url_action(secmgr, zonemgr, URLACTION_ACTIVEX_RUN); + test_url_action(secmgr, zonemgr, URLACTION_ACTIVEX_OVERRIDE_OBJECT_SAFETY); + test_url_action(secmgr, zonemgr, URLACTION_CHANNEL_SOFTDIST_PERMISSIONS); + test_url_action(secmgr, zonemgr, 0xdeadbeef); + + test_special_url_action(secmgr, zonemgr, URLACTION_SCRIPT_OVERRIDE_SAFETY); + test_special_url_action(secmgr, zonemgr, URLACTION_ACTIVEX_OVERRIDE_SCRIPT_SAFETY); + + test_activex(secmgr); + + IInternetSecurityManager_Release(secmgr); + IInternetZoneManager_Release(zonemgr); +} + +static void test_CoInternetCreateZoneManager(void) +{ + IInternetZoneManager *zonemgr = NULL; + IUnknown *punk = NULL; + HRESULT hr; + + hr = CoInternetCreateZoneManager(NULL, &zonemgr, 0); + ok(hr == S_OK, "CoInternetCreateZoneManager result: 0x%x\n", hr); + if (FAILED(hr)) + return; + + hr = IInternetZoneManager_QueryInterface(zonemgr, &IID_IUnknown, (void **) &punk); + ok(SUCCEEDED(hr), "got 0x%x with %p (expected Success)\n", hr, punk); + if (punk) + IUnknown_Release(punk); + + hr = IInternetZoneManager_QueryInterface(zonemgr, &IID_IInternetZoneManager, (void **) &punk); + ok(SUCCEEDED(hr), "got 0x%x with %p (expected Success)\n", hr, punk); + if (punk) + IUnknown_Release(punk); + + + hr = IInternetZoneManager_QueryInterface(zonemgr, &IID_IInternetZoneManagerEx, (void **) &punk); + if (SUCCEEDED(hr)) { + IUnknown_Release(punk); + + hr = IInternetZoneManager_QueryInterface(zonemgr, &IID_IInternetZoneManagerEx2, (void **) &punk); + if (punk) + IUnknown_Release(punk); + else + win_skip("InternetZoneManagerEx2 not supported\n"); + + } + else + win_skip("InternetZoneManagerEx not supported\n"); + + hr = IInternetZoneManager_Release(zonemgr); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + +} + +static void test_CreateZoneEnumerator(void) +{ + IInternetZoneManager *zonemgr = NULL; + HRESULT hr; + DWORD dwEnum; + DWORD dwEnum2; + DWORD dwCount; + DWORD dwCount2; + + hr = CoInternetCreateZoneManager(NULL, &zonemgr, 0); + ok(hr == S_OK, "CoInternetCreateZoneManager result: 0x%x\n", hr); + if (FAILED(hr)) + return; + + dwEnum=0xdeadbeef; + hr = IInternetZoneManager_CreateZoneEnumerator(zonemgr, &dwEnum, NULL, 0); + ok((hr == E_INVALIDARG) && (dwEnum == 0xdeadbeef), + "got 0x%x with 0x%x (expected E_INVALIDARG with 0xdeadbeef)\n", hr, dwEnum); + + dwCount=0xdeadbeef; + hr = IInternetZoneManager_CreateZoneEnumerator(zonemgr, NULL, &dwCount, 0); + ok((hr == E_INVALIDARG) && (dwCount == 0xdeadbeef), + "got 0x%x and 0x%x (expected E_INVALIDARG and 0xdeadbeef)\n", hr, dwCount); + + dwEnum=0xdeadbeef; + dwCount=0xdeadbeef; + hr = IInternetZoneManager_CreateZoneEnumerator(zonemgr, &dwEnum, &dwCount, 0xffffffff); + ok((hr == E_INVALIDARG) && (dwEnum == 0xdeadbeef) && (dwCount == 0xdeadbeef), + "got 0x%x with 0x%x and 0x%x (expected E_INVALIDARG with 0xdeadbeef and 0xdeadbeef)\n", + hr, dwEnum, dwCount); + + dwEnum=0xdeadbeef; + dwCount=0xdeadbeef; + hr = IInternetZoneManager_CreateZoneEnumerator(zonemgr, &dwEnum, &dwCount, 1); + ok((hr == E_INVALIDARG) && (dwEnum == 0xdeadbeef) && (dwCount == 0xdeadbeef), + "got 0x%x with 0x%x and 0x%x (expected E_INVALIDARG with 0xdeadbeef and 0xdeadbeef)\n", + hr, dwEnum, dwCount); + + dwEnum=0xdeadbeef; + dwCount=0xdeadbeef; + /* Normal use */ + hr = IInternetZoneManager_CreateZoneEnumerator(zonemgr, &dwEnum, &dwCount, 0); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + + if (SUCCEEDED(hr)) { + dwEnum2=0xdeadbeef; + dwCount2=0xdeadbeef; + hr = IInternetZoneManager_CreateZoneEnumerator(zonemgr, &dwEnum2, &dwCount2, 0); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + if (SUCCEEDED(hr)) { + /* native urlmon has an incrementing counter for dwEnum */ + hr = IInternetZoneManager_DestroyZoneEnumerator(zonemgr, dwEnum2); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + } + + hr = IInternetZoneManager_DestroyZoneEnumerator(zonemgr, dwEnum); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + + /* Destroy the Enumerator twice is detected and handled in native urlmon */ + hr = IInternetZoneManager_DestroyZoneEnumerator(zonemgr, dwEnum); + ok((hr == E_INVALIDARG), "got 0x%x (expected E_INVALIDARG)\n", hr); + } + + /* ::Release succeed also, when a ::DestroyZoneEnumerator is missing */ + hr = IInternetZoneManager_Release(zonemgr); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); +} + +static void test_GetZoneActionPolicy(void) +{ + IInternetZoneManager *zonemgr = NULL; + BYTE buf[32]; + HRESULT hres; + DWORD action = URLACTION_CREDENTIALS_USE; /* Implemented on all IE versions */ + + hres = CoInternetCreateZoneManager(NULL, &zonemgr, 0); + ok(hres == S_OK, "CoInternetCreateZoneManager failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, buf, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == S_OK, "GetZoneActionPolicy failed: %08x\n", hres); + ok(*(DWORD*)buf == URLPOLICY_CREDENTIALS_SILENT_LOGON_OK || + *(DWORD*)buf == URLPOLICY_CREDENTIALS_MUST_PROMPT_USER || + *(DWORD*)buf == URLPOLICY_CREDENTIALS_CONDITIONAL_PROMPT || + *(DWORD*)buf == URLPOLICY_CREDENTIALS_ANONYMOUS_ONLY, + "unexpected policy=%d\n", *(DWORD*)buf); + + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, NULL, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == E_INVALIDARG, "GetZoneActionPolicy failed: %08x, expected E_INVALIDARG\n", hres); + + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, buf, + 2, URLZONEREG_DEFAULT); + ok(hres == E_INVALIDARG, "GetZoneActionPolicy failed: %08x, expected E_INVALIDARG\n", hres); + + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, 0x1fff, buf, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == E_FAIL || broken(hres == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)), + "(0x%x) got 0x%x (expected E_FAIL)\n", action, hres); + + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 13, action, buf, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == E_INVALIDARG, "GetZoneActionPolicy failed: %08x, expected E_INVALIDARG\n", hres); + + IInternetZoneManager_Release(zonemgr); +} + +static void test_GetZoneAt(void) +{ + IInternetZoneManager *zonemgr = NULL; + HRESULT hr; + DWORD dwEnum; + DWORD dwCount; + DWORD dwZone; + DWORD i; + + hr = CoInternetCreateZoneManager(NULL, &zonemgr, 0); + ok(hr == S_OK, "CoInternetCreateZoneManager result: 0x%x\n", hr); + if (FAILED(hr)) + return; + + hr = IInternetZoneManager_CreateZoneEnumerator(zonemgr, &dwEnum, &dwCount, 0); + if (FAILED(hr)) + goto cleanup; + + if (0) { + /* this crashes with native urlmon */ + hr = IInternetZoneManager_GetZoneAt(zonemgr, dwEnum, 0, NULL); + } + + dwZone = 0xdeadbeef; + hr = IInternetZoneManager_GetZoneAt(zonemgr, 0xdeadbeef, 0, &dwZone); + ok(hr == E_INVALIDARG, + "got 0x%x with 0x%x (expected E_INVALIDARG)\n", hr, dwZone); + + for (i = 0; i < dwCount; i++) + { + dwZone = 0xdeadbeef; + hr = IInternetZoneManager_GetZoneAt(zonemgr, dwEnum, i, &dwZone); + ok(hr == S_OK, "#%d: got x%x with %d (expected S_OK)\n", i, hr, dwZone); + } + + dwZone = 0xdeadbeef; + /* MSDN (index .. must be .. less than or equal to) is wrong */ + hr = IInternetZoneManager_GetZoneAt(zonemgr, dwEnum, dwCount, &dwZone); + ok(hr == E_INVALIDARG, + "got 0x%x with 0x%x (expected E_INVALIDARG)\n", hr, dwZone); + + hr = IInternetZoneManager_DestroyZoneEnumerator(zonemgr, dwEnum); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + +cleanup: + hr = IInternetZoneManager_Release(zonemgr); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); +} + +static void test_GetZoneAttributes(void) +{ + IInternetZoneManager *zonemgr = NULL; + CHAR buffer [sizeof(ZONEATTRIBUTES) + 32]; + ZONEATTRIBUTES* pZA = (ZONEATTRIBUTES*) buffer; + HRESULT hr; + DWORD i; + + hr = CoInternetCreateZoneManager(NULL, &zonemgr, 0); + ok(hr == S_OK, "CoInternetCreateZoneManager result: 0x%x\n", hr); + if (FAILED(hr)) + return; + + /* native urlmon has Zone "0" up to Zone "4" since IE4 */ + for (i = 0; i < 5; i++) { + memset(buffer, -1, sizeof(buffer)); + hr = IInternetZoneManager_GetZoneAttributes(zonemgr, i, pZA); + ok(hr == S_OK, "#%d: got 0x%x (expected S_OK)\n", i, hr); + } + + /* IE8 no longer set cbSize */ + memset(buffer, -1, sizeof(buffer)); + pZA->cbSize = 0; + hr = IInternetZoneManager_GetZoneAttributes(zonemgr, 0, pZA); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + ok((pZA->cbSize == 0) || (pZA->cbSize == sizeof(ZONEATTRIBUTES)), + "got cbSize = %d (expected 0)\n", pZA->cbSize); + + memset(buffer, -1, sizeof(buffer)); + pZA->cbSize = 64; + hr = IInternetZoneManager_GetZoneAttributes(zonemgr, 0, pZA); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + ok((pZA->cbSize == 64) || (pZA->cbSize == sizeof(ZONEATTRIBUTES)), + "got cbSize = %d (expected 64)\n", pZA->cbSize); + + memset(buffer, -1, sizeof(buffer)); + hr = IInternetZoneManager_GetZoneAttributes(zonemgr, 0, pZA); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + ok((pZA->cbSize == 0xffffffff) || (pZA->cbSize == sizeof(ZONEATTRIBUTES)), + "got cbSize = 0x%x (expected 0xffffffff)\n", pZA->cbSize); + + /* IE8 no longer fail on invalid zones */ + memset(buffer, -1, sizeof(buffer)); + hr = IInternetZoneManager_GetZoneAttributes(zonemgr, 0xdeadbeef, pZA); + ok(hr == S_OK || (hr == E_FAIL), + "got 0x%x (expected S_OK or E_FAIL)\n", hr); + + hr = IInternetZoneManager_GetZoneAttributes(zonemgr, 0, NULL); + ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr); + + hr = IInternetZoneManager_Release(zonemgr); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); +} + + +START_TEST(sec_mgr) +{ + OleInitialize(NULL); + + test_SecurityManager(); + test_polices(); + test_CoInternetCreateZoneManager(); + test_CreateZoneEnumerator(); + test_GetZoneActionPolicy(); + test_GetZoneAt(); + test_GetZoneAttributes(); + + OleUninitialize(); +} diff --git a/rostests/winetests/urlmon/stream.c b/rostests/winetests/urlmon/stream.c index 4fc96ef6ed5..6b25e2d2d0c 100644 --- a/rostests/winetests/urlmon/stream.c +++ b/rostests/winetests/urlmon/stream.c @@ -76,6 +76,7 @@ DEFINE_EXPECT(OnStopBinding); DEFINE_EXPECT(OnDataAvailable); DEFINE_EXPECT(GetBindInfo); +static const CHAR wszIndexHtmlA[] = "index.html"; static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0}; static WCHAR INDEX_HTML[MAX_PATH]; static const char szHtmlDoc[] = ""; @@ -260,26 +261,22 @@ static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = { static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl }; -static void set_file_url(void) +static void set_file_url(char *path) { - int len; + char INDEX_HTML_A[MAX_PATH]; - static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'}; - - memcpy(INDEX_HTML, wszFile, sizeof(wszFile)); - len = sizeof(wszFile)/sizeof(WCHAR); - INDEX_HTML[len++] = '/'; - len += GetCurrentDirectoryW(sizeof(INDEX_HTML)/sizeof(WCHAR)-len, INDEX_HTML+len); - INDEX_HTML[len++] = '\\'; - memcpy(INDEX_HTML+len, wszIndexHtml, sizeof(wszIndexHtml)); + lstrcpyA(INDEX_HTML_A, "file:///"); + lstrcatA(INDEX_HTML_A, path); + MultiByteToWideChar(CP_ACP, 0, INDEX_HTML_A, -1, INDEX_HTML, MAX_PATH); } static void create_file(void) { HANDLE file; DWORD size; + CHAR path[MAX_PATH]; - file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + file = CreateFileA(wszIndexHtmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n"); if(file == INVALID_HANDLE_VALUE) @@ -288,7 +285,10 @@ static void create_file(void) WriteFile(file, szHtmlDoc, sizeof(szHtmlDoc)-1, &size, NULL); CloseHandle(file); - set_file_url(); + GetCurrentDirectoryA(MAX_PATH, path); + lstrcatA(path, "\\"); + lstrcatA(path, wszIndexHtmlA); + set_file_url(path); } static void test_URLOpenBlockingStreamW(void) @@ -370,5 +370,5 @@ START_TEST(stream) create_file(); test_URLOpenBlockingStreamW(); test_URLOpenStreamW(); - DeleteFileW(wszIndexHtml); + DeleteFileA(wszIndexHtmlA); } diff --git a/rostests/winetests/urlmon/testlist.c b/rostests/winetests/urlmon/testlist.c index 76cace38ca4..6b3733802cc 100644 --- a/rostests/winetests/urlmon/testlist.c +++ b/rostests/winetests/urlmon/testlist.c @@ -9,6 +9,7 @@ extern void func_generated(void); extern void func_misc(void); extern void func_protocol(void); +extern void func_sec_mgr(void); extern void func_stream(void); extern void func_url(void); @@ -17,6 +18,7 @@ const struct test winetest_testlist[] = { "generated", func_generated }, { "misc", func_misc }, { "protocol", func_protocol }, + { "sec_mgr", func_sec_mgr }, { "stream", func_stream }, { "url", func_url }, { 0, 0 } diff --git a/rostests/winetests/urlmon/url.c b/rostests/winetests/urlmon/url.c index c0e93ec6c5b..bd2d49b0354 100644 --- a/rostests/winetests/urlmon/url.c +++ b/rostests/winetests/urlmon/url.c @@ -28,12 +28,17 @@ #include "windef.h" #include "winbase.h" +#include "initguid.h" #include "urlmon.h" #include "wininet.h" #include "mshtml.h" #include "wine/test.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +DEFINE_GUID(CLSID_IdentityUnmarshal,0x0000001b,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +DEFINE_GUID(IID_IBindStatusCallbackHolder,0x79eac9cc,0xbaf9,0x11ce,0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b); + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -64,24 +69,34 @@ expect_ ## func = called_ ## func = FALSE; \ }while(0) +#define CHECK_CALLED_BROKEN(func) \ + do { \ + ok(called_ ## func || broken(!called_ ## func), "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + #define CLEAR_CALLED(func) \ expect_ ## func = called_ ## func = FALSE DEFINE_EXPECT(QueryInterface_IServiceProvider); DEFINE_EXPECT(QueryInterface_IHttpNegotiate); DEFINE_EXPECT(QueryInterface_IBindStatusCallback); +DEFINE_EXPECT(QueryInterface_IBindStatusCallbackEx); DEFINE_EXPECT(QueryInterface_IBindStatusCallbackHolder); DEFINE_EXPECT(QueryInterface_IInternetBindInfo); DEFINE_EXPECT(QueryInterface_IAuthenticate); DEFINE_EXPECT(QueryInterface_IInternetProtocol); +DEFINE_EXPECT(QueryInterface_IWindowForBindingUI); DEFINE_EXPECT(QueryService_IAuthenticate); DEFINE_EXPECT(QueryService_IInternetProtocol); DEFINE_EXPECT(QueryService_IInternetBindInfo); +DEFINE_EXPECT(QueryService_IWindowForBindingUI); DEFINE_EXPECT(BeginningTransaction); DEFINE_EXPECT(OnResponse); DEFINE_EXPECT(QueryInterface_IHttpNegotiate2); DEFINE_EXPECT(GetRootSecurityId); DEFINE_EXPECT(GetBindInfo); +DEFINE_EXPECT(GetBindInfoEx); DEFINE_EXPECT(OnStartBinding); DEFINE_EXPECT(OnProgress_FINDINGRESOURCE); DEFINE_EXPECT(OnProgress_CONNECTING); @@ -117,6 +132,7 @@ DEFINE_EXPECT(CreateInstance); DEFINE_EXPECT(Load); DEFINE_EXPECT(PutProperty_MIMETYPEPROP); DEFINE_EXPECT(PutProperty_CLASSIDPROP); +DEFINE_EXPECT(SetPriority); static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'}; static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'}; @@ -133,6 +149,13 @@ static const WCHAR ITS_URL[] = {'i','t','s',':','t','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; static const WCHAR MK_URL[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':', 't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0}; +static const WCHAR https_urlW[] = + {'h','t','t','p','s',':','/','/','w','w','w','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m', + '/','t','e','s','t','.','h','t','m','l',0}; +static const WCHAR ftp_urlW[] = {'f','t','p',':','/','/','f','t','p','.','w','i','n','e','h','q','.','o','r','g', + '/','p','u','b','/','o','t','h','e','r','/', + 'w','i','n','e','l','o','g','o','.','x','c','f','.','t','a','r','.','b','z','2',0}; + static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0}; @@ -142,8 +165,10 @@ static const WCHAR wszWineHQSite[] = {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; static const WCHAR wszWineHQIP[] = {'2','0','9','.','3','2','.','1','4','1','.','3',0}; +static const CHAR wszIndexHtmlA[] = "index.html"; static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0}; static const WCHAR cache_fileW[] = {'c',':','\\','c','a','c','h','e','.','h','t','m',0}; +static const CHAR dwl_htmlA[] = "dwl.html"; static const WCHAR dwl_htmlW[] = {'d','w','l','.','h','t','m','l',0}; static const WCHAR emptyW[] = {0}; @@ -152,17 +177,19 @@ static BOOL stopped_binding = FALSE, stopped_obj_binding = FALSE, emulate_protoc static DWORD read = 0, bindf = 0, prot_state = 0, thread_id, tymed; static CHAR mime_type[512]; static IInternetProtocolSink *protocol_sink = NULL; +static IBinding *current_binding; static HANDLE complete_event, complete_event2; static HRESULT binding_hres; - -extern IID IID_IBindStatusCallbackHolder; +static BOOL have_IHttpNegotiate2, use_bscex; static LPCWSTR urls[] = { WINE_ABOUT_URL, ABOUT_BLANK, INDEX_HTML, ITS_URL, - MK_URL + MK_URL, + https_urlW, + ftp_urlW }; static WCHAR file_url[INTERNET_MAX_URL_LENGTH]; @@ -172,7 +199,9 @@ static enum { ABOUT_TEST, FILE_TEST, ITS_TEST, - MK_TEST + MK_TEST, + HTTPS_TEST, + FTP_TEST } test_protocol; static enum { @@ -181,13 +210,6 @@ static enum { END_DOWNLOAD } download_state; -static const char *debugstr_w(LPCWSTR str) -{ - static char buf[1024]; - WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); - return buf; -} - static const char *debugstr_guid(REFIID riid) { static char buf[50]; @@ -200,6 +222,11 @@ static const char *debugstr_guid(REFIID riid) return buf; } +static BOOL is_urlmon_protocol(int prot) +{ + return prot == FILE_TEST || prot == HTTP_TEST || prot == HTTPS_TEST || prot == FTP_TEST || prot == MK_TEST; +} + static void test_CreateURLMoniker(LPCWSTR url1, LPCWSTR url2) { HRESULT hr; @@ -221,14 +248,66 @@ static void test_create(void) test_CreateURLMoniker(TEST_URL_1, TEST_PART_URL_1); } +static HRESULT WINAPI Priority_QueryInterface(IInternetPriority *iface, REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI Priority_AddRef(IInternetPriority *iface) +{ + return 2; +} + +static ULONG WINAPI Priority_Release(IInternetPriority *iface) +{ + return 1; +} + +static HRESULT WINAPI Priority_SetPriority(IInternetPriority *iface, LONG nPriority) +{ + CHECK_EXPECT(SetPriority); + ok(!nPriority, "nPriority = %d\n", nPriority); + return S_OK; +} + +static HRESULT WINAPI Priority_GetPriority(IInternetPriority *iface, LONG *pnPriority) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static const IInternetPriorityVtbl InternetPriorityVtbl = { + Priority_QueryInterface, + Priority_AddRef, + Priority_Release, + Priority_SetPriority, + Priority_GetPriority +}; + +static IInternetPriority InternetPriority = { &InternetPriorityVtbl }; + static HRESULT WINAPI Protocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) { + *ppv = NULL; + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) { *ppv = iface; return S_OK; } - *ppv = NULL; + if(IsEqualGUID(&IID_IInternetPriority, riid)) { + if(!is_urlmon_protocol(test_protocol)) + return E_NOINTERFACE; + + *ppv = &InternetPriority; + return S_OK; +} + + if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) + return E_NOINTERFACE; /* TODO */ + + ok(0, "unexpected call %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } @@ -242,6 +321,28 @@ static ULONG WINAPI Protocol_Release(IInternetProtocol *iface) return 1; } +static void test_switch_fail(void) +{ + IInternetProtocolSink *binding_sink; + PROTOCOLDATA protocoldata; + HRESULT hres; + + static BOOL tested_switch_fail; + + if(tested_switch_fail) + return; + + tested_switch_fail = TRUE; + + hres = IBinding_QueryInterface(current_binding, &IID_IInternetProtocolSink, (void**)&binding_sink); + ok(hres == S_OK, "Could not get IInternetProtocolSink iface: %08x\n", hres); + if(SUCCEEDED(hres)) { + hres = IInternetProtocolSink_Switch(binding_sink, &protocoldata); + ok(hres == E_FAIL, "Switch failed: %08x, expected E_FAIL\n", hres); + IInternetProtocolSink_Release(binding_sink); + } +} + static DWORD WINAPI thread_proc(PVOID arg) { PROTOCOLDATA protocoldata; @@ -286,6 +387,8 @@ static DWORD WINAPI thread_proc(PVOID arg) else CHECK_CALLED(OnProgress_SENDINGREQUEST); + test_switch_fail(); + SET_EXPECT(Continue); prot_state = 1; hres = IInternetProtocolSink_Switch(protocol_sink, &protocoldata); @@ -301,7 +404,7 @@ static DWORD WINAPI thread_proc(PVOID arg) CHECK_CALLED(Obj_OnProgress_BEGINSYNCOPERATION); CHECK_CALLED(CreateInstance); CHECK_CALLED(PutProperty_MIMETYPEPROP); - CLEAR_CALLED(PutProperty_CLASSIDPROP); + CHECK_CALLED_BROKEN(PutProperty_CLASSIDPROP); CHECK_CALLED(Load); CHECK_CALLED(Obj_OnProgress_ENDSYNCOPERATION); CHECK_CALLED(OnObjectAvailable); @@ -352,7 +455,7 @@ static DWORD WINAPI thread_proc(PVOID arg) static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, - DWORD grfPI, DWORD dwReserved) + DWORD grfPI, HANDLE_PTR dwReserved) { BINDINFO bindinfo; DWORD bindf, bscf = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION; @@ -366,11 +469,11 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, read = 0; if(!filedwl_api) /* FIXME */ - ok(szUrl && !lstrcmpW(szUrl, urls[test_protocol]), "wrong url %s\n", debugstr_w(szUrl)); + ok(szUrl && !lstrcmpW(szUrl, urls[test_protocol]), "wrong url %s\n", wine_dbgstr_w(szUrl)); ok(pOIProtSink != NULL, "pOIProtSink == NULL\n"); ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n"); ok(grfPI == 0, "grfPI=%d, expected 0\n", grfPI); - ok(dwReserved == 0, "dwReserved=%d, expected 0\n", dwReserved); + ok(dwReserved == 0, "dwReserved=%lx, expected 0\n", dwReserved); if(!filedwl_api && binding_hres != S_OK) { SET_EXPECT(OnStopBinding); @@ -390,8 +493,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, if(filedwl_api) { ok(bindf == (BINDF_PULLDATA|BINDF_FROMURLMON|BINDF_NEEDFILE), "bindf=%08x\n", bindf); - }else if(tymed == TYMED_ISTREAM - && (test_protocol == FILE_TEST || test_protocol == MK_TEST || test_protocol == HTTP_TEST)) { + }else if(tymed == TYMED_ISTREAM && is_urlmon_protocol(test_protocol)) { ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA |BINDF_FROMURLMON), "bindf=%08x\n", bindf); @@ -441,7 +543,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, break; } - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { IServiceProvider *service_provider; IHttpNegotiate *http_negotiate; IHttpNegotiate2 *http_negotiate2; @@ -457,10 +559,9 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, SET_EXPECT(QueryService_IInternetBindInfo); hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_USER_AGENT, &ua, 1, &fetched); - todo_wine { - CHECK_CALLED(QueryInterface_IInternetBindInfo); - CHECK_CALLED(QueryService_IInternetBindInfo); - } + CLEAR_CALLED(QueryInterface_IInternetBindInfo); /* IE <8 */ + CLEAR_CALLED(QueryService_IInternetBindInfo); /* IE <8 */ + ok(hres == E_NOINTERFACE, "GetBindString(BINDSTRING_USER_AGETNT) failed: %08x\n", hres); ok(fetched == 256, "fetched = %d, expected 254\n", fetched); @@ -490,12 +591,14 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, SET_EXPECT(QueryInterface_IHttpNegotiate); hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate, &IID_IHttpNegotiate, (void**)&http_negotiate); - CHECK_CALLED(QueryInterface_IHttpNegotiate); + CLEAR_CALLED(QueryInterface_IHttpNegotiate); /* IE <8 */ ok(hres == S_OK, "QueryService failed: %08x\n", hres); SET_EXPECT(BeginningTransaction); + SET_EXPECT(QueryInterface_IHttpNegotiate); hres = IHttpNegotiate_BeginningTransaction(http_negotiate, urls[test_protocol], NULL, 0, &additional_headers); + CHECK_CALLED_BROKEN(QueryInterface_IHttpNegotiate); CHECK_CALLED(BeginningTransaction); IHttpNegotiate_Release(http_negotiate); ok(hres == S_OK, "BeginningTransction failed: %08x\n", hres); @@ -504,12 +607,14 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, SET_EXPECT(QueryInterface_IHttpNegotiate2); hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2, &IID_IHttpNegotiate2, (void**)&http_negotiate2); - CHECK_CALLED(QueryInterface_IHttpNegotiate2); + CLEAR_CALLED(QueryInterface_IHttpNegotiate2); /* IE <8 */ ok(hres == S_OK, "QueryService failed: %08x\n", hres); size = 512; + SET_EXPECT(QueryInterface_IHttpNegotiate2); SET_EXPECT(GetRootSecurityId); hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, sec_id, &size, 0); + CHECK_CALLED_BROKEN(QueryInterface_IHttpNegotiate2); CHECK_CALLED(GetRootSecurityId); IHttpNegotiate2_Release(http_negotiate2); ok(hres == E_FAIL, "GetRootSecurityId failed: %08x, expected E_FAIL\n", hres); @@ -599,7 +704,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, CHECK_CALLED(Obj_OnProgress_BEGINSYNCOPERATION); CHECK_CALLED(CreateInstance); CHECK_CALLED(PutProperty_MIMETYPEPROP); - CLEAR_CALLED(PutProperty_CLASSIDPROP); + CHECK_CALLED_BROKEN(PutProperty_CLASSIDPROP); CHECK_CALLED(Load); CHECK_CALLED(Obj_OnProgress_ENDSYNCOPERATION); CHECK_CALLED(OnObjectAvailable); @@ -660,12 +765,19 @@ static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface, &IID_IHttpNegotiate, (void**)&http_negotiate); ok(hres == S_OK, "Could not get IHttpNegotiate\n"); + SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(OnResponse); hres = IHttpNegotiate_OnResponse(http_negotiate, 200, header, NULL, NULL); + CHECK_CALLED_BROKEN(QueryInterface_IHttpNegotiate); CHECK_CALLED(OnResponse); IHttpNegotiate_Release(http_negotiate); ok(hres == S_OK, "OnResponse failed: %08x\n", hres); + if(test_protocol == HTTPS_TEST) { + hres = IInternetProtocolSink_ReportProgress(protocol_sink, BINDSTATUS_ACCEPTRANGES, NULL); + ok(hres == S_OK, "ReportProgress(BINDSTATUS_ACCEPTRANGES) failed: %08x\n", hres); + } + hres = IInternetProtocolSink_ReportProgress(protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml); ok(hres == S_OK, @@ -766,7 +878,7 @@ static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv, CHECK_EXPECT2(Read); - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { HRESULT hres; static BOOL pending = TRUE; @@ -989,6 +1101,11 @@ static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, return E_NOTIMPL; } + if(IsEqualGUID(&IID_IWindowForBindingUI, guidService)) { + CHECK_EXPECT(QueryService_IWindowForBindingUI); + return E_NOTIMPL; + } + ok(0, "unexpected service %s\n", debugstr_guid(guidService)); return E_NOINTERFACE; } @@ -1002,9 +1119,9 @@ static IServiceProviderVtbl ServiceProviderVtbl = { static IServiceProvider ServiceProvider = { &ServiceProviderVtbl }; -static IBindStatusCallback objbsc; +static IBindStatusCallbackEx objbsc; -static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv) +static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallbackEx *iface, REFIID riid, void **ppv) { ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId()); @@ -1025,7 +1142,7 @@ static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFII } else if (IsEqualGUID(&IID_IHttpNegotiate, riid)) { - CHECK_EXPECT(QueryInterface_IHttpNegotiate); + CHECK_EXPECT2(QueryInterface_IHttpNegotiate); *ppv = &HttpNegotiate; return S_OK; } @@ -1051,11 +1168,24 @@ static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFII CHECK_EXPECT2(QueryInterface_IBindStatusCallbackHolder); return E_NOINTERFACE; } + else if(IsEqualGUID(&IID_IBindStatusCallbackEx, riid)) + { + CHECK_EXPECT(QueryInterface_IBindStatusCallbackEx); + if(!use_bscex) + return E_NOINTERFACE; + *ppv = iface; + return S_OK; + } else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) { /* TODO */ CHECK_EXPECT2(QueryInterface_IInternetBindInfo); } + else if(IsEqualGUID(&IID_IWindowForBindingUI, riid)) + { + CHECK_EXPECT2(QueryInterface_IWindowForBindingUI); + return E_NOINTERFACE; + } else { ok(0, "unexpected interface %s\n", debugstr_guid(riid)); @@ -1064,17 +1194,17 @@ static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFII return E_NOINTERFACE; } -static ULONG WINAPI statusclb_AddRef(IBindStatusCallback *iface) +static ULONG WINAPI statusclb_AddRef(IBindStatusCallbackEx *iface) { return 2; } -static ULONG WINAPI statusclb_Release(IBindStatusCallback *iface) +static ULONG WINAPI statusclb_Release(IBindStatusCallbackEx *iface) { return 1; } -static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved, +static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallbackEx *iface, DWORD dwReserved, IBinding *pib) { IWinInetHttpInfo *http_info; @@ -1094,6 +1224,8 @@ static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD if(pib == (void*)0xdeadbeef) return S_OK; + current_binding = pib; + hres = IBinding_QueryInterface(pib, &IID_IMoniker, (void**)&mon); ok(hres == E_NOINTERFACE, "IBinding should not have IMoniker interface\n"); if(SUCCEEDED(hres)) @@ -1105,19 +1237,19 @@ static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD return S_OK; } -static HRESULT WINAPI statusclb_GetPriority(IBindStatusCallback *iface, LONG *pnPriority) +static HRESULT WINAPI statusclb_GetPriority(IBindStatusCallbackEx *iface, LONG *pnPriority) { ok(0, "unexpected call\n"); return E_NOTIMPL; } -static HRESULT WINAPI statusclb_OnLowResource(IBindStatusCallback *iface, DWORD reserved) +static HRESULT WINAPI statusclb_OnLowResource(IBindStatusCallbackEx *iface, DWORD reserved) { ok(0, "unexpected call\n"); return E_NOTIMPL; } -static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, +static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallbackEx *iface, ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) { ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId()); @@ -1126,6 +1258,8 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP case BINDSTATUS_FINDINGRESOURCE: if(iface == &objbsc) CHECK_EXPECT(Obj_OnProgress_FINDINGRESOURCE); + else if(test_protocol == FTP_TEST) + todo_wine CHECK_EXPECT(OnProgress_FINDINGRESOURCE); else CHECK_EXPECT(OnProgress_FINDINGRESOURCE); if((bindf & BINDF_ASYNCHRONOUS) && emulate_protocol) @@ -1134,6 +1268,8 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP case BINDSTATUS_CONNECTING: if(iface == &objbsc) CHECK_EXPECT(Obj_OnProgress_CONNECTING); + else if(test_protocol == FTP_TEST) + todo_wine CHECK_EXPECT(OnProgress_CONNECTING); else CHECK_EXPECT(OnProgress_CONNECTING); if((bindf & BINDF_ASYNCHRONOUS) && emulate_protocol) @@ -1142,6 +1278,8 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP case BINDSTATUS_SENDINGREQUEST: if(iface == &objbsc) CHECK_EXPECT(Obj_OnProgress_SENDINGREQUEST); + else if(test_protocol == FTP_TEST) + CHECK_EXPECT2(OnProgress_SENDINGREQUEST); else CHECK_EXPECT(OnProgress_SENDINGREQUEST); if((bindf & BINDF_ASYNCHRONOUS) && emulate_protocol) @@ -1167,7 +1305,7 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP if(filedwl_api) { /* FIXME */ }else { - ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText %s\n", debugstr_w(szStatusText)); + ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText %s\n", wine_dbgstr_w(szStatusText)); } } if(!bind_to_object) @@ -1177,8 +1315,7 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP break; case BINDSTATUS_DOWNLOADINGDATA: CHECK_EXPECT2(OnProgress_DOWNLOADINGDATA); - if(iface == &objbsc) - todo_wine ok(0, "unexpected call\n"); + ok(iface != &objbsc, "unexpected call\n"); ok(download_state == DOWNLOADING, "Download state was %d, expected DOWNLOADING\n", download_state); break; @@ -1192,7 +1329,7 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP if(filedwl_api) { /* FIXME */ }else { - ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText %s\n", debugstr_w(szStatusText)); + ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText %s\n", wine_dbgstr_w(szStatusText)); } } ok(download_state == DOWNLOADING, "Download state was %d, expected DOWNLOADING\n", @@ -1200,7 +1337,7 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP download_state = END_DOWNLOAD; break; case BINDSTATUS_CACHEFILENAMEAVAILABLE: - if(test_protocol != HTTP_TEST) { + if(test_protocol != HTTP_TEST && test_protocol != HTTPS_TEST) { if(iface == &objbsc) CHECK_EXPECT(Obj_OnProgress_CACHEFILENAMEAVAILABLE); else @@ -1212,7 +1349,7 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP ok(szStatusText != NULL, "szStatusText == NULL\n"); if(szStatusText && test_protocol == FILE_TEST) - ok(!lstrcmpW(file_url+8, szStatusText), "wrong szStatusText %s\n", debugstr_w(szStatusText)); + ok(!lstrcmpW(file_url+8, szStatusText), "wrong szStatusText %s\n", wine_dbgstr_w(szStatusText)); break; case BINDSTATUS_CLASSIDAVAILABLE: { @@ -1242,13 +1379,34 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP ok(0, "unexpected call\n"); ok(szStatusText == NULL, "Expected szStatusText to be NULL\n"); break; + case BINDSTATUS_PROXYDETECTING: + trace("BINDSTATUS_PROXYDETECTING\n"); + break; + case BINDSTATUS_COOKIE_SENT: + trace("BINDSTATUS_COOKIE_SENT\n"); + break; default: ok(0, "unexpected code %d\n", ulStatusCode); }; + + if(current_binding) { + IWinInetHttpInfo *http_info; + HRESULT hres; + + hres = IBinding_QueryInterface(current_binding, &IID_IWinInetHttpInfo, (void**)&http_info); + if(!emulate_protocol && test_protocol != FILE_TEST && is_urlmon_protocol(test_protocol)) + ok(hres == S_OK, "Could not get IWinInetHttpInfo iface: %08x\n", hres); + else + ok(hres == E_NOINTERFACE, + "QueryInterface(IID_IWinInetHttpInfo) returned: %08x, expected E_NOINTERFACE\n", hres); + if(SUCCEEDED(hres)) + IWinInetHttpInfo_Release(http_info); + } + return S_OK; } -static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError) +static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallbackEx *iface, HRESULT hresult, LPCWSTR szError) { if(iface == &objbsc) { CHECK_EXPECT(Obj_OnStopBinding); @@ -1270,7 +1428,7 @@ static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESUL ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres); ok(szError == NULL, "szError should be NULL\n"); - if(test_protocol == HTTP_TEST && emulate_protocol) { + if((test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) && emulate_protocol) { SetEvent(complete_event); if(iface != &objbsc) WaitForSingleObject(complete_event2, INFINITE); @@ -1279,7 +1437,7 @@ static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESUL return S_OK; } -static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) +static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallbackEx *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) { DWORD cbSize; @@ -1298,7 +1456,7 @@ static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *g return S_OK; } -static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF, +static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallbackEx *iface, DWORD grfBSCF, DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed) { HRESULT hres; @@ -1362,21 +1520,22 @@ static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWOR case TYMED_FILE: if(test_protocol == FILE_TEST) ok(!lstrcmpW(pstgmed->u.lpszFileName, INDEX_HTML+7), - "unexpected file name %s\n", debugstr_w(pstgmed->u.lpszFileName)); + "unexpected file name %s\n", wine_dbgstr_w(pstgmed->u.lpszFileName)); else if(emulate_protocol) ok(!lstrcmpW(pstgmed->u.lpszFileName, cache_fileW), - "unexpected file name %s\n", debugstr_w(pstgmed->u.lpszFileName)); + "unexpected file name %s\n", wine_dbgstr_w(pstgmed->u.lpszFileName)); else ok(pstgmed->u.lpszFileName != NULL, "lpszFileName == NULL\n"); } - if(test_protocol == HTTP_TEST && emulate_protocol && prot_state < 4 && (!bind_to_object || prot_state > 1)) + if((test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) + && emulate_protocol && prot_state < 4 && (!bind_to_object || prot_state > 1)) SetEvent(complete_event); return S_OK; } -static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk) +static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallbackEx *iface, REFIID riid, IUnknown *punk) { CHECK_EXPECT(OnObjectAvailable); @@ -1389,7 +1548,20 @@ static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, RE return S_OK; } -static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = { +static HRESULT WINAPI statusclb_GetBindInfoEx(IBindStatusCallbackEx *iface, DWORD *grfBINDF, BINDINFO *pbindinfo, + DWORD *grfBINDF2, DWORD *pdwReserved) +{ + CHECK_EXPECT(GetBindInfoEx); + + ok(grfBINDF != NULL, "grfBINDF == NULL\n"); + ok(grfBINDF2 != NULL, "grfBINDF2 == NULL\n"); + ok(pbindinfo != NULL, "pbindinfo == NULL\n"); + ok(pdwReserved != NULL, "dwReserved == NULL\n"); + + return S_OK; +} + +static const IBindStatusCallbackExVtbl BindStatusCallbackVtbl = { statusclb_QueryInterface, statusclb_AddRef, statusclb_Release, @@ -1400,11 +1572,12 @@ static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = { statusclb_OnStopBinding, statusclb_GetBindInfo, statusclb_OnDataAvailable, - statusclb_OnObjectAvailable + statusclb_OnObjectAvailable, + statusclb_GetBindInfoEx }; -static IBindStatusCallback bsc = { &BindStatusCallbackVtbl }; -static IBindStatusCallback objbsc = { &BindStatusCallbackVtbl }; +static IBindStatusCallbackEx bsc = { &BindStatusCallbackVtbl }; +static IBindStatusCallbackEx objbsc = { &BindStatusCallbackVtbl }; static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppv) { @@ -1428,7 +1601,7 @@ static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPER switch(mkp) { case MIMETYPEPROP: CHECK_EXPECT(PutProperty_MIMETYPEPROP); - ok(!lstrcmpW(val, wszTextHtml), "val = %s\n", debugstr_w(val)); + ok(!lstrcmpW(val, wszTextHtml), "val = %s\n", wine_dbgstr_w(val)); break; case CLASSIDPROP: CHECK_EXPECT(PutProperty_CLASSIDPROP); @@ -1499,7 +1672,7 @@ static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAva CHECK_EXPECT(Load); ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId()); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) ok(!fFullyAvailable, "fFulyAvailable = %x\n", fFullyAvailable); else ok(fFullyAvailable, "fFulyAvailable = %x\n", fFullyAvailable); @@ -1520,35 +1693,37 @@ static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAva } SET_EXPECT(QueryInterface_IServiceProvider); - hres = RegisterBindStatusCallback(pibc, &bsc, NULL, 0); + hres = RegisterBindStatusCallback(pibc, (IBindStatusCallback*)&bsc, NULL, 0); ok(hres == S_OK, "RegisterBindStatusCallback failed: %08x\n", hres); CHECK_CALLED(QueryInterface_IServiceProvider); + SET_EXPECT(QueryInterface_IBindStatusCallbackEx); SET_EXPECT(GetBindInfo); SET_EXPECT(OnStartBinding); SET_EXPECT(OnProgress_BEGINDOWNLOADDATA); if(test_protocol == FILE_TEST) SET_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); - if(test_protocol != HTTP_TEST) + if(test_protocol != HTTP_TEST && test_protocol != HTTPS_TEST) SET_EXPECT(OnProgress_ENDDOWNLOADDATA); SET_EXPECT(LockRequest); SET_EXPECT(OnDataAvailable); - if(test_protocol != HTTP_TEST) + if(test_protocol != HTTP_TEST && test_protocol != HTTPS_TEST) SET_EXPECT(OnStopBinding); hres = IMoniker_BindToStorage(pimkName, pibc, NULL, &IID_IStream, (void**)&unk); ok(hres == S_OK, "Load failed: %08x\n", hres); + CLEAR_CALLED(QueryInterface_IBindStatusCallbackEx); /* IE 8 */ CHECK_CALLED(GetBindInfo); CHECK_CALLED(OnStartBinding); CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA); if(test_protocol == FILE_TEST) CHECK_CALLED(OnProgress_CACHEFILENAMEAVAILABLE); - if(test_protocol != HTTP_TEST) + if(test_protocol != HTTP_TEST && test_protocol != HTTPS_TEST) CHECK_CALLED(OnProgress_ENDDOWNLOADDATA); CHECK_CALLED(LockRequest); CHECK_CALLED(OnDataAvailable); - if(test_protocol != HTTP_TEST) + if(test_protocol != HTTP_TEST && test_protocol != HTTPS_TEST) CHECK_CALLED(OnStopBinding); if(unk) @@ -1658,7 +1833,7 @@ static void test_CreateAsyncBindCtx(void) ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08x\n", hres); SET_EXPECT(QueryInterface_IServiceProvider); - hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx); + hres = CreateAsyncBindCtx(0, (IBindStatusCallback*)&bsc, NULL, &bctx); ok(hres == S_OK, "CreateAsyncBindCtx failed: %08x\n", hres); CHECK_CALLED(QueryInterface_IServiceProvider); @@ -1734,7 +1909,7 @@ static void test_CreateAsyncBindCtxEx(void) IBindCtx_Release(bctx_arg); SET_EXPECT(QueryInterface_IServiceProvider); - hres = CreateAsyncBindCtxEx(NULL, 0, &bsc, NULL, &bctx, 0); + hres = CreateAsyncBindCtxEx(NULL, 0, (IBindStatusCallback*)&bsc, NULL, &bctx, 0); ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres); CHECK_CALLED(QueryInterface_IServiceProvider); @@ -1762,7 +1937,53 @@ static void test_CreateAsyncBindCtxEx(void) IBindCtx_Release(bctx2); } -static void test_bscholder(IBindStatusCallback *holder) +static void test_GetBindInfoEx(IBindStatusCallback *holder) +{ + IBindStatusCallbackEx *bscex; + BINDINFO bindinfo = {sizeof(bindinfo)}; + DWORD bindf, bindf2, dw; + HRESULT hres; + + hres = IBindStatusCallback_QueryInterface(holder, &IID_IBindStatusCallbackEx, (void**)&bscex); + if(FAILED(hres)) { + win_skip("IBindStatusCallbackEx not supported\n"); + return; + } + + use_bscex = TRUE; + + bindf = 0; + SET_EXPECT(QueryInterface_IBindStatusCallbackEx); + SET_EXPECT(GetBindInfoEx); + hres = IBindStatusCallback_GetBindInfo(holder, &bindf, &bindinfo); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + CHECK_CALLED(QueryInterface_IBindStatusCallbackEx); + CHECK_CALLED(GetBindInfoEx); + + bindf = bindf2 = dw = 0; + SET_EXPECT(QueryInterface_IBindStatusCallbackEx); + SET_EXPECT(GetBindInfoEx); + hres = IBindStatusCallbackEx_GetBindInfoEx(bscex, &bindf, &bindinfo, &bindf2, &dw); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + CHECK_CALLED(QueryInterface_IBindStatusCallbackEx); + CHECK_CALLED(GetBindInfoEx); + + use_bscex = FALSE; + + bindf = bindf2 = dw = 0xdeadbeef; + SET_EXPECT(QueryInterface_IBindStatusCallbackEx); + SET_EXPECT(GetBindInfo); + hres = IBindStatusCallbackEx_GetBindInfoEx(bscex, &bindf, &bindinfo, &bindf2, &dw); + ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + CHECK_CALLED(QueryInterface_IBindStatusCallbackEx); + CHECK_CALLED(GetBindInfo); + ok(bindf2 == 0xdeadbeef, "bindf2 = %x\n", bindf2); + ok(dw == 0xdeadbeef, "dw = %x\n", dw); + + IBindStatusCallbackEx_Release(bscex); +} + +static BOOL test_bscholder(IBindStatusCallback *holder) { IServiceProvider *serv_prov; IHttpNegotiate *http_negotiate, *http_negotiate_serv; @@ -1770,6 +1991,7 @@ static void test_bscholder(IBindStatusCallback *holder) IAuthenticate *authenticate, *authenticate_serv; IInternetProtocol *protocol; BINDINFO bindinfo = {sizeof(bindinfo)}; + BOOL ret = TRUE; LPWSTR wstr; DWORD dw; HRESULT hres; @@ -1778,11 +2000,15 @@ static void test_bscholder(IBindStatusCallback *holder) ok(hres == S_OK, "Could not get IServiceProvider interface: %08x\n", hres); dw = 0xdeadbeef; + SET_EXPECT(QueryInterface_IBindStatusCallbackEx); SET_EXPECT(GetBindInfo); hres = IBindStatusCallback_GetBindInfo(holder, &dw, &bindinfo); ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); + CLEAR_CALLED(QueryInterface_IBindStatusCallbackEx); /* IE 8 */ CHECK_CALLED(GetBindInfo); + test_GetBindInfoEx(holder); + SET_EXPECT(OnStartBinding); hres = IBindStatusCallback_OnStartBinding(holder, 0, (void*)0xdeadbeef); ok(hres == S_OK, "OnStartBinding failed: %08x\n", hres); @@ -1791,22 +2017,19 @@ static void test_bscholder(IBindStatusCallback *holder) hres = IBindStatusCallback_QueryInterface(holder, &IID_IHttpNegotiate, (void**)&http_negotiate); ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres); - wstr = (void*)0xdeadbeef; - hres = IHttpNegotiate_BeginningTransaction(http_negotiate, urls[test_protocol], (void*)0xdeadbeef, 0xff, &wstr); - ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres); - ok(wstr == NULL, "wstr = %p\n", wstr); - SET_EXPECT(QueryInterface_IHttpNegotiate); hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpNegotiate, &IID_IHttpNegotiate, (void**)&http_negotiate_serv); ok(hres == S_OK, "Could not get IHttpNegotiate service: %08x\n", hres); - CHECK_CALLED(QueryInterface_IHttpNegotiate); + CLEAR_CALLED(QueryInterface_IHttpNegotiate); /* IE <8 */ ok(http_negotiate == http_negotiate_serv, "http_negotiate != http_negotiate_serv\n"); wstr = (void*)0xdeadbeef; + SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(BeginningTransaction); hres = IHttpNegotiate_BeginningTransaction(http_negotiate_serv, urls[test_protocol], emptyW, 0, &wstr); + CHECK_CALLED_BROKEN(QueryInterface_IHttpNegotiate); /* IE8 */ CHECK_CALLED(BeginningTransaction); ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres); ok(wstr == NULL, "wstr = %p\n", wstr); @@ -1821,25 +2044,27 @@ static void test_bscholder(IBindStatusCallback *holder) hres = IBindStatusCallback_QueryInterface(holder, &IID_IHttpNegotiate2, (void**)&http_negotiate2); if(SUCCEEDED(hres)) { - hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, (void*)0xdeadbeef, (void*)0xdeadbeef, 0); - ok(hres == E_FAIL, "GetRootSecurityId failed: %08x\n", hres); + have_IHttpNegotiate2 = TRUE; SET_EXPECT(QueryInterface_IHttpNegotiate2); hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpNegotiate2, &IID_IHttpNegotiate2, (void**)&http_negotiate2_serv); ok(hres == S_OK, "Could not get IHttpNegotiate2 service: %08x\n", hres); - CHECK_CALLED(QueryInterface_IHttpNegotiate2); + CLEAR_CALLED(QueryInterface_IHttpNegotiate2); /* IE <8 */ ok(http_negotiate2 == http_negotiate2_serv, "http_negotiate != http_negotiate_serv\n"); + SET_EXPECT(QueryInterface_IHttpNegotiate2); SET_EXPECT(GetRootSecurityId); hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, (void*)0xdeadbeef, (void*)0xdeadbeef, 0); ok(hres == E_NOTIMPL, "GetRootSecurityId failed: %08x\n", hres); + CHECK_CALLED_BROKEN(QueryInterface_IHttpNegotiate2); /* IE8 */ CHECK_CALLED(GetRootSecurityId); IHttpNegotiate_Release(http_negotiate2_serv); IHttpNegotiate_Release(http_negotiate2); }else { skip("Could not get IHttpNegotiate2\n"); + ret = FALSE; } SET_EXPECT(OnProgress_FINDINGRESOURCE); @@ -1847,10 +2072,12 @@ static void test_bscholder(IBindStatusCallback *holder) ok(hres == S_OK, "OnProgress failed: %08x\n", hres); CHECK_CALLED(OnProgress_FINDINGRESOURCE); + SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(OnResponse); wstr = (void*)0xdeadbeef; hres = IHttpNegotiate_OnResponse(http_negotiate, 200, emptyW, NULL, NULL); ok(hres == S_OK, "OnResponse failed: %08x\n", hres); + CHECK_CALLED_BROKEN(QueryInterface_IHttpNegotiate); /* IE8 */ CHECK_CALLED(OnResponse); IHttpNegotiate_Release(http_negotiate); @@ -1863,8 +2090,8 @@ static void test_bscholder(IBindStatusCallback *holder) hres = IServiceProvider_QueryService(serv_prov, &IID_IAuthenticate, &IID_IAuthenticate, (void**)&authenticate_serv); ok(hres == S_OK, "Could not get IAuthenticate service: %08x\n", hres); - CHECK_CALLED(QueryInterface_IAuthenticate); - CHECK_CALLED(QueryService_IAuthenticate); + CLEAR_CALLED(QueryInterface_IAuthenticate); /* IE <8 */ + CLEAR_CALLED(QueryService_IAuthenticate); /* IE <8 */ ok(authenticate == authenticate_serv, "authenticate != authenticate_serv\n"); IAuthenticate_Release(authenticate_serv); @@ -1890,12 +2117,14 @@ static void test_bscholder(IBindStatusCallback *holder) CHECK_CALLED(QueryService_IInternetProtocol); IServiceProvider_Release(serv_prov); + return ret; } -static void test_RegisterBindStatusCallback(void) +static BOOL test_RegisterBindStatusCallback(void) { IBindStatusCallback *prevbsc, *clb; IBindCtx *bindctx; + BOOL ret = TRUE; IUnknown *unk; HRESULT hres; @@ -1910,9 +2139,9 @@ static void test_RegisterBindStatusCallback(void) SET_EXPECT(QueryInterface_IBindStatusCallback); SET_EXPECT(QueryInterface_IBindStatusCallbackHolder); prevbsc = (void*)0xdeadbeef; - hres = RegisterBindStatusCallback(bindctx, &bsc, &prevbsc, 0); + hres = RegisterBindStatusCallback(bindctx, (IBindStatusCallback*)&bsc, &prevbsc, 0); ok(hres == S_OK, "RegisterBindStatusCallback failed: %08x\n", hres); - ok(prevbsc == &bsc, "prevbsc=%p\n", prevbsc); + ok(prevbsc == (IBindStatusCallback*)&bsc, "prevbsc=%p\n", prevbsc); CHECK_CALLED(QueryInterface_IBindStatusCallback); CHECK_CALLED(QueryInterface_IBindStatusCallbackHolder); @@ -1924,13 +2153,14 @@ static void test_RegisterBindStatusCallback(void) hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)&clb); IUnknown_Release(unk); ok(hres == S_OK, "QueryInterface(IID_IBindStatusCallback) failed: %08x\n", hres); - ok(clb != &bsc, "bsc == clb\n"); + ok(clb != (IBindStatusCallback*)&bsc, "bsc == clb\n"); - test_bscholder(clb); + if(!test_bscholder(clb)) + ret = FALSE; IBindStatusCallback_Release(clb); - hres = RevokeBindStatusCallback(bindctx, &bsc); + hres = RevokeBindStatusCallback(bindctx, (IBindStatusCallback*)&bsc); ok(hres == S_OK, "RevokeBindStatusCallback failed: %08x\n", hres); unk = (void*)0xdeadbeef; @@ -1951,6 +2181,7 @@ static void test_RegisterBindStatusCallback(void) ok(hres == E_INVALIDARG, "RevokeBindStatusCallback failed: %08x\n", hres); IBindCtx_Release(bindctx); + return ret; } #define BINDTEST_EMULATE 1 @@ -1986,16 +2217,16 @@ static void test_BindToStorage(int protocol, BOOL emul, DWORD t) init_bind_test(protocol, emul ? BINDTEST_EMULATE : 0, t); SET_EXPECT(QueryInterface_IServiceProvider); - hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx); + hres = CreateAsyncBindCtx(0, (IBindStatusCallback*)&bsc, NULL, &bctx); ok(hres == S_OK, "CreateAsyncBindCtx failed: %08x\n\n", hres); CHECK_CALLED(QueryInterface_IServiceProvider); if(FAILED(hres)) return; SET_EXPECT(QueryInterface_IServiceProvider); - hres = RegisterBindStatusCallback(bctx, &bsc, &previousclb, 0); + hres = RegisterBindStatusCallback(bctx, (IBindStatusCallback*)&bsc, &previousclb, 0); ok(hres == S_OK, "RegisterBindStatusCallback failed: %08x\n", hres); - ok(previousclb == &bsc, "previousclb(%p) != sclb(%p)\n", previousclb, &bsc); + ok(previousclb == (IBindStatusCallback*)&bsc, "previousclb(%p) != sclb(%p)\n", previousclb, &bsc); CHECK_CALLED(QueryInterface_IServiceProvider); if(previousclb) IBindStatusCallback_Release(previousclb); @@ -2015,43 +2246,51 @@ static void test_BindToStorage(int protocol, BOOL emul, DWORD t) hres = IMoniker_GetDisplayName(mon, bctx, NULL, &display_name); ok(hres == S_OK, "GetDisplayName failed %08x\n", hres); ok(!lstrcmpW(display_name, urls[test_protocol]), - "GetDisplayName got wrong name %s\n", debugstr_w(display_name)); + "GetDisplayName got wrong name %s\n", wine_dbgstr_w(display_name)); CoTaskMemFree(display_name); if(tymed == TYMED_FILE && (test_protocol == ABOUT_TEST || test_protocol == ITS_TEST)) binding_hres = INET_E_DATA_NOT_AVAILABLE; + SET_EXPECT(QueryInterface_IBindStatusCallbackEx); SET_EXPECT(GetBindInfo); SET_EXPECT(QueryInterface_IInternetProtocol); if(!emulate_protocol) SET_EXPECT(QueryService_IInternetProtocol); SET_EXPECT(OnStartBinding); if(emulate_protocol) { + if(is_urlmon_protocol(test_protocol)) + SET_EXPECT(SetPriority); SET_EXPECT(Start); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) SET_EXPECT(Terminate); if(tymed != TYMED_FILE || (test_protocol != ABOUT_TEST && test_protocol != ITS_TEST)) SET_EXPECT(UnlockRequest); }else { - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { SET_EXPECT(QueryInterface_IInternetBindInfo); SET_EXPECT(QueryService_IInternetBindInfo); SET_EXPECT(QueryInterface_IHttpNegotiate); + SET_EXPECT(QueryInterface_IWindowForBindingUI); + SET_EXPECT(QueryService_IWindowForBindingUI); SET_EXPECT(BeginningTransaction); SET_EXPECT(QueryInterface_IHttpNegotiate2); SET_EXPECT(GetRootSecurityId); SET_EXPECT(OnProgress_FINDINGRESOURCE); SET_EXPECT(OnProgress_CONNECTING); } - if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FTP_TEST + || test_protocol == FILE_TEST) SET_EXPECT(OnProgress_SENDINGREQUEST); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { + SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(OnResponse); + } SET_EXPECT(OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(OnProgress_BEGINDOWNLOADDATA); if(test_protocol == FILE_TEST) SET_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FTP_TEST) SET_EXPECT(OnProgress_DOWNLOADINGDATA); SET_EXPECT(OnProgress_ENDDOWNLOADDATA); if(tymed != TYMED_FILE || test_protocol != ABOUT_TEST) @@ -2060,7 +2299,8 @@ static void test_BindToStorage(int protocol, BOOL emul, DWORD t) } hres = IMoniker_BindToStorage(mon, bctx, NULL, tymed == TYMED_ISTREAM ? &IID_IStream : &IID_IUnknown, (void**)&unk); - if (test_protocol == HTTP_TEST && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED)) + if ((test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) + && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED)) { skip("Network unreachable, skipping tests\n"); return; @@ -2090,14 +2330,17 @@ static void test_BindToStorage(int protocol, BOOL emul, DWORD t) DispatchMessage(&msg); } + CLEAR_CALLED(QueryInterface_IBindStatusCallbackEx); /* IE 8 */ CHECK_CALLED(GetBindInfo); CHECK_CALLED(QueryInterface_IInternetProtocol); if(!emulate_protocol) CHECK_CALLED(QueryService_IInternetProtocol); CHECK_CALLED(OnStartBinding); if(emulate_protocol) { + if(is_urlmon_protocol(test_protocol)) + CHECK_CALLED(SetPriority); CHECK_CALLED(Start); - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { if(tymed == TYMED_FILE) CLEAR_CALLED(Read); CHECK_CALLED(Terminate); @@ -2105,32 +2348,40 @@ static void test_BindToStorage(int protocol, BOOL emul, DWORD t) if(tymed != TYMED_FILE || (test_protocol != ABOUT_TEST && test_protocol != ITS_TEST)) CHECK_CALLED(UnlockRequest); }else { - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { CLEAR_CALLED(QueryInterface_IInternetBindInfo); CLEAR_CALLED(QueryService_IInternetBindInfo); CHECK_CALLED(QueryInterface_IHttpNegotiate); + CLEAR_CALLED(QueryInterface_IWindowForBindingUI); + CLEAR_CALLED(QueryService_IWindowForBindingUI); CHECK_CALLED(BeginningTransaction); - /* QueryInterface_IHttpNegotiate2 and GetRootSecurityId - * called on WinXP but not on Win98 */ - CLEAR_CALLED(QueryInterface_IHttpNegotiate2); - CLEAR_CALLED(GetRootSecurityId); - if(http_is_first) { + if (have_IHttpNegotiate2) + { + CHECK_CALLED(QueryInterface_IHttpNegotiate2); + CHECK_CALLED(GetRootSecurityId); + } + if(http_is_first || test_protocol == HTTPS_TEST) { CHECK_CALLED(OnProgress_FINDINGRESOURCE); CHECK_CALLED(OnProgress_CONNECTING); }else todo_wine { CHECK_NOT_CALLED(OnProgress_FINDINGRESOURCE); - CHECK_NOT_CALLED(OnProgress_CONNECTING); + /* IE7 does call this */ + CLEAR_CALLED(OnProgress_CONNECTING); } } - if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FILE_TEST) CHECK_CALLED(OnProgress_SENDINGREQUEST); - if(test_protocol == HTTP_TEST) + else if(test_protocol == FTP_TEST) + todo_wine CHECK_CALLED(OnProgress_SENDINGREQUEST); + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { + CLEAR_CALLED(QueryInterface_IHttpNegotiate); CHECK_CALLED(OnResponse); + } CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA); if(test_protocol == FILE_TEST) CHECK_CALLED(OnProgress_CACHEFILENAMEAVAILABLE); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FTP_TEST) CLEAR_CALLED(OnProgress_DOWNLOADINGDATA); CHECK_CALLED(OnProgress_ENDDOWNLOADDATA); if(tymed != TYMED_FILE || test_protocol != ABOUT_TEST) @@ -2141,7 +2392,7 @@ static void test_BindToStorage(int protocol, BOOL emul, DWORD t) ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n"); ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n"); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) http_is_first = FALSE; } @@ -2163,7 +2414,7 @@ static void test_BindToObject(int protocol, BOOL emul) CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id); SET_EXPECT(QueryInterface_IServiceProvider); - hres = CreateAsyncBindCtx(0, &objbsc, NULL, &bctx); + hres = CreateAsyncBindCtx(0, (IBindStatusCallback*)&objbsc, NULL, &bctx); ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08x\n\n", hres); CHECK_CALLED(QueryInterface_IServiceProvider); if(FAILED(hres)) @@ -2185,36 +2436,43 @@ static void test_BindToObject(int protocol, BOOL emul) ok(hres == S_OK, "GetDisplayName failed %08x\n", hres); ok(!lstrcmpW(display_name, urls[test_protocol]), "GetDisplayName got wrong name\n"); + SET_EXPECT(QueryInterface_IBindStatusCallbackEx); SET_EXPECT(Obj_GetBindInfo); SET_EXPECT(QueryInterface_IInternetProtocol); if(!emulate_protocol) SET_EXPECT(QueryService_IInternetProtocol); SET_EXPECT(Obj_OnStartBinding); if(emulate_protocol) { + if(is_urlmon_protocol(test_protocol)) + SET_EXPECT(SetPriority); SET_EXPECT(Start); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) SET_EXPECT(Terminate); if(test_protocol == FILE_TEST) SET_EXPECT(OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(UnlockRequest); }else { - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(BeginningTransaction); SET_EXPECT(QueryInterface_IHttpNegotiate2); SET_EXPECT(GetRootSecurityId); SET_EXPECT(Obj_OnProgress_FINDINGRESOURCE); SET_EXPECT(Obj_OnProgress_CONNECTING); + SET_EXPECT(QueryInterface_IWindowForBindingUI); + SET_EXPECT(QueryService_IWindowForBindingUI); } - if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FILE_TEST) SET_EXPECT(Obj_OnProgress_SENDINGREQUEST); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { + SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(OnResponse); + } SET_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(Obj_OnProgress_BEGINDOWNLOADDATA); if(test_protocol == FILE_TEST) SET_EXPECT(Obj_OnProgress_CACHEFILENAMEAVAILABLE); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) SET_EXPECT(OnProgress_DOWNLOADINGDATA); SET_EXPECT(Obj_OnProgress_ENDDOWNLOADDATA); SET_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE); @@ -2226,7 +2484,8 @@ static void test_BindToObject(int protocol, BOOL emul) hres = IMoniker_BindToObject(mon, bctx, NULL, &IID_IUnknown, (void**)&unk); - if (test_protocol == HTTP_TEST && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED)) + if ((test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) + && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED)) { skip( "Network unreachable, skipping tests\n" ); return; @@ -2253,47 +2512,56 @@ static void test_BindToObject(int protocol, BOOL emul) DispatchMessage(&msg); } + CLEAR_CALLED(QueryInterface_IBindStatusCallbackEx); CHECK_CALLED(Obj_GetBindInfo); CHECK_CALLED(QueryInterface_IInternetProtocol); if(!emulate_protocol) CHECK_CALLED(QueryService_IInternetProtocol); CHECK_CALLED(Obj_OnStartBinding); if(emulate_protocol) { + if(is_urlmon_protocol(test_protocol)) + CHECK_CALLED(SetPriority); CHECK_CALLED(Start); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) CHECK_CALLED(Terminate); if(test_protocol == FILE_TEST) CLEAR_CALLED(OnProgress_MIMETYPEAVAILABLE); /* not called in IE7 */ CHECK_CALLED(UnlockRequest); }else { - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { CHECK_CALLED(QueryInterface_IHttpNegotiate); CHECK_CALLED(BeginningTransaction); - /* QueryInterface_IHttpNegotiate2 and GetRootSecurityId - * called on WinXP but not on Win98 */ - CLEAR_CALLED(QueryInterface_IHttpNegotiate2); - CLEAR_CALLED(GetRootSecurityId); + if (have_IHttpNegotiate2) + { + CHECK_CALLED(QueryInterface_IHttpNegotiate2); + CHECK_CALLED(GetRootSecurityId); + } if(http_is_first) { CHECK_CALLED(Obj_OnProgress_FINDINGRESOURCE); CHECK_CALLED(Obj_OnProgress_CONNECTING); }else todo_wine { CHECK_NOT_CALLED(Obj_OnProgress_FINDINGRESOURCE); - CHECK_NOT_CALLED(Obj_OnProgress_CONNECTING); + /* IE7 does call this */ + CLEAR_CALLED(Obj_OnProgress_CONNECTING); } + CLEAR_CALLED(QueryInterface_IWindowForBindingUI); + CLEAR_CALLED(QueryService_IWindowForBindingUI); } - if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FILE_TEST) { if(urls[test_protocol] == SHORT_RESPONSE_URL) CLEAR_CALLED(Obj_OnProgress_SENDINGREQUEST); else CHECK_CALLED(Obj_OnProgress_SENDINGREQUEST); } - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { + CLEAR_CALLED(QueryInterface_IHttpNegotiate); CHECK_CALLED(OnResponse); + } CHECK_CALLED(Obj_OnProgress_MIMETYPEAVAILABLE); CHECK_CALLED(Obj_OnProgress_BEGINDOWNLOADDATA); if(test_protocol == FILE_TEST) CHECK_CALLED(Obj_OnProgress_CACHEFILENAMEAVAILABLE); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) CLEAR_CALLED(OnProgress_DOWNLOADINGDATA); CLEAR_CALLED(Obj_OnProgress_ENDDOWNLOADDATA); CHECK_CALLED(Obj_OnProgress_CLASSIDAVAILABLE); @@ -2303,22 +2571,18 @@ static void test_BindToObject(int protocol, BOOL emul) CHECK_CALLED(Obj_OnStopBinding); } - if(test_protocol != HTTP_TEST || emul || urls[test_protocol] == SHORT_RESPONSE_URL) { + if(test_protocol != HTTP_TEST || emul || urls[test_protocol] == SHORT_RESPONSE_URL || !(bindf & BINDF_ASYNCHRONOUS)) { ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n"); ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n"); }else { todo_wine ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n"); - - if(bindf & BINDF_ASYNCHRONOUS) - ok(IBindCtx_Release(bctx) != 0, "bctx should not be destroyed here\n"); - else - todo_wine ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n"); + IBindCtx_Release(bctx); } if(emul) CoRevokeClassObject(regid); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) http_is_first = FALSE; } @@ -2337,30 +2601,36 @@ static void test_URLDownloadToFile(DWORD prot, BOOL emul) } SET_EXPECT(OnStartBinding); if(emulate_protocol) { + if(is_urlmon_protocol(test_protocol)) + SET_EXPECT(SetPriority); SET_EXPECT(Start); SET_EXPECT(UnlockRequest); }else { - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(BeginningTransaction); SET_EXPECT(QueryInterface_IHttpNegotiate2); SET_EXPECT(GetRootSecurityId); + SET_EXPECT(QueryInterface_IWindowForBindingUI); } - if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST || test_protocol == FILE_TEST) SET_EXPECT(OnProgress_SENDINGREQUEST); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { + SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(OnResponse); + } SET_EXPECT(OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(OnProgress_BEGINDOWNLOADDATA); if(test_protocol == FILE_TEST) SET_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) SET_EXPECT(OnProgress_DOWNLOADINGDATA); SET_EXPECT(OnProgress_ENDDOWNLOADDATA); SET_EXPECT(OnStopBinding); } - hres = URLDownloadToFileW(NULL, test_protocol == FILE_TEST ? file_url : urls[test_protocol], dwl_htmlW, 0, &bsc); + hres = URLDownloadToFileW(NULL, test_protocol == FILE_TEST ? file_url : urls[test_protocol], + dwl_htmlW, 0, (IBindStatusCallback*)&bsc); ok(hres == S_OK, "URLDownloadToFile failed: %08x\n", hres); CHECK_CALLED(GetBindInfo); @@ -2371,30 +2641,40 @@ static void test_URLDownloadToFile(DWORD prot, BOOL emul) } CHECK_CALLED(OnStartBinding); if(emulate_protocol) { + if(is_urlmon_protocol(test_protocol)) + CHECK_CALLED(SetPriority); CHECK_CALLED(Start); CHECK_CALLED(UnlockRequest); }else { - if(test_protocol == HTTP_TEST) { + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { CHECK_CALLED(QueryInterface_IHttpNegotiate); CHECK_CALLED(BeginningTransaction); + if (have_IHttpNegotiate2) + { CHECK_CALLED(QueryInterface_IHttpNegotiate2); CHECK_CALLED(GetRootSecurityId); } - if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) + CLEAR_CALLED(QueryInterface_IWindowForBindingUI); + } + if(test_protocol == FILE_TEST) CHECK_CALLED(OnProgress_SENDINGREQUEST); - if(test_protocol == HTTP_TEST) + else if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) + CLEAR_CALLED(OnProgress_SENDINGREQUEST); /* not called by IE7 */ + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) { + CLEAR_CALLED(QueryInterface_IHttpNegotiate); CHECK_CALLED(OnResponse); + } CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA); if(test_protocol == FILE_TEST) CHECK_CALLED(OnProgress_CACHEFILENAMEAVAILABLE); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST || test_protocol == HTTPS_TEST) CLEAR_CALLED(OnProgress_DOWNLOADINGDATA); CHECK_CALLED(OnProgress_ENDDOWNLOADDATA); CHECK_CALLED(OnStopBinding); } - res = DeleteFileW(dwl_htmlW); + res = DeleteFileA(dwl_htmlA); ok(res, "DeleteFile failed: %u\n", GetLastError()); if(prot != FILE_TEST || emul) @@ -2403,35 +2683,33 @@ static void test_URLDownloadToFile(DWORD prot, BOOL emul) hres = URLDownloadToFileW(NULL, urls[test_protocol], dwl_htmlW, 0, NULL); ok(hres == S_OK, "URLDownloadToFile failed: %08x\n", hres); - res = DeleteFileW(dwl_htmlW); + res = DeleteFileA(dwl_htmlA); ok(res, "DeleteFile failed: %u\n", GetLastError()); } -static void set_file_url(void) +static void set_file_url(char *path) { - int len; + CHAR file_urlA[INTERNET_MAX_URL_LENGTH]; + CHAR INDEX_HTMLA[MAX_PATH]; - static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'}; + lstrcpyA(file_urlA, "file:///"); + lstrcatA(file_urlA, path); + MultiByteToWideChar(CP_ACP, 0, file_urlA, -1, file_url, INTERNET_MAX_URL_LENGTH); - memcpy(file_url, wszFile, sizeof(wszFile)); - len = sizeof(wszFile)/sizeof(WCHAR); - file_url[len++] = '/'; - len += GetCurrentDirectoryW(sizeof(file_url)/sizeof(WCHAR)-len, file_url+len); - file_url[len++] = '\\'; - memcpy(file_url+len, wszIndexHtml, sizeof(wszIndexHtml)); - - memcpy(INDEX_HTML, wszFile, sizeof(wszIndexHtml)); - memmove(INDEX_HTML+7, file_url+8, (lstrlenW(file_url+8)+1)*sizeof(WCHAR)); + lstrcpyA(INDEX_HTMLA, "file://"); + lstrcatA(INDEX_HTMLA, path); + MultiByteToWideChar(CP_ACP, 0, INDEX_HTMLA, -1, INDEX_HTML, MAX_PATH); } static void create_file(void) { HANDLE file; DWORD size; + CHAR path[MAX_PATH]; static const char html_doc[] = ""; - file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + file = CreateFileA(wszIndexHtmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n"); if(file == INVALID_HANDLE_VALUE) @@ -2440,7 +2718,10 @@ static void create_file(void) WriteFile(file, html_doc, sizeof(html_doc)-1, &size, NULL); CloseHandle(file); - set_file_url(); + GetCurrentDirectoryA(MAX_PATH, path); + lstrcatA(path, "\\"); + lstrcatA(path, wszIndexHtmlA); + set_file_url(path); } static void test_ReportResult(HRESULT exhres) @@ -2457,13 +2738,16 @@ static void test_ReportResult(HRESULT exhres) ok(hres == S_OK, "CreateURLMoniker failed: %08x\n", hres); SET_EXPECT(QueryInterface_IServiceProvider); - hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx); + hres = CreateAsyncBindCtx(0, (IBindStatusCallback*)&bsc, NULL, &bctx); ok(hres == S_OK, "CreateAsyncBindCtx failed: %08x\n\n", hres); CHECK_CALLED(QueryInterface_IServiceProvider); + SET_EXPECT(QueryInterface_IBindStatusCallbackEx); SET_EXPECT(GetBindInfo); SET_EXPECT(QueryInterface_IInternetProtocol); SET_EXPECT(OnStartBinding); + if(is_urlmon_protocol(test_protocol)) + SET_EXPECT(SetPriority); SET_EXPECT(Start); hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk); @@ -2473,9 +2757,12 @@ static void test_ReportResult(HRESULT exhres) ok(hres == exhres || hres == MK_S_ASYNCHRONOUS, "BindToStorage failed: %08x, expected %08x or MK_S_ASYNCHRONOUS\n", hres, exhres); + CLEAR_CALLED(QueryInterface_IBindStatusCallbackEx); /* IE 8 */ CHECK_CALLED(GetBindInfo); CHECK_CALLED(QueryInterface_IInternetProtocol); CHECK_CALLED(OnStartBinding); + if(is_urlmon_protocol(test_protocol)) + CHECK_CALLED(SetPriority); CHECK_CALLED(Start); ok(unk == NULL, "unk=%p\n", unk); @@ -2511,6 +2798,29 @@ static void test_BindToStorage_fail(void) test_ReportResult(S_FALSE); } +static void test_StdURLMoniker(void) +{ + IMoniker *mon, *async_mon; + LPOLESTR display_name; + HRESULT hres; + + hres = CoCreateInstance(&IID_IInternet, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IMoniker, (void**)&mon); + ok(hres == S_OK, "Could not create IInternet instance: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IMoniker_QueryInterface(mon, &IID_IAsyncMoniker, (void**)&async_mon); + ok(hres == S_OK, "Could not get IAsyncMoniker iface: %08x\n", hres); + ok(mon == async_mon, "mon != async_mon\n"); + IMoniker_Release(async_mon); + + hres = IMoniker_GetDisplayName(mon, NULL, NULL, &display_name); + ok(hres == E_OUTOFMEMORY, "GetDisplayName failed: %08x, expected E_OUTOFMEMORY\n", hres); + + IMoniker_Release(mon); +} + static void gecko_installer_workaround(BOOL disable) { HKEY hkey; @@ -2551,9 +2861,16 @@ START_TEST(url) create_file(); test_create(); + + trace("test CreateAsyncBindCtx...\n"); test_CreateAsyncBindCtx(); + + trace("test CreateAsyncBindCtxEx...\n"); test_CreateAsyncBindCtxEx(); - test_RegisterBindStatusCallback(); + + trace("test RegisterBindStatusCallback...\n"); + if(test_RegisterBindStatusCallback()) { + trace("test BindToStorage failures...\n"); test_BindToStorage_fail(); trace("synchronous http test (COM not initialised)...\n"); @@ -2561,6 +2878,9 @@ START_TEST(url) CoInitialize(NULL); + trace("test StdURLMoniker...\n"); + test_StdURLMoniker(); + trace("synchronous http test...\n"); test_BindToStorage(HTTP_TEST, FALSE, TYMED_ISTREAM); @@ -2601,6 +2921,12 @@ START_TEST(url) trace("emulated http test (to file)...\n"); test_BindToStorage(HTTP_TEST, TRUE, TYMED_FILE); + trace("asynchronous https test...\n"); + test_BindToStorage(HTTPS_TEST, FALSE, TYMED_ISTREAM); + + trace("emulated https test...\n"); + test_BindToStorage(HTTPS_TEST, TRUE, TYMED_ISTREAM); + trace("about test...\n"); test_BindToStorage(ABOUT_TEST, FALSE, TYMED_ISTREAM); @@ -2655,10 +2981,16 @@ START_TEST(url) trace("test URLDownloadToFile for http protocol...\n"); test_URLDownloadToFile(HTTP_TEST, FALSE); + bindf |= BINDF_NOWRITECACHE; + + trace("ftp test...\n"); + test_BindToStorage(FTP_TEST, FALSE, TYMED_ISTREAM); + trace("test failures...\n"); test_BindToStorage_fail(); + } - DeleteFileW(wszIndexHtml); + DeleteFileA(wszIndexHtmlA); CloseHandle(complete_event); CloseHandle(complete_event2); CoUninitialize(); diff --git a/rostests/winetests/urlmon/urlmon.rbuild b/rostests/winetests/urlmon/urlmon.rbuild index 77302f3d260..593386f2b97 100644 --- a/rostests/winetests/urlmon/urlmon.rbuild +++ b/rostests/winetests/urlmon/urlmon.rbuild @@ -3,11 +3,11 @@ . - 0x600 - 0x600 + generated.c misc.c protocol.c + sec_mgr.c stream.c url.c testlist.c @@ -17,7 +17,6 @@ ole32 user32 advapi32 - kernel32 ntdll diff --git a/rostests/winetests/user32/broadcast.c b/rostests/winetests/user32/broadcast.c index 786df7d698a..8e4dcf6d9eb 100644 --- a/rostests/winetests/user32/broadcast.c +++ b/rostests/winetests/user32/broadcast.c @@ -18,12 +18,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define _WIN32_WINNT 0x0501 + #include #include #include -#define _WIN32_WINNT 0x0501 - #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -66,7 +66,10 @@ static BOOL init_procs(void) pBroadcastA = (PBROADCAST)GetProcAddress(user32, "BroadcastSystemMessage"); ok(pBroadcastA != NULL, "No BroadcastSystemMessage found\n"); if (!pBroadcastA) + { + win_skip("BroadcastA is not available\n"); return FALSE; + } pBroadcastW = (PBROADCAST)GetProcAddress(user32, "BroadcastSystemMessageW"); pBroadcastExA = (PBROADCASTEX)GetProcAddress(user32, "BroadcastSystemMessageExA"); @@ -80,13 +83,13 @@ static BOOL init_procs(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "MainWindowClass"; if (!RegisterClassA(&cls)) - return 0; + return FALSE; if (!CreateWindowExA(0, "MainWindowClass", "Main window", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, 100, 100, 200, @@ -105,17 +108,17 @@ static void test_parameters(PBROADCAST broadcast, const char *functionname) ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 ); if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("%s is not implemented\n", functionname); + win_skip("%s is not implemented\n", functionname); return; } - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); - ok(!ret, "Returned: %d\n", ret); + ok(!ret || broken(ret), "Returned: %d\n", ret); + if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); SetLastError(0xcafebabe); recips = BSM_APPLICATIONS; ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 ); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); - ok(!ret, "Returned: %d\n", ret); + ok(!ret || broken(ret), "Returned: %d\n", ret); + if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); #if 0 /* TODO: Check the hang flags */ SetLastError(0xcafebabe); @@ -150,8 +153,11 @@ static void test_parameters(PBROADCAST broadcast, const char *functionname) ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); PulseEvent(hevent); + SetLastError( 0xdeadbeef ); recips = BSM_APPLICATIONS; ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 ); + if (ret) + { ok(ret==1, "Returned: %d\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n"); PulseEvent(hevent); @@ -167,6 +173,9 @@ static void test_parameters(PBROADCAST broadcast, const char *functionname) ok(!ret, "Returned: %d\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); PulseEvent(hevent); + } + else /* BSF_SENDNOTIFYMESSAGE not supported on NT4 */ + ok( GetLastError() == ERROR_INVALID_PARAMETER, "failed with err %u\n", GetLastError() ); recips = BSM_APPLICATIONS; ret = broadcast( 0, &recips, WM_NULL, 100, 0 ); @@ -264,6 +273,9 @@ static void test_noprivileges(void) DWORD recips; BOOL ret; + static const DWORD BSM_ALL_RECIPS = BSM_VXDS | BSM_NETDRIVER | + BSM_INSTALLABLEDRIVERS | BSM_APPLICATIONS; + pOpenProcessToken = (void *)GetProcAddress(advapi32, "OpenProcessToken"); pAdjustTokenPrivileges = (void *)GetProcAddress(advapi32, "AdjustTokenPrivileges"); if (!pOpenProcessToken || !pAdjustTokenPrivileges || !pOpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) @@ -282,41 +294,44 @@ static void test_noprivileges(void) recips = BSM_ALLDESKTOPS; ResetEvent(hevent); ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); - todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError()); - ok(ret==1, "Returned: %d\n", ret); + ok(ret==1, "Returned: %d error %u\n", ret, GetLastError()); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - ok(recips == BSM_ALLDESKTOPS, "Received by: %08x\n", recips); + ok(recips == BSM_ALLDESKTOPS || + recips == BSM_ALL_RECIPS, /* win2k3 */ + "Received by: %08x\n", recips); PulseEvent(hevent); - /* Wine sets last error to 0, so just use that one as token here so it doesn't fail */ - SetLastError(0); + SetLastError(0xcafebabe); recips = BSM_ALLCOMPONENTS; ResetEvent(hevent); ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); - ok(!GetLastError(), "Last error: %08x\n", GetLastError()); - ok(ret==1, "Returned: %d\n", ret); + ok(ret==1, "Returned: %d error %u\n", ret, GetLastError()); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - ok(recips == BSM_ALLCOMPONENTS, "Received by: %08x\n", recips); + ok(recips == BSM_ALLCOMPONENTS || + recips == BSM_ALL_RECIPS, /* win2k3 */ + "Received by: %08x\n", recips); PulseEvent(hevent); SetLastError(0xcafebabe); recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS; ResetEvent(hevent); ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); - todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError()); - ok(ret==1, "Returned: %d\n", ret); + ok(ret==1, "Returned: %d error %u\n", ret, GetLastError()); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS), "Received by: %08x\n", recips); + ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) || + recips == BSM_APPLICATIONS, /* win2k3 */ + "Received by: %08x\n", recips); PulseEvent(hevent); SetLastError(0xcafebabe); recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS; ResetEvent(hevent); ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL ); - todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError()); ok(!ret, "Returned: %d\n", ret); ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); - ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS), "Received by: %08x\n", recips); + ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) || + recips == BSM_APPLICATIONS, /* win2k3 */ + "Received by: %08x\n", recips); PulseEvent(hevent); } @@ -333,14 +348,14 @@ START_TEST(broadcast) test_parameters(pBroadcastW, "BroadcastSystemMessageW"); } else - skip("No BroadcastSystemMessageW, skipping\n"); + win_skip("No BroadcastSystemMessageW, skipping\n"); if (pBroadcastExA) { trace("Running BroadcastSystemMessageExA tests\n"); test_parametersEx(pBroadcastExA); } else - skip("No BroadcastSystemMessageExA, skipping\n"); + win_skip("No BroadcastSystemMessageExA, skipping\n"); if (pBroadcastExW) { trace("Running BroadcastSystemMessageExW tests\n"); @@ -349,5 +364,5 @@ START_TEST(broadcast) test_noprivileges(); } else - skip("No BroadcastSystemMessageExW, skipping\n"); + win_skip("No BroadcastSystemMessageExW, skipping\n"); } diff --git a/rostests/winetests/user32/class.c b/rostests/winetests/user32/class.c index 486e227be1a..090fcce1ec2 100755 --- a/rostests/winetests/user32/class.c +++ b/rostests/winetests/user32/class.c @@ -39,15 +39,17 @@ static const WCHAR WC_EDITW[] = {'E','d','i','t',0}; #define NUMCLASSWORDS 4 -#define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~((ULONG_PTR)0) >> 16)) +#define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16)) static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + if (msg == WM_NCCREATE) return 1; return DefWindowProcW (hWnd, msg, wParam, lParam); } static LRESULT WINAPI ClassTest_WndProc2 (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + if (msg == WM_NCCREATE) return 1; return DefWindowProcA (hWnd, msg, wParam, lParam); } @@ -234,42 +236,48 @@ static void test_styles(void) check_style( "#32772", 1, 0, 0 ); /* icon title */ } -static void check_class(HINSTANCE inst, const char *name, const char *menu_name) +static void check_class_(int line, HINSTANCE inst, const char *name, const char *menu_name) { WNDCLASS wc; UINT atom = GetClassInfo(inst,name,&wc); - ok( atom, "Class %s %p not found\n", name, inst ); + ok_(__FILE__,line)( atom, "Class %s %p not found\n", name, inst ); if (atom) { if (wc.lpszMenuName && menu_name) - ok( !strcmp( menu_name, wc.lpszMenuName ), "Wrong name %s/%s for class %s %p\n", + ok_(__FILE__,line)( !strcmp( menu_name, wc.lpszMenuName ), + "Wrong name %s/%s for class %s %p\n", wc.lpszMenuName, menu_name, name, inst ); else - ok( !menu_name == !wc.lpszMenuName, "Wrong name %p/%p for class %s %p\n", + ok_(__FILE__,line)( !menu_name == !wc.lpszMenuName, "Wrong name %p/%p for class %s %p\n", wc.lpszMenuName, menu_name, name, inst ); } } +#define check_class(inst,name,menu) check_class_(__LINE__,inst,name,menu) -static void check_instance( const char *name, HINSTANCE inst, HINSTANCE info_inst, HINSTANCE gcl_inst ) +static void check_instance_( int line, const char *name, HINSTANCE inst, + HINSTANCE info_inst, HINSTANCE gcl_inst ) { WNDCLASSA wc; HWND hwnd; - ok( GetClassInfo( inst, name, &wc ), "Couldn't find class %s inst %p\n", name, inst ); - ok( wc.hInstance == info_inst, "Wrong info instance %p/%p for class %s\n", + ok_(__FILE__,line)( GetClassInfo( inst, name, &wc ), "Couldn't find class %s inst %p\n", name, inst ); + ok_(__FILE__,line)( wc.hInstance == info_inst, "Wrong info instance %p/%p for class %s\n", wc.hInstance, info_inst, name ); hwnd = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, inst, 0 ); - ok( hwnd != NULL, "Couldn't create window for class %s inst %p\n", name, inst ); - ok( (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ) == gcl_inst, + ok_(__FILE__,line)( hwnd != NULL, "Couldn't create window for class %s inst %p\n", name, inst ); + ok_(__FILE__,line)( (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ) == gcl_inst, "Wrong GCL instance %p/%p for class %s\n", (HINSTANCE)GetClassLongPtrA( hwnd, GCLP_HMODULE ), gcl_inst, name ); - ok( (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ) == inst, + ok_(__FILE__,line)( (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ) == inst, "Wrong GWL instance %p/%p for window %s\n", (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ), inst, name ); - ok(!UnregisterClassA(name, inst), "UnregisterClassA should fail while exists a class window\n"); - ok(GetLastError() == ERROR_CLASS_HAS_WINDOWS, "GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS not %d\n", GetLastError()); + ok_(__FILE__,line)(!UnregisterClassA(name, inst), + "UnregisterClassA should fail while exists a class window\n"); + ok_(__FILE__,line)(GetLastError() == ERROR_CLASS_HAS_WINDOWS, + "GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS not %d\n", GetLastError()); DestroyWindow(hwnd); } +#define check_instance(name,inst,info_inst,gcl_inst) check_instance_(__LINE__,name,inst,info_inst,gcl_inst) struct class_info { @@ -279,7 +287,7 @@ struct class_info static DWORD WINAPI thread_proc(void *param) { - struct class_info *class_info = (struct class_info *)param; + struct class_info *class_info = param; check_instance(class_info->name, class_info->inst, class_info->info_inst, class_info->gcl_inst); @@ -364,6 +372,7 @@ static void test_instances(void) /* setting global flag doesn't change status of class */ hwnd = CreateWindowExA( 0, name, "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 ); + ok( hwnd != 0, "CreateWindow failed error %u\n", GetLastError()); SetClassLongA( hwnd, GCL_STYLE, CS_GLOBALCLASS ); cls.lpszMenuName = "kernel32"; cls.hInstance = kernel32; @@ -415,7 +424,7 @@ static void test_instances(void) cls.style = 3; ok( RegisterClassA( &cls ), "Failed to register local class for deadbeef\n" ); hwnd2 = CreateWindowExA( 0, name, "test_window", 0, 0, 0, 0, 0, 0, 0, NULL, 0 ); - ok( (HINSTANCE)GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == (HINSTANCE)0xdeadbeef, + ok( GetClassLongPtrA( hwnd2, GCLP_HMODULE ) == 0xdeadbeef, "Didn't get deadbeef class for null instance\n" ); DestroyWindow( hwnd2 ); ok( UnregisterClassA( name, (HINSTANCE)0xdeadbeef ), "Unregister failed for deadbeef\n" ); @@ -554,10 +563,7 @@ static void test_instances(void) ok( !UnregisterClass( "BUTTON", (HINSTANCE)0x87654321 ), "Unregistered button a second time\n" ); ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %d\n", GetLastError() ); ok( !GetClassInfo( 0, "BUTTON", &wc ), "Button still exists\n" ); - ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST || - GetLastError() == ERROR_INVALID_PARAMETER || /* W2K3 */ - GetLastError() == ERROR_SUCCESS /* Vista */, - "Wrong error code %d\n", GetLastError() ); + /* last error not set reliably */ /* we can change the instance of a system class */ check_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 ); @@ -566,17 +572,19 @@ static void test_instances(void) SetClassLongPtrA( hwnd, GCLP_HMODULE, 0xdeadbeef ); check_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef ); check_thread_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef ); + DestroyWindow(hwnd); } static void test_builtinproc(void) { - /* Edit behaves differently. ScrollBar have currently only a Unicode winproc */ + /* Edit behaves differently */ static const CHAR NORMAL_CLASSES[][10] = { "Button", "Static", "ComboBox", "ComboLBox", "ListBox", + "ScrollBar", "#32770", /* dialog */ }; static const int NUM_NORMAL_CLASSES = (sizeof(NORMAL_CLASSES)/sizeof(NORMAL_CLASSES[0])); @@ -700,6 +708,7 @@ static void test_builtinproc(void) oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); ok(IS_WNDPROC_HANDLE(oldproc) == FALSE, "Class %s shouldn't return a handle\n", NORMAL_CLASSES[i]); + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); DestroyWindow(hwnd); } @@ -740,6 +749,8 @@ static void test_builtinproc(void) CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n"); + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); + DestroyWindow(hwnd); hwnd = CreateWindowA(WC_EDITA, classA, WS_OVERLAPPEDWINDOW, @@ -761,7 +772,7 @@ static void test_builtinproc(void) CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n"); - SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); + oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); SetWindowTextW(hwnd, unistring); CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n"); @@ -774,6 +785,8 @@ static void test_builtinproc(void) CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf); ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n"); + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc); + DestroyWindow(hwnd); } @@ -796,13 +809,11 @@ static BOOL RegisterTestDialog(HINSTANCE hInstance) wcx.hInstance = hInstance; wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcx.hCursor = LoadCursor(NULL, IDC_ARROW); - wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wcx.hbrBackground = GetStockObject(WHITE_BRUSH); wcx.lpszClassName = "TestDialog"; wcx.lpszMenuName = "TestDialog"; - wcx.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(5), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), + wcx.hIconSm = LoadImage(hInstance, MAKEINTRESOURCE(5), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); atom = RegisterClassEx(&wcx); @@ -813,7 +824,7 @@ static BOOL RegisterTestDialog(HINSTANCE hInstance) /* test registering a dialog box created by using the CLASS directive in a resource file, then test creating the dialog using CreateDialogParam. */ -static void WINAPI CreateDialogParamTest(HINSTANCE hInstance) +static void CreateDialogParamTest(HINSTANCE hInstance) { HWND hWndMain; @@ -826,10 +837,42 @@ static void WINAPI CreateDialogParamTest(HINSTANCE hInstance) } } +static const struct +{ + const char name[9]; + int value; + int badvalue; +} extra_values[] = +{ + {"#32770",30,30}, /* Dialog */ +#ifdef _WIN64 + {"Edit",8,8}, +#else + {"Edit",6,8}, /* Windows XP 64-bit returns 8 also to 32-bit applications */ +#endif +}; + +static void test_extra_values(void) +{ + int i; + for(i=0; i< sizeof(extra_values)/sizeof(extra_values[0]); i++) + { + WNDCLASSEX wcx; + BOOL ret = GetClassInfoEx(NULL,extra_values[i].name,&wcx); + + ok( ret, "GetClassInfo (0) failed for global class %s\n", extra_values[i].name); + if (!ret) continue; + ok(extra_values[i].value == wcx.cbWndExtra || broken(extra_values[i].badvalue == wcx.cbWndExtra), + "expected %d, got %d\n", extra_values[i].value, wcx.cbWndExtra); + } +} + START_TEST(class) { HANDLE hInstance = GetModuleHandleA( NULL ); + test_extra_values(); + if (!GetModuleHandleW(0)) { trace("Class test is incompatible with Win9x implementation, skipping\n"); diff --git a/rostests/winetests/user32/clipboard.c b/rostests/winetests/user32/clipboard.c index 30b170759a2..e2ba2f92e5e 100755 --- a/rostests/winetests/user32/clipboard.c +++ b/rostests/winetests/user32/clipboard.c @@ -21,6 +21,7 @@ #include "wine/test.h" #include "winbase.h" #include "winerror.h" +#include "wingdi.h" #include "winuser.h" static BOOL is_win9x = FALSE; @@ -190,6 +191,77 @@ todo_wine test_last_error(ERROR_CLIPBOARD_NOT_OPEN); } +static HGLOBAL create_text(void) +{ + HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5); + char *p = GlobalLock(h); + strcpy(p, "test"); + GlobalUnlock(h); + return h; +} + +static HENHMETAFILE create_emf(void) +{ + const RECT rect = {0, 0, 100, 100}; + HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0"); + ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL); + return CloseEnhMetaFile(hdc); +} + +static void test_synthesized(void) +{ + HGLOBAL h, htext; + HENHMETAFILE emf; + BOOL r; + UINT cf; + + htext = create_text(); + emf = create_emf(); + + r = OpenClipboard(NULL); + ok(r, "gle %d\n", GetLastError()); + r = EmptyClipboard(); + ok(r, "gle %d\n", GetLastError()); + h = SetClipboardData(CF_TEXT, htext); + ok(h == htext, "got %p\n", h); + h = SetClipboardData(CF_ENHMETAFILE, emf); + ok(h == emf, "got %p\n", h); + r = CloseClipboard(); + ok(r, "gle %d\n", GetLastError()); + + r = OpenClipboard(NULL); + ok(r, "gle %d\n", GetLastError()); + cf = EnumClipboardFormats(0); + ok(cf == CF_TEXT, "cf %08x\n", cf); + + cf = EnumClipboardFormats(cf); + ok(cf == CF_ENHMETAFILE, "cf %08x\n", cf); + + cf = EnumClipboardFormats(cf); + todo_wine ok(cf == CF_LOCALE, "cf %08x\n", cf); + if(cf == CF_LOCALE) + cf = EnumClipboardFormats(cf); + ok(cf == CF_OEMTEXT, "cf %08x\n", cf); + + cf = EnumClipboardFormats(cf); + ok(cf == CF_UNICODETEXT || + broken(cf == CF_METAFILEPICT), /* win9x and winME has no CF_UNICODETEXT */ + "cf %08x\n", cf); + + if(cf == CF_UNICODETEXT) + cf = EnumClipboardFormats(cf); + ok(cf == CF_METAFILEPICT, "cf %08x\n", cf); + + cf = EnumClipboardFormats(cf); + ok(cf == 0, "cf %08x\n", cf); + + r = EmptyClipboard(); + ok(r, "gle %d\n", GetLastError()); + + r = CloseClipboard(); + ok(r, "gle %d\n", GetLastError()); +} + START_TEST(clipboard) { SetLastError(0xdeadbeef); @@ -198,4 +270,5 @@ START_TEST(clipboard) test_RegisterClipboardFormatA(); test_ClipboardOwner(); + test_synthesized(); } diff --git a/rostests/winetests/user32/combo.c b/rostests/winetests/user32/combo.c index 34d8c7ab304..8108dce05c4 100644 --- a/rostests/winetests/user32/combo.c +++ b/rostests/winetests/user32/combo.c @@ -94,28 +94,29 @@ static void test_setitemheight(DWORD style) static void test_setfont(DWORD style) { - HWND hCombo = build_combo(style); - HFONT hFont1 = CreateFont(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); - HFONT hFont2 = CreateFont(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); + HWND hCombo; + HFONT hFont1, hFont2; RECT r; int i; + if (!is_font_installed("Marlett")) + { + skip("Marlett font not available\n"); + return; + } + trace("Style %x\n", style); + + hCombo = build_combo(style); + hFont1 = CreateFont(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); + hFont2 = CreateFont(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); + GetClientRect(hCombo, &r); expect_rect(r, 0, 0, 100, 24); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); todo_wine expect_rect(r, 5, 5, 105, 105); - if (!is_font_installed("Marlett")) - { - skip("Marlett font not available\n"); - DestroyWindow(hCombo); - DeleteObject(hFont1); - DeleteObject(hFont2); - return; - } - if (font_height(hFont1) == 10 && font_height(hFont2) == 8) { SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); @@ -140,11 +141,14 @@ static void test_setfont(DWORD style) todo_wine expect_rect(r, 5, 5, 105, 99); } else - skip("Invalid Marlett font heights\n"); + { + ok(0, "Expected Marlett font heights 10/8, got %d/%d\n", + font_height(hFont1), font_height(hFont2)); + } for (i = 1; i < 30; i++) { - HFONT hFont = CreateFont(i, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); + HFONT hFont = CreateFont(i, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); int height = font_height(hFont); SendMessage(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE); @@ -265,6 +269,138 @@ static void test_CBN_SELCHANGE(void) test_selection(CBS_DROPDOWNLIST, text, sel_2, sel_2); } +static void test_WM_LBUTTONDOWN(void) +{ + HWND hCombo, hEdit, hList; + COMBOBOXINFO cbInfo; + UINT x, y, item_height; + LRESULT result; + int i, idx; + RECT rect; + CHAR buffer[3]; + static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72}; + static const CHAR stringFormat[] = "%2d"; + BOOL ret; + BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO); + + pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo"); + if (!pGetComboBoxInfo){ + win_skip("GetComboBoxInfo is not available\n"); + return; + } + + hCombo = CreateWindow("ComboBox", "Combo", WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, + 0, 0, 200, 150, hMainWnd, (HMENU)COMBO_ID, NULL, 0); + + for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){ + sprintf(buffer, stringFormat, choices[i]); + result = SendMessageA(hCombo, CB_ADDSTRING, 0, (LPARAM)buffer); + ok(result == i, + "Failed to add item %d\n", i); + } + + cbInfo.cbSize = sizeof(COMBOBOXINFO); + SetLastError(0xdeadbeef); + ret = pGetComboBoxInfo(hCombo, &cbInfo); + ok(ret, "Failed to get combobox info structure. LastError=%d\n", + GetLastError()); + hEdit = cbInfo.hwndItem; + hList = cbInfo.hwndList; + + trace("hMainWnd=%p, hCombo=%p, hList=%p, hEdit=%p\n", hMainWnd, hCombo, hList, hEdit); + ok(GetFocus() == hMainWnd, "Focus not on Main Window, instead on %p\n", GetFocus()); + + /* Click on the button to drop down the list */ + x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2; + y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2; + result = SendMessage(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); + ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + GetLastError()); + ok(SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0), + "The dropdown list should have appeared after clicking the button.\n"); + + ok(GetFocus() == hEdit, + "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); + result = SendMessage(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); + ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hEdit, + "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); + + /* Click on the 5th item in the list */ + item_height = SendMessage(hCombo, CB_GETITEMHEIGHT, 0, 0); + ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n"); + x = rect.left + (rect.right-rect.left)/2; + y = item_height/2 + item_height*4; + result = SendMessage(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); + ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hEdit, + "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); + + result = SendMessage(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y)); + ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hEdit, + "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); + ok(SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0), + "The dropdown list should still be visible.\n"); + + result = SendMessage(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); + ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hEdit, + "Focus not on ComboBox's Edit Control, instead on %p\n", GetFocus()); + ok(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0), + "The dropdown list should have been rolled up.\n"); + idx = SendMessage(hCombo, CB_GETCURSEL, 0, 0); + ok(idx, "Current Selection: expected %d, got %d\n", 4, idx); + + DestroyWindow(hCombo); +} + +static void test_changesize( DWORD style) +{ + HWND hCombo = build_combo(style); + RECT rc; + INT ddheight, clheight, ddwidth, clwidth; + /* get initial measurements */ + GetClientRect( hCombo, &rc); + clheight = rc.bottom - rc.top; + clwidth = rc.right - rc.left; + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); + ddheight = rc.bottom - rc.top; + ddwidth = rc.right - rc.left; + /* use MoveWindow to move & resize the combo */ + /* first make it slightly smaller */ + MoveWindow( hCombo, 10, 10, clwidth - 2, clheight - 2, TRUE); + GetClientRect( hCombo, &rc); + ok( rc.right - rc.left == clwidth - 2, "clientrect witdh is %d vs %d\n", + rc.right - rc.left, clwidth - 2); + ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n", + rc.bottom - rc.top, clheight); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); + ok( rc.right - rc.left == clwidth - 2, "drop-down rect witdh is %d vs %d\n", + rc.right - rc.left, clwidth - 2); + ok( rc.bottom - rc.top == ddheight, "drop-down rect height is %d vs %d\n", + rc.bottom - rc.top, ddheight); + /* new cx, cy is slightly bigger than the initial values */ + MoveWindow( hCombo, 10, 10, clwidth + 2, clheight + 2, TRUE); + GetClientRect( hCombo, &rc); + ok( rc.right - rc.left == clwidth + 2, "clientrect witdh is %d vs %d\n", + rc.right - rc.left, clwidth + 2); + ok( rc.bottom - rc.top == clheight, "clientrect height is %d vs %d\n", + rc.bottom - rc.top, clheight); + SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rc); + ok( rc.right - rc.left == clwidth + 2, "drop-down rect witdh is %d vs %d\n", + rc.right - rc.left, clwidth + 2); + todo_wine { + ok( rc.bottom - rc.top == clheight + 2, "drop-down rect height is %d vs %d\n", + rc.bottom - rc.top, clheight + 2); + } + DestroyWindow(hCombo); +} + START_TEST(combo) { hMainWnd = CreateWindow("static", "Test", WS_OVERLAPPEDWINDOW, 10, 10, 300, 300, NULL, NULL, NULL, 0); @@ -275,6 +411,9 @@ START_TEST(combo) test_setitemheight(CBS_DROPDOWN); test_setitemheight(CBS_DROPDOWNLIST); test_CBN_SELCHANGE(); + test_WM_LBUTTONDOWN(); + test_changesize(CBS_DROPDOWN); + test_changesize(CBS_DROPDOWNLIST); DestroyWindow(hMainWnd); } diff --git a/rostests/winetests/user32/cursoricon.c b/rostests/winetests/user32/cursoricon.c index 40f3a1413f2..f33a7d9304a 100644 --- a/rostests/winetests/user32/cursoricon.c +++ b/rostests/winetests/user32/cursoricon.c @@ -76,11 +76,10 @@ static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARA SetLastError(0xdeadbeef); ret = DestroyCursor((HCURSOR) lParam); error = GetLastError(); - todo_wine { - ok(!ret, "DestroyCursor on the active cursor succeeded.\n"); - ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD, + todo_wine ok(!ret || broken(ret) /* win9x */, "DestroyCursor on the active cursor succeeded.\n"); + ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD || + error == 0xdeadbeef, /* vista */ "Last error: %u\n", error); - } return TRUE; case WM_DESTROY: PostQuitMessage(0); @@ -132,7 +131,7 @@ static void do_child(void) PostMessage(parent, PROC_INIT, (WPARAM) child, 0); /* Receive messages. */ - while ((ret = GetMessage(&msg, child, 0, 0))) + while ((ret = GetMessage(&msg, 0, 0, 0))) { ok(ret != -1, "GetMessage failed. Error: %u\n", GetLastError()); TranslateMessage(&msg); @@ -176,7 +175,7 @@ static void do_parent(void) startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; - sprintf(path_name, "%s cursoricon %x", test_argv[0], (unsigned int) parent); + sprintf(path_name, "%s cursoricon %lx", test_argv[0], (INT_PTR)parent); ok(CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess failed.\n"); child_process = info.hProcess; @@ -233,7 +232,7 @@ static void test_CopyImage_Check(HBITMAP bitmap, UINT flags, INT copyWidth, INT BOOL orig_is_dib; BOOL copy_is_dib; - copy = (HBITMAP) CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags); + copy = CopyImage(bitmap, IMAGE_BITMAP, copyWidth, copyHeight, flags); ok(copy != NULL, "CopyImage() failed\n"); if (copy != NULL) { @@ -504,13 +503,14 @@ static void test_CreateIcon(void) static const BYTE bmp_bits[1024]; HICON hIcon; HBITMAP hbmMask, hbmColor; + BITMAPINFO *bmpinfo; ICONINFO info; HDC hdc; + void *bits; UINT display_bpp; hdc = GetDC(0); display_bpp = GetDeviceCaps(hdc, BITSPIXEL); - ReleaseDC(0, hdc); /* these crash under XP hIcon = CreateIcon(0, 16, 16, 1, 1, bmp_bits, NULL); @@ -581,6 +581,78 @@ static void test_CreateIcon(void) DeleteObject(hbmMask); DeleteObject(hbmColor); + + /* test creating an icon from a DIB section */ + + bmpinfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO,bmiColors[256])); + bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmpinfo->bmiHeader.biWidth = 32; + bmpinfo->bmiHeader.biHeight = 32; + bmpinfo->bmiHeader.biPlanes = 1; + bmpinfo->bmiHeader.biBitCount = 8; + bmpinfo->bmiHeader.biCompression = BI_RGB; + hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 ); + ok(hbmColor != NULL, "Expected a handle to the DIB\n"); + if (bits) + memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 ); + bmpinfo->bmiHeader.biBitCount = 1; + hbmMask = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 ); + ok(hbmMask != NULL, "Expected a handle to the DIB\n"); + if (bits) + memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 ); + + info.fIcon = TRUE; + info.xHotspot = 8; + info.yHotspot = 8; + info.hbmMask = hbmColor; + info.hbmColor = hbmMask; + SetLastError(0xdeadbeaf); + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + test_icon_info(hIcon, 32, 32, 8); + DestroyIcon(hIcon); + DeleteObject(hbmColor); + + bmpinfo->bmiHeader.biBitCount = 16; + hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 ); + ok(hbmColor != NULL, "Expected a handle to the DIB\n"); + if (bits) + memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 ); + + info.fIcon = TRUE; + info.xHotspot = 8; + info.yHotspot = 8; + info.hbmMask = hbmColor; + info.hbmColor = hbmMask; + SetLastError(0xdeadbeaf); + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + test_icon_info(hIcon, 32, 32, 8); + DestroyIcon(hIcon); + DeleteObject(hbmColor); + + bmpinfo->bmiHeader.biBitCount = 32; + hbmColor = CreateDIBSection( hdc, bmpinfo, DIB_RGB_COLORS, &bits, NULL, 0 ); + ok(hbmColor != NULL, "Expected a handle to the DIB\n"); + if (bits) + memset( bits, 0x55, 32 * 32 * bmpinfo->bmiHeader.biBitCount / 8 ); + + info.fIcon = TRUE; + info.xHotspot = 8; + info.yHotspot = 8; + info.hbmMask = hbmColor; + info.hbmColor = hbmMask; + SetLastError(0xdeadbeaf); + hIcon = CreateIconIndirect(&info); + ok(hIcon != 0, "CreateIconIndirect failed\n"); + test_icon_info(hIcon, 32, 32, 8); + DestroyIcon(hIcon); + + DeleteObject(hbmMask); + DeleteObject(hbmColor); + HeapFree( GetProcessHeap(), 0, bmpinfo ); + + ReleaseDC(0, hdc); } /* Shamelessly ripped from dlls/oleaut32/tests/olepicture.c */ @@ -664,7 +736,10 @@ static void test_LoadImageFile(const unsigned char * image_data, handle = LoadImageA(NULL, filename, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); ok(handle == NULL, "LoadImage(%s) as IMAGE_CURSOR succeeded incorrectly.\n", ext); error = GetLastError(); - ok(error == 0, "Last error: %u\n", error); + ok(error == 0 || + broken(error == 0xdeadbeef) || /* Win9x */ + broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */ + "Last error: %u\n", error); if (handle != NULL) DestroyCursor(handle); /* Load as icon. For all tested formats, this should fail */ @@ -672,7 +747,10 @@ static void test_LoadImageFile(const unsigned char * image_data, handle = LoadImageA(NULL, filename, IMAGE_ICON, 0, 0, LR_LOADFROMFILE); ok(handle == NULL, "LoadImage(%s) as IMAGE_ICON succeeded incorrectly.\n", ext); error = GetLastError(); - ok(error == 0, "Last error: %u\n", error); + ok(error == 0 || + broken(error == 0xdeadbeef) || /* Win9x */ + broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */ + "Last error: %u\n", error); if (handle != NULL) DestroyIcon(handle); /* Load as bitmap. Should succeed if bmp, fail for everything else */ @@ -682,7 +760,9 @@ static void test_LoadImageFile(const unsigned char * image_data, ok(handle != NULL, "LoadImage(%s) as IMAGE_BITMAP failed.\n", ext); else ok(handle == NULL, "LoadImage(%s) as IMAGE_BITMAP succeeded incorrectly.\n", ext); error = GetLastError(); - ok(error == 0, "Last error: %u\n", error); + ok(error == 0 || + error == 0xdeadbeef, /* Win9x, WinMe */ + "Last error: %u\n", error); if (handle != NULL) DeleteObject(handle); DeleteFileA(filename); @@ -741,15 +821,16 @@ static void test_LoadImage(void) /* Test loading an icon as a cursor. */ SetLastError(0xdeadbeef); handle = LoadImageA(NULL, "icon.ico", IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); - todo_wine ok(handle != NULL, "LoadImage() failed.\n"); error = GetLastError(); - ok(error == 0, "Last error: %u\n", error); + ok(error == 0 || + broken(error == 0xdeadbeef) || /* Win9x */ + broken(error == ERROR_BAD_PATHNAME), /* Win98, WinMe */ + "Last error: %u\n", error); /* Test the icon information. */ SetLastError(0xdeadbeef); ret = GetIconInfo(handle, &icon_info); - todo_wine ok(ret, "GetIconInfo() failed.\n"); error = GetLastError(); ok(error == 0xdeadbeef, "Last error: %u\n", error); @@ -759,14 +840,14 @@ static void test_LoadImage(void) ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n"); ok(icon_info.xHotspot == 1, "xHotspot is %u.\n", icon_info.xHotspot); ok(icon_info.yHotspot == 1, "yHotspot is %u.\n", icon_info.yHotspot); - ok(icon_info.hbmColor != NULL, "No hbmColor!\n"); + ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */, + "No hbmColor!\n"); ok(icon_info.hbmMask != NULL, "No hbmMask!\n"); } /* Clean up. */ SetLastError(0xdeadbeef); ret = DestroyCursor(handle); - todo_wine ok(ret, "DestroyCursor() failed.\n"); error = GetLastError(); ok(error == 0xdeadbeef, "Last error: %u\n", error); @@ -781,6 +862,497 @@ static void test_LoadImage(void) test_LoadImageFile(pngimage, sizeof(pngimage), "png", 0); } +static void test_CreateIconFromResource(void) +{ + HANDLE handle; + BOOL ret; + DWORD error; + BITMAPINFOHEADER *icon_header; + INT16 *hotspot; + ICONINFO icon_info; + +#define ICON_RES_WIDTH 32 +#define ICON_RES_HEIGHT 32 +#define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8) +#define ICON_RES_BPP 32 +#define ICON_RES_SIZE \ + (sizeof(BITMAPINFOHEADER) + ICON_AND_SIZE + ICON_AND_SIZE*ICON_BPP) +#define CRSR_RES_SIZE (2*sizeof(INT16) + ICON_RES_SIZE) + + /* Set icon data. */ + hotspot = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, CRSR_RES_SIZE); + + /* Cursor resources have an extra hotspot, icon resources not. */ + hotspot[0] = 3; + hotspot[1] = 3; + + icon_header = (BITMAPINFOHEADER *) (hotspot + 2); + icon_header->biSize = sizeof(BITMAPINFOHEADER); + icon_header->biWidth = ICON_WIDTH; + icon_header->biHeight = ICON_HEIGHT*2; + icon_header->biPlanes = 1; + icon_header->biBitCount = ICON_BPP; + icon_header->biSizeImage = 0; /* Uncompressed bitmap. */ + + /* Test creating a cursor. */ + SetLastError(0xdeadbeef); + handle = CreateIconFromResource((PBYTE) hotspot, CRSR_RES_SIZE, FALSE, 0x00030000); + ok(handle != NULL, "Create cursor failed.\n"); + + /* Test the icon information. */ + SetLastError(0xdeadbeef); + ret = GetIconInfo(handle, &icon_info); + ok(ret, "GetIconInfo() failed.\n"); + error = GetLastError(); + ok(error == 0xdeadbeef, "Last error: %u\n", error); + + if (ret) + { + ok(icon_info.fIcon == FALSE, "fIcon != FALSE.\n"); + ok(icon_info.xHotspot == 3, "xHotspot is %u.\n", icon_info.xHotspot); + ok(icon_info.yHotspot == 3, "yHotspot is %u.\n", icon_info.yHotspot); + ok(icon_info.hbmColor != NULL || broken(!icon_info.hbmColor) /* no color cursor support */, + "No hbmColor!\n"); + ok(icon_info.hbmMask != NULL, "No hbmMask!\n"); + } + + /* Clean up. */ + SetLastError(0xdeadbeef); + ret = DestroyCursor(handle); + ok(ret, "DestroyCursor() failed.\n"); + error = GetLastError(); + ok(error == 0xdeadbeef, "Last error: %u\n", error); + + /* Test creating an icon. */ + SetLastError(0xdeadbeef); + handle = CreateIconFromResource((PBYTE) icon_header, ICON_RES_SIZE, TRUE, + 0x00030000); + ok(handle != NULL, "Create icon failed.\n"); + + /* Test the icon information. */ + SetLastError(0xdeadbeef); + ret = GetIconInfo(handle, &icon_info); + ok(ret, "GetIconInfo() failed.\n"); + error = GetLastError(); + ok(error == 0xdeadbeef, "Last error: %u\n", error); + + if (ret) + { + ok(icon_info.fIcon == TRUE, "fIcon != TRUE.\n"); + /* Icons always have hotspot in the middle */ + ok(icon_info.xHotspot == ICON_WIDTH/2, "xHotspot is %u.\n", icon_info.xHotspot); + ok(icon_info.yHotspot == ICON_HEIGHT/2, "yHotspot is %u.\n", icon_info.yHotspot); + ok(icon_info.hbmColor != NULL, "No hbmColor!\n"); + ok(icon_info.hbmMask != NULL, "No hbmMask!\n"); + } + + /* Clean up. */ + SetLastError(0xdeadbeef); + ret = DestroyCursor(handle); + ok(ret, "DestroyCursor() failed.\n"); + error = GetLastError(); + ok(error == 0xdeadbeef, "Last error: %u\n", error); + + HeapFree(GetProcessHeap(), 0, hotspot); +} + +static HICON create_test_icon(HDC hdc, int width, int height, int bpp, + BOOL maskvalue, UINT32 *color, int colorSize) +{ + ICONINFO iconInfo; + BITMAPINFO bitmapInfo; + UINT32 *buffer = NULL; + UINT32 mask = maskvalue ? 0xFFFFFFFF : 0x00000000; + + memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = width; + bitmapInfo.bmiHeader.biHeight = height; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = bpp; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = colorSize; + + iconInfo.fIcon = TRUE; + iconInfo.xHotspot = 0; + iconInfo.yHotspot = 0; + + iconInfo.hbmMask = CreateBitmap( width, height, 1, 1, &mask ); + if(!iconInfo.hbmMask) return NULL; + + iconInfo.hbmColor = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, NULL, 0); + if(!iconInfo.hbmColor || !buffer) + { + DeleteObject(iconInfo.hbmMask); + return NULL; + } + + memcpy(buffer, color, colorSize); + + return CreateIconIndirect(&iconInfo); +} + +static BOOL color_match(COLORREF a, COLORREF b) +{ + /* 5-bit accuracy is a sufficient test. This will match, so long as + * colors are never truncated to less that 3x5-bit accuracy i.e. + * paletized. */ + return (a & 0x00F8F8F8) == (b & 0x00F8F8F8); +} + +static void check_alpha_draw(HDC hdc, BOOL drawiconex, BOOL alpha, int bpp, int line) +{ + HICON hicon; + UINT32 mask; + UINT32 color[2]; + COLORREF modern_expected, legacy_expected, result; + + mask = 0x00000000; + color[0] = 0x00A0B0C0; + color[1] = alpha ? 0xFF000000 : 0x00000000; + modern_expected = alpha ? 0x00FFFFFF : 0x00C0B0A0; + legacy_expected = 0x00C0B0A0; + + hicon = create_test_icon(hdc, 2, 1, bpp, 0, color, sizeof(color)); + if (!hicon) return; + + SetPixelV(hdc, 0, 0, 0x00FFFFFF); + + if(drawiconex) + DrawIconEx(hdc, 0, 0, hicon, 2, 1, 0, NULL, DI_NORMAL); + else + DrawIcon(hdc, 0, 0, hicon); + + result = GetPixel(hdc, 0, 0); + ok (color_match(result, modern_expected) || /* Windows 2000 and up */ + broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */ + "%s. Expected a close match to %06X (modern) or %06X (legacy) with %s. " + "Got %06X from line %d\n", + alpha ? "Alpha blending" : "Not alpha blending", modern_expected, legacy_expected, + drawiconex ? "DrawIconEx" : "DrawIcon", result, line); +} + +static void check_DrawIcon(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, COLORREF background, + COLORREF modern_expected, COLORREF legacy_expected, int line) +{ + COLORREF result; + HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color)); + if (!hicon) return; + SetPixelV(hdc, 0, 0, background); + SetPixelV(hdc, GetSystemMetrics(SM_CXICON)-1, GetSystemMetrics(SM_CYICON)-1, background); + SetPixelV(hdc, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), background); + DrawIcon(hdc, 0, 0, hicon); + result = GetPixel(hdc, 0, 0); + + ok (color_match(result, modern_expected) || /* Windows 2000 and up */ + broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */ + "Overlaying Mask %d on Color %06X with DrawIcon. " + "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n", + maskvalue, color, modern_expected, legacy_expected, result, line); + + result = GetPixel(hdc, GetSystemMetrics(SM_CXICON)-1, GetSystemMetrics(SM_CYICON)-1); + + ok (color_match(result, modern_expected) || /* Windows 2000 and up */ + broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */ + "Overlaying Mask %d on Color %06X with DrawIcon. " + "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n", + maskvalue, color, modern_expected, legacy_expected, result, line); + + result = GetPixel(hdc, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); + + ok (color_match(result, background), + "Overlaying Mask %d on Color %06X with DrawIcon. " + "Expected unchanged background color %06X. Got %06X from line %d\n", + maskvalue, color, background, result, line); +} + +static void test_DrawIcon(void) +{ + BITMAPINFO bitmapInfo; + HDC hdcDst = NULL; + HBITMAP bmpDst = NULL; + HBITMAP bmpOld = NULL; + UINT32 *bits = 0; + + hdcDst = CreateCompatibleDC(0); + ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n"); + if (!hdcDst) + return; + + if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8) + { + skip("Windows will distort DrawIcon colors at 8-bpp and less due to palletizing.\n"); + goto cleanup; + } + + memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = GetSystemMetrics(SM_CXICON)+1; + bitmapInfo.bmiHeader.biHeight = GetSystemMetrics(SM_CYICON)+1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32); + + bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n"); + if (!bmpDst || !bits) + goto cleanup; + bmpOld = SelectObject(hdcDst, bmpDst); + + /* Mask is only heeded if alpha channel is always zero */ + check_DrawIcon(hdcDst, FALSE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__); + + /* Test alpha blending */ + /* Windows 2000 and up will alpha blend, earlier Windows versions will not */ + check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__); + + check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__); + + check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__); + + /* Test detecting of alpha channel */ + /* If a single pixel's alpha channel is non-zero, the icon + will be alpha blended, otherwise it will be draw with + and + xor blts. */ + check_alpha_draw(hdcDst, FALSE, FALSE, 32, __LINE__); + check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__); + +cleanup: + if(bmpOld) + SelectObject(hdcDst, bmpOld); + if(bmpDst) + DeleteObject(bmpDst); + if(hdcDst) + DeleteDC(hdcDst); +} + +static void check_DrawIconEx(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, UINT flags, COLORREF background, + COLORREF modern_expected, COLORREF legacy_expected, int line) +{ + COLORREF result; + HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color)); + if (!hicon) return; + SetPixelV(hdc, 0, 0, background); + DrawIconEx(hdc, 0, 0, hicon, 1, 1, 0, NULL, flags); + result = GetPixel(hdc, 0, 0); + + ok (color_match(result, modern_expected) || /* Windows 2000 and up */ + broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */ + "Overlaying Mask %d on Color %06X with DrawIconEx flags %08X. " + "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n", + maskvalue, color, flags, modern_expected, legacy_expected, result, line); +} + +static void test_DrawIconEx(void) +{ + BITMAPINFO bitmapInfo; + HDC hdcDst = NULL; + HBITMAP bmpDst = NULL; + HBITMAP bmpOld = NULL; + UINT32 bits = 0; + + hdcDst = CreateCompatibleDC(0); + ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n"); + if (!hdcDst) + return; + + if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8) + { + skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n"); + goto cleanup; + } + + memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = 1; + bitmapInfo.bmiHeader.biHeight = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32); + bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n"); + if (!bmpDst || !bits) + goto cleanup; + bmpOld = SelectObject(hdcDst, bmpDst); + + /* Test null, image only, and mask only drawing */ + check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__); + + check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00000000, 0x00000000, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, __LINE__); + + todo_wine + { + check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + } + + /* Test normal drawing */ + check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + todo_wine check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__); + check_DrawIconEx(hdcDst, FALSE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + + /* Test alpha blending */ + /* Windows 2000 and up will alpha blend, earlier Windows versions will not */ + check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__); + + check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__); + check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__); + + check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__); + + /* Test detecting of alpha channel */ + /* If a single pixel's alpha channel is non-zero, the icon + will be alpha blended, otherwise it will be draw with + and + xor blts. */ + check_alpha_draw(hdcDst, TRUE, FALSE, 32, __LINE__); + check_alpha_draw(hdcDst, TRUE, TRUE, 32, __LINE__); + +cleanup: + if(bmpOld) + SelectObject(hdcDst, bmpOld); + if(bmpDst) + DeleteObject(bmpDst); + if(hdcDst) + DeleteDC(hdcDst); +} + +static void check_DrawState_Size(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, HBRUSH hbr, UINT flags, int line) +{ + COLORREF result, background; + BOOL passed[2]; + HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color)); + background = 0x00FFFFFF; + /* Set color of the 2 pixels that will be checked afterwards */ + SetPixelV(hdc, 0, 0, background); + SetPixelV(hdc, 2, 2, background); + + /* Let DrawState calculate the size of the icon (it's 1x1) */ + DrawState(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 0, 0, (DST_ICON | flags )); + + result = GetPixel(hdc, 0, 0); + passed[0] = color_match(result, background); + result = GetPixel(hdc, 2, 2); + passed[0] = passed[0] & color_match(result, background); + + /* Check if manually specifying the icon size DOESN'T work */ + + /* IMPORTANT: For Icons, DrawState wants the size of the source image, not the + * size in which it should be ultimately drawn. Therefore giving + * width/height 2x2 if the icon is only 1x1 pixels in size should + * result in drawing it with size 1x1. The size parameters must be + * ignored if a Icon has to be drawn! */ + DrawState(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 2, 2, (DST_ICON | flags )); + + result = GetPixel(hdc, 0, 0); + passed[1] = color_match(result, background); + result = GetPixel(hdc, 2, 2); + passed[1] = passed[0] & color_match(result, background); + + if(!passed[0]&&!passed[1]) + ok (passed[1], + "DrawState failed to draw a 1x1 Icon in the correct size, independent of the " + "width and height settings passed to it, for Icon with: Overlaying Mask %d on " + "Color %06X with flags %08X. Line %d\n", + maskvalue, color, (DST_ICON | flags), line); + else if(!passed[1]) + ok (passed[1], + "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height " + "parameters passed to it are bigger than the real Icon size, for Icon with: Overlaying " + "Mask %d on Color %06X with flags %08X. Line %d\n", + maskvalue, color, (DST_ICON | flags), line); + else + ok (passed[0], + "DrawState failed to draw a 1x1 Icon in the correct size, if the width and height " + "parameters passed to it are 0, for Icon with: Overlaying Mask %d on " + "Color %06X with flags %08X. Line %d\n", + maskvalue, color, (DST_ICON | flags), line); +} + +static void check_DrawState_Color(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, HBRUSH hbr, UINT flags, + COLORREF background, COLORREF modern_expected, COLORREF legacy_expected, int line) +{ + COLORREF result; + HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color)); + if (!hicon) return; + /* Set color of the pixel that will be checked afterwards */ + SetPixelV(hdc, 1, 1, background); + + DrawState(hdc, hbr, NULL, (LPARAM) hicon, 0, 1, 1, 0, 0, ( DST_ICON | flags )); + + /* Check the color of the pixel is correct */ + result = GetPixel(hdc, 1, 1); + + ok (color_match(result, modern_expected) || /* Windows 2000 and up */ + broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */ + "DrawState drawing Icon with Overlaying Mask %d on Color %06X with flags %08X. " + "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n", + maskvalue, color, (DST_ICON | flags), modern_expected, legacy_expected, result, line); +} + +static void test_DrawState(void) +{ + BITMAPINFO bitmapInfo; + HDC hdcDst = NULL; + HBITMAP bmpDst = NULL; + HBITMAP bmpOld = NULL; + UINT32 bits = 0; + + hdcDst = CreateCompatibleDC(0); + ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n"); + if (!hdcDst) + return; + + if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8) + { + skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n"); + goto cleanup; + } + + memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = 3; + bitmapInfo.bmiHeader.biHeight = 3; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32); + bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n"); + if (!bmpDst || !bits) + goto cleanup; + bmpOld = SelectObject(hdcDst, bmpDst); + + /* potential flags to test with DrawState are: */ + /* DSS_DISABLED embosses the icon */ + /* DSS_MONO draw Icon using a brush as parameter 5 */ + /* DSS_NORMAL draw Icon without any modifications */ + /* DSS_UNION draw the Icon dithered */ + + check_DrawState_Size(hdcDst, FALSE, 0x00A0B0C0, 32, 0, DSS_NORMAL, __LINE__); + check_DrawState_Color(hdcDst, FALSE, 0x00A0B0C0, 32, 0, DSS_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + +cleanup: + if(bmpOld) + SelectObject(hdcDst, bmpOld); + if(bmpDst) + DeleteObject(bmpDst); + if(hdcDst) + DeleteDC(hdcDst); +} + static void test_DestroyCursor(void) { static const BYTE bmp_bits[4096]; @@ -810,13 +1382,13 @@ static void test_DestroyCursor(void) SetLastError(0xdeadbeef); ret = DestroyCursor(cursor); - ok(!ret, "DestroyCursor on the active cursor succeeded\n"); + ok(!ret || broken(ret) /* succeeds on win9x */, "DestroyCursor on the active cursor succeeded\n"); error = GetLastError(); ok(error == 0xdeadbeef, "Last error: %u\n", error); - + if (!ret) + { cursor2 = GetCursor(); ok(cursor2 == cursor, "Active was set to %p when trying to destroy it\n", cursor2); - SetCursor(NULL); /* Trying to destroy the cursor properly fails now with @@ -827,7 +1399,9 @@ static void test_DestroyCursor(void) todo_wine { ok(!ret, "DestroyCursor succeeded.\n"); error = GetLastError(); - ok(error == ERROR_INVALID_CURSOR_HANDLE, "Last error: 0x%08x\n", error); + ok(error == ERROR_INVALID_CURSOR_HANDLE || error == 0xdeadbeef, /* vista */ + "Last error: 0x%08x\n", error); + } } DeleteObject(cursorInfo.hbmMask); @@ -838,7 +1412,7 @@ static void test_DestroyCursor(void) SetLastError(0xdeadbeef); ret = DestroyCursor(cursor); - ok(ret, "DestroyCursor on the active cursor failed.\n"); + ok(ret || broken(!ret) /* fails on win9x */, "DestroyCursor on the active cursor failed.\n"); error = GetLastError(); ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error); @@ -885,6 +1459,10 @@ START_TEST(cursoricon) test_initial_cursor(); test_CreateIcon(); test_LoadImage(); + test_CreateIconFromResource(); + test_DrawIcon(); + test_DrawIconEx(); + test_DrawState(); test_DestroyCursor(); do_parent(); test_child_process(); diff --git a/rostests/winetests/user32/dce.c b/rostests/winetests/user32/dce.c index fead3850a9c..37b95464ef0 100755 --- a/rostests/winetests/user32/dce.c +++ b/rostests/winetests/user32/dce.c @@ -402,7 +402,7 @@ START_TEST(dce) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "cache_class"; diff --git a/rostests/winetests/user32/dde.c b/rostests/winetests/user32/dde.c index eb875e3dc45..62572af58e6 100755 --- a/rostests/winetests/user32/dde.c +++ b/rostests/winetests/user32/dde.c @@ -73,6 +73,12 @@ static void create_dde_window(HWND *hwnd, LPCSTR name, WNDPROC wndproc) assert(*hwnd); } +static void destroy_dde_window(HWND *hwnd, LPCSTR name) +{ + DestroyWindow(*hwnd); + UnregisterClass(name, GetModuleHandleA(0)); +} + static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { UINT_PTR lo, hi; @@ -154,7 +160,7 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA lstrcpyA((LPSTR)data->Value, str); GlobalUnlock(hglobal); - lparam = PackDDElParam(WM_DDE_ACK, (UINT)hglobal, HIWORD(lparam)); + lparam = PackDDElParam(WM_DDE_ACK, (UINT_PTR)hglobal, HIWORD(lparam)); PostMessageA(client, WM_DDE_DATA, (WPARAM)hwnd, lparam); break; @@ -178,8 +184,10 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA ok(poke->cfFormat == CF_TEXT, "Expected CF_TEXT, got %d\n", poke->cfFormat); if (msg_index == 5) - ok(lstrcmpA((LPSTR)poke->Value, "poke data\r\n"), - "Expected 'poke data\\r\\n', got %s\n", poke->Value); + { + size = GlobalSize((HGLOBAL)lo); + ok(size == 4, "got %d\n", size); + } else ok(!lstrcmpA((LPSTR)poke->Value, "poke data\r\n"), "Expected 'poke data\\r\\n', got %s\n", poke->Value); @@ -203,7 +211,7 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA executed = TRUE; - lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, DDE_FACK, HIWORD(lparam)); + lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, DDE_FACK, lparam); PostMessageA(client, WM_DDE_ACK, (WPARAM)hwnd, lparam); break; @@ -227,20 +235,21 @@ static LRESULT WINAPI dde_server_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPA return DefWindowProcA(hwnd, msg, wparam, lparam); } -static void test_msg_server(HANDLE hproc) +static void test_msg_server(HANDLE hproc, HANDLE hthread) { MSG msg; HWND hwnd; DWORD res; create_dde_window(&hwnd, "dde_server", dde_server_wndproc); + ResumeThread( hthread ); while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0) { while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); } - DestroyWindow(hwnd); + destroy_dde_window(&hwnd, "dde_server"); GetExitCodeProcess( hproc, &res ); ok( !res, "client failed with %u error(s)\n", res ); } @@ -288,11 +297,8 @@ static void test_ddeml_client(void) DdeGetLastError(client_pid); hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); - ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret); - todo_wine - { - ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %08x\n", res); - } + ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); + ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %08x\n", res); if (hdata == NULL) ok(FALSE, "hdata is NULL\n"); else @@ -310,11 +316,9 @@ static void test_ddeml_client(void) DdeGetLastError(client_pid); hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); + ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res); todo_wine - { - ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res); ok(ret == DMLERR_MEMORY_ERROR, "Expected DMLERR_MEMORY_ERROR, got %d\n", ret); - } if (hdata == NULL) ok(FALSE, "hdata is NULL\n"); else @@ -333,10 +337,7 @@ static void test_ddeml_client(void) hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); - todo_wine - { ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res); - } if (hdata == NULL) ok(FALSE, "hdata is NULL\n"); else @@ -426,10 +427,7 @@ static void test_ddeml_client(void) ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); - todo_wine - { ok(ret == DMLERR_MEMORY_ERROR, "Expected DMLERR_MEMORY_ERROR, got %d\n", ret); - } /* XTYP_EXECUTE, no data, -1 size */ res = 0xdeadbeef; @@ -438,10 +436,7 @@ static void test_ddeml_client(void) ret = DdeGetLastError(client_pid); ok(op == NULL, "Expected NULL, got %p\n", op); ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", res); - todo_wine - { ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); - } DdeFreeStringHandle(client_pid, topic); DdeFreeDataHandle(hdata); @@ -454,10 +449,7 @@ static void test_ddeml_client(void) hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); ret = DdeGetLastError(client_pid); ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); - todo_wine - { ok(res == DDE_FNOTPROCESSED, "Expected DDE_FNOTPROCESSED, got %d\n", res); - } if (hdata == NULL) ok(FALSE, "hdata is NULL\n"); else @@ -567,7 +559,7 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ULONG_PTR dwData1, ULONG_PTR dwData2) { char str[MAX_PATH], *ptr; - HDDEDATA ret; + HDDEDATA ret = NULL; DWORD size; static int msg_index = 0; @@ -593,7 +585,7 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); ok(!strncmp(str, "TestDDEServer(", 14), "Expected TestDDEServer(, got %s\n", str); ok(str[size - 1] == ')', "Expected ')', got %c\n", str[size - 1]); - ok(size == 25, "Expected 25, got %d\n", size); + ok(size == 17 + 2*sizeof(ULONG_PTR), "Got size %d for %s\n", size, str); return (HDDEDATA)TRUE; } @@ -662,7 +654,6 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon if (msg_index == 5) { - todo_wine { ok(!lstrcmpA(str, ""), "Expected empty string, got %s\n", str); ok(size == 1, "Expected 1, got %d\n", size); @@ -698,16 +689,12 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ptr = (LPSTR)DdeAccessData(hdata, &size); ok(!lstrcmpA(ptr, "poke data\r\n"), "Expected 'poke data\\r\\n', got %s\n", ptr); - todo_wine - { - ok(size == 14, "Expected 14, got %d\n", size); - } + ok(size == 12, "Expected 12, got %d\n", size); DdeUnaccessData(hdata); size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); if (msg_index == 7) { - todo_wine { ok(!lstrcmpA(str, ""), "Expected empty string, got %s\n", str); ok(size == 1, "Expected 1, got %d\n", size); @@ -724,7 +711,7 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon case XTYP_EXECUTE: { - ok(msg_index == 9 || msg_index == 10, "Expected 9 or 10, got %d\n", msg_index); + ok(msg_index >= 9 && msg_index <= 11, "Expected 9 or 11, got %d\n", msg_index); ok(uFmt == 0, "Expected 0, got %d\n", uFmt); ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv); ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); @@ -735,6 +722,8 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); ok(size == 12, "Expected 12, got %d\n", size); + if (msg_index == 9 || msg_index == 11) + { ptr = (LPSTR)DdeAccessData(hdata, &size); if (msg_index == 9) @@ -747,17 +736,36 @@ static HDDEDATA CALLBACK server_ddeml_callback(UINT uType, UINT uFmt, HCONV hcon { ok(!lstrcmpA(ptr, "[BadCommand(Var)]"), "Expected '[BadCommand(Var)]', got %s\n", ptr); ok(size == 18, "Expected 18, got %d\n", size); - ret = (HDDEDATA)DDE_FNOTPROCESSED; + ret = DDE_FNOTPROCESSED; } DdeUnaccessData(hdata); + } + else if (msg_index == 10) + { + DWORD rsize = 0; + size = 0; + + size = DdeGetData(hdata, NULL, 0, 0); + ok(size == 17, "DdeGetData should have returned 17 not %d\n", size); + ptr = HeapAlloc(GetProcessHeap(), 0, size); + ok(ptr != NULL,"HeapAlloc should have returned ptr not NULL\n"); + rsize = DdeGetData(hdata, (LPBYTE)ptr, size, 0); + ok(rsize == size, "DdeGetData did not return %d bytes but %d\n", size, rsize); + + ok(!lstrcmpA(ptr, "[Command-2(Var)]"), "Expected '[Command-2(Var)]' got %s\n", ptr); + ok(size == 17, "Expected 17, got %d\n", size); + ret = (HDDEDATA)DDE_FACK; + + HeapFree(GetProcessHeap(), 0, ptr); + } return ret; } case XTYP_DISCONNECT: { - ok(msg_index == 11, "Expected 11, got %d\n", msg_index); + ok(msg_index == 12, "Expected 12, got %d\n", msg_index); ok(uFmt == 0, "Expected 0, got %d\n", uFmt); ok(hconv == conversation, "Expected conversation handle, got %p\n", hconv); ok(dwData1 == 0, "Expected 0, got %08lx\n", dwData1); @@ -846,8 +854,8 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, case WM_DDE_ACK: { - ok((msg_index >= 2 && msg_index <= 4) || (msg_index >= 6 && msg_index <= 10), - "Expected 2, 3, 4, 6, 7, 8, 9 or 10, got %d\n", msg_index); + ok((msg_index >= 2 && msg_index <= 4) || (msg_index >= 6 && msg_index <= 11), + "Expected 2, 3, 4, 6, 7, 8, 9, 10 or 11, got %d\n", msg_index); if (msg_index == 2) { @@ -864,7 +872,7 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, ok(!lstrcmpA(str, "TestDDETopic"), "Expected TestDDETopic, got %s\n", str); ok(size == 12, "Expected 12, got %d\n", size); } - else if (msg_index == 9 || msg_index == 10) + else if (msg_index >= 9 && msg_index <= 11) { ok(wparam == (WPARAM)server_hwnd, "Expected server hwnd, got %08lx\n", wparam); @@ -882,6 +890,10 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, { ok(ack->fAck == TRUE, "Expected TRUE, got %d\n", ack->fAck); ok(!lstrcmpA(ptr, "[Command(Var)]"), "Expected '[Command(Var)]', got %s\n", ptr); + } else if (msg_index == 10) + { + ok(ack->fAck == TRUE, "Expected TRUE, got %d\n", ack->fAck); + ok(!lstrcmpA(ptr, "[Command-2(Var)]"), "Expected '[Command-2(Var)]', got %s\n", ptr); } else { @@ -974,13 +986,13 @@ static LRESULT WINAPI dde_msg_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, return DefWindowProcA(hwnd, msg, wparam, lparam); } -static HGLOBAL create_poke() +static HGLOBAL create_poke(void) { HGLOBAL hglobal; DDEPOKE *poke; DWORD size; - size = sizeof(DDEPOKE) + lstrlenA("poke data\r\n") + 1; + size = FIELD_OFFSET(DDEPOKE, Value[sizeof("poke data\r\n")]); hglobal = GlobalAlloc(GMEM_DDESHARE, size); ok(hglobal != 0, "Expected non-NULL hglobal\n"); @@ -1010,7 +1022,7 @@ static HGLOBAL create_execute(LPCSTR command) return hglobal; } -static void test_msg_client() +static void test_msg_client(void) { HGLOBAL hglobal; LPARAM lparam; @@ -1065,9 +1077,14 @@ static void test_msg_client() /* WM_DDE_POKE, no ddepoke */ lparam = PackDDElParam(WM_DDE_POKE, 0, item); + /* win9x returns 0 here and crashes in PostMessageA */ + if (lparam) { PostMessageA(server_hwnd, WM_DDE_POKE, (WPARAM)client_hwnd, lparam); - flush_events(); + } + else + win_skip("no lparam for WM_DDE_POKE\n"); + /* WM_DDE_POKE, no item */ lparam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)hglobal, 0); @@ -1114,6 +1131,15 @@ static void test_msg_client() flush_events(); + GlobalFree(execute_hglobal); + execute_hglobal = create_execute("[Command-2(Var)]"); + + /* WM_DDE_EXECUTE, all params correct */ + lparam = PackDDElParam(WM_DDE_EXECUTE, 0, (UINT_PTR)execute_hglobal); + PostMessageA(server_hwnd, WM_DDE_EXECUTE, (WPARAM)client_hwnd, lparam); + + flush_events(); + GlobalFree(execute_hglobal); execute_hglobal = create_execute("[BadCommand(Var)]"); @@ -1123,7 +1149,7 @@ static void test_msg_client() flush_events(); - DestroyWindow(client_hwnd); + destroy_dde_window(&client_hwnd, "dde_client"); } static LRESULT WINAPI hook_dde_client_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -1162,7 +1188,7 @@ static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LP ok(!IsWindowUnicode((HWND)wparam), "client should be an ANSI window\n"); old_dde_client_wndproc = (WNDPROC)SetWindowLongPtrA((HWND)wparam, GWLP_WNDPROC, (ULONG_PTR)hook_dde_client_wndproc); trace("server: sending WM_DDE_ACK to %p\n", (HWND)wparam); - SendMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, MAKELPARAM(aService, 0)); + SendMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, PackDDElParam(WM_DDE_ACK, aService, 0)); } else GlobalDeleteAtom(aService); @@ -1186,7 +1212,6 @@ static LRESULT WINAPI dde_server_wndprocW(HWND hwnd, UINT msg, WPARAM wparam, LP ack.fBusy = 0; cmd = GlobalLock((HGLOBAL)hi); - if (!cmd || (lstrcmpA(cmd, exec_cmdA) && lstrcmpW((LPCWSTR)cmd, exec_cmdW))) { trace("ignoring unknown WM_DDE_EXECUTE command\n"); @@ -1319,7 +1344,7 @@ static void test_dde_aw_transaction(void) dde_inst = 0; ret = DdeInitializeA(&dde_inst, client_dde_callback, APPCMD_CLIENTONLY, 0); - ok(ret == DMLERR_NO_ERROR, "DdeInitializeW failed with error %04x (%x)\n", + ok(ret == DMLERR_NO_ERROR, "DdeInitializeA failed with error %04x (%x)\n", ret, DdeGetLastError(dde_inst)); hsz_server = DdeCreateStringHandleW(dde_inst, TEST_DDE_SERVICE, CP_WINUNICODE); @@ -1388,6 +1413,53 @@ todo_wine { DestroyWindow(hwnd_server); } +static void test_initialisation(void) +{ + UINT ret; + DWORD res; + HDDEDATA hdata; + HSZ server, topic, item; + DWORD client_pid; + HCONV conversation; + + /* Initialise without a valid server window. */ + client_pid = 0; + ret = DdeInitializeA(&client_pid, client_ddeml_callback, APPCMD_CLIENTONLY, 0); + ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", ret); + + + server = DdeCreateStringHandleA(client_pid, "TestDDEService", CP_WINANSI); + topic = DdeCreateStringHandleA(client_pid, "TestDDETopic", CP_WINANSI); + + DdeGetLastError(client_pid); + + /* There is no server window so no conversation can be extracted */ + conversation = DdeConnect(client_pid, server, topic, NULL); + ok(conversation == NULL, "Expected NULL conversation, %p\n", conversation); + ret = DdeGetLastError(client_pid); + ok(ret == DMLERR_NO_CONV_ESTABLISHED, "Expected DMLERR_NO_CONV_ESTABLISHED, got %d\n", ret); + + DdeFreeStringHandle(client_pid, server); + + item = DdeCreateStringHandleA(client_pid, "request", CP_WINANSI); + + /* There is no converstation so an invalild parameter results */ + res = 0xdeadbeef; + DdeGetLastError(client_pid); + hdata = DdeClientTransaction(NULL, 0, conversation, item, CF_TEXT, XTYP_REQUEST, default_timeout, &res); + ret = DdeGetLastError(client_pid); +todo_wine + ok(ret == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", ret); + ok(res == 0xdeadbeef, "Expected 0xdeadbeef, got %08x\n", res); + + DdeFreeStringHandle(client_pid, server); + ret = DdeDisconnect(conversation); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + + ret = DdeUninitialize(client_pid); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); +} + static void test_DdeCreateStringHandleW(DWORD dde_inst, int codepage) { static const WCHAR dde_string[] = {'D','D','E',' ','S','t','r','i','n','g',0}; @@ -1472,41 +1544,69 @@ static void test_DdeCreateStringHandleW(DWORD dde_inst, int codepage) static void test_DdeCreateDataHandle(void) { HDDEDATA hdata; - DWORD dde_inst; + DWORD dde_inst, dde_inst2; DWORD size; UINT res, err; BOOL ret; HSZ item; LPBYTE ptr; + WCHAR item_str[] = {'i','t','e','m',0}; dde_inst = 0; + dde_inst2 = 0; res = DdeInitializeA(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0); ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res); + res = DdeInitializeA(&dde_inst2, client_ddeml_callback, APPCMD_CLIENTONLY, 0); + ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res); + + /* 0 instance id + * This block tests an invalid instance Id. The correct behaviour is that if the instance Id + * is invalid then the lastError of all instances is set to the error. There are two instances + * created, lastError is cleared, an error is generated and then both instances are checked to + * ensure that they both have the same error set + */ + item = DdeCreateStringHandleA(0, "item", CP_WINANSI); + ok(item == NULL, "Expected NULL hsz got %p\n", item); + err = DdeGetLastError(dde_inst); + ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err); + err = DdeGetLastError(dde_inst2); + ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err); + item = DdeCreateStringHandleW(0, item_str, CP_WINUNICODE); + ok(item == NULL, "Expected NULL hsz got %p\n", item); + err = DdeGetLastError(dde_inst); + ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err); + err = DdeGetLastError(dde_inst2); + ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err); + item = DdeCreateStringHandleA(dde_inst, "item", CP_WINANSI); ok(item != NULL, "Expected non-NULL hsz\n"); + item = DdeCreateStringHandleA(dde_inst2, "item", CP_WINANSI); + ok(item != NULL, "Expected non-NULL hsz\n"); - /* invalid instance id */ - DdeGetLastError(dde_inst); + if (0) { + /* do not test with an invalid instance id: that crashes on win9x */ hdata = DdeCreateDataHandle(0xdeadbeef, (LPBYTE)"data", MAX_PATH, 0, item, CF_TEXT, 0); - err = DdeGetLastError(dde_inst); - todo_wine - { - ok(hdata == NULL, "Expected NULL, got %p\n", hdata); - ok(err == DMLERR_INVALIDPARAMETER, - "Expected DMLERR_INVALIDPARAMETER, got %d\n", err); } - /* 0 instance id */ + /* 0 instance id + * This block tests an invalid instance Id. The correct behaviour is that if the instance Id + * is invalid then the lastError of all instances is set to the error. There are two instances + * created, lastError is cleared, an error is generated and then both instances are checked to + * ensure that they both have the same error set + */ DdeGetLastError(dde_inst); + DdeGetLastError(dde_inst2); hdata = DdeCreateDataHandle(0, (LPBYTE)"data", MAX_PATH, 0, item, CF_TEXT, 0); err = DdeGetLastError(dde_inst); - todo_wine - { ok(hdata == NULL, "Expected NULL, got %p\n", hdata); - ok(err == DMLERR_INVALIDPARAMETER, - "Expected DMLERR_INVALIDPARAMETER, got %d\n", err); - } + ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err); + err = DdeGetLastError(dde_inst2); + ok(err == DMLERR_INVALIDPARAMETER, "Expected DMLERR_INVALIDPARAMETER, got %d\n", err); + + ret = DdeUninitialize(dde_inst2); + ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res); + /* NULL pSrc */ DdeGetLastError(dde_inst); @@ -1515,12 +1615,6 @@ static void test_DdeCreateDataHandle(void) ok(hdata != NULL, "Expected non-NULL hdata\n"); ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err); - ptr = GlobalLock(hdata); - todo_wine - { - ok(ptr == NULL, "Expected NULL, got %p\n", ptr); - } - ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(size == 260, "Expected 260, got %d\n", size); @@ -1538,12 +1632,6 @@ static void test_DdeCreateDataHandle(void) ok(hdata != NULL, "Expected non-NULL hdata\n"); ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err); - ptr = GlobalLock(hdata); - todo_wine - { - ok(ptr == NULL, "Expected NULL, got %p\n", ptr); - } - ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(size == 0, "Expected 0, got %d\n", size); @@ -1561,12 +1649,6 @@ static void test_DdeCreateDataHandle(void) ok(hdata != NULL, "Expected non-NULL hdata\n"); ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err); - ptr = GlobalLock(hdata); - todo_wine - { - ok(ptr == NULL, "Expected NULL, got %p\n", ptr); - } - ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(size == 262, "Expected 262, got %d\n", size); @@ -1588,12 +1670,6 @@ static void test_DdeCreateDataHandle(void) ok(hdata != NULL, "Expected non-NULL hdata\n"); ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err); - ptr = GlobalLock(hdata); - todo_wine - { - ok(ptr == NULL, "Expected NULL, got %p\n", ptr); - } - ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr); @@ -1612,12 +1688,6 @@ static void test_DdeCreateDataHandle(void) ok(hdata != NULL, "Expected non-NULL hdata\n"); ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err); - ptr = GlobalLock(hdata); - todo_wine - { - ok(ptr == NULL, "Expected NULL, got %p\n", ptr); - } - ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr); @@ -1636,12 +1706,6 @@ static void test_DdeCreateDataHandle(void) ok(hdata != NULL, "Expected non-NULL hdata\n"); ok(err == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", err); - ptr = GlobalLock(hdata); - todo_wine - { - ok(ptr == NULL, "Expected NULL, got %p\n", ptr); - } - ptr = DdeAccessData(hdata, &size); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(!lstrcmpA((LPSTR)ptr, "data"), "Expected data, got %s\n", ptr); @@ -1666,7 +1730,7 @@ static void test_DdeCreateStringHandle(void) ret = DdeInitializeW(&dde_inst, client_ddeml_callback, APPCMD_CLIENTONLY, 0); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("Skipping the DDE test on a Win9x platform\n"); + win_skip("DdeInitializeW is unimplemented\n"); return; } @@ -1690,7 +1754,7 @@ static void test_FreeDDElParam(void) HGLOBAL val, hglobal; BOOL ret; - ret = FreeDDElParam(WM_DDE_INITIATE, (LPARAM)NULL); + ret = FreeDDElParam(WM_DDE_INITIATE, 0); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); hglobal = GlobalAlloc(GMEM_DDESHARE, 100); @@ -1702,10 +1766,6 @@ static void test_FreeDDElParam(void) hglobal = GlobalAlloc(GMEM_DDESHARE, 100); ret = FreeDDElParam(WM_DDE_ADVISE, (LPARAM)hglobal); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - val = GlobalFree(hglobal); - ok(val == hglobal, "Expected hglobal, got %p\n", val); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); hglobal = GlobalAlloc(GMEM_DDESHARE, 100); ret = FreeDDElParam(WM_DDE_UNADVISE, (LPARAM)hglobal); @@ -1716,18 +1776,10 @@ static void test_FreeDDElParam(void) hglobal = GlobalAlloc(GMEM_DDESHARE, 100); ret = FreeDDElParam(WM_DDE_ACK, (LPARAM)hglobal); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - val = GlobalFree(hglobal); - ok(val == hglobal, "Expected hglobal, got %p\n", val); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); hglobal = GlobalAlloc(GMEM_DDESHARE, 100); ret = FreeDDElParam(WM_DDE_DATA, (LPARAM)hglobal); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - val = GlobalFree(hglobal); - ok(val == hglobal, "Expected hglobal, got %p\n", val); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); hglobal = GlobalAlloc(GMEM_DDESHARE, 100); ret = FreeDDElParam(WM_DDE_REQUEST, (LPARAM)hglobal); @@ -1738,10 +1790,6 @@ static void test_FreeDDElParam(void) hglobal = GlobalAlloc(GMEM_DDESHARE, 100); ret = FreeDDElParam(WM_DDE_POKE, (LPARAM)hglobal); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - val = GlobalFree(hglobal); - ok(val == hglobal, "Expected hglobal, got %p\n", val); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); hglobal = GlobalAlloc(GMEM_DDESHARE, 100); ret = FreeDDElParam(WM_DDE_EXECUTE, (LPARAM)hglobal); @@ -1753,16 +1801,12 @@ static void test_FreeDDElParam(void) static void test_PackDDElParam(void) { UINT_PTR lo, hi, *ptr; - HGLOBAL hglobal; LPARAM lparam; BOOL ret; lparam = PackDDElParam(WM_DDE_INITIATE, 0xcafe, 0xbeef); - ok(lparam == 0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); - ok(GlobalLock((HGLOBAL)lparam) == NULL, - "Expected NULL, got %p\n", GlobalLock((HGLOBAL)lparam)); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + /* value gets sign-extended despite being an LPARAM */ + ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_INITIATE, lparam, &lo, &hi); @@ -1774,11 +1818,7 @@ static void test_PackDDElParam(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_TERMINATE, 0xcafe, 0xbeef); - ok(lparam == 0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); - ok(GlobalLock((HGLOBAL)lparam) == NULL, - "Expected NULL, got %p\n", GlobalLock((HGLOBAL)lparam)); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_TERMINATE, lparam, &lo, &hi); @@ -1790,6 +1830,8 @@ static void test_PackDDElParam(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_ADVISE, 0xcafe, 0xbeef); + /* win9x returns 0 here */ + if (lparam) { ptr = GlobalLock((HGLOBAL)lparam); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]); @@ -1803,21 +1845,15 @@ static void test_PackDDElParam(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + } + else + win_skip("no lparam for WM_DDE_ADVISE\n"); ret = FreeDDElParam(WM_DDE_ADVISE, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - hglobal = GlobalFree((HGLOBAL)lparam); - ok(hglobal == (HGLOBAL)lparam, "Expected lparam, got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); - lparam = PackDDElParam(WM_DDE_UNADVISE, 0xcafe, 0xbeef); - ok(lparam == 0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); - ok(GlobalLock((HGLOBAL)lparam) == NULL, - "Expected NULL, got %p\n", GlobalLock((HGLOBAL)lparam)); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_UNADVISE, lparam, &lo, &hi); @@ -1829,6 +1865,8 @@ static void test_PackDDElParam(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_ACK, 0xcafe, 0xbeef); + /* win9x returns the input (0xbeef<<16 | 0xcafe) here */ + if (lparam != (int)0xbeefcafe) { ptr = GlobalLock((HGLOBAL)lparam); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]); @@ -1845,13 +1883,13 @@ static void test_PackDDElParam(void) ret = FreeDDElParam(WM_DDE_ACK, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - - hglobal = GlobalFree((HGLOBAL)lparam); - ok(hglobal == (HGLOBAL)lparam, "Expected lparam, got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + } + else + win_skip("got lparam 0x%lx for WM_DDE_ACK\n", lparam); lparam = PackDDElParam(WM_DDE_DATA, 0xcafe, 0xbeef); + /* win9x returns 0 here */ + if (lparam) { ptr = GlobalLock((HGLOBAL)lparam); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]); @@ -1865,21 +1903,15 @@ static void test_PackDDElParam(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + } + else + win_skip("no lparam for WM_DDE_DATA\n"); ret = FreeDDElParam(WM_DDE_DATA, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - hglobal = GlobalFree((HGLOBAL)lparam); - ok(hglobal == (HGLOBAL)lparam, "Expected lparam, got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); - lparam = PackDDElParam(WM_DDE_REQUEST, 0xcafe, 0xbeef); - ok(lparam == 0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); - ok(GlobalLock((HGLOBAL)lparam) == NULL, - "Expected NULL, got %p\n", GlobalLock((HGLOBAL)lparam)); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(lparam == (int)0xbeefcafe, "Expected 0xbeefcafe, got %08lx\n", lparam); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_REQUEST, lparam, &lo, &hi); @@ -1891,6 +1923,8 @@ static void test_PackDDElParam(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); lparam = PackDDElParam(WM_DDE_POKE, 0xcafe, 0xbeef); + /* win9x returns 0 here */ + if (lparam) { ptr = GlobalLock((HGLOBAL)lparam); ok(ptr != NULL, "Expected non-NULL ptr\n"); ok(ptr[0] == 0xcafe, "Expected 0xcafe, got %08lx\n", ptr[0]); @@ -1904,21 +1938,15 @@ static void test_PackDDElParam(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); ok(lo == 0xcafe, "Expected 0xcafe, got %08lx\n", lo); ok(hi == 0xbeef, "Expected 0xbeef, got %08lx\n", hi); + } + else + win_skip("no lparam for WM_DDE_POKE\n"); ret = FreeDDElParam(WM_DDE_POKE, lparam); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); - hglobal = GlobalFree((HGLOBAL)lparam); - ok(hglobal == (HGLOBAL)lparam, "Expected lparam, got %d\n", ret); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); - lparam = PackDDElParam(WM_DDE_EXECUTE, 0xcafe, 0xbeef); ok(lparam == 0xbeef, "Expected 0xbeef, got %08lx\n", lparam); - ok(GlobalLock((HGLOBAL)lparam) == NULL, - "Expected NULL, got %p\n", GlobalLock((HGLOBAL)lparam)); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); lo = hi = 0; ret = UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi); @@ -1939,7 +1967,7 @@ static void test_UnpackDDElParam(void) /* NULL lParam */ lo = 0xdead; hi = 0xbeef; - ret = UnpackDDElParam(WM_DDE_INITIATE, (LPARAM)NULL, &lo, &hi); + ret = UnpackDDElParam(WM_DDE_INITIATE, 0, &lo, &hi); ok(ret == TRUE, "Expected TRUE, got %d\n", ret); ok(lo == 0, "Expected 0, got %08lx\n", lo); ok(hi == 0, "Expected 0, got %08lx\n", hi); @@ -1976,19 +2004,16 @@ static void test_UnpackDDElParam(void) lo = 0xdead; hi = 0xbeef; - ret = UnpackDDElParam(WM_DDE_ADVISE, (LPARAM)NULL, &lo, &hi); + ret = UnpackDDElParam(WM_DDE_ADVISE, 0, &lo, &hi); ok(ret == FALSE, "Expected FALSE, got %d\n", ret); - ok(lo == 0, "Expected 0, got %08lx\n", lo); - ok(hi == 0, "Expected 0, got %08lx\n", hi); + ok(lo == 0 || + broken(lo == 0xdead), /* win2k */ + "Expected 0, got %08lx\n", lo); + ok(hi == 0 || + broken(hi == 0xbeef), /* win2k */ + "Expected 0, got %08lx\n", hi); - lo = 0xdead; - hi = 0xbeef; - ret = UnpackDDElParam(WM_DDE_ADVISE, 0xcafebabe, &lo, &hi); - ok(ret == FALSE, "Expected FALSE, got %d\n", ret); - ok(lo == 0, "Expected 0, got %08lx\n", lo); - ok(hi == 0, "Expected 0, got %08lx\n", hi); - - hglobal = GlobalAlloc(GMEM_DDESHARE, 2); + hglobal = GlobalAlloc(GMEM_DDESHARE, 2 * sizeof(*ptr)); ptr = GlobalLock(hglobal); ptr[0] = 0xcafebabe; ptr[1] = 0xdeadbeef; @@ -2008,13 +2033,6 @@ static void test_UnpackDDElParam(void) ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo); ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi); - lo = 0xdead; - hi = 0xbeef; - ret = UnpackDDElParam(WM_DDE_ACK, 0xcafebabe, &lo, &hi); - ok(ret == FALSE, "Expected FALSE, got %d\n", ret); - ok(lo == 0, "Expected 0, got %08lx\n", lo); - ok(hi == 0, "Expected 0, got %08lx\n", hi); - lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_ACK, (LPARAM)hglobal, &lo, &hi); @@ -2022,13 +2040,6 @@ static void test_UnpackDDElParam(void) ok(lo == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", lo); ok(hi == 0xdeadbeef, "Expected 0xdeadbeef, got %08lx\n", hi); - lo = 0xdead; - hi = 0xbeef; - ret = UnpackDDElParam(WM_DDE_DATA, 0xcafebabe, &lo, &hi); - ok(ret == FALSE, "Expected FALSE, got %d\n", ret); - ok(lo == 0, "Expected 0, got %08lx\n", lo); - ok(hi == 0, "Expected 0, got %08lx\n", hi); - lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_DATA, (LPARAM)hglobal, &lo, &hi); @@ -2043,13 +2054,6 @@ static void test_UnpackDDElParam(void) ok(lo == 0xbabe, "Expected 0xbabe, got %08lx\n", lo); ok(hi == 0xcafe, "Expected 0xcafe, got %08lx\n", hi); - lo = 0xdead; - hi = 0xbeef; - ret = UnpackDDElParam(WM_DDE_POKE, 0xcafebabe, &lo, &hi); - ok(ret == FALSE, "Expected FALSE, got %d\n", ret); - ok(lo == 0, "Expected 0, got %08lx\n", lo); - ok(hi == 0, "Expected 0, got %08lx\n", hi); - lo = 0xdead; hi = 0xbeef; ret = UnpackDDElParam(WM_DDE_POKE, (LPARAM)hglobal, &lo, &hi); @@ -2063,6 +2067,279 @@ static void test_UnpackDDElParam(void) ok(ret == TRUE, "Expected TRUE, got %d\n", ret); ok(lo == 0, "Expected 0, got %08lx\n", lo); ok(hi == 0xcafebabe, "Expected 0xcafebabe, got %08lx\n", hi); + + GlobalFree(hglobal); +} + +static HDDEDATA CALLBACK server_end_to_end_callback(UINT uType, UINT uFmt, HCONV hconv, + HSZ hsz1, HSZ hsz2, HDDEDATA hdata, + ULONG_PTR dwData1, ULONG_PTR dwData2) +{ + DWORD size, rsize; + char str[MAX_PATH]; + static int msg_index = 0; + static HCONV conversation = 0; + static char test_cmd_w_to_a[] = "test dde command"; + static char test_cmd_a_to_a[] = "Test dde command"; + static WCHAR test_cmd_w_to_w[] = {'t','e','s','t',' ','d','d','e',' ','c','o','m','m','a','n','d',0}; + static WCHAR test_cmd_a_to_w[] = {'T','e','s','t',' ','d','d','e',' ','c','o','m','m','a','n','d',0}; + static char test_service [] = "TestDDEService"; + static char test_topic [] = "TestDDETopic"; + + msg_index++; + + switch (uType) + { + case XTYP_REGISTER: + { + ok(msg_index == 1 || msg_index == 7 || msg_index == 13 || msg_index == 19, + "Expected 1, 7, 13 or 19, got %d\n", msg_index); + return (HDDEDATA)TRUE; + } + + case XTYP_CONNECT: + { + ok(msg_index == 2 || msg_index == 8 || msg_index == 14 || msg_index == 20, + "Expected 2, 8, 14 or 20, got %d\n", msg_index); + ok(uFmt == 0, "Expected 0, got %d, msg_index=%d\n", uFmt, msg_index); + ok(hconv == 0, "Expected 0, got %p, msg_index=%d\n", hconv, msg_index); + ok(hdata == 0, "Expected 0, got %p, msg_index=%d\n", hdata, msg_index); + ok(dwData1 != 0, "Expected not 0, got %08lx, msg_index=%d\n", dwData1, msg_index); + ok(dwData2 == FALSE, "Expected FALSE, got %08lx, msg_index=%d\n", dwData2, msg_index); + + size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); + ok(!lstrcmpA(str, test_topic), "Expected %s, got %s, msg_index=%d\n", + test_topic, str, msg_index); + ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index); + + size = DdeQueryStringA(server_pid, hsz2, str, MAX_PATH, CP_WINANSI); + ok(!lstrcmpA(str, test_service), "Expected %s, got %s, msg_index=%d\n", + test_service, str, msg_index); + ok(size == 14, "Expected 14, got %d, msg_index=%d\n", size, msg_index); + + return (HDDEDATA) TRUE; + } + case XTYP_CONNECT_CONFIRM: + { + ok(msg_index == 3 || msg_index == 9 || msg_index == 15 || msg_index == 21, + "Expected 3, 9, 15 or 21 got %d\n", msg_index); + conversation = hconv; + return (HDDEDATA) TRUE; + } + case XTYP_EXECUTE: + { + BYTE *buffer = NULL; + + ok(msg_index == 4 || msg_index == 5 || msg_index == 10 || msg_index == 11 || + msg_index == 16 || msg_index == 17 || msg_index == 22 || msg_index == 23, + "Expected 4, 5, 10, 11, 16, 17, 22 or 23, got %d\n", msg_index); + ok(uFmt == 0, "Expected 0, got %d\n", uFmt); + ok(hconv == conversation, "Expected conversation handle, got %p, msg_index=%d\n", + hconv, msg_index); + ok(dwData1 == 0, "Expected 0, got %08lx, msg_index=%d\n", dwData1, msg_index); + ok(dwData2 == 0, "Expected 0, got %08lx, msg_index=%d\n", dwData2, msg_index); + ok(hsz2 == 0, "Expected 0, got %p, msg_index=%d\n", hsz2, msg_index); + size = DdeQueryStringA(server_pid, hsz1, str, MAX_PATH, CP_WINANSI); + ok(!lstrcmpA(str, test_topic), "Expected %s, got %s, msg_index=%d\n", + test_topic, str, msg_index); + ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index); + ok(size == 12, "Expected 12, got %d, msg_index=%d\n", size, msg_index); + + size = DdeGetData(hdata, NULL, 0, 0); + if (msg_index == 10 || msg_index ==11 || msg_index == 16 || msg_index ==17) + if (msg_index == 10 || msg_index == 16) + todo_wine + ok(size == 34, "Expected that size should be 34 not %d, msg_index=%d\n", + size, msg_index); + else + ok(size == 34, "Expected that size should be 34 not %d, msg_index=%d\n", + size, msg_index); + else + if (msg_index ==22) + ok(size == 8 || size == 9, "Expected that size should be 8 or 9 not %d, msg_index=%d\n", + size, msg_index); + else + if (msg_index == 5) + todo_wine + ok(size == 17, "Expected that size should be 17 not %d, msg_index=%d\n", + size, msg_index); + else + ok(size == 17, "Expected that size should be 17 not %d, msg_index=%d\n", + size, msg_index); + ok((buffer = HeapAlloc(GetProcessHeap(), 0, size)) != NULL, "should not be null\n"); + rsize = DdeGetData(hdata, buffer, size, 0); + if (msg_index == 10 || msg_index == 11 || msg_index == 16 || msg_index ==17) + { + ok(rsize == size, "Incorrect size returned, expected %d got %d, msg_index=%d\n", + size, rsize, msg_index); + if (msg_index == 10 || msg_index == 16) + todo_wine { + ok(!lstrcmpW((WCHAR*)buffer, test_cmd_a_to_w), + "Expected \"Test dde command\", msg_index=%d\n", + msg_index); + ok(size == 34, "Expected 34, got %d, msg_index=%d\n", size, msg_index); + } else + { + ok(!lstrcmpW((WCHAR*)buffer, test_cmd_w_to_w), + "Expected \"test dde command\", msg_index=%d\n", + msg_index); + ok(size == 34, "Expected 34, got %d, msg_index=%d\n", size, msg_index); + } + }else if (msg_index == 22) + { + ok(rsize == size, "Incorrect size returned, expected %d got %d, msg_index=%d\n", + size, rsize, msg_index); + } else + { + ok(rsize == size, "Incorrect size returned, expected %d got %d, msg_index=%d\n", + size, rsize, msg_index); + if (msg_index == 5) + todo_wine { + ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n", + test_cmd_w_to_a, buffer, msg_index); + ok(size == 17, "Expected size should be 17, got %d, msg_index=%d\n", size, msg_index); + } + else if (msg_index == 23) + { + ok(!lstrcmpA((CHAR*)buffer, test_cmd_w_to_a), "Expected %s, got %s, msg_index=%d\n", + test_cmd_w_to_a, buffer, msg_index); + ok(size == 17, "Expected size should be 17, got %d, msg_index=%d\n", size, msg_index); + } + else + { + ok(!lstrcmpA((CHAR*)buffer, test_cmd_a_to_a), "Expected %s, got %s, msg_index=%d\n", + test_cmd_a_to_a, buffer, msg_index); + ok(size == 17, "Expected size should be 17, got %d, msg_index=%d\n", size, msg_index); + } + + } + + return (HDDEDATA) DDE_FACK; + } + case XTYP_DISCONNECT: + return (HDDEDATA) TRUE; + + default: + ok(FALSE, "Unhandled msg: %08x, msg_index=%d\n", uType, msg_index); + } + + return NULL; +} + +static HDDEDATA CALLBACK client_end_to_end_callback(UINT uType, UINT uFmt, HCONV hconv, + HSZ hsz1, HSZ hsz2, HDDEDATA hdata, + ULONG_PTR dwData1, ULONG_PTR dwData2) +{ + switch (uType) + { + case XTYP_DISCONNECT: + return (HDDEDATA) TRUE; + + default: + ok(FALSE, "Unhandled msg: %08x\n", uType); + } + + return NULL; +} + +static void test_end_to_end_client(BOOL type_a) +{ + DWORD ret, err; + DWORD client_pid = 0; + HSZ server, topic; + HCONV hconv; + HDDEDATA hdata; + static char test_cmd[] = "Test dde command"; + static WCHAR test_cmd_w[] = {'t','e','s','t',' ','d','d','e',' ','c','o','m','m','a','n','d',0}; + static char test_service[] = "TestDDEService"; + static WCHAR test_service_w[] = {'T','e','s','t','D','D','E','S','e','r','v','i','c','e',0}; + static char test_topic[] = "TestDDETopic"; + static WCHAR test_topic_w[] = {'T','e','s','t','D','D','E','T','o','p','i','c',0}; + + trace("Start end to end client %s\n", type_a ? "ASCII" : "UNICODE"); + + if (type_a) + ret = DdeInitializeA(&client_pid, client_end_to_end_callback, APPCMD_CLIENTONLY, 0); + else + ret = DdeInitializeW(&client_pid, client_end_to_end_callback, APPCMD_CLIENTONLY, 0); + ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %x\n", ret); + + if (type_a) + { + server = DdeCreateStringHandleA(client_pid, test_service, CP_WINANSI); + topic = DdeCreateStringHandleA(client_pid, test_topic, CP_WINANSI); + } + else { + server = DdeCreateStringHandleW(client_pid, test_service_w, CP_WINUNICODE); + topic = DdeCreateStringHandleW(client_pid, test_topic_w, CP_WINUNICODE); + } + + DdeGetLastError(client_pid); + hconv = DdeConnect(client_pid, server, topic, NULL); + ok(hconv != NULL, "Expected non-NULL conversation\n"); + ret = DdeGetLastError(client_pid); + ok(ret == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %x\n", ret); + DdeFreeStringHandle(client_pid, server); + + /* Test both A and W data being passed to DdeClientTransaction */ + hdata = DdeClientTransaction((LPBYTE)test_cmd, strlen(test_cmd) + 1, + hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret); + ok(hdata != NULL, "DdeClientTransaction failed\n"); + ok(ret == DDE_FACK, "wrong status code %x\n", ret); + err = DdeGetLastError(client_pid); + ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); + + hdata = DdeClientTransaction((LPBYTE)test_cmd_w, lstrlenW(test_cmd_w) * sizeof(WCHAR) + 2, + hconv, (HSZ)0xdead, 0xbeef, XTYP_EXECUTE, 1000, &ret); + ok(hdata != NULL, "DdeClientTransaction failed\n"); + ok(ret == DDE_FACK, "wrong status code %x\n", ret); + err = DdeGetLastError(client_pid); + ok(err == DMLERR_NO_ERROR, "wrong dde error %x\n", err); + + DdeFreeStringHandle(client_pid, topic); + ret = DdeDisconnect(hconv); + ok(ret == TRUE, "Expected TRUE, got %x\n", ret); + + ret = DdeUninitialize(client_pid); + ok(ret == TRUE, "Expected TRUE, got %x\n", ret); + +} + +static void test_end_to_end_server(HANDLE hproc, HANDLE hthread, BOOL type_a) +{ + MSG msg; + HSZ server; + BOOL ret; + DWORD res; + HDDEDATA hdata; + static CHAR test_service[] = "TestDDEService"; + + trace("start end to end server %s\n", type_a ? "ASCII" : "UNICODE"); + server_pid = 0; + + if (type_a) + res = DdeInitializeA(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0); + else + res = DdeInitializeW(&server_pid, server_end_to_end_callback, APPCLASS_STANDARD, 0); + ok(res == DMLERR_NO_ERROR, "Expected DMLERR_NO_ERROR, got %d\n", res); + + server = DdeCreateStringHandleA(server_pid, test_service, CP_WINANSI); + ok(server != NULL, "Expected non-NULL string handle\n"); + + hdata = DdeNameService(server_pid, server, 0, DNS_REGISTER); + ok(hdata == (HDDEDATA)TRUE, "Expected TRUE, got %p\n", hdata); + ResumeThread( hthread ); + + + while (MsgWaitForMultipleObjects( 1, &hproc, FALSE, INFINITE, QS_ALLINPUT ) != 0) + { + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + } + + ret = DdeUninitialize(server_pid); + ok(ret == TRUE, "Expected TRUE, got %d\n", ret); + GetExitCodeProcess( hproc, &res ); + ok( !res, "client failed with %u error(s)\n", res ); } START_TEST(dde) @@ -2080,10 +2357,16 @@ START_TEST(dde) test_ddeml_client(); else if (!lstrcmpA(argv[2], "msg")) test_msg_client(); + else if (!lstrcmpA(argv[2], "enda")) + test_end_to_end_client(TRUE); + else if (!lstrcmpA(argv[2], "endw")) + test_end_to_end_client(FALSE); return; } + test_initialisation(); + ZeroMemory(&startup, sizeof(STARTUPINFO)); sprintf(buffer, "%s dde ddeml", argv[0]); startup.cb = sizeof(startup); @@ -2091,9 +2374,9 @@ START_TEST(dde) startup.wShowWindow = SW_SHOWNORMAL; CreateProcessA(NULL, buffer, NULL, NULL, FALSE, - 0, NULL, NULL, &startup, &proc); + CREATE_SUSPENDED, NULL, NULL, &startup, &proc); - test_msg_server(proc.hProcess); + test_msg_server(proc.hProcess, proc.hThread); sprintf(buffer, "%s dde msg", argv[0]); CreateProcessA(NULL, buffer, NULL, NULL, FALSE, @@ -2101,6 +2384,42 @@ START_TEST(dde) test_ddeml_server(proc.hProcess); + /* Test the combinations of A and W interfaces with A and W data + end to end to ensure that data conversions are accurate */ + sprintf(buffer, "%s dde enda", argv[0]); + CreateProcessA(NULL, buffer, NULL, NULL, FALSE, + CREATE_SUSPENDED, NULL, NULL, &startup, &proc); + + test_end_to_end_server(proc.hProcess, proc.hThread, TRUE); + + /* Don't bother testing W interfaces on Win9x/WinMe */ + SetLastError(0xdeadbeef); + lstrcmpW(NULL, NULL); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Skipping W-interface tests\n"); + } + else + { + sprintf(buffer, "%s dde endw", argv[0]); + CreateProcessA(NULL, buffer, NULL, NULL, FALSE, + CREATE_SUSPENDED, NULL, NULL, &startup, &proc); + + test_end_to_end_server(proc.hProcess, proc.hThread, FALSE); + + sprintf(buffer, "%s dde enda", argv[0]); + CreateProcessA(NULL, buffer, NULL, NULL, FALSE, + CREATE_SUSPENDED, NULL, NULL, &startup, &proc); + + test_end_to_end_server(proc.hProcess, proc.hThread, FALSE); + + sprintf(buffer, "%s dde endw", argv[0]); + CreateProcessA(NULL, buffer, NULL, NULL, FALSE, + CREATE_SUSPENDED, NULL, NULL, &startup, &proc); + + test_end_to_end_server(proc.hProcess, proc.hThread, TRUE); + } + test_dde_aw_transaction(); test_DdeCreateDataHandle(); diff --git a/rostests/winetests/user32/dialog.c b/rostests/winetests/user32/dialog.c index 8bf3c290b95..5879fbcb569 100755 --- a/rostests/winetests/user32/dialog.c +++ b/rostests/winetests/user32/dialog.c @@ -36,6 +36,7 @@ #include "wine/test.h" #include "windef.h" #include "winbase.h" +#include "wingdi.h" #include "winuser.h" #define MAXHWNDS 1024 @@ -54,7 +55,7 @@ static BOOL g_bInitialFocusInitDlgResult; static int g_terminated; typedef struct { - unsigned int id; + INT_PTR id; int parent; DWORD style; DWORD exstyle; @@ -160,7 +161,7 @@ static BOOL CreateWindows (HINSTANCE hinst) { if (p->id >= sizeof(hwnd)/sizeof(hwnd[0])) { - trace ("Control %d is out of range\n", p->id); + trace ("Control %ld is out of range\n", p->id); return FALSE; } else @@ -168,21 +169,21 @@ static BOOL CreateWindows (HINSTANCE hinst) } if (p->id <= 0) { - trace ("Control %d is out of range\n", p->id); + trace ("Control %ld is out of range\n", p->id); return FALSE; } if (hwnd[p->id] != 0) { - trace ("Control %d is used more than once\n", p->id); + trace ("Control %ld is used more than once\n", p->id); return FALSE; } /* Create the control */ - sprintf (ctrlname, "ctrl%4.4d", p->id); + sprintf (ctrlname, "ctrl%4.4ld", p->id); hwnd[p->id] = CreateWindowEx (p->exstyle, TEXT(p->parent ? "static" : "GetNextDlgItemWindowClass"), TEXT(ctrlname), p->style, 10, 10, 10, 10, hwnd[p->parent], p->parent ? (HMENU) (2000 + p->id) : 0, hinst, 0); if (!hwnd[p->id]) { - trace ("Failed to create control %d\n", p->id); + trace ("Failed to create control %ld\n", p->id); return FALSE; } @@ -196,7 +197,7 @@ static BOOL CreateWindows (HINSTANCE hinst) exstyle = GetWindowLong (hwnd[p->id], GWL_EXSTYLE); if (style != p->style || exstyle != p->exstyle) { - trace ("Style mismatch at %d: %8.8x %8.8x cf %8.8x %8.8x\n", p->id, style, exstyle, p->style, p->exstyle); + trace ("Style mismatch at %ld: %8.8x %8.8x cf %8.8x %8.8x\n", p->id, style, exstyle, p->style, p->exstyle); } } p++; @@ -872,9 +873,9 @@ static void InitialFocusTest (void) HANDLE hTemplate; DLGTEMPLATE* pTemplate; - hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", (LPSTR)RT_DIALOG); + hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", RT_DIALOG); hTemplate = LoadResource(g_hinst, hResource); - pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate); + pTemplate = LockResource(hTemplate); g_hwndInitialFocusT1 = 0; hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0); @@ -896,22 +897,93 @@ static void test_GetDlgItemText(void) ret = GetDlgItemTextA(NULL, 0, string, sizeof(string)/sizeof(string[0])); ok(!ret, "GetDlgItemText(NULL) shouldn't have succeeded\n"); - ok(string[0] == '\0', "string retrieved using GetDlgItemText should have been NULL terminated\n"); + ok(string[0] == '\0' || broken(!strcmp(string, "Overwrite Me")), + "string retrieved using GetDlgItemText should have been NULL terminated\n"); +} + +static INT_PTR CALLBACK DestroyDlgWinProc (HWND hDlg, UINT uiMsg, + WPARAM wParam, LPARAM lParam) +{ + if (uiMsg == WM_INITDIALOG) + { + DestroyWindow(hDlg); + return TRUE; + } + return FALSE; +} + +static INT_PTR CALLBACK DestroyOnCloseDlgWinProc (HWND hDlg, UINT uiMsg, + WPARAM wParam, LPARAM lParam) +{ + switch (uiMsg) + { + case WM_INITDIALOG: + PostMessage(hDlg, WM_CLOSE, 0, 0); + return TRUE; + case WM_CLOSE: + DestroyWindow(hDlg); + return TRUE; + case WM_DESTROY: + PostQuitMessage(0); + return TRUE; + } + return FALSE; +} + + +static INT_PTR CALLBACK TestDefButtonDlgProc (HWND hDlg, UINT uiMsg, + WPARAM wParam, LPARAM lParam) +{ + switch (uiMsg) + { + case WM_INITDIALOG: + EndDialog(hDlg, LOWORD(SendMessage(hDlg, DM_GETDEFID, 0, 0))); + return TRUE; + } + return FALSE; } static void test_DialogBoxParamA(void) { - int ret; + INT_PTR ret; HWND hwnd_invalid = (HWND)0x4444; SetLastError(0xdeadbeef); ret = DialogBoxParamA(GetModuleHandle(NULL), "IDD_DIALOG" , hwnd_invalid, 0 , 0); - ok(0 == ret, "DialogBoxParamA returned %d, expected 0\n", ret); - ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError(),"got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError()); + ok(0 == ret || broken(ret == -1), "DialogBoxParamA returned %ld, expected 0\n", ret); + ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() || + broken(GetLastError() == 0xdeadbeef), + "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError()); + + /* Test a dialog which destroys itself on WM_INITDIALOG. */ + SetLastError(0xdeadbeef); + ret = DialogBoxParamA(GetModuleHandle(NULL), "IDD_DIALOG", 0, DestroyDlgWinProc, 0); + ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret); + ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() || + GetLastError() == ERROR_SUCCESS || + broken(GetLastError() == 0xdeadbeef), + "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError()); + + /* Test a dialog which destroys itself on WM_CLOSE. */ + ret = DialogBoxParamA(GetModuleHandle(NULL), "IDD_DIALOG", 0, DestroyOnCloseDlgWinProc, 0); + ok(0 == ret, "DialogBoxParamA returned %ld, expected 0\n", ret); + SetLastError(0xdeadbeef); ret = DialogBoxParamA(GetModuleHandle(NULL), "RESOURCE_INVALID" , 0, 0, 0); - ok(-1 == ret, "DialogBoxParamA returned %d, expected -1\n", ret); - ok(ERROR_RESOURCE_NAME_NOT_FOUND == GetLastError(),"got %d, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError()); + ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret); + ok(ERROR_RESOURCE_NAME_NOT_FOUND == GetLastError() || + broken(GetLastError() == 0xdeadbeef), + "got %d, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError()); + + SetLastError(0xdeadbeef); + ret = DefDlgProcA(0, WM_ERASEBKGND, 0, 0); + ok(ret == 0, "DefDlgProcA returned %ld, expected 0\n", ret); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || + broken(GetLastError() == 0xdeadbeef), + "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); + + ret = DialogBoxParamA(GetModuleHandle(NULL), "TEST_EMPTY_DIALOG", 0, TestDefButtonDlgProc, 0); + ok(ret == IDOK, "Expected IDOK\n"); } static void test_DisabledDialogTest(void) @@ -921,6 +993,156 @@ static void test_DisabledDialogTest(void) ok(FALSE == g_terminated, "dialog with disabled ok button has been terminated\n"); } +static INT_PTR CALLBACK messageBoxFontDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam, + LPARAM lParam) +{ + return (uiMsg == WM_INITDIALOG); +} + +static void test_MessageBoxFontTest(void) +{ + /* This dialog template defines a dialog template which got 0x7fff as its + * font size and omits the other font members. On WinNT, passing such a + * dialog template to CreateDialogIndirectParamW will result in a dialog + * being created which uses the message box font. We test that here. + */ + + static unsigned char dlgTemplate[] = + { + /* Dialog header */ + 0x01,0x00, /* Version */ + 0xff,0xff, /* Extended template marker */ + 0x00,0x00,0x00,0x00, /* Context Help ID */ + 0x00,0x00,0x00,0x00, /* Extended style */ + 0xc0,0x00,0xc8,0x80, /* Style (WS_SYSMENU|WS_CAPTION|WS_POPUP|DS_SETFONT|DS_MODALFRAME) */ + 0x01,0x00, /* Control count */ + 0x00,0x00, /* X */ + 0x00,0x00, /* Y */ + 0x80,0x00, /* Width */ + 0x80,0x00, /* Height */ + 0x00,0x00, /* Menu name */ + 0x00,0x00, /* Class name */ + 'T',0x00,'e',0x00, /* Caption (unicode) */ + 's',0x00,'t',0x00, + 0x00,0x00, + 0xff,0x7f, /* Font height (0x7fff = message box font) */ + + /* Control #1 */ + 0x00,0x00, /* Align to DWORD (header is 42 bytes) */ + 0x00,0x00,0x00,0x00, /* Context Help ID */ + 0x00,0x00,0x00,0x00, /* Extended style */ + 0x00,0x00,0x00,0x50, /* Style (WS_CHILD|WS_VISIBLE) */ + 0x00,0x00, /* X */ + 0x00,0x00, /* Y */ + 0x80,0x00, /* Width */ + 0x80,0x00, /* Height */ + 0x00,0x01,0x00,0x00, /* Control ID (256) */ + 0xff,0xff,0x82,0x00, /* Class (Static) */ + 'W',0x00,'I',0x00, /* Caption (unicode) */ + 'N',0x00,'E',0x00, + ' ',0x00,'d',0x00, + 'i',0x00,'a',0x00, + 'l',0x00,'o',0x00, + 'g',0x00,' ',0x00, + 't',0x00,'e',0x00, + 's',0x00,'t',0x00, + '.',0x00,0x00,0x00, + 0x00,0x00, /* Size of extended data */ + + 0x00,0x00 /* Align to DWORD */ + }; + + HWND hDlg; + HFONT hFont; + LOGFONTW lfStaticFont; + NONCLIENTMETRICSW ncMetrics; + + /* Check if the dialog can be created from the template. On Win9x, this should fail + * because we are calling the W function which is not implemented, but that's what + * we want, because passing such a template to CreateDialogIndirectParamA would crash + * anyway. + */ + hDlg = CreateDialogIndirectParamW(g_hinst, (LPCDLGTEMPLATE)dlgTemplate, NULL, messageBoxFontDlgWinProc, 0); + if (!hDlg) + { + win_skip("dialog wasn't created\n"); + return; + } + + hFont = (HFONT) SendDlgItemMessageW(hDlg, 256, WM_GETFONT, 0, 0); + if (!hFont) + { + skip("dialog uses system font\n"); + DestroyWindow(hDlg); + return; + } + GetObjectW(hFont, sizeof(LOGFONTW), &lfStaticFont); + + ncMetrics.cbSize = sizeof(NONCLIENTMETRICSW); + SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncMetrics, 0); + ok( !memcmp(&lfStaticFont, &ncMetrics.lfMessageFont, FIELD_OFFSET(LOGFONTW, lfFaceName)) && + !lstrcmpW(lfStaticFont.lfFaceName, ncMetrics.lfMessageFont.lfFaceName), + "dialog doesn't use message box font\n"); + DestroyWindow(hDlg); +} + +static void test_SaveRestoreFocus(void) +{ + HWND hDlg; + HRSRC hResource; + HANDLE hTemplate; + DLGTEMPLATE* pTemplate; + LONG_PTR foundId; + HWND foundHwnd; + + /* create the dialog */ + hResource = FindResourceA(g_hinst, "MULTI_EDIT_DIALOG", RT_DIALOG); + hTemplate = LoadResource(g_hinst, hResource); + pTemplate = LockResource(hTemplate); + + hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, messageBoxFontDlgWinProc, 0); + ok (hDlg != 0, "Failed to create test dialog.\n"); + + foundId = GetWindowLongPtr(GetFocus(), GWLP_ID); + ok (foundId == 1000, "First edit box should have gained focus on dialog creation. Expected: %d, Found: %ld\n", 1000, foundId); + + /* de- then reactivate the dialog */ + SendMessage(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0); + SendMessage(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0); + + foundId = GetWindowLongPtr(GetFocus(), GWLP_ID); + ok (foundId == 1000, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1000, foundId); + + /* select the next tabbable item */ + SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE)); + + foundId = GetWindowLongPtr(GetFocus(), GWLP_ID); + ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId); + + /* de- then reactivate the dialog */ + SendMessage(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0); + SendMessage(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0); + + foundId = GetWindowLongPtr(GetFocus(), GWLP_ID); + ok (foundId == 1001, "Second edit box should have gained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId); + + /* disable the 2nd box */ + EnableWindow(GetFocus(), FALSE); + + foundHwnd = GetFocus(); + ok (foundHwnd == NULL, "Second edit box should have lost focus after being disabled. Expected: %p, Found: %p\n", NULL, foundHwnd); + + /* de- then reactivate the dialog */ + SendMessage(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0); + SendMessage(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0); + + foundHwnd = GetFocus(); + ok (foundHwnd == NULL, "No controls should have gained focus after dialog reactivation. Expected: %p, Found: %p\n", NULL, foundHwnd); + + /* clean up */ + DestroyWindow(hDlg); +} + START_TEST(dialog) { g_hinst = GetModuleHandleA (0); @@ -934,4 +1156,6 @@ START_TEST(dialog) test_GetDlgItemText(); test_DialogBoxParamA(); test_DisabledDialogTest(); + test_MessageBoxFontTest(); + test_SaveRestoreFocus(); } diff --git a/rostests/winetests/user32/edit.c b/rostests/winetests/user32/edit.c index 0c5a6786188..b24f138ce93 100755 --- a/rostests/winetests/user32/edit.c +++ b/rostests/winetests/user32/edit.c @@ -28,6 +28,7 @@ #define ES_COMBO 0x200 #endif +#define ID_EDITTESTDBUTTON 0x123 #define ID_EDITTEST2 99 #define MAXLEN 200 @@ -646,8 +647,8 @@ static void set_client_height(HWND Wnd, unsigned Height) GetClientRect(Wnd, &ClientRect); ok(ClientRect.bottom - ClientRect.top == Height, - "The client height should be %ld, but is %ld\n", - (long)Height, (long)(ClientRect.bottom - ClientRect.top)); + "The client height should be %d, but is %d\n", + Height, ClientRect.bottom - ClientRect.top); } static void test_edit_control_1(void) @@ -1177,9 +1178,13 @@ static void test_edit_control_4(void) static void test_edit_control_5(void) { static const char *str = "test\r\ntest"; + HWND parentWnd; HWND hWnd; int len; + RECT rc1 = { 10, 10, 11, 11}; + RECT rc; + /* first show that a non-child won't do for this test */ hWnd = CreateWindowEx(0, "EDIT", str, @@ -1187,24 +1192,92 @@ static void test_edit_control_5(void) 10, 10, 1, 1, NULL, NULL, NULL, NULL); assert(hWnd); - + /* size of non-child edit control is (much) bigger than requested */ + GetWindowRect( hWnd, &rc); + ok( rc.right - rc.left > 20, "size of the window (%d) is smaller than expected\n", + rc.right - rc.left); + DestroyWindow(hWnd); + /* so create a parent, and give it edit controls children to test with */ + parentWnd = CreateWindowEx(0, + szEditTextPositionClass, + "Edit Test", WS_VISIBLE | + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + 250, 250, + NULL, NULL, hinst, NULL); + assert(parentWnd); + ShowWindow( parentWnd, SW_SHOW); + /* single line */ + hWnd = CreateWindowEx(0, + "EDIT", + str, WS_VISIBLE | WS_BORDER | + WS_CHILD, + rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, + parentWnd, NULL, NULL, NULL); + assert(hWnd); + GetClientRect( hWnd, &rc); + ok( rc.right == rc1.right - rc1.left && rc.bottom == rc1.bottom - rc1.top, + "Client rectangle not the expected size (%d,%d,%d,%d)\n", + rc.left, rc.top, rc.right, rc.bottom); len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); DestroyWindow(hWnd); - + /* multi line */ hWnd = CreateWindowEx(0, "EDIT", str, - ES_MULTILINE, - 10, 10, 1, 1, - NULL, NULL, NULL, NULL); + WS_CHILD | ES_MULTILINE, + rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, + parentWnd, NULL, NULL, NULL); assert(hWnd); - + GetClientRect( hWnd, &rc); + ok( rc.right == rc1.right - rc1.left && rc.bottom == rc1.bottom - rc1.top, + "Client rectangle not the expected size (%d,%d,%d,%d)\n", + rc.left, rc.top, rc.right, rc.bottom); len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0); ok(lstrlenA(str) == len, "text shouldn't have been truncated\n"); DestroyWindow(hWnd); } +/* Test WM_GETTEXT processing + * after destroy messages + */ +static void test_edit_control_6(void) +{ + static const char *str = "test\r\ntest"; + char buf[MAXLEN]; + LONG ret; + HWND hWnd; + + hWnd = CreateWindowEx(0, + "EDIT", + "Test", + 0, + 10, 10, 1, 1, + NULL, NULL, hinst, NULL); + assert(hWnd); + + ret = SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str); + ok(ret == TRUE, "Expected %d, got %d\n", TRUE, ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); + ok(ret == lstrlen(str), "Expected %s, got len %d\n", str, ret); + ok(!lstrcmp(buf, str), "Expected %s, got %s\n", str, buf); + buf[0] = 0; + ret = SendMessageA(hWnd, WM_DESTROY, 0, 0); + ok(ret == 0, "Expected 0, got %d\n", ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); + ok(ret == lstrlen(str), "Expected %s, got len %d\n", str, ret); + ok(!lstrcmp(buf, str), "Expected %s, got %s\n", str, buf); + buf[0] = 0; + ret = SendMessageA(hWnd, WM_NCDESTROY, 0, 0); + ok(ret == 0, "Expected 0, got %d\n", ret); + ret = SendMessageA(hWnd, WM_GETTEXT, MAXLEN, (LPARAM)buf); + ok(ret == 0, "Expected 0, got len %d\n", ret); + ok(!lstrcmp(buf, ""), "Expected empty string, got %s\n", buf); + + DestroyWindow(hWnd); +} + static void test_edit_control_limittext(void) { HWND hwEdit; @@ -1336,29 +1409,40 @@ static void test_margins_font_change(void) SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0,0)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 0, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins)); + ok(LOWORD(margins) == 0 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */ + "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 0 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */ + "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,0)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 0, "got %d\n", HIWORD(margins)); + ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */ + "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 0 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */ + "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(1,1)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont, 0); margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); + ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */ + "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 1 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */ + "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(EC_USEFONTINFO,EC_USEFONTINFO)); margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); + ok(LOWORD(margins) == 1 || broken(LOWORD(margins) == LOWORD(font_margins)), /* win95 */ + "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 1 || broken(HIWORD(margins) == HIWORD(font_margins)), /* win95 */ + "got %d\n", HIWORD(margins)); + SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0); margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) == 1, "got %d\n", LOWORD(margins)); - ok(HIWORD(margins) == 1, "got %d\n", HIWORD(margins)); + ok(LOWORD(margins) == 1 || broken(LOWORD(margins) != 1 && LOWORD(margins) != LOWORD(font_margins)), /* win95 */ + "got %d\n", LOWORD(margins)); + ok(HIWORD(margins) == 1 || broken(HIWORD(margins) != 1 && HIWORD(margins) != HIWORD(font_margins)), /* win95 */ + "got %d\n", HIWORD(margins)); /* Above a certain size threshold then the margin is updated */ SetWindowPos(hwEdit, NULL, 10, 10, 1000, 100, SWP_NOZORDER | SWP_NOACTIVATE); @@ -1380,7 +1464,8 @@ static void test_margins_font_change(void) ok(HIWORD(margins) == HIWORD(font_margins), "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, WM_SETFONT, (WPARAM)hfont2, 0); margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0); - ok(LOWORD(margins) != LOWORD(font_margins), "got %d\n", LOWORD(margins)); + ok(LOWORD(margins) != LOWORD(font_margins) || broken(LOWORD(margins) == LOWORD(font_margins)), /* win98 */ + "got %d\n", LOWORD(margins)); ok(HIWORD(margins) != HIWORD(font_margins), "got %d\n", HIWORD(margins)); SendMessageA(hwEdit, WM_SETFONT, 0, 0); @@ -1772,9 +1857,9 @@ static void test_edit_dialog(void) /* more tests for WM_KEYDOWN + WM_CHAR */ r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 6); - todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r); + ok(444 == r, "Expected %d, got %d\n", 444, r); r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 7); - todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r); + ok(444 == r, "Expected %d, got %d\n", 444, r); r = DialogBoxParam(hinst, "EDIT_READONLY_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 8); ok(444 == r, "Expected %d, got %d\n", 444, r); @@ -1796,9 +1881,9 @@ static void test_edit_dialog(void) /* tests for WM_KEYDOWN + WM_CHAR */ r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 6); - todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r); + ok(444 == r, "Expected %d, got %d\n", 444, r); r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 7); - todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r); + ok(444 == r, "Expected %d, got %d\n", 444, r); r = DialogBoxParam(hinst, "EDIT_DIALOG", NULL, (DLGPROC)edit_dialog_proc, 8); ok(444 == r, "Expected %d, got %d\n", 444, r); @@ -1846,7 +1931,7 @@ static void test_wantreturn_edit_dialog(void) /* tests for WM_KEYDOWN + WM_CHAR */ r = DialogBoxParam(hinst, "EDIT_WANTRETURN_DIALOG", NULL, (DLGPROC)edit_wantreturn_dialog_proc, 6); - todo_wine ok(444 == r, "Expected %d, got %d\n", 444, r); + ok(444 == r, "Expected %d, got %d\n", 444, r); r = DialogBoxParam(hinst, "EDIT_WANTRETURN_DIALOG", NULL, (DLGPROC)edit_wantreturn_dialog_proc, 7); ok(444 == r, "Expected %d, got %d\n", 444, r); r = DialogBoxParam(hinst, "EDIT_WANTRETURN_DIALOG", NULL, (DLGPROC)edit_wantreturn_dialog_proc, 8); @@ -1961,7 +2046,7 @@ static BOOL RegisterWindowClasses (void) test3.cbWndExtra = 0; test3.hInstance = hinst; test3.hIcon = 0; - test3.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + test3.hCursor = LoadCursorA(0, IDC_ARROW); test3.hbrBackground = GetStockObject(WHITE_BRUSH); test3.lpszMenuName = NULL; test3.lpszClassName = szEditTest3Class; @@ -1989,6 +2074,231 @@ static void UnregisterWindowClasses (void) UnregisterClassA(szEditTextPositionClass, hinst); } +static void test_fontsize(void) +{ + HWND hwEdit; + HFONT hfont; + LOGFONT lf; + LONG r; + char szLocalString[MAXLEN]; + + memset(&lf,0,sizeof(LOGFONTA)); + strcpy(lf.lfFaceName,"Arial"); + lf.lfHeight = -300; /* taller than the edit box */ + lf.lfWeight = 500; + hfont = CreateFontIndirect(&lf); + + trace("EDIT: Oversized font (Multi line)\n"); + hwEdit= CreateWindow("EDIT", NULL, ES_MULTILINE|ES_AUTOHSCROLL, + 0, 0, 150, 50, NULL, NULL, hinst, NULL); + + SendMessage(hwEdit,WM_SETFONT,(WPARAM)hfont,0); + + if (winetest_interactive) + ShowWindow (hwEdit, SW_SHOW); + + r = SendMessage(hwEdit, WM_CHAR, 'A', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + r = SendMessage(hwEdit, WM_CHAR, 'B', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + r = SendMessage(hwEdit, WM_CHAR, 'C', 1); + ok(1 == r, "Expected: %d, got: %d\n", 1, r); + + GetWindowText(hwEdit, szLocalString, MAXLEN); + ok(lstrcmp(szLocalString, "ABC")==0, + "Wrong contents of edit: %s\n", szLocalString); + + r = SendMessage(hwEdit, EM_POSFROMCHAR,0,0); + ok(r != -1,"EM_POSFROMCHAR failed index 0\n"); + r = SendMessage(hwEdit, EM_POSFROMCHAR,1,0); + ok(r != -1,"EM_POSFROMCHAR failed index 1\n"); + r = SendMessage(hwEdit, EM_POSFROMCHAR,2,0); + ok(r != -1,"EM_POSFROMCHAR failed index 2\n"); + r = SendMessage(hwEdit, EM_POSFROMCHAR,3,0); + ok(r == -1,"EM_POSFROMCHAR succeeded index 3\n"); + + DestroyWindow (hwEdit); + DeleteObject(hfont); +} + +struct dialog_mode_messages +{ + int wm_getdefid, wm_close, wm_command, wm_nextdlgctl; +}; + +static struct dialog_mode_messages dm_messages; + +static void zero_dm_messages(void) +{ + dm_messages.wm_command = 0; + dm_messages.wm_close = 0; + dm_messages.wm_getdefid = 0; + dm_messages.wm_nextdlgctl = 0; +} + +#define test_dm_messages(wmcommand, wmclose, wmgetdefid, wmnextdlgctl) \ + ok(dm_messages.wm_command == wmcommand, "expected %d WM_COMMAND messages, " \ + "got %d\n", wmcommand, dm_messages.wm_command); \ + ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE messages, " \ + "got %d\n", wmclose, dm_messages.wm_close); \ + ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID messages, " \ + "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\ + ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL messages, " \ + "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl) + +static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + switch (iMsg) + { + case WM_COMMAND: + dm_messages.wm_command++; + break; + case DM_GETDEFID: + dm_messages.wm_getdefid++; + return MAKELONG(ID_EDITTESTDBUTTON, DC_HASDEFID); + case WM_NEXTDLGCTL: + dm_messages.wm_nextdlgctl++; + break; + case WM_CLOSE: + dm_messages.wm_close++; + break; + } + + return DefWindowProc(hwnd, iMsg, wParam, lParam); +} + +static void test_dialogmode(void) +{ + HWND hwEdit, hwParent, hwButton; + MSG msg= {0}; + int len, r; + hwEdit = create_child_editcontrol(ES_MULTILINE, 0); + + r = SendMessage(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessage(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(11 == len, "expected 11, got %d\n", len); + + r = SendMessage(hwEdit, WM_GETDLGCODE, (WPARAM)NULL, (LPARAM)NULL); + ok(0x8d == r, "expected 0x8d, got 0x%x\n", r); + + r = SendMessage(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessage(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(13 == len, "expected 13, got %d\n", len); + + r = SendMessage(hwEdit, WM_GETDLGCODE, (WPARAM)NULL, (LPARAM)&msg); + ok(0x8d == r, "expected 0x8d, got 0x%x\n", r); + r = SendMessage(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessage(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(13 == len, "expected 13, got %d\n", len); + + r = SendMessage(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessage(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(13 == len, "expected 13, got %d\n", len); + + destroy_child_editcontrol(hwEdit); + + hwEdit = create_editcontrol(ES_MULTILINE, 0); + + r = SendMessage(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessage(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(11 == len, "expected 11, got %d\n", len); + + msg.hwnd = hwEdit; + msg.message = WM_KEYDOWN; + msg.wParam = VK_BACK; + msg.lParam = 0xe0001; + r = SendMessage(hwEdit, WM_GETDLGCODE, VK_BACK, (LPARAM)&msg); + ok(0x8d == r, "expected 0x8d, got 0x%x\n", r); + + r = SendMessage(hwEdit, WM_CHAR, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + len = SendMessage(hwEdit, WM_GETTEXTLENGTH, 0, 0); + ok(11 == len, "expected 11, got %d\n", len); + + DestroyWindow(hwEdit); + + hwEdit = create_child_editcontrol(0, 0); + hwParent = GetParent(hwEdit); + SetWindowLongPtr(hwParent, GWLP_WNDPROC, (LONG_PTR)dialog_mode_wnd_proc); + + zero_dm_messages(); + r = SendMessage(hwEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + r = SendMessage(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + msg.hwnd = hwEdit; + msg.message = WM_KEYDOWN; + msg.wParam = VK_TAB; + msg.lParam = 0xf0001; + r = SendMessage(hwEdit, WM_GETDLGCODE, VK_TAB, (LPARAM)&msg); + ok(0x89 == r, "expected 0x89, got 0x%x\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + r = SendMessage(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + destroy_child_editcontrol(hwEdit); + + hwEdit = create_child_editcontrol(ES_MULTILINE, 0); + hwParent = GetParent(hwEdit); + SetWindowLongPtr(hwParent, GWLP_WNDPROC, (LONG_PTR)dialog_mode_wnd_proc); + + r = SendMessage(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + msg.hwnd = hwEdit; + msg.message = WM_KEYDOWN; + msg.wParam = VK_ESCAPE; + msg.lParam = 0x10001; + r = SendMessage(hwEdit, WM_GETDLGCODE, VK_ESCAPE, (LPARAM)&msg); + ok(0x8d == r, "expected 0x8d, got 0x%x\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + r = SendMessage(hwEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 0); + zero_dm_messages(); + + r = SendMessage(hwEdit, WM_KEYDOWN, VK_TAB, 0xf0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 0, 1); + zero_dm_messages(); + + r = SendMessage(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 1, 0); + zero_dm_messages(); + + hwButton = CreateWindow("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, + 100, 100, 50, 20, hwParent, (HMENU)ID_EDITTESTDBUTTON, hinst, NULL); + ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError()); + + r = SendMessage(hwEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001); + ok(1 == r, "expected 1, got %d\n", r); + test_dm_messages(0, 0, 1, 1); + zero_dm_messages(); + + DestroyWindow(hwButton); + destroy_child_editcontrol(hwEdit); +} + START_TEST(edit) { hinst = GetModuleHandleA(NULL); @@ -1999,6 +2309,7 @@ START_TEST(edit) test_edit_control_3(); test_edit_control_4(); test_edit_control_5(); + test_edit_control_6(); test_edit_control_limittext(); test_margins(); test_margins_font_change(); @@ -2012,6 +2323,8 @@ START_TEST(edit) test_wantreturn_edit_dialog(); test_singleline_wantreturn_edit_dialog(); test_child_edit_wmkeydown(); + test_fontsize(); + test_dialogmode(); UnregisterWindowClasses(); } diff --git a/rostests/winetests/user32/generated.c b/rostests/winetests/user32/generated.c index c2d24f913ff..2327a30a35c 100644 --- a/rostests/winetests/user32/generated.c +++ b/rostests/winetests/user32/generated.c @@ -1,4 +1,4 @@ -/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* File generated automatically from tools/winapi/tests.dat; do not edit! */ /* This file can be copied, modified and distributed without restriction. */ /* @@ -27,22 +27,14 @@ * Windows API extension */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) -# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) -#elif defined(__GNUC__) -# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) -#else -/* FIXME: Not sure if is possible to do without compiler extension */ -#endif - #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) #elif defined(__GNUC__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* - * FIXME: Not sure if is possible to do without compiler extension - * (if type is not just a name that is, if so the normal) + * FIXME: May not be possible without a compiler extension + * (if type is not just a name that is, otherwise the normal * TYPE_ALIGNMENT can be used) */ #endif @@ -59,2170 +51,3536 @@ * Test helper macros */ -#ifdef FIELD_ALIGNMENT -# define TEST_FIELD_ALIGNMENT(type, field, align) \ - ok(FIELD_ALIGNMENT(type, field) == align, \ - "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ - (int)FIELD_ALIGNMENT(type, field)) +#ifdef _WIN64 + +# define TEST_TYPE_SIZE(type, size) +# define TEST_TYPE_ALIGN(type, align) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) +# define TEST_FIELD_OFFSET(type, field, offset) + #else -# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) + +# define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); + +# ifdef TYPE_ALIGNMENT +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +#else +# define TEST_TYPE_ALIGN(type, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) \ - ok(FIELD_OFFSET(type, field) == offset, \ - "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ - (long int)FIELD_OFFSET(type, field)) - -#ifdef _TYPE_ALIGNMENT -#define TEST__TYPE_ALIGNMENT(type, align) \ - ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +# ifdef _TYPE_ALIGNMENT +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else -# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) #endif -#ifdef TYPE_ALIGNMENT -#define TEST_TYPE_ALIGNMENT(type, align) \ - ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) -#else -# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); + #endif -#define TEST_TYPE_SIZE(type, size) \ - ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) +#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) +#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) +#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0); +#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0); -/*********************************************************************** - * Test macros - */ - -#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ - TEST_TYPE_SIZE(field_type, field_size); \ - TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ - TEST_FIELD_OFFSET(type, field_name, field_offset); \ - -#define TEST_TYPE(type, size, align) \ - TEST_TYPE_ALIGNMENT(type, align); \ - TEST_TYPE_SIZE(type, size) - -#define TEST_TYPE_POINTER(type, size, align) \ - TEST__TYPE_ALIGNMENT(*(type)0, align); \ - TEST_TYPE_SIZE(*(type)0, size) - -#define TEST_TYPE_SIGNED(type) \ - ok((type) -1 < 0, "(" #type ") -1 < 0\n"); - -#define TEST_TYPE_UNSIGNED(type) \ - ok((type) -1 > 0, "(" #type ") -1 > 0\n"); static void test_pack_ACCESSTIMEOUT(void) { /* ACCESSTIMEOUT (pack 4) */ - TEST_TYPE(ACCESSTIMEOUT, 12, 4); - TEST_FIELD(ACCESSTIMEOUT, UINT, cbSize, 0, 4, 4); - TEST_FIELD(ACCESSTIMEOUT, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(ACCESSTIMEOUT, DWORD, iTimeOutMSec, 8, 4, 4); + TEST_TYPE_SIZE (ACCESSTIMEOUT, 12) + TEST_TYPE_ALIGN (ACCESSTIMEOUT, 4) + TEST_FIELD_SIZE (ACCESSTIMEOUT, cbSize, 4) + TEST_FIELD_ALIGN (ACCESSTIMEOUT, cbSize, 4) + TEST_FIELD_OFFSET(ACCESSTIMEOUT, cbSize, 0) + TEST_FIELD_SIZE (ACCESSTIMEOUT, dwFlags, 4) + TEST_FIELD_ALIGN (ACCESSTIMEOUT, dwFlags, 4) + TEST_FIELD_OFFSET(ACCESSTIMEOUT, dwFlags, 4) + TEST_FIELD_SIZE (ACCESSTIMEOUT, iTimeOutMSec, 4) + TEST_FIELD_ALIGN (ACCESSTIMEOUT, iTimeOutMSec, 4) + TEST_FIELD_OFFSET(ACCESSTIMEOUT, iTimeOutMSec, 8) } static void test_pack_ANIMATIONINFO(void) { /* ANIMATIONINFO (pack 4) */ - TEST_TYPE(ANIMATIONINFO, 8, 4); - TEST_FIELD(ANIMATIONINFO, UINT, cbSize, 0, 4, 4); - TEST_FIELD(ANIMATIONINFO, INT, iMinAnimate, 4, 4, 4); + TEST_TYPE_SIZE (ANIMATIONINFO, 8) + TEST_TYPE_ALIGN (ANIMATIONINFO, 4) + TEST_FIELD_SIZE (ANIMATIONINFO, cbSize, 4) + TEST_FIELD_ALIGN (ANIMATIONINFO, cbSize, 4) + TEST_FIELD_OFFSET(ANIMATIONINFO, cbSize, 0) + TEST_FIELD_SIZE (ANIMATIONINFO, iMinAnimate, 4) + TEST_FIELD_ALIGN (ANIMATIONINFO, iMinAnimate, 4) + TEST_FIELD_OFFSET(ANIMATIONINFO, iMinAnimate, 4) } static void test_pack_CBTACTIVATESTRUCT(void) { /* CBTACTIVATESTRUCT (pack 4) */ - TEST_TYPE(CBTACTIVATESTRUCT, 8, 4); - TEST_FIELD(CBTACTIVATESTRUCT, BOOL, fMouse, 0, 4, 4); - TEST_FIELD(CBTACTIVATESTRUCT, HWND, hWndActive, 4, 4, 4); + TEST_TYPE_SIZE (CBTACTIVATESTRUCT, 8) + TEST_TYPE_ALIGN (CBTACTIVATESTRUCT, 4) + TEST_FIELD_SIZE (CBTACTIVATESTRUCT, fMouse, 4) + TEST_FIELD_ALIGN (CBTACTIVATESTRUCT, fMouse, 4) + TEST_FIELD_OFFSET(CBTACTIVATESTRUCT, fMouse, 0) + TEST_FIELD_SIZE (CBTACTIVATESTRUCT, hWndActive, 4) + TEST_FIELD_ALIGN (CBTACTIVATESTRUCT, hWndActive, 4) + TEST_FIELD_OFFSET(CBTACTIVATESTRUCT, hWndActive, 4) } static void test_pack_CBT_CREATEWNDA(void) { /* CBT_CREATEWNDA (pack 4) */ - TEST_TYPE(CBT_CREATEWNDA, 8, 4); - TEST_FIELD(CBT_CREATEWNDA, CREATESTRUCTA *, lpcs, 0, 4, 4); - TEST_FIELD(CBT_CREATEWNDA, HWND, hwndInsertAfter, 4, 4, 4); + TEST_TYPE_SIZE (CBT_CREATEWNDA, 8) + TEST_TYPE_ALIGN (CBT_CREATEWNDA, 4) + TEST_FIELD_SIZE (CBT_CREATEWNDA, lpcs, 4) + TEST_FIELD_ALIGN (CBT_CREATEWNDA, lpcs, 4) + TEST_FIELD_OFFSET(CBT_CREATEWNDA, lpcs, 0) + TEST_FIELD_SIZE (CBT_CREATEWNDA, hwndInsertAfter, 4) + TEST_FIELD_ALIGN (CBT_CREATEWNDA, hwndInsertAfter, 4) + TEST_FIELD_OFFSET(CBT_CREATEWNDA, hwndInsertAfter, 4) } static void test_pack_CBT_CREATEWNDW(void) { /* CBT_CREATEWNDW (pack 4) */ - TEST_TYPE(CBT_CREATEWNDW, 8, 4); - TEST_FIELD(CBT_CREATEWNDW, CREATESTRUCTW *, lpcs, 0, 4, 4); - TEST_FIELD(CBT_CREATEWNDW, HWND, hwndInsertAfter, 4, 4, 4); + TEST_TYPE_SIZE (CBT_CREATEWNDW, 8) + TEST_TYPE_ALIGN (CBT_CREATEWNDW, 4) + TEST_FIELD_SIZE (CBT_CREATEWNDW, lpcs, 4) + TEST_FIELD_ALIGN (CBT_CREATEWNDW, lpcs, 4) + TEST_FIELD_OFFSET(CBT_CREATEWNDW, lpcs, 0) + TEST_FIELD_SIZE (CBT_CREATEWNDW, hwndInsertAfter, 4) + TEST_FIELD_ALIGN (CBT_CREATEWNDW, hwndInsertAfter, 4) + TEST_FIELD_OFFSET(CBT_CREATEWNDW, hwndInsertAfter, 4) } static void test_pack_CLIENTCREATESTRUCT(void) { /* CLIENTCREATESTRUCT (pack 4) */ - TEST_TYPE(CLIENTCREATESTRUCT, 8, 4); - TEST_FIELD(CLIENTCREATESTRUCT, HMENU, hWindowMenu, 0, 4, 4); - TEST_FIELD(CLIENTCREATESTRUCT, UINT, idFirstChild, 4, 4, 4); + TEST_TYPE_SIZE (CLIENTCREATESTRUCT, 8) + TEST_TYPE_ALIGN (CLIENTCREATESTRUCT, 4) + TEST_FIELD_SIZE (CLIENTCREATESTRUCT, hWindowMenu, 4) + TEST_FIELD_ALIGN (CLIENTCREATESTRUCT, hWindowMenu, 4) + TEST_FIELD_OFFSET(CLIENTCREATESTRUCT, hWindowMenu, 0) + TEST_FIELD_SIZE (CLIENTCREATESTRUCT, idFirstChild, 4) + TEST_FIELD_ALIGN (CLIENTCREATESTRUCT, idFirstChild, 4) + TEST_FIELD_OFFSET(CLIENTCREATESTRUCT, idFirstChild, 4) } static void test_pack_COMBOBOXINFO(void) { /* COMBOBOXINFO (pack 4) */ - TEST_TYPE(COMBOBOXINFO, 52, 4); - TEST_FIELD(COMBOBOXINFO, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(COMBOBOXINFO, RECT, rcItem, 4, 16, 4); - TEST_FIELD(COMBOBOXINFO, RECT, rcButton, 20, 16, 4); - TEST_FIELD(COMBOBOXINFO, DWORD, stateButton, 36, 4, 4); - TEST_FIELD(COMBOBOXINFO, HWND, hwndCombo, 40, 4, 4); - TEST_FIELD(COMBOBOXINFO, HWND, hwndItem, 44, 4, 4); - TEST_FIELD(COMBOBOXINFO, HWND, hwndList, 48, 4, 4); + TEST_TYPE_SIZE (COMBOBOXINFO, 52) + TEST_TYPE_ALIGN (COMBOBOXINFO, 4) + TEST_FIELD_SIZE (COMBOBOXINFO, cbSize, 4) + TEST_FIELD_ALIGN (COMBOBOXINFO, cbSize, 4) + TEST_FIELD_OFFSET(COMBOBOXINFO, cbSize, 0) + TEST_FIELD_SIZE (COMBOBOXINFO, rcItem, 16) + TEST_FIELD_ALIGN (COMBOBOXINFO, rcItem, 4) + TEST_FIELD_OFFSET(COMBOBOXINFO, rcItem, 4) + TEST_FIELD_SIZE (COMBOBOXINFO, rcButton, 16) + TEST_FIELD_ALIGN (COMBOBOXINFO, rcButton, 4) + TEST_FIELD_OFFSET(COMBOBOXINFO, rcButton, 20) + TEST_FIELD_SIZE (COMBOBOXINFO, stateButton, 4) + TEST_FIELD_ALIGN (COMBOBOXINFO, stateButton, 4) + TEST_FIELD_OFFSET(COMBOBOXINFO, stateButton, 36) + TEST_FIELD_SIZE (COMBOBOXINFO, hwndCombo, 4) + TEST_FIELD_ALIGN (COMBOBOXINFO, hwndCombo, 4) + TEST_FIELD_OFFSET(COMBOBOXINFO, hwndCombo, 40) + TEST_FIELD_SIZE (COMBOBOXINFO, hwndItem, 4) + TEST_FIELD_ALIGN (COMBOBOXINFO, hwndItem, 4) + TEST_FIELD_OFFSET(COMBOBOXINFO, hwndItem, 44) + TEST_FIELD_SIZE (COMBOBOXINFO, hwndList, 4) + TEST_FIELD_ALIGN (COMBOBOXINFO, hwndList, 4) + TEST_FIELD_OFFSET(COMBOBOXINFO, hwndList, 48) } static void test_pack_COMPAREITEMSTRUCT(void) { /* COMPAREITEMSTRUCT (pack 4) */ - TEST_TYPE(COMPAREITEMSTRUCT, 32, 4); - TEST_FIELD(COMPAREITEMSTRUCT, UINT, CtlType, 0, 4, 4); - TEST_FIELD(COMPAREITEMSTRUCT, UINT, CtlID, 4, 4, 4); - TEST_FIELD(COMPAREITEMSTRUCT, HWND, hwndItem, 8, 4, 4); - TEST_FIELD(COMPAREITEMSTRUCT, UINT, itemID1, 12, 4, 4); - TEST_FIELD(COMPAREITEMSTRUCT, ULONG_PTR, itemData1, 16, 4, 4); - TEST_FIELD(COMPAREITEMSTRUCT, UINT, itemID2, 20, 4, 4); - TEST_FIELD(COMPAREITEMSTRUCT, ULONG_PTR, itemData2, 24, 4, 4); - TEST_FIELD(COMPAREITEMSTRUCT, DWORD, dwLocaleId, 28, 4, 4); + TEST_TYPE_SIZE (COMPAREITEMSTRUCT, 32) + TEST_TYPE_ALIGN (COMPAREITEMSTRUCT, 4) + TEST_FIELD_SIZE (COMPAREITEMSTRUCT, CtlType, 4) + TEST_FIELD_ALIGN (COMPAREITEMSTRUCT, CtlType, 4) + TEST_FIELD_OFFSET(COMPAREITEMSTRUCT, CtlType, 0) + TEST_FIELD_SIZE (COMPAREITEMSTRUCT, CtlID, 4) + TEST_FIELD_ALIGN (COMPAREITEMSTRUCT, CtlID, 4) + TEST_FIELD_OFFSET(COMPAREITEMSTRUCT, CtlID, 4) + TEST_FIELD_SIZE (COMPAREITEMSTRUCT, hwndItem, 4) + TEST_FIELD_ALIGN (COMPAREITEMSTRUCT, hwndItem, 4) + TEST_FIELD_OFFSET(COMPAREITEMSTRUCT, hwndItem, 8) + TEST_FIELD_SIZE (COMPAREITEMSTRUCT, itemID1, 4) + TEST_FIELD_ALIGN (COMPAREITEMSTRUCT, itemID1, 4) + TEST_FIELD_OFFSET(COMPAREITEMSTRUCT, itemID1, 12) + TEST_FIELD_SIZE (COMPAREITEMSTRUCT, itemData1, 4) + TEST_FIELD_ALIGN (COMPAREITEMSTRUCT, itemData1, 4) + TEST_FIELD_OFFSET(COMPAREITEMSTRUCT, itemData1, 16) + TEST_FIELD_SIZE (COMPAREITEMSTRUCT, itemID2, 4) + TEST_FIELD_ALIGN (COMPAREITEMSTRUCT, itemID2, 4) + TEST_FIELD_OFFSET(COMPAREITEMSTRUCT, itemID2, 20) + TEST_FIELD_SIZE (COMPAREITEMSTRUCT, itemData2, 4) + TEST_FIELD_ALIGN (COMPAREITEMSTRUCT, itemData2, 4) + TEST_FIELD_OFFSET(COMPAREITEMSTRUCT, itemData2, 24) + TEST_FIELD_SIZE (COMPAREITEMSTRUCT, dwLocaleId, 4) + TEST_FIELD_ALIGN (COMPAREITEMSTRUCT, dwLocaleId, 4) + TEST_FIELD_OFFSET(COMPAREITEMSTRUCT, dwLocaleId, 28) } static void test_pack_COPYDATASTRUCT(void) { /* COPYDATASTRUCT (pack 4) */ - TEST_TYPE(COPYDATASTRUCT, 12, 4); - TEST_FIELD(COPYDATASTRUCT, ULONG_PTR, dwData, 0, 4, 4); - TEST_FIELD(COPYDATASTRUCT, DWORD, cbData, 4, 4, 4); - TEST_FIELD(COPYDATASTRUCT, PVOID, lpData, 8, 4, 4); + TEST_TYPE_SIZE (COPYDATASTRUCT, 12) + TEST_TYPE_ALIGN (COPYDATASTRUCT, 4) + TEST_FIELD_SIZE (COPYDATASTRUCT, dwData, 4) + TEST_FIELD_ALIGN (COPYDATASTRUCT, dwData, 4) + TEST_FIELD_OFFSET(COPYDATASTRUCT, dwData, 0) + TEST_FIELD_SIZE (COPYDATASTRUCT, cbData, 4) + TEST_FIELD_ALIGN (COPYDATASTRUCT, cbData, 4) + TEST_FIELD_OFFSET(COPYDATASTRUCT, cbData, 4) + TEST_FIELD_SIZE (COPYDATASTRUCT, lpData, 4) + TEST_FIELD_ALIGN (COPYDATASTRUCT, lpData, 4) + TEST_FIELD_OFFSET(COPYDATASTRUCT, lpData, 8) } static void test_pack_CREATESTRUCTA(void) { /* CREATESTRUCTA (pack 4) */ - TEST_TYPE(CREATESTRUCTA, 48, 4); - TEST_FIELD(CREATESTRUCTA, LPVOID, lpCreateParams, 0, 4, 4); - TEST_FIELD(CREATESTRUCTA, HINSTANCE, hInstance, 4, 4, 4); - TEST_FIELD(CREATESTRUCTA, HMENU, hMenu, 8, 4, 4); - TEST_FIELD(CREATESTRUCTA, HWND, hwndParent, 12, 4, 4); - TEST_FIELD(CREATESTRUCTA, INT, cy, 16, 4, 4); - TEST_FIELD(CREATESTRUCTA, INT, cx, 20, 4, 4); - TEST_FIELD(CREATESTRUCTA, INT, y, 24, 4, 4); - TEST_FIELD(CREATESTRUCTA, INT, x, 28, 4, 4); - TEST_FIELD(CREATESTRUCTA, LONG, style, 32, 4, 4); - TEST_FIELD(CREATESTRUCTA, LPCSTR, lpszName, 36, 4, 4); - TEST_FIELD(CREATESTRUCTA, LPCSTR, lpszClass, 40, 4, 4); - TEST_FIELD(CREATESTRUCTA, DWORD, dwExStyle, 44, 4, 4); + TEST_TYPE_SIZE (CREATESTRUCTA, 48) + TEST_TYPE_ALIGN (CREATESTRUCTA, 4) + TEST_FIELD_SIZE (CREATESTRUCTA, lpCreateParams, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, lpCreateParams, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, lpCreateParams, 0) + TEST_FIELD_SIZE (CREATESTRUCTA, hInstance, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, hInstance, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, hInstance, 4) + TEST_FIELD_SIZE (CREATESTRUCTA, hMenu, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, hMenu, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, hMenu, 8) + TEST_FIELD_SIZE (CREATESTRUCTA, hwndParent, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, hwndParent, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, hwndParent, 12) + TEST_FIELD_SIZE (CREATESTRUCTA, cy, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, cy, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, cy, 16) + TEST_FIELD_SIZE (CREATESTRUCTA, cx, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, cx, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, cx, 20) + TEST_FIELD_SIZE (CREATESTRUCTA, y, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, y, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, y, 24) + TEST_FIELD_SIZE (CREATESTRUCTA, x, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, x, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, x, 28) + TEST_FIELD_SIZE (CREATESTRUCTA, style, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, style, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, style, 32) + TEST_FIELD_SIZE (CREATESTRUCTA, lpszName, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, lpszName, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, lpszName, 36) + TEST_FIELD_SIZE (CREATESTRUCTA, lpszClass, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, lpszClass, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, lpszClass, 40) + TEST_FIELD_SIZE (CREATESTRUCTA, dwExStyle, 4) + TEST_FIELD_ALIGN (CREATESTRUCTA, dwExStyle, 4) + TEST_FIELD_OFFSET(CREATESTRUCTA, dwExStyle, 44) } static void test_pack_CREATESTRUCTW(void) { /* CREATESTRUCTW (pack 4) */ - TEST_TYPE(CREATESTRUCTW, 48, 4); - TEST_FIELD(CREATESTRUCTW, LPVOID, lpCreateParams, 0, 4, 4); - TEST_FIELD(CREATESTRUCTW, HINSTANCE, hInstance, 4, 4, 4); - TEST_FIELD(CREATESTRUCTW, HMENU, hMenu, 8, 4, 4); - TEST_FIELD(CREATESTRUCTW, HWND, hwndParent, 12, 4, 4); - TEST_FIELD(CREATESTRUCTW, INT, cy, 16, 4, 4); - TEST_FIELD(CREATESTRUCTW, INT, cx, 20, 4, 4); - TEST_FIELD(CREATESTRUCTW, INT, y, 24, 4, 4); - TEST_FIELD(CREATESTRUCTW, INT, x, 28, 4, 4); - TEST_FIELD(CREATESTRUCTW, LONG, style, 32, 4, 4); - TEST_FIELD(CREATESTRUCTW, LPCWSTR, lpszName, 36, 4, 4); - TEST_FIELD(CREATESTRUCTW, LPCWSTR, lpszClass, 40, 4, 4); - TEST_FIELD(CREATESTRUCTW, DWORD, dwExStyle, 44, 4, 4); + TEST_TYPE_SIZE (CREATESTRUCTW, 48) + TEST_TYPE_ALIGN (CREATESTRUCTW, 4) + TEST_FIELD_SIZE (CREATESTRUCTW, lpCreateParams, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, lpCreateParams, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, lpCreateParams, 0) + TEST_FIELD_SIZE (CREATESTRUCTW, hInstance, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, hInstance, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, hInstance, 4) + TEST_FIELD_SIZE (CREATESTRUCTW, hMenu, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, hMenu, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, hMenu, 8) + TEST_FIELD_SIZE (CREATESTRUCTW, hwndParent, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, hwndParent, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, hwndParent, 12) + TEST_FIELD_SIZE (CREATESTRUCTW, cy, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, cy, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, cy, 16) + TEST_FIELD_SIZE (CREATESTRUCTW, cx, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, cx, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, cx, 20) + TEST_FIELD_SIZE (CREATESTRUCTW, y, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, y, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, y, 24) + TEST_FIELD_SIZE (CREATESTRUCTW, x, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, x, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, x, 28) + TEST_FIELD_SIZE (CREATESTRUCTW, style, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, style, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, style, 32) + TEST_FIELD_SIZE (CREATESTRUCTW, lpszName, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, lpszName, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, lpszName, 36) + TEST_FIELD_SIZE (CREATESTRUCTW, lpszClass, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, lpszClass, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, lpszClass, 40) + TEST_FIELD_SIZE (CREATESTRUCTW, dwExStyle, 4) + TEST_FIELD_ALIGN (CREATESTRUCTW, dwExStyle, 4) + TEST_FIELD_OFFSET(CREATESTRUCTW, dwExStyle, 44) } static void test_pack_CURSORINFO(void) { /* CURSORINFO (pack 4) */ - TEST_TYPE(CURSORINFO, 20, 4); - TEST_FIELD(CURSORINFO, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(CURSORINFO, DWORD, flags, 4, 4, 4); - TEST_FIELD(CURSORINFO, HCURSOR, hCursor, 8, 4, 4); - TEST_FIELD(CURSORINFO, POINT, ptScreenPos, 12, 8, 4); + TEST_TYPE_SIZE (CURSORINFO, 20) + TEST_TYPE_ALIGN (CURSORINFO, 4) + TEST_FIELD_SIZE (CURSORINFO, cbSize, 4) + TEST_FIELD_ALIGN (CURSORINFO, cbSize, 4) + TEST_FIELD_OFFSET(CURSORINFO, cbSize, 0) + TEST_FIELD_SIZE (CURSORINFO, flags, 4) + TEST_FIELD_ALIGN (CURSORINFO, flags, 4) + TEST_FIELD_OFFSET(CURSORINFO, flags, 4) + TEST_FIELD_SIZE (CURSORINFO, hCursor, 4) + TEST_FIELD_ALIGN (CURSORINFO, hCursor, 4) + TEST_FIELD_OFFSET(CURSORINFO, hCursor, 8) + TEST_FIELD_SIZE (CURSORINFO, ptScreenPos, 8) + TEST_FIELD_ALIGN (CURSORINFO, ptScreenPos, 4) + TEST_FIELD_OFFSET(CURSORINFO, ptScreenPos, 12) } static void test_pack_CWPRETSTRUCT(void) { /* CWPRETSTRUCT (pack 4) */ - TEST_TYPE(CWPRETSTRUCT, 20, 4); - TEST_FIELD(CWPRETSTRUCT, LRESULT, lResult, 0, 4, 4); - TEST_FIELD(CWPRETSTRUCT, LPARAM, lParam, 4, 4, 4); - TEST_FIELD(CWPRETSTRUCT, WPARAM, wParam, 8, 4, 4); - TEST_FIELD(CWPRETSTRUCT, DWORD, message, 12, 4, 4); - TEST_FIELD(CWPRETSTRUCT, HWND, hwnd, 16, 4, 4); + TEST_TYPE_SIZE (CWPRETSTRUCT, 20) + TEST_TYPE_ALIGN (CWPRETSTRUCT, 4) + TEST_FIELD_SIZE (CWPRETSTRUCT, lResult, 4) + TEST_FIELD_ALIGN (CWPRETSTRUCT, lResult, 4) + TEST_FIELD_OFFSET(CWPRETSTRUCT, lResult, 0) + TEST_FIELD_SIZE (CWPRETSTRUCT, lParam, 4) + TEST_FIELD_ALIGN (CWPRETSTRUCT, lParam, 4) + TEST_FIELD_OFFSET(CWPRETSTRUCT, lParam, 4) + TEST_FIELD_SIZE (CWPRETSTRUCT, wParam, 4) + TEST_FIELD_ALIGN (CWPRETSTRUCT, wParam, 4) + TEST_FIELD_OFFSET(CWPRETSTRUCT, wParam, 8) + TEST_FIELD_SIZE (CWPRETSTRUCT, message, 4) + TEST_FIELD_ALIGN (CWPRETSTRUCT, message, 4) + TEST_FIELD_OFFSET(CWPRETSTRUCT, message, 12) + TEST_FIELD_SIZE (CWPRETSTRUCT, hwnd, 4) + TEST_FIELD_ALIGN (CWPRETSTRUCT, hwnd, 4) + TEST_FIELD_OFFSET(CWPRETSTRUCT, hwnd, 16) } static void test_pack_CWPSTRUCT(void) { /* CWPSTRUCT (pack 4) */ - TEST_TYPE(CWPSTRUCT, 16, 4); - TEST_FIELD(CWPSTRUCT, LPARAM, lParam, 0, 4, 4); - TEST_FIELD(CWPSTRUCT, WPARAM, wParam, 4, 4, 4); - TEST_FIELD(CWPSTRUCT, UINT, message, 8, 4, 4); - TEST_FIELD(CWPSTRUCT, HWND, hwnd, 12, 4, 4); + TEST_TYPE_SIZE (CWPSTRUCT, 16) + TEST_TYPE_ALIGN (CWPSTRUCT, 4) + TEST_FIELD_SIZE (CWPSTRUCT, lParam, 4) + TEST_FIELD_ALIGN (CWPSTRUCT, lParam, 4) + TEST_FIELD_OFFSET(CWPSTRUCT, lParam, 0) + TEST_FIELD_SIZE (CWPSTRUCT, wParam, 4) + TEST_FIELD_ALIGN (CWPSTRUCT, wParam, 4) + TEST_FIELD_OFFSET(CWPSTRUCT, wParam, 4) + TEST_FIELD_SIZE (CWPSTRUCT, message, 4) + TEST_FIELD_ALIGN (CWPSTRUCT, message, 4) + TEST_FIELD_OFFSET(CWPSTRUCT, message, 8) + TEST_FIELD_SIZE (CWPSTRUCT, hwnd, 4) + TEST_FIELD_ALIGN (CWPSTRUCT, hwnd, 4) + TEST_FIELD_OFFSET(CWPSTRUCT, hwnd, 12) } static void test_pack_DEBUGHOOKINFO(void) { /* DEBUGHOOKINFO (pack 4) */ - TEST_TYPE(DEBUGHOOKINFO, 20, 4); - TEST_FIELD(DEBUGHOOKINFO, DWORD, idThread, 0, 4, 4); - TEST_FIELD(DEBUGHOOKINFO, DWORD, idThreadInstaller, 4, 4, 4); - TEST_FIELD(DEBUGHOOKINFO, LPARAM, lParam, 8, 4, 4); - TEST_FIELD(DEBUGHOOKINFO, WPARAM, wParam, 12, 4, 4); - TEST_FIELD(DEBUGHOOKINFO, INT, code, 16, 4, 4); + TEST_TYPE_SIZE (DEBUGHOOKINFO, 20) + TEST_TYPE_ALIGN (DEBUGHOOKINFO, 4) + TEST_FIELD_SIZE (DEBUGHOOKINFO, idThread, 4) + TEST_FIELD_ALIGN (DEBUGHOOKINFO, idThread, 4) + TEST_FIELD_OFFSET(DEBUGHOOKINFO, idThread, 0) + TEST_FIELD_SIZE (DEBUGHOOKINFO, idThreadInstaller, 4) + TEST_FIELD_ALIGN (DEBUGHOOKINFO, idThreadInstaller, 4) + TEST_FIELD_OFFSET(DEBUGHOOKINFO, idThreadInstaller, 4) + TEST_FIELD_SIZE (DEBUGHOOKINFO, lParam, 4) + TEST_FIELD_ALIGN (DEBUGHOOKINFO, lParam, 4) + TEST_FIELD_OFFSET(DEBUGHOOKINFO, lParam, 8) + TEST_FIELD_SIZE (DEBUGHOOKINFO, wParam, 4) + TEST_FIELD_ALIGN (DEBUGHOOKINFO, wParam, 4) + TEST_FIELD_OFFSET(DEBUGHOOKINFO, wParam, 12) + TEST_FIELD_SIZE (DEBUGHOOKINFO, code, 4) + TEST_FIELD_ALIGN (DEBUGHOOKINFO, code, 4) + TEST_FIELD_OFFSET(DEBUGHOOKINFO, code, 16) } static void test_pack_DELETEITEMSTRUCT(void) { /* DELETEITEMSTRUCT (pack 4) */ - TEST_TYPE(DELETEITEMSTRUCT, 20, 4); - TEST_FIELD(DELETEITEMSTRUCT, UINT, CtlType, 0, 4, 4); - TEST_FIELD(DELETEITEMSTRUCT, UINT, CtlID, 4, 4, 4); - TEST_FIELD(DELETEITEMSTRUCT, UINT, itemID, 8, 4, 4); - TEST_FIELD(DELETEITEMSTRUCT, HWND, hwndItem, 12, 4, 4); - TEST_FIELD(DELETEITEMSTRUCT, ULONG_PTR, itemData, 16, 4, 4); + TEST_TYPE_SIZE (DELETEITEMSTRUCT, 20) + TEST_TYPE_ALIGN (DELETEITEMSTRUCT, 4) + TEST_FIELD_SIZE (DELETEITEMSTRUCT, CtlType, 4) + TEST_FIELD_ALIGN (DELETEITEMSTRUCT, CtlType, 4) + TEST_FIELD_OFFSET(DELETEITEMSTRUCT, CtlType, 0) + TEST_FIELD_SIZE (DELETEITEMSTRUCT, CtlID, 4) + TEST_FIELD_ALIGN (DELETEITEMSTRUCT, CtlID, 4) + TEST_FIELD_OFFSET(DELETEITEMSTRUCT, CtlID, 4) + TEST_FIELD_SIZE (DELETEITEMSTRUCT, itemID, 4) + TEST_FIELD_ALIGN (DELETEITEMSTRUCT, itemID, 4) + TEST_FIELD_OFFSET(DELETEITEMSTRUCT, itemID, 8) + TEST_FIELD_SIZE (DELETEITEMSTRUCT, hwndItem, 4) + TEST_FIELD_ALIGN (DELETEITEMSTRUCT, hwndItem, 4) + TEST_FIELD_OFFSET(DELETEITEMSTRUCT, hwndItem, 12) + TEST_FIELD_SIZE (DELETEITEMSTRUCT, itemData, 4) + TEST_FIELD_ALIGN (DELETEITEMSTRUCT, itemData, 4) + TEST_FIELD_OFFSET(DELETEITEMSTRUCT, itemData, 16) } static void test_pack_DESKTOPENUMPROCA(void) { /* DESKTOPENUMPROCA */ - TEST_TYPE(DESKTOPENUMPROCA, 4, 4); + TEST_TYPE_SIZE (DESKTOPENUMPROCA, 4) + TEST_TYPE_ALIGN (DESKTOPENUMPROCA, 4) } static void test_pack_DESKTOPENUMPROCW(void) { /* DESKTOPENUMPROCW */ - TEST_TYPE(DESKTOPENUMPROCW, 4, 4); + TEST_TYPE_SIZE (DESKTOPENUMPROCW, 4) + TEST_TYPE_ALIGN (DESKTOPENUMPROCW, 4) } static void test_pack_DLGITEMTEMPLATE(void) { /* DLGITEMTEMPLATE (pack 2) */ - TEST_TYPE(DLGITEMTEMPLATE, 18, 2); - TEST_FIELD(DLGITEMTEMPLATE, DWORD, style, 0, 4, 2); - TEST_FIELD(DLGITEMTEMPLATE, DWORD, dwExtendedStyle, 4, 4, 2); - TEST_FIELD(DLGITEMTEMPLATE, short, x, 8, 2, 2); - TEST_FIELD(DLGITEMTEMPLATE, short, y, 10, 2, 2); - TEST_FIELD(DLGITEMTEMPLATE, short, cx, 12, 2, 2); - TEST_FIELD(DLGITEMTEMPLATE, short, cy, 14, 2, 2); - TEST_FIELD(DLGITEMTEMPLATE, WORD, id, 16, 2, 2); + TEST_TYPE_SIZE (DLGITEMTEMPLATE, 18) + TEST_TYPE_ALIGN (DLGITEMTEMPLATE, 2) + TEST_FIELD_SIZE (DLGITEMTEMPLATE, style, 4) + TEST_FIELD_ALIGN (DLGITEMTEMPLATE, style, 2) + TEST_FIELD_OFFSET(DLGITEMTEMPLATE, style, 0) + TEST_FIELD_SIZE (DLGITEMTEMPLATE, dwExtendedStyle, 4) + TEST_FIELD_ALIGN (DLGITEMTEMPLATE, dwExtendedStyle, 2) + TEST_FIELD_OFFSET(DLGITEMTEMPLATE, dwExtendedStyle, 4) + TEST_FIELD_SIZE (DLGITEMTEMPLATE, x, 2) + TEST_FIELD_ALIGN (DLGITEMTEMPLATE, x, 2) + TEST_FIELD_OFFSET(DLGITEMTEMPLATE, x, 8) + TEST_FIELD_SIZE (DLGITEMTEMPLATE, y, 2) + TEST_FIELD_ALIGN (DLGITEMTEMPLATE, y, 2) + TEST_FIELD_OFFSET(DLGITEMTEMPLATE, y, 10) + TEST_FIELD_SIZE (DLGITEMTEMPLATE, cx, 2) + TEST_FIELD_ALIGN (DLGITEMTEMPLATE, cx, 2) + TEST_FIELD_OFFSET(DLGITEMTEMPLATE, cx, 12) + TEST_FIELD_SIZE (DLGITEMTEMPLATE, cy, 2) + TEST_FIELD_ALIGN (DLGITEMTEMPLATE, cy, 2) + TEST_FIELD_OFFSET(DLGITEMTEMPLATE, cy, 14) + TEST_FIELD_SIZE (DLGITEMTEMPLATE, id, 2) + TEST_FIELD_ALIGN (DLGITEMTEMPLATE, id, 2) + TEST_FIELD_OFFSET(DLGITEMTEMPLATE, id, 16) } static void test_pack_DLGPROC(void) { /* DLGPROC */ - TEST_TYPE(DLGPROC, 4, 4); + TEST_TYPE_SIZE (DLGPROC, 4) + TEST_TYPE_ALIGN (DLGPROC, 4) } static void test_pack_DLGTEMPLATE(void) { /* DLGTEMPLATE (pack 2) */ - TEST_TYPE(DLGTEMPLATE, 18, 2); - TEST_FIELD(DLGTEMPLATE, DWORD, style, 0, 4, 2); - TEST_FIELD(DLGTEMPLATE, DWORD, dwExtendedStyle, 4, 4, 2); - TEST_FIELD(DLGTEMPLATE, WORD, cdit, 8, 2, 2); - TEST_FIELD(DLGTEMPLATE, short, x, 10, 2, 2); - TEST_FIELD(DLGTEMPLATE, short, y, 12, 2, 2); - TEST_FIELD(DLGTEMPLATE, short, cx, 14, 2, 2); - TEST_FIELD(DLGTEMPLATE, short, cy, 16, 2, 2); + TEST_TYPE_SIZE (DLGTEMPLATE, 18) + TEST_TYPE_ALIGN (DLGTEMPLATE, 2) + TEST_FIELD_SIZE (DLGTEMPLATE, style, 4) + TEST_FIELD_ALIGN (DLGTEMPLATE, style, 2) + TEST_FIELD_OFFSET(DLGTEMPLATE, style, 0) + TEST_FIELD_SIZE (DLGTEMPLATE, dwExtendedStyle, 4) + TEST_FIELD_ALIGN (DLGTEMPLATE, dwExtendedStyle, 2) + TEST_FIELD_OFFSET(DLGTEMPLATE, dwExtendedStyle, 4) + TEST_FIELD_SIZE (DLGTEMPLATE, cdit, 2) + TEST_FIELD_ALIGN (DLGTEMPLATE, cdit, 2) + TEST_FIELD_OFFSET(DLGTEMPLATE, cdit, 8) + TEST_FIELD_SIZE (DLGTEMPLATE, x, 2) + TEST_FIELD_ALIGN (DLGTEMPLATE, x, 2) + TEST_FIELD_OFFSET(DLGTEMPLATE, x, 10) + TEST_FIELD_SIZE (DLGTEMPLATE, y, 2) + TEST_FIELD_ALIGN (DLGTEMPLATE, y, 2) + TEST_FIELD_OFFSET(DLGTEMPLATE, y, 12) + TEST_FIELD_SIZE (DLGTEMPLATE, cx, 2) + TEST_FIELD_ALIGN (DLGTEMPLATE, cx, 2) + TEST_FIELD_OFFSET(DLGTEMPLATE, cx, 14) + TEST_FIELD_SIZE (DLGTEMPLATE, cy, 2) + TEST_FIELD_ALIGN (DLGTEMPLATE, cy, 2) + TEST_FIELD_OFFSET(DLGTEMPLATE, cy, 16) } static void test_pack_DRAWITEMSTRUCT(void) { /* DRAWITEMSTRUCT (pack 4) */ - TEST_TYPE(DRAWITEMSTRUCT, 48, 4); - TEST_FIELD(DRAWITEMSTRUCT, UINT, CtlType, 0, 4, 4); - TEST_FIELD(DRAWITEMSTRUCT, UINT, CtlID, 4, 4, 4); - TEST_FIELD(DRAWITEMSTRUCT, UINT, itemID, 8, 4, 4); - TEST_FIELD(DRAWITEMSTRUCT, UINT, itemAction, 12, 4, 4); - TEST_FIELD(DRAWITEMSTRUCT, UINT, itemState, 16, 4, 4); - TEST_FIELD(DRAWITEMSTRUCT, HWND, hwndItem, 20, 4, 4); - TEST_FIELD(DRAWITEMSTRUCT, HDC, hDC, 24, 4, 4); - TEST_FIELD(DRAWITEMSTRUCT, RECT, rcItem, 28, 16, 4); - TEST_FIELD(DRAWITEMSTRUCT, ULONG_PTR, itemData, 44, 4, 4); + TEST_TYPE_SIZE (DRAWITEMSTRUCT, 48) + TEST_TYPE_ALIGN (DRAWITEMSTRUCT, 4) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, CtlType, 4) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, CtlType, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, CtlType, 0) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, CtlID, 4) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, CtlID, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, CtlID, 4) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, itemID, 4) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, itemID, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, itemID, 8) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, itemAction, 4) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, itemAction, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, itemAction, 12) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, itemState, 4) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, itemState, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, itemState, 16) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, hwndItem, 4) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, hwndItem, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, hwndItem, 20) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, hDC, 4) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, hDC, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, hDC, 24) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, rcItem, 16) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, rcItem, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, rcItem, 28) + TEST_FIELD_SIZE (DRAWITEMSTRUCT, itemData, 4) + TEST_FIELD_ALIGN (DRAWITEMSTRUCT, itemData, 4) + TEST_FIELD_OFFSET(DRAWITEMSTRUCT, itemData, 44) } static void test_pack_DRAWSTATEPROC(void) { /* DRAWSTATEPROC */ - TEST_TYPE(DRAWSTATEPROC, 4, 4); + TEST_TYPE_SIZE (DRAWSTATEPROC, 4) + TEST_TYPE_ALIGN (DRAWSTATEPROC, 4) } static void test_pack_DRAWTEXTPARAMS(void) { /* DRAWTEXTPARAMS (pack 4) */ - TEST_TYPE(DRAWTEXTPARAMS, 20, 4); - TEST_FIELD(DRAWTEXTPARAMS, UINT, cbSize, 0, 4, 4); - TEST_FIELD(DRAWTEXTPARAMS, INT, iTabLength, 4, 4, 4); - TEST_FIELD(DRAWTEXTPARAMS, INT, iLeftMargin, 8, 4, 4); - TEST_FIELD(DRAWTEXTPARAMS, INT, iRightMargin, 12, 4, 4); - TEST_FIELD(DRAWTEXTPARAMS, UINT, uiLengthDrawn, 16, 4, 4); + TEST_TYPE_SIZE (DRAWTEXTPARAMS, 20) + TEST_TYPE_ALIGN (DRAWTEXTPARAMS, 4) + TEST_FIELD_SIZE (DRAWTEXTPARAMS, cbSize, 4) + TEST_FIELD_ALIGN (DRAWTEXTPARAMS, cbSize, 4) + TEST_FIELD_OFFSET(DRAWTEXTPARAMS, cbSize, 0) + TEST_FIELD_SIZE (DRAWTEXTPARAMS, iTabLength, 4) + TEST_FIELD_ALIGN (DRAWTEXTPARAMS, iTabLength, 4) + TEST_FIELD_OFFSET(DRAWTEXTPARAMS, iTabLength, 4) + TEST_FIELD_SIZE (DRAWTEXTPARAMS, iLeftMargin, 4) + TEST_FIELD_ALIGN (DRAWTEXTPARAMS, iLeftMargin, 4) + TEST_FIELD_OFFSET(DRAWTEXTPARAMS, iLeftMargin, 8) + TEST_FIELD_SIZE (DRAWTEXTPARAMS, iRightMargin, 4) + TEST_FIELD_ALIGN (DRAWTEXTPARAMS, iRightMargin, 4) + TEST_FIELD_OFFSET(DRAWTEXTPARAMS, iRightMargin, 12) + TEST_FIELD_SIZE (DRAWTEXTPARAMS, uiLengthDrawn, 4) + TEST_FIELD_ALIGN (DRAWTEXTPARAMS, uiLengthDrawn, 4) + TEST_FIELD_OFFSET(DRAWTEXTPARAMS, uiLengthDrawn, 16) } static void test_pack_EDITWORDBREAKPROCA(void) { /* EDITWORDBREAKPROCA */ - TEST_TYPE(EDITWORDBREAKPROCA, 4, 4); + TEST_TYPE_SIZE (EDITWORDBREAKPROCA, 4) + TEST_TYPE_ALIGN (EDITWORDBREAKPROCA, 4) } static void test_pack_EDITWORDBREAKPROCW(void) { /* EDITWORDBREAKPROCW */ - TEST_TYPE(EDITWORDBREAKPROCW, 4, 4); + TEST_TYPE_SIZE (EDITWORDBREAKPROCW, 4) + TEST_TYPE_ALIGN (EDITWORDBREAKPROCW, 4) } static void test_pack_EVENTMSG(void) { /* EVENTMSG (pack 4) */ - TEST_TYPE(EVENTMSG, 20, 4); - TEST_FIELD(EVENTMSG, UINT, message, 0, 4, 4); - TEST_FIELD(EVENTMSG, UINT, paramL, 4, 4, 4); - TEST_FIELD(EVENTMSG, UINT, paramH, 8, 4, 4); - TEST_FIELD(EVENTMSG, DWORD, time, 12, 4, 4); - TEST_FIELD(EVENTMSG, HWND, hwnd, 16, 4, 4); + TEST_TYPE_SIZE (EVENTMSG, 20) + TEST_TYPE_ALIGN (EVENTMSG, 4) + TEST_FIELD_SIZE (EVENTMSG, message, 4) + TEST_FIELD_ALIGN (EVENTMSG, message, 4) + TEST_FIELD_OFFSET(EVENTMSG, message, 0) + TEST_FIELD_SIZE (EVENTMSG, paramL, 4) + TEST_FIELD_ALIGN (EVENTMSG, paramL, 4) + TEST_FIELD_OFFSET(EVENTMSG, paramL, 4) + TEST_FIELD_SIZE (EVENTMSG, paramH, 4) + TEST_FIELD_ALIGN (EVENTMSG, paramH, 4) + TEST_FIELD_OFFSET(EVENTMSG, paramH, 8) + TEST_FIELD_SIZE (EVENTMSG, time, 4) + TEST_FIELD_ALIGN (EVENTMSG, time, 4) + TEST_FIELD_OFFSET(EVENTMSG, time, 12) + TEST_FIELD_SIZE (EVENTMSG, hwnd, 4) + TEST_FIELD_ALIGN (EVENTMSG, hwnd, 4) + TEST_FIELD_OFFSET(EVENTMSG, hwnd, 16) } static void test_pack_FILTERKEYS(void) { /* FILTERKEYS (pack 4) */ - TEST_TYPE(FILTERKEYS, 24, 4); - TEST_FIELD(FILTERKEYS, UINT, cbSize, 0, 4, 4); - TEST_FIELD(FILTERKEYS, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(FILTERKEYS, DWORD, iWaitMSec, 8, 4, 4); - TEST_FIELD(FILTERKEYS, DWORD, iDelayMSec, 12, 4, 4); - TEST_FIELD(FILTERKEYS, DWORD, iRepeatMSec, 16, 4, 4); - TEST_FIELD(FILTERKEYS, DWORD, iBounceMSec, 20, 4, 4); + TEST_TYPE_SIZE (FILTERKEYS, 24) + TEST_TYPE_ALIGN (FILTERKEYS, 4) + TEST_FIELD_SIZE (FILTERKEYS, cbSize, 4) + TEST_FIELD_ALIGN (FILTERKEYS, cbSize, 4) + TEST_FIELD_OFFSET(FILTERKEYS, cbSize, 0) + TEST_FIELD_SIZE (FILTERKEYS, dwFlags, 4) + TEST_FIELD_ALIGN (FILTERKEYS, dwFlags, 4) + TEST_FIELD_OFFSET(FILTERKEYS, dwFlags, 4) + TEST_FIELD_SIZE (FILTERKEYS, iWaitMSec, 4) + TEST_FIELD_ALIGN (FILTERKEYS, iWaitMSec, 4) + TEST_FIELD_OFFSET(FILTERKEYS, iWaitMSec, 8) + TEST_FIELD_SIZE (FILTERKEYS, iDelayMSec, 4) + TEST_FIELD_ALIGN (FILTERKEYS, iDelayMSec, 4) + TEST_FIELD_OFFSET(FILTERKEYS, iDelayMSec, 12) + TEST_FIELD_SIZE (FILTERKEYS, iRepeatMSec, 4) + TEST_FIELD_ALIGN (FILTERKEYS, iRepeatMSec, 4) + TEST_FIELD_OFFSET(FILTERKEYS, iRepeatMSec, 16) + TEST_FIELD_SIZE (FILTERKEYS, iBounceMSec, 4) + TEST_FIELD_ALIGN (FILTERKEYS, iBounceMSec, 4) + TEST_FIELD_OFFSET(FILTERKEYS, iBounceMSec, 20) } static void test_pack_FLASHWINFO(void) { /* FLASHWINFO (pack 4) */ - TEST_TYPE(FLASHWINFO, 20, 4); - TEST_FIELD(FLASHWINFO, UINT, cbSize, 0, 4, 4); - TEST_FIELD(FLASHWINFO, HWND, hwnd, 4, 4, 4); - TEST_FIELD(FLASHWINFO, DWORD, dwFlags, 8, 4, 4); - TEST_FIELD(FLASHWINFO, UINT, uCount, 12, 4, 4); - TEST_FIELD(FLASHWINFO, DWORD, dwTimeout, 16, 4, 4); + TEST_TYPE_SIZE (FLASHWINFO, 20) + TEST_TYPE_ALIGN (FLASHWINFO, 4) + TEST_FIELD_SIZE (FLASHWINFO, cbSize, 4) + TEST_FIELD_ALIGN (FLASHWINFO, cbSize, 4) + TEST_FIELD_OFFSET(FLASHWINFO, cbSize, 0) + TEST_FIELD_SIZE (FLASHWINFO, hwnd, 4) + TEST_FIELD_ALIGN (FLASHWINFO, hwnd, 4) + TEST_FIELD_OFFSET(FLASHWINFO, hwnd, 4) + TEST_FIELD_SIZE (FLASHWINFO, dwFlags, 4) + TEST_FIELD_ALIGN (FLASHWINFO, dwFlags, 4) + TEST_FIELD_OFFSET(FLASHWINFO, dwFlags, 8) + TEST_FIELD_SIZE (FLASHWINFO, uCount, 4) + TEST_FIELD_ALIGN (FLASHWINFO, uCount, 4) + TEST_FIELD_OFFSET(FLASHWINFO, uCount, 12) + TEST_FIELD_SIZE (FLASHWINFO, dwTimeout, 4) + TEST_FIELD_ALIGN (FLASHWINFO, dwTimeout, 4) + TEST_FIELD_OFFSET(FLASHWINFO, dwTimeout, 16) } static void test_pack_GRAYSTRINGPROC(void) { /* GRAYSTRINGPROC */ - TEST_TYPE(GRAYSTRINGPROC, 4, 4); + TEST_TYPE_SIZE (GRAYSTRINGPROC, 4) + TEST_TYPE_ALIGN (GRAYSTRINGPROC, 4) } static void test_pack_GUITHREADINFO(void) { /* GUITHREADINFO (pack 4) */ - TEST_TYPE(GUITHREADINFO, 48, 4); - TEST_FIELD(GUITHREADINFO, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(GUITHREADINFO, DWORD, flags, 4, 4, 4); - TEST_FIELD(GUITHREADINFO, HWND, hwndActive, 8, 4, 4); - TEST_FIELD(GUITHREADINFO, HWND, hwndFocus, 12, 4, 4); - TEST_FIELD(GUITHREADINFO, HWND, hwndCapture, 16, 4, 4); - TEST_FIELD(GUITHREADINFO, HWND, hwndMenuOwner, 20, 4, 4); - TEST_FIELD(GUITHREADINFO, HWND, hwndMoveSize, 24, 4, 4); - TEST_FIELD(GUITHREADINFO, HWND, hwndCaret, 28, 4, 4); - TEST_FIELD(GUITHREADINFO, RECT, rcCaret, 32, 16, 4); + TEST_TYPE_SIZE (GUITHREADINFO, 48) + TEST_TYPE_ALIGN (GUITHREADINFO, 4) + TEST_FIELD_SIZE (GUITHREADINFO, cbSize, 4) + TEST_FIELD_ALIGN (GUITHREADINFO, cbSize, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, cbSize, 0) + TEST_FIELD_SIZE (GUITHREADINFO, flags, 4) + TEST_FIELD_ALIGN (GUITHREADINFO, flags, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, flags, 4) + TEST_FIELD_SIZE (GUITHREADINFO, hwndActive, 4) + TEST_FIELD_ALIGN (GUITHREADINFO, hwndActive, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, hwndActive, 8) + TEST_FIELD_SIZE (GUITHREADINFO, hwndFocus, 4) + TEST_FIELD_ALIGN (GUITHREADINFO, hwndFocus, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, hwndFocus, 12) + TEST_FIELD_SIZE (GUITHREADINFO, hwndCapture, 4) + TEST_FIELD_ALIGN (GUITHREADINFO, hwndCapture, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, hwndCapture, 16) + TEST_FIELD_SIZE (GUITHREADINFO, hwndMenuOwner, 4) + TEST_FIELD_ALIGN (GUITHREADINFO, hwndMenuOwner, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, hwndMenuOwner, 20) + TEST_FIELD_SIZE (GUITHREADINFO, hwndMoveSize, 4) + TEST_FIELD_ALIGN (GUITHREADINFO, hwndMoveSize, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, hwndMoveSize, 24) + TEST_FIELD_SIZE (GUITHREADINFO, hwndCaret, 4) + TEST_FIELD_ALIGN (GUITHREADINFO, hwndCaret, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, hwndCaret, 28) + TEST_FIELD_SIZE (GUITHREADINFO, rcCaret, 16) + TEST_FIELD_ALIGN (GUITHREADINFO, rcCaret, 4) + TEST_FIELD_OFFSET(GUITHREADINFO, rcCaret, 32) } static void test_pack_HARDWAREHOOKSTRUCT(void) { /* HARDWAREHOOKSTRUCT (pack 4) */ - TEST_TYPE(HARDWAREHOOKSTRUCT, 16, 4); - TEST_FIELD(HARDWAREHOOKSTRUCT, HWND, hwnd, 0, 4, 4); - TEST_FIELD(HARDWAREHOOKSTRUCT, UINT, message, 4, 4, 4); - TEST_FIELD(HARDWAREHOOKSTRUCT, WPARAM, wParam, 8, 4, 4); - TEST_FIELD(HARDWAREHOOKSTRUCT, LPARAM, lParam, 12, 4, 4); + TEST_TYPE_SIZE (HARDWAREHOOKSTRUCT, 16) + TEST_TYPE_ALIGN (HARDWAREHOOKSTRUCT, 4) + TEST_FIELD_SIZE (HARDWAREHOOKSTRUCT, hwnd, 4) + TEST_FIELD_ALIGN (HARDWAREHOOKSTRUCT, hwnd, 4) + TEST_FIELD_OFFSET(HARDWAREHOOKSTRUCT, hwnd, 0) + TEST_FIELD_SIZE (HARDWAREHOOKSTRUCT, message, 4) + TEST_FIELD_ALIGN (HARDWAREHOOKSTRUCT, message, 4) + TEST_FIELD_OFFSET(HARDWAREHOOKSTRUCT, message, 4) + TEST_FIELD_SIZE (HARDWAREHOOKSTRUCT, wParam, 4) + TEST_FIELD_ALIGN (HARDWAREHOOKSTRUCT, wParam, 4) + TEST_FIELD_OFFSET(HARDWAREHOOKSTRUCT, wParam, 8) + TEST_FIELD_SIZE (HARDWAREHOOKSTRUCT, lParam, 4) + TEST_FIELD_ALIGN (HARDWAREHOOKSTRUCT, lParam, 4) + TEST_FIELD_OFFSET(HARDWAREHOOKSTRUCT, lParam, 12) } static void test_pack_HARDWAREINPUT(void) { /* HARDWAREINPUT (pack 4) */ - TEST_TYPE(HARDWAREINPUT, 8, 4); - TEST_FIELD(HARDWAREINPUT, DWORD, uMsg, 0, 4, 4); - TEST_FIELD(HARDWAREINPUT, WORD, wParamL, 4, 2, 2); - TEST_FIELD(HARDWAREINPUT, WORD, wParamH, 6, 2, 2); + TEST_TYPE_SIZE (HARDWAREINPUT, 8) + TEST_TYPE_ALIGN (HARDWAREINPUT, 4) + TEST_FIELD_SIZE (HARDWAREINPUT, uMsg, 4) + TEST_FIELD_ALIGN (HARDWAREINPUT, uMsg, 4) + TEST_FIELD_OFFSET(HARDWAREINPUT, uMsg, 0) + TEST_FIELD_SIZE (HARDWAREINPUT, wParamL, 2) + TEST_FIELD_ALIGN (HARDWAREINPUT, wParamL, 2) + TEST_FIELD_OFFSET(HARDWAREINPUT, wParamL, 4) + TEST_FIELD_SIZE (HARDWAREINPUT, wParamH, 2) + TEST_FIELD_ALIGN (HARDWAREINPUT, wParamH, 2) + TEST_FIELD_OFFSET(HARDWAREINPUT, wParamH, 6) } static void test_pack_HDEVNOTIFY(void) { /* HDEVNOTIFY */ - TEST_TYPE(HDEVNOTIFY, 4, 4); + TEST_TYPE_SIZE (HDEVNOTIFY, 4) + TEST_TYPE_ALIGN (HDEVNOTIFY, 4) } static void test_pack_HDWP(void) { /* HDWP */ - TEST_TYPE(HDWP, 4, 4); + TEST_TYPE_SIZE (HDWP, 4) + TEST_TYPE_ALIGN (HDWP, 4) } static void test_pack_HELPINFO(void) { /* HELPINFO (pack 4) */ - TEST_TYPE(HELPINFO, 28, 4); - TEST_FIELD(HELPINFO, UINT, cbSize, 0, 4, 4); - TEST_FIELD(HELPINFO, INT, iContextType, 4, 4, 4); - TEST_FIELD(HELPINFO, INT, iCtrlId, 8, 4, 4); - TEST_FIELD(HELPINFO, HANDLE, hItemHandle, 12, 4, 4); - TEST_FIELD(HELPINFO, DWORD_PTR, dwContextId, 16, 4, 4); - TEST_FIELD(HELPINFO, POINT, MousePos, 20, 8, 4); + TEST_TYPE_SIZE (HELPINFO, 28) + TEST_TYPE_ALIGN (HELPINFO, 4) + TEST_FIELD_SIZE (HELPINFO, cbSize, 4) + TEST_FIELD_ALIGN (HELPINFO, cbSize, 4) + TEST_FIELD_OFFSET(HELPINFO, cbSize, 0) + TEST_FIELD_SIZE (HELPINFO, iContextType, 4) + TEST_FIELD_ALIGN (HELPINFO, iContextType, 4) + TEST_FIELD_OFFSET(HELPINFO, iContextType, 4) + TEST_FIELD_SIZE (HELPINFO, iCtrlId, 4) + TEST_FIELD_ALIGN (HELPINFO, iCtrlId, 4) + TEST_FIELD_OFFSET(HELPINFO, iCtrlId, 8) + TEST_FIELD_SIZE (HELPINFO, hItemHandle, 4) + TEST_FIELD_ALIGN (HELPINFO, hItemHandle, 4) + TEST_FIELD_OFFSET(HELPINFO, hItemHandle, 12) + TEST_FIELD_SIZE (HELPINFO, dwContextId, 4) + TEST_FIELD_ALIGN (HELPINFO, dwContextId, 4) + TEST_FIELD_OFFSET(HELPINFO, dwContextId, 16) + TEST_FIELD_SIZE (HELPINFO, MousePos, 8) + TEST_FIELD_ALIGN (HELPINFO, MousePos, 4) + TEST_FIELD_OFFSET(HELPINFO, MousePos, 20) } static void test_pack_HELPWININFOA(void) { /* HELPWININFOA (pack 4) */ - TEST_TYPE(HELPWININFOA, 28, 4); - TEST_FIELD(HELPWININFOA, int, wStructSize, 0, 4, 4); - TEST_FIELD(HELPWININFOA, int, x, 4, 4, 4); - TEST_FIELD(HELPWININFOA, int, y, 8, 4, 4); - TEST_FIELD(HELPWININFOA, int, dx, 12, 4, 4); - TEST_FIELD(HELPWININFOA, int, dy, 16, 4, 4); - TEST_FIELD(HELPWININFOA, int, wMax, 20, 4, 4); - TEST_FIELD(HELPWININFOA, CHAR[2], rgchMember, 24, 2, 1); + TEST_TYPE_SIZE (HELPWININFOA, 28) + TEST_TYPE_ALIGN (HELPWININFOA, 4) + TEST_FIELD_SIZE (HELPWININFOA, wStructSize, 4) + TEST_FIELD_ALIGN (HELPWININFOA, wStructSize, 4) + TEST_FIELD_OFFSET(HELPWININFOA, wStructSize, 0) + TEST_FIELD_SIZE (HELPWININFOA, x, 4) + TEST_FIELD_ALIGN (HELPWININFOA, x, 4) + TEST_FIELD_OFFSET(HELPWININFOA, x, 4) + TEST_FIELD_SIZE (HELPWININFOA, y, 4) + TEST_FIELD_ALIGN (HELPWININFOA, y, 4) + TEST_FIELD_OFFSET(HELPWININFOA, y, 8) + TEST_FIELD_SIZE (HELPWININFOA, dx, 4) + TEST_FIELD_ALIGN (HELPWININFOA, dx, 4) + TEST_FIELD_OFFSET(HELPWININFOA, dx, 12) + TEST_FIELD_SIZE (HELPWININFOA, dy, 4) + TEST_FIELD_ALIGN (HELPWININFOA, dy, 4) + TEST_FIELD_OFFSET(HELPWININFOA, dy, 16) + TEST_FIELD_SIZE (HELPWININFOA, wMax, 4) + TEST_FIELD_ALIGN (HELPWININFOA, wMax, 4) + TEST_FIELD_OFFSET(HELPWININFOA, wMax, 20) + TEST_FIELD_SIZE (HELPWININFOA, rgchMember, 2) + TEST_FIELD_ALIGN (HELPWININFOA, rgchMember, 1) + TEST_FIELD_OFFSET(HELPWININFOA, rgchMember, 24) } static void test_pack_HELPWININFOW(void) { /* HELPWININFOW (pack 4) */ - TEST_TYPE(HELPWININFOW, 28, 4); - TEST_FIELD(HELPWININFOW, int, wStructSize, 0, 4, 4); - TEST_FIELD(HELPWININFOW, int, x, 4, 4, 4); - TEST_FIELD(HELPWININFOW, int, y, 8, 4, 4); - TEST_FIELD(HELPWININFOW, int, dx, 12, 4, 4); - TEST_FIELD(HELPWININFOW, int, dy, 16, 4, 4); - TEST_FIELD(HELPWININFOW, int, wMax, 20, 4, 4); - TEST_FIELD(HELPWININFOW, WCHAR[2], rgchMember, 24, 4, 2); + TEST_TYPE_SIZE (HELPWININFOW, 28) + TEST_TYPE_ALIGN (HELPWININFOW, 4) + TEST_FIELD_SIZE (HELPWININFOW, wStructSize, 4) + TEST_FIELD_ALIGN (HELPWININFOW, wStructSize, 4) + TEST_FIELD_OFFSET(HELPWININFOW, wStructSize, 0) + TEST_FIELD_SIZE (HELPWININFOW, x, 4) + TEST_FIELD_ALIGN (HELPWININFOW, x, 4) + TEST_FIELD_OFFSET(HELPWININFOW, x, 4) + TEST_FIELD_SIZE (HELPWININFOW, y, 4) + TEST_FIELD_ALIGN (HELPWININFOW, y, 4) + TEST_FIELD_OFFSET(HELPWININFOW, y, 8) + TEST_FIELD_SIZE (HELPWININFOW, dx, 4) + TEST_FIELD_ALIGN (HELPWININFOW, dx, 4) + TEST_FIELD_OFFSET(HELPWININFOW, dx, 12) + TEST_FIELD_SIZE (HELPWININFOW, dy, 4) + TEST_FIELD_ALIGN (HELPWININFOW, dy, 4) + TEST_FIELD_OFFSET(HELPWININFOW, dy, 16) + TEST_FIELD_SIZE (HELPWININFOW, wMax, 4) + TEST_FIELD_ALIGN (HELPWININFOW, wMax, 4) + TEST_FIELD_OFFSET(HELPWININFOW, wMax, 20) + TEST_FIELD_SIZE (HELPWININFOW, rgchMember, 4) + TEST_FIELD_ALIGN (HELPWININFOW, rgchMember, 2) + TEST_FIELD_OFFSET(HELPWININFOW, rgchMember, 24) } static void test_pack_HIGHCONTRASTA(void) { /* HIGHCONTRASTA (pack 4) */ - TEST_TYPE(HIGHCONTRASTA, 12, 4); - TEST_FIELD(HIGHCONTRASTA, UINT, cbSize, 0, 4, 4); - TEST_FIELD(HIGHCONTRASTA, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(HIGHCONTRASTA, LPSTR, lpszDefaultScheme, 8, 4, 4); + TEST_TYPE_SIZE (HIGHCONTRASTA, 12) + TEST_TYPE_ALIGN (HIGHCONTRASTA, 4) + TEST_FIELD_SIZE (HIGHCONTRASTA, cbSize, 4) + TEST_FIELD_ALIGN (HIGHCONTRASTA, cbSize, 4) + TEST_FIELD_OFFSET(HIGHCONTRASTA, cbSize, 0) + TEST_FIELD_SIZE (HIGHCONTRASTA, dwFlags, 4) + TEST_FIELD_ALIGN (HIGHCONTRASTA, dwFlags, 4) + TEST_FIELD_OFFSET(HIGHCONTRASTA, dwFlags, 4) + TEST_FIELD_SIZE (HIGHCONTRASTA, lpszDefaultScheme, 4) + TEST_FIELD_ALIGN (HIGHCONTRASTA, lpszDefaultScheme, 4) + TEST_FIELD_OFFSET(HIGHCONTRASTA, lpszDefaultScheme, 8) } static void test_pack_HIGHCONTRASTW(void) { /* HIGHCONTRASTW (pack 4) */ - TEST_TYPE(HIGHCONTRASTW, 12, 4); - TEST_FIELD(HIGHCONTRASTW, UINT, cbSize, 0, 4, 4); - TEST_FIELD(HIGHCONTRASTW, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(HIGHCONTRASTW, LPWSTR, lpszDefaultScheme, 8, 4, 4); + TEST_TYPE_SIZE (HIGHCONTRASTW, 12) + TEST_TYPE_ALIGN (HIGHCONTRASTW, 4) + TEST_FIELD_SIZE (HIGHCONTRASTW, cbSize, 4) + TEST_FIELD_ALIGN (HIGHCONTRASTW, cbSize, 4) + TEST_FIELD_OFFSET(HIGHCONTRASTW, cbSize, 0) + TEST_FIELD_SIZE (HIGHCONTRASTW, dwFlags, 4) + TEST_FIELD_ALIGN (HIGHCONTRASTW, dwFlags, 4) + TEST_FIELD_OFFSET(HIGHCONTRASTW, dwFlags, 4) + TEST_FIELD_SIZE (HIGHCONTRASTW, lpszDefaultScheme, 4) + TEST_FIELD_ALIGN (HIGHCONTRASTW, lpszDefaultScheme, 4) + TEST_FIELD_OFFSET(HIGHCONTRASTW, lpszDefaultScheme, 8) } static void test_pack_HOOKPROC(void) { /* HOOKPROC */ - TEST_TYPE(HOOKPROC, 4, 4); + TEST_TYPE_SIZE (HOOKPROC, 4) + TEST_TYPE_ALIGN (HOOKPROC, 4) } static void test_pack_ICONINFO(void) { /* ICONINFO (pack 4) */ - TEST_TYPE(ICONINFO, 20, 4); - TEST_FIELD(ICONINFO, BOOL, fIcon, 0, 4, 4); - TEST_FIELD(ICONINFO, DWORD, xHotspot, 4, 4, 4); - TEST_FIELD(ICONINFO, DWORD, yHotspot, 8, 4, 4); - TEST_FIELD(ICONINFO, HBITMAP, hbmMask, 12, 4, 4); - TEST_FIELD(ICONINFO, HBITMAP, hbmColor, 16, 4, 4); + TEST_TYPE_SIZE (ICONINFO, 20) + TEST_TYPE_ALIGN (ICONINFO, 4) + TEST_FIELD_SIZE (ICONINFO, fIcon, 4) + TEST_FIELD_ALIGN (ICONINFO, fIcon, 4) + TEST_FIELD_OFFSET(ICONINFO, fIcon, 0) + TEST_FIELD_SIZE (ICONINFO, xHotspot, 4) + TEST_FIELD_ALIGN (ICONINFO, xHotspot, 4) + TEST_FIELD_OFFSET(ICONINFO, xHotspot, 4) + TEST_FIELD_SIZE (ICONINFO, yHotspot, 4) + TEST_FIELD_ALIGN (ICONINFO, yHotspot, 4) + TEST_FIELD_OFFSET(ICONINFO, yHotspot, 8) + TEST_FIELD_SIZE (ICONINFO, hbmMask, 4) + TEST_FIELD_ALIGN (ICONINFO, hbmMask, 4) + TEST_FIELD_OFFSET(ICONINFO, hbmMask, 12) + TEST_FIELD_SIZE (ICONINFO, hbmColor, 4) + TEST_FIELD_ALIGN (ICONINFO, hbmColor, 4) + TEST_FIELD_OFFSET(ICONINFO, hbmColor, 16) } static void test_pack_ICONMETRICSA(void) { /* ICONMETRICSA (pack 4) */ - TEST_TYPE(ICONMETRICSA, 76, 4); - TEST_FIELD(ICONMETRICSA, UINT, cbSize, 0, 4, 4); - TEST_FIELD(ICONMETRICSA, int, iHorzSpacing, 4, 4, 4); - TEST_FIELD(ICONMETRICSA, int, iVertSpacing, 8, 4, 4); - TEST_FIELD(ICONMETRICSA, int, iTitleWrap, 12, 4, 4); - TEST_FIELD(ICONMETRICSA, LOGFONTA, lfFont, 16, 60, 4); + TEST_TYPE_SIZE (ICONMETRICSA, 76) + TEST_TYPE_ALIGN (ICONMETRICSA, 4) + TEST_FIELD_SIZE (ICONMETRICSA, cbSize, 4) + TEST_FIELD_ALIGN (ICONMETRICSA, cbSize, 4) + TEST_FIELD_OFFSET(ICONMETRICSA, cbSize, 0) + TEST_FIELD_SIZE (ICONMETRICSA, iHorzSpacing, 4) + TEST_FIELD_ALIGN (ICONMETRICSA, iHorzSpacing, 4) + TEST_FIELD_OFFSET(ICONMETRICSA, iHorzSpacing, 4) + TEST_FIELD_SIZE (ICONMETRICSA, iVertSpacing, 4) + TEST_FIELD_ALIGN (ICONMETRICSA, iVertSpacing, 4) + TEST_FIELD_OFFSET(ICONMETRICSA, iVertSpacing, 8) + TEST_FIELD_SIZE (ICONMETRICSA, iTitleWrap, 4) + TEST_FIELD_ALIGN (ICONMETRICSA, iTitleWrap, 4) + TEST_FIELD_OFFSET(ICONMETRICSA, iTitleWrap, 12) + TEST_FIELD_SIZE (ICONMETRICSA, lfFont, 60) + TEST_FIELD_ALIGN (ICONMETRICSA, lfFont, 4) + TEST_FIELD_OFFSET(ICONMETRICSA, lfFont, 16) } static void test_pack_ICONMETRICSW(void) { /* ICONMETRICSW (pack 4) */ - TEST_TYPE(ICONMETRICSW, 108, 4); - TEST_FIELD(ICONMETRICSW, UINT, cbSize, 0, 4, 4); - TEST_FIELD(ICONMETRICSW, int, iHorzSpacing, 4, 4, 4); - TEST_FIELD(ICONMETRICSW, int, iVertSpacing, 8, 4, 4); - TEST_FIELD(ICONMETRICSW, int, iTitleWrap, 12, 4, 4); - TEST_FIELD(ICONMETRICSW, LOGFONTW, lfFont, 16, 92, 4); + TEST_TYPE_SIZE (ICONMETRICSW, 108) + TEST_TYPE_ALIGN (ICONMETRICSW, 4) + TEST_FIELD_SIZE (ICONMETRICSW, cbSize, 4) + TEST_FIELD_ALIGN (ICONMETRICSW, cbSize, 4) + TEST_FIELD_OFFSET(ICONMETRICSW, cbSize, 0) + TEST_FIELD_SIZE (ICONMETRICSW, iHorzSpacing, 4) + TEST_FIELD_ALIGN (ICONMETRICSW, iHorzSpacing, 4) + TEST_FIELD_OFFSET(ICONMETRICSW, iHorzSpacing, 4) + TEST_FIELD_SIZE (ICONMETRICSW, iVertSpacing, 4) + TEST_FIELD_ALIGN (ICONMETRICSW, iVertSpacing, 4) + TEST_FIELD_OFFSET(ICONMETRICSW, iVertSpacing, 8) + TEST_FIELD_SIZE (ICONMETRICSW, iTitleWrap, 4) + TEST_FIELD_ALIGN (ICONMETRICSW, iTitleWrap, 4) + TEST_FIELD_OFFSET(ICONMETRICSW, iTitleWrap, 12) + TEST_FIELD_SIZE (ICONMETRICSW, lfFont, 92) + TEST_FIELD_ALIGN (ICONMETRICSW, lfFont, 4) + TEST_FIELD_OFFSET(ICONMETRICSW, lfFont, 16) } static void test_pack_INPUT(void) { /* INPUT (pack 4) */ - TEST_FIELD(INPUT, DWORD, type, 0, 4, 4); + TEST_FIELD_SIZE (INPUT, type, 4) + TEST_FIELD_ALIGN (INPUT, type, 4) + TEST_FIELD_OFFSET(INPUT, type, 0) } static void test_pack_KBDLLHOOKSTRUCT(void) { /* KBDLLHOOKSTRUCT (pack 4) */ - TEST_TYPE(KBDLLHOOKSTRUCT, 20, 4); - TEST_FIELD(KBDLLHOOKSTRUCT, DWORD, vkCode, 0, 4, 4); - TEST_FIELD(KBDLLHOOKSTRUCT, DWORD, scanCode, 4, 4, 4); - TEST_FIELD(KBDLLHOOKSTRUCT, DWORD, flags, 8, 4, 4); - TEST_FIELD(KBDLLHOOKSTRUCT, DWORD, time, 12, 4, 4); - TEST_FIELD(KBDLLHOOKSTRUCT, ULONG_PTR, dwExtraInfo, 16, 4, 4); + TEST_TYPE_SIZE (KBDLLHOOKSTRUCT, 20) + TEST_TYPE_ALIGN (KBDLLHOOKSTRUCT, 4) + TEST_FIELD_SIZE (KBDLLHOOKSTRUCT, vkCode, 4) + TEST_FIELD_ALIGN (KBDLLHOOKSTRUCT, vkCode, 4) + TEST_FIELD_OFFSET(KBDLLHOOKSTRUCT, vkCode, 0) + TEST_FIELD_SIZE (KBDLLHOOKSTRUCT, scanCode, 4) + TEST_FIELD_ALIGN (KBDLLHOOKSTRUCT, scanCode, 4) + TEST_FIELD_OFFSET(KBDLLHOOKSTRUCT, scanCode, 4) + TEST_FIELD_SIZE (KBDLLHOOKSTRUCT, flags, 4) + TEST_FIELD_ALIGN (KBDLLHOOKSTRUCT, flags, 4) + TEST_FIELD_OFFSET(KBDLLHOOKSTRUCT, flags, 8) + TEST_FIELD_SIZE (KBDLLHOOKSTRUCT, time, 4) + TEST_FIELD_ALIGN (KBDLLHOOKSTRUCT, time, 4) + TEST_FIELD_OFFSET(KBDLLHOOKSTRUCT, time, 12) + TEST_FIELD_SIZE (KBDLLHOOKSTRUCT, dwExtraInfo, 4) + TEST_FIELD_ALIGN (KBDLLHOOKSTRUCT, dwExtraInfo, 4) + TEST_FIELD_OFFSET(KBDLLHOOKSTRUCT, dwExtraInfo, 16) } static void test_pack_KEYBDINPUT(void) { /* KEYBDINPUT (pack 4) */ - TEST_TYPE(KEYBDINPUT, 16, 4); - TEST_FIELD(KEYBDINPUT, WORD, wVk, 0, 2, 2); - TEST_FIELD(KEYBDINPUT, WORD, wScan, 2, 2, 2); - TEST_FIELD(KEYBDINPUT, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(KEYBDINPUT, DWORD, time, 8, 4, 4); - TEST_FIELD(KEYBDINPUT, ULONG_PTR, dwExtraInfo, 12, 4, 4); + TEST_TYPE_SIZE (KEYBDINPUT, 16) + TEST_TYPE_ALIGN (KEYBDINPUT, 4) + TEST_FIELD_SIZE (KEYBDINPUT, wVk, 2) + TEST_FIELD_ALIGN (KEYBDINPUT, wVk, 2) + TEST_FIELD_OFFSET(KEYBDINPUT, wVk, 0) + TEST_FIELD_SIZE (KEYBDINPUT, wScan, 2) + TEST_FIELD_ALIGN (KEYBDINPUT, wScan, 2) + TEST_FIELD_OFFSET(KEYBDINPUT, wScan, 2) + TEST_FIELD_SIZE (KEYBDINPUT, dwFlags, 4) + TEST_FIELD_ALIGN (KEYBDINPUT, dwFlags, 4) + TEST_FIELD_OFFSET(KEYBDINPUT, dwFlags, 4) + TEST_FIELD_SIZE (KEYBDINPUT, time, 4) + TEST_FIELD_ALIGN (KEYBDINPUT, time, 4) + TEST_FIELD_OFFSET(KEYBDINPUT, time, 8) + TEST_FIELD_SIZE (KEYBDINPUT, dwExtraInfo, 4) + TEST_FIELD_ALIGN (KEYBDINPUT, dwExtraInfo, 4) + TEST_FIELD_OFFSET(KEYBDINPUT, dwExtraInfo, 12) } static void test_pack_LPACCESSTIMEOUT(void) { /* LPACCESSTIMEOUT */ - TEST_TYPE(LPACCESSTIMEOUT, 4, 4); - TEST_TYPE_POINTER(LPACCESSTIMEOUT, 12, 4); + TEST_TYPE_SIZE (LPACCESSTIMEOUT, 4) + TEST_TYPE_ALIGN (LPACCESSTIMEOUT, 4) + TEST_TARGET_SIZE (LPACCESSTIMEOUT, 12) + TEST_TARGET_ALIGN(LPACCESSTIMEOUT, 4) } static void test_pack_LPANIMATIONINFO(void) { /* LPANIMATIONINFO */ - TEST_TYPE(LPANIMATIONINFO, 4, 4); - TEST_TYPE_POINTER(LPANIMATIONINFO, 8, 4); + TEST_TYPE_SIZE (LPANIMATIONINFO, 4) + TEST_TYPE_ALIGN (LPANIMATIONINFO, 4) + TEST_TARGET_SIZE (LPANIMATIONINFO, 8) + TEST_TARGET_ALIGN(LPANIMATIONINFO, 4) } static void test_pack_LPCBTACTIVATESTRUCT(void) { /* LPCBTACTIVATESTRUCT */ - TEST_TYPE(LPCBTACTIVATESTRUCT, 4, 4); - TEST_TYPE_POINTER(LPCBTACTIVATESTRUCT, 8, 4); + TEST_TYPE_SIZE (LPCBTACTIVATESTRUCT, 4) + TEST_TYPE_ALIGN (LPCBTACTIVATESTRUCT, 4) + TEST_TARGET_SIZE (LPCBTACTIVATESTRUCT, 8) + TEST_TARGET_ALIGN(LPCBTACTIVATESTRUCT, 4) } static void test_pack_LPCBT_CREATEWNDA(void) { /* LPCBT_CREATEWNDA */ - TEST_TYPE(LPCBT_CREATEWNDA, 4, 4); - TEST_TYPE_POINTER(LPCBT_CREATEWNDA, 8, 4); + TEST_TYPE_SIZE (LPCBT_CREATEWNDA, 4) + TEST_TYPE_ALIGN (LPCBT_CREATEWNDA, 4) + TEST_TARGET_SIZE (LPCBT_CREATEWNDA, 8) + TEST_TARGET_ALIGN(LPCBT_CREATEWNDA, 4) } static void test_pack_LPCBT_CREATEWNDW(void) { /* LPCBT_CREATEWNDW */ - TEST_TYPE(LPCBT_CREATEWNDW, 4, 4); - TEST_TYPE_POINTER(LPCBT_CREATEWNDW, 8, 4); + TEST_TYPE_SIZE (LPCBT_CREATEWNDW, 4) + TEST_TYPE_ALIGN (LPCBT_CREATEWNDW, 4) + TEST_TARGET_SIZE (LPCBT_CREATEWNDW, 8) + TEST_TARGET_ALIGN(LPCBT_CREATEWNDW, 4) } static void test_pack_LPCDLGTEMPLATEA(void) { /* LPCDLGTEMPLATEA */ - TEST_TYPE(LPCDLGTEMPLATEA, 4, 4); - TEST_TYPE_POINTER(LPCDLGTEMPLATEA, 18, 2); + TEST_TYPE_SIZE (LPCDLGTEMPLATEA, 4) + TEST_TYPE_ALIGN (LPCDLGTEMPLATEA, 4) + TEST_TARGET_SIZE (LPCDLGTEMPLATEA, 18) + TEST_TARGET_ALIGN(LPCDLGTEMPLATEA, 2) } static void test_pack_LPCDLGTEMPLATEW(void) { /* LPCDLGTEMPLATEW */ - TEST_TYPE(LPCDLGTEMPLATEW, 4, 4); - TEST_TYPE_POINTER(LPCDLGTEMPLATEW, 18, 2); + TEST_TYPE_SIZE (LPCDLGTEMPLATEW, 4) + TEST_TYPE_ALIGN (LPCDLGTEMPLATEW, 4) + TEST_TARGET_SIZE (LPCDLGTEMPLATEW, 18) + TEST_TARGET_ALIGN(LPCDLGTEMPLATEW, 2) } static void test_pack_LPCLIENTCREATESTRUCT(void) { /* LPCLIENTCREATESTRUCT */ - TEST_TYPE(LPCLIENTCREATESTRUCT, 4, 4); - TEST_TYPE_POINTER(LPCLIENTCREATESTRUCT, 8, 4); + TEST_TYPE_SIZE (LPCLIENTCREATESTRUCT, 4) + TEST_TYPE_ALIGN (LPCLIENTCREATESTRUCT, 4) + TEST_TARGET_SIZE (LPCLIENTCREATESTRUCT, 8) + TEST_TARGET_ALIGN(LPCLIENTCREATESTRUCT, 4) } static void test_pack_LPCMENUINFO(void) { /* LPCMENUINFO */ - TEST_TYPE(LPCMENUINFO, 4, 4); - TEST_TYPE_POINTER(LPCMENUINFO, 28, 4); + TEST_TYPE_SIZE (LPCMENUINFO, 4) + TEST_TYPE_ALIGN (LPCMENUINFO, 4) + TEST_TARGET_SIZE (LPCMENUINFO, 28) + TEST_TARGET_ALIGN(LPCMENUINFO, 4) } static void test_pack_LPCMENUITEMINFOA(void) { /* LPCMENUITEMINFOA */ - TEST_TYPE(LPCMENUITEMINFOA, 4, 4); - TEST_TYPE_POINTER(LPCMENUITEMINFOA, 48, 4); + TEST_TYPE_SIZE (LPCMENUITEMINFOA, 4) + TEST_TYPE_ALIGN (LPCMENUITEMINFOA, 4) + TEST_TARGET_SIZE (LPCMENUITEMINFOA, 48) + TEST_TARGET_ALIGN(LPCMENUITEMINFOA, 4) } static void test_pack_LPCMENUITEMINFOW(void) { /* LPCMENUITEMINFOW */ - TEST_TYPE(LPCMENUITEMINFOW, 4, 4); - TEST_TYPE_POINTER(LPCMENUITEMINFOW, 48, 4); + TEST_TYPE_SIZE (LPCMENUITEMINFOW, 4) + TEST_TYPE_ALIGN (LPCMENUITEMINFOW, 4) + TEST_TARGET_SIZE (LPCMENUITEMINFOW, 48) + TEST_TARGET_ALIGN(LPCMENUITEMINFOW, 4) } static void test_pack_LPCOMBOBOXINFO(void) { /* LPCOMBOBOXINFO */ - TEST_TYPE(LPCOMBOBOXINFO, 4, 4); - TEST_TYPE_POINTER(LPCOMBOBOXINFO, 52, 4); + TEST_TYPE_SIZE (LPCOMBOBOXINFO, 4) + TEST_TYPE_ALIGN (LPCOMBOBOXINFO, 4) + TEST_TARGET_SIZE (LPCOMBOBOXINFO, 52) + TEST_TARGET_ALIGN(LPCOMBOBOXINFO, 4) } static void test_pack_LPCOMPAREITEMSTRUCT(void) { /* LPCOMPAREITEMSTRUCT */ - TEST_TYPE(LPCOMPAREITEMSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPCOMPAREITEMSTRUCT, 32, 4); + TEST_TYPE_SIZE (LPCOMPAREITEMSTRUCT, 4) + TEST_TYPE_ALIGN (LPCOMPAREITEMSTRUCT, 4) + TEST_TARGET_SIZE (LPCOMPAREITEMSTRUCT, 32) + TEST_TARGET_ALIGN(LPCOMPAREITEMSTRUCT, 4) } static void test_pack_LPCREATESTRUCTA(void) { /* LPCREATESTRUCTA */ - TEST_TYPE(LPCREATESTRUCTA, 4, 4); - TEST_TYPE_POINTER(LPCREATESTRUCTA, 48, 4); + TEST_TYPE_SIZE (LPCREATESTRUCTA, 4) + TEST_TYPE_ALIGN (LPCREATESTRUCTA, 4) + TEST_TARGET_SIZE (LPCREATESTRUCTA, 48) + TEST_TARGET_ALIGN(LPCREATESTRUCTA, 4) } static void test_pack_LPCREATESTRUCTW(void) { /* LPCREATESTRUCTW */ - TEST_TYPE(LPCREATESTRUCTW, 4, 4); - TEST_TYPE_POINTER(LPCREATESTRUCTW, 48, 4); + TEST_TYPE_SIZE (LPCREATESTRUCTW, 4) + TEST_TYPE_ALIGN (LPCREATESTRUCTW, 4) + TEST_TARGET_SIZE (LPCREATESTRUCTW, 48) + TEST_TARGET_ALIGN(LPCREATESTRUCTW, 4) } static void test_pack_LPCSCROLLINFO(void) { /* LPCSCROLLINFO */ - TEST_TYPE(LPCSCROLLINFO, 4, 4); - TEST_TYPE_POINTER(LPCSCROLLINFO, 28, 4); + TEST_TYPE_SIZE (LPCSCROLLINFO, 4) + TEST_TYPE_ALIGN (LPCSCROLLINFO, 4) + TEST_TARGET_SIZE (LPCSCROLLINFO, 28) + TEST_TARGET_ALIGN(LPCSCROLLINFO, 4) } static void test_pack_LPCURSORINFO(void) { /* LPCURSORINFO */ - TEST_TYPE(LPCURSORINFO, 4, 4); - TEST_TYPE_POINTER(LPCURSORINFO, 20, 4); + TEST_TYPE_SIZE (LPCURSORINFO, 4) + TEST_TYPE_ALIGN (LPCURSORINFO, 4) + TEST_TARGET_SIZE (LPCURSORINFO, 20) + TEST_TARGET_ALIGN(LPCURSORINFO, 4) } static void test_pack_LPCWPRETSTRUCT(void) { /* LPCWPRETSTRUCT */ - TEST_TYPE(LPCWPRETSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPCWPRETSTRUCT, 20, 4); + TEST_TYPE_SIZE (LPCWPRETSTRUCT, 4) + TEST_TYPE_ALIGN (LPCWPRETSTRUCT, 4) + TEST_TARGET_SIZE (LPCWPRETSTRUCT, 20) + TEST_TARGET_ALIGN(LPCWPRETSTRUCT, 4) } static void test_pack_LPCWPSTRUCT(void) { /* LPCWPSTRUCT */ - TEST_TYPE(LPCWPSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPCWPSTRUCT, 16, 4); + TEST_TYPE_SIZE (LPCWPSTRUCT, 4) + TEST_TYPE_ALIGN (LPCWPSTRUCT, 4) + TEST_TARGET_SIZE (LPCWPSTRUCT, 16) + TEST_TARGET_ALIGN(LPCWPSTRUCT, 4) } static void test_pack_LPDEBUGHOOKINFO(void) { /* LPDEBUGHOOKINFO */ - TEST_TYPE(LPDEBUGHOOKINFO, 4, 4); - TEST_TYPE_POINTER(LPDEBUGHOOKINFO, 20, 4); + TEST_TYPE_SIZE (LPDEBUGHOOKINFO, 4) + TEST_TYPE_ALIGN (LPDEBUGHOOKINFO, 4) + TEST_TARGET_SIZE (LPDEBUGHOOKINFO, 20) + TEST_TARGET_ALIGN(LPDEBUGHOOKINFO, 4) } static void test_pack_LPDELETEITEMSTRUCT(void) { /* LPDELETEITEMSTRUCT */ - TEST_TYPE(LPDELETEITEMSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPDELETEITEMSTRUCT, 20, 4); + TEST_TYPE_SIZE (LPDELETEITEMSTRUCT, 4) + TEST_TYPE_ALIGN (LPDELETEITEMSTRUCT, 4) + TEST_TARGET_SIZE (LPDELETEITEMSTRUCT, 20) + TEST_TARGET_ALIGN(LPDELETEITEMSTRUCT, 4) } static void test_pack_LPDLGITEMTEMPLATEA(void) { /* LPDLGITEMTEMPLATEA */ - TEST_TYPE(LPDLGITEMTEMPLATEA, 4, 4); - TEST_TYPE_POINTER(LPDLGITEMTEMPLATEA, 18, 2); + TEST_TYPE_SIZE (LPDLGITEMTEMPLATEA, 4) + TEST_TYPE_ALIGN (LPDLGITEMTEMPLATEA, 4) + TEST_TARGET_SIZE (LPDLGITEMTEMPLATEA, 18) + TEST_TARGET_ALIGN(LPDLGITEMTEMPLATEA, 2) } static void test_pack_LPDLGITEMTEMPLATEW(void) { /* LPDLGITEMTEMPLATEW */ - TEST_TYPE(LPDLGITEMTEMPLATEW, 4, 4); - TEST_TYPE_POINTER(LPDLGITEMTEMPLATEW, 18, 2); + TEST_TYPE_SIZE (LPDLGITEMTEMPLATEW, 4) + TEST_TYPE_ALIGN (LPDLGITEMTEMPLATEW, 4) + TEST_TARGET_SIZE (LPDLGITEMTEMPLATEW, 18) + TEST_TARGET_ALIGN(LPDLGITEMTEMPLATEW, 2) } static void test_pack_LPDLGTEMPLATEA(void) { /* LPDLGTEMPLATEA */ - TEST_TYPE(LPDLGTEMPLATEA, 4, 4); - TEST_TYPE_POINTER(LPDLGTEMPLATEA, 18, 2); + TEST_TYPE_SIZE (LPDLGTEMPLATEA, 4) + TEST_TYPE_ALIGN (LPDLGTEMPLATEA, 4) + TEST_TARGET_SIZE (LPDLGTEMPLATEA, 18) + TEST_TARGET_ALIGN(LPDLGTEMPLATEA, 2) } static void test_pack_LPDLGTEMPLATEW(void) { /* LPDLGTEMPLATEW */ - TEST_TYPE(LPDLGTEMPLATEW, 4, 4); - TEST_TYPE_POINTER(LPDLGTEMPLATEW, 18, 2); + TEST_TYPE_SIZE (LPDLGTEMPLATEW, 4) + TEST_TYPE_ALIGN (LPDLGTEMPLATEW, 4) + TEST_TARGET_SIZE (LPDLGTEMPLATEW, 18) + TEST_TARGET_ALIGN(LPDLGTEMPLATEW, 2) } static void test_pack_LPDRAWITEMSTRUCT(void) { /* LPDRAWITEMSTRUCT */ - TEST_TYPE(LPDRAWITEMSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPDRAWITEMSTRUCT, 48, 4); + TEST_TYPE_SIZE (LPDRAWITEMSTRUCT, 4) + TEST_TYPE_ALIGN (LPDRAWITEMSTRUCT, 4) + TEST_TARGET_SIZE (LPDRAWITEMSTRUCT, 48) + TEST_TARGET_ALIGN(LPDRAWITEMSTRUCT, 4) } static void test_pack_LPDRAWTEXTPARAMS(void) { /* LPDRAWTEXTPARAMS */ - TEST_TYPE(LPDRAWTEXTPARAMS, 4, 4); - TEST_TYPE_POINTER(LPDRAWTEXTPARAMS, 20, 4); + TEST_TYPE_SIZE (LPDRAWTEXTPARAMS, 4) + TEST_TYPE_ALIGN (LPDRAWTEXTPARAMS, 4) + TEST_TARGET_SIZE (LPDRAWTEXTPARAMS, 20) + TEST_TARGET_ALIGN(LPDRAWTEXTPARAMS, 4) } static void test_pack_LPEVENTMSG(void) { /* LPEVENTMSG */ - TEST_TYPE(LPEVENTMSG, 4, 4); - TEST_TYPE_POINTER(LPEVENTMSG, 20, 4); + TEST_TYPE_SIZE (LPEVENTMSG, 4) + TEST_TYPE_ALIGN (LPEVENTMSG, 4) + TEST_TARGET_SIZE (LPEVENTMSG, 20) + TEST_TARGET_ALIGN(LPEVENTMSG, 4) } static void test_pack_LPFILTERKEYS(void) { /* LPFILTERKEYS */ - TEST_TYPE(LPFILTERKEYS, 4, 4); - TEST_TYPE_POINTER(LPFILTERKEYS, 24, 4); + TEST_TYPE_SIZE (LPFILTERKEYS, 4) + TEST_TYPE_ALIGN (LPFILTERKEYS, 4) + TEST_TARGET_SIZE (LPFILTERKEYS, 24) + TEST_TARGET_ALIGN(LPFILTERKEYS, 4) } static void test_pack_LPGUITHREADINFO(void) { /* LPGUITHREADINFO */ - TEST_TYPE(LPGUITHREADINFO, 4, 4); - TEST_TYPE_POINTER(LPGUITHREADINFO, 48, 4); + TEST_TYPE_SIZE (LPGUITHREADINFO, 4) + TEST_TYPE_ALIGN (LPGUITHREADINFO, 4) + TEST_TARGET_SIZE (LPGUITHREADINFO, 48) + TEST_TARGET_ALIGN(LPGUITHREADINFO, 4) } static void test_pack_LPHARDWAREHOOKSTRUCT(void) { /* LPHARDWAREHOOKSTRUCT */ - TEST_TYPE(LPHARDWAREHOOKSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPHARDWAREHOOKSTRUCT, 16, 4); + TEST_TYPE_SIZE (LPHARDWAREHOOKSTRUCT, 4) + TEST_TYPE_ALIGN (LPHARDWAREHOOKSTRUCT, 4) + TEST_TARGET_SIZE (LPHARDWAREHOOKSTRUCT, 16) + TEST_TARGET_ALIGN(LPHARDWAREHOOKSTRUCT, 4) } static void test_pack_LPHARDWAREINPUT(void) { /* LPHARDWAREINPUT */ - TEST_TYPE(LPHARDWAREINPUT, 4, 4); - TEST_TYPE_POINTER(LPHARDWAREINPUT, 8, 4); + TEST_TYPE_SIZE (LPHARDWAREINPUT, 4) + TEST_TYPE_ALIGN (LPHARDWAREINPUT, 4) + TEST_TARGET_SIZE (LPHARDWAREINPUT, 8) + TEST_TARGET_ALIGN(LPHARDWAREINPUT, 4) } static void test_pack_LPHELPINFO(void) { /* LPHELPINFO */ - TEST_TYPE(LPHELPINFO, 4, 4); - TEST_TYPE_POINTER(LPHELPINFO, 28, 4); + TEST_TYPE_SIZE (LPHELPINFO, 4) + TEST_TYPE_ALIGN (LPHELPINFO, 4) + TEST_TARGET_SIZE (LPHELPINFO, 28) + TEST_TARGET_ALIGN(LPHELPINFO, 4) } static void test_pack_LPHELPWININFOA(void) { /* LPHELPWININFOA */ - TEST_TYPE(LPHELPWININFOA, 4, 4); - TEST_TYPE_POINTER(LPHELPWININFOA, 28, 4); + TEST_TYPE_SIZE (LPHELPWININFOA, 4) + TEST_TYPE_ALIGN (LPHELPWININFOA, 4) + TEST_TARGET_SIZE (LPHELPWININFOA, 28) + TEST_TARGET_ALIGN(LPHELPWININFOA, 4) } static void test_pack_LPHELPWININFOW(void) { /* LPHELPWININFOW */ - TEST_TYPE(LPHELPWININFOW, 4, 4); - TEST_TYPE_POINTER(LPHELPWININFOW, 28, 4); + TEST_TYPE_SIZE (LPHELPWININFOW, 4) + TEST_TYPE_ALIGN (LPHELPWININFOW, 4) + TEST_TARGET_SIZE (LPHELPWININFOW, 28) + TEST_TARGET_ALIGN(LPHELPWININFOW, 4) } static void test_pack_LPHIGHCONTRASTA(void) { /* LPHIGHCONTRASTA */ - TEST_TYPE(LPHIGHCONTRASTA, 4, 4); - TEST_TYPE_POINTER(LPHIGHCONTRASTA, 12, 4); + TEST_TYPE_SIZE (LPHIGHCONTRASTA, 4) + TEST_TYPE_ALIGN (LPHIGHCONTRASTA, 4) + TEST_TARGET_SIZE (LPHIGHCONTRASTA, 12) + TEST_TARGET_ALIGN(LPHIGHCONTRASTA, 4) } static void test_pack_LPHIGHCONTRASTW(void) { /* LPHIGHCONTRASTW */ - TEST_TYPE(LPHIGHCONTRASTW, 4, 4); - TEST_TYPE_POINTER(LPHIGHCONTRASTW, 12, 4); + TEST_TYPE_SIZE (LPHIGHCONTRASTW, 4) + TEST_TYPE_ALIGN (LPHIGHCONTRASTW, 4) + TEST_TARGET_SIZE (LPHIGHCONTRASTW, 12) + TEST_TARGET_ALIGN(LPHIGHCONTRASTW, 4) } static void test_pack_LPICONMETRICSA(void) { /* LPICONMETRICSA */ - TEST_TYPE(LPICONMETRICSA, 4, 4); - TEST_TYPE_POINTER(LPICONMETRICSA, 76, 4); + TEST_TYPE_SIZE (LPICONMETRICSA, 4) + TEST_TYPE_ALIGN (LPICONMETRICSA, 4) + TEST_TARGET_SIZE (LPICONMETRICSA, 76) + TEST_TARGET_ALIGN(LPICONMETRICSA, 4) } static void test_pack_LPICONMETRICSW(void) { /* LPICONMETRICSW */ - TEST_TYPE(LPICONMETRICSW, 4, 4); - TEST_TYPE_POINTER(LPICONMETRICSW, 108, 4); + TEST_TYPE_SIZE (LPICONMETRICSW, 4) + TEST_TYPE_ALIGN (LPICONMETRICSW, 4) + TEST_TARGET_SIZE (LPICONMETRICSW, 108) + TEST_TARGET_ALIGN(LPICONMETRICSW, 4) } static void test_pack_LPINPUT(void) { /* LPINPUT */ - TEST_TYPE(LPINPUT, 4, 4); + TEST_TYPE_SIZE (LPINPUT, 4) + TEST_TYPE_ALIGN (LPINPUT, 4) } static void test_pack_LPKBDLLHOOKSTRUCT(void) { /* LPKBDLLHOOKSTRUCT */ - TEST_TYPE(LPKBDLLHOOKSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPKBDLLHOOKSTRUCT, 20, 4); + TEST_TYPE_SIZE (LPKBDLLHOOKSTRUCT, 4) + TEST_TYPE_ALIGN (LPKBDLLHOOKSTRUCT, 4) + TEST_TARGET_SIZE (LPKBDLLHOOKSTRUCT, 20) + TEST_TARGET_ALIGN(LPKBDLLHOOKSTRUCT, 4) } static void test_pack_LPKEYBDINPUT(void) { /* LPKEYBDINPUT */ - TEST_TYPE(LPKEYBDINPUT, 4, 4); - TEST_TYPE_POINTER(LPKEYBDINPUT, 16, 4); + TEST_TYPE_SIZE (LPKEYBDINPUT, 4) + TEST_TYPE_ALIGN (LPKEYBDINPUT, 4) + TEST_TARGET_SIZE (LPKEYBDINPUT, 16) + TEST_TARGET_ALIGN(LPKEYBDINPUT, 4) } static void test_pack_LPMDICREATESTRUCTA(void) { /* LPMDICREATESTRUCTA */ - TEST_TYPE(LPMDICREATESTRUCTA, 4, 4); - TEST_TYPE_POINTER(LPMDICREATESTRUCTA, 36, 4); + TEST_TYPE_SIZE (LPMDICREATESTRUCTA, 4) + TEST_TYPE_ALIGN (LPMDICREATESTRUCTA, 4) + TEST_TARGET_SIZE (LPMDICREATESTRUCTA, 36) + TEST_TARGET_ALIGN(LPMDICREATESTRUCTA, 4) } static void test_pack_LPMDICREATESTRUCTW(void) { /* LPMDICREATESTRUCTW */ - TEST_TYPE(LPMDICREATESTRUCTW, 4, 4); - TEST_TYPE_POINTER(LPMDICREATESTRUCTW, 36, 4); + TEST_TYPE_SIZE (LPMDICREATESTRUCTW, 4) + TEST_TYPE_ALIGN (LPMDICREATESTRUCTW, 4) + TEST_TARGET_SIZE (LPMDICREATESTRUCTW, 36) + TEST_TARGET_ALIGN(LPMDICREATESTRUCTW, 4) } static void test_pack_LPMDINEXTMENU(void) { /* LPMDINEXTMENU */ - TEST_TYPE(LPMDINEXTMENU, 4, 4); - TEST_TYPE_POINTER(LPMDINEXTMENU, 12, 4); + TEST_TYPE_SIZE (LPMDINEXTMENU, 4) + TEST_TYPE_ALIGN (LPMDINEXTMENU, 4) + TEST_TARGET_SIZE (LPMDINEXTMENU, 12) + TEST_TARGET_ALIGN(LPMDINEXTMENU, 4) } static void test_pack_LPMEASUREITEMSTRUCT(void) { /* LPMEASUREITEMSTRUCT */ - TEST_TYPE(LPMEASUREITEMSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPMEASUREITEMSTRUCT, 24, 4); + TEST_TYPE_SIZE (LPMEASUREITEMSTRUCT, 4) + TEST_TYPE_ALIGN (LPMEASUREITEMSTRUCT, 4) + TEST_TARGET_SIZE (LPMEASUREITEMSTRUCT, 24) + TEST_TARGET_ALIGN(LPMEASUREITEMSTRUCT, 4) } static void test_pack_LPMENUINFO(void) { /* LPMENUINFO */ - TEST_TYPE(LPMENUINFO, 4, 4); - TEST_TYPE_POINTER(LPMENUINFO, 28, 4); + TEST_TYPE_SIZE (LPMENUINFO, 4) + TEST_TYPE_ALIGN (LPMENUINFO, 4) + TEST_TARGET_SIZE (LPMENUINFO, 28) + TEST_TARGET_ALIGN(LPMENUINFO, 4) } static void test_pack_LPMENUITEMINFOA(void) { /* LPMENUITEMINFOA */ - TEST_TYPE(LPMENUITEMINFOA, 4, 4); - TEST_TYPE_POINTER(LPMENUITEMINFOA, 48, 4); + TEST_TYPE_SIZE (LPMENUITEMINFOA, 4) + TEST_TYPE_ALIGN (LPMENUITEMINFOA, 4) + TEST_TARGET_SIZE (LPMENUITEMINFOA, 48) + TEST_TARGET_ALIGN(LPMENUITEMINFOA, 4) } static void test_pack_LPMENUITEMINFOW(void) { /* LPMENUITEMINFOW */ - TEST_TYPE(LPMENUITEMINFOW, 4, 4); - TEST_TYPE_POINTER(LPMENUITEMINFOW, 48, 4); + TEST_TYPE_SIZE (LPMENUITEMINFOW, 4) + TEST_TYPE_ALIGN (LPMENUITEMINFOW, 4) + TEST_TARGET_SIZE (LPMENUITEMINFOW, 48) + TEST_TARGET_ALIGN(LPMENUITEMINFOW, 4) } static void test_pack_LPMINIMIZEDMETRICS(void) { /* LPMINIMIZEDMETRICS */ - TEST_TYPE(LPMINIMIZEDMETRICS, 4, 4); - TEST_TYPE_POINTER(LPMINIMIZEDMETRICS, 20, 4); + TEST_TYPE_SIZE (LPMINIMIZEDMETRICS, 4) + TEST_TYPE_ALIGN (LPMINIMIZEDMETRICS, 4) + TEST_TARGET_SIZE (LPMINIMIZEDMETRICS, 20) + TEST_TARGET_ALIGN(LPMINIMIZEDMETRICS, 4) } static void test_pack_LPMINMAXINFO(void) { /* LPMINMAXINFO */ - TEST_TYPE(LPMINMAXINFO, 4, 4); - TEST_TYPE_POINTER(LPMINMAXINFO, 40, 4); + TEST_TYPE_SIZE (LPMINMAXINFO, 4) + TEST_TYPE_ALIGN (LPMINMAXINFO, 4) + TEST_TARGET_SIZE (LPMINMAXINFO, 40) + TEST_TARGET_ALIGN(LPMINMAXINFO, 4) } static void test_pack_LPMONITORINFO(void) { /* LPMONITORINFO */ - TEST_TYPE(LPMONITORINFO, 4, 4); - TEST_TYPE_POINTER(LPMONITORINFO, 40, 4); + TEST_TYPE_SIZE (LPMONITORINFO, 4) + TEST_TYPE_ALIGN (LPMONITORINFO, 4) + TEST_TARGET_SIZE (LPMONITORINFO, 40) + TEST_TARGET_ALIGN(LPMONITORINFO, 4) } static void test_pack_LPMONITORINFOEXA(void) { /* LPMONITORINFOEXA */ - TEST_TYPE(LPMONITORINFOEXA, 4, 4); - TEST_TYPE_POINTER(LPMONITORINFOEXA, 72, 4); + TEST_TYPE_SIZE (LPMONITORINFOEXA, 4) + TEST_TYPE_ALIGN (LPMONITORINFOEXA, 4) + TEST_TARGET_SIZE (LPMONITORINFOEXA, 72) + TEST_TARGET_ALIGN(LPMONITORINFOEXA, 4) } static void test_pack_LPMONITORINFOEXW(void) { /* LPMONITORINFOEXW */ - TEST_TYPE(LPMONITORINFOEXW, 4, 4); - TEST_TYPE_POINTER(LPMONITORINFOEXW, 104, 4); + TEST_TYPE_SIZE (LPMONITORINFOEXW, 4) + TEST_TYPE_ALIGN (LPMONITORINFOEXW, 4) + TEST_TARGET_SIZE (LPMONITORINFOEXW, 104) + TEST_TARGET_ALIGN(LPMONITORINFOEXW, 4) } static void test_pack_LPMOUSEHOOKSTRUCT(void) { /* LPMOUSEHOOKSTRUCT */ - TEST_TYPE(LPMOUSEHOOKSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPMOUSEHOOKSTRUCT, 20, 4); + TEST_TYPE_SIZE (LPMOUSEHOOKSTRUCT, 4) + TEST_TYPE_ALIGN (LPMOUSEHOOKSTRUCT, 4) + TEST_TARGET_SIZE (LPMOUSEHOOKSTRUCT, 20) + TEST_TARGET_ALIGN(LPMOUSEHOOKSTRUCT, 4) } static void test_pack_LPMOUSEINPUT(void) { /* LPMOUSEINPUT */ - TEST_TYPE(LPMOUSEINPUT, 4, 4); - TEST_TYPE_POINTER(LPMOUSEINPUT, 24, 4); + TEST_TYPE_SIZE (LPMOUSEINPUT, 4) + TEST_TYPE_ALIGN (LPMOUSEINPUT, 4) + TEST_TARGET_SIZE (LPMOUSEINPUT, 24) + TEST_TARGET_ALIGN(LPMOUSEINPUT, 4) } static void test_pack_LPMOUSEKEYS(void) { /* LPMOUSEKEYS */ - TEST_TYPE(LPMOUSEKEYS, 4, 4); - TEST_TYPE_POINTER(LPMOUSEKEYS, 28, 4); + TEST_TYPE_SIZE (LPMOUSEKEYS, 4) + TEST_TYPE_ALIGN (LPMOUSEKEYS, 4) + TEST_TARGET_SIZE (LPMOUSEKEYS, 28) + TEST_TARGET_ALIGN(LPMOUSEKEYS, 4) } static void test_pack_LPMSG(void) { /* LPMSG */ - TEST_TYPE(LPMSG, 4, 4); - TEST_TYPE_POINTER(LPMSG, 28, 4); + TEST_TYPE_SIZE (LPMSG, 4) + TEST_TYPE_ALIGN (LPMSG, 4) + TEST_TARGET_SIZE (LPMSG, 28) + TEST_TARGET_ALIGN(LPMSG, 4) } static void test_pack_LPMSGBOXPARAMSA(void) { /* LPMSGBOXPARAMSA */ - TEST_TYPE(LPMSGBOXPARAMSA, 4, 4); - TEST_TYPE_POINTER(LPMSGBOXPARAMSA, 40, 4); + TEST_TYPE_SIZE (LPMSGBOXPARAMSA, 4) + TEST_TYPE_ALIGN (LPMSGBOXPARAMSA, 4) + TEST_TARGET_SIZE (LPMSGBOXPARAMSA, 40) + TEST_TARGET_ALIGN(LPMSGBOXPARAMSA, 4) } static void test_pack_LPMSGBOXPARAMSW(void) { /* LPMSGBOXPARAMSW */ - TEST_TYPE(LPMSGBOXPARAMSW, 4, 4); - TEST_TYPE_POINTER(LPMSGBOXPARAMSW, 40, 4); + TEST_TYPE_SIZE (LPMSGBOXPARAMSW, 4) + TEST_TYPE_ALIGN (LPMSGBOXPARAMSW, 4) + TEST_TARGET_SIZE (LPMSGBOXPARAMSW, 40) + TEST_TARGET_ALIGN(LPMSGBOXPARAMSW, 4) } static void test_pack_LPMSLLHOOKSTRUCT(void) { /* LPMSLLHOOKSTRUCT */ - TEST_TYPE(LPMSLLHOOKSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPMSLLHOOKSTRUCT, 24, 4); + TEST_TYPE_SIZE (LPMSLLHOOKSTRUCT, 4) + TEST_TYPE_ALIGN (LPMSLLHOOKSTRUCT, 4) + TEST_TARGET_SIZE (LPMSLLHOOKSTRUCT, 24) + TEST_TARGET_ALIGN(LPMSLLHOOKSTRUCT, 4) } static void test_pack_LPMULTIKEYHELPA(void) { /* LPMULTIKEYHELPA */ - TEST_TYPE(LPMULTIKEYHELPA, 4, 4); - TEST_TYPE_POINTER(LPMULTIKEYHELPA, 8, 4); + TEST_TYPE_SIZE (LPMULTIKEYHELPA, 4) + TEST_TYPE_ALIGN (LPMULTIKEYHELPA, 4) + TEST_TARGET_SIZE (LPMULTIKEYHELPA, 8) + TEST_TARGET_ALIGN(LPMULTIKEYHELPA, 4) } static void test_pack_LPMULTIKEYHELPW(void) { /* LPMULTIKEYHELPW */ - TEST_TYPE(LPMULTIKEYHELPW, 4, 4); - TEST_TYPE_POINTER(LPMULTIKEYHELPW, 8, 4); + TEST_TYPE_SIZE (LPMULTIKEYHELPW, 4) + TEST_TYPE_ALIGN (LPMULTIKEYHELPW, 4) + TEST_TARGET_SIZE (LPMULTIKEYHELPW, 8) + TEST_TARGET_ALIGN(LPMULTIKEYHELPW, 4) } static void test_pack_LPNCCALCSIZE_PARAMS(void) { /* LPNCCALCSIZE_PARAMS */ - TEST_TYPE(LPNCCALCSIZE_PARAMS, 4, 4); - TEST_TYPE_POINTER(LPNCCALCSIZE_PARAMS, 52, 4); + TEST_TYPE_SIZE (LPNCCALCSIZE_PARAMS, 4) + TEST_TYPE_ALIGN (LPNCCALCSIZE_PARAMS, 4) + TEST_TARGET_SIZE (LPNCCALCSIZE_PARAMS, 52) + TEST_TARGET_ALIGN(LPNCCALCSIZE_PARAMS, 4) } static void test_pack_LPNMHDR(void) { /* LPNMHDR */ - TEST_TYPE(LPNMHDR, 4, 4); - TEST_TYPE_POINTER(LPNMHDR, 12, 4); + TEST_TYPE_SIZE (LPNMHDR, 4) + TEST_TYPE_ALIGN (LPNMHDR, 4) + TEST_TARGET_SIZE (LPNMHDR, 12) + TEST_TARGET_ALIGN(LPNMHDR, 4) } static void test_pack_LPNONCLIENTMETRICSA(void) { /* LPNONCLIENTMETRICSA */ - TEST_TYPE(LPNONCLIENTMETRICSA, 4, 4); - TEST_TYPE_POINTER(LPNONCLIENTMETRICSA, 340, 4); + TEST_TYPE_SIZE (LPNONCLIENTMETRICSA, 4) + TEST_TYPE_ALIGN (LPNONCLIENTMETRICSA, 4) + TEST_TARGET_SIZE (LPNONCLIENTMETRICSA, 340) + TEST_TARGET_ALIGN(LPNONCLIENTMETRICSA, 4) } static void test_pack_LPNONCLIENTMETRICSW(void) { /* LPNONCLIENTMETRICSW */ - TEST_TYPE(LPNONCLIENTMETRICSW, 4, 4); - TEST_TYPE_POINTER(LPNONCLIENTMETRICSW, 500, 4); + TEST_TYPE_SIZE (LPNONCLIENTMETRICSW, 4) + TEST_TYPE_ALIGN (LPNONCLIENTMETRICSW, 4) + TEST_TARGET_SIZE (LPNONCLIENTMETRICSW, 500) + TEST_TARGET_ALIGN(LPNONCLIENTMETRICSW, 4) } static void test_pack_LPPAINTSTRUCT(void) { /* LPPAINTSTRUCT */ - TEST_TYPE(LPPAINTSTRUCT, 4, 4); - TEST_TYPE_POINTER(LPPAINTSTRUCT, 64, 4); + TEST_TYPE_SIZE (LPPAINTSTRUCT, 4) + TEST_TYPE_ALIGN (LPPAINTSTRUCT, 4) + TEST_TARGET_SIZE (LPPAINTSTRUCT, 64) + TEST_TARGET_ALIGN(LPPAINTSTRUCT, 4) } static void test_pack_LPSCROLLINFO(void) { /* LPSCROLLINFO */ - TEST_TYPE(LPSCROLLINFO, 4, 4); - TEST_TYPE_POINTER(LPSCROLLINFO, 28, 4); + TEST_TYPE_SIZE (LPSCROLLINFO, 4) + TEST_TYPE_ALIGN (LPSCROLLINFO, 4) + TEST_TARGET_SIZE (LPSCROLLINFO, 28) + TEST_TARGET_ALIGN(LPSCROLLINFO, 4) } static void test_pack_LPSERIALKEYSA(void) { /* LPSERIALKEYSA */ - TEST_TYPE(LPSERIALKEYSA, 4, 4); - TEST_TYPE_POINTER(LPSERIALKEYSA, 28, 4); + TEST_TYPE_SIZE (LPSERIALKEYSA, 4) + TEST_TYPE_ALIGN (LPSERIALKEYSA, 4) + TEST_TARGET_SIZE (LPSERIALKEYSA, 28) + TEST_TARGET_ALIGN(LPSERIALKEYSA, 4) } static void test_pack_LPSERIALKEYSW(void) { /* LPSERIALKEYSW */ - TEST_TYPE(LPSERIALKEYSW, 4, 4); - TEST_TYPE_POINTER(LPSERIALKEYSW, 28, 4); + TEST_TYPE_SIZE (LPSERIALKEYSW, 4) + TEST_TYPE_ALIGN (LPSERIALKEYSW, 4) + TEST_TARGET_SIZE (LPSERIALKEYSW, 28) + TEST_TARGET_ALIGN(LPSERIALKEYSW, 4) } static void test_pack_LPSOUNDSENTRYA(void) { /* LPSOUNDSENTRYA */ - TEST_TYPE(LPSOUNDSENTRYA, 4, 4); - TEST_TYPE_POINTER(LPSOUNDSENTRYA, 48, 4); + TEST_TYPE_SIZE (LPSOUNDSENTRYA, 4) + TEST_TYPE_ALIGN (LPSOUNDSENTRYA, 4) + TEST_TARGET_SIZE (LPSOUNDSENTRYA, 48) + TEST_TARGET_ALIGN(LPSOUNDSENTRYA, 4) } static void test_pack_LPSOUNDSENTRYW(void) { /* LPSOUNDSENTRYW */ - TEST_TYPE(LPSOUNDSENTRYW, 4, 4); - TEST_TYPE_POINTER(LPSOUNDSENTRYW, 48, 4); + TEST_TYPE_SIZE (LPSOUNDSENTRYW, 4) + TEST_TYPE_ALIGN (LPSOUNDSENTRYW, 4) + TEST_TARGET_SIZE (LPSOUNDSENTRYW, 48) + TEST_TARGET_ALIGN(LPSOUNDSENTRYW, 4) } static void test_pack_LPSTICKYKEYS(void) { /* LPSTICKYKEYS */ - TEST_TYPE(LPSTICKYKEYS, 4, 4); - TEST_TYPE_POINTER(LPSTICKYKEYS, 8, 4); + TEST_TYPE_SIZE (LPSTICKYKEYS, 4) + TEST_TYPE_ALIGN (LPSTICKYKEYS, 4) + TEST_TARGET_SIZE (LPSTICKYKEYS, 8) + TEST_TARGET_ALIGN(LPSTICKYKEYS, 4) } static void test_pack_LPSTYLESTRUCT(void) { /* LPSTYLESTRUCT */ - TEST_TYPE(LPSTYLESTRUCT, 4, 4); - TEST_TYPE_POINTER(LPSTYLESTRUCT, 8, 4); + TEST_TYPE_SIZE (LPSTYLESTRUCT, 4) + TEST_TYPE_ALIGN (LPSTYLESTRUCT, 4) + TEST_TARGET_SIZE (LPSTYLESTRUCT, 8) + TEST_TARGET_ALIGN(LPSTYLESTRUCT, 4) } static void test_pack_LPTITLEBARINFO(void) { /* LPTITLEBARINFO */ - TEST_TYPE(LPTITLEBARINFO, 4, 4); - TEST_TYPE_POINTER(LPTITLEBARINFO, 44, 4); + TEST_TYPE_SIZE (LPTITLEBARINFO, 4) + TEST_TYPE_ALIGN (LPTITLEBARINFO, 4) + TEST_TARGET_SIZE (LPTITLEBARINFO, 44) + TEST_TARGET_ALIGN(LPTITLEBARINFO, 4) } static void test_pack_LPTOGGLEKEYS(void) { /* LPTOGGLEKEYS */ - TEST_TYPE(LPTOGGLEKEYS, 4, 4); - TEST_TYPE_POINTER(LPTOGGLEKEYS, 8, 4); + TEST_TYPE_SIZE (LPTOGGLEKEYS, 4) + TEST_TYPE_ALIGN (LPTOGGLEKEYS, 4) + TEST_TARGET_SIZE (LPTOGGLEKEYS, 8) + TEST_TARGET_ALIGN(LPTOGGLEKEYS, 4) } static void test_pack_LPTPMPARAMS(void) { /* LPTPMPARAMS */ - TEST_TYPE(LPTPMPARAMS, 4, 4); - TEST_TYPE_POINTER(LPTPMPARAMS, 20, 4); + TEST_TYPE_SIZE (LPTPMPARAMS, 4) + TEST_TYPE_ALIGN (LPTPMPARAMS, 4) + TEST_TARGET_SIZE (LPTPMPARAMS, 20) + TEST_TARGET_ALIGN(LPTPMPARAMS, 4) } static void test_pack_LPTRACKMOUSEEVENT(void) { /* LPTRACKMOUSEEVENT */ - TEST_TYPE(LPTRACKMOUSEEVENT, 4, 4); - TEST_TYPE_POINTER(LPTRACKMOUSEEVENT, 16, 4); + TEST_TYPE_SIZE (LPTRACKMOUSEEVENT, 4) + TEST_TYPE_ALIGN (LPTRACKMOUSEEVENT, 4) + TEST_TARGET_SIZE (LPTRACKMOUSEEVENT, 16) + TEST_TARGET_ALIGN(LPTRACKMOUSEEVENT, 4) } static void test_pack_LPWINDOWINFO(void) { /* LPWINDOWINFO */ - TEST_TYPE(LPWINDOWINFO, 4, 4); - TEST_TYPE_POINTER(LPWINDOWINFO, 60, 4); + TEST_TYPE_SIZE (LPWINDOWINFO, 4) + TEST_TYPE_ALIGN (LPWINDOWINFO, 4) + TEST_TARGET_SIZE (LPWINDOWINFO, 60) + TEST_TARGET_ALIGN(LPWINDOWINFO, 4) } static void test_pack_LPWINDOWPLACEMENT(void) { /* LPWINDOWPLACEMENT */ - TEST_TYPE(LPWINDOWPLACEMENT, 4, 4); - TEST_TYPE_POINTER(LPWINDOWPLACEMENT, 44, 4); + TEST_TYPE_SIZE (LPWINDOWPLACEMENT, 4) + TEST_TYPE_ALIGN (LPWINDOWPLACEMENT, 4) + TEST_TARGET_SIZE (LPWINDOWPLACEMENT, 44) + TEST_TARGET_ALIGN(LPWINDOWPLACEMENT, 4) } static void test_pack_LPWINDOWPOS(void) { /* LPWINDOWPOS */ - TEST_TYPE(LPWINDOWPOS, 4, 4); - TEST_TYPE_POINTER(LPWINDOWPOS, 28, 4); + TEST_TYPE_SIZE (LPWINDOWPOS, 4) + TEST_TYPE_ALIGN (LPWINDOWPOS, 4) + TEST_TARGET_SIZE (LPWINDOWPOS, 28) + TEST_TARGET_ALIGN(LPWINDOWPOS, 4) } static void test_pack_LPWNDCLASSA(void) { /* LPWNDCLASSA */ - TEST_TYPE(LPWNDCLASSA, 4, 4); - TEST_TYPE_POINTER(LPWNDCLASSA, 40, 4); + TEST_TYPE_SIZE (LPWNDCLASSA, 4) + TEST_TYPE_ALIGN (LPWNDCLASSA, 4) + TEST_TARGET_SIZE (LPWNDCLASSA, 40) + TEST_TARGET_ALIGN(LPWNDCLASSA, 4) } static void test_pack_LPWNDCLASSEXA(void) { /* LPWNDCLASSEXA */ - TEST_TYPE(LPWNDCLASSEXA, 4, 4); - TEST_TYPE_POINTER(LPWNDCLASSEXA, 48, 4); + TEST_TYPE_SIZE (LPWNDCLASSEXA, 4) + TEST_TYPE_ALIGN (LPWNDCLASSEXA, 4) + TEST_TARGET_SIZE (LPWNDCLASSEXA, 48) + TEST_TARGET_ALIGN(LPWNDCLASSEXA, 4) } static void test_pack_LPWNDCLASSEXW(void) { /* LPWNDCLASSEXW */ - TEST_TYPE(LPWNDCLASSEXW, 4, 4); - TEST_TYPE_POINTER(LPWNDCLASSEXW, 48, 4); + TEST_TYPE_SIZE (LPWNDCLASSEXW, 4) + TEST_TYPE_ALIGN (LPWNDCLASSEXW, 4) + TEST_TARGET_SIZE (LPWNDCLASSEXW, 48) + TEST_TARGET_ALIGN(LPWNDCLASSEXW, 4) } static void test_pack_LPWNDCLASSW(void) { /* LPWNDCLASSW */ - TEST_TYPE(LPWNDCLASSW, 4, 4); - TEST_TYPE_POINTER(LPWNDCLASSW, 40, 4); + TEST_TYPE_SIZE (LPWNDCLASSW, 4) + TEST_TYPE_ALIGN (LPWNDCLASSW, 4) + TEST_TARGET_SIZE (LPWNDCLASSW, 40) + TEST_TARGET_ALIGN(LPWNDCLASSW, 4) } static void test_pack_MDICREATESTRUCTA(void) { /* MDICREATESTRUCTA (pack 4) */ - TEST_TYPE(MDICREATESTRUCTA, 36, 4); - TEST_FIELD(MDICREATESTRUCTA, LPCSTR, szClass, 0, 4, 4); - TEST_FIELD(MDICREATESTRUCTA, LPCSTR, szTitle, 4, 4, 4); - TEST_FIELD(MDICREATESTRUCTA, HINSTANCE, hOwner, 8, 4, 4); - TEST_FIELD(MDICREATESTRUCTA, INT, x, 12, 4, 4); - TEST_FIELD(MDICREATESTRUCTA, INT, y, 16, 4, 4); - TEST_FIELD(MDICREATESTRUCTA, INT, cx, 20, 4, 4); - TEST_FIELD(MDICREATESTRUCTA, INT, cy, 24, 4, 4); - TEST_FIELD(MDICREATESTRUCTA, DWORD, style, 28, 4, 4); - TEST_FIELD(MDICREATESTRUCTA, LPARAM, lParam, 32, 4, 4); + TEST_TYPE_SIZE (MDICREATESTRUCTA, 36) + TEST_TYPE_ALIGN (MDICREATESTRUCTA, 4) + TEST_FIELD_SIZE (MDICREATESTRUCTA, szClass, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, szClass, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, szClass, 0) + TEST_FIELD_SIZE (MDICREATESTRUCTA, szTitle, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, szTitle, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, szTitle, 4) + TEST_FIELD_SIZE (MDICREATESTRUCTA, hOwner, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, hOwner, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, hOwner, 8) + TEST_FIELD_SIZE (MDICREATESTRUCTA, x, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, x, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, x, 12) + TEST_FIELD_SIZE (MDICREATESTRUCTA, y, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, y, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, y, 16) + TEST_FIELD_SIZE (MDICREATESTRUCTA, cx, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, cx, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, cx, 20) + TEST_FIELD_SIZE (MDICREATESTRUCTA, cy, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, cy, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, cy, 24) + TEST_FIELD_SIZE (MDICREATESTRUCTA, style, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, style, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, style, 28) + TEST_FIELD_SIZE (MDICREATESTRUCTA, lParam, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTA, lParam, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTA, lParam, 32) } static void test_pack_MDICREATESTRUCTW(void) { /* MDICREATESTRUCTW (pack 4) */ - TEST_TYPE(MDICREATESTRUCTW, 36, 4); - TEST_FIELD(MDICREATESTRUCTW, LPCWSTR, szClass, 0, 4, 4); - TEST_FIELD(MDICREATESTRUCTW, LPCWSTR, szTitle, 4, 4, 4); - TEST_FIELD(MDICREATESTRUCTW, HINSTANCE, hOwner, 8, 4, 4); - TEST_FIELD(MDICREATESTRUCTW, INT, x, 12, 4, 4); - TEST_FIELD(MDICREATESTRUCTW, INT, y, 16, 4, 4); - TEST_FIELD(MDICREATESTRUCTW, INT, cx, 20, 4, 4); - TEST_FIELD(MDICREATESTRUCTW, INT, cy, 24, 4, 4); - TEST_FIELD(MDICREATESTRUCTW, DWORD, style, 28, 4, 4); - TEST_FIELD(MDICREATESTRUCTW, LPARAM, lParam, 32, 4, 4); + TEST_TYPE_SIZE (MDICREATESTRUCTW, 36) + TEST_TYPE_ALIGN (MDICREATESTRUCTW, 4) + TEST_FIELD_SIZE (MDICREATESTRUCTW, szClass, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, szClass, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, szClass, 0) + TEST_FIELD_SIZE (MDICREATESTRUCTW, szTitle, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, szTitle, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, szTitle, 4) + TEST_FIELD_SIZE (MDICREATESTRUCTW, hOwner, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, hOwner, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, hOwner, 8) + TEST_FIELD_SIZE (MDICREATESTRUCTW, x, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, x, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, x, 12) + TEST_FIELD_SIZE (MDICREATESTRUCTW, y, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, y, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, y, 16) + TEST_FIELD_SIZE (MDICREATESTRUCTW, cx, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, cx, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, cx, 20) + TEST_FIELD_SIZE (MDICREATESTRUCTW, cy, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, cy, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, cy, 24) + TEST_FIELD_SIZE (MDICREATESTRUCTW, style, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, style, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, style, 28) + TEST_FIELD_SIZE (MDICREATESTRUCTW, lParam, 4) + TEST_FIELD_ALIGN (MDICREATESTRUCTW, lParam, 4) + TEST_FIELD_OFFSET(MDICREATESTRUCTW, lParam, 32) } static void test_pack_MDINEXTMENU(void) { /* MDINEXTMENU (pack 4) */ - TEST_TYPE(MDINEXTMENU, 12, 4); - TEST_FIELD(MDINEXTMENU, HMENU, hmenuIn, 0, 4, 4); - TEST_FIELD(MDINEXTMENU, HMENU, hmenuNext, 4, 4, 4); - TEST_FIELD(MDINEXTMENU, HWND, hwndNext, 8, 4, 4); + TEST_TYPE_SIZE (MDINEXTMENU, 12) + TEST_TYPE_ALIGN (MDINEXTMENU, 4) + TEST_FIELD_SIZE (MDINEXTMENU, hmenuIn, 4) + TEST_FIELD_ALIGN (MDINEXTMENU, hmenuIn, 4) + TEST_FIELD_OFFSET(MDINEXTMENU, hmenuIn, 0) + TEST_FIELD_SIZE (MDINEXTMENU, hmenuNext, 4) + TEST_FIELD_ALIGN (MDINEXTMENU, hmenuNext, 4) + TEST_FIELD_OFFSET(MDINEXTMENU, hmenuNext, 4) + TEST_FIELD_SIZE (MDINEXTMENU, hwndNext, 4) + TEST_FIELD_ALIGN (MDINEXTMENU, hwndNext, 4) + TEST_FIELD_OFFSET(MDINEXTMENU, hwndNext, 8) } static void test_pack_MEASUREITEMSTRUCT(void) { /* MEASUREITEMSTRUCT (pack 4) */ - TEST_TYPE(MEASUREITEMSTRUCT, 24, 4); - TEST_FIELD(MEASUREITEMSTRUCT, UINT, CtlType, 0, 4, 4); - TEST_FIELD(MEASUREITEMSTRUCT, UINT, CtlID, 4, 4, 4); - TEST_FIELD(MEASUREITEMSTRUCT, UINT, itemID, 8, 4, 4); - TEST_FIELD(MEASUREITEMSTRUCT, UINT, itemWidth, 12, 4, 4); - TEST_FIELD(MEASUREITEMSTRUCT, UINT, itemHeight, 16, 4, 4); - TEST_FIELD(MEASUREITEMSTRUCT, ULONG_PTR, itemData, 20, 4, 4); + TEST_TYPE_SIZE (MEASUREITEMSTRUCT, 24) + TEST_TYPE_ALIGN (MEASUREITEMSTRUCT, 4) + TEST_FIELD_SIZE (MEASUREITEMSTRUCT, CtlType, 4) + TEST_FIELD_ALIGN (MEASUREITEMSTRUCT, CtlType, 4) + TEST_FIELD_OFFSET(MEASUREITEMSTRUCT, CtlType, 0) + TEST_FIELD_SIZE (MEASUREITEMSTRUCT, CtlID, 4) + TEST_FIELD_ALIGN (MEASUREITEMSTRUCT, CtlID, 4) + TEST_FIELD_OFFSET(MEASUREITEMSTRUCT, CtlID, 4) + TEST_FIELD_SIZE (MEASUREITEMSTRUCT, itemID, 4) + TEST_FIELD_ALIGN (MEASUREITEMSTRUCT, itemID, 4) + TEST_FIELD_OFFSET(MEASUREITEMSTRUCT, itemID, 8) + TEST_FIELD_SIZE (MEASUREITEMSTRUCT, itemWidth, 4) + TEST_FIELD_ALIGN (MEASUREITEMSTRUCT, itemWidth, 4) + TEST_FIELD_OFFSET(MEASUREITEMSTRUCT, itemWidth, 12) + TEST_FIELD_SIZE (MEASUREITEMSTRUCT, itemHeight, 4) + TEST_FIELD_ALIGN (MEASUREITEMSTRUCT, itemHeight, 4) + TEST_FIELD_OFFSET(MEASUREITEMSTRUCT, itemHeight, 16) + TEST_FIELD_SIZE (MEASUREITEMSTRUCT, itemData, 4) + TEST_FIELD_ALIGN (MEASUREITEMSTRUCT, itemData, 4) + TEST_FIELD_OFFSET(MEASUREITEMSTRUCT, itemData, 20) } static void test_pack_MENUINFO(void) { /* MENUINFO (pack 4) */ - TEST_TYPE(MENUINFO, 28, 4); - TEST_FIELD(MENUINFO, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(MENUINFO, DWORD, fMask, 4, 4, 4); - TEST_FIELD(MENUINFO, DWORD, dwStyle, 8, 4, 4); - TEST_FIELD(MENUINFO, UINT, cyMax, 12, 4, 4); - TEST_FIELD(MENUINFO, HBRUSH, hbrBack, 16, 4, 4); - TEST_FIELD(MENUINFO, DWORD, dwContextHelpID, 20, 4, 4); - TEST_FIELD(MENUINFO, ULONG_PTR, dwMenuData, 24, 4, 4); + TEST_TYPE_SIZE (MENUINFO, 28) + TEST_TYPE_ALIGN (MENUINFO, 4) + TEST_FIELD_SIZE (MENUINFO, cbSize, 4) + TEST_FIELD_ALIGN (MENUINFO, cbSize, 4) + TEST_FIELD_OFFSET(MENUINFO, cbSize, 0) + TEST_FIELD_SIZE (MENUINFO, fMask, 4) + TEST_FIELD_ALIGN (MENUINFO, fMask, 4) + TEST_FIELD_OFFSET(MENUINFO, fMask, 4) + TEST_FIELD_SIZE (MENUINFO, dwStyle, 4) + TEST_FIELD_ALIGN (MENUINFO, dwStyle, 4) + TEST_FIELD_OFFSET(MENUINFO, dwStyle, 8) + TEST_FIELD_SIZE (MENUINFO, cyMax, 4) + TEST_FIELD_ALIGN (MENUINFO, cyMax, 4) + TEST_FIELD_OFFSET(MENUINFO, cyMax, 12) + TEST_FIELD_SIZE (MENUINFO, hbrBack, 4) + TEST_FIELD_ALIGN (MENUINFO, hbrBack, 4) + TEST_FIELD_OFFSET(MENUINFO, hbrBack, 16) + TEST_FIELD_SIZE (MENUINFO, dwContextHelpID, 4) + TEST_FIELD_ALIGN (MENUINFO, dwContextHelpID, 4) + TEST_FIELD_OFFSET(MENUINFO, dwContextHelpID, 20) + TEST_FIELD_SIZE (MENUINFO, dwMenuData, 4) + TEST_FIELD_ALIGN (MENUINFO, dwMenuData, 4) + TEST_FIELD_OFFSET(MENUINFO, dwMenuData, 24) } static void test_pack_MENUITEMINFOA(void) { /* MENUITEMINFOA (pack 4) */ - TEST_TYPE(MENUITEMINFOA, 48, 4); - TEST_FIELD(MENUITEMINFOA, UINT, cbSize, 0, 4, 4); - TEST_FIELD(MENUITEMINFOA, UINT, fMask, 4, 4, 4); - TEST_FIELD(MENUITEMINFOA, UINT, fType, 8, 4, 4); - TEST_FIELD(MENUITEMINFOA, UINT, fState, 12, 4, 4); - TEST_FIELD(MENUITEMINFOA, UINT, wID, 16, 4, 4); - TEST_FIELD(MENUITEMINFOA, HMENU, hSubMenu, 20, 4, 4); - TEST_FIELD(MENUITEMINFOA, HBITMAP, hbmpChecked, 24, 4, 4); - TEST_FIELD(MENUITEMINFOA, HBITMAP, hbmpUnchecked, 28, 4, 4); - TEST_FIELD(MENUITEMINFOA, ULONG_PTR, dwItemData, 32, 4, 4); - TEST_FIELD(MENUITEMINFOA, LPSTR, dwTypeData, 36, 4, 4); - TEST_FIELD(MENUITEMINFOA, UINT, cch, 40, 4, 4); - TEST_FIELD(MENUITEMINFOA, HBITMAP, hbmpItem, 44, 4, 4); + TEST_TYPE_SIZE (MENUITEMINFOA, 48) + TEST_TYPE_ALIGN (MENUITEMINFOA, 4) + TEST_FIELD_SIZE (MENUITEMINFOA, cbSize, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, cbSize, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, cbSize, 0) + TEST_FIELD_SIZE (MENUITEMINFOA, fMask, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, fMask, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, fMask, 4) + TEST_FIELD_SIZE (MENUITEMINFOA, fType, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, fType, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, fType, 8) + TEST_FIELD_SIZE (MENUITEMINFOA, fState, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, fState, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, fState, 12) + TEST_FIELD_SIZE (MENUITEMINFOA, wID, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, wID, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, wID, 16) + TEST_FIELD_SIZE (MENUITEMINFOA, hSubMenu, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, hSubMenu, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, hSubMenu, 20) + TEST_FIELD_SIZE (MENUITEMINFOA, hbmpChecked, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, hbmpChecked, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, hbmpChecked, 24) + TEST_FIELD_SIZE (MENUITEMINFOA, hbmpUnchecked, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, hbmpUnchecked, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, hbmpUnchecked, 28) + TEST_FIELD_SIZE (MENUITEMINFOA, dwItemData, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, dwItemData, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, dwItemData, 32) + TEST_FIELD_SIZE (MENUITEMINFOA, dwTypeData, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, dwTypeData, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, dwTypeData, 36) + TEST_FIELD_SIZE (MENUITEMINFOA, cch, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, cch, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, cch, 40) + TEST_FIELD_SIZE (MENUITEMINFOA, hbmpItem, 4) + TEST_FIELD_ALIGN (MENUITEMINFOA, hbmpItem, 4) + TEST_FIELD_OFFSET(MENUITEMINFOA, hbmpItem, 44) } static void test_pack_MENUITEMINFOW(void) { /* MENUITEMINFOW (pack 4) */ - TEST_TYPE(MENUITEMINFOW, 48, 4); - TEST_FIELD(MENUITEMINFOW, UINT, cbSize, 0, 4, 4); - TEST_FIELD(MENUITEMINFOW, UINT, fMask, 4, 4, 4); - TEST_FIELD(MENUITEMINFOW, UINT, fType, 8, 4, 4); - TEST_FIELD(MENUITEMINFOW, UINT, fState, 12, 4, 4); - TEST_FIELD(MENUITEMINFOW, UINT, wID, 16, 4, 4); - TEST_FIELD(MENUITEMINFOW, HMENU, hSubMenu, 20, 4, 4); - TEST_FIELD(MENUITEMINFOW, HBITMAP, hbmpChecked, 24, 4, 4); - TEST_FIELD(MENUITEMINFOW, HBITMAP, hbmpUnchecked, 28, 4, 4); - TEST_FIELD(MENUITEMINFOW, ULONG_PTR, dwItemData, 32, 4, 4); - TEST_FIELD(MENUITEMINFOW, LPWSTR, dwTypeData, 36, 4, 4); - TEST_FIELD(MENUITEMINFOW, UINT, cch, 40, 4, 4); - TEST_FIELD(MENUITEMINFOW, HBITMAP, hbmpItem, 44, 4, 4); + TEST_TYPE_SIZE (MENUITEMINFOW, 48) + TEST_TYPE_ALIGN (MENUITEMINFOW, 4) + TEST_FIELD_SIZE (MENUITEMINFOW, cbSize, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, cbSize, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, cbSize, 0) + TEST_FIELD_SIZE (MENUITEMINFOW, fMask, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, fMask, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, fMask, 4) + TEST_FIELD_SIZE (MENUITEMINFOW, fType, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, fType, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, fType, 8) + TEST_FIELD_SIZE (MENUITEMINFOW, fState, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, fState, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, fState, 12) + TEST_FIELD_SIZE (MENUITEMINFOW, wID, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, wID, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, wID, 16) + TEST_FIELD_SIZE (MENUITEMINFOW, hSubMenu, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, hSubMenu, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, hSubMenu, 20) + TEST_FIELD_SIZE (MENUITEMINFOW, hbmpChecked, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, hbmpChecked, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, hbmpChecked, 24) + TEST_FIELD_SIZE (MENUITEMINFOW, hbmpUnchecked, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, hbmpUnchecked, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, hbmpUnchecked, 28) + TEST_FIELD_SIZE (MENUITEMINFOW, dwItemData, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, dwItemData, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, dwItemData, 32) + TEST_FIELD_SIZE (MENUITEMINFOW, dwTypeData, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, dwTypeData, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, dwTypeData, 36) + TEST_FIELD_SIZE (MENUITEMINFOW, cch, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, cch, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, cch, 40) + TEST_FIELD_SIZE (MENUITEMINFOW, hbmpItem, 4) + TEST_FIELD_ALIGN (MENUITEMINFOW, hbmpItem, 4) + TEST_FIELD_OFFSET(MENUITEMINFOW, hbmpItem, 44) } static void test_pack_MENUITEMTEMPLATE(void) { /* MENUITEMTEMPLATE (pack 4) */ - TEST_TYPE(MENUITEMTEMPLATE, 6, 2); - TEST_FIELD(MENUITEMTEMPLATE, WORD, mtOption, 0, 2, 2); - TEST_FIELD(MENUITEMTEMPLATE, WORD, mtID, 2, 2, 2); - TEST_FIELD(MENUITEMTEMPLATE, WCHAR[1], mtString, 4, 2, 2); + TEST_TYPE_SIZE (MENUITEMTEMPLATE, 6) + TEST_TYPE_ALIGN (MENUITEMTEMPLATE, 2) + TEST_FIELD_SIZE (MENUITEMTEMPLATE, mtOption, 2) + TEST_FIELD_ALIGN (MENUITEMTEMPLATE, mtOption, 2) + TEST_FIELD_OFFSET(MENUITEMTEMPLATE, mtOption, 0) + TEST_FIELD_SIZE (MENUITEMTEMPLATE, mtID, 2) + TEST_FIELD_ALIGN (MENUITEMTEMPLATE, mtID, 2) + TEST_FIELD_OFFSET(MENUITEMTEMPLATE, mtID, 2) + TEST_FIELD_SIZE (MENUITEMTEMPLATE, mtString, 2) + TEST_FIELD_ALIGN (MENUITEMTEMPLATE, mtString, 2) + TEST_FIELD_OFFSET(MENUITEMTEMPLATE, mtString, 4) } static void test_pack_MENUITEMTEMPLATEHEADER(void) { /* MENUITEMTEMPLATEHEADER (pack 4) */ - TEST_TYPE(MENUITEMTEMPLATEHEADER, 4, 2); - TEST_FIELD(MENUITEMTEMPLATEHEADER, WORD, versionNumber, 0, 2, 2); - TEST_FIELD(MENUITEMTEMPLATEHEADER, WORD, offset, 2, 2, 2); + TEST_TYPE_SIZE (MENUITEMTEMPLATEHEADER, 4) + TEST_TYPE_ALIGN (MENUITEMTEMPLATEHEADER, 2) + TEST_FIELD_SIZE (MENUITEMTEMPLATEHEADER, versionNumber, 2) + TEST_FIELD_ALIGN (MENUITEMTEMPLATEHEADER, versionNumber, 2) + TEST_FIELD_OFFSET(MENUITEMTEMPLATEHEADER, versionNumber, 0) + TEST_FIELD_SIZE (MENUITEMTEMPLATEHEADER, offset, 2) + TEST_FIELD_ALIGN (MENUITEMTEMPLATEHEADER, offset, 2) + TEST_FIELD_OFFSET(MENUITEMTEMPLATEHEADER, offset, 2) } static void test_pack_MINIMIZEDMETRICS(void) { /* MINIMIZEDMETRICS (pack 4) */ - TEST_TYPE(MINIMIZEDMETRICS, 20, 4); - TEST_FIELD(MINIMIZEDMETRICS, UINT, cbSize, 0, 4, 4); - TEST_FIELD(MINIMIZEDMETRICS, int, iWidth, 4, 4, 4); - TEST_FIELD(MINIMIZEDMETRICS, int, iHorzGap, 8, 4, 4); - TEST_FIELD(MINIMIZEDMETRICS, int, iVertGap, 12, 4, 4); - TEST_FIELD(MINIMIZEDMETRICS, int, iArrange, 16, 4, 4); + TEST_TYPE_SIZE (MINIMIZEDMETRICS, 20) + TEST_TYPE_ALIGN (MINIMIZEDMETRICS, 4) + TEST_FIELD_SIZE (MINIMIZEDMETRICS, cbSize, 4) + TEST_FIELD_ALIGN (MINIMIZEDMETRICS, cbSize, 4) + TEST_FIELD_OFFSET(MINIMIZEDMETRICS, cbSize, 0) + TEST_FIELD_SIZE (MINIMIZEDMETRICS, iWidth, 4) + TEST_FIELD_ALIGN (MINIMIZEDMETRICS, iWidth, 4) + TEST_FIELD_OFFSET(MINIMIZEDMETRICS, iWidth, 4) + TEST_FIELD_SIZE (MINIMIZEDMETRICS, iHorzGap, 4) + TEST_FIELD_ALIGN (MINIMIZEDMETRICS, iHorzGap, 4) + TEST_FIELD_OFFSET(MINIMIZEDMETRICS, iHorzGap, 8) + TEST_FIELD_SIZE (MINIMIZEDMETRICS, iVertGap, 4) + TEST_FIELD_ALIGN (MINIMIZEDMETRICS, iVertGap, 4) + TEST_FIELD_OFFSET(MINIMIZEDMETRICS, iVertGap, 12) + TEST_FIELD_SIZE (MINIMIZEDMETRICS, iArrange, 4) + TEST_FIELD_ALIGN (MINIMIZEDMETRICS, iArrange, 4) + TEST_FIELD_OFFSET(MINIMIZEDMETRICS, iArrange, 16) } static void test_pack_MINMAXINFO(void) { /* MINMAXINFO (pack 4) */ - TEST_TYPE(MINMAXINFO, 40, 4); - TEST_FIELD(MINMAXINFO, POINT, ptReserved, 0, 8, 4); - TEST_FIELD(MINMAXINFO, POINT, ptMaxSize, 8, 8, 4); - TEST_FIELD(MINMAXINFO, POINT, ptMaxPosition, 16, 8, 4); - TEST_FIELD(MINMAXINFO, POINT, ptMinTrackSize, 24, 8, 4); - TEST_FIELD(MINMAXINFO, POINT, ptMaxTrackSize, 32, 8, 4); + TEST_TYPE_SIZE (MINMAXINFO, 40) + TEST_TYPE_ALIGN (MINMAXINFO, 4) + TEST_FIELD_SIZE (MINMAXINFO, ptReserved, 8) + TEST_FIELD_ALIGN (MINMAXINFO, ptReserved, 4) + TEST_FIELD_OFFSET(MINMAXINFO, ptReserved, 0) + TEST_FIELD_SIZE (MINMAXINFO, ptMaxSize, 8) + TEST_FIELD_ALIGN (MINMAXINFO, ptMaxSize, 4) + TEST_FIELD_OFFSET(MINMAXINFO, ptMaxSize, 8) + TEST_FIELD_SIZE (MINMAXINFO, ptMaxPosition, 8) + TEST_FIELD_ALIGN (MINMAXINFO, ptMaxPosition, 4) + TEST_FIELD_OFFSET(MINMAXINFO, ptMaxPosition, 16) + TEST_FIELD_SIZE (MINMAXINFO, ptMinTrackSize, 8) + TEST_FIELD_ALIGN (MINMAXINFO, ptMinTrackSize, 4) + TEST_FIELD_OFFSET(MINMAXINFO, ptMinTrackSize, 24) + TEST_FIELD_SIZE (MINMAXINFO, ptMaxTrackSize, 8) + TEST_FIELD_ALIGN (MINMAXINFO, ptMaxTrackSize, 4) + TEST_FIELD_OFFSET(MINMAXINFO, ptMaxTrackSize, 32) } static void test_pack_MONITORENUMPROC(void) { /* MONITORENUMPROC */ - TEST_TYPE(MONITORENUMPROC, 4, 4); + TEST_TYPE_SIZE (MONITORENUMPROC, 4) + TEST_TYPE_ALIGN (MONITORENUMPROC, 4) } static void test_pack_MONITORINFO(void) { /* MONITORINFO (pack 4) */ - TEST_TYPE(MONITORINFO, 40, 4); - TEST_FIELD(MONITORINFO, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(MONITORINFO, RECT, rcMonitor, 4, 16, 4); - TEST_FIELD(MONITORINFO, RECT, rcWork, 20, 16, 4); - TEST_FIELD(MONITORINFO, DWORD, dwFlags, 36, 4, 4); + TEST_TYPE_SIZE (MONITORINFO, 40) + TEST_TYPE_ALIGN (MONITORINFO, 4) + TEST_FIELD_SIZE (MONITORINFO, cbSize, 4) + TEST_FIELD_ALIGN (MONITORINFO, cbSize, 4) + TEST_FIELD_OFFSET(MONITORINFO, cbSize, 0) + TEST_FIELD_SIZE (MONITORINFO, rcMonitor, 16) + TEST_FIELD_ALIGN (MONITORINFO, rcMonitor, 4) + TEST_FIELD_OFFSET(MONITORINFO, rcMonitor, 4) + TEST_FIELD_SIZE (MONITORINFO, rcWork, 16) + TEST_FIELD_ALIGN (MONITORINFO, rcWork, 4) + TEST_FIELD_OFFSET(MONITORINFO, rcWork, 20) + TEST_FIELD_SIZE (MONITORINFO, dwFlags, 4) + TEST_FIELD_ALIGN (MONITORINFO, dwFlags, 4) + TEST_FIELD_OFFSET(MONITORINFO, dwFlags, 36) } static void test_pack_MONITORINFOEXA(void) { /* MONITORINFOEXA (pack 4) */ - TEST_TYPE(MONITORINFOEXA, 72, 4); - TEST_FIELD(MONITORINFOEXA, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(MONITORINFOEXA, RECT, rcMonitor, 4, 16, 4); - TEST_FIELD(MONITORINFOEXA, RECT, rcWork, 20, 16, 4); - TEST_FIELD(MONITORINFOEXA, DWORD, dwFlags, 36, 4, 4); - TEST_FIELD(MONITORINFOEXA, CHAR[CCHDEVICENAME], szDevice, 40, 32, 1); + TEST_TYPE_SIZE (MONITORINFOEXA, 72) + TEST_TYPE_ALIGN (MONITORINFOEXA, 4) + TEST_FIELD_SIZE (MONITORINFOEXA, cbSize, 4) + TEST_FIELD_ALIGN (MONITORINFOEXA, cbSize, 4) + TEST_FIELD_OFFSET(MONITORINFOEXA, cbSize, 0) + TEST_FIELD_SIZE (MONITORINFOEXA, rcMonitor, 16) + TEST_FIELD_ALIGN (MONITORINFOEXA, rcMonitor, 4) + TEST_FIELD_OFFSET(MONITORINFOEXA, rcMonitor, 4) + TEST_FIELD_SIZE (MONITORINFOEXA, rcWork, 16) + TEST_FIELD_ALIGN (MONITORINFOEXA, rcWork, 4) + TEST_FIELD_OFFSET(MONITORINFOEXA, rcWork, 20) + TEST_FIELD_SIZE (MONITORINFOEXA, dwFlags, 4) + TEST_FIELD_ALIGN (MONITORINFOEXA, dwFlags, 4) + TEST_FIELD_OFFSET(MONITORINFOEXA, dwFlags, 36) + TEST_FIELD_SIZE (MONITORINFOEXA, szDevice, 32) + TEST_FIELD_ALIGN (MONITORINFOEXA, szDevice, 1) + TEST_FIELD_OFFSET(MONITORINFOEXA, szDevice, 40) } static void test_pack_MONITORINFOEXW(void) { /* MONITORINFOEXW (pack 4) */ - TEST_TYPE(MONITORINFOEXW, 104, 4); - TEST_FIELD(MONITORINFOEXW, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(MONITORINFOEXW, RECT, rcMonitor, 4, 16, 4); - TEST_FIELD(MONITORINFOEXW, RECT, rcWork, 20, 16, 4); - TEST_FIELD(MONITORINFOEXW, DWORD, dwFlags, 36, 4, 4); - TEST_FIELD(MONITORINFOEXW, WCHAR[CCHDEVICENAME], szDevice, 40, 64, 2); + TEST_TYPE_SIZE (MONITORINFOEXW, 104) + TEST_TYPE_ALIGN (MONITORINFOEXW, 4) + TEST_FIELD_SIZE (MONITORINFOEXW, cbSize, 4) + TEST_FIELD_ALIGN (MONITORINFOEXW, cbSize, 4) + TEST_FIELD_OFFSET(MONITORINFOEXW, cbSize, 0) + TEST_FIELD_SIZE (MONITORINFOEXW, rcMonitor, 16) + TEST_FIELD_ALIGN (MONITORINFOEXW, rcMonitor, 4) + TEST_FIELD_OFFSET(MONITORINFOEXW, rcMonitor, 4) + TEST_FIELD_SIZE (MONITORINFOEXW, rcWork, 16) + TEST_FIELD_ALIGN (MONITORINFOEXW, rcWork, 4) + TEST_FIELD_OFFSET(MONITORINFOEXW, rcWork, 20) + TEST_FIELD_SIZE (MONITORINFOEXW, dwFlags, 4) + TEST_FIELD_ALIGN (MONITORINFOEXW, dwFlags, 4) + TEST_FIELD_OFFSET(MONITORINFOEXW, dwFlags, 36) + TEST_FIELD_SIZE (MONITORINFOEXW, szDevice, 64) + TEST_FIELD_ALIGN (MONITORINFOEXW, szDevice, 2) + TEST_FIELD_OFFSET(MONITORINFOEXW, szDevice, 40) } static void test_pack_MOUSEHOOKSTRUCT(void) { /* MOUSEHOOKSTRUCT (pack 4) */ - TEST_TYPE(MOUSEHOOKSTRUCT, 20, 4); - TEST_FIELD(MOUSEHOOKSTRUCT, POINT, pt, 0, 8, 4); - TEST_FIELD(MOUSEHOOKSTRUCT, HWND, hwnd, 8, 4, 4); - TEST_FIELD(MOUSEHOOKSTRUCT, UINT, wHitTestCode, 12, 4, 4); - TEST_FIELD(MOUSEHOOKSTRUCT, ULONG_PTR, dwExtraInfo, 16, 4, 4); + TEST_TYPE_SIZE (MOUSEHOOKSTRUCT, 20) + TEST_TYPE_ALIGN (MOUSEHOOKSTRUCT, 4) + TEST_FIELD_SIZE (MOUSEHOOKSTRUCT, pt, 8) + TEST_FIELD_ALIGN (MOUSEHOOKSTRUCT, pt, 4) + TEST_FIELD_OFFSET(MOUSEHOOKSTRUCT, pt, 0) + TEST_FIELD_SIZE (MOUSEHOOKSTRUCT, hwnd, 4) + TEST_FIELD_ALIGN (MOUSEHOOKSTRUCT, hwnd, 4) + TEST_FIELD_OFFSET(MOUSEHOOKSTRUCT, hwnd, 8) + TEST_FIELD_SIZE (MOUSEHOOKSTRUCT, wHitTestCode, 4) + TEST_FIELD_ALIGN (MOUSEHOOKSTRUCT, wHitTestCode, 4) + TEST_FIELD_OFFSET(MOUSEHOOKSTRUCT, wHitTestCode, 12) + TEST_FIELD_SIZE (MOUSEHOOKSTRUCT, dwExtraInfo, 4) + TEST_FIELD_ALIGN (MOUSEHOOKSTRUCT, dwExtraInfo, 4) + TEST_FIELD_OFFSET(MOUSEHOOKSTRUCT, dwExtraInfo, 16) } static void test_pack_MOUSEINPUT(void) { /* MOUSEINPUT (pack 4) */ - TEST_TYPE(MOUSEINPUT, 24, 4); - TEST_FIELD(MOUSEINPUT, LONG, dx, 0, 4, 4); - TEST_FIELD(MOUSEINPUT, LONG, dy, 4, 4, 4); - TEST_FIELD(MOUSEINPUT, DWORD, mouseData, 8, 4, 4); - TEST_FIELD(MOUSEINPUT, DWORD, dwFlags, 12, 4, 4); - TEST_FIELD(MOUSEINPUT, DWORD, time, 16, 4, 4); - TEST_FIELD(MOUSEINPUT, ULONG_PTR, dwExtraInfo, 20, 4, 4); + TEST_TYPE_SIZE (MOUSEINPUT, 24) + TEST_TYPE_ALIGN (MOUSEINPUT, 4) + TEST_FIELD_SIZE (MOUSEINPUT, dx, 4) + TEST_FIELD_ALIGN (MOUSEINPUT, dx, 4) + TEST_FIELD_OFFSET(MOUSEINPUT, dx, 0) + TEST_FIELD_SIZE (MOUSEINPUT, dy, 4) + TEST_FIELD_ALIGN (MOUSEINPUT, dy, 4) + TEST_FIELD_OFFSET(MOUSEINPUT, dy, 4) + TEST_FIELD_SIZE (MOUSEINPUT, mouseData, 4) + TEST_FIELD_ALIGN (MOUSEINPUT, mouseData, 4) + TEST_FIELD_OFFSET(MOUSEINPUT, mouseData, 8) + TEST_FIELD_SIZE (MOUSEINPUT, dwFlags, 4) + TEST_FIELD_ALIGN (MOUSEINPUT, dwFlags, 4) + TEST_FIELD_OFFSET(MOUSEINPUT, dwFlags, 12) + TEST_FIELD_SIZE (MOUSEINPUT, time, 4) + TEST_FIELD_ALIGN (MOUSEINPUT, time, 4) + TEST_FIELD_OFFSET(MOUSEINPUT, time, 16) + TEST_FIELD_SIZE (MOUSEINPUT, dwExtraInfo, 4) + TEST_FIELD_ALIGN (MOUSEINPUT, dwExtraInfo, 4) + TEST_FIELD_OFFSET(MOUSEINPUT, dwExtraInfo, 20) } static void test_pack_MOUSEKEYS(void) { /* MOUSEKEYS (pack 4) */ - TEST_TYPE(MOUSEKEYS, 28, 4); - TEST_FIELD(MOUSEKEYS, UINT, cbSize, 0, 4, 4); - TEST_FIELD(MOUSEKEYS, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(MOUSEKEYS, DWORD, iMaxSpeed, 8, 4, 4); - TEST_FIELD(MOUSEKEYS, DWORD, iTimeToMaxSpeed, 12, 4, 4); - TEST_FIELD(MOUSEKEYS, DWORD, iCtrlSpeed, 16, 4, 4); - TEST_FIELD(MOUSEKEYS, DWORD, dwReserved1, 20, 4, 4); - TEST_FIELD(MOUSEKEYS, DWORD, dwReserved2, 24, 4, 4); + TEST_TYPE_SIZE (MOUSEKEYS, 28) + TEST_TYPE_ALIGN (MOUSEKEYS, 4) + TEST_FIELD_SIZE (MOUSEKEYS, cbSize, 4) + TEST_FIELD_ALIGN (MOUSEKEYS, cbSize, 4) + TEST_FIELD_OFFSET(MOUSEKEYS, cbSize, 0) + TEST_FIELD_SIZE (MOUSEKEYS, dwFlags, 4) + TEST_FIELD_ALIGN (MOUSEKEYS, dwFlags, 4) + TEST_FIELD_OFFSET(MOUSEKEYS, dwFlags, 4) + TEST_FIELD_SIZE (MOUSEKEYS, iMaxSpeed, 4) + TEST_FIELD_ALIGN (MOUSEKEYS, iMaxSpeed, 4) + TEST_FIELD_OFFSET(MOUSEKEYS, iMaxSpeed, 8) + TEST_FIELD_SIZE (MOUSEKEYS, iTimeToMaxSpeed, 4) + TEST_FIELD_ALIGN (MOUSEKEYS, iTimeToMaxSpeed, 4) + TEST_FIELD_OFFSET(MOUSEKEYS, iTimeToMaxSpeed, 12) + TEST_FIELD_SIZE (MOUSEKEYS, iCtrlSpeed, 4) + TEST_FIELD_ALIGN (MOUSEKEYS, iCtrlSpeed, 4) + TEST_FIELD_OFFSET(MOUSEKEYS, iCtrlSpeed, 16) + TEST_FIELD_SIZE (MOUSEKEYS, dwReserved1, 4) + TEST_FIELD_ALIGN (MOUSEKEYS, dwReserved1, 4) + TEST_FIELD_OFFSET(MOUSEKEYS, dwReserved1, 20) + TEST_FIELD_SIZE (MOUSEKEYS, dwReserved2, 4) + TEST_FIELD_ALIGN (MOUSEKEYS, dwReserved2, 4) + TEST_FIELD_OFFSET(MOUSEKEYS, dwReserved2, 24) } static void test_pack_MSG(void) { /* MSG (pack 4) */ - TEST_TYPE(MSG, 28, 4); - TEST_FIELD(MSG, HWND, hwnd, 0, 4, 4); - TEST_FIELD(MSG, UINT, message, 4, 4, 4); - TEST_FIELD(MSG, WPARAM, wParam, 8, 4, 4); - TEST_FIELD(MSG, LPARAM, lParam, 12, 4, 4); - TEST_FIELD(MSG, DWORD, time, 16, 4, 4); - TEST_FIELD(MSG, POINT, pt, 20, 8, 4); + TEST_TYPE_SIZE (MSG, 28) + TEST_TYPE_ALIGN (MSG, 4) + TEST_FIELD_SIZE (MSG, hwnd, 4) + TEST_FIELD_ALIGN (MSG, hwnd, 4) + TEST_FIELD_OFFSET(MSG, hwnd, 0) + TEST_FIELD_SIZE (MSG, message, 4) + TEST_FIELD_ALIGN (MSG, message, 4) + TEST_FIELD_OFFSET(MSG, message, 4) + TEST_FIELD_SIZE (MSG, wParam, 4) + TEST_FIELD_ALIGN (MSG, wParam, 4) + TEST_FIELD_OFFSET(MSG, wParam, 8) + TEST_FIELD_SIZE (MSG, lParam, 4) + TEST_FIELD_ALIGN (MSG, lParam, 4) + TEST_FIELD_OFFSET(MSG, lParam, 12) + TEST_FIELD_SIZE (MSG, time, 4) + TEST_FIELD_ALIGN (MSG, time, 4) + TEST_FIELD_OFFSET(MSG, time, 16) + TEST_FIELD_SIZE (MSG, pt, 8) + TEST_FIELD_ALIGN (MSG, pt, 4) + TEST_FIELD_OFFSET(MSG, pt, 20) } static void test_pack_MSGBOXCALLBACK(void) { /* MSGBOXCALLBACK */ - TEST_TYPE(MSGBOXCALLBACK, 4, 4); + TEST_TYPE_SIZE (MSGBOXCALLBACK, 4) + TEST_TYPE_ALIGN (MSGBOXCALLBACK, 4) } static void test_pack_MSGBOXPARAMSA(void) { /* MSGBOXPARAMSA (pack 4) */ - TEST_TYPE(MSGBOXPARAMSA, 40, 4); - TEST_FIELD(MSGBOXPARAMSA, UINT, cbSize, 0, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, HWND, hwndOwner, 4, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, HINSTANCE, hInstance, 8, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, LPCSTR, lpszText, 12, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, LPCSTR, lpszCaption, 16, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, DWORD, dwStyle, 20, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, LPCSTR, lpszIcon, 24, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, DWORD_PTR, dwContextHelpId, 28, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, MSGBOXCALLBACK, lpfnMsgBoxCallback, 32, 4, 4); - TEST_FIELD(MSGBOXPARAMSA, DWORD, dwLanguageId, 36, 4, 4); + TEST_TYPE_SIZE (MSGBOXPARAMSA, 40) + TEST_TYPE_ALIGN (MSGBOXPARAMSA, 4) + TEST_FIELD_SIZE (MSGBOXPARAMSA, cbSize, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, cbSize, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, cbSize, 0) + TEST_FIELD_SIZE (MSGBOXPARAMSA, hwndOwner, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, hwndOwner, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, hwndOwner, 4) + TEST_FIELD_SIZE (MSGBOXPARAMSA, hInstance, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, hInstance, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, hInstance, 8) + TEST_FIELD_SIZE (MSGBOXPARAMSA, lpszText, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, lpszText, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, lpszText, 12) + TEST_FIELD_SIZE (MSGBOXPARAMSA, lpszCaption, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, lpszCaption, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, lpszCaption, 16) + TEST_FIELD_SIZE (MSGBOXPARAMSA, dwStyle, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, dwStyle, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, dwStyle, 20) + TEST_FIELD_SIZE (MSGBOXPARAMSA, lpszIcon, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, lpszIcon, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, lpszIcon, 24) + TEST_FIELD_SIZE (MSGBOXPARAMSA, dwContextHelpId, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, dwContextHelpId, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, dwContextHelpId, 28) + TEST_FIELD_SIZE (MSGBOXPARAMSA, lpfnMsgBoxCallback, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, lpfnMsgBoxCallback, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, lpfnMsgBoxCallback, 32) + TEST_FIELD_SIZE (MSGBOXPARAMSA, dwLanguageId, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSA, dwLanguageId, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSA, dwLanguageId, 36) } static void test_pack_MSGBOXPARAMSW(void) { /* MSGBOXPARAMSW (pack 4) */ - TEST_TYPE(MSGBOXPARAMSW, 40, 4); - TEST_FIELD(MSGBOXPARAMSW, UINT, cbSize, 0, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, HWND, hwndOwner, 4, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, HINSTANCE, hInstance, 8, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, LPCWSTR, lpszText, 12, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, LPCWSTR, lpszCaption, 16, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, DWORD, dwStyle, 20, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, LPCWSTR, lpszIcon, 24, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, DWORD_PTR, dwContextHelpId, 28, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, MSGBOXCALLBACK, lpfnMsgBoxCallback, 32, 4, 4); - TEST_FIELD(MSGBOXPARAMSW, DWORD, dwLanguageId, 36, 4, 4); + TEST_TYPE_SIZE (MSGBOXPARAMSW, 40) + TEST_TYPE_ALIGN (MSGBOXPARAMSW, 4) + TEST_FIELD_SIZE (MSGBOXPARAMSW, cbSize, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, cbSize, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, cbSize, 0) + TEST_FIELD_SIZE (MSGBOXPARAMSW, hwndOwner, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, hwndOwner, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, hwndOwner, 4) + TEST_FIELD_SIZE (MSGBOXPARAMSW, hInstance, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, hInstance, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, hInstance, 8) + TEST_FIELD_SIZE (MSGBOXPARAMSW, lpszText, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, lpszText, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, lpszText, 12) + TEST_FIELD_SIZE (MSGBOXPARAMSW, lpszCaption, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, lpszCaption, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, lpszCaption, 16) + TEST_FIELD_SIZE (MSGBOXPARAMSW, dwStyle, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, dwStyle, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, dwStyle, 20) + TEST_FIELD_SIZE (MSGBOXPARAMSW, lpszIcon, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, lpszIcon, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, lpszIcon, 24) + TEST_FIELD_SIZE (MSGBOXPARAMSW, dwContextHelpId, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, dwContextHelpId, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, dwContextHelpId, 28) + TEST_FIELD_SIZE (MSGBOXPARAMSW, lpfnMsgBoxCallback, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, lpfnMsgBoxCallback, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, lpfnMsgBoxCallback, 32) + TEST_FIELD_SIZE (MSGBOXPARAMSW, dwLanguageId, 4) + TEST_FIELD_ALIGN (MSGBOXPARAMSW, dwLanguageId, 4) + TEST_FIELD_OFFSET(MSGBOXPARAMSW, dwLanguageId, 36) } static void test_pack_MSLLHOOKSTRUCT(void) { /* MSLLHOOKSTRUCT (pack 4) */ - TEST_TYPE(MSLLHOOKSTRUCT, 24, 4); - TEST_FIELD(MSLLHOOKSTRUCT, POINT, pt, 0, 8, 4); - TEST_FIELD(MSLLHOOKSTRUCT, DWORD, mouseData, 8, 4, 4); - TEST_FIELD(MSLLHOOKSTRUCT, DWORD, flags, 12, 4, 4); - TEST_FIELD(MSLLHOOKSTRUCT, DWORD, time, 16, 4, 4); - TEST_FIELD(MSLLHOOKSTRUCT, ULONG_PTR, dwExtraInfo, 20, 4, 4); + TEST_TYPE_SIZE (MSLLHOOKSTRUCT, 24) + TEST_TYPE_ALIGN (MSLLHOOKSTRUCT, 4) + TEST_FIELD_SIZE (MSLLHOOKSTRUCT, pt, 8) + TEST_FIELD_ALIGN (MSLLHOOKSTRUCT, pt, 4) + TEST_FIELD_OFFSET(MSLLHOOKSTRUCT, pt, 0) + TEST_FIELD_SIZE (MSLLHOOKSTRUCT, mouseData, 4) + TEST_FIELD_ALIGN (MSLLHOOKSTRUCT, mouseData, 4) + TEST_FIELD_OFFSET(MSLLHOOKSTRUCT, mouseData, 8) + TEST_FIELD_SIZE (MSLLHOOKSTRUCT, flags, 4) + TEST_FIELD_ALIGN (MSLLHOOKSTRUCT, flags, 4) + TEST_FIELD_OFFSET(MSLLHOOKSTRUCT, flags, 12) + TEST_FIELD_SIZE (MSLLHOOKSTRUCT, time, 4) + TEST_FIELD_ALIGN (MSLLHOOKSTRUCT, time, 4) + TEST_FIELD_OFFSET(MSLLHOOKSTRUCT, time, 16) + TEST_FIELD_SIZE (MSLLHOOKSTRUCT, dwExtraInfo, 4) + TEST_FIELD_ALIGN (MSLLHOOKSTRUCT, dwExtraInfo, 4) + TEST_FIELD_OFFSET(MSLLHOOKSTRUCT, dwExtraInfo, 20) } static void test_pack_MULTIKEYHELPA(void) { /* MULTIKEYHELPA (pack 4) */ - TEST_TYPE(MULTIKEYHELPA, 8, 4); - TEST_FIELD(MULTIKEYHELPA, DWORD, mkSize, 0, 4, 4); - TEST_FIELD(MULTIKEYHELPA, CHAR, mkKeylist, 4, 1, 1); - TEST_FIELD(MULTIKEYHELPA, CHAR[1], szKeyphrase, 5, 1, 1); + TEST_TYPE_SIZE (MULTIKEYHELPA, 8) + TEST_TYPE_ALIGN (MULTIKEYHELPA, 4) + TEST_FIELD_SIZE (MULTIKEYHELPA, mkSize, 4) + TEST_FIELD_ALIGN (MULTIKEYHELPA, mkSize, 4) + TEST_FIELD_OFFSET(MULTIKEYHELPA, mkSize, 0) + TEST_FIELD_SIZE (MULTIKEYHELPA, mkKeylist, 1) + TEST_FIELD_ALIGN (MULTIKEYHELPA, mkKeylist, 1) + TEST_FIELD_OFFSET(MULTIKEYHELPA, mkKeylist, 4) + TEST_FIELD_SIZE (MULTIKEYHELPA, szKeyphrase, 1) + TEST_FIELD_ALIGN (MULTIKEYHELPA, szKeyphrase, 1) + TEST_FIELD_OFFSET(MULTIKEYHELPA, szKeyphrase, 5) } static void test_pack_MULTIKEYHELPW(void) { /* MULTIKEYHELPW (pack 4) */ - TEST_TYPE(MULTIKEYHELPW, 8, 4); - TEST_FIELD(MULTIKEYHELPW, DWORD, mkSize, 0, 4, 4); - TEST_FIELD(MULTIKEYHELPW, WCHAR, mkKeylist, 4, 2, 2); - TEST_FIELD(MULTIKEYHELPW, WCHAR[1], szKeyphrase, 6, 2, 2); + TEST_TYPE_SIZE (MULTIKEYHELPW, 8) + TEST_TYPE_ALIGN (MULTIKEYHELPW, 4) + TEST_FIELD_SIZE (MULTIKEYHELPW, mkSize, 4) + TEST_FIELD_ALIGN (MULTIKEYHELPW, mkSize, 4) + TEST_FIELD_OFFSET(MULTIKEYHELPW, mkSize, 0) + TEST_FIELD_SIZE (MULTIKEYHELPW, mkKeylist, 2) + TEST_FIELD_ALIGN (MULTIKEYHELPW, mkKeylist, 2) + TEST_FIELD_OFFSET(MULTIKEYHELPW, mkKeylist, 4) + TEST_FIELD_SIZE (MULTIKEYHELPW, szKeyphrase, 2) + TEST_FIELD_ALIGN (MULTIKEYHELPW, szKeyphrase, 2) + TEST_FIELD_OFFSET(MULTIKEYHELPW, szKeyphrase, 6) } static void test_pack_NAMEENUMPROCA(void) { /* NAMEENUMPROCA */ - TEST_TYPE(NAMEENUMPROCA, 4, 4); + TEST_TYPE_SIZE (NAMEENUMPROCA, 4) + TEST_TYPE_ALIGN (NAMEENUMPROCA, 4) } static void test_pack_NAMEENUMPROCW(void) { /* NAMEENUMPROCW */ - TEST_TYPE(NAMEENUMPROCW, 4, 4); + TEST_TYPE_SIZE (NAMEENUMPROCW, 4) + TEST_TYPE_ALIGN (NAMEENUMPROCW, 4) } static void test_pack_NCCALCSIZE_PARAMS(void) { /* NCCALCSIZE_PARAMS (pack 4) */ - TEST_TYPE(NCCALCSIZE_PARAMS, 52, 4); - TEST_FIELD(NCCALCSIZE_PARAMS, RECT[3], rgrc, 0, 48, 4); - TEST_FIELD(NCCALCSIZE_PARAMS, WINDOWPOS *, lppos, 48, 4, 4); + TEST_TYPE_SIZE (NCCALCSIZE_PARAMS, 52) + TEST_TYPE_ALIGN (NCCALCSIZE_PARAMS, 4) + TEST_FIELD_SIZE (NCCALCSIZE_PARAMS, rgrc, 48) + TEST_FIELD_ALIGN (NCCALCSIZE_PARAMS, rgrc, 4) + TEST_FIELD_OFFSET(NCCALCSIZE_PARAMS, rgrc, 0) + TEST_FIELD_SIZE (NCCALCSIZE_PARAMS, lppos, 4) + TEST_FIELD_ALIGN (NCCALCSIZE_PARAMS, lppos, 4) + TEST_FIELD_OFFSET(NCCALCSIZE_PARAMS, lppos, 48) } static void test_pack_NMHDR(void) { /* NMHDR (pack 4) */ - TEST_TYPE(NMHDR, 12, 4); - TEST_FIELD(NMHDR, HWND, hwndFrom, 0, 4, 4); - TEST_FIELD(NMHDR, UINT_PTR, idFrom, 4, 4, 4); - TEST_FIELD(NMHDR, UINT, code, 8, 4, 4); + TEST_TYPE_SIZE (NMHDR, 12) + TEST_TYPE_ALIGN (NMHDR, 4) + TEST_FIELD_SIZE (NMHDR, hwndFrom, 4) + TEST_FIELD_ALIGN (NMHDR, hwndFrom, 4) + TEST_FIELD_OFFSET(NMHDR, hwndFrom, 0) + TEST_FIELD_SIZE (NMHDR, idFrom, 4) + TEST_FIELD_ALIGN (NMHDR, idFrom, 4) + TEST_FIELD_OFFSET(NMHDR, idFrom, 4) + TEST_FIELD_SIZE (NMHDR, code, 4) + TEST_FIELD_ALIGN (NMHDR, code, 4) + TEST_FIELD_OFFSET(NMHDR, code, 8) } static void test_pack_NONCLIENTMETRICSA(void) { /* NONCLIENTMETRICSA (pack 4) */ - TEST_TYPE(NONCLIENTMETRICSA, 340, 4); - TEST_FIELD(NONCLIENTMETRICSA, UINT, cbSize, 0, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iBorderWidth, 4, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iScrollWidth, 8, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iScrollHeight, 12, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iCaptionWidth, 16, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iCaptionHeight, 20, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, LOGFONTA, lfCaptionFont, 24, 60, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iSmCaptionWidth, 84, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iSmCaptionHeight, 88, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, LOGFONTA, lfSmCaptionFont, 92, 60, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iMenuWidth, 152, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, INT, iMenuHeight, 156, 4, 4); - TEST_FIELD(NONCLIENTMETRICSA, LOGFONTA, lfMenuFont, 160, 60, 4); - TEST_FIELD(NONCLIENTMETRICSA, LOGFONTA, lfStatusFont, 220, 60, 4); - TEST_FIELD(NONCLIENTMETRICSA, LOGFONTA, lfMessageFont, 280, 60, 4); + TEST_TYPE_SIZE (NONCLIENTMETRICSA, 340) + TEST_TYPE_ALIGN (NONCLIENTMETRICSA, 4) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, cbSize, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, cbSize, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, cbSize, 0) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iBorderWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iBorderWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iBorderWidth, 4) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iScrollWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iScrollWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iScrollWidth, 8) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iScrollHeight, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iScrollHeight, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iScrollHeight, 12) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iCaptionWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iCaptionWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iCaptionWidth, 16) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iCaptionHeight, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iCaptionHeight, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iCaptionHeight, 20) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, lfCaptionFont, 60) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, lfCaptionFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, lfCaptionFont, 24) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iSmCaptionWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iSmCaptionWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iSmCaptionWidth, 84) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iSmCaptionHeight, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iSmCaptionHeight, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iSmCaptionHeight, 88) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, lfSmCaptionFont, 60) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, lfSmCaptionFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, lfSmCaptionFont, 92) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iMenuWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iMenuWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iMenuWidth, 152) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, iMenuHeight, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, iMenuHeight, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, iMenuHeight, 156) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, lfMenuFont, 60) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, lfMenuFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, lfMenuFont, 160) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, lfStatusFont, 60) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, lfStatusFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, lfStatusFont, 220) + TEST_FIELD_SIZE (NONCLIENTMETRICSA, lfMessageFont, 60) + TEST_FIELD_ALIGN (NONCLIENTMETRICSA, lfMessageFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSA, lfMessageFont, 280) } static void test_pack_NONCLIENTMETRICSW(void) { /* NONCLIENTMETRICSW (pack 4) */ - TEST_TYPE(NONCLIENTMETRICSW, 500, 4); - TEST_FIELD(NONCLIENTMETRICSW, UINT, cbSize, 0, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iBorderWidth, 4, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iScrollWidth, 8, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iScrollHeight, 12, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iCaptionWidth, 16, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iCaptionHeight, 20, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, LOGFONTW, lfCaptionFont, 24, 92, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iSmCaptionWidth, 116, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iSmCaptionHeight, 120, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, LOGFONTW, lfSmCaptionFont, 124, 92, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iMenuWidth, 216, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, INT, iMenuHeight, 220, 4, 4); - TEST_FIELD(NONCLIENTMETRICSW, LOGFONTW, lfMenuFont, 224, 92, 4); - TEST_FIELD(NONCLIENTMETRICSW, LOGFONTW, lfStatusFont, 316, 92, 4); - TEST_FIELD(NONCLIENTMETRICSW, LOGFONTW, lfMessageFont, 408, 92, 4); + TEST_TYPE_SIZE (NONCLIENTMETRICSW, 500) + TEST_TYPE_ALIGN (NONCLIENTMETRICSW, 4) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, cbSize, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, cbSize, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, cbSize, 0) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iBorderWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iBorderWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iBorderWidth, 4) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iScrollWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iScrollWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iScrollWidth, 8) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iScrollHeight, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iScrollHeight, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iScrollHeight, 12) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iCaptionWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iCaptionWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iCaptionWidth, 16) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iCaptionHeight, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iCaptionHeight, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iCaptionHeight, 20) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, lfCaptionFont, 92) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, lfCaptionFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, lfCaptionFont, 24) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iSmCaptionWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iSmCaptionWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iSmCaptionWidth, 116) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iSmCaptionHeight, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iSmCaptionHeight, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iSmCaptionHeight, 120) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, lfSmCaptionFont, 92) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, lfSmCaptionFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, lfSmCaptionFont, 124) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iMenuWidth, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iMenuWidth, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iMenuWidth, 216) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, iMenuHeight, 4) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, iMenuHeight, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, iMenuHeight, 220) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, lfMenuFont, 92) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, lfMenuFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, lfMenuFont, 224) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, lfStatusFont, 92) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, lfStatusFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, lfStatusFont, 316) + TEST_FIELD_SIZE (NONCLIENTMETRICSW, lfMessageFont, 92) + TEST_FIELD_ALIGN (NONCLIENTMETRICSW, lfMessageFont, 4) + TEST_FIELD_OFFSET(NONCLIENTMETRICSW, lfMessageFont, 408) } static void test_pack_PAINTSTRUCT(void) { /* PAINTSTRUCT (pack 4) */ - TEST_TYPE(PAINTSTRUCT, 64, 4); - TEST_FIELD(PAINTSTRUCT, HDC, hdc, 0, 4, 4); - TEST_FIELD(PAINTSTRUCT, BOOL, fErase, 4, 4, 4); - TEST_FIELD(PAINTSTRUCT, RECT, rcPaint, 8, 16, 4); - TEST_FIELD(PAINTSTRUCT, BOOL, fRestore, 24, 4, 4); - TEST_FIELD(PAINTSTRUCT, BOOL, fIncUpdate, 28, 4, 4); - TEST_FIELD(PAINTSTRUCT, BYTE[32], rgbReserved, 32, 32, 1); + TEST_TYPE_SIZE (PAINTSTRUCT, 64) + TEST_TYPE_ALIGN (PAINTSTRUCT, 4) + TEST_FIELD_SIZE (PAINTSTRUCT, hdc, 4) + TEST_FIELD_ALIGN (PAINTSTRUCT, hdc, 4) + TEST_FIELD_OFFSET(PAINTSTRUCT, hdc, 0) + TEST_FIELD_SIZE (PAINTSTRUCT, fErase, 4) + TEST_FIELD_ALIGN (PAINTSTRUCT, fErase, 4) + TEST_FIELD_OFFSET(PAINTSTRUCT, fErase, 4) + TEST_FIELD_SIZE (PAINTSTRUCT, rcPaint, 16) + TEST_FIELD_ALIGN (PAINTSTRUCT, rcPaint, 4) + TEST_FIELD_OFFSET(PAINTSTRUCT, rcPaint, 8) + TEST_FIELD_SIZE (PAINTSTRUCT, fRestore, 4) + TEST_FIELD_ALIGN (PAINTSTRUCT, fRestore, 4) + TEST_FIELD_OFFSET(PAINTSTRUCT, fRestore, 24) + TEST_FIELD_SIZE (PAINTSTRUCT, fIncUpdate, 4) + TEST_FIELD_ALIGN (PAINTSTRUCT, fIncUpdate, 4) + TEST_FIELD_OFFSET(PAINTSTRUCT, fIncUpdate, 28) + TEST_FIELD_SIZE (PAINTSTRUCT, rgbReserved, 32) + TEST_FIELD_ALIGN (PAINTSTRUCT, rgbReserved, 1) + TEST_FIELD_OFFSET(PAINTSTRUCT, rgbReserved, 32) } static void test_pack_PCOMBOBOXINFO(void) { /* PCOMBOBOXINFO */ - TEST_TYPE(PCOMBOBOXINFO, 4, 4); - TEST_TYPE_POINTER(PCOMBOBOXINFO, 52, 4); + TEST_TYPE_SIZE (PCOMBOBOXINFO, 4) + TEST_TYPE_ALIGN (PCOMBOBOXINFO, 4) + TEST_TARGET_SIZE (PCOMBOBOXINFO, 52) + TEST_TARGET_ALIGN(PCOMBOBOXINFO, 4) } static void test_pack_PCOMPAREITEMSTRUCT(void) { /* PCOMPAREITEMSTRUCT */ - TEST_TYPE(PCOMPAREITEMSTRUCT, 4, 4); - TEST_TYPE_POINTER(PCOMPAREITEMSTRUCT, 32, 4); + TEST_TYPE_SIZE (PCOMPAREITEMSTRUCT, 4) + TEST_TYPE_ALIGN (PCOMPAREITEMSTRUCT, 4) + TEST_TARGET_SIZE (PCOMPAREITEMSTRUCT, 32) + TEST_TARGET_ALIGN(PCOMPAREITEMSTRUCT, 4) } static void test_pack_PCOPYDATASTRUCT(void) { /* PCOPYDATASTRUCT */ - TEST_TYPE(PCOPYDATASTRUCT, 4, 4); - TEST_TYPE_POINTER(PCOPYDATASTRUCT, 12, 4); + TEST_TYPE_SIZE (PCOPYDATASTRUCT, 4) + TEST_TYPE_ALIGN (PCOPYDATASTRUCT, 4) + TEST_TARGET_SIZE (PCOPYDATASTRUCT, 12) + TEST_TARGET_ALIGN(PCOPYDATASTRUCT, 4) } static void test_pack_PCURSORINFO(void) { /* PCURSORINFO */ - TEST_TYPE(PCURSORINFO, 4, 4); - TEST_TYPE_POINTER(PCURSORINFO, 20, 4); + TEST_TYPE_SIZE (PCURSORINFO, 4) + TEST_TYPE_ALIGN (PCURSORINFO, 4) + TEST_TARGET_SIZE (PCURSORINFO, 20) + TEST_TARGET_ALIGN(PCURSORINFO, 4) } static void test_pack_PCWPRETSTRUCT(void) { /* PCWPRETSTRUCT */ - TEST_TYPE(PCWPRETSTRUCT, 4, 4); - TEST_TYPE_POINTER(PCWPRETSTRUCT, 20, 4); + TEST_TYPE_SIZE (PCWPRETSTRUCT, 4) + TEST_TYPE_ALIGN (PCWPRETSTRUCT, 4) + TEST_TARGET_SIZE (PCWPRETSTRUCT, 20) + TEST_TARGET_ALIGN(PCWPRETSTRUCT, 4) } static void test_pack_PCWPSTRUCT(void) { /* PCWPSTRUCT */ - TEST_TYPE(PCWPSTRUCT, 4, 4); - TEST_TYPE_POINTER(PCWPSTRUCT, 16, 4); + TEST_TYPE_SIZE (PCWPSTRUCT, 4) + TEST_TYPE_ALIGN (PCWPSTRUCT, 4) + TEST_TARGET_SIZE (PCWPSTRUCT, 16) + TEST_TARGET_ALIGN(PCWPSTRUCT, 4) } static void test_pack_PDEBUGHOOKINFO(void) { /* PDEBUGHOOKINFO */ - TEST_TYPE(PDEBUGHOOKINFO, 4, 4); - TEST_TYPE_POINTER(PDEBUGHOOKINFO, 20, 4); + TEST_TYPE_SIZE (PDEBUGHOOKINFO, 4) + TEST_TYPE_ALIGN (PDEBUGHOOKINFO, 4) + TEST_TARGET_SIZE (PDEBUGHOOKINFO, 20) + TEST_TARGET_ALIGN(PDEBUGHOOKINFO, 4) } static void test_pack_PDELETEITEMSTRUCT(void) { /* PDELETEITEMSTRUCT */ - TEST_TYPE(PDELETEITEMSTRUCT, 4, 4); - TEST_TYPE_POINTER(PDELETEITEMSTRUCT, 20, 4); + TEST_TYPE_SIZE (PDELETEITEMSTRUCT, 4) + TEST_TYPE_ALIGN (PDELETEITEMSTRUCT, 4) + TEST_TARGET_SIZE (PDELETEITEMSTRUCT, 20) + TEST_TARGET_ALIGN(PDELETEITEMSTRUCT, 4) } static void test_pack_PDLGITEMTEMPLATEA(void) { /* PDLGITEMTEMPLATEA */ - TEST_TYPE(PDLGITEMTEMPLATEA, 4, 4); - TEST_TYPE_POINTER(PDLGITEMTEMPLATEA, 18, 2); + TEST_TYPE_SIZE (PDLGITEMTEMPLATEA, 4) + TEST_TYPE_ALIGN (PDLGITEMTEMPLATEA, 4) + TEST_TARGET_SIZE (PDLGITEMTEMPLATEA, 18) + TEST_TARGET_ALIGN(PDLGITEMTEMPLATEA, 2) } static void test_pack_PDLGITEMTEMPLATEW(void) { /* PDLGITEMTEMPLATEW */ - TEST_TYPE(PDLGITEMTEMPLATEW, 4, 4); - TEST_TYPE_POINTER(PDLGITEMTEMPLATEW, 18, 2); + TEST_TYPE_SIZE (PDLGITEMTEMPLATEW, 4) + TEST_TYPE_ALIGN (PDLGITEMTEMPLATEW, 4) + TEST_TARGET_SIZE (PDLGITEMTEMPLATEW, 18) + TEST_TARGET_ALIGN(PDLGITEMTEMPLATEW, 2) } static void test_pack_PDRAWITEMSTRUCT(void) { /* PDRAWITEMSTRUCT */ - TEST_TYPE(PDRAWITEMSTRUCT, 4, 4); - TEST_TYPE_POINTER(PDRAWITEMSTRUCT, 48, 4); + TEST_TYPE_SIZE (PDRAWITEMSTRUCT, 4) + TEST_TYPE_ALIGN (PDRAWITEMSTRUCT, 4) + TEST_TARGET_SIZE (PDRAWITEMSTRUCT, 48) + TEST_TARGET_ALIGN(PDRAWITEMSTRUCT, 4) } static void test_pack_PEVENTMSG(void) { /* PEVENTMSG */ - TEST_TYPE(PEVENTMSG, 4, 4); - TEST_TYPE_POINTER(PEVENTMSG, 20, 4); + TEST_TYPE_SIZE (PEVENTMSG, 4) + TEST_TYPE_ALIGN (PEVENTMSG, 4) + TEST_TARGET_SIZE (PEVENTMSG, 20) + TEST_TARGET_ALIGN(PEVENTMSG, 4) } static void test_pack_PFLASHWINFO(void) { /* PFLASHWINFO */ - TEST_TYPE(PFLASHWINFO, 4, 4); - TEST_TYPE_POINTER(PFLASHWINFO, 20, 4); + TEST_TYPE_SIZE (PFLASHWINFO, 4) + TEST_TYPE_ALIGN (PFLASHWINFO, 4) + TEST_TARGET_SIZE (PFLASHWINFO, 20) + TEST_TARGET_ALIGN(PFLASHWINFO, 4) } static void test_pack_PGUITHREADINFO(void) { /* PGUITHREADINFO */ - TEST_TYPE(PGUITHREADINFO, 4, 4); - TEST_TYPE_POINTER(PGUITHREADINFO, 48, 4); + TEST_TYPE_SIZE (PGUITHREADINFO, 4) + TEST_TYPE_ALIGN (PGUITHREADINFO, 4) + TEST_TARGET_SIZE (PGUITHREADINFO, 48) + TEST_TARGET_ALIGN(PGUITHREADINFO, 4) } static void test_pack_PHARDWAREHOOKSTRUCT(void) { /* PHARDWAREHOOKSTRUCT */ - TEST_TYPE(PHARDWAREHOOKSTRUCT, 4, 4); - TEST_TYPE_POINTER(PHARDWAREHOOKSTRUCT, 16, 4); + TEST_TYPE_SIZE (PHARDWAREHOOKSTRUCT, 4) + TEST_TYPE_ALIGN (PHARDWAREHOOKSTRUCT, 4) + TEST_TARGET_SIZE (PHARDWAREHOOKSTRUCT, 16) + TEST_TARGET_ALIGN(PHARDWAREHOOKSTRUCT, 4) } static void test_pack_PHARDWAREINPUT(void) { /* PHARDWAREINPUT */ - TEST_TYPE(PHARDWAREINPUT, 4, 4); - TEST_TYPE_POINTER(PHARDWAREINPUT, 8, 4); + TEST_TYPE_SIZE (PHARDWAREINPUT, 4) + TEST_TYPE_ALIGN (PHARDWAREINPUT, 4) + TEST_TARGET_SIZE (PHARDWAREINPUT, 8) + TEST_TARGET_ALIGN(PHARDWAREINPUT, 4) } static void test_pack_PHDEVNOTIFY(void) { /* PHDEVNOTIFY */ - TEST_TYPE(PHDEVNOTIFY, 4, 4); - TEST_TYPE_POINTER(PHDEVNOTIFY, 4, 4); + TEST_TYPE_SIZE (PHDEVNOTIFY, 4) + TEST_TYPE_ALIGN (PHDEVNOTIFY, 4) + TEST_TARGET_SIZE (PHDEVNOTIFY, 4) + TEST_TARGET_ALIGN(PHDEVNOTIFY, 4) } static void test_pack_PHELPWININFOA(void) { /* PHELPWININFOA */ - TEST_TYPE(PHELPWININFOA, 4, 4); - TEST_TYPE_POINTER(PHELPWININFOA, 28, 4); + TEST_TYPE_SIZE (PHELPWININFOA, 4) + TEST_TYPE_ALIGN (PHELPWININFOA, 4) + TEST_TARGET_SIZE (PHELPWININFOA, 28) + TEST_TARGET_ALIGN(PHELPWININFOA, 4) } static void test_pack_PHELPWININFOW(void) { /* PHELPWININFOW */ - TEST_TYPE(PHELPWININFOW, 4, 4); - TEST_TYPE_POINTER(PHELPWININFOW, 28, 4); + TEST_TYPE_SIZE (PHELPWININFOW, 4) + TEST_TYPE_ALIGN (PHELPWININFOW, 4) + TEST_TARGET_SIZE (PHELPWININFOW, 28) + TEST_TARGET_ALIGN(PHELPWININFOW, 4) } static void test_pack_PICONINFO(void) { /* PICONINFO */ - TEST_TYPE(PICONINFO, 4, 4); - TEST_TYPE_POINTER(PICONINFO, 20, 4); + TEST_TYPE_SIZE (PICONINFO, 4) + TEST_TYPE_ALIGN (PICONINFO, 4) + TEST_TARGET_SIZE (PICONINFO, 20) + TEST_TARGET_ALIGN(PICONINFO, 4) } static void test_pack_PICONMETRICSA(void) { /* PICONMETRICSA */ - TEST_TYPE(PICONMETRICSA, 4, 4); - TEST_TYPE_POINTER(PICONMETRICSA, 76, 4); + TEST_TYPE_SIZE (PICONMETRICSA, 4) + TEST_TYPE_ALIGN (PICONMETRICSA, 4) + TEST_TARGET_SIZE (PICONMETRICSA, 76) + TEST_TARGET_ALIGN(PICONMETRICSA, 4) } static void test_pack_PICONMETRICSW(void) { /* PICONMETRICSW */ - TEST_TYPE(PICONMETRICSW, 4, 4); - TEST_TYPE_POINTER(PICONMETRICSW, 108, 4); + TEST_TYPE_SIZE (PICONMETRICSW, 4) + TEST_TYPE_ALIGN (PICONMETRICSW, 4) + TEST_TARGET_SIZE (PICONMETRICSW, 108) + TEST_TARGET_ALIGN(PICONMETRICSW, 4) } static void test_pack_PINPUT(void) { /* PINPUT */ - TEST_TYPE(PINPUT, 4, 4); + TEST_TYPE_SIZE (PINPUT, 4) + TEST_TYPE_ALIGN (PINPUT, 4) } static void test_pack_PKBDLLHOOKSTRUCT(void) { /* PKBDLLHOOKSTRUCT */ - TEST_TYPE(PKBDLLHOOKSTRUCT, 4, 4); - TEST_TYPE_POINTER(PKBDLLHOOKSTRUCT, 20, 4); + TEST_TYPE_SIZE (PKBDLLHOOKSTRUCT, 4) + TEST_TYPE_ALIGN (PKBDLLHOOKSTRUCT, 4) + TEST_TARGET_SIZE (PKBDLLHOOKSTRUCT, 20) + TEST_TARGET_ALIGN(PKBDLLHOOKSTRUCT, 4) } static void test_pack_PKEYBDINPUT(void) { /* PKEYBDINPUT */ - TEST_TYPE(PKEYBDINPUT, 4, 4); - TEST_TYPE_POINTER(PKEYBDINPUT, 16, 4); + TEST_TYPE_SIZE (PKEYBDINPUT, 4) + TEST_TYPE_ALIGN (PKEYBDINPUT, 4) + TEST_TARGET_SIZE (PKEYBDINPUT, 16) + TEST_TARGET_ALIGN(PKEYBDINPUT, 4) } static void test_pack_PMDINEXTMENU(void) { /* PMDINEXTMENU */ - TEST_TYPE(PMDINEXTMENU, 4, 4); - TEST_TYPE_POINTER(PMDINEXTMENU, 12, 4); + TEST_TYPE_SIZE (PMDINEXTMENU, 4) + TEST_TYPE_ALIGN (PMDINEXTMENU, 4) + TEST_TARGET_SIZE (PMDINEXTMENU, 12) + TEST_TARGET_ALIGN(PMDINEXTMENU, 4) } static void test_pack_PMEASUREITEMSTRUCT(void) { /* PMEASUREITEMSTRUCT */ - TEST_TYPE(PMEASUREITEMSTRUCT, 4, 4); - TEST_TYPE_POINTER(PMEASUREITEMSTRUCT, 24, 4); + TEST_TYPE_SIZE (PMEASUREITEMSTRUCT, 4) + TEST_TYPE_ALIGN (PMEASUREITEMSTRUCT, 4) + TEST_TARGET_SIZE (PMEASUREITEMSTRUCT, 24) + TEST_TARGET_ALIGN(PMEASUREITEMSTRUCT, 4) } static void test_pack_PMENUITEMTEMPLATE(void) { /* PMENUITEMTEMPLATE */ - TEST_TYPE(PMENUITEMTEMPLATE, 4, 4); - TEST_TYPE_POINTER(PMENUITEMTEMPLATE, 6, 2); + TEST_TYPE_SIZE (PMENUITEMTEMPLATE, 4) + TEST_TYPE_ALIGN (PMENUITEMTEMPLATE, 4) + TEST_TARGET_SIZE (PMENUITEMTEMPLATE, 6) + TEST_TARGET_ALIGN(PMENUITEMTEMPLATE, 2) } static void test_pack_PMENUITEMTEMPLATEHEADER(void) { /* PMENUITEMTEMPLATEHEADER */ - TEST_TYPE(PMENUITEMTEMPLATEHEADER, 4, 4); - TEST_TYPE_POINTER(PMENUITEMTEMPLATEHEADER, 4, 2); + TEST_TYPE_SIZE (PMENUITEMTEMPLATEHEADER, 4) + TEST_TYPE_ALIGN (PMENUITEMTEMPLATEHEADER, 4) + TEST_TARGET_SIZE (PMENUITEMTEMPLATEHEADER, 4) + TEST_TARGET_ALIGN(PMENUITEMTEMPLATEHEADER, 2) } static void test_pack_PMINIMIZEDMETRICS(void) { /* PMINIMIZEDMETRICS */ - TEST_TYPE(PMINIMIZEDMETRICS, 4, 4); - TEST_TYPE_POINTER(PMINIMIZEDMETRICS, 20, 4); + TEST_TYPE_SIZE (PMINIMIZEDMETRICS, 4) + TEST_TYPE_ALIGN (PMINIMIZEDMETRICS, 4) + TEST_TARGET_SIZE (PMINIMIZEDMETRICS, 20) + TEST_TARGET_ALIGN(PMINIMIZEDMETRICS, 4) } static void test_pack_PMINMAXINFO(void) { /* PMINMAXINFO */ - TEST_TYPE(PMINMAXINFO, 4, 4); - TEST_TYPE_POINTER(PMINMAXINFO, 40, 4); + TEST_TYPE_SIZE (PMINMAXINFO, 4) + TEST_TYPE_ALIGN (PMINMAXINFO, 4) + TEST_TARGET_SIZE (PMINMAXINFO, 40) + TEST_TARGET_ALIGN(PMINMAXINFO, 4) } static void test_pack_PMOUSEHOOKSTRUCT(void) { /* PMOUSEHOOKSTRUCT */ - TEST_TYPE(PMOUSEHOOKSTRUCT, 4, 4); - TEST_TYPE_POINTER(PMOUSEHOOKSTRUCT, 20, 4); + TEST_TYPE_SIZE (PMOUSEHOOKSTRUCT, 4) + TEST_TYPE_ALIGN (PMOUSEHOOKSTRUCT, 4) + TEST_TARGET_SIZE (PMOUSEHOOKSTRUCT, 20) + TEST_TARGET_ALIGN(PMOUSEHOOKSTRUCT, 4) } static void test_pack_PMOUSEINPUT(void) { /* PMOUSEINPUT */ - TEST_TYPE(PMOUSEINPUT, 4, 4); - TEST_TYPE_POINTER(PMOUSEINPUT, 24, 4); + TEST_TYPE_SIZE (PMOUSEINPUT, 4) + TEST_TYPE_ALIGN (PMOUSEINPUT, 4) + TEST_TARGET_SIZE (PMOUSEINPUT, 24) + TEST_TARGET_ALIGN(PMOUSEINPUT, 4) } static void test_pack_PMSG(void) { /* PMSG */ - TEST_TYPE(PMSG, 4, 4); - TEST_TYPE_POINTER(PMSG, 28, 4); + TEST_TYPE_SIZE (PMSG, 4) + TEST_TYPE_ALIGN (PMSG, 4) + TEST_TARGET_SIZE (PMSG, 28) + TEST_TARGET_ALIGN(PMSG, 4) } static void test_pack_PMSGBOXPARAMSA(void) { /* PMSGBOXPARAMSA */ - TEST_TYPE(PMSGBOXPARAMSA, 4, 4); - TEST_TYPE_POINTER(PMSGBOXPARAMSA, 40, 4); + TEST_TYPE_SIZE (PMSGBOXPARAMSA, 4) + TEST_TYPE_ALIGN (PMSGBOXPARAMSA, 4) + TEST_TARGET_SIZE (PMSGBOXPARAMSA, 40) + TEST_TARGET_ALIGN(PMSGBOXPARAMSA, 4) } static void test_pack_PMSGBOXPARAMSW(void) { /* PMSGBOXPARAMSW */ - TEST_TYPE(PMSGBOXPARAMSW, 4, 4); - TEST_TYPE_POINTER(PMSGBOXPARAMSW, 40, 4); + TEST_TYPE_SIZE (PMSGBOXPARAMSW, 4) + TEST_TYPE_ALIGN (PMSGBOXPARAMSW, 4) + TEST_TARGET_SIZE (PMSGBOXPARAMSW, 40) + TEST_TARGET_ALIGN(PMSGBOXPARAMSW, 4) } static void test_pack_PMSLLHOOKSTRUCT(void) { /* PMSLLHOOKSTRUCT */ - TEST_TYPE(PMSLLHOOKSTRUCT, 4, 4); - TEST_TYPE_POINTER(PMSLLHOOKSTRUCT, 24, 4); + TEST_TYPE_SIZE (PMSLLHOOKSTRUCT, 4) + TEST_TYPE_ALIGN (PMSLLHOOKSTRUCT, 4) + TEST_TARGET_SIZE (PMSLLHOOKSTRUCT, 24) + TEST_TARGET_ALIGN(PMSLLHOOKSTRUCT, 4) } static void test_pack_PMULTIKEYHELPA(void) { /* PMULTIKEYHELPA */ - TEST_TYPE(PMULTIKEYHELPA, 4, 4); - TEST_TYPE_POINTER(PMULTIKEYHELPA, 8, 4); + TEST_TYPE_SIZE (PMULTIKEYHELPA, 4) + TEST_TYPE_ALIGN (PMULTIKEYHELPA, 4) + TEST_TARGET_SIZE (PMULTIKEYHELPA, 8) + TEST_TARGET_ALIGN(PMULTIKEYHELPA, 4) } static void test_pack_PMULTIKEYHELPW(void) { /* PMULTIKEYHELPW */ - TEST_TYPE(PMULTIKEYHELPW, 4, 4); - TEST_TYPE_POINTER(PMULTIKEYHELPW, 8, 4); + TEST_TYPE_SIZE (PMULTIKEYHELPW, 4) + TEST_TYPE_ALIGN (PMULTIKEYHELPW, 4) + TEST_TARGET_SIZE (PMULTIKEYHELPW, 8) + TEST_TARGET_ALIGN(PMULTIKEYHELPW, 4) } static void test_pack_PNONCLIENTMETRICSA(void) { /* PNONCLIENTMETRICSA */ - TEST_TYPE(PNONCLIENTMETRICSA, 4, 4); - TEST_TYPE_POINTER(PNONCLIENTMETRICSA, 340, 4); + TEST_TYPE_SIZE (PNONCLIENTMETRICSA, 4) + TEST_TYPE_ALIGN (PNONCLIENTMETRICSA, 4) + TEST_TARGET_SIZE (PNONCLIENTMETRICSA, 340) + TEST_TARGET_ALIGN(PNONCLIENTMETRICSA, 4) } static void test_pack_PNONCLIENTMETRICSW(void) { /* PNONCLIENTMETRICSW */ - TEST_TYPE(PNONCLIENTMETRICSW, 4, 4); - TEST_TYPE_POINTER(PNONCLIENTMETRICSW, 500, 4); + TEST_TYPE_SIZE (PNONCLIENTMETRICSW, 4) + TEST_TYPE_ALIGN (PNONCLIENTMETRICSW, 4) + TEST_TARGET_SIZE (PNONCLIENTMETRICSW, 500) + TEST_TARGET_ALIGN(PNONCLIENTMETRICSW, 4) } static void test_pack_PPAINTSTRUCT(void) { /* PPAINTSTRUCT */ - TEST_TYPE(PPAINTSTRUCT, 4, 4); - TEST_TYPE_POINTER(PPAINTSTRUCT, 64, 4); + TEST_TYPE_SIZE (PPAINTSTRUCT, 4) + TEST_TYPE_ALIGN (PPAINTSTRUCT, 4) + TEST_TARGET_SIZE (PPAINTSTRUCT, 64) + TEST_TARGET_ALIGN(PPAINTSTRUCT, 4) } static void test_pack_PROPENUMPROCA(void) { /* PROPENUMPROCA */ - TEST_TYPE(PROPENUMPROCA, 4, 4); + TEST_TYPE_SIZE (PROPENUMPROCA, 4) + TEST_TYPE_ALIGN (PROPENUMPROCA, 4) } static void test_pack_PROPENUMPROCEXA(void) { /* PROPENUMPROCEXA */ - TEST_TYPE(PROPENUMPROCEXA, 4, 4); + TEST_TYPE_SIZE (PROPENUMPROCEXA, 4) + TEST_TYPE_ALIGN (PROPENUMPROCEXA, 4) } static void test_pack_PROPENUMPROCEXW(void) { /* PROPENUMPROCEXW */ - TEST_TYPE(PROPENUMPROCEXW, 4, 4); + TEST_TYPE_SIZE (PROPENUMPROCEXW, 4) + TEST_TYPE_ALIGN (PROPENUMPROCEXW, 4) } static void test_pack_PROPENUMPROCW(void) { /* PROPENUMPROCW */ - TEST_TYPE(PROPENUMPROCW, 4, 4); + TEST_TYPE_SIZE (PROPENUMPROCW, 4) + TEST_TYPE_ALIGN (PROPENUMPROCW, 4) } static void test_pack_PTITLEBARINFO(void) { /* PTITLEBARINFO */ - TEST_TYPE(PTITLEBARINFO, 4, 4); - TEST_TYPE_POINTER(PTITLEBARINFO, 44, 4); + TEST_TYPE_SIZE (PTITLEBARINFO, 4) + TEST_TYPE_ALIGN (PTITLEBARINFO, 4) + TEST_TARGET_SIZE (PTITLEBARINFO, 44) + TEST_TARGET_ALIGN(PTITLEBARINFO, 4) } static void test_pack_PUSEROBJECTFLAGS(void) { /* PUSEROBJECTFLAGS */ - TEST_TYPE(PUSEROBJECTFLAGS, 4, 4); - TEST_TYPE_POINTER(PUSEROBJECTFLAGS, 12, 4); + TEST_TYPE_SIZE (PUSEROBJECTFLAGS, 4) + TEST_TYPE_ALIGN (PUSEROBJECTFLAGS, 4) + TEST_TARGET_SIZE (PUSEROBJECTFLAGS, 12) + TEST_TARGET_ALIGN(PUSEROBJECTFLAGS, 4) } static void test_pack_PWINDOWINFO(void) { /* PWINDOWINFO */ - TEST_TYPE(PWINDOWINFO, 4, 4); - TEST_TYPE_POINTER(PWINDOWINFO, 60, 4); + TEST_TYPE_SIZE (PWINDOWINFO, 4) + TEST_TYPE_ALIGN (PWINDOWINFO, 4) + TEST_TARGET_SIZE (PWINDOWINFO, 60) + TEST_TARGET_ALIGN(PWINDOWINFO, 4) } static void test_pack_PWINDOWPLACEMENT(void) { /* PWINDOWPLACEMENT */ - TEST_TYPE(PWINDOWPLACEMENT, 4, 4); - TEST_TYPE_POINTER(PWINDOWPLACEMENT, 44, 4); + TEST_TYPE_SIZE (PWINDOWPLACEMENT, 4) + TEST_TYPE_ALIGN (PWINDOWPLACEMENT, 4) + TEST_TARGET_SIZE (PWINDOWPLACEMENT, 44) + TEST_TARGET_ALIGN(PWINDOWPLACEMENT, 4) } static void test_pack_PWINDOWPOS(void) { /* PWINDOWPOS */ - TEST_TYPE(PWINDOWPOS, 4, 4); - TEST_TYPE_POINTER(PWINDOWPOS, 28, 4); + TEST_TYPE_SIZE (PWINDOWPOS, 4) + TEST_TYPE_ALIGN (PWINDOWPOS, 4) + TEST_TARGET_SIZE (PWINDOWPOS, 28) + TEST_TARGET_ALIGN(PWINDOWPOS, 4) } static void test_pack_PWNDCLASSA(void) { /* PWNDCLASSA */ - TEST_TYPE(PWNDCLASSA, 4, 4); - TEST_TYPE_POINTER(PWNDCLASSA, 40, 4); + TEST_TYPE_SIZE (PWNDCLASSA, 4) + TEST_TYPE_ALIGN (PWNDCLASSA, 4) + TEST_TARGET_SIZE (PWNDCLASSA, 40) + TEST_TARGET_ALIGN(PWNDCLASSA, 4) } static void test_pack_PWNDCLASSEXA(void) { /* PWNDCLASSEXA */ - TEST_TYPE(PWNDCLASSEXA, 4, 4); - TEST_TYPE_POINTER(PWNDCLASSEXA, 48, 4); + TEST_TYPE_SIZE (PWNDCLASSEXA, 4) + TEST_TYPE_ALIGN (PWNDCLASSEXA, 4) + TEST_TARGET_SIZE (PWNDCLASSEXA, 48) + TEST_TARGET_ALIGN(PWNDCLASSEXA, 4) } static void test_pack_PWNDCLASSEXW(void) { /* PWNDCLASSEXW */ - TEST_TYPE(PWNDCLASSEXW, 4, 4); - TEST_TYPE_POINTER(PWNDCLASSEXW, 48, 4); + TEST_TYPE_SIZE (PWNDCLASSEXW, 4) + TEST_TYPE_ALIGN (PWNDCLASSEXW, 4) + TEST_TARGET_SIZE (PWNDCLASSEXW, 48) + TEST_TARGET_ALIGN(PWNDCLASSEXW, 4) } static void test_pack_PWNDCLASSW(void) { /* PWNDCLASSW */ - TEST_TYPE(PWNDCLASSW, 4, 4); - TEST_TYPE_POINTER(PWNDCLASSW, 40, 4); + TEST_TYPE_SIZE (PWNDCLASSW, 4) + TEST_TYPE_ALIGN (PWNDCLASSW, 4) + TEST_TARGET_SIZE (PWNDCLASSW, 40) + TEST_TARGET_ALIGN(PWNDCLASSW, 4) } static void test_pack_SCROLLINFO(void) { /* SCROLLINFO (pack 4) */ - TEST_TYPE(SCROLLINFO, 28, 4); - TEST_FIELD(SCROLLINFO, UINT, cbSize, 0, 4, 4); - TEST_FIELD(SCROLLINFO, UINT, fMask, 4, 4, 4); - TEST_FIELD(SCROLLINFO, INT, nMin, 8, 4, 4); - TEST_FIELD(SCROLLINFO, INT, nMax, 12, 4, 4); - TEST_FIELD(SCROLLINFO, UINT, nPage, 16, 4, 4); - TEST_FIELD(SCROLLINFO, INT, nPos, 20, 4, 4); - TEST_FIELD(SCROLLINFO, INT, nTrackPos, 24, 4, 4); + TEST_TYPE_SIZE (SCROLLINFO, 28) + TEST_TYPE_ALIGN (SCROLLINFO, 4) + TEST_FIELD_SIZE (SCROLLINFO, cbSize, 4) + TEST_FIELD_ALIGN (SCROLLINFO, cbSize, 4) + TEST_FIELD_OFFSET(SCROLLINFO, cbSize, 0) + TEST_FIELD_SIZE (SCROLLINFO, fMask, 4) + TEST_FIELD_ALIGN (SCROLLINFO, fMask, 4) + TEST_FIELD_OFFSET(SCROLLINFO, fMask, 4) + TEST_FIELD_SIZE (SCROLLINFO, nMin, 4) + TEST_FIELD_ALIGN (SCROLLINFO, nMin, 4) + TEST_FIELD_OFFSET(SCROLLINFO, nMin, 8) + TEST_FIELD_SIZE (SCROLLINFO, nMax, 4) + TEST_FIELD_ALIGN (SCROLLINFO, nMax, 4) + TEST_FIELD_OFFSET(SCROLLINFO, nMax, 12) + TEST_FIELD_SIZE (SCROLLINFO, nPage, 4) + TEST_FIELD_ALIGN (SCROLLINFO, nPage, 4) + TEST_FIELD_OFFSET(SCROLLINFO, nPage, 16) + TEST_FIELD_SIZE (SCROLLINFO, nPos, 4) + TEST_FIELD_ALIGN (SCROLLINFO, nPos, 4) + TEST_FIELD_OFFSET(SCROLLINFO, nPos, 20) + TEST_FIELD_SIZE (SCROLLINFO, nTrackPos, 4) + TEST_FIELD_ALIGN (SCROLLINFO, nTrackPos, 4) + TEST_FIELD_OFFSET(SCROLLINFO, nTrackPos, 24) } static void test_pack_SENDASYNCPROC(void) { /* SENDASYNCPROC */ - TEST_TYPE(SENDASYNCPROC, 4, 4); + TEST_TYPE_SIZE (SENDASYNCPROC, 4) + TEST_TYPE_ALIGN (SENDASYNCPROC, 4) } static void test_pack_SERIALKEYSA(void) { /* SERIALKEYSA (pack 4) */ - TEST_TYPE(SERIALKEYSA, 28, 4); - TEST_FIELD(SERIALKEYSA, UINT, cbSize, 0, 4, 4); - TEST_FIELD(SERIALKEYSA, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(SERIALKEYSA, LPSTR, lpszActivePort, 8, 4, 4); - TEST_FIELD(SERIALKEYSA, LPSTR, lpszPort, 12, 4, 4); - TEST_FIELD(SERIALKEYSA, UINT, iBaudRate, 16, 4, 4); - TEST_FIELD(SERIALKEYSA, UINT, iPortState, 20, 4, 4); - TEST_FIELD(SERIALKEYSA, UINT, iActive, 24, 4, 4); + TEST_TYPE_SIZE (SERIALKEYSA, 28) + TEST_TYPE_ALIGN (SERIALKEYSA, 4) + TEST_FIELD_SIZE (SERIALKEYSA, cbSize, 4) + TEST_FIELD_ALIGN (SERIALKEYSA, cbSize, 4) + TEST_FIELD_OFFSET(SERIALKEYSA, cbSize, 0) + TEST_FIELD_SIZE (SERIALKEYSA, dwFlags, 4) + TEST_FIELD_ALIGN (SERIALKEYSA, dwFlags, 4) + TEST_FIELD_OFFSET(SERIALKEYSA, dwFlags, 4) + TEST_FIELD_SIZE (SERIALKEYSA, lpszActivePort, 4) + TEST_FIELD_ALIGN (SERIALKEYSA, lpszActivePort, 4) + TEST_FIELD_OFFSET(SERIALKEYSA, lpszActivePort, 8) + TEST_FIELD_SIZE (SERIALKEYSA, lpszPort, 4) + TEST_FIELD_ALIGN (SERIALKEYSA, lpszPort, 4) + TEST_FIELD_OFFSET(SERIALKEYSA, lpszPort, 12) + TEST_FIELD_SIZE (SERIALKEYSA, iBaudRate, 4) + TEST_FIELD_ALIGN (SERIALKEYSA, iBaudRate, 4) + TEST_FIELD_OFFSET(SERIALKEYSA, iBaudRate, 16) + TEST_FIELD_SIZE (SERIALKEYSA, iPortState, 4) + TEST_FIELD_ALIGN (SERIALKEYSA, iPortState, 4) + TEST_FIELD_OFFSET(SERIALKEYSA, iPortState, 20) + TEST_FIELD_SIZE (SERIALKEYSA, iActive, 4) + TEST_FIELD_ALIGN (SERIALKEYSA, iActive, 4) + TEST_FIELD_OFFSET(SERIALKEYSA, iActive, 24) } static void test_pack_SERIALKEYSW(void) { /* SERIALKEYSW (pack 4) */ - TEST_TYPE(SERIALKEYSW, 28, 4); - TEST_FIELD(SERIALKEYSW, UINT, cbSize, 0, 4, 4); - TEST_FIELD(SERIALKEYSW, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(SERIALKEYSW, LPWSTR, lpszActivePort, 8, 4, 4); - TEST_FIELD(SERIALKEYSW, LPWSTR, lpszPort, 12, 4, 4); - TEST_FIELD(SERIALKEYSW, UINT, iBaudRate, 16, 4, 4); - TEST_FIELD(SERIALKEYSW, UINT, iPortState, 20, 4, 4); - TEST_FIELD(SERIALKEYSW, UINT, iActive, 24, 4, 4); + TEST_TYPE_SIZE (SERIALKEYSW, 28) + TEST_TYPE_ALIGN (SERIALKEYSW, 4) + TEST_FIELD_SIZE (SERIALKEYSW, cbSize, 4) + TEST_FIELD_ALIGN (SERIALKEYSW, cbSize, 4) + TEST_FIELD_OFFSET(SERIALKEYSW, cbSize, 0) + TEST_FIELD_SIZE (SERIALKEYSW, dwFlags, 4) + TEST_FIELD_ALIGN (SERIALKEYSW, dwFlags, 4) + TEST_FIELD_OFFSET(SERIALKEYSW, dwFlags, 4) + TEST_FIELD_SIZE (SERIALKEYSW, lpszActivePort, 4) + TEST_FIELD_ALIGN (SERIALKEYSW, lpszActivePort, 4) + TEST_FIELD_OFFSET(SERIALKEYSW, lpszActivePort, 8) + TEST_FIELD_SIZE (SERIALKEYSW, lpszPort, 4) + TEST_FIELD_ALIGN (SERIALKEYSW, lpszPort, 4) + TEST_FIELD_OFFSET(SERIALKEYSW, lpszPort, 12) + TEST_FIELD_SIZE (SERIALKEYSW, iBaudRate, 4) + TEST_FIELD_ALIGN (SERIALKEYSW, iBaudRate, 4) + TEST_FIELD_OFFSET(SERIALKEYSW, iBaudRate, 16) + TEST_FIELD_SIZE (SERIALKEYSW, iPortState, 4) + TEST_FIELD_ALIGN (SERIALKEYSW, iPortState, 4) + TEST_FIELD_OFFSET(SERIALKEYSW, iPortState, 20) + TEST_FIELD_SIZE (SERIALKEYSW, iActive, 4) + TEST_FIELD_ALIGN (SERIALKEYSW, iActive, 4) + TEST_FIELD_OFFSET(SERIALKEYSW, iActive, 24) } static void test_pack_SOUNDSENTRYA(void) { /* SOUNDSENTRYA (pack 4) */ - TEST_TYPE(SOUNDSENTRYA, 48, 4); - TEST_FIELD(SOUNDSENTRYA, UINT, cbSize, 0, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iFSTextEffect, 8, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iFSTextEffectMSec, 12, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iFSTextEffectColorBits, 16, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iFSGrafEffect, 20, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iFSGrafEffectMSec, 24, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iFSGrafEffectColor, 28, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iWindowsEffect, 32, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iWindowsEffectMSec, 36, 4, 4); - TEST_FIELD(SOUNDSENTRYA, LPSTR, lpszWindowsEffectDLL, 40, 4, 4); - TEST_FIELD(SOUNDSENTRYA, DWORD, iWindowsEffectOrdinal, 44, 4, 4); + TEST_TYPE_SIZE (SOUNDSENTRYA, 48) + TEST_TYPE_ALIGN (SOUNDSENTRYA, 4) + TEST_FIELD_SIZE (SOUNDSENTRYA, cbSize, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, cbSize, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, cbSize, 0) + TEST_FIELD_SIZE (SOUNDSENTRYA, dwFlags, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, dwFlags, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, dwFlags, 4) + TEST_FIELD_SIZE (SOUNDSENTRYA, iFSTextEffect, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iFSTextEffect, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iFSTextEffect, 8) + TEST_FIELD_SIZE (SOUNDSENTRYA, iFSTextEffectMSec, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iFSTextEffectMSec, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iFSTextEffectMSec, 12) + TEST_FIELD_SIZE (SOUNDSENTRYA, iFSTextEffectColorBits, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iFSTextEffectColorBits, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iFSTextEffectColorBits, 16) + TEST_FIELD_SIZE (SOUNDSENTRYA, iFSGrafEffect, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iFSGrafEffect, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iFSGrafEffect, 20) + TEST_FIELD_SIZE (SOUNDSENTRYA, iFSGrafEffectMSec, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iFSGrafEffectMSec, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iFSGrafEffectMSec, 24) + TEST_FIELD_SIZE (SOUNDSENTRYA, iFSGrafEffectColor, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iFSGrafEffectColor, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iFSGrafEffectColor, 28) + TEST_FIELD_SIZE (SOUNDSENTRYA, iWindowsEffect, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iWindowsEffect, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iWindowsEffect, 32) + TEST_FIELD_SIZE (SOUNDSENTRYA, iWindowsEffectMSec, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iWindowsEffectMSec, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iWindowsEffectMSec, 36) + TEST_FIELD_SIZE (SOUNDSENTRYA, lpszWindowsEffectDLL, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, lpszWindowsEffectDLL, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, lpszWindowsEffectDLL, 40) + TEST_FIELD_SIZE (SOUNDSENTRYA, iWindowsEffectOrdinal, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYA, iWindowsEffectOrdinal, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYA, iWindowsEffectOrdinal, 44) } static void test_pack_SOUNDSENTRYW(void) { /* SOUNDSENTRYW (pack 4) */ - TEST_TYPE(SOUNDSENTRYW, 48, 4); - TEST_FIELD(SOUNDSENTRYW, UINT, cbSize, 0, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iFSTextEffect, 8, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iFSTextEffectMSec, 12, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iFSTextEffectColorBits, 16, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iFSGrafEffect, 20, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iFSGrafEffectMSec, 24, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iFSGrafEffectColor, 28, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iWindowsEffect, 32, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iWindowsEffectMSec, 36, 4, 4); - TEST_FIELD(SOUNDSENTRYW, LPWSTR, lpszWindowsEffectDLL, 40, 4, 4); - TEST_FIELD(SOUNDSENTRYW, DWORD, iWindowsEffectOrdinal, 44, 4, 4); + TEST_TYPE_SIZE (SOUNDSENTRYW, 48) + TEST_TYPE_ALIGN (SOUNDSENTRYW, 4) + TEST_FIELD_SIZE (SOUNDSENTRYW, cbSize, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, cbSize, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, cbSize, 0) + TEST_FIELD_SIZE (SOUNDSENTRYW, dwFlags, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, dwFlags, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, dwFlags, 4) + TEST_FIELD_SIZE (SOUNDSENTRYW, iFSTextEffect, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iFSTextEffect, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iFSTextEffect, 8) + TEST_FIELD_SIZE (SOUNDSENTRYW, iFSTextEffectMSec, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iFSTextEffectMSec, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iFSTextEffectMSec, 12) + TEST_FIELD_SIZE (SOUNDSENTRYW, iFSTextEffectColorBits, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iFSTextEffectColorBits, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iFSTextEffectColorBits, 16) + TEST_FIELD_SIZE (SOUNDSENTRYW, iFSGrafEffect, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iFSGrafEffect, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iFSGrafEffect, 20) + TEST_FIELD_SIZE (SOUNDSENTRYW, iFSGrafEffectMSec, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iFSGrafEffectMSec, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iFSGrafEffectMSec, 24) + TEST_FIELD_SIZE (SOUNDSENTRYW, iFSGrafEffectColor, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iFSGrafEffectColor, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iFSGrafEffectColor, 28) + TEST_FIELD_SIZE (SOUNDSENTRYW, iWindowsEffect, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iWindowsEffect, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iWindowsEffect, 32) + TEST_FIELD_SIZE (SOUNDSENTRYW, iWindowsEffectMSec, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iWindowsEffectMSec, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iWindowsEffectMSec, 36) + TEST_FIELD_SIZE (SOUNDSENTRYW, lpszWindowsEffectDLL, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, lpszWindowsEffectDLL, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, lpszWindowsEffectDLL, 40) + TEST_FIELD_SIZE (SOUNDSENTRYW, iWindowsEffectOrdinal, 4) + TEST_FIELD_ALIGN (SOUNDSENTRYW, iWindowsEffectOrdinal, 4) + TEST_FIELD_OFFSET(SOUNDSENTRYW, iWindowsEffectOrdinal, 44) } static void test_pack_STICKYKEYS(void) { /* STICKYKEYS (pack 4) */ - TEST_TYPE(STICKYKEYS, 8, 4); - TEST_FIELD(STICKYKEYS, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(STICKYKEYS, DWORD, dwFlags, 4, 4, 4); + TEST_TYPE_SIZE (STICKYKEYS, 8) + TEST_TYPE_ALIGN (STICKYKEYS, 4) + TEST_FIELD_SIZE (STICKYKEYS, cbSize, 4) + TEST_FIELD_ALIGN (STICKYKEYS, cbSize, 4) + TEST_FIELD_OFFSET(STICKYKEYS, cbSize, 0) + TEST_FIELD_SIZE (STICKYKEYS, dwFlags, 4) + TEST_FIELD_ALIGN (STICKYKEYS, dwFlags, 4) + TEST_FIELD_OFFSET(STICKYKEYS, dwFlags, 4) } static void test_pack_STYLESTRUCT(void) { /* STYLESTRUCT (pack 4) */ - TEST_TYPE(STYLESTRUCT, 8, 4); - TEST_FIELD(STYLESTRUCT, DWORD, styleOld, 0, 4, 4); - TEST_FIELD(STYLESTRUCT, DWORD, styleNew, 4, 4, 4); + TEST_TYPE_SIZE (STYLESTRUCT, 8) + TEST_TYPE_ALIGN (STYLESTRUCT, 4) + TEST_FIELD_SIZE (STYLESTRUCT, styleOld, 4) + TEST_FIELD_ALIGN (STYLESTRUCT, styleOld, 4) + TEST_FIELD_OFFSET(STYLESTRUCT, styleOld, 0) + TEST_FIELD_SIZE (STYLESTRUCT, styleNew, 4) + TEST_FIELD_ALIGN (STYLESTRUCT, styleNew, 4) + TEST_FIELD_OFFSET(STYLESTRUCT, styleNew, 4) } static void test_pack_TIMERPROC(void) { /* TIMERPROC */ - TEST_TYPE(TIMERPROC, 4, 4); + TEST_TYPE_SIZE (TIMERPROC, 4) + TEST_TYPE_ALIGN (TIMERPROC, 4) } static void test_pack_TITLEBARINFO(void) { /* TITLEBARINFO (pack 4) */ - TEST_TYPE(TITLEBARINFO, 44, 4); - TEST_FIELD(TITLEBARINFO, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(TITLEBARINFO, RECT, rcTitleBar, 4, 16, 4); - TEST_FIELD(TITLEBARINFO, DWORD[CCHILDREN_TITLEBAR+1], rgstate, 20, 24, 4); + TEST_TYPE_SIZE (TITLEBARINFO, 44) + TEST_TYPE_ALIGN (TITLEBARINFO, 4) + TEST_FIELD_SIZE (TITLEBARINFO, cbSize, 4) + TEST_FIELD_ALIGN (TITLEBARINFO, cbSize, 4) + TEST_FIELD_OFFSET(TITLEBARINFO, cbSize, 0) + TEST_FIELD_SIZE (TITLEBARINFO, rcTitleBar, 16) + TEST_FIELD_ALIGN (TITLEBARINFO, rcTitleBar, 4) + TEST_FIELD_OFFSET(TITLEBARINFO, rcTitleBar, 4) + TEST_FIELD_SIZE (TITLEBARINFO, rgstate, 24) + TEST_FIELD_ALIGN (TITLEBARINFO, rgstate, 4) + TEST_FIELD_OFFSET(TITLEBARINFO, rgstate, 20) } static void test_pack_TOGGLEKEYS(void) { /* TOGGLEKEYS (pack 4) */ - TEST_TYPE(TOGGLEKEYS, 8, 4); - TEST_FIELD(TOGGLEKEYS, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(TOGGLEKEYS, DWORD, dwFlags, 4, 4, 4); + TEST_TYPE_SIZE (TOGGLEKEYS, 8) + TEST_TYPE_ALIGN (TOGGLEKEYS, 4) + TEST_FIELD_SIZE (TOGGLEKEYS, cbSize, 4) + TEST_FIELD_ALIGN (TOGGLEKEYS, cbSize, 4) + TEST_FIELD_OFFSET(TOGGLEKEYS, cbSize, 0) + TEST_FIELD_SIZE (TOGGLEKEYS, dwFlags, 4) + TEST_FIELD_ALIGN (TOGGLEKEYS, dwFlags, 4) + TEST_FIELD_OFFSET(TOGGLEKEYS, dwFlags, 4) } static void test_pack_TPMPARAMS(void) { /* TPMPARAMS (pack 4) */ - TEST_TYPE(TPMPARAMS, 20, 4); - TEST_FIELD(TPMPARAMS, UINT, cbSize, 0, 4, 4); - TEST_FIELD(TPMPARAMS, RECT, rcExclude, 4, 16, 4); + TEST_TYPE_SIZE (TPMPARAMS, 20) + TEST_TYPE_ALIGN (TPMPARAMS, 4) + TEST_FIELD_SIZE (TPMPARAMS, cbSize, 4) + TEST_FIELD_ALIGN (TPMPARAMS, cbSize, 4) + TEST_FIELD_OFFSET(TPMPARAMS, cbSize, 0) + TEST_FIELD_SIZE (TPMPARAMS, rcExclude, 16) + TEST_FIELD_ALIGN (TPMPARAMS, rcExclude, 4) + TEST_FIELD_OFFSET(TPMPARAMS, rcExclude, 4) } static void test_pack_TRACKMOUSEEVENT(void) { /* TRACKMOUSEEVENT (pack 4) */ - TEST_TYPE(TRACKMOUSEEVENT, 16, 4); - TEST_FIELD(TRACKMOUSEEVENT, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(TRACKMOUSEEVENT, DWORD, dwFlags, 4, 4, 4); - TEST_FIELD(TRACKMOUSEEVENT, HWND, hwndTrack, 8, 4, 4); - TEST_FIELD(TRACKMOUSEEVENT, DWORD, dwHoverTime, 12, 4, 4); + TEST_TYPE_SIZE (TRACKMOUSEEVENT, 16) + TEST_TYPE_ALIGN (TRACKMOUSEEVENT, 4) + TEST_FIELD_SIZE (TRACKMOUSEEVENT, cbSize, 4) + TEST_FIELD_ALIGN (TRACKMOUSEEVENT, cbSize, 4) + TEST_FIELD_OFFSET(TRACKMOUSEEVENT, cbSize, 0) + TEST_FIELD_SIZE (TRACKMOUSEEVENT, dwFlags, 4) + TEST_FIELD_ALIGN (TRACKMOUSEEVENT, dwFlags, 4) + TEST_FIELD_OFFSET(TRACKMOUSEEVENT, dwFlags, 4) + TEST_FIELD_SIZE (TRACKMOUSEEVENT, hwndTrack, 4) + TEST_FIELD_ALIGN (TRACKMOUSEEVENT, hwndTrack, 4) + TEST_FIELD_OFFSET(TRACKMOUSEEVENT, hwndTrack, 8) + TEST_FIELD_SIZE (TRACKMOUSEEVENT, dwHoverTime, 4) + TEST_FIELD_ALIGN (TRACKMOUSEEVENT, dwHoverTime, 4) + TEST_FIELD_OFFSET(TRACKMOUSEEVENT, dwHoverTime, 12) } static void test_pack_USEROBJECTFLAGS(void) { /* USEROBJECTFLAGS (pack 4) */ - TEST_TYPE(USEROBJECTFLAGS, 12, 4); - TEST_FIELD(USEROBJECTFLAGS, BOOL, fInherit, 0, 4, 4); - TEST_FIELD(USEROBJECTFLAGS, BOOL, fReserved, 4, 4, 4); - TEST_FIELD(USEROBJECTFLAGS, DWORD, dwFlags, 8, 4, 4); + TEST_TYPE_SIZE (USEROBJECTFLAGS, 12) + TEST_TYPE_ALIGN (USEROBJECTFLAGS, 4) + TEST_FIELD_SIZE (USEROBJECTFLAGS, fInherit, 4) + TEST_FIELD_ALIGN (USEROBJECTFLAGS, fInherit, 4) + TEST_FIELD_OFFSET(USEROBJECTFLAGS, fInherit, 0) + TEST_FIELD_SIZE (USEROBJECTFLAGS, fReserved, 4) + TEST_FIELD_ALIGN (USEROBJECTFLAGS, fReserved, 4) + TEST_FIELD_OFFSET(USEROBJECTFLAGS, fReserved, 4) + TEST_FIELD_SIZE (USEROBJECTFLAGS, dwFlags, 4) + TEST_FIELD_ALIGN (USEROBJECTFLAGS, dwFlags, 4) + TEST_FIELD_OFFSET(USEROBJECTFLAGS, dwFlags, 8) } static void test_pack_WINDOWINFO(void) { /* WINDOWINFO (pack 4) */ - TEST_TYPE(WINDOWINFO, 60, 4); - TEST_FIELD(WINDOWINFO, DWORD, cbSize, 0, 4, 4); - TEST_FIELD(WINDOWINFO, RECT, rcWindow, 4, 16, 4); - TEST_FIELD(WINDOWINFO, RECT, rcClient, 20, 16, 4); - TEST_FIELD(WINDOWINFO, DWORD, dwStyle, 36, 4, 4); - TEST_FIELD(WINDOWINFO, DWORD, dwExStyle, 40, 4, 4); - TEST_FIELD(WINDOWINFO, DWORD, dwWindowStatus, 44, 4, 4); - TEST_FIELD(WINDOWINFO, UINT, cxWindowBorders, 48, 4, 4); - TEST_FIELD(WINDOWINFO, UINT, cyWindowBorders, 52, 4, 4); - TEST_FIELD(WINDOWINFO, ATOM, atomWindowType, 56, 2, 2); - TEST_FIELD(WINDOWINFO, WORD, wCreatorVersion, 58, 2, 2); + TEST_TYPE_SIZE (WINDOWINFO, 60) + TEST_TYPE_ALIGN (WINDOWINFO, 4) + TEST_FIELD_SIZE (WINDOWINFO, cbSize, 4) + TEST_FIELD_ALIGN (WINDOWINFO, cbSize, 4) + TEST_FIELD_OFFSET(WINDOWINFO, cbSize, 0) + TEST_FIELD_SIZE (WINDOWINFO, rcWindow, 16) + TEST_FIELD_ALIGN (WINDOWINFO, rcWindow, 4) + TEST_FIELD_OFFSET(WINDOWINFO, rcWindow, 4) + TEST_FIELD_SIZE (WINDOWINFO, rcClient, 16) + TEST_FIELD_ALIGN (WINDOWINFO, rcClient, 4) + TEST_FIELD_OFFSET(WINDOWINFO, rcClient, 20) + TEST_FIELD_SIZE (WINDOWINFO, dwStyle, 4) + TEST_FIELD_ALIGN (WINDOWINFO, dwStyle, 4) + TEST_FIELD_OFFSET(WINDOWINFO, dwStyle, 36) + TEST_FIELD_SIZE (WINDOWINFO, dwExStyle, 4) + TEST_FIELD_ALIGN (WINDOWINFO, dwExStyle, 4) + TEST_FIELD_OFFSET(WINDOWINFO, dwExStyle, 40) + TEST_FIELD_SIZE (WINDOWINFO, dwWindowStatus, 4) + TEST_FIELD_ALIGN (WINDOWINFO, dwWindowStatus, 4) + TEST_FIELD_OFFSET(WINDOWINFO, dwWindowStatus, 44) + TEST_FIELD_SIZE (WINDOWINFO, cxWindowBorders, 4) + TEST_FIELD_ALIGN (WINDOWINFO, cxWindowBorders, 4) + TEST_FIELD_OFFSET(WINDOWINFO, cxWindowBorders, 48) + TEST_FIELD_SIZE (WINDOWINFO, cyWindowBorders, 4) + TEST_FIELD_ALIGN (WINDOWINFO, cyWindowBorders, 4) + TEST_FIELD_OFFSET(WINDOWINFO, cyWindowBorders, 52) + TEST_FIELD_SIZE (WINDOWINFO, atomWindowType, 2) + TEST_FIELD_ALIGN (WINDOWINFO, atomWindowType, 2) + TEST_FIELD_OFFSET(WINDOWINFO, atomWindowType, 56) + TEST_FIELD_SIZE (WINDOWINFO, wCreatorVersion, 2) + TEST_FIELD_ALIGN (WINDOWINFO, wCreatorVersion, 2) + TEST_FIELD_OFFSET(WINDOWINFO, wCreatorVersion, 58) } static void test_pack_WINDOWPLACEMENT(void) { /* WINDOWPLACEMENT (pack 4) */ - TEST_TYPE(WINDOWPLACEMENT, 44, 4); - TEST_FIELD(WINDOWPLACEMENT, UINT, length, 0, 4, 4); - TEST_FIELD(WINDOWPLACEMENT, UINT, flags, 4, 4, 4); - TEST_FIELD(WINDOWPLACEMENT, UINT, showCmd, 8, 4, 4); - TEST_FIELD(WINDOWPLACEMENT, POINT, ptMinPosition, 12, 8, 4); - TEST_FIELD(WINDOWPLACEMENT, POINT, ptMaxPosition, 20, 8, 4); - TEST_FIELD(WINDOWPLACEMENT, RECT, rcNormalPosition, 28, 16, 4); + TEST_TYPE_SIZE (WINDOWPLACEMENT, 44) + TEST_TYPE_ALIGN (WINDOWPLACEMENT, 4) + TEST_FIELD_SIZE (WINDOWPLACEMENT, length, 4) + TEST_FIELD_ALIGN (WINDOWPLACEMENT, length, 4) + TEST_FIELD_OFFSET(WINDOWPLACEMENT, length, 0) + TEST_FIELD_SIZE (WINDOWPLACEMENT, flags, 4) + TEST_FIELD_ALIGN (WINDOWPLACEMENT, flags, 4) + TEST_FIELD_OFFSET(WINDOWPLACEMENT, flags, 4) + TEST_FIELD_SIZE (WINDOWPLACEMENT, showCmd, 4) + TEST_FIELD_ALIGN (WINDOWPLACEMENT, showCmd, 4) + TEST_FIELD_OFFSET(WINDOWPLACEMENT, showCmd, 8) + TEST_FIELD_SIZE (WINDOWPLACEMENT, ptMinPosition, 8) + TEST_FIELD_ALIGN (WINDOWPLACEMENT, ptMinPosition, 4) + TEST_FIELD_OFFSET(WINDOWPLACEMENT, ptMinPosition, 12) + TEST_FIELD_SIZE (WINDOWPLACEMENT, ptMaxPosition, 8) + TEST_FIELD_ALIGN (WINDOWPLACEMENT, ptMaxPosition, 4) + TEST_FIELD_OFFSET(WINDOWPLACEMENT, ptMaxPosition, 20) + TEST_FIELD_SIZE (WINDOWPLACEMENT, rcNormalPosition, 16) + TEST_FIELD_ALIGN (WINDOWPLACEMENT, rcNormalPosition, 4) + TEST_FIELD_OFFSET(WINDOWPLACEMENT, rcNormalPosition, 28) } static void test_pack_WINDOWPOS(void) { /* WINDOWPOS (pack 4) */ - TEST_TYPE(WINDOWPOS, 28, 4); - TEST_FIELD(WINDOWPOS, HWND, hwnd, 0, 4, 4); - TEST_FIELD(WINDOWPOS, HWND, hwndInsertAfter, 4, 4, 4); - TEST_FIELD(WINDOWPOS, INT, x, 8, 4, 4); - TEST_FIELD(WINDOWPOS, INT, y, 12, 4, 4); - TEST_FIELD(WINDOWPOS, INT, cx, 16, 4, 4); - TEST_FIELD(WINDOWPOS, INT, cy, 20, 4, 4); - TEST_FIELD(WINDOWPOS, UINT, flags, 24, 4, 4); + TEST_TYPE_SIZE (WINDOWPOS, 28) + TEST_TYPE_ALIGN (WINDOWPOS, 4) + TEST_FIELD_SIZE (WINDOWPOS, hwnd, 4) + TEST_FIELD_ALIGN (WINDOWPOS, hwnd, 4) + TEST_FIELD_OFFSET(WINDOWPOS, hwnd, 0) + TEST_FIELD_SIZE (WINDOWPOS, hwndInsertAfter, 4) + TEST_FIELD_ALIGN (WINDOWPOS, hwndInsertAfter, 4) + TEST_FIELD_OFFSET(WINDOWPOS, hwndInsertAfter, 4) + TEST_FIELD_SIZE (WINDOWPOS, x, 4) + TEST_FIELD_ALIGN (WINDOWPOS, x, 4) + TEST_FIELD_OFFSET(WINDOWPOS, x, 8) + TEST_FIELD_SIZE (WINDOWPOS, y, 4) + TEST_FIELD_ALIGN (WINDOWPOS, y, 4) + TEST_FIELD_OFFSET(WINDOWPOS, y, 12) + TEST_FIELD_SIZE (WINDOWPOS, cx, 4) + TEST_FIELD_ALIGN (WINDOWPOS, cx, 4) + TEST_FIELD_OFFSET(WINDOWPOS, cx, 16) + TEST_FIELD_SIZE (WINDOWPOS, cy, 4) + TEST_FIELD_ALIGN (WINDOWPOS, cy, 4) + TEST_FIELD_OFFSET(WINDOWPOS, cy, 20) + TEST_FIELD_SIZE (WINDOWPOS, flags, 4) + TEST_FIELD_ALIGN (WINDOWPOS, flags, 4) + TEST_FIELD_OFFSET(WINDOWPOS, flags, 24) } static void test_pack_WINEVENTPROC(void) { /* WINEVENTPROC */ - TEST_TYPE(WINEVENTPROC, 4, 4); + TEST_TYPE_SIZE (WINEVENTPROC, 4) + TEST_TYPE_ALIGN (WINEVENTPROC, 4) } static void test_pack_WINSTAENUMPROCA(void) { /* WINSTAENUMPROCA */ - TEST_TYPE(WINSTAENUMPROCA, 4, 4); + TEST_TYPE_SIZE (WINSTAENUMPROCA, 4) + TEST_TYPE_ALIGN (WINSTAENUMPROCA, 4) } static void test_pack_WINSTAENUMPROCW(void) { /* WINSTAENUMPROCW */ - TEST_TYPE(WINSTAENUMPROCW, 4, 4); + TEST_TYPE_SIZE (WINSTAENUMPROCW, 4) + TEST_TYPE_ALIGN (WINSTAENUMPROCW, 4) } static void test_pack_WNDCLASSA(void) { /* WNDCLASSA (pack 4) */ - TEST_TYPE(WNDCLASSA, 40, 4); - TEST_FIELD(WNDCLASSA, UINT, style, 0, 4, 4); - TEST_FIELD(WNDCLASSA, WNDPROC, lpfnWndProc, 4, 4, 4); - TEST_FIELD(WNDCLASSA, INT, cbClsExtra, 8, 4, 4); - TEST_FIELD(WNDCLASSA, INT, cbWndExtra, 12, 4, 4); - TEST_FIELD(WNDCLASSA, HINSTANCE, hInstance, 16, 4, 4); - TEST_FIELD(WNDCLASSA, HICON, hIcon, 20, 4, 4); - TEST_FIELD(WNDCLASSA, HCURSOR, hCursor, 24, 4, 4); - TEST_FIELD(WNDCLASSA, HBRUSH, hbrBackground, 28, 4, 4); - TEST_FIELD(WNDCLASSA, LPCSTR, lpszMenuName, 32, 4, 4); - TEST_FIELD(WNDCLASSA, LPCSTR, lpszClassName, 36, 4, 4); + TEST_TYPE_SIZE (WNDCLASSA, 40) + TEST_TYPE_ALIGN (WNDCLASSA, 4) + TEST_FIELD_SIZE (WNDCLASSA, style, 4) + TEST_FIELD_ALIGN (WNDCLASSA, style, 4) + TEST_FIELD_OFFSET(WNDCLASSA, style, 0) + TEST_FIELD_SIZE (WNDCLASSA, lpfnWndProc, 4) + TEST_FIELD_ALIGN (WNDCLASSA, lpfnWndProc, 4) + TEST_FIELD_OFFSET(WNDCLASSA, lpfnWndProc, 4) + TEST_FIELD_SIZE (WNDCLASSA, cbClsExtra, 4) + TEST_FIELD_ALIGN (WNDCLASSA, cbClsExtra, 4) + TEST_FIELD_OFFSET(WNDCLASSA, cbClsExtra, 8) + TEST_FIELD_SIZE (WNDCLASSA, cbWndExtra, 4) + TEST_FIELD_ALIGN (WNDCLASSA, cbWndExtra, 4) + TEST_FIELD_OFFSET(WNDCLASSA, cbWndExtra, 12) + TEST_FIELD_SIZE (WNDCLASSA, hInstance, 4) + TEST_FIELD_ALIGN (WNDCLASSA, hInstance, 4) + TEST_FIELD_OFFSET(WNDCLASSA, hInstance, 16) + TEST_FIELD_SIZE (WNDCLASSA, hIcon, 4) + TEST_FIELD_ALIGN (WNDCLASSA, hIcon, 4) + TEST_FIELD_OFFSET(WNDCLASSA, hIcon, 20) + TEST_FIELD_SIZE (WNDCLASSA, hCursor, 4) + TEST_FIELD_ALIGN (WNDCLASSA, hCursor, 4) + TEST_FIELD_OFFSET(WNDCLASSA, hCursor, 24) + TEST_FIELD_SIZE (WNDCLASSA, hbrBackground, 4) + TEST_FIELD_ALIGN (WNDCLASSA, hbrBackground, 4) + TEST_FIELD_OFFSET(WNDCLASSA, hbrBackground, 28) + TEST_FIELD_SIZE (WNDCLASSA, lpszMenuName, 4) + TEST_FIELD_ALIGN (WNDCLASSA, lpszMenuName, 4) + TEST_FIELD_OFFSET(WNDCLASSA, lpszMenuName, 32) + TEST_FIELD_SIZE (WNDCLASSA, lpszClassName, 4) + TEST_FIELD_ALIGN (WNDCLASSA, lpszClassName, 4) + TEST_FIELD_OFFSET(WNDCLASSA, lpszClassName, 36) } static void test_pack_WNDCLASSEXA(void) { /* WNDCLASSEXA (pack 4) */ - TEST_TYPE(WNDCLASSEXA, 48, 4); - TEST_FIELD(WNDCLASSEXA, UINT, cbSize, 0, 4, 4); - TEST_FIELD(WNDCLASSEXA, UINT, style, 4, 4, 4); - TEST_FIELD(WNDCLASSEXA, WNDPROC, lpfnWndProc, 8, 4, 4); - TEST_FIELD(WNDCLASSEXA, INT, cbClsExtra, 12, 4, 4); - TEST_FIELD(WNDCLASSEXA, INT, cbWndExtra, 16, 4, 4); - TEST_FIELD(WNDCLASSEXA, HINSTANCE, hInstance, 20, 4, 4); - TEST_FIELD(WNDCLASSEXA, HICON, hIcon, 24, 4, 4); - TEST_FIELD(WNDCLASSEXA, HCURSOR, hCursor, 28, 4, 4); - TEST_FIELD(WNDCLASSEXA, HBRUSH, hbrBackground, 32, 4, 4); - TEST_FIELD(WNDCLASSEXA, LPCSTR, lpszMenuName, 36, 4, 4); - TEST_FIELD(WNDCLASSEXA, LPCSTR, lpszClassName, 40, 4, 4); - TEST_FIELD(WNDCLASSEXA, HICON, hIconSm, 44, 4, 4); + TEST_TYPE_SIZE (WNDCLASSEXA, 48) + TEST_TYPE_ALIGN (WNDCLASSEXA, 4) + TEST_FIELD_SIZE (WNDCLASSEXA, cbSize, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, cbSize, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, cbSize, 0) + TEST_FIELD_SIZE (WNDCLASSEXA, style, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, style, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, style, 4) + TEST_FIELD_SIZE (WNDCLASSEXA, lpfnWndProc, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, lpfnWndProc, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, lpfnWndProc, 8) + TEST_FIELD_SIZE (WNDCLASSEXA, cbClsExtra, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, cbClsExtra, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, cbClsExtra, 12) + TEST_FIELD_SIZE (WNDCLASSEXA, cbWndExtra, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, cbWndExtra, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, cbWndExtra, 16) + TEST_FIELD_SIZE (WNDCLASSEXA, hInstance, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, hInstance, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, hInstance, 20) + TEST_FIELD_SIZE (WNDCLASSEXA, hIcon, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, hIcon, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, hIcon, 24) + TEST_FIELD_SIZE (WNDCLASSEXA, hCursor, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, hCursor, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, hCursor, 28) + TEST_FIELD_SIZE (WNDCLASSEXA, hbrBackground, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, hbrBackground, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, hbrBackground, 32) + TEST_FIELD_SIZE (WNDCLASSEXA, lpszMenuName, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, lpszMenuName, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, lpszMenuName, 36) + TEST_FIELD_SIZE (WNDCLASSEXA, lpszClassName, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, lpszClassName, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, lpszClassName, 40) + TEST_FIELD_SIZE (WNDCLASSEXA, hIconSm, 4) + TEST_FIELD_ALIGN (WNDCLASSEXA, hIconSm, 4) + TEST_FIELD_OFFSET(WNDCLASSEXA, hIconSm, 44) } static void test_pack_WNDCLASSEXW(void) { /* WNDCLASSEXW (pack 4) */ - TEST_TYPE(WNDCLASSEXW, 48, 4); - TEST_FIELD(WNDCLASSEXW, UINT, cbSize, 0, 4, 4); - TEST_FIELD(WNDCLASSEXW, UINT, style, 4, 4, 4); - TEST_FIELD(WNDCLASSEXW, WNDPROC, lpfnWndProc, 8, 4, 4); - TEST_FIELD(WNDCLASSEXW, INT, cbClsExtra, 12, 4, 4); - TEST_FIELD(WNDCLASSEXW, INT, cbWndExtra, 16, 4, 4); - TEST_FIELD(WNDCLASSEXW, HINSTANCE, hInstance, 20, 4, 4); - TEST_FIELD(WNDCLASSEXW, HICON, hIcon, 24, 4, 4); - TEST_FIELD(WNDCLASSEXW, HCURSOR, hCursor, 28, 4, 4); - TEST_FIELD(WNDCLASSEXW, HBRUSH, hbrBackground, 32, 4, 4); - TEST_FIELD(WNDCLASSEXW, LPCWSTR, lpszMenuName, 36, 4, 4); - TEST_FIELD(WNDCLASSEXW, LPCWSTR, lpszClassName, 40, 4, 4); - TEST_FIELD(WNDCLASSEXW, HICON, hIconSm, 44, 4, 4); + TEST_TYPE_SIZE (WNDCLASSEXW, 48) + TEST_TYPE_ALIGN (WNDCLASSEXW, 4) + TEST_FIELD_SIZE (WNDCLASSEXW, cbSize, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, cbSize, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, cbSize, 0) + TEST_FIELD_SIZE (WNDCLASSEXW, style, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, style, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, style, 4) + TEST_FIELD_SIZE (WNDCLASSEXW, lpfnWndProc, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, lpfnWndProc, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, lpfnWndProc, 8) + TEST_FIELD_SIZE (WNDCLASSEXW, cbClsExtra, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, cbClsExtra, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, cbClsExtra, 12) + TEST_FIELD_SIZE (WNDCLASSEXW, cbWndExtra, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, cbWndExtra, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, cbWndExtra, 16) + TEST_FIELD_SIZE (WNDCLASSEXW, hInstance, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, hInstance, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, hInstance, 20) + TEST_FIELD_SIZE (WNDCLASSEXW, hIcon, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, hIcon, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, hIcon, 24) + TEST_FIELD_SIZE (WNDCLASSEXW, hCursor, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, hCursor, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, hCursor, 28) + TEST_FIELD_SIZE (WNDCLASSEXW, hbrBackground, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, hbrBackground, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, hbrBackground, 32) + TEST_FIELD_SIZE (WNDCLASSEXW, lpszMenuName, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, lpszMenuName, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, lpszMenuName, 36) + TEST_FIELD_SIZE (WNDCLASSEXW, lpszClassName, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, lpszClassName, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, lpszClassName, 40) + TEST_FIELD_SIZE (WNDCLASSEXW, hIconSm, 4) + TEST_FIELD_ALIGN (WNDCLASSEXW, hIconSm, 4) + TEST_FIELD_OFFSET(WNDCLASSEXW, hIconSm, 44) } static void test_pack_WNDCLASSW(void) { /* WNDCLASSW (pack 4) */ - TEST_TYPE(WNDCLASSW, 40, 4); - TEST_FIELD(WNDCLASSW, UINT, style, 0, 4, 4); - TEST_FIELD(WNDCLASSW, WNDPROC, lpfnWndProc, 4, 4, 4); - TEST_FIELD(WNDCLASSW, INT, cbClsExtra, 8, 4, 4); - TEST_FIELD(WNDCLASSW, INT, cbWndExtra, 12, 4, 4); - TEST_FIELD(WNDCLASSW, HINSTANCE, hInstance, 16, 4, 4); - TEST_FIELD(WNDCLASSW, HICON, hIcon, 20, 4, 4); - TEST_FIELD(WNDCLASSW, HCURSOR, hCursor, 24, 4, 4); - TEST_FIELD(WNDCLASSW, HBRUSH, hbrBackground, 28, 4, 4); - TEST_FIELD(WNDCLASSW, LPCWSTR, lpszMenuName, 32, 4, 4); - TEST_FIELD(WNDCLASSW, LPCWSTR, lpszClassName, 36, 4, 4); + TEST_TYPE_SIZE (WNDCLASSW, 40) + TEST_TYPE_ALIGN (WNDCLASSW, 4) + TEST_FIELD_SIZE (WNDCLASSW, style, 4) + TEST_FIELD_ALIGN (WNDCLASSW, style, 4) + TEST_FIELD_OFFSET(WNDCLASSW, style, 0) + TEST_FIELD_SIZE (WNDCLASSW, lpfnWndProc, 4) + TEST_FIELD_ALIGN (WNDCLASSW, lpfnWndProc, 4) + TEST_FIELD_OFFSET(WNDCLASSW, lpfnWndProc, 4) + TEST_FIELD_SIZE (WNDCLASSW, cbClsExtra, 4) + TEST_FIELD_ALIGN (WNDCLASSW, cbClsExtra, 4) + TEST_FIELD_OFFSET(WNDCLASSW, cbClsExtra, 8) + TEST_FIELD_SIZE (WNDCLASSW, cbWndExtra, 4) + TEST_FIELD_ALIGN (WNDCLASSW, cbWndExtra, 4) + TEST_FIELD_OFFSET(WNDCLASSW, cbWndExtra, 12) + TEST_FIELD_SIZE (WNDCLASSW, hInstance, 4) + TEST_FIELD_ALIGN (WNDCLASSW, hInstance, 4) + TEST_FIELD_OFFSET(WNDCLASSW, hInstance, 16) + TEST_FIELD_SIZE (WNDCLASSW, hIcon, 4) + TEST_FIELD_ALIGN (WNDCLASSW, hIcon, 4) + TEST_FIELD_OFFSET(WNDCLASSW, hIcon, 20) + TEST_FIELD_SIZE (WNDCLASSW, hCursor, 4) + TEST_FIELD_ALIGN (WNDCLASSW, hCursor, 4) + TEST_FIELD_OFFSET(WNDCLASSW, hCursor, 24) + TEST_FIELD_SIZE (WNDCLASSW, hbrBackground, 4) + TEST_FIELD_ALIGN (WNDCLASSW, hbrBackground, 4) + TEST_FIELD_OFFSET(WNDCLASSW, hbrBackground, 28) + TEST_FIELD_SIZE (WNDCLASSW, lpszMenuName, 4) + TEST_FIELD_ALIGN (WNDCLASSW, lpszMenuName, 4) + TEST_FIELD_OFFSET(WNDCLASSW, lpszMenuName, 32) + TEST_FIELD_SIZE (WNDCLASSW, lpszClassName, 4) + TEST_FIELD_ALIGN (WNDCLASSW, lpszClassName, 4) + TEST_FIELD_OFFSET(WNDCLASSW, lpszClassName, 36) } static void test_pack_WNDENUMPROC(void) { /* WNDENUMPROC */ - TEST_TYPE(WNDENUMPROC, 4, 4); + TEST_TYPE_SIZE (WNDENUMPROC, 4) + TEST_TYPE_ALIGN (WNDENUMPROC, 4) } static void test_pack_WNDPROC(void) { /* WNDPROC */ - TEST_TYPE(WNDPROC, 4, 4); + TEST_TYPE_SIZE (WNDPROC, 4) + TEST_TYPE_ALIGN (WNDPROC, 4) } static void test_pack(void) @@ -2477,5 +3835,9 @@ static void test_pack(void) START_TEST(generated) { +#ifdef _WIN64 + ok(0, "The type size / alignment tests don't support Win64 yet\n"); +#else test_pack(); +#endif } diff --git a/rostests/winetests/user32/input.c b/rostests/winetests/user32/input.c index 07df61f9eab..460e0fb986c 100755 --- a/rostests/winetests/user32/input.c +++ b/rostests/winetests/user32/input.c @@ -44,23 +44,41 @@ * */ +#define _WIN32_WINNT 0x500 +#define _WIN32_IE 0x0500 + #include #include #include "windef.h" #include "winbase.h" -#include "wine/winuser.h" +#include "winuser.h" #include "wine/test.h" /* globals */ static HWND hWndTest; -static long timetag = 0x10000000; +static LONG timetag = 0x10000000; + +static struct { + LONG last_key_down; + LONG last_key_up; + LONG last_syskey_down; + LONG last_syskey_up; + LONG last_char; + LONG last_syschar; + LONG last_hook_down; + LONG last_hook_up; + LONG last_hook_syskey_down; + LONG last_hook_syskey_up; + BOOL expect_alt; + BOOL sendinput_broken; +} key_status; static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); static int (WINAPI *pGetMouseMovePointsEx) (UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD); -#define MAXKEYEVENTS 6 +#define MAXKEYEVENTS 12 #define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one and only one message */ @@ -200,7 +218,7 @@ static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam ) * . retrieve the messages from the input queue * . verify */ -static void do_test( HWND hwnd, int seqnr, const KEV td[] ) +static BOOL do_test( HWND hwnd, int seqnr, const KEV td[] ) { INPUT inputs[MAXKEYEVENTS]; KMSG expmsg[MAXKEYEVENTS]; @@ -235,20 +253,25 @@ static void do_test( HWND hwnd, int seqnr, const KEV td[] ) ok( msg.message == expmsg[i].message && msg.wParam == expmsg[i].wParam && msg.lParam == expmsg[i].lParam, - "wrong message! expected:\n" - "message[%d] %-15s wParam %04lx lParam %08lx\n",i, - MSGNAME[(expmsg[i]).message - WM_KEYFIRST], - expmsg[i].wParam, expmsg[i].lParam ); + "%u/%u: wrong message %x/%08lx/%08lx expected %s/%08lx/%08lx\n", + seqnr, i, msg.message, msg.wParam, msg.lParam, + MSGNAME[(expmsg[i]).message - WM_KEYFIRST], expmsg[i].wParam, expmsg[i].lParam ); } i++; } if (winetest_debug > 1) trace("%d messages retrieved\n", i); + if (!i && kmctr) + { + skip( "simulated keyboard input doesn't work\n" ); + return FALSE; + } ok( i == kmctr, "message count is wrong: got %d expected: %d\n", i, kmctr); + return TRUE; } /* test all combinations of the specified key events */ -static void TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[] ) +static BOOL TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[] ) { int i,j,k,l,m,n; static int count=0; @@ -263,7 +286,7 @@ static void TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[ kbuf[1] = kevdwn[1-i]; kbuf[2] = kevup[j]; kbuf[3] = kevup[1-j]; - do_test( hWnd, count++, kbuf); + if (!do_test( hWnd, count++, kbuf)) return FALSE; } } } @@ -285,7 +308,7 @@ static void TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[ kbuf[3] = kevup[l]; kbuf[4] = kevup[m]; kbuf[5] = kevup[n]; - do_test( hWnd, count++, kbuf); + if (!do_test( hWnd, count++, kbuf)) return FALSE; } } } @@ -293,6 +316,7 @@ static void TestASet( HWND hWnd, int nrkev, const KEV kevdwn[], const KEV kevup[ } } } + return TRUE; } /* test each set specified in the global testkeyset array */ @@ -300,32 +324,15 @@ static void TestSysKeys( HWND hWnd) { int i; for(i=0; testkeyset[i].nrkev;i++) - TestASet( hWnd, testkeyset[i].nrkev, testkeyset[i].keydwn, - testkeyset[i].keyup); + if (!TestASet( hWnd, testkeyset[i].nrkev, testkeyset[i].keydwn, testkeyset[i].keyup)) break; } static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { - switch (msg) { - case WM_USER: - SetFocus(hWnd); - /* window has focus, now do the test */ - if( hWnd == hWndTest) TestSysKeys( hWnd); - /* finished :-) */ - break; - - case WM_DESTROY: - PostQuitMessage( 0 ); - break; - - default: - return( DefWindowProcA( hWnd, msg, wParam, lParam ) ); + return DefWindowProcA( hWnd, msg, wParam, lParam ); } - return 0; -} - static void test_Input_whitebox(void) { MSG msg; @@ -336,38 +343,55 @@ static void test_Input_whitebox(void) wclass.style = CS_HREDRAW | CS_VREDRAW; wclass.lpfnWndProc = WndProc; wclass.hInstance = hInstance; - wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION ); + wclass.hIcon = LoadIconA( 0, IDI_APPLICATION ); wclass.hCursor = LoadCursorA( NULL, IDC_ARROW); wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1); wclass.lpszMenuName = 0; wclass.cbClsExtra = 0; wclass.cbWndExtra = 0; - assert (RegisterClassA( &wclass )); + RegisterClassA( &wclass ); /* create the test window that will receive the keystrokes */ - assert ( hWndTest = CreateWindowA( wclass.lpszClassName, "InputSysKeyTest", + hWndTest = CreateWindowA( wclass.lpszClassName, "InputSysKeyTest", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100, - NULL, NULL, hInstance, NULL) ); + NULL, NULL, hInstance, NULL); + assert( hWndTest ); ShowWindow( hWndTest, SW_SHOW); + SetWindowPos( hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); + SetForegroundWindow( hWndTest ); UpdateWindow( hWndTest); /* flush pending messages */ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); - SendMessageA(hWndTest, WM_USER, 0, 0); + SetFocus( hWndTest ); + TestSysKeys( hWndTest ); DestroyWindow(hWndTest); } -static void empty_message_queue(void) { +/* try to make sure pending X events have been processed before continuing */ +static void empty_message_queue(void) +{ MSG msg; - while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + int diff = 200; + int min_timeout = 50; + DWORD time = GetTickCount() + diff; + + while (diff > 0) + { + if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { TranslateMessage(&msg); DispatchMessage(&msg); } + diff = time - GetTickCount(); +} } struct transition_s { WORD wVk; BYTE before_state; + BYTE optional; }; typedef enum { @@ -398,6 +422,7 @@ struct sendinput_test_s { struct message expected_messages[MAXKEYMESSAGES+1]; } sendinput_test[] = { /* test ALT+F */ + /* 0 */ {VK_LMENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, {{WM_SYSKEYDOWN, hook|wparam, VK_LMENU}, {WM_SYSKEYDOWN}, {0}}}, {'F', 0, 0, {{'F', 0x00}, {0}}, @@ -410,6 +435,7 @@ struct sendinput_test_s { {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, /* test CTRL+O */ + /* 4 */ {VK_LCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, {'O', 0, 0, {{'O', 0x00}, {0}}, @@ -420,6 +446,7 @@ struct sendinput_test_s { {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, /* test ALT+CTRL+X */ + /* 8 */ {VK_LMENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, {0}}}, {VK_LCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, @@ -434,6 +461,7 @@ struct sendinput_test_s { {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, /* test SHIFT+A */ + /* 14 */ {VK_LSHIFT, 0, 0, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, {'A', 0, 0, {{'A', 0x00}, {0}}, @@ -444,16 +472,19 @@ struct sendinput_test_s { {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, /* test L-SHIFT & R-SHIFT: */ /* RSHIFT == LSHIFT */ + /* 18 */ {VK_RSHIFT, 0, 0, - {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, + /* recent windows versions (>= w2k3) correctly report an RSHIFT transition */ + {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00, TRUE}, {VK_RSHIFT, 0x00, TRUE}, {0}}, {{WM_KEYDOWN, hook|wparam, VK_RSHIFT}, {WM_KEYDOWN}, {0}}}, {VK_RSHIFT, KEYEVENTF_KEYUP, 0, - {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, + {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80, TRUE}, {VK_RSHIFT, 0x80, TRUE}, {0}}, {{WM_KEYUP, hook, hook|wparam, VK_RSHIFT}, {WM_KEYUP}, {0}}}, /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ + /* 20 */ {VK_LSHIFT, KEYEVENTF_EXTENDEDKEY, 0, {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, LLKHF_EXTENDED}, @@ -463,6 +494,7 @@ struct sendinput_test_s { {{WM_KEYUP, hook|wparam|lparam, VK_LSHIFT, LLKHF_UP|LLKHF_EXTENDED}, {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ + /* 22 */ {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, 0, {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED}, @@ -471,27 +503,35 @@ struct sendinput_test_s { {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}}, {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED}, {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, + + /* Note about wparam for hook with generic key (VK_SHIFT, VK_CONTROL, VK_MENU): + win2k - sends to hook whatever we generated here + winXP+ - Attempts to convert key to L/R key but not always correct + */ /* SHIFT == LSHIFT */ + /* 24 */ {VK_SHIFT, 0, 0, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_SHIFT, 0}, + {{WM_KEYDOWN, hook/* |wparam */|lparam, VK_SHIFT, 0}, {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, {VK_SHIFT, KEYEVENTF_KEYUP, 0, {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_SHIFT, LLKHF_UP}, + {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP}, {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ + /* 26 */ {VK_SHIFT, KEYEVENTF_EXTENDEDKEY, 0, {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_SHIFT, LLKHF_EXTENDED}, + {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_EXTENDED}, {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, {VK_SHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED}, + {{WM_KEYUP, hook/*|wparam*/|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED}, {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, /* test L-CONTROL & R-CONTROL: */ /* RCONTROL == LCONTROL */ + /* 28 */ {VK_RCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, {{WM_KEYDOWN, hook|wparam, VK_RCONTROL}, @@ -501,6 +541,7 @@ struct sendinput_test_s { {{WM_KEYUP, hook|wparam, VK_RCONTROL}, {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}}, /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ + /* 30 */ {VK_LCONTROL, KEYEVENTF_EXTENDEDKEY, 0, {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, {{WM_KEYDOWN, hook|wparam|lparam, VK_LCONTROL, LLKHF_EXTENDED}, @@ -510,6 +551,7 @@ struct sendinput_test_s { {{WM_KEYUP, hook|wparam|lparam, VK_LCONTROL, LLKHF_UP|LLKHF_EXTENDED}, {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ + /* 32 */ {VK_RCONTROL, KEYEVENTF_EXTENDEDKEY, 0, {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, {{WM_KEYDOWN, hook|wparam|lparam, VK_RCONTROL, LLKHF_EXTENDED}, @@ -519,36 +561,44 @@ struct sendinput_test_s { {{WM_KEYUP, hook|wparam|lparam, VK_RCONTROL, LLKHF_UP|LLKHF_EXTENDED}, {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, /* CONTROL == LCONTROL */ + /* 34 */ {VK_CONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam, VK_CONTROL}, + {{WM_KEYDOWN, hook/*|wparam, VK_CONTROL*/}, {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}}, {VK_CONTROL, KEYEVENTF_KEYUP, 0, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam, VK_CONTROL}, + {{WM_KEYUP, hook/*|wparam, VK_CONTROL*/}, {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}}, /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ + /* 36 */ {VK_CONTROL, KEYEVENTF_EXTENDEDKEY, 0, {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, - {{WM_KEYDOWN, hook|wparam|lparam, VK_CONTROL, LLKHF_EXTENDED}, + {{WM_KEYDOWN, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_EXTENDED}, {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}}, {VK_CONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED}, + {{WM_KEYUP, hook/*|wparam*/|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED}, {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, /* test L-MENU & R-MENU: */ /* RMENU == LMENU */ + /* 38 */ {VK_RMENU, 0, 0, - {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam, VK_RMENU}, + {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam|optional, VK_LCONTROL}, + {WM_SYSKEYDOWN, hook|wparam, VK_RMENU}, + {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0}, {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}}, {VK_RMENU, KEYEVENTF_KEYUP, 1, - {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam, VK_RMENU}, + {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}}, + {{WM_KEYUP, hook|wparam|optional, VK_LCONTROL}, + {WM_KEYUP, hook|wparam, VK_RMENU}, + {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP}, {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP}, - {WM_SYSCOMMAND}, {0}}}, + {WM_SYSCOMMAND, optional}, {0}}}, /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */ + /* 40 */ {VK_LMENU, KEYEVENTF_EXTENDEDKEY, 0, {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}}, {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_LMENU, LLKHF_EXTENDED}, @@ -559,37 +609,47 @@ struct sendinput_test_s { {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, {WM_SYSCOMMAND}, {0}}}, /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */ + /* 42 */ {VK_RMENU, KEYEVENTF_EXTENDEDKEY, 0, - {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_RMENU, LLKHF_EXTENDED}, + {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_LCONTROL, 0}, + {WM_SYSKEYDOWN, hook|wparam|lparam, VK_RMENU, LLKHF_EXTENDED}, + {WM_KEYDOWN, wparam|lparam|optional, VK_CONTROL, 0}, {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}}, {VK_RMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1, - {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_RMENU, LLKHF_UP|LLKHF_EXTENDED}, + {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}}, + {{WM_KEYUP, hook|wparam|lparam|optional, VK_LCONTROL, LLKHF_UP}, + {WM_KEYUP, hook|wparam|lparam, VK_RMENU, LLKHF_UP|LLKHF_EXTENDED}, + {WM_SYSKEYUP, wparam|lparam|optional, VK_CONTROL, KF_UP}, {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, - {WM_SYSCOMMAND}, {0}}}, + {WM_SYSCOMMAND, optional}, {0}}}, /* MENU == LMENU */ + /* 44 */ {VK_MENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam, VK_MENU}, + {{WM_SYSKEYDOWN, hook/*|wparam, VK_MENU*/}, {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}}, {VK_MENU, KEYEVENTF_KEYUP, 1, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam, VK_MENU}, + {{WM_KEYUP, hook/*|wparam, VK_MENU*/}, {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP}, {WM_SYSCOMMAND}, {0}}}, /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */ + /* 46 */ {VK_MENU, KEYEVENTF_EXTENDEDKEY, 0, - {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}}, - {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_MENU, LLKHF_EXTENDED}, + {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {VK_CONTROL, 0x00, 1}, {VK_LCONTROL, 0x01, 1}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam|lparam|optional, VK_CONTROL, 0}, + {WM_SYSKEYDOWN, hook/*|wparam*/|lparam, VK_MENU, LLKHF_EXTENDED}, {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}}, {VK_MENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1, - {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}}, - {{WM_KEYUP, hook|wparam|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED}, + {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {VK_CONTROL, 0x81, 1}, {VK_LCONTROL, 0x80, 1}, {0}}, + {{WM_KEYUP, hook|wparam|lparam|optional, VK_CONTROL, LLKHF_UP}, + {WM_KEYUP, hook/*|wparam*/|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED}, {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, {WM_SYSCOMMAND}, {0}}}, /* test LSHIFT & RSHIFT */ + /* 48 */ {VK_LSHIFT, 0, 0, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, 0}, @@ -625,19 +685,19 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes int matched = ((ks1[t->wVk]&0x80) == (t->before_state&0x80) && (ks2[t->wVk]&0x80) == (~t->before_state&0x80)); - if (!matched && test->_todo_wine) + if (!matched && !t->optional && test->_todo_wine) { failcount++; todo_wine { - ok(matched, "%02d: %02x from %02x -> %02x " - "instead of %02x -> %02x\n", id, t->wVk, - ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state, + ok(matched, "%2d (%x/%x): %02x from %02x -> %02x " + "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags, + t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state, ~t->before_state&0x80); } } else { - ok(matched, "%02d: %02x from %02x -> %02x " - "instead of %02x -> %02x\n", id, t->wVk, - ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state, + ok(matched || t->optional, "%2d (%x/%x): %02x from %02x -> %02x " + "instead of %02x -> %02x\n", id, test->wVk, test->dwFlags, + t->wVk, ks1[t->wVk]&0x80, ks2[t->wVk]&0x80, t->before_state, ~t->before_state&0x80); } ks2[t->wVk] = ks1[t->wVk]; /* clear the match */ @@ -648,11 +708,12 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes { failcount++; todo_wine - ok(FALSE, "%02d: %02x from %02x -> %02x unexpected\n", id, i, ks1[i], ks2[i]); + ok(FALSE, "%2d (%x/%x): %02x from %02x -> %02x unexpected\n", + id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]); } else - ok(ks2[i] == ks1[i], "%02d: %02x from %02x -> %02x unexpected\n", - id, i, ks1[i], ks2[i]); + ok(ks2[i] == ks1[i], "%2d (%x/%x): %02x from %02x -> %02x unexpected\n", + id, test->wVk, test->dwFlags, i, ks1[i], ks2[i]); while (expected->message && actual_cnt < sent_messages_cnt) { @@ -660,23 +721,24 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes if (expected->message == actual->message) { - ok((expected->flags & hook) == (actual->flags & hook), - "%x/%x: the msg 0x%04x should have been sent by a hook\n", - test->wVk, test->dwFlags, expected->message); - if (expected->flags & wparam) { + if ((expected->flags & optional) && (expected->wParam != actual->wParam)) + { + expected++; + continue; + } if (expected->wParam != actual->wParam && test->_todo_wine) { failcount++; todo_wine - ok(FALSE, "%x/%x: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam); + ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", + id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam); } else ok(expected->wParam == actual->wParam, - "%x/%x: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam); + "%2d (%x/%x): in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", + id, test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam); } if (expected->flags & lparam) { @@ -684,32 +746,55 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes { failcount++; todo_wine - ok(FALSE, "%x/%x: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam); + ok(FALSE, "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam); } else ok(expected->lParam == actual->lParam, - "%x/%x: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam); + "%2d (%x/%x): in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + id, test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam); } + ok((expected->flags & hook) == (actual->flags & hook), + "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n", + id, test->wVk, test->dwFlags, expected->message); + } else if (expected->flags & optional) { expected++; continue; } + /* NT4 doesn't send SYSKEYDOWN/UP to hooks, only KEYDOWN/UP */ + else if ((expected->flags & hook) && + (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) && + (actual->message == expected->message - 4)) + { + ok((expected->flags & hook) == (actual->flags & hook), + "%2d (%x/%x): the msg 0x%04x should have been sent by a hook\n", + id, test->wVk, test->dwFlags, expected->message); + } + /* For VK_RMENU, at least localized Win2k/XP sends KEYDOWN/UP + * instead of SYSKEYDOWN/UP to the WNDPROC */ + else if (test->wVk == VK_RMENU && !(expected->flags & hook) && + (expected->message == WM_SYSKEYDOWN || expected->message == WM_SYSKEYUP) && + (actual->message == expected->message - 4)) + { + ok(expected->wParam == actual->wParam && expected->lParam == actual->lParam, + "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n", + id, test->wVk, test->dwFlags, expected->message, actual->message); + } else if (test->_todo_wine) { failcount++; todo_wine ok(FALSE, - "%x/%x: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - test->wVk, test->dwFlags, expected->message, actual->message); + "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n", + id, test->wVk, test->dwFlags, expected->message, actual->message); } else ok(FALSE, - "%x/%x: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - test->wVk, test->dwFlags, expected->message, actual->message); + "%2d (%x/%x): the msg 0x%04x was expected, but got msg 0x%04x instead\n", + id, test->wVk, test->dwFlags, expected->message, actual->message); actual_cnt++; expected++; @@ -725,17 +810,17 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_tes { failcount++; todo_wine - ok(FALSE, "%x/%x: the msg sequence is not complete: expected %04x - actual %04x\n", - test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message); + ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n", + id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message); } else - ok(FALSE, "%x/%x: the msg sequence is not complete: expected %04x - actual %04x\n", - test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message); + ok(FALSE, "%2d (%x/%x): the msg sequence is not complete: expected %04x - actual %04x\n", + id, test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message); } if( test->_todo_wine && !failcount) /* succeeded yet marked todo */ todo_wine - ok(TRUE, "%x/%x: marked \"todo_wine\" but succeeds\n", test->wVk, test->dwFlags); + ok(TRUE, "%2d (%x/%x): marked \"todo_wine\" but succeeds\n", id, test->wVk, test->dwFlags); sent_messages_cnt = 0; } @@ -753,13 +838,19 @@ static LRESULT CALLBACK WndProc2(HWND hWnd, UINT Msg, WPARAM wParam, Msg != WM_NCHITTEST && Msg != WM_GETTEXT && Msg != WM_GETICON && - Msg != WM_DEVICECHANGE) + Msg != WM_IME_SELECT && + Msg != WM_DEVICECHANGE && + Msg != WM_TIMECHANGE) { + ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n"); + if (sent_messages_cnt < MAXKEYMESSAGES) + { sent_messages[sent_messages_cnt].message = Msg; sent_messages[sent_messages_cnt].flags = 0; sent_messages[sent_messages_cnt].wParam = wParam; sent_messages[sent_messages_cnt++].lParam = HIWORD(lParam) & (KF_UP|KF_EXTENDED); } + } return DefWindowProc(hWnd, Msg, wParam, lParam); } @@ -769,10 +860,14 @@ static LRESULT CALLBACK hook_proc(int code, WPARAM wparam, LPARAM lparam) if (code == HC_ACTION) { + ok(sent_messages_cnt < MAXKEYMESSAGES, "Too many messages\n"); + if (sent_messages_cnt < MAXKEYMESSAGES) + { sent_messages[sent_messages_cnt].message = wparam; sent_messages[sent_messages_cnt].flags = hook; sent_messages[sent_messages_cnt].wParam = hook_info->vkCode; sent_messages[sent_messages_cnt++].lParam = hook_info->flags & (LLKHF_UP|LLKHF_EXTENDED); + } if(0) /* For some reason not stable on Wine */ { @@ -797,18 +892,24 @@ static void test_Input_blackbox(void) HWND window; HHOOK hook; - if (!pSendInput) + if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409) { - skip("SendInput is not available\n"); + skip("Skipping Input_blackbox test on non-US keyboard\n"); return; } - window = CreateWindow("Static", NULL, WS_POPUP|WS_HSCROLL|WS_VSCROLL |WS_VISIBLE, 0, 0, 200, 60, NULL, NULL, NULL, NULL); ok(window != NULL, "error: %d\n", (int) GetLastError()); + SetWindowPos( window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); + SetForegroundWindow( window ); - hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, GetModuleHandleA( NULL ), 0); + if (!(hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, GetModuleHandleA( NULL ), 0))) + { + DestroyWindow(window); + win_skip("WH_KEYBOARD_LL is not supported\n"); + return; + } /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets * key state set by SendInput(). */ @@ -831,6 +932,14 @@ static void test_Input_blackbox(void) pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT)); empty_message_queue(); GetKeyboardState(ks2); + if (!ii && sent_messages_cnt <= 1 && !memcmp( ks1, ks2, sizeof(ks1) )) + { + win_skip( "window doesn't receive the queued input\n" ); + /* release the key */ + i.u.ki.dwFlags |= KEYEVENTF_KEYUP; + pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT)); + break; + } compare_and_check(ii, ks1, ks2, &sendinput_test[ii]); } @@ -839,6 +948,241 @@ static void test_Input_blackbox(void) UnhookWindowsHookEx(hook); } +static void reset_key_status(void) +{ + key_status.last_key_down = -1; + key_status.last_key_up = -1; + key_status.last_syskey_down = -1; + key_status.last_syskey_up = -1; + key_status.last_char = -1; + key_status.last_syschar = -1; + key_status.last_hook_down = -1; + key_status.last_hook_up = -1; + key_status.last_hook_syskey_down = -1; + key_status.last_hook_syskey_up = -1; + key_status.expect_alt = FALSE; + key_status.sendinput_broken = FALSE; +} + +static void test_unicode_keys(HWND hwnd, HHOOK hook) +{ + TEST_INPUT inputs[2]; + MSG msg; + + /* init input data that never changes */ + inputs[1].type = inputs[0].type = INPUT_KEYBOARD; + inputs[1].u.ki.dwExtraInfo = inputs[0].u.ki.dwExtraInfo = 0; + inputs[1].u.ki.time = inputs[0].u.ki.time = 0; + + /* pressing & releasing a single unicode character */ + inputs[0].u.ki.wVk = 0; + inputs[0].u.ki.wScan = 0x3c0; + inputs[0].u.ki.dwFlags = KEYEVENTF_UNICODE; + + reset_key_status(); + pSendInput(1, (INPUT*)inputs, sizeof(INPUT)); + while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){ + if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){ + TranslateMessage(&msg); + } + DispatchMessageW(&msg); + } + if(!key_status.sendinput_broken){ + ok(key_status.last_key_down == VK_PACKET, + "Last keydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_down); + ok(key_status.last_char == 0x3c0, + "Last char msg wparam should have been 0x3c0 (was: 0x%x)\n", key_status.last_char); + if(hook) + ok(key_status.last_hook_down == 0x3c0, + "Last hookdown msg should have been 0x3c0, was: 0x%x\n", key_status.last_hook_down); + } + + inputs[1].u.ki.wVk = 0; + inputs[1].u.ki.wScan = 0x3c0; + inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; + + reset_key_status(); + pSendInput(1, (INPUT*)(inputs+1), sizeof(INPUT)); + while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){ + if(msg.message == WM_KEYDOWN && msg.wParam == VK_PACKET){ + TranslateMessage(&msg); + } + DispatchMessageW(&msg); + } + if(!key_status.sendinput_broken){ + ok(key_status.last_key_up == VK_PACKET, + "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_up); + if(hook) + ok(key_status.last_hook_up == 0x3c0, + "Last hookup msg should have been 0x3c0, was: 0x%x\n", key_status.last_hook_up); + } + + /* holding alt, pressing & releasing a unicode character, releasing alt */ + inputs[0].u.ki.wVk = VK_LMENU; + inputs[0].u.ki.wScan = 0; + inputs[0].u.ki.dwFlags = 0; + + inputs[1].u.ki.wVk = 0; + inputs[1].u.ki.wScan = 0x3041; + inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE; + + reset_key_status(); + key_status.expect_alt = TRUE; + pSendInput(2, (INPUT*)inputs, sizeof(INPUT)); + while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){ + if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){ + TranslateMessage(&msg); + } + DispatchMessageW(&msg); + } + if(!key_status.sendinput_broken){ + ok(key_status.last_syskey_down == VK_PACKET, + "Last syskeydown msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_syskey_down); + ok(key_status.last_syschar == 0x3041, + "Last syschar msg should have been 0x3041 (was: 0x%x)\n", key_status.last_syschar); + if(hook) + ok(key_status.last_hook_syskey_down == 0x3041, + "Last hooksysdown msg should have been 0x3041, was: 0x%x\n", key_status.last_hook_syskey_down); + } + + inputs[1].u.ki.wVk = 0; + inputs[1].u.ki.wScan = 0x3041; + inputs[1].u.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; + + inputs[0].u.ki.wVk = VK_LMENU; + inputs[0].u.ki.wScan = 0; + inputs[0].u.ki.dwFlags = KEYEVENTF_KEYUP; + + reset_key_status(); + key_status.expect_alt = TRUE; + pSendInput(2, (INPUT*)inputs, sizeof(INPUT)); + while(PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)){ + if(msg.message == WM_SYSKEYDOWN && msg.wParam == VK_PACKET){ + TranslateMessage(&msg); + } + DispatchMessageW(&msg); + } + if(!key_status.sendinput_broken){ + ok(key_status.last_key_up == VK_PACKET, + "Last keyup msg should have been VK_PACKET[0x%04x] (was: 0x%x)\n", VK_PACKET, key_status.last_key_up); + if(hook) + ok(key_status.last_hook_up == 0x3041, + "Last hook up msg should have been 0x3041, was: 0x%x\n", key_status.last_hook_up); + } +} + +static LRESULT CALLBACK unicode_wnd_proc( HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam ) +{ + switch(msg){ + case WM_KEYDOWN: + key_status.last_key_down = wParam; + break; + case WM_SYSKEYDOWN: + key_status.last_syskey_down = wParam; + break; + case WM_KEYUP: + key_status.last_key_up = wParam; + break; + case WM_SYSKEYUP: + key_status.last_syskey_up = wParam; + break; + case WM_CHAR: + key_status.last_char = wParam; + break; + case WM_SYSCHAR: + key_status.last_syschar = wParam; + break; + } + return DefWindowProcW(hWnd, msg, wParam, lParam); +} + +static LRESULT CALLBACK llkbd_unicode_hook(int nCode, WPARAM wParam, LPARAM lParam) +{ + if(nCode == HC_ACTION){ + LPKBDLLHOOKSTRUCT info = (LPKBDLLHOOKSTRUCT)lParam; + if(!info->vkCode){ + key_status.sendinput_broken = TRUE; + win_skip("SendInput doesn't support unicode on this platform\n"); + }else{ + if(key_status.expect_alt){ + ok(info->vkCode == VK_LMENU, "vkCode should have been VK_LMENU[0x%04x], was: 0x%x\n", VK_LMENU, info->vkCode); + key_status.expect_alt = FALSE; + }else + ok(info->vkCode == VK_PACKET, "vkCode should have been VK_PACKET[0x%04x], was: 0x%x\n", VK_PACKET, info->vkCode); + } + switch(wParam){ + case WM_KEYDOWN: + key_status.last_hook_down = info->scanCode; + break; + case WM_KEYUP: + key_status.last_hook_up = info->scanCode; + break; + case WM_SYSKEYDOWN: + key_status.last_hook_syskey_down = info->scanCode; + break; + case WM_SYSKEYUP: + key_status.last_hook_syskey_up = info->scanCode; + break; + } + } + return CallNextHookEx(NULL, nCode, wParam, lParam); +} + +static void test_Input_unicode(void) +{ + WCHAR classNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e', + 'K','e','y','T','e','s','t','C','l','a','s','s',0}; + WCHAR windowNameW[] = {'I','n','p','u','t','U','n','i','c','o','d','e', + 'K','e','y','T','e','s','t',0}; + MSG msg; + WNDCLASSW wclass; + HANDLE hInstance = GetModuleHandleW(NULL); + HHOOK hook; + + wclass.lpszClassName = classNameW; + wclass.style = CS_HREDRAW | CS_VREDRAW; + wclass.lpfnWndProc = unicode_wnd_proc; + wclass.hInstance = hInstance; + wclass.hIcon = LoadIcon(0, IDI_APPLICATION); + wclass.hCursor = LoadCursor( NULL, IDC_ARROW); + wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wclass.lpszMenuName = 0; + wclass.cbClsExtra = 0; + wclass.cbWndExtra = 0; + if(!RegisterClassW(&wclass)){ + win_skip("Unicode functions not supported\n"); + return; + } + /* create the test window that will receive the keystrokes */ + hWndTest = CreateWindowW(wclass.lpszClassName, windowNameW, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 100, 100, + NULL, NULL, hInstance, NULL); + + assert(hWndTest); + assert(IsWindowUnicode(hWndTest)); + + hook = SetWindowsHookExW(WH_KEYBOARD_LL, llkbd_unicode_hook, GetModuleHandleW(NULL), 0); + if(!hook) + win_skip("unable to set WH_KEYBOARD_LL hook\n"); + + ShowWindow(hWndTest, SW_SHOW); + SetWindowPos(hWndTest, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hWndTest); + UpdateWindow(hWndTest); + + /* flush pending messages */ + while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageW(&msg); + + SetFocus(hWndTest); + + test_unicode_keys(hWndTest, hook); + + if(hook) + UnhookWindowsHookEx(hook); + DestroyWindow(hWndTest); +} + static void test_keynames(void) { int i, len; @@ -854,7 +1198,7 @@ static void test_keynames(void) static POINT pt_old, pt_new; static BOOL clipped; -#define STEP 20 +#define STEP 3 static LRESULT CALLBACK hook_proc1( int code, WPARAM wparam, LPARAM lparam ) { @@ -914,7 +1258,11 @@ static void test_mouse_ll_hook(void) 10, 10, 200, 200, NULL, NULL, NULL, NULL); SetCursorPos(100, 100); - hook2 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc2, GetModuleHandleA(0), 0); + if (!(hook2 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc2, GetModuleHandleA(0), 0))) + { + win_skip( "cannot set MOUSE_LL hook\n" ); + goto done; + } hook1 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc1, GetModuleHandleA(0), 0); GetCursorPos(&pt_old); @@ -971,6 +1319,7 @@ static void test_mouse_ll_hook(void) ok(pt.x == pt_new.x && pt.y == pt_new.y, "Position changed: (%d,%d)\n", pt.x, pt.y); UnhookWindowsHookEx(hook2); +done: DestroyWindow(hwnd); SetCursorPos(pt_org.x, pt_org.y); } @@ -999,20 +1348,25 @@ static void test_GetMouseMovePointsEx(void) */ SetLastError(MYERROR); retval = pGetMouseMovePointsEx(0, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); + if (retval == ERROR_INVALID_PARAMETER) + { + win_skip( "GetMouseMovePointsEx broken on WinME\n" ); + return; + } ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)+1, &in, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); /* test second and third parameter @@ -1020,7 +1374,7 @@ static void test_GetMouseMovePointsEx(void) SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_NOACCESS == GetLastError(), + ok(GetLastError() == ERROR_NOACCESS || GetLastError() == MYERROR, "expected error ERROR_NOACCESS, got %u\n", GetLastError()); SetLastError(MYERROR); @@ -1038,11 +1392,10 @@ static void test_GetMouseMovePointsEx(void) SetLastError(MYERROR); count = 0; retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, count, GMMP_USE_DISPLAY_POINTS); - todo_wine { + if (retval == -1) + ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError()); + else ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval); - ok(MYERROR == GetLastError(), - "expected error %d, got %u\n", MYERROR, GetLastError()); - } /* test fourth parameter * a value higher than 64 is expected to fail with ERROR_INVALID_PARAMETER @@ -1051,31 +1404,29 @@ static void test_GetMouseMovePointsEx(void) count = -1; retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS); ok(retval == count, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); SetLastError(MYERROR); count = 0; retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS); - todo_wine { + if (retval == -1) + ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError()); + else ok(retval == count, "expected GetMouseMovePointsEx to succeed, got %d\n", retval); - ok(MYERROR == GetLastError(), - "expected error %d, got %u\n", MYERROR, GetLastError()); - } SetLastError(MYERROR); count = BUFLIM; retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, count, GMMP_USE_DISPLAY_POINTS); - todo_wine { + if (retval == -1) + ok(GetLastError() == ERROR_POINT_NOT_FOUND, "unexpected error %u\n", GetLastError()); + else ok((0 <= retval) && (retval <= count), "expected GetMouseMovePointsEx to succeed, got %d\n", retval); - ok(MYERROR == GetLastError(), - "expected error %d, got %u\n", MYERROR, GetLastError()); - } SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); /* it was not possible to force an error with the fifth parameter on win2k */ @@ -1084,25 +1435,25 @@ static void test_GetMouseMovePointsEx(void) SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, NULL, out, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT)-1, &in, NULL, BUFLIM, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), NULL, out, BUFLIM+1, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); SetLastError(MYERROR); retval = pGetMouseMovePointsEx(sizeof(MOUSEMOVEPOINT), &in, NULL, BUFLIM+1, GMMP_USE_DISPLAY_POINTS); ok(retval == -1, "expected GetMouseMovePointsEx to fail, got %d\n", retval); - ok(ERROR_INVALID_PARAMETER == GetLastError(), + ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == MYERROR, "expected error ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); #undef BUFLIM @@ -1113,11 +1464,24 @@ static void test_key_map(void) { HKL kl = GetKeyboardLayout(0); UINT kL, kR, s, sL; + int i; + static const UINT numpad_collisions[][2] = { + { VK_NUMPAD0, VK_INSERT }, + { VK_NUMPAD1, VK_END }, + { VK_NUMPAD2, VK_DOWN }, + { VK_NUMPAD3, VK_NEXT }, + { VK_NUMPAD4, VK_LEFT }, + { VK_NUMPAD6, VK_RIGHT }, + { VK_NUMPAD7, VK_HOME }, + { VK_NUMPAD8, VK_UP }, + { VK_NUMPAD9, VK_PRIOR }, + }; s = MapVirtualKeyEx(VK_SHIFT, MAPVK_VK_TO_VSC, kl); ok(s != 0, "MapVirtualKeyEx(VK_SHIFT) should return non-zero\n"); sL = MapVirtualKeyEx(VK_LSHIFT, MAPVK_VK_TO_VSC, kl); - ok(s == sL, "%x != %x\n", s, sL); + ok(s == sL || broken(sL == 0), /* win9x */ + "%x != %x\n", s, sL); kL = MapVirtualKeyEx(0x2a, MAPVK_VSC_TO_VK, kl); ok(kL == VK_SHIFT, "Scan code -> vKey = %x (not VK_SHIFT)\n", kL); @@ -1125,27 +1489,110 @@ static void test_key_map(void) ok(kR == VK_SHIFT, "Scan code -> vKey = %x (not VK_SHIFT)\n", kR); kL = MapVirtualKeyEx(0x2a, MAPVK_VSC_TO_VK_EX, kl); - ok(kL == VK_LSHIFT, "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL); + ok(kL == VK_LSHIFT || broken(kL == 0), /* win9x */ + "Scan code -> vKey = %x (not VK_LSHIFT)\n", kL); kR = MapVirtualKeyEx(0x36, MAPVK_VSC_TO_VK_EX, kl); - ok(kR == VK_RSHIFT, "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR); + ok(kR == VK_RSHIFT || broken(kR == 0), /* win9x */ + "Scan code -> vKey = %x (not VK_RSHIFT)\n", kR); + + /* test that MAPVK_VSC_TO_VK prefers the non-numpad vkey if there's ambiguity */ + for (i = 0; i < sizeof(numpad_collisions)/sizeof(numpad_collisions[0]); i++) + { + UINT numpad_scan = MapVirtualKeyEx(numpad_collisions[i][0], MAPVK_VK_TO_VSC, kl); + UINT other_scan = MapVirtualKeyEx(numpad_collisions[i][1], MAPVK_VK_TO_VSC, kl); + + /* do they really collide for this layout? */ + if (numpad_scan && other_scan == numpad_scan) + { + UINT vkey = MapVirtualKeyEx(numpad_scan, MAPVK_VSC_TO_VK, kl); + ok(vkey != numpad_collisions[i][0], + "Got numpad vKey %x for scan code %x when there was another choice\n", + vkey, numpad_scan); +} + } +} + +static void test_ToUnicode(void) +{ + WCHAR wStr[2]; + BYTE state[256]; + const BYTE SC_RETURN = 0x1c, SC_TAB = 0x0f; + const BYTE HIGHEST_BIT = 0x80; + int i, ret; + for(i=0; i<256; i++) + state[i]=0; + + SetLastError(0xdeadbeef); + ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("ToUnicode is not implemented\n"); + return; + } + + ok(ret == 1, "ToUnicode for Return key didn't return 1 (was %i)\n", ret); + if(ret == 1) + ok(wStr[0]=='\r', "ToUnicode for CTRL + Return was %i (expected 13)\n", wStr[0]); + state[VK_CONTROL] |= HIGHEST_BIT; + state[VK_LCONTROL] |= HIGHEST_BIT; + + ret = ToUnicode(VK_TAB, SC_TAB, state, wStr, 2, 0); + ok(ret == 0, "ToUnicode for CTRL + Tab didn't return 0 (was %i)\n", ret); + + ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0); + ok(ret == 1, "ToUnicode for CTRL + Return didn't return 1 (was %i)\n", ret); + if(ret == 1) + ok(wStr[0]=='\n', "ToUnicode for CTRL + Return was %i (expected 10)\n", wStr[0]); + + state[VK_SHIFT] |= HIGHEST_BIT; + state[VK_LSHIFT] |= HIGHEST_BIT; + ret = ToUnicode(VK_TAB, SC_TAB, state, wStr, 2, 0); + ok(ret == 0, "ToUnicode for CTRL + SHIFT + Tab didn't return 0 (was %i)\n", ret); + ret = ToUnicode(VK_RETURN, SC_RETURN, state, wStr, 2, 0); + todo_wine ok(ret == 0, "ToUnicode for CTRL + SHIFT + Return didn't return 0 (was %i)\n", ret); +} + +static void test_get_async_key_state(void) +{ + /* input value sanity checks */ + ok(0 == GetAsyncKeyState(1000000), "GetAsyncKeyState did not return 0\n"); + ok(0 == GetAsyncKeyState(-1000000), "GetAsyncKeyState did not return 0\n"); +} + +static void test_keyboard_layout_name(void) +{ + BOOL ret; + char klid[KL_NAMELENGTH]; + + if (GetKeyboardLayout(0) != (HKL)(ULONG_PTR)0x04090409) return; + + klid[0] = 0; + ret = GetKeyboardLayoutNameA(klid); + ok(ret, "GetKeyboardLayoutNameA failed %u\n", GetLastError()); + ok(!strcmp(klid, "00000409"), "expected 00000409, got %s\n", klid); } START_TEST(input) { init_function_pointers(); - if (!pSendInput) - skip("SendInput is not available\n"); - else + if (pSendInput) + { + test_Input_blackbox(); test_Input_whitebox(); + test_Input_unicode(); + } + else win_skip("SendInput is not available\n"); - test_Input_blackbox(); test_keynames(); test_mouse_ll_hook(); test_key_map(); + test_ToUnicode(); + test_get_async_key_state(); + test_keyboard_layout_name(); if(pGetMouseMovePointsEx) test_GetMouseMovePointsEx(); else - skip("GetMouseMovePointsEx is not available\n"); + win_skip("GetMouseMovePointsEx is not available\n"); } diff --git a/rostests/winetests/user32/listbox.c b/rostests/winetests/user32/listbox.c index 5e650e089bc..9ca6f2027cd 100644 --- a/rostests/winetests/user32/listbox.c +++ b/rostests/winetests/user32/listbox.c @@ -44,13 +44,13 @@ static const char * const strings[4] = { "Fourth added which is very long because at some time we only had a 256 byte character buffer and that was overflowing in one of those applications that had a common dialog file open box and tried to add a 300 characters long custom filter string which of course the code did not like and crashed. Just make sure this string is longer than 256 characters." }; -static const char BAD_EXTENSION[] = "*.txtbad"; +static const char BAD_EXTENSION[] = "*.badtxt"; static HWND create_listbox (DWORD add_style, HWND parent) { HWND handle; - int ctl_id=0; + INT_PTR ctl_id=0; if (parent) ctl_id=1; handle=CreateWindow ("LISTBOX", "TestList", @@ -59,10 +59,10 @@ create_listbox (DWORD add_style, HWND parent) parent, (HMENU)ctl_id, NULL, 0); assert (handle); - SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[0]); - SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[1]); - SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[2]); - SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) strings[3]); + SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) strings[0]); + SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) strings[1]); + SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) strings[2]); + SendMessage (handle, LB_ADDSTRING, 0, (LPARAM) strings[3]); #ifdef VISIBLE ShowWindow (handle, SW_SHOW); @@ -103,8 +103,8 @@ buttonpress (HWND handle, WORD x, WORD y) LPARAM lp=x+(y<<16); WAIT; - SendMessage (handle, WM_LBUTTONDOWN, (WPARAM) MK_LBUTTON, lp); - SendMessage (handle, WM_LBUTTONUP , (WPARAM) 0 , lp); + SendMessage (handle, WM_LBUTTONDOWN, MK_LBUTTON, lp); + SendMessage (handle, WM_LBUTTONUP, 0, lp); REDRAW; } @@ -254,7 +254,9 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA rc_client.left, rc_client.top, rc_client.right, rc_client.bottom); GetClipBox(dis->hDC, &rc_clip); trace("clip rect (%d,%d-%d,%d)\n", rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom); - ok(EqualRect(&rc_client, &rc_clip), "client rect of the listbox should be equal to the clip box\n"); + ok(EqualRect(&rc_client, &rc_clip) || IsRectEmpty(&rc_clip), + "client rect of the listbox should be equal to the clip box," + "or the clip box should be empty\n"); trace("rcItem (%d,%d-%d,%d)\n", dis->rcItem.left, dis->rcItem.top, dis->rcItem.right, dis->rcItem.bottom); @@ -285,7 +287,7 @@ static void test_ownerdraw(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandle(0); cls.hIcon = 0; - cls.hCursor = LoadCursor(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursor(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "main_window_class"; @@ -301,6 +303,7 @@ static void test_ownerdraw(void) hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent); assert(hLB); + SetForegroundWindow(hLB); UpdateWindow(hLB); /* make height short enough */ @@ -456,18 +459,18 @@ static void test_itemfrompoint(void) HWND hList = CreateWindow( "ListBox", "list test", WS_VISIBLE|WS_POPUP|LBS_NOINTEGRALHEIGHT, 1, 1, 600, 100, NULL, NULL, NULL, NULL ); - LONG r, id; + ULONG r, id; RECT rc; - /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000 */ + /* For an empty listbox win2k returns 0x1ffff, win98 returns 0x10000, nt4 returns 0xffffffff */ r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 30 )); - ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r ); + ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r ); r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 700, 30 )); - ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r ); + ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r ); r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( 30, 300 )); - ok( r == 0x1ffff || r == 0x10000, "ret %x\n", r ); + ok( r == 0x1ffff || r == 0x10000 || r == 0xffffffff, "ret %x\n", r ); id = SendMessage( hList, LB_ADDSTRING, 0, (LPARAM) "hi"); ok( id == 0, "item id wrong\n"); @@ -478,7 +481,8 @@ static void test_itemfrompoint(void) ok( r == 0x1, "ret %x\n", r ); r = SendMessage(hList, LB_ITEMFROMPOINT, 0, MAKELPARAM( /* x */ 30, /* y */ 601 )); - ok( r == 0x10001, "ret %x\n", r ); + ok( r == 0x10001 || broken(r == 1), /* nt4 */ + "ret %x\n", r ); /* Resize control so that below assertions about sizes are valid */ r = SendMessage( hList, LB_GETITEMRECT, 0, (LPARAM)&rc); @@ -515,16 +519,20 @@ static void test_itemfrompoint(void) ok( r == 1, "ret %x\n", r); r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(1000, 10) ); - ok( r == 0x10001, "ret %x\n", r ); + ok( r == 0x10001 || broken(r == 1), /* nt4 */ + "ret %x\n", r ); r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, -10) ); - ok( r == 0x10001, "ret %x\n", r ); + ok( r == 0x10001 || broken(r == 1), /* nt4 */ + "ret %x\n", r ); r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 100) ); - ok( r == 0x10005, "item %x\n", r ); + ok( r == 0x10005 || broken(r == 5), /* nt4 */ + "item %x\n", r ); r = SendMessage( hList, LB_ITEMFROMPOINT, 0, MAKELPARAM(10, 200) ); - ok( r == 0x10005, "item %x\n", r ); + ok( r == 0x10005 || broken(r == 5), /* nt4 */ + "item %x\n", r ); DestroyWindow( hList ); } @@ -550,17 +558,19 @@ static void test_listbox_item_data(void) DestroyWindow( hList ); } -static void test_listbox_LB_DIR() +static void test_listbox_LB_DIR(void) { HWND hList; int res, itemCount; int itemCount_justFiles; int itemCount_justDrives; int itemCount_allFiles; + int itemCount_allDirs; int i; char pathBuffer[MAX_PATH]; char * p; char driveletter; + const char *wildcard = "*"; HANDLE file; file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); @@ -579,9 +589,15 @@ static void test_listbox_LB_DIR() /* Test for standard usage */ /* This should list all the files in the test directory. */ - strcpy(pathBuffer, "*"); + strcpy(pathBuffer, wildcard); SendMessage(hList, LB_RESETCONTENT, 0, 0); res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer); + if (res == -1) /* "*" wildcard doesn't work on win9x */ + { + wildcard = "*.*"; + strcpy(pathBuffer, wildcard); + res = SendMessage(hList, LB_DIR, 0, (LPARAM)pathBuffer); + } ok (res >= 0, "SendMessage(LB_DIR, 0, *) failed - 0x%08x\n", GetLastError()); /* There should be some content in the listbox */ @@ -634,7 +650,7 @@ static void test_listbox_LB_DIR() } /* Test DDL_DIRECTORY */ - strcpy(pathBuffer, "*"); + strcpy(pathBuffer, wildcard); SendMessage(hList, LB_RESETCONTENT, 0, 0); res = SendMessage(hList, LB_DIR, DDL_DIRECTORY, (LPARAM)pathBuffer); ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY, *) failed - 0x%08x\n", GetLastError()); @@ -643,9 +659,10 @@ static void test_listbox_LB_DIR() * All files plus "[..]" */ itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0); - ok (itemCount == itemCount_allFiles + 1, - "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected %d\n", - itemCount, itemCount_allFiles + 1); + itemCount_allDirs = itemCount - itemCount_allFiles; + ok (itemCount > itemCount_allFiles, + "SendMessage(LB_DIR, DDL_DIRECTORY, *) filled with %d entries, expected > %d\n", + itemCount, itemCount_allFiles); ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY, *) returned incorrect index (expected %d got %d)!\n", itemCount - 1, res); @@ -691,10 +708,10 @@ static void test_listbox_LB_DIR() /* Test DDL_DRIVES|DDL_EXCLUSIVE */ - strcpy(pathBuffer, "*"); + strcpy(pathBuffer, wildcard); SendMessage(hList, LB_RESETCONTENT, 0, 0); res = SendMessage(hList, LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); - ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError()); + ok (res >= 0, "SendMessage(LB_DIR, DDL_DRIVES|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError()); /* There should be some content in the listbox. In particular, there should * be at least one element before, since the string "[-c-]" should @@ -738,7 +755,7 @@ static void test_listbox_LB_DIR() itemCount_justFiles, itemCount_justDrives); /* Test DDL_DRIVES. */ - strcpy(pathBuffer, "*"); + strcpy(pathBuffer, wildcard); SendMessage(hList, LB_RESETCONTENT, 0, 0); res = SendMessage(hList, LB_DIR, DDL_DRIVES, (LPARAM)pathBuffer); ok (res > 0, "SendMessage(LB_DIR, DDL_DRIVES, *) failed - 0x%08x\n", GetLastError()); @@ -750,9 +767,9 @@ static void test_listbox_LB_DIR() */ itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0); ok (itemCount == itemCount_justDrives + itemCount_allFiles, - "SendMessage(LB_DIR, DDL_DRIVES, w*.c) filled with %d entries, expected %d\n", + "SendMessage(LB_DIR, DDL_DRIVES, *) filled with %d entries, expected %d\n", itemCount, itemCount_justDrives + itemCount_allFiles); - ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, w*.c) returned incorrect index!\n"); + ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DRIVES, *) returned incorrect index!\n"); /* This tests behavior when no files match the wildcard */ strcpy(pathBuffer, BAD_EXTENSION); @@ -801,7 +818,7 @@ static void test_listbox_LB_DIR() /* Test DDL_DIRECTORY|DDL_DRIVES. This does *not* imply DDL_EXCLUSIVE */ - strcpy(pathBuffer, "*"); + strcpy(pathBuffer, wildcard); SendMessage(hList, LB_RESETCONTENT, 0, 0); res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES, (LPARAM)pathBuffer); ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, *) failed - 0x%08x\n", GetLastError()); @@ -810,9 +827,9 @@ static void test_listbox_LB_DIR() * be exactly the number of plain files, plus the number of mapped drives. */ itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0); - ok (itemCount == itemCount_allFiles + itemCount_justDrives + 1, + ok (itemCount == itemCount_allFiles + itemCount_justDrives + itemCount_allDirs, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n", - itemCount, itemCount_allFiles + itemCount_justDrives + 1); + itemCount, itemCount_allFiles + itemCount_justDrives + itemCount_allDirs); ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES, w*.c) returned incorrect index!\n"); /* Every single item in the control should start with a w and end in .c, @@ -876,21 +893,23 @@ static void test_listbox_LB_DIR() } /* Test DDL_DIRECTORY|DDL_EXCLUSIVE. */ - strcpy(pathBuffer, "*"); + strcpy(pathBuffer, wildcard); SendMessage(hList, LB_RESETCONTENT, 0, 0); res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, (LPARAM)pathBuffer); - ok (res == 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed - 0x%08x\n", GetLastError()); + ok (res != -1, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) failed err %u\n", GetLastError()); - /* There should be exactly one element: "[..]" */ itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0); - ok (itemCount == 1, + ok (itemCount == itemCount_allDirs, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", - itemCount, 1); + itemCount, itemCount_allDirs); ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n"); + if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */ + { memset(pathBuffer, 0, MAX_PATH); SendMessage(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer); - ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n"); + ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n"); + } /* This tests behavior when no files match the wildcard */ strcpy(pathBuffer, BAD_EXTENSION); @@ -916,16 +935,16 @@ static void test_listbox_LB_DIR() itemCount, 0); /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */ - strcpy(pathBuffer, "*"); + strcpy(pathBuffer, wildcard); SendMessage(hList, LB_RESETCONTENT, 0, 0); res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError()); /* There should be no plain files on the listbox */ itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0); - ok (itemCount == itemCount_justDrives + 1, + ok (itemCount == itemCount_justDrives + itemCount_allDirs, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", - itemCount, itemCount_justDrives + 1); + itemCount, itemCount_justDrives + itemCount_allDirs); ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c) returned incorrect index!\n"); for (i = 0; i < itemCount; i++) { @@ -936,7 +955,8 @@ static void test_listbox_LB_DIR() if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) { ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); } else { - ok( !strcmp(pathBuffer, "[..]"), "Element %d (%s) does not fit expected [..]\n", i, pathBuffer); + ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']', + "Element %d (%s) does not fit expected [...]\n", i, pathBuffer); } } @@ -954,7 +974,7 @@ static void test_listbox_LB_DIR() strcpy(pathBuffer, "w*.c"); SendMessage(hList, LB_RESETCONTENT, 0, 0); res = SendMessage(hList, LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, (LPARAM)pathBuffer); - ok (res > 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError()); + ok (res >= 0, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE, w*.c,) failed - 0x%08x\n", GetLastError()); /* There should be no plain files on the listbox, and no [..], since it does not fit w*.c */ itemCount = SendMessage(hList, LB_GETCOUNT, 0, 0); @@ -1046,6 +1066,7 @@ static void test_listbox_dlgdir(void) HINSTANCE hInst; HWND hWnd; int res, itemCount; + int itemCount_allDirs; int itemCount_justFiles; int itemCount_justDrives; int i; @@ -1125,13 +1146,14 @@ static void test_listbox_dlgdir(void) ok (res == 1, "DlgDirList(*.c, DDL_DIRECTORY) failed - 0x%08x\n", GetLastError()); /* There should be some content in the listbox. In particular, there should - * be exactly one more element than before, since the string "[..]" should + * be exactly more elements than before, since the directories should * have been added. */ itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0); - ok (itemCount == itemCount_justFiles + 1, - "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected %d\n", - itemCount, itemCount_justFiles + 1); + itemCount_allDirs = itemCount - itemCount_justFiles; + ok (itemCount >= itemCount_justFiles, + "DlgDirList(DDL_DIRECTORY) filled with %d entries, expected > %d\n", + itemCount, itemCount_justFiles); /* Every single item in the control should start with a w and end in .c, * except for the "[..]" string, which should appear exactly as it is. @@ -1140,7 +1162,7 @@ static void test_listbox_dlgdir(void) memset(pathBuffer, 0, MAX_PATH); SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer); p = pathBuffer + strlen(pathBuffer); - ok( !strcmp(pathBuffer, "[..]") || + ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') || ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && (*(p-1) == 'c' || *(p-1) == 'C') && (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); @@ -1153,13 +1175,15 @@ static void test_listbox_dlgdir(void) ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY) returned %d expected 1\n", BAD_EXTENSION, res); itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0); - ok (itemCount == 1, "DlgDirList() incorrectly filled the listbox! (expected 1 got %d)\n", - itemCount); + ok (itemCount == itemCount_allDirs, + "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n", + itemCount_allDirs, itemCount); for (i = 0; i < itemCount; i++) { memset(pathBuffer, 0, MAX_PATH); SendMessage(g_listBox, LB_GETTEXT, i, (LPARAM)pathBuffer); p = pathBuffer + strlen(pathBuffer); - ok( !strcmp(pathBuffer, "[..]"), "Element %d (%s) does not fit requested [..]\n", i, pathBuffer); + ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']', + "Element %d (%s) does not fit requested [...]\n", i, pathBuffer); } @@ -1216,9 +1240,9 @@ static void test_listbox_dlgdir(void) * plus one "[..]" */ itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0); - ok (itemCount == itemCount_justFiles + itemCount_justDrives + 1, + ok (itemCount == itemCount_justFiles + itemCount_justDrives + itemCount_allDirs, "DlgDirList(DDL_DIRECTORY|DDL_DRIVES) filled with %d entries, expected %d\n", - itemCount, itemCount_justFiles + itemCount_justDrives + 1); + itemCount, itemCount_justFiles + itemCount_justDrives + itemCount_allDirs); /* Every single item in the control should start with a w and end in .c, * except for the "[..]" string, which should appear exactly as it is, @@ -1232,7 +1256,7 @@ static void test_listbox_dlgdir(void) if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) { ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); } else { - ok( !strcmp(pathBuffer, "[..]") || + ok( (pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']') || ((pathBuffer[0] == 'w' || pathBuffer[0] == 'W') && (*(p-1) == 'c' || *(p-1) == 'C') && (*(p-2) == '.')), "Element %d (%s) does not fit requested w*.c\n", i, pathBuffer); @@ -1246,9 +1270,9 @@ static void test_listbox_dlgdir(void) ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES) returned %d expected 1\n", BAD_EXTENSION, res); itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0); - ok (itemCount == itemCount_justDrives + 1, + ok (itemCount == itemCount_justDrives + itemCount_allDirs, "DlgDirList() incorrectly filled the listbox! (expected %d got %d)\n", - itemCount_justDrives + 1, itemCount); + itemCount_justDrives + itemCount_allDirs, itemCount); @@ -1260,14 +1284,16 @@ static void test_listbox_dlgdir(void) /* There should be exactly one element: "[..]" */ itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0); - ok (itemCount == 1, + ok (itemCount == itemCount_allDirs, "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", - itemCount, 1); + itemCount, itemCount_allDirs); + if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */ + { memset(pathBuffer, 0, MAX_PATH); SendMessage(g_listBox, LB_GETTEXT, 0, (LPARAM)pathBuffer); ok( !strcmp(pathBuffer, "[..]"), "First (and only) element is not [..]\n"); - + } /* Test behavior when no files match the wildcard */ strcpy(pathBuffer, BAD_EXTENSION); @@ -1276,7 +1302,7 @@ static void test_listbox_dlgdir(void) ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res); itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0); - ok (itemCount == 1, "DlgDirList() incorrectly filled the listbox!\n"); + ok (itemCount == itemCount_allDirs, "DlgDirList() incorrectly filled the listbox!\n"); /* Test DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE. */ @@ -1287,9 +1313,9 @@ static void test_listbox_dlgdir(void) /* There should be no plain files on the listbox */ itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0); - ok (itemCount == itemCount_justDrives + 1, + ok (itemCount == itemCount_justDrives + itemCount_allDirs, "DlgDirList(DDL_DIRECTORY|DDL_EXCLUSIVE) filled with %d entries, expected %d\n", - itemCount, itemCount_justDrives + 1); + itemCount, itemCount_justDrives + itemCount_allDirs); for (i = 0; i < itemCount; i++) { memset(pathBuffer, 0, MAX_PATH); @@ -1299,7 +1325,8 @@ static void test_listbox_dlgdir(void) if (sscanf(pathBuffer, "[-%c-]", &driveletter) == 1) { ok( driveletter >= 'a' && driveletter <= 'z', "Drive letter not in range a..z, got ascii %d\n", driveletter); } else { - ok( !strcmp(pathBuffer, "[..]"), "Element %d (%s) does not fit expected [..]\n", i, pathBuffer); + ok( pathBuffer[0] == '[' && pathBuffer[strlen(pathBuffer)-1] == ']', + "Element %d (%s) does not fit expected [...]\n", i, pathBuffer); } } @@ -1310,7 +1337,8 @@ static void test_listbox_dlgdir(void) ok (res == 1, "DlgDirList(%s, DDL_DIRECTORY|DDL_DRIVES|DDL_EXCLUSIVE) returned %d expected 1\n", BAD_EXTENSION, res); itemCount = SendMessage(g_listBox, LB_GETCOUNT, 0, 0); - ok (itemCount == itemCount_justDrives + 1, "DlgDirList() incorrectly filled the listbox!\n"); + ok (itemCount == itemCount_justDrives + itemCount_allDirs, + "DlgDirList() incorrectly filled the listbox!\n"); /* Now test DlgDirSelectEx() in normal operation */ diff --git a/rostests/winetests/user32/menu.c b/rostests/winetests/user32/menu.c index 1aa2eb6688c..d0d1e19d2f4 100755 --- a/rostests/winetests/user32/menu.c +++ b/rostests/winetests/user32/menu.c @@ -40,6 +40,7 @@ static ATOM atomMenuCheckClass; static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO); static UINT (WINAPI *pSendInput)(UINT, INPUT*, size_t); static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO); +static BOOL (WINAPI *pEndMenu) (void); static void init_function_pointers(void) { @@ -53,10 +54,38 @@ static void init_function_pointers(void) GET_PROC(GetMenuInfo) GET_PROC(SendInput) GET_PROC(SetMenuInfo) + GET_PROC(EndMenu) #undef GET_PROC } +static BOOL correct_behavior(void) +{ + HMENU hmenu; + MENUITEMINFO info; + BOOL rc; + + hmenu = CreateMenu(); + + memset(&info, 0, sizeof(MENUITEMINFO)); + info.cbSize= sizeof(MENUITEMINFO); + SetLastError(0xdeadbeef); + rc = GetMenuItemInfo(hmenu, 0, TRUE, &info); + /* Win9x : 0xdeadbeef + * NT4 : ERROR_INVALID_PARAMETER + * >= W2K : ERROR_MENU_ITEM_NOT_FOUND + */ + if (!rc && GetLastError() != ERROR_MENU_ITEM_NOT_FOUND) + { + win_skip("NT4 and below can't handle a bigger MENUITEMINFO struct\n"); + DestroyMenu(hmenu); + return FALSE; + } + + DestroyMenu(hmenu); + return TRUE; +} + static LRESULT WINAPI menu_check_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) @@ -87,6 +116,7 @@ typedef struct /* globals to communicate between test and wndproc */ static BOOL bMenuVisible; +static BOOL got_input; static HMENU hMenus[4]; #define MOD_SIZE 10 @@ -112,12 +142,27 @@ static int MOD_odheight; static SIZE MODsizes[MOD_NRMENUS]= { {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}, {MOD_SIZE, MOD_SIZE},{MOD_SIZE, MOD_SIZE}}; static int MOD_GotDrawItemMsg = FALSE; +static int gflag_initmenupopup, + gflag_entermenuloop, + gflag_initmenu; + /* wndproc used by test_menu_ownerdraw() */ static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + static HMENU hmenupopup; switch (msg) { + case WM_INITMENUPOPUP: + gflag_initmenupopup++; + hmenupopup = (HMENU) wparam; + break; + case WM_ENTERMENULOOP: + gflag_entermenuloop++; + break; + case WM_INITMENU: + gflag_initmenu++; + break; case WM_MEASUREITEM: { MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)lparam; @@ -142,8 +187,8 @@ static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg, RECT rc; GetMenuItemRect( hwnd, (HMENU)pdis->hwndItem, pdis->itemData ,&rc); trace("WM_DRAWITEM received hwnd %p hmenu %p itemdata %ld item %d rc %d,%d-%d,%d itemrc: %d,%d-%d,%d\n", - hwnd, (HMENU)pdis->hwndItem, pdis->itemData, - pdis->itemID, pdis->rcItem.left, pdis->rcItem.top, + hwnd, pdis->hwndItem, pdis->itemData, pdis->itemID, + pdis->rcItem.left, pdis->rcItem.top, pdis->rcItem.right,pdis->rcItem.bottom, rc.left,rc.top,rc.right,rc.bottom); oldpen=SelectObject( pdis->hDC, GetStockObject( @@ -184,6 +229,13 @@ static LRESULT WINAPI menu_ownerdraw_wnd_proc(HWND hwnd, UINT msg, } case WM_ENTERIDLE: { + ok( lparam || broken(!lparam), /* win9x, nt4 */ + "Menu window handle is NULL!\n"); + if( lparam) { + HMENU hmenu = (HMENU)SendMessageA( (HWND)lparam, MN_GETHMENU, 0, 0); + ok( hmenupopup == hmenu, "MN_GETHMENU returns %p expected %p\n", + hmenu, hmenupopup); + } PostMessage(hwnd, WM_CANCELMODE, 0, 0); return TRUE; } @@ -235,7 +287,7 @@ static void test_menu_locked_by_window(void) ok(ret, "DrawMenuBar failed with error %d\n", GetLastError()); } ret = IsMenu(GetMenu(hwnd)); - ok(!ret, "Menu handle should have been destroyed\n"); + ok(!ret || broken(ret) /* nt4 */, "Menu handle should have been destroyed\n"); SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); /* did we process the WM_INITMENU message? */ @@ -247,6 +299,105 @@ static void test_menu_locked_by_window(void) DestroyWindow(hwnd); } +/* demonstrates that subpopup's are locked + * even after a client calls DestroyMenu on it */ +static LRESULT WINAPI subpopuplocked_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + HWND hwndmenu; + switch (msg) + { + case WM_ENTERIDLE: + hwndmenu = GetCapture(); + if( hwndmenu) { + PostMessage( hwndmenu, WM_KEYDOWN, VK_DOWN, 0); + PostMessage( hwndmenu, WM_KEYDOWN, VK_RIGHT, 0); + PostMessage( hwndmenu, WM_KEYDOWN, VK_RETURN, 0); + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +static void test_subpopup_locked_by_menu(void) +{ + DWORD gle; + BOOL ret; + HMENU hmenu, hsubmenu; + MENUINFO mi = { sizeof( MENUINFO)}; + MENUITEMINFO mii = { sizeof( MENUITEMINFO)}; + HWND hwnd; + const int itemid = 0x1234567; + if( !pGetMenuInfo) + { + win_skip("GetMenuInfo is not available\n"); + return; + } + /* create window, popupmenu with one subpopup */ + hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL, + WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, + NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR) subpopuplocked_wnd_proc); + hmenu = CreatePopupMenu(); + ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + hsubmenu = CreatePopupMenu(); + ok(hsubmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + ret = InsertMenu(hmenu, 0, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT_PTR)hsubmenu, + TEXT("PopUpLockTest")); + ok(ret, "InsertMenu failed with error %d\n", GetLastError()); + ret = InsertMenu(hsubmenu, 0, MF_BYPOSITION | MF_STRING, itemid, TEXT("PopUpMenu")); + ok(ret, "InsertMenu failed with error %d\n", GetLastError()); + /* first some tests that all this functions properly */ + mii.fMask = MIIM_SUBMENU; + ret = GetMenuItemInfo( hmenu, 0, TRUE, &mii); + ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); + ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); + mi.fMask |= MIM_STYLE; + ret = pGetMenuInfo( hsubmenu, &mi); + ok( ret , "GetMenuInfo returned 0 with error %d\n", GetLastError()); + ret = IsMenu( hsubmenu); + ok( ret , "Menu handle is not valid\n"); + SetLastError( 0xdeadbeef); + ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL); + if( ret == (itemid & 0xffff)) { + win_skip("not on 16 bit menu subsystem\n"); + DestroyMenu( hsubmenu); + } else { + gle = GetLastError(); + ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, gle); + ok( gle == 0 || + broken( gle == 0xdeadbeef), /* win2k0 */ + "Last error is %d\n", gle); + /* then destroy the sub-popup */ + ret = DestroyMenu( hsubmenu); + ok(ret, "DestroyMenu failed with error %d\n", GetLastError()); + /* and repeat the tests */ + mii.fMask = MIIM_SUBMENU; + ret = GetMenuItemInfo( hmenu, 0, TRUE, &mii); + ok( ret, "GetMenuItemInfo failed error %d\n", GetLastError()); + /* GetMenuInfo fails now */ + ok( mii.hSubMenu == hsubmenu, "submenu is %p\n", mii.hSubMenu); + mi.fMask |= MIM_STYLE; + ret = pGetMenuInfo( hsubmenu, &mi); + ok( !ret , "GetMenuInfo should have failed\n"); + /* IsMenu says it is not */ + ret = IsMenu( hsubmenu); + ok( !ret , "Menu handle should be invalid\n"); + /* but TrackPopupMenu still works! */ + SetLastError( 0xdeadbeef); + ret = TrackPopupMenu( hmenu, 0x100, 100,100, 0, hwnd, NULL); + gle = GetLastError(); + todo_wine { + ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, gle); + } + ok( gle == 0 || + broken( gle == ERROR_INVALID_PARAMETER), /* win2k0 */ + "Last error is %d\n", gle); + } + /* clean up */ + DestroyMenu( hmenu); + DestroyWindow(hwnd); +} + static void test_menu_ownerdraw(void) { int i,j,k; @@ -258,7 +409,7 @@ static void test_menu_ownerdraw(void) NULL, NULL, NULL, NULL); ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); if( !hwnd) return; - SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc); + SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); hmenu = CreatePopupMenu(); ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); if( !hmenu) { DestroyWindow(hwnd);return;} @@ -266,7 +417,7 @@ static void test_menu_ownerdraw(void) for( j=0;j<2;j++) /* create columns */ for(i=0;i<2;i++) { /* create rows */ ret = AppendMenu( hmenu, MF_OWNERDRAW | - (i==0 ? MF_MENUBREAK : 0), k, (LPCTSTR) k); + (i==0 ? MF_MENUBREAK : 0), k, MAKEINTRESOURCE(k)); k++; ok( ret, "AppendMenu failed for %d\n", k-1); } @@ -357,7 +508,8 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, MOD_GotDrawItemMsg = FALSE; mii.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STATE; mii.fType = 0; - mii.fState = MF_CHECKED; + /* check the menu item unless MNS_CHECKORBMP is set */ + mii.fState = (mnuopt != 2 ? MFS_CHECKED : MFS_UNCHECKED); mii.dwItemData =0; MODsizes[0] = bmpsize; hastab = 0; @@ -391,7 +543,7 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, mi.cbSize = sizeof(mi); mi.fMask = MIM_STYLE; pGetMenuInfo( hmenu, &mi); - mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP; + if( mnuopt) mi.dwStyle |= mnuopt == 1 ? MNS_NOCHECK : MNS_CHECKORBMP; ret = pSetMenuInfo( hmenu, &mi); ok( ret, "SetMenuInfo failed with error %d\n", GetLastError()); } @@ -405,7 +557,7 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, sprintf( buf,"%d text \"%s\" mnuopt %d", count, text ? text: "(nil)", mnuopt); FillRect( hdc, &rc, (HBRUSH) COLOR_WINDOW); - TextOut( hdc, 100, 50, buf, strlen( buf)); + TextOut( hdc, 10, 50, buf, strlen( buf)); ReleaseDC( hwnd, hdc); } if(ispop) @@ -416,12 +568,18 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, DrawMenuBar( hwnd); } ret = GetMenuItemRect( hwnd, hmenu, 0, &rc); + if (0) /* comment out menu size checks, behavior is different in almost every Windows version */ + /* the tests should however succeed on win2000, XP and Wine (at least up to 1.1.15) */ + /* with a variety of dpis and desktop font sizes */ + { /* check menu width */ if( ispop) expect = ( text || hbmp ? 4 + (mnuopt != 1 ? GetSystemMetrics(SM_CXMENUCHECK) : 0) : 0) + - arrowwidth + MOD_avec + (hbmp ? bmpsize.cx + 2 : 0) + + arrowwidth + MOD_avec + (hbmp ? + ((INT_PTR)hbmp<0||(INT_PTR)hbmp>12 ? bmpsize.cx + 2 : GetSystemMetrics( SM_CXMENUSIZE) + 2) + : 0) + (text && hastab ? /* TAB space */ MOD_avec + ( hastab==2 ? sc_size.cx : 0) : 0) + (text ? 2 + (text[0] ? size.cx :0): 0) ; @@ -436,7 +594,11 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, if( ispop) expect = max( ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : 0), max( (text ? max( 2 + size.cy, MOD_hic + 4) : 0), - (hbmp ? bmpsize.cy + 2 : 0))); + (hbmp ? + ((INT_PTR)hbmp<0||(INT_PTR)hbmp>12 ? + bmpsize.cy + 2 + : GetSystemMetrics( SM_CYMENUSIZE) + 2) + : 0))); else expect = ( !(text || hbmp) ? GetSystemMetrics( SM_CYMENUSIZE)/2 : max( GetSystemMetrics( SM_CYMENU) - 1, (hbmp ? bmpsize.cy : 0))); @@ -447,8 +609,14 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, if( hbmp == HBMMENU_CALLBACK && MOD_GotDrawItemMsg) { /* check the position of the bitmap */ /* horizontal */ - expect = ispop ? (4 + ( mnuopt ? 0 : GetSystemMetrics(SM_CXMENUCHECK))) - : 3; + if (!ispop) + expect = 3; + else if (mnuopt == 0) + expect = 4 + GetSystemMetrics(SM_CXMENUCHECK); + else if (mnuopt == 1) + expect = 4; + else /* mnuopt == 2 */ + expect = 2; ok( expect == MOD_rc[0].left, "bitmap left is %d expected %d\n", MOD_rc[0].left, expect); failed = failed || !(expect == MOD_rc[0].left); @@ -458,10 +626,11 @@ static void test_mbs_help( int ispop, int hassub, int mnuopt, "bitmap top is %d expected %d\n", MOD_rc[0].top, expect); failed = failed || !(expect == MOD_rc[0].top); } + } /* if there was a failure, report details */ if( failed) { - trace("*** count %d text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n", - count, text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy, + trace("*** count %d %s text \"%s\" bitmap %p bmsize %d,%d textsize %d+%d,%d mnuopt %d hastab %d\n", + count, (ispop? "POPUP": "MENUBAR"),text ? text: "(nil)", hbmp, bmpsize.cx, bmpsize.cy, size.cx, size.cy, sc_size.cx, mnuopt, hastab); trace(" check %d,%d arrow %d avechar %d\n", GetSystemMetrics(SM_CXMENUCHECK ), @@ -486,25 +655,41 @@ static void test_menu_bmp_and_string(void) BITMAP bm; INT arrowwidth; HWND hwnd; + HMENU hsysmenu; + MENUINFO mi= {sizeof(MENUINFO)}; + MENUITEMINFOA mii= {sizeof(MENUITEMINFOA)}; int count, szidx, txtidx, bmpidx, hassub, mnuopt, ispop; if( !pGetMenuInfo) { - skip("GetMenuInfo is not available\n"); + win_skip("GetMenuInfo is not available\n"); return; } memset( bmfill, 0xcc, sizeof( bmfill)); - hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL, + hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL, WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, NULL, NULL); hbm_arrow=LoadBitmap( 0, (CHAR*)OBM_MNARROW); GetObject( hbm_arrow, sizeof(bm), &bm); arrowwidth = bm.bmWidth; - ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); if( !hwnd) return; - SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG)menu_ownerdraw_wnd_proc); + /* test system menu */ + hsysmenu = GetSystemMenu( hwnd, FALSE); + ok( hsysmenu != NULL, "GetSystemMenu failed with error %d\n", GetLastError()); + mi.fMask = MIM_STYLE; + mi.dwStyle = 0; + ok( pGetMenuInfo( hsysmenu, &mi), "GetMenuInfo failed gle=%d\n", GetLastError()); + ok( MNS_CHECKORBMP == mi.dwStyle, "System Menu Style is %08x, without the bit %08x\n", + mi.dwStyle, MNS_CHECKORBMP); + mii.fMask = MIIM_BITMAP; + mii.hbmpItem = NULL; + ok( GetMenuItemInfoA( hsysmenu, SC_CLOSE, FALSE, &mii), "GetMenuItemInfoA failed gle=%d\n", GetLastError()); + ok( HBMMENU_POPUP_CLOSE == mii.hbmpItem, "Item info did not get the right hbitmap: got %p expected %p\n", + mii.hbmpItem, HBMMENU_POPUP_CLOSE); + + SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); if( winetest_debug) trace(" check %d,%d arrow %d avechar %d\n", @@ -517,14 +702,18 @@ static void test_menu_bmp_and_string(void) {10,10},{38,38},{1,30},{55,5}}; for( szidx=0; szidx < sizeof( bmsizes) / sizeof( SIZE); szidx++) { HBITMAP hbm = CreateBitmap( bmsizes[szidx].cx, bmsizes[szidx].cy,1,1,bmfill); - HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, NULL }; - ok( (int)hbm, "CreateBitmap failed err %d\n", GetLastError()); + HBITMAP bitmaps[] = { HBMMENU_CALLBACK, hbm, HBMMENU_POPUP_CLOSE, NULL }; + ok( hbm != 0, "CreateBitmap failed err %d\n", GetLastError()); for( txtidx = 0; txtidx < sizeof(MOD_txtsizes)/sizeof(MOD_txtsizes[0]); txtidx++) { for( hassub = 0; hassub < 2 ; hassub++) { /* add submenu item */ for( mnuopt = 0; mnuopt < 3 ; mnuopt++){ /* test MNS_NOCHECK/MNS_CHECKORBMP */ for( bmpidx = 0; bmpidx 0) continue; + /* the HBMMENU_POPUP not to test for menu bars */ + if( !ispop && + bitmaps[bmpidx] >= HBMMENU_POPUP_CLOSE && + bitmaps[bmpidx] <= HBMMENU_POPUP_MINIMIZE) continue; if( !ispop && hassub) continue; test_mbs_help( ispop, hassub, mnuopt, hwnd, arrowwidth, ++count, @@ -596,9 +785,9 @@ static void test_menu_add_string( void ) ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n"); SetLastError(0xdeadbeef); - ret = GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION); + ret = GetMenuStringW( hmenu, 0, strbackW, 99, MF_BYPOSITION ); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - skip("GetMenuStringW is not implemented\n"); + win_skip("GetMenuStringW is not implemented\n"); else { ok (ret, "GetMenuStringW on ownerdraw entry failed\n"); @@ -661,7 +850,7 @@ static void test_menu_add_string( void ) SetLastError(0xdeadbeef); ret = GetMenuStringW( hmenu, 0, NULL, 0, MF_BYPOSITION); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - skip("GetMenuStringW is not implemented\n"); + win_skip("GetMenuStringW is not implemented\n"); else ok (!ret, "GetMenuStringW on ownerdraw entry succeeded.\n"); @@ -683,130 +872,173 @@ static WCHAR *strcpyW( WCHAR *dst, const WCHAR *src ) return dst; } +static void insert_menu_item( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, UINT id, + HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data, + void *type_data, UINT len, HBITMAP item, BOOL expect ) +{ + MENUITEMINFOA info; + BOOL ret; -#define DMIINFF( i, e, field)\ - ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \ - "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field)); + /* magic bitmap handle to test smaller cbSize */ + if (item == (HBITMAP)(ULONG_PTR)0xdeadbeef) + info.cbSize = FIELD_OFFSET(MENUITEMINFOA,hbmpItem); + else + info.cbSize = sizeof(info); + info.fMask = mask; + info.fType = type; + info.fState = state; + info.wID = id; + info.hSubMenu = submenu; + info.hbmpChecked = checked; + info.hbmpUnchecked = unchecked; + info.dwItemData = data; + info.dwTypeData = type_data; + info.cch = len; + info.hbmpItem = item; + SetLastError( 0xdeadbeef ); + if (ansi) ret = InsertMenuItemA( hmenu, 0, TRUE, &info ); + else ret = InsertMenuItemW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info ); + if (!expect) ok_(__FILE__, line)( !ret, "InsertMenuItem should have failed.\n" ); + else ok_(__FILE__, line)( ret, "InsertMenuItem failed, err %u\n", GetLastError()); +} -#define DUMPMIINF(s,i,e)\ -{\ - DMIINFF( i, e, fMask)\ - DMIINFF( i, e, fType)\ - DMIINFF( i, e, fState)\ - DMIINFF( i, e, wID)\ - DMIINFF( i, e, hSubMenu)\ - DMIINFF( i, e, hbmpChecked)\ - DMIINFF( i, e, hbmpUnchecked)\ - DMIINFF( i, e, dwItemData)\ - DMIINFF( i, e, dwTypeData)\ - DMIINFF( i, e, cch)\ - if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\ +static void check_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, + UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked, + ULONG_PTR data, void *type_data, UINT in_len, UINT out_len, + HBITMAP item, LPCSTR expname, BOOL expect, BOOL expstring ) +{ + MENUITEMINFOA info; + BOOL ret; + WCHAR buffer[80]; + + SetLastError( 0xdeadbeef ); + memset( &info, 0xcc, sizeof(info) ); + info.cbSize = sizeof(info); + info.fMask = mask; + info.dwTypeData = type_data; + info.cch = in_len; + + ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, &info ) : + GetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW *)&info ); + if (!expect) + { + ok_(__FILE__, line)( !ret, "GetMenuItemInfo should have failed.\n" ); + return; } + ok_(__FILE__, line)( ret, "GetMenuItemInfo failed, err %u\n", GetLastError()); + if (mask & MIIM_TYPE) + ok_(__FILE__, line)( info.fType == type || info.fType == LOWORD(type), + "wrong type %x/%x\n", info.fType, type ); + if (mask & MIIM_STATE) + ok_(__FILE__, line)( info.fState == state || info.fState == LOWORD(state), + "wrong state %x/%x\n", info.fState, state ); + if (mask & MIIM_ID) + ok_(__FILE__, line)( info.wID == id || info.wID == LOWORD(id), + "wrong id %x/%x\n", info.wID, id ); + if (mask & MIIM_SUBMENU) + ok_(__FILE__, line)( info.hSubMenu == submenu || (ULONG_PTR)info.hSubMenu == LOWORD(submenu), + "wrong submenu %p/%p\n", info.hSubMenu, submenu ); + if (mask & MIIM_CHECKMARKS) + { + ok_(__FILE__, line)( info.hbmpChecked == checked || (ULONG_PTR)info.hbmpChecked == LOWORD(checked), + "wrong bmpchecked %p/%p\n", info.hbmpChecked, checked ); + ok_(__FILE__, line)( info.hbmpUnchecked == unchecked || (ULONG_PTR)info.hbmpUnchecked == LOWORD(unchecked), + "wrong bmpunchecked %p/%p\n", info.hbmpUnchecked, unchecked ); + } + if (mask & MIIM_DATA) + ok_(__FILE__, line)( info.dwItemData == data || info.dwItemData == LOWORD(data), + "wrong item data %lx/%lx\n", info.dwItemData, data ); + if (mask & MIIM_BITMAP) + ok_(__FILE__, line)( info.hbmpItem == item || (ULONG_PTR)info.hbmpItem == LOWORD(item), + "wrong bmpitem %p/%p\n", info.hbmpItem, item ); + ok_(__FILE__, line)( info.dwTypeData == type_data || (ULONG_PTR)info.dwTypeData == LOWORD(type_data), + "wrong type data %p/%p\n", info.dwTypeData, type_data ); + ok_(__FILE__, line)( info.cch == out_len, "wrong len %x/%x\n", info.cch, out_len ); + if (expname) + { + if(ansi) + ok_(__FILE__, line)( !strncmp( expname, info.dwTypeData, out_len ), + "menu item name differed from '%s' '%s'\n", expname, info.dwTypeData ); + else + ok_(__FILE__, line)( !strncmpW( (WCHAR *)expname, (WCHAR *)info.dwTypeData, out_len ), + "menu item name wrong\n" ); -/* insert menu item */ -#define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\ - eret1)\ -{\ - MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\ - HMENU hmenu = CreateMenu();\ - BOOL ret, stop = FALSE;\ - SetLastError( 0xdeadbeef);\ + SetLastError( 0xdeadbeef ); + ret = ansi ? GetMenuStringA( hmenu, 0, (char *)buffer, 80, MF_BYPOSITION ) : + GetMenuStringW( hmenu, 0, buffer, 80, MF_BYPOSITION ); + if (expstring) + ok_(__FILE__, line)( ret, "GetMenuString failed, err %u\n", GetLastError()); + else + ok_(__FILE__, line)( !ret, "GetMenuString should have failed\n" ); + } +} + +static void modify_menu( int line, HMENU hmenu, BOOL ansi, UINT flags, UINT_PTR id, void *data ) +{ + BOOL ret; + + SetLastError( 0xdeadbeef ); + if (ansi) ret = ModifyMenuA( hmenu, 0, flags, id, data ); + else ret = ModifyMenuW( hmenu, 0, flags, id, data ); + ok_(__FILE__,line)( ret, "ModifyMenuA failed, err %u\n", GetLastError()); +} + +static void set_menu_item_info( int line, HMENU hmenu, BOOL ansi, UINT mask, UINT type, UINT state, + UINT id, HMENU submenu, HBITMAP checked, HBITMAP unchecked, ULONG_PTR data, + void *type_data, UINT len, HBITMAP item ) + +{ + MENUITEMINFOA info; + BOOL ret; + + /* magic bitmap handle to test smaller cbSize */ + if (item == (HBITMAP)(ULONG_PTR)0xdeadbeef) + info.cbSize = FIELD_OFFSET(MENUITEMINFOA,hbmpItem); + else + info.cbSize = sizeof(info); + info.fMask = mask; + info.fType = type; + info.fState = state; + info.wID = id; + info.hSubMenu = submenu; + info.hbmpChecked = checked; + info.hbmpUnchecked = unchecked; + info.dwItemData = data; + info.dwTypeData = type_data; + info.cch = len; + info.hbmpItem = item; + SetLastError( 0xdeadbeef ); + if (ansi) ret = SetMenuItemInfoA( hmenu, 0, TRUE, &info ); + else ret = SetMenuItemInfoW( hmenu, 0, TRUE, (MENUITEMINFOW*)&info ); + ok_(__FILE__, line)( ret, "SetMenuItemInfo failed, err %u\n", GetLastError()); +} + +#define TMII_INSMI( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,eret1 )\ + hmenu = CreateMenu();\ + submenu = CreateMenu();\ if(ansi)strcpy( string, init);\ - else strcpyW( (WCHAR*)string, (WCHAR*)init);\ - if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\ - else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\ - if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\ - {\ - skip("InsertMenuItem%s not implemented\n", ansi ? "A" : "W");\ - break;\ - }\ - if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\ - stop = TRUE;\ - } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\ - + else strcpyW( string, init );\ + insert_menu_item( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, eret1 ) /* GetMenuItemInfo + GetMenuString */ -#define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\ - a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\ +#define TMII_GMII( c2,l2,\ + d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,\ expname, eret2, eret3)\ -{\ - MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\ - MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\ - MENUITEMINFOA *info2 = &info2A;\ - MENUITEMINFOA *einfo = &einfoA;\ - MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\ - if( !stop) {\ - SetLastError( 0xdeadbeef);\ - ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\ - GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\ - if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\ - {\ - skip("GetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\ - break;\ - }\ - if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\ - else { \ - ok( (eret2)==ret,"GetMenuItemInfo failed, err %d\n",GetLastError());\ - ret = memcmp( info2, einfo, sizeof einfoA);\ - /* ok( ret==0, "Got wrong menu item info data\n");*/\ - if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\ - if( einfo->dwTypeData == string) {\ - if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\ - einfo->dwTypeData ? einfo->dwTypeData: "");\ - else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\ - einfo->dwTypeData ? einfo->dwTypeData: "");\ - ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\ - GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\ - if( (eret3)){\ - ok( ret, "GetMenuString failed, err %d\n",GetLastError());\ - }else\ - ok( !ret, "GetMenuString should have failed\n");\ - }\ - }\ - }\ -} + check_menu_item_info( __LINE__, hmenu, ansi, c2, d3, e3, f3, g3, h3, i3, j3, k3, l2, l3, m3, \ + expname, eret2, eret3 ) #define TMII_DONE \ RemoveMenu(hmenu, 0, TRUE );\ DestroyMenu( hmenu );\ - DestroyMenu( submenu );\ -submenu = CreateMenu();\ -} + DestroyMenu( submenu ); + /* modify menu */ -#define TMII_MODM( flags, id, data, eret )\ -if( !stop) {\ - SetLastError( 0xdeadbeef);\ - if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\ - else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\ - if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\ - {\ - skip("ModifyMenu%s not implemented\n", ansi ? "A" : "W");\ - break;\ - }\ - if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\ - else ok( (eret)==ret,"ModifyMenuA failed, err %d\n",GetLastError());\ -} +#define TMII_MODM( flags, id, data ) \ + modify_menu( __LINE__, hmenu, ansi, flags, id, data ) /* SetMenuItemInfo */ -#define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\ - eret1)\ -if( !stop) {\ - MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\ - SetLastError( 0xdeadbeef);\ - if(ansi)strcpy( string, init);\ - else strcpyW( (WCHAR*)string, (WCHAR*)init);\ - if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\ - else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\ - if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)\ - {\ - skip("SetMenuItemInfo%s not implemented\n", ansi ? "A" : "W");\ - break;\ - }\ - if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\ - stop = TRUE;\ - } else ok( (eret1)==ret,"InsertMenuItem failed, err %d\n",GetLastError());\ -} - +#define TMII_SMII( c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1 ) \ + set_menu_item_info( __LINE__, hmenu, ansi, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1 ) #define OK 1 @@ -815,7 +1047,6 @@ if( !stop) {\ static void test_menu_iteminfo( void ) { - int S=sizeof( MENUITEMINFOA); int ansi = TRUE; char txtA[]="wine"; char initA[]="XYZ"; @@ -826,7 +1057,8 @@ static void test_menu_iteminfo( void ) void *txt, *init, *empty, *string; HBITMAP hbm = CreateBitmap(1,1,1,1,NULL); char stringA[0x80]; - HMENU submenu=CreateMenu(); + HMENU hmenu, submenu=CreateMenu(); + HBITMAP dummy_hbm = (HBITMAP)(ULONG_PTR)0xdeadbeef; do { if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;} @@ -834,481 +1066,465 @@ static void test_menu_iteminfo( void ) trace( "%s string %p hbm %p txt %p\n", ansi ? "ANSI tests: " : "Unicode tests:", string, hbm, txt); /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */ /* (since MFT_STRING is zero, there are four of them) */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, 0, 0, 0, 0, 0, 0, txt, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0, + NULL, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, + NULL, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, + NULL, OK, ER ); TMII_DONE /* not enough space for name*/ - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, }, - {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE, 0, + MFT_STRING, 0, 0, 0, 0, 0, 0, NULL, 4, 0, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, }, - {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE, 5, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, }, - {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE, 4, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 3, 0, + txt, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, }, - {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, }, - empty, OK, ER ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE, 0, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, 0, + NULL, OK, ER ); TMII_DONE /* cannot combine MIIM_TYPE with some other flags */ - TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER) - TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - empty, ER, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE|MIIM_STRING, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + NULL, ER, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER) - TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - empty, ER, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE|MIIM_FTYPE, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + NULL, ER, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER) - TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, 6, hbm, ER ); TMII_DONE /* but succeeds with some others */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE|MIIM_SUBMENU, 80, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE|MIIM_STATE, 80, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE|MIIM_ID, 80, + MFT_STRING, 0, 888, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, 0, 0, 0, 999, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80, + MFT_STRING, 0, 0, 0, 0, 0, 999, string, 4, 0, + txt, OK, OK ); TMII_DONE /* to be continued */ /* set text with MIIM_TYPE and retrieve with MIIM_STRING */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0, + empty, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0, + empty, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, }, - init, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); + TMII_GMII ( MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 80, 0, + init, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK) - TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, }, - init, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); + TMII_GMII ( 0, 80, + 0, 0, 0, 0, 0, 0, 0, string, 80, 0, + init, OK, OK ); TMII_DONE /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */ - TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE /* same but retrieve with MIIM_TYPE */ - TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, }, - empty, OK, ER ) + TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 0, 0, + empty, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, }, - empty, OK, ER ) + TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 0, 0, + empty, OK, ER ); TMII_DONE /* How is that with bitmaps? */ - TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, - empty, OK, ER ) + TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, + NULL, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, }, - init, OK, ER ) + TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); + TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80, + 0, 0, 0, 0, 0, 0, 0, string, 80, hbm, + init, OK, ER ); TMII_DONE /* MIIM_BITMAP does not like MFT_BITMAP */ - TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER) - TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - init, OK, OK ) + TMII_INSMI( MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, 0, -1, hbm, ER ); TMII_DONE /* no problem with OWNERDRAWN */ - TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, }, - init, OK, ER ) + TMII_INSMI( MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); + TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 80, hbm, + init, OK, ER ); TMII_DONE /* setting MFT_BITMAP with MFT_FTYPE fails anyway */ - TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER) - TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - empty, OK, OK ) + TMII_INSMI( MIIM_FTYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, 0, -1, 0, ER ); TMII_DONE /* menu with submenu */ - TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, }, - init, OK, ER ) + TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, txt, 0, 0, OK ); + TMII_GMII ( MIIM_SUBMENU, 80, + 0, 0, 0, submenu, 0, 0, 0, string, 80, 0, + init, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, }, - init, OK, ER ) + TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, empty, 0, 0, OK ); + TMII_GMII ( MIIM_SUBMENU, 80, + 0, 0, 0, submenu, 0, 0, 0, string, 80, 0, + init, OK, ER ); TMII_DONE /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */ - TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, }, - empty, OK, ER ) - TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, }, - empty, OK, ER ) + TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, 0, 0, -1, txt, 0, 0, OK ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_STRING|MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 0, 0, + empty, OK, ER ); + TMII_GMII ( MIIM_SUBMENU|MIIM_FTYPE, 80, + MFT_SEPARATOR, 0, 0, submenu, 0, 0, 0, string, 80, 0, + empty, OK, ER ); TMII_DONE /* menu with invalid submenu */ - TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER) - TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - init, OK, ER ) + TMII_INSMI( MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, (HMENU)999, 0, 0, -1, txt, 0, 0, ER ); TMII_DONE /* Separator */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, 0, 0, 0, + NULL, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, hbm, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP|MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, + NULL, OK, ER ); TMII_DONE /* SEPARATOR and STRING go well together */ /* BITMAP and STRING go well together */ - TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, 80, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, hbm, + txt, OK, OK ); TMII_DONE /* BITMAP, SEPARATOR and STRING go well together */ - TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 4, hbm, + txt, OK, OK ); TMII_DONE /* last two tests, but use MIIM_TYPE to retrieve info */ - TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 4, hbm, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_SEPARATOR|MFT_BITMAP, 0, 0, 0, 0, 0, 0, hbm, 4, hbm, + NULL, OK, OK ); TMII_DONE /* same three with MFT_OWNERDRAW */ - TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_SEPARATOR|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 4, hbm, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 4, hbm, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, + NULL, OK, OK ); TMII_DONE /* test with modifymenu: string is preserved after setting OWNERDRAW */ - TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK) - TMII_MODM( MFT_OWNERDRAW, -1, 787, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); + TMII_MODM( MFT_OWNERDRAW, -1, (void*)787 ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_DATA, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 787, string, 4, 0, + txt, OK, OK ); TMII_DONE /* same with bitmap: now the text is cleared */ - TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK) - TMII_MODM( MFT_BITMAP, 545, hbm, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, }, - empty, OK, ER ) + TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); + TMII_MODM( MFT_BITMAP, 545, hbm ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, + MFT_BITMAP, 0, 545, 0, 0, 0, 0, string, 0, hbm, + empty, OK, ER ); TMII_DONE /* start with bitmap: now setting text clears it (though he flag is raised) */ - TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, }, - empty, OK, ER ) - TMII_MODM( MFT_STRING, 545, txt, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_BITMAP, MFT_STRING, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 0, hbm, + empty, OK, ER ); + TMII_MODM( MFT_STRING, 545, txt ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, + MFT_STRING, 0, 545, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE /*repeat with text NULL */ - TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_MODM( MFT_STRING, 545, NULL, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, }, - empty, OK, ER ) + TMII_INSMI( MIIM_BITMAP, MFT_STRING, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); + TMII_MODM( MFT_STRING, 545, NULL ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, + MFT_SEPARATOR, 0, 545, 0, 0, 0, 0, string, 0, 0, + empty, OK, ER ); TMII_DONE /* repeat with text "" */ - TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_MODM( MFT_STRING, 545, empty, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, }, - empty, OK, ER ) + TMII_INSMI( MIIM_BITMAP, -1 , -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); + TMII_MODM( MFT_STRING, 545, empty ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, 80, + MFT_STRING, 0, 545, 0, 0, 0, 0, string, 0, 0, + empty, OK, ER ); TMII_DONE /* start with bitmap: set ownerdraw */ - TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_MODM( MFT_OWNERDRAW, -1, 232, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, }, - empty, OK, ER ) + TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, hbm, OK ); + TMII_MODM( MFT_OWNERDRAW, -1, (void *)232 ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 232, string, 0, hbm, + empty, OK, ER ); TMII_DONE /* ask nothing */ - TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, }, - init, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, hbm, OK ); + TMII_GMII ( 0, 80, + 0, 0, 0, 0, 0, 0, 0, string, 80, 0, + init, OK, OK ); TMII_DONE /* some tests with small cbSize: the hbmpItem is to be ignored */ - TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, }, - empty, OK, ER ) + TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, dummy_hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 0, NULL, + NULL, OK, ER ); TMII_DONE - TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, }, - init, OK, ER ) + TMII_INSMI( MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, 0, -1, dummy_hbm, OK ); + TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 80, NULL, + init, OK, ER ); TMII_DONE - TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING|MIIM_BITMAP, -1, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, NULL, + txt, OK, OK ); TMII_DONE - TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, + NULL, OK, OK ); TMII_DONE - TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, }, - txt, OK, OK ) + TMII_INSMI( MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, 0, 0, 0, -1, txt, 6, dummy_hbm, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_SEPARATOR|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 4, NULL, + NULL, OK, OK ); TMII_DONE /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus */ - TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80, + MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 343, 0, 0, 0, + NULL, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0, + NULL, OK, ER ); TMII_DONE - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, }, - empty, OK, ER ) + TMII_INSMI( MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, 0, 0, 0, 343, txt, 0, 0, OK ); + TMII_GMII ( MIIM_TYPE|MIIM_DATA, 80, + MFT_STRING|MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0, + NULL, OK, ER ); TMII_DONE /* set a string menu to ownerdraw with MIIM_TYPE */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK) - TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, }, - txt, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_STRING, -2, -2, 0, 0, 0, -2, txt, -2, 0, OK ); + TMII_SMII ( MIIM_TYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE /* test with modifymenu add submenu */ - TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK) - TMII_MODM( MF_POPUP, submenu, txt, OK) - TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, }, - txt, OK, OK ) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING, MFT_STRING, -1, -1, 0, 0, 0, -1, txt, 0, 0, OK ); + TMII_MODM( MF_POPUP, (UINT_PTR)submenu, txt ); + TMII_GMII ( MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, 80, + MFT_STRING, 0, 0, submenu, 0, 0, 0, string, 4, 0, + txt, OK, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_STRING, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE /* MFT_SEPARATOR bit is kept when the text is added */ - TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK) - TMII_SMII( {, S, MIIM_STRING, -1, -1, -1, -1, -1, -1, -1, txt, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, -9, }, - txt, OK, OK ) + TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); + TMII_SMII( MIIM_STRING, 0, 0, 0, 0, 0, 0, 0, txt, 0, 0 ); + TMII_GMII ( MIIM_STRING|MIIM_FTYPE, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 4, 0, + txt, OK, OK ); TMII_DONE /* MFT_SEPARATOR bit is kept when bitmap is added */ - TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK) - TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK) - TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, - {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, }, - init, OK, ER ) + TMII_INSMI( MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, 0, 0, 0, -1, NULL, 0, 0, OK ); + TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, hbm ); + TMII_GMII ( MIIM_BITMAP|MIIM_FTYPE, 80, + MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, string, 80, hbm, + init, OK, ER ); TMII_DONE /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP: Only the low word of the dwTypeData is used. Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1, + (HMENU)MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, + NULL, OK, OK ); TMII_DONE /* Type flags */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, + NULL, OK, OK ); TMII_DONE /* State flags */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) - TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); + TMII_SMII( MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 0, 0 ); + TMII_GMII ( MIIM_STATE, 80, + 0, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 80, 0, + NULL, OK, OK ); TMII_DONE /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) - TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); + TMII_SMII( MIIM_CHECKMARKS, MFT_RADIOCHECK, 0, 0, 0, hbm, hbm, 0, 0, 0, 0 ); + TMII_GMII ( MIIM_CHECKMARKS | MIIM_TYPE, 80, + MFT_BITMAP, 0, 0, 0, hbm, hbm, 0, hbm, 0, hbm, + NULL, OK, OK ); TMII_DONE /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) - TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, }, - empty, OK, OK ) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, - empty, OK, OK ) - TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, }, - empty, OK, OK ) - TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); + TMII_SMII( MIIM_FTYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, (HBITMAP)0x1234, 0, 0 ); + TMII_GMII ( MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0, + NULL, OK, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP | MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, + NULL, OK, OK ); + TMII_GMII ( MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0, + NULL, OK, OK ); + TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, NULL, + NULL, OK, OK ); TMII_DONE /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP: Only the low word of the dwTypeData is used. Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, 0, 0, 0, -1, + (HMENU)MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP | MFT_RIGHTJUSTIFY, 0, 0, 0, 0, 0, 0, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, + NULL, OK, OK ); TMII_DONE /* Type flags */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, + NULL, OK, OK ); TMII_DONE /* State flags */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) - TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); + TMII_SMII( MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 0, 0 ); + TMII_GMII ( MIIM_STATE, 80, + 0, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, 0, 0, 0, 0, 0, 0, 80, 0, + NULL, OK, OK ); TMII_DONE /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) - TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); + TMII_SMII( MIIM_CHECKMARKS, MFT_RADIOCHECK, 0, 0, 0, hbm, hbm, 0, 0, 0, 0 ); + TMII_GMII ( MIIM_CHECKMARKS | MIIM_TYPE, 80, + MFT_BITMAP, 0, 0, 0, hbm, hbm, 0, hbm, 0, hbm, + NULL, OK, OK ); TMII_DONE /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */ - TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) - TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK) - TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, }, - empty, OK, OK ) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, - empty, OK, OK ) - TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, }, - empty, OK, OK ) - TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK) - TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, - {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, }, - empty, OK, OK ) + TMII_INSMI( MIIM_TYPE, MFT_BITMAP, -1, -1, 0, 0, 0, -1, hbm, -1, 0, OK ); + TMII_SMII( MIIM_FTYPE, MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, (HBITMAP)0x1234, 0, 0 ); + TMII_GMII ( MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0, + NULL, OK, OK ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_BITMAP | MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, hbm, 0, hbm, + NULL, OK, OK ); + TMII_GMII ( MIIM_FTYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, 0, 80, 0, + NULL, OK, OK ); + TMII_SMII( MIIM_BITMAP, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL ); + TMII_GMII ( MIIM_TYPE, 80, + MFT_OWNERDRAW, 0, 0, 0, 0, 0, 0, NULL, 0, NULL, + NULL, OK, OK ); TMII_DONE } while( !(ansi = !ansi) ); DeleteObject( hbm); @@ -1573,7 +1789,7 @@ static void test_menu_search_bycommand( void ) rc = GetMenuItemInfo(hmenu, (UINT_PTR)hmenuSub2, FALSE, &info); ok (rc, "Getting the menus info failed\n"); - ok (info.wID == (UINT)hmenuSub2, "IDs differ for popup menu\n"); + ok (info.wID == (UINT_PTR)hmenuSub2, "IDs differ for popup menu\n"); ok (!strcmp(info.dwTypeData, "Submenu2"), "Returned item has wrong label (%s)\n", info.dwTypeData); DestroyMenu( hmenu ); @@ -1655,23 +1871,23 @@ static struct menu_mouse_tests_s { BOOL _todo_wine; } menu_tests[] = { /* for each test, send keys or clicks and check for menu visibility */ - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, /* test 0 */ + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE }, /* test 0 */ { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE }, - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE }, - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 0}, TRUE, FALSE }, + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE }, - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE }, + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, VK_ESCAPE, 0}, FALSE, FALSE }, - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE }, + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', VK_ESCAPE, 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {VK_ESCAPE, 0}, FALSE, FALSE }, - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE }, + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE }, - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 0}, TRUE, FALSE }, + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE }, - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE }, + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 'P', 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {'D', 0}, FALSE, FALSE }, - { INPUT_KEYBOARD, {{0}}, {VK_LMENU, 'M', 'P', 0}, TRUE, FALSE }, + { INPUT_KEYBOARD, {{0}}, {VK_MENU, 'M', 'P', 0}, TRUE, FALSE }, { INPUT_KEYBOARD, {{0}}, {'E', 0}, FALSE, FALSE }, { INPUT_MOUSE, {{1, 2}, {0}}, {0}, TRUE, TRUE }, /* test 18 */ @@ -1691,14 +1907,14 @@ static struct menu_mouse_tests_s { static void send_key(WORD wVk) { TEST_INPUT i[2]; - memset(&i, 0, 2*sizeof(INPUT)); + memset(i, 0, sizeof(i)); i[0].type = i[1].type = INPUT_KEYBOARD; i[0].u.ki.wVk = i[1].u.ki.wVk = wVk; i[1].u.ki.dwFlags = KEYEVENTF_KEYUP; pSendInput(2, (INPUT *) i, sizeof(INPUT)); } -static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) +static BOOL click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) { HMENU hMenu = hMenus[mi->uMenu]; TEST_INPUT i[3]; @@ -1706,10 +1922,10 @@ static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) RECT r; int screen_w = GetSystemMetrics(SM_CXSCREEN); int screen_h = GetSystemMetrics(SM_CYSCREEN); + BOOL ret = GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r); + if(!ret) return FALSE; - GetMenuItemRect(mi->uMenu > 2 ? NULL : hWnd, hMenu, mi->uItem, &r); - - memset(&i, 0, 3*sizeof(INPUT)); + memset(i, 0, sizeof(i)); i[0].type = i[1].type = i[2].type = INPUT_MOUSE; i[0].u.mi.dx = i[1].u.mi.dx = i[2].u.mi.dx = ((r.left + 5) * 65535) / screen_w; @@ -1720,10 +1936,11 @@ static void click_menu(HANDLE hWnd, struct menu_item_pair_s *mi) i[0].u.mi.dwFlags |= MOUSEEVENTF_MOVE; i[1].u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; i[2].u.mi.dwFlags |= MOUSEEVENTF_LEFTUP; - pSendInput(3, (INPUT *) i, sizeof(INPUT)); + ret = pSendInput(3, (INPUT *) i, sizeof(INPUT)); /* hack to prevent mouse message buildup in Wine */ while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); + return ret; } static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter) @@ -1735,15 +1952,23 @@ static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter) /* mixed keyboard/mouse test */ for (i = 0; menu_tests[i].type != -1; i++) { - int elapsed = 0; + int ret = TRUE, elapsed = 0; + + got_input = i && menu_tests[i-1].bMenuVisible; if (menu_tests[i].type == INPUT_KEYBOARD) for (j = 0; menu_tests[i].wVk[j] != 0; j++) send_key(menu_tests[i].wVk[j]); else for (j = 0; menu_tests[i].menu_item_pairs[j].uMenu != 0; j++) - click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]); + if (!(ret = click_menu(hWnd, &menu_tests[i].menu_item_pairs[j]))) break; + if (!ret) + { + skip( "test %u: failed to send input\n", i ); + PostMessage( hWnd, WM_CANCELMODE, 0, 0 ); + return 0; + } while (menu_tests[i].bMenuVisible != bMenuVisible) { if (elapsed > 200) @@ -1752,6 +1977,13 @@ static DWORD WINAPI test_menu_input_thread(LPVOID lpParameter) Sleep(20); } + if (!got_input) + { + skip( "test %u: didn't receive input\n", i ); + PostMessage( hWnd, WM_CANCELMODE, 0, 0 ); + return 0; + } + if (menu_tests[i]._todo_wine) { todo_wine { @@ -1774,6 +2006,16 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, case WM_EXITMENULOOP: bMenuVisible = FALSE; break; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_NCMOUSEMOVE: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + got_input = TRUE; + /* fall through */ default: return( DefWindowProcA( hWnd, msg, wParam, lParam ) ); } @@ -1785,13 +2027,14 @@ static void test_menu_input(void) { WNDCLASSA wclass; HINSTANCE hInstance = GetModuleHandleA( NULL ); HANDLE hThread, hWnd; + DWORD tid; wclass.lpszClassName = "MenuTestClass"; wclass.style = CS_HREDRAW | CS_VREDRAW; wclass.lpfnWndProc = WndProc; wclass.hInstance = hInstance; - wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION ); - wclass.hCursor = LoadCursorA( NULL, (LPSTR)IDC_ARROW); + wclass.hIcon = LoadIconA( 0, IDI_APPLICATION ); + wclass.hCursor = LoadCursorA( NULL, IDC_ARROW ); wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1); wclass.lpszMenuName = 0; wclass.cbClsExtra = 0; @@ -1820,7 +2063,7 @@ static void test_menu_input(void) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); - hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, NULL); + hThread = CreateThread(NULL, 0, test_menu_input_thread, hWnd, 0, &tid); while(1) { if (WAIT_TIMEOUT != WaitForSingleObject(hThread, 50)) @@ -1837,7 +2080,7 @@ static void test_menu_flags( void ) hMenu = CreateMenu(); hPopupMenu = CreatePopupMenu(); - AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup"); + AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT_PTR)hPopupMenu, "Popup"); AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1"); InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2"); @@ -1871,8 +2114,8 @@ static void test_menu_hilitemenuitem( void ) wclass.style = CS_HREDRAW | CS_VREDRAW; wclass.lpfnWndProc = WndProc; wclass.hInstance = GetModuleHandleA( NULL ); - wclass.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION ); - wclass.hCursor = LoadCursorA( NULL, (LPSTR)IDC_ARROW); + wclass.hIcon = LoadIconA( 0, IDI_APPLICATION ); + wclass.hCursor = LoadCursorA( NULL, IDC_ARROW ); wclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1); wclass.lpszMenuName = 0; wclass.cbClsExtra = 0; @@ -1885,7 +2128,7 @@ static void test_menu_hilitemenuitem( void ) hMenu = CreateMenu(); hPopupMenu = CreatePopupMenu(); - AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup"); + AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT_PTR)hPopupMenu, "Popup"); AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1"); AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2"); @@ -1997,9 +2240,10 @@ static void test_menu_hilitemenuitem( void ) static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type, UINT checked_state) { - UINT i, count; + INT i, count; count = GetMenuItemCount(hmenu); + ok (count != -1, "GetMenuItemCount returned -1\n"); for (i = 0; i < count; i++) { @@ -2017,7 +2261,7 @@ static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type, #endif if (mii.hSubMenu) { - ok((HMENU)mii.wID == mii.hSubMenu, "id %u: wID should be equal to hSubMenu\n", checked_cmd); + ok(mii.wID == (UINT_PTR)mii.hSubMenu, "id %u: wID should be equal to hSubMenu\n", checked_cmd); check_menu_items(mii.hSubMenu, checked_cmd, checked_type, checked_state); } else @@ -2140,7 +2384,7 @@ static void test_menu_resource_layout(void) { MF_SEPARATOR, MF_GRAYED|MF_DISABLED, 8, "" } }; HMENU hmenu; - UINT count, i; + INT count, i; BOOL ret; hmenu = LoadMenuIndirect(&menu_template); @@ -2182,7 +2426,7 @@ static void test_menu_resource_layout(void) "%u: expected wID %04x, got %04x\n", i, menu_data[i].id, mii.wID); ok(mii.cch == strlen(menu_data[i].str), "%u: expected cch %u, got %u\n", i, (UINT)strlen(menu_data[i].str), mii.cch); - ok(!strcmp((LPCSTR)mii.dwTypeData, menu_data[i].str), + ok(!strcmp(mii.dwTypeData, menu_data[i].str), "%u: expected dwTypeData %s, got %s\n", i, menu_data[i].str, (LPCSTR)mii.dwTypeData); } @@ -2214,6 +2458,48 @@ static HMENU create_menu_from_data(const struct menu_data *item, INT item_count) return hmenu; } +/* use InsertMenuItem: does not set the MFT_BITMAP flag, + * and does not accept non-magic bitmaps with invalid + * bitmap handles */ +static HMENU create_menuitem_from_data(const struct menu_data *item, INT item_count) +{ + HMENU hmenu; + INT i; + BOOL ret; + MENUITEMINFO mii = { sizeof( MENUITEMINFO)}; + + hmenu = CreateMenu(); + assert(hmenu != 0); + + for (i = 0; i < item_count; i++) + { + SetLastError(0xdeadbeef); + + mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE; + mii.fType = 0; + if( item[i].type & MFT_BITMAP) + { + mii.fMask |= MIIM_BITMAP; + mii.hbmpItem = (HBITMAP)item[i].str; + } + else if( item[i].type & MFT_SEPARATOR) + mii.fType = MFT_SEPARATOR; + else + { + mii.fMask |= MIIM_STRING; + mii.dwTypeData = (LPSTR)item[i].str; + mii.cch = strlen( item[i].str); + } + mii.fState = 0; + if( item[i].type & MF_HELP) mii.fType |= MF_HELP; + mii.wID = item[i].id; + ret = InsertMenuItem( hmenu, -1, TRUE, &mii); + ok(ret, "%d: InsertMenuItem(%04x, %04x, %p) error %u\n", + i, item[i].type, item[i].id, item[i].str, GetLastError()); + } + return hmenu; +} + static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT item_count) { INT count, i; @@ -2242,19 +2528,17 @@ static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT ite "%u: expected fType %04x, got %04x\n", i, item[i].type, mii.fType); ok(mii.wID == item[i].id, "%u: expected wID %04x, got %04x\n", i, item[i].id, mii.wID); - if (item[i].type & (MF_BITMAP | MF_SEPARATOR)) - { + if (mii.hbmpItem || !item[i].str) /* For some reason Windows sets high word to not 0 for * not "magic" ids. */ ok(LOWORD(mii.hbmpItem) == LOWORD(item[i].str), "%u: expected hbmpItem %p, got %p\n", i, item[i].str, mii.hbmpItem); - } else { ok(mii.cch == strlen(item[i].str), "%u: expected cch %u, got %u\n", i, (UINT)strlen(item[i].str), mii.cch); - ok(!strcmp((LPCSTR)mii.dwTypeData, item[i].str), + ok(!strcmp(mii.dwTypeData, item[i].str), "%u: expected dwTypeData %s, got %s\n", i, item[i].str, (LPCSTR)mii.dwTypeData); } } @@ -2262,6 +2546,7 @@ static void compare_menu_data(HMENU hmenu, const struct menu_data *item, INT ite static void test_InsertMenu(void) { + HBITMAP hbm = CreateBitmap(1,1,1,1,NULL); /* Note: XP treats only bitmap handles 1 - 6 as "magic" ones * regardless of their id. */ @@ -2277,16 +2562,28 @@ static void test_InsertMenu(void) { MF_STRING|MF_HELP, 2, "Help" }, { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) } }; - static const struct menu_data in2[] = + static const struct menu_data out1a[] = { { MF_STRING, 1, "File" }, - { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(100) }, + { MF_STRING|MF_HELP, 2, "Help" }, + { MF_HELP, SC_CLOSE, MAKEINTRESOURCE(1) } + }; + const struct menu_data in2[] = + { + { MF_STRING, 1, "File" }, + { MF_BITMAP|MF_HELP, SC_CLOSE, (char*)hbm }, { MF_STRING|MF_HELP, 2, "Help" } }; - static const struct menu_data out2[] = + const struct menu_data out2[] = { { MF_STRING, 1, "File" }, - { MF_BITMAP|MF_HELP, SC_CLOSE, MAKEINTRESOURCE(100) }, + { MF_BITMAP|MF_HELP, SC_CLOSE, (char*)hbm }, + { MF_STRING|MF_HELP, 2, "Help" } + }; + const struct menu_data out2a[] = + { + { MF_STRING, 1, "File" }, + { MF_HELP, SC_CLOSE, (char*)hbm }, { MF_STRING|MF_HELP, 2, "Help" } }; static const struct menu_data in3[] = @@ -2313,9 +2610,16 @@ static void test_InsertMenu(void) { MF_STRING|MF_HELP, 2, "Help" }, { MF_BITMAP|MF_HELP, 1, MAKEINTRESOURCE(1) } }; + static const struct menu_data out4a[] = + { + { MF_STRING, 1, "File" }, + { MF_STRING|MF_HELP, 2, "Help" }, + { MF_HELP, 1, MAKEINTRESOURCE(1) } + }; HMENU hmenu; #define create_menu(a) create_menu_from_data((a), sizeof(a)/sizeof((a)[0])) +#define create_menuitem(a) create_menuitem_from_data((a), sizeof(a)/sizeof((a)[0])) #define compare_menu(h, a) compare_menu_data((h), (a), sizeof(a)/sizeof((a)[0])) hmenu = create_menu(in1); @@ -2334,31 +2638,584 @@ static void test_InsertMenu(void) compare_menu(hmenu, out4); DestroyMenu(hmenu); + /* now using InsertMenuItemInfo */ + hmenu = create_menuitem(in1); + compare_menu(hmenu, out1a); + DestroyMenu(hmenu); + + hmenu = create_menuitem(in2); + compare_menu(hmenu, out2a); + DestroyMenu(hmenu); + + hmenu = create_menuitem(in3); + compare_menu(hmenu, out3); + DestroyMenu(hmenu); + + hmenu = create_menuitem(in4); + compare_menu(hmenu, out4a); + DestroyMenu(hmenu); + #undef create_menu +#undef create_menuitem #undef compare_menu } +static void test_menu_getmenuinfo(void) +{ + HMENU hmenu; + MENUINFO mi = {0}; + BOOL ret; + DWORD gle; + + /* create a menu */ + hmenu = CreateMenu(); + assert( hmenu); + /* test some parameter errors */ + SetLastError(0xdeadbeef); + ret = pGetMenuInfo( hmenu, NULL); + gle= GetLastError(); + ok( !ret, "GetMenuInfo() should have failed\n"); + ok( gle == ERROR_INVALID_PARAMETER || + broken(gle == 0xdeadbeef), /* Win98, WinME */ + "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + mi.cbSize = 0; + ret = pGetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( !ret, "GetMenuInfo() should have failed\n"); + ok( gle == ERROR_INVALID_PARAMETER || + broken(gle == 0xdeadbeef), /* Win98, WinME */ + "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + ret = pGetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( ret, "GetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + SetLastError(0xdeadbeef); + mi.cbSize = 0; + ret = pGetMenuInfo( NULL, &mi); + gle= GetLastError(); + ok( !ret, "GetMenuInfo() should have failed\n"); + ok( gle == ERROR_INVALID_PARAMETER || + broken(gle == 0xdeadbeef), /* Win98, WinME */ + "GetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + /* clean up */ + DestroyMenu( hmenu); + return; +} + +static void test_menu_setmenuinfo(void) +{ + HMENU hmenu, hsubmenu; + MENUINFO mi = {0}; + MENUITEMINFOA mii = {sizeof( MENUITEMINFOA)}; + BOOL ret; + DWORD gle; + + /* create a menu with a submenu */ + hmenu = CreateMenu(); + hsubmenu = CreateMenu(); + assert( hmenu && hsubmenu); + mii.fMask = MIIM_SUBMENU; + mii.hSubMenu = hsubmenu; + ret = InsertMenuItem( hmenu, 0, FALSE, &mii); + ok( ret, "InsertMenuItem failed with error %d\n", GetLastError()); + /* test some parameter errors */ + SetLastError(0xdeadbeef); + ret = pSetMenuInfo( hmenu, NULL); + gle= GetLastError(); + ok( !ret, "SetMenuInfo() should have failed\n"); + ok( gle == ERROR_INVALID_PARAMETER || + broken(gle == 0xdeadbeef), /* Win98, WinME */ + "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + mi.cbSize = 0; + ret = pSetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( !ret, "SetMenuInfo() should have failed\n"); + ok( gle == ERROR_INVALID_PARAMETER || + broken(gle == 0xdeadbeef), /* Win98, WinME */ + "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + ret = pSetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( ret, "SetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); + SetLastError(0xdeadbeef); + mi.cbSize = 0; + ret = pSetMenuInfo( NULL, &mi); + gle= GetLastError(); + ok( !ret, "SetMenuInfo() should have failed\n"); + ok( gle == ERROR_INVALID_PARAMETER || + broken(gle == 0xdeadbeef), /* Win98, WinME */ + "SetMenuInfo() error got %u expected %u\n", gle, ERROR_INVALID_PARAMETER); + /* functional tests */ + /* menu and submenu should have the CHECKORBMP style bit cleared */ + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + mi.fMask = MIM_STYLE; + ret = pGetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( ret, "GetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n"); + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + mi.fMask = MIM_STYLE; + ret = pGetMenuInfo( hsubmenu, &mi); + gle= GetLastError(); + ok( ret, "GetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( !(mi.dwStyle & MNS_CHECKORBMP), "menustyle was not expected to have the MNS_CHECKORBMP flag\n"); + /* SetMenuInfo() */ + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + mi.fMask = MIM_STYLE | MIM_APPLYTOSUBMENUS; + mi.dwStyle = MNS_CHECKORBMP; + ret = pSetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( ret, "SetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); + /* Now both menus should have the MNS_CHECKORBMP style bit set */ + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + mi.fMask = MIM_STYLE; + ret = pGetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( ret, "GetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n"); + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + mi.fMask = MIM_STYLE; + ret = pGetMenuInfo( hsubmenu, &mi); + gle= GetLastError(); + ok( ret, "GetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( mi.dwStyle & MNS_CHECKORBMP, "menustyle was expected to have the MNS_CHECKORBMP flag\n"); + /* now repeat that without the APPLYTOSUBMENUS flag and another style bit */ + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + mi.fMask = MIM_STYLE ; + mi.dwStyle = MNS_NOCHECK; + ret = pSetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( ret, "SetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "SetMenuInfo() error got %u\n", gle); + /* Now only the top menu should have the MNS_NOCHECK style bit set */ + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + mi.fMask = MIM_STYLE; + ret = pGetMenuInfo( hmenu, &mi); + gle= GetLastError(); + ok( ret, "GetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( mi.dwStyle & MNS_NOCHECK, "menustyle was expected to have the MNS_NOCHECK flag\n"); + SetLastError(0xdeadbeef); + mi.cbSize = sizeof( MENUINFO); + mi.fMask = MIM_STYLE; + ret = pGetMenuInfo( hsubmenu, &mi); + gle= GetLastError(); + ok( ret, "GetMenuInfo() should have succeeded\n"); + ok( gle == 0xdeadbeef, "GetMenuInfo() error got %u\n", gle); + ok( !(mi.dwStyle & MNS_NOCHECK), "menustyle was not expected to have the MNS_NOCHECK flag\n"); + /* clean up */ + DestroyMenu( hsubmenu); + DestroyMenu( hmenu); + return; +} + +/* little func to easy switch either TrackPopupMenu() or TrackPopupMenuEx() */ +static DWORD MyTrackPopupMenu( int ex, HMENU hmenu, UINT flags, INT x, INT y, HWND hwnd, LPTPMPARAMS ptpm) +{ + return ex + ? TrackPopupMenuEx( hmenu, flags, x, y, hwnd, ptpm) + : TrackPopupMenu( hmenu, flags, x, y, 0, hwnd, NULL); +} + +/* some TrackPopupMenu and TrackPopupMenuEx tests */ +/* the LastError values differ between NO_ERROR and invalid handle */ +/* between all windows versions tested. The first value is that valid on XP */ +/* Vista was the only that made returned different error values */ +/* between the TrackPopupMenu and TrackPopupMenuEx functions */ +static void test_menu_trackpopupmenu(void) +{ + BOOL ret; + HMENU hmenu; + DWORD gle; + int Ex; + HWND hwnd = CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass), NULL, + WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, + NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError()); + if (!hwnd) return; + SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_ownerdraw_wnd_proc); + for( Ex = 0; Ex < 2; Ex++) + { + hmenu = CreatePopupMenu(); + ok(hmenu != NULL, "CreateMenu failed with error %d\n", GetLastError()); + if (!hmenu) + { + DestroyWindow(hwnd); + return; + } + /* display the menu */ + /* start with an invalid menu handle */ + gle = 0xdeadbeef; + gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; + ret = MyTrackPopupMenu( Ex, NULL, 0x100, 100,100, hwnd, NULL); + gle = GetLastError(); + ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); + ok( gle == ERROR_INVALID_MENU_HANDLE + || broken (gle == 0xdeadbeef) /* win95 */ + || broken (gle == NO_ERROR) /* win98/ME */ + ,"TrackPopupMenu%s error got %u expected %u\n", + Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE); + ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), + "got unexpected message(s)%s%s%s\n", + gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", + gflag_entermenuloop ? "WM_INITMENULOOP ": "", + gflag_initmenu ? "WM_INITMENU": ""); + /* another one but not NULL */ + gle = 0xdeadbeef; + gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; + ret = MyTrackPopupMenu( Ex, (HMENU)hwnd, 0x100, 100,100, hwnd, NULL); + gle = GetLastError(); + ok( !ret, "TrackPopupMenu%s should have failed\n", Ex ? "Ex" : ""); + ok( gle == ERROR_INVALID_MENU_HANDLE + || broken (gle == 0xdeadbeef) /* win95 */ + || broken (gle == NO_ERROR) /* win98/ME */ + ,"TrackPopupMenu%s error got %u expected %u\n", + Ex ? "Ex" : "", gle, ERROR_INVALID_MENU_HANDLE); + ok( !(gflag_initmenupopup || gflag_entermenuloop || gflag_initmenu), + "got unexpected message(s)%s%s%s\n", + gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", + gflag_entermenuloop ? "WM_INITMENULOOP ": "", + gflag_initmenu ? "WM_INITMENU": ""); + /* now a somewhat successful call */ + gle = 0xdeadbeef; + gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; + ret = MyTrackPopupMenu( Ex, hmenu, 0x100, 100,100, hwnd, NULL); + gle = GetLastError(); + ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret); + ok( gle == NO_ERROR + || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k */ + || broken (gle == 0xdeadbeef) /* win95 */ + ,"TrackPopupMenu%s error got %u expected %u or %u\n", + Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE); + ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu, + "missed expected message(s)%s%s%s\n", + !gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", + !gflag_entermenuloop ? "WM_INITMENULOOP ": "", + !gflag_initmenu ? "WM_INITMENU": ""); + /* and another */ + ret = AppendMenuA( hmenu, MF_STRING, 1, "winetest"); + ok( ret, "AppendMenA has failed!\n"); + gle = 0xdeadbeef; + gflag_initmenupopup = gflag_entermenuloop = gflag_initmenu = 0; + ret = MyTrackPopupMenu( Ex, hmenu, 0x100, 100,100, hwnd, NULL); + gle = GetLastError(); + ok( ret == 0, "TrackPopupMenu%s returned %d expected zero\n", Ex ? "Ex" : "", ret); + ok( gle == NO_ERROR + || gle == ERROR_INVALID_MENU_HANDLE /* NT4, win2k and Vista in the TrackPopupMenuEx case */ + || broken (gle == 0xdeadbeef) /* win95 */ + ,"TrackPopupMenu%s error got %u expected %u or %u\n", + Ex ? "Ex" : "", gle, NO_ERROR, ERROR_INVALID_MENU_HANDLE); + ok( gflag_initmenupopup && gflag_entermenuloop && gflag_initmenu, + "missed expected message(s)%s%s%s\n", + !gflag_initmenupopup ? " WM_INITMENUPOPUP ": " ", + !gflag_entermenuloop ? "WM_INITMENULOOP ": "", + !gflag_initmenu ? "WM_INITMENU": ""); + DestroyMenu(hmenu); + } + /* clean up */ + DestroyWindow(hwnd); +} + +/* test handling of WM_CANCELMODE messages */ +static int g_got_enteridle; +static HWND g_hwndtosend; +static LRESULT WINAPI menu_cancelmode_wnd_proc(HWND hwnd, UINT msg, + WPARAM wparam, LPARAM lparam) +{ + switch (msg) + { + case WM_ENTERMENULOOP: + g_got_enteridle = 0; + return SendMessage( g_hwndtosend, WM_CANCELMODE, 0, 0); + case WM_ENTERIDLE: + { + if( g_got_enteridle++ == 0) { + /* little hack to get another WM_ENTERIDLE message */ + PostMessage( hwnd, WM_MOUSEMOVE, 0, 0); + return SendMessage( g_hwndtosend, WM_CANCELMODE, 0, 0); + } + pEndMenu(); + return TRUE; + } + } + return DefWindowProc( hwnd, msg, wparam, lparam); +} + +static void test_menu_cancelmode(void) +{ + DWORD ret; + HWND hwnd, hwndchild; + HMENU menu; + if( !pEndMenu) { /* win95 */ + win_skip( "EndMenu is not available\n"); + return; + } + hwnd = CreateWindowEx( 0, MAKEINTATOM(atomMenuCheckClass), NULL, + WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, + NULL, NULL, NULL, NULL); + hwndchild = CreateWindowEx( 0, MAKEINTATOM(atomMenuCheckClass), NULL, + WS_VISIBLE | WS_CHILD, 10, 10, 20, 20, + hwnd, NULL, NULL, NULL); + ok( hwnd != NULL && hwndchild != NULL, + "CreateWindowEx failed with error %d\n", GetLastError()); + g_hwndtosend = hwnd; + SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)menu_cancelmode_wnd_proc); + SetWindowLongPtr( hwndchild, GWLP_WNDPROC, (LONG_PTR)menu_cancelmode_wnd_proc); + menu = CreatePopupMenu(); + ok( menu != NULL, "CreatePopupMenu failed with error %d\n", GetLastError()); + ret = AppendMenuA( menu, MF_STRING, 1, "winetest"); + ok( ret, "Functie failed lasterror is %u\n", GetLastError()); + /* seems to be needed only on wine :( */ + {MSG msg; while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg);} + /* test the effect of sending a WM_CANCELMODE message in the WM_INITMENULOOP + * handler of the menu owner */ + /* test results is exctracted from variable g_got_enteridle. Possible values: + * 0 : complete conformance. Sending WM_CANCELMODE cancels a menu initializing tracking + * 1 : Sending WM_CANCELMODE cancels a menu that is in tracking state + * 2 : Sending WM_CANCELMODE does not work + */ + /* menu owner is top level window */ + g_hwndtosend = hwnd; + ret = TrackPopupMenu( menu, 0x100, 100,100, 0, hwnd, NULL); + todo_wine { + ok( g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle); + } + ok( g_got_enteridle < 2, "received %d WM_ENTERIDLE messages, should be less than 2\n", g_got_enteridle); + /* menu owner is child window */ + g_hwndtosend = hwndchild; + ret = TrackPopupMenu( menu, 0x100, 100,100, 0, hwndchild, NULL); + todo_wine { + ok(g_got_enteridle == 0, "received %d WM_ENTERIDLE messages, none expected\n", g_got_enteridle); + } + ok(g_got_enteridle < 2, "received %d WM_ENTERIDLE messages, should be less than 2\n", g_got_enteridle); + /* now send the WM_CANCELMODE messages to the WRONG window */ + /* those should fail ( to have any effect) */ + g_hwndtosend = hwnd; + ret = TrackPopupMenu( menu, 0x100, 100,100, 0, hwndchild, NULL); + ok( g_got_enteridle == 2, "received %d WM_ENTERIDLE messages, should be 2\n", g_got_enteridle); + /* cleanup */ + DestroyMenu( menu); + DestroyWindow( hwndchild); + DestroyWindow( hwnd); +} + +/* show menu trees have a maximum depth */ +static void test_menu_maxdepth(void) +{ +#define NR_MENUS 100 + HMENU hmenus[ NR_MENUS]; + int i; + DWORD ret; + + SetLastError(12345678); + for( i = 0; i < NR_MENUS; i++) { + hmenus[i] = CreatePopupMenu(); + if( !hmenus[i]) break; + } + ok( i == NR_MENUS, "could not create more than %d menu's\n", i); + for( i = 1; i < NR_MENUS; i++) { + ret = AppendMenuA( hmenus[i], MF_POPUP, (UINT_PTR)hmenus[i-1],"test"); + if( !ret) break; + } + trace("Maximum depth is %d\n", i); + ok( GetLastError() == 12345678, "unexpected error %d\n", GetLastError()); + ok( i < NR_MENUS || + broken( i == NR_MENUS), /* win98, NT */ + "no ( or very large) limit on menu depth!\n"); + + for( i = 0; i < NR_MENUS; i++) + DestroyMenu( hmenus[i]); +} + +/* bug #12171 */ +static void test_menu_circref(void) +{ + HMENU menu1, menu2; + DWORD ret; + + menu1 = CreatePopupMenu(); + menu2 = CreatePopupMenu(); + ok( menu1 && menu2, "error creating menus.\n"); + ret = AppendMenuA( menu1, MF_POPUP, (UINT_PTR)menu2, "winetest"); + ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); + ret = AppendMenuA( menu1, MF_STRING | MF_HILITE, 123, "winetest"); + ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); + /* app chooses an id that happens to clash with its own hmenu */ + ret = AppendMenuA( menu2, MF_STRING, (UINT_PTR)menu2, "winetest"); + ok( ret, "AppendMenu failed, error is %d\n", GetLastError()); + /* now attempt to change the string of the first item of menu1 */ + ret = ModifyMenuA( menu1, (UINT_PTR)menu2, MF_POPUP, (UINT_PTR)menu2, "menu 2"); + ok( !ret || + broken( ret), /* win98, NT */ + "ModifyMenu should have failed.\n"); + if( !ret) { /* will probably stack fault if the ModifyMenu succeeded */ + ret = GetMenuState( menu1, 123, 0); + ok( ret == MF_HILITE, "GetMenuState returned %x\n",ret); + } + DestroyMenu( menu2); + DestroyMenu( menu1); +} + +/* test how the menu texts are aligned when the menu items have + * different combinations of text and bitmaps (bug #13350) */ +static void test_menualign(void) +{ + BYTE bmfill[300]; + HMENU menu; + HBITMAP hbm1, hbm2, hbm3; + MENUITEMINFO mii = { sizeof(MENUITEMINFO)}; + DWORD ret; + HWND hwnd; + MENUINFO mi = { sizeof( MENUINFO)}; + + if( !winetest_interactive) { + skip( "interactive alignment tests.\n"); + return; + } + hwnd = CreateWindowEx(0, + "STATIC", + "Menu text alignment Test\nPlease make a selection.", + WS_OVERLAPPEDWINDOW, + 100, 100, + 300, 300, + NULL, NULL, 0, NULL); + ShowWindow( hwnd, SW_SHOW); + /* create bitmaps */ + memset( bmfill, 0xcc, sizeof( bmfill)); + hbm1 = CreateBitmap( 10,10,1,1,bmfill); + hbm2 = CreateBitmap( 20,20,1,1,bmfill); + hbm3 = CreateBitmap( 50,6,1,1,bmfill); + ok( hbm1 && hbm2 && hbm3, "Creating bitmaps failed\n"); + menu = CreatePopupMenu(); + ok( menu != NULL, "CreatePopupMenu() failed\n"); + if( pGetMenuInfo) { + mi.fMask = MIM_STYLE; + ret = pGetMenuInfo( menu, &mi); + ok( menu != NULL, "GetMenuInfo() failed\n"); + ok( 0 == mi.dwStyle, "menuinfo style is %x\n", mi.dwStyle); + } + /* test 1 */ + mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; + mii.wID = 1; + mii.hbmpItem = hbm1; + mii.dwTypeData = (LPSTR) " OK: menu texts are correctly left-aligned."; + ret = InsertMenuItem( menu, -1, TRUE, &mii); + ok( ret, "InsertMenuItem() failed\n"); + mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID ; + mii.wID = 2; + mii.hbmpItem = hbm2; + mii.dwTypeData = (LPSTR) " FAIL: menu texts are NOT left-aligned."; + ret = InsertMenuItem( menu, -1, TRUE, &mii); + ok( ret, "InsertMenuItem() failed\n"); + ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); + ok( ret != 2, "User indicated that menu text alignment test 1 failed %d\n", ret); + /* test 2*/ + mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; + mii.wID = 3; + mii.hbmpItem = hbm3; + mii.dwTypeData = NULL; + ret = InsertMenuItem( menu, 0, TRUE, &mii); + ok( ret, "InsertMenuItem() failed\n"); + mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; + mii.wID = 1; + mii.hbmpItem = hbm1; + /* make the text a bit longer, to keep it readable */ + /* this bug is on winXP and reproduced on wine */ + mii.dwTypeData = (LPSTR) " OK: menu texts are to the right of the bitmaps........"; + ret = SetMenuItemInfo( menu, 1, TRUE, &mii); + ok( ret, "SetMenuItemInfo() failed\n"); + mii.wID = 2; + mii.hbmpItem = hbm2; + mii.dwTypeData = (LPSTR) " FAIL: menu texts are below the first bitmap. "; + ret = SetMenuItemInfo( menu, 2, TRUE, &mii); + ok( ret, "SetMenuItemInfo() failed\n"); + ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); + ok( ret != 2, "User indicated that menu text alignment test 2 failed %d\n", ret); + /* test 3 */ + mii.fMask = MIIM_TYPE | MIIM_ID; + mii.wID = 3; + mii.fType = MFT_BITMAP; + mii.dwTypeData = (LPSTR) hbm3; + ret = SetMenuItemInfo( menu, 0, TRUE, &mii); + ok( ret, "SetMenuItemInfo() failed\n"); + mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_ID; + mii.wID = 1; + mii.hbmpItem = NULL; + mii.dwTypeData = (LPSTR) " OK: menu texts are below the bitmap."; + ret = SetMenuItemInfo( menu, 1, TRUE, &mii); + ok( ret, "SetMenuItemInfo() failed\n"); + mii.wID = 2; + mii.hbmpItem = NULL; + mii.dwTypeData = (LPSTR) " FAIL: menu texts are NOT below the bitmap."; + ret = SetMenuItemInfo( menu, 2, TRUE, &mii); + ok( ret, "SetMenuItemInfo() failed\n"); + ret = TrackPopupMenu( menu, TPM_RETURNCMD, 110, 200, 0, hwnd, NULL); + ok( ret != 2, "User indicated that menu text alignment test 3 failed %d\n", ret); + /* cleanup */ + DeleteObject( hbm1); + DeleteObject( hbm2); + DeleteObject( hbm3); + DestroyMenu( menu); + DestroyWindow( hwnd); +} + START_TEST(menu) { init_function_pointers(); + /* Wine defines MENUITEMINFO for W2K and above. NT4 and below can't + * handle that. + */ + if (correct_behavior()) + { + test_menu_add_string(); + test_menu_iteminfo(); + test_menu_search_bycommand(); + test_CheckMenuRadioItem(); + test_menu_resource_layout(); + test_InsertMenu(); + test_menualign(); + } + register_menu_check_class(); test_menu_locked_by_window(); + test_subpopup_locked_by_menu(); test_menu_ownerdraw(); - test_menu_add_string(); - test_menu_iteminfo(); - test_menu_search_bycommand(); test_menu_bmp_and_string(); - + /* test Get/SetMenuInfo if available */ + if( pGetMenuInfo && pSetMenuInfo) { + test_menu_getmenuinfo(); + test_menu_setmenuinfo(); + } else + win_skip("Get/SetMenuInfo are not available\n"); if( !pSendInput) - skip("SendInput is not available\n"); + win_skip("SendInput is not available\n"); else test_menu_input(); test_menu_flags(); test_menu_hilitemenuitem(); - test_CheckMenuRadioItem(); - test_menu_resource_layout(); - test_InsertMenu(); + test_menu_trackpopupmenu(); + test_menu_cancelmode(); + test_menu_maxdepth(); + test_menu_circref(); } diff --git a/rostests/winetests/user32/monitor.c b/rostests/winetests/user32/monitor.c index a723dd1d610..250a421e5dc 100644 --- a/rostests/winetests/user32/monitor.c +++ b/rostests/winetests/user32/monitor.c @@ -2,6 +2,7 @@ * Unit tests for monitor APIs * * Copyright 2005 Huw Davies + * Copyright 2008 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -61,7 +62,7 @@ static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, mi.cbSize = sizeof(mi); ok(pGetMonitorInfoA(hmon, (MONITORINFO*)&mi), "GetMonitorInfo failed\n"); - if(mi.dwFlags == MONITORINFOF_PRIMARY) + if (mi.dwFlags & MONITORINFOF_PRIMARY) strcpy(primary, mi.szDevice); return TRUE; @@ -73,15 +74,20 @@ static void test_enumdisplaydevices(void) char primary_device_name[32]; char primary_monitor_device_name[32]; DWORD primary_num = -1, num = 0; + BOOL ret; + + if (!pEnumDisplayDevicesA) + { + win_skip("EnumDisplayDevicesA is not available\n"); + return; + } dd.cb = sizeof(dd); - if(pEnumDisplayDevicesA == NULL) return; while(1) { BOOL ret; HDC dc; ret = pEnumDisplayDevicesA(NULL, num, &dd, 0); - ok(ret || num != 0, "EnumDisplayDevices fails with num == 0\n"); if(!ret) break; if(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { @@ -97,22 +103,25 @@ static void test_enumdisplaydevices(void) } num++; } - ok(primary_num != -1, "Didn't get the primary device\n"); - if(pEnumDisplayMonitors && pGetMonitorInfoA) { - ok(pEnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)primary_monitor_device_name), - "EnumDisplayMonitors failed\n"); + if (primary_num == -1 || !pEnumDisplayMonitors || !pGetMonitorInfoA) + { + win_skip("EnumDisplayMonitors or GetMonitorInfoA are not available\n"); + return; + } + primary_monitor_device_name[0] = 0; + ret = pEnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)primary_monitor_device_name); + ok(ret, "EnumDisplayMonitors failed\n"); ok(!strcmp(primary_monitor_device_name, primary_device_name), "monitor device name %s, device name %s\n", primary_monitor_device_name, primary_device_name); } -} struct vid_mode { DWORD w, h, bpp, freq, fields; - LONG success; + BOOL must_succeed; }; static const struct vid_mode vid_modes_test[] = { @@ -120,18 +129,20 @@ static const struct vid_mode vid_modes_test[] = { {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY, 1}, {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL , 1}, {640, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT , 1}, - {640, 480, 0, 0, DM_BITSPERPEL , 1}, - {640, 480, 0, 0, DM_DISPLAYFREQUENCY, 1}, + {640, 480, 0, 0, DM_BITSPERPEL , 0}, + {640, 480, 0, 0, DM_DISPLAYFREQUENCY, 0}, - {0, 0, 0, 0, DM_PELSWIDTH, 1}, - {0, 0, 0, 0, DM_PELSHEIGHT, 1}, + {0, 0, 0, 0, DM_PELSWIDTH, 0}, + {0, 0, 0, 0, DM_PELSHEIGHT, 0}, {640, 480, 0, 0, DM_PELSWIDTH, 0}, {640, 480, 0, 0, DM_PELSHEIGHT, 0}, { 0, 480, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0}, {640, 0, 0, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0}, - {0, 0, 0, 0, DM_DISPLAYFREQUENCY, 0}, + /* the following test succeeds under XP SP3 + {0, 0, 0, 0, DM_DISPLAYFREQUENCY, 0} + */ }; #define vid_modes_cnt (sizeof(vid_modes_test) / sizeof(vid_modes_test[0])) @@ -145,7 +156,7 @@ static void test_ChangeDisplaySettingsEx(void) if (!pChangeDisplaySettingsExA) { - skip("ChangeDisplaySettingsExA is not available\n"); + win_skip("ChangeDisplaySettingsExA is not available\n"); return; } @@ -155,6 +166,45 @@ static void test_ChangeDisplaySettingsEx(void) width = dm.dmPelsWidth; + dm.dmDriverExtra = 1; + res = ChangeDisplaySettingsA(&dm, CDS_TEST); + ok(res == DISP_CHANGE_SUCCESSFUL, + "ChangeDisplaySettingsA returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); + ok(dm.dmDriverExtra == 0 || broken(dm.dmDriverExtra == 1) /* win9x */, + "ChangeDisplaySettingsA didn't reset dmDriverExtra to 0\n"); + + /* crashes under XP SP3 for large dmDriverExtra values */ + dm.dmDriverExtra = 1; + res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); + ok(res == DISP_CHANGE_SUCCESSFUL, + "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_BADMODE\n", res); + ok(dm.dmDriverExtra == 1, "ChangeDisplaySettingsExA shouldn't reset dmDriverExtra to 0\n"); + + memset(&dmW, 0, sizeof(dmW)); + dmW.dmSize = sizeof(dmW); + dmW.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + dmW.dmPelsWidth = dm.dmPelsWidth; + dmW.dmPelsHeight = dm.dmPelsHeight; + dmW.dmDriverExtra = 1; + SetLastError(0xdeadbeef); + res = ChangeDisplaySettingsW(&dmW, CDS_TEST); + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + { + ok(res == DISP_CHANGE_SUCCESSFUL, + "ChangeDisplaySettingsW returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); + ok(dmW.dmDriverExtra == 0, "ChangeDisplaySettingsW didn't reset dmDriverExtra to 0\n"); + } + + /* Apparently XP treats dmDriverExtra being != 0 as an error */ + dmW.dmDriverExtra = 1; + res = pChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + { + ok(res == DISP_CHANGE_SUCCESSFUL, + "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_BADMODE\n", res); + ok(dmW.dmDriverExtra == 1, "ChangeDisplaySettingsExW shouldn't reset dmDriverExtra to 0\n"); + } + /* the following 2 tests show that dm.dmSize being 0 is invalid, but * ChangeDisplaySettingsExA still reports success. */ @@ -162,8 +212,10 @@ static void test_ChangeDisplaySettingsEx(void) dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; dm.dmPelsWidth = width; res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); - ok(res == DISP_CHANGE_SUCCESSFUL, - "ChangeDisplaySettingsExA returned %d, expected DISP_CHANGE_SUCCESSFUL\n", res); + ok(res == DISP_CHANGE_SUCCESSFUL || + res == DISP_CHANGE_BADMODE || /* Win98, WinMe */ + res == DISP_CHANGE_FAILED, /* NT4 */ + "ChangeDisplaySettingsExA returned unexpected %d\n", res); memset(&dmW, 0, sizeof(dmW)); dmW.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; @@ -171,8 +223,10 @@ static void test_ChangeDisplaySettingsEx(void) SetLastError(0xdeadbeef); res = pChangeDisplaySettingsExW(NULL, &dmW, NULL, CDS_TEST, NULL); if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - ok(res == DISP_CHANGE_FAILED, - "ChangeDisplaySettingsExW returned %d, expected DISP_CHANGE_FAILED\n", res); + ok(res == DISP_CHANGE_FAILED || + res == DISP_CHANGE_BADPARAM || /* NT4 */ + res == DISP_CHANGE_BADMODE /* XP SP3 */, + "ChangeDisplaySettingsExW returned %d\n", res); memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); @@ -184,10 +238,11 @@ static void test_ChangeDisplaySettingsEx(void) dm.dmBitsPerPel = vid_modes_test[i].bpp; dm.dmDisplayFrequency = vid_modes_test[i].freq; dm.dmFields = vid_modes_test[i].fields; - res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_FULLSCREEN, NULL); - ok(vid_modes_test[i].success ? - (res == DISP_CHANGE_SUCCESSFUL) : - (res == DISP_CHANGE_BADMODE || res == DISP_CHANGE_BADPARAM), + res = pChangeDisplaySettingsExA(NULL, &dm, NULL, CDS_TEST, NULL); + ok(vid_modes_test[i].must_succeed ? + (res == DISP_CHANGE_SUCCESSFUL || res == DISP_CHANGE_RESTART) : + (res == DISP_CHANGE_SUCCESSFUL || res == DISP_CHANGE_RESTART || + res == DISP_CHANGE_BADMODE || res == DISP_CHANGE_BADPARAM), "Unexpected ChangeDisplaySettingsEx() return code for resolution[%d]: %d\n", i, res); if (res == DISP_CHANGE_SUCCESSFUL) @@ -195,13 +250,15 @@ static void test_ChangeDisplaySettingsEx(void) RECT r, r1, virt; SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)); + if (IsRectEmpty(&virt)) /* NT4 doesn't have SM_CX/YVIRTUALSCREEN */ + SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); OffsetRect(&virt, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN)); /* Resolution change resets clip rect */ ok(GetClipCursor(&r), "GetClipCursor() failed\n"); ok(EqualRect(&r, &virt), "Invalid clip rect: (%d %d) x (%d %d)\n", r.left, r.top, r.right, r.bottom); - ok(ClipCursor(NULL), "ClipCursor() failed\n"); + if (!ClipCursor(NULL)) continue; ok(GetClipCursor(&r), "GetClipCursor() failed\n"); ok(EqualRect(&r, &virt), "Invalid clip rect: (%d %d) x (%d %d)\n", r.left, r.top, r.right, r.bottom); @@ -214,7 +271,10 @@ static void test_ChangeDisplaySettingsEx(void) SetRect(&r1, virt.left - 10, virt.top - 10, virt.right + 20, virt.bottom + 20); ok(ClipCursor(&r1), "ClipCursor() failed\n"); ok(GetClipCursor(&r), "GetClipCursor() failed\n"); - ok(EqualRect(&r, &virt), "Invalid clip rect: (%d %d) x (%d %d)\n", r.left, r.top, r.right, r.bottom); + ok(EqualRect(&r, &virt) || + broken(EqualRect(&r, &r1)) /* win9x */, + "Invalid clip rect: (%d %d) x (%d %d)\n", r.left, r.top, r.right, r.bottom); + ClipCursor(&virt); } } res = pChangeDisplaySettingsExA(NULL, NULL, NULL, CDS_RESET, NULL); @@ -226,6 +286,12 @@ static void test_monitors(void) HMONITOR monitor, primary; POINT pt; + if (!pMonitorFromPoint || !pMonitorFromWindow) + { + win_skip("MonitorFromPoint or MonitorFromWindow are not available\n"); + return; + } + pt.x = pt.y = 0; primary = pMonitorFromPoint( pt, MONITOR_DEFAULTTOPRIMARY ); ok( primary != 0, "couldn't get primary monitor\n" ); @@ -238,15 +304,97 @@ static void test_monitors(void) ok( monitor == primary, "got %p, should get primary %p for MONITOR_DEFAULTTONEAREST\n", monitor, primary ); } +static BOOL CALLBACK find_primary_mon(HMONITOR hmon, HDC hdc, LPRECT rc, LPARAM lp) +{ + MONITORINFO mi; + BOOL ret; + + mi.cbSize = sizeof(mi); + ret = pGetMonitorInfoA(hmon, &mi); + ok(ret, "GetMonitorInfo failed\n"); + if (mi.dwFlags & MONITORINFOF_PRIMARY) + { + *(HMONITOR *)lp = hmon; + return FALSE; + } + return TRUE; +} + +static void test_work_area(void) +{ + HMONITOR hmon; + MONITORINFO mi; + RECT rc_work, rc_normal; + HWND hwnd; + WINDOWPLACEMENT wp; + BOOL ret; + + if (!pEnumDisplayMonitors || !pGetMonitorInfoA) + { + win_skip("EnumDisplayMonitors or GetMonitorInfoA are not available\n"); + return; + } + + hmon = 0; + ret = pEnumDisplayMonitors(NULL, NULL, find_primary_mon, (LPARAM)&hmon); + ok(!ret && hmon != 0, "Failed to find primary monitor\n"); + + mi.cbSize = sizeof(mi); + SetLastError(0xdeadbeef); + ret = pGetMonitorInfoA(hmon, &mi); + ok(ret, "GetMonitorInfo error %u\n", GetLastError()); + ok(mi.dwFlags & MONITORINFOF_PRIMARY, "not a primary monitor\n"); + trace("primary monitor (%d,%d-%d,%d)\n", + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom); + + SetLastError(0xdeadbeef); + ret = SystemParametersInfo(SPI_GETWORKAREA, 0, &rc_work, 0); + ok(ret, "SystemParametersInfo error %u\n", GetLastError()); + trace("work area (%d,%d-%d,%d)\n", rc_work.left, rc_work.top, rc_work.right, rc_work.bottom); + ok(EqualRect(&rc_work, &mi.rcWork), "work area is different\n"); + + hwnd = CreateWindowEx(0, "static", NULL, WS_OVERLAPPEDWINDOW|WS_VISIBLE,100,100,10,10,0,0,0,NULL); + ok(hwnd != 0, "CreateWindowEx failed\n"); + + ret = GetWindowRect(hwnd, &rc_normal); + ok(ret, "GetWindowRect failed\n"); + trace("normal (%d,%d-%d,%d)\n", rc_normal.left, rc_normal.top, rc_normal.right, rc_normal.bottom); + + wp.length = sizeof(wp); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "GetWindowPlacement failed\n"); + trace("min: %d,%d max %d,%d normal %d,%d-%d,%d\n", + wp.ptMinPosition.x, wp.ptMinPosition.y, + wp.ptMaxPosition.x, wp.ptMaxPosition.y, + wp.rcNormalPosition.left, wp.rcNormalPosition.top, + wp.rcNormalPosition.right, wp.rcNormalPosition.bottom); + OffsetRect(&wp.rcNormalPosition, rc_work.left, rc_work.top); + if (mi.rcMonitor.left != mi.rcWork.left || + mi.rcMonitor.top != mi.rcWork.top) /* FIXME: remove once Wine is fixed */ + todo_wine ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n"); + else + ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n"); + + SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW); + + wp.length = sizeof(wp); + ret = GetWindowPlacement(hwnd, &wp); + ok(ret, "GetWindowPlacement failed\n"); + trace("min: %d,%d max %d,%d normal %d,%d-%d,%d\n", + wp.ptMinPosition.x, wp.ptMinPosition.y, + wp.ptMaxPosition.x, wp.ptMaxPosition.y, + wp.rcNormalPosition.left, wp.rcNormalPosition.top, + wp.rcNormalPosition.right, wp.rcNormalPosition.bottom); + ok(EqualRect(&rc_normal, &wp.rcNormalPosition), "normal pos is different\n"); + + DestroyWindow(hwnd); +} START_TEST(monitor) { init_function_pointers(); test_enumdisplaydevices(); - if (winetest_interactive) test_ChangeDisplaySettingsEx(); - if (pMonitorFromPoint && pMonitorFromWindow) test_monitors(); - else - skip("MonitorFromPoint and/or MonitorFromWindow are not available\n"); + test_work_area(); } diff --git a/rostests/winetests/user32/msg.c b/rostests/winetests/user32/msg.c index 1b110311c0f..4f62457d099 100755 --- a/rostests/winetests/user32/msg.c +++ b/rostests/winetests/user32/msg.c @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define _WIN32_WINNT 0x0501 /* For WM_CHANGEUISTATE,QS_RAWINPUT */ + #include #include #include @@ -27,7 +29,6 @@ #include "windef.h" #include "winbase.h" #include "wingdi.h" -#include "wine/winuser.h" #include "winuser.h" #include "winnls.h" @@ -77,8 +78,8 @@ typedef struct static BOOL test_DestroyWindow_flag; static HWINEVENTHOOK hEvent_hook; - -static void dump_winpos_flags(UINT flags); +static HHOOK hCBT_hook; +static DWORD cbt_hook_thread_id; static const WCHAR testWindowClassW[] = { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 }; @@ -111,6 +112,19 @@ struct message { msg_flags_t flags; /* message props */ WPARAM wParam; /* expected value of wParam */ LPARAM lParam; /* expected value of lParam */ + WPARAM wp_mask; /* mask for wParam checks */ + LPARAM lp_mask; /* mask for lParam checks */ +}; + +struct recvd_message { + UINT message; /* the WM_* code */ + msg_flags_t flags; /* message props */ + HWND hwnd; /* window that received the message */ + WPARAM wParam; /* expected value of wParam */ + LPARAM lParam; /* expected value of lParam */ + int line; /* source line where logged */ + const char *descr; /* description for trace output */ + char output[512]; /* trace output */ }; /* Empty message sequence */ @@ -142,6 +156,8 @@ static const struct message WmSWP_ShowOverlappedSeq[] = { { WM_ERASEBKGND, sent|optional }, { HCBT_ACTIVATE, hook }, { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, + { WM_NOTIFYFORMAT, sent|optional }, + { WM_QUERYUISTATE, sent|optional }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */ { WM_ACTIVATEAPP, sent|wparam, 1 }, @@ -153,15 +169,23 @@ static const struct message WmSWP_ShowOverlappedSeq[] = { { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, /* Win9x adds SWP_NOZORDER below */ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_GETTEXT, sent|optional }, { WM_NCCALCSIZE, sent|wparam|optional, 1 }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SYNCPAINT, sent|optional }, + { WM_GETTITLEBARINFOEX, sent|optional }, + { WM_PAINT, sent|optional }, + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE) @@ -170,6 +194,11 @@ static const struct message WmSWP_ShowOverlappedSeq[] = { static const struct message WmSWP_HideOverlappedSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, + { HCBT_ACTIVATE, hook|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, + { WM_NCACTIVATE, sent|optional }, + { WM_ACTIVATE, sent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; @@ -180,12 +209,12 @@ static const struct message WmSWP_HideOverlappedSeq[] = { static const struct message WmSWP_ResizeSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE }, { WM_GETMINMAXINFO, sent|defwinproc }, - { WM_NCCALCSIZE, sent|wparam, TRUE }, + { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE }, + { WM_SIZE, sent|defwinproc|optional }, { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, @@ -201,12 +230,12 @@ static const struct message WmSWP_ResizeSeq[] = { static const struct message WmSWP_ResizePopupSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE }, { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */ - { WM_NCCALCSIZE, sent|wparam, TRUE }, + { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE }, + { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED }, { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, @@ -220,6 +249,9 @@ static const struct message WmSWP_ResizePopupSeq[] = { */ static const struct message WmSWP_MoveSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE }, + { WM_NCPAINT, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE }, { WM_MOVE, sent|defwinproc|wparam, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, @@ -230,14 +262,16 @@ static const struct message WmSWP_MoveSeq[] = { * SWP_NOZORDER is stripped by the logging code */ static const struct message WmSWP_ResizeNoZOrder[] = { - { WM_WINDOWPOSCHANGING, sent|wparam, 0/*SWP_NOZORDER*/ }, + { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE }, { WM_GETMINMAXINFO, sent|defwinproc }, - { WM_NCCALCSIZE, sent|wparam, 1 }, - { WM_NCPAINT, sent }, + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, + { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, - { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */ - { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOMOVE|SWP_NOCLIENTMOVE }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0, + SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE }, + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|defwinproc|optional }, { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */ { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */ { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */ @@ -315,12 +349,12 @@ static const struct message WmSwitchNotMaximizedChild[] = { /* Activate 2nd MDI child */ { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */ { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */ - { WM_SETVISIBLE, hook }, /* in the 1st MDI child */ + { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */ { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */ { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */ { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */ { WM_SETFOCUS, sent, 0 }, /* in the MDI client */ - { WM_SETVISIBLE, hook }, + { HCBT_SETFOCUS, hook }, { WM_KILLFOCUS, sent }, /* in the MDI client */ { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */ { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */ @@ -338,7 +372,7 @@ static const struct message WmSwitchNotMaximizedChild[] = { static const struct message WmSWP_FrameChanged_clip[] = { { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED }, { WM_NCCALCSIZE, sent|wparam|parent, 1 }, - { WM_NCPAINT, sent|parent }, /* wparam != 1 */ + { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */ { WM_GETTEXT, sent|parent|defwinproc|optional }, { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */ { WM_NCPAINT, sent }, /* wparam != 1 */ @@ -357,12 +391,12 @@ static const struct message WmSWP_FrameChangedDeferErase[] = { { WM_NCCALCSIZE, sent|wparam|parent, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, - { WM_PAINT, sent|parent }, - { WM_NCPAINT, sent|beginpaint|parent }, /* wparam != 1 */ + { WM_PAINT, sent|parent|optional }, + { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */ { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional }, { WM_PAINT, sent }, { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */ - { WM_ERASEBKGND, sent|beginpaint }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; @@ -373,14 +407,14 @@ static const struct message WmSWP_FrameChangedDeferErase[] = { static const struct message WmSWP_FrameChanged_noclip[] = { { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED }, { WM_NCCALCSIZE, sent|wparam|parent, 1 }, - { WM_NCPAINT, sent|parent }, /* wparam != 1 */ + { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */ { WM_GETTEXT, sent|parent|defwinproc|optional }, - { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */ + { WM_ERASEBKGND, sent|parent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { WM_PAINT, sent }, { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */ - { WM_ERASEBKGND, sent|beginpaint }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; @@ -396,7 +430,7 @@ static const struct message WmShowOverlappedSeq[] = { { HCBT_ACTIVATE, hook }, { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ACTIVATEAPP, sent|wparam, 1 }, { WM_NCACTIVATE, sent|wparam, 1 }, @@ -407,14 +441,17 @@ static const struct message WmShowOverlappedSeq[] = { { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, /* Win9x adds SWP_NOZORDER below */ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_NCCALCSIZE, sent|optional }, + { WM_GETTEXT, sent|optional }, { WM_NCPAINT, sent|optional }, { WM_ERASEBKGND, sent|optional }, + { WM_SYNCPAINT, sent|optional }, #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE * messages. Does that mean that CreateWindow doesn't set initial * window dimensions for overlapped windows? @@ -422,6 +459,8 @@ static const struct message WmShowOverlappedSeq[] = { { WM_SIZE, sent }, { WM_MOVE, sent }, #endif + { WM_PAINT, sent|optional }, + { WM_NCPAINT, sent|beginpaint|optional }, { 0 } }; /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */ @@ -435,7 +474,7 @@ static const struct message WmShowMaxOverlappedSeq[] = { { HCBT_ACTIVATE, hook }, { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_ACTIVATEAPP, sent|wparam, 1 }, { WM_NCACTIVATE, sent|wparam, 1 }, { WM_GETTEXT, sent|defwinproc|optional }, @@ -445,6 +484,7 @@ static const struct message WmShowMaxOverlappedSeq[] = { { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, @@ -452,11 +492,76 @@ static const struct message WmShowMaxOverlappedSeq[] = { { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, + { WM_GETTEXT, sent|optional }, { WM_NCCALCSIZE, sent|optional }, { WM_NCPAINT, sent|optional }, { WM_ERASEBKGND, sent|optional }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_SYNCPAINT, sent|optional }, + { WM_GETTITLEBARINFOEX, sent|optional }, + { WM_PAINT, sent|optional }, + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, + { 0 } +}; +/* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */ +static const struct message WmShowRestoreMaxOverlappedSeq[] = { + { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam, TRUE }, + { WM_NCPAINT, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, + { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, + { WM_NCPAINT, sent|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_PAINT, sent|optional }, + { WM_GETTITLEBARINFOEX, sent|optional }, + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, + { 0 } +}; +/* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */ +static const struct message WmShowRestoreMinOverlappedSeq[] = { + { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE }, + { WM_QUERYOPEN, sent|optional }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS }, + { WM_GETMINMAXINFO, sent|defwinproc }, + { WM_NCCALCSIZE, sent|wparam, TRUE }, + { HCBT_ACTIVATE, hook }, + { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_ACTIVATEAPP, sent|wparam, 1 }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam, 1 }, + { HCBT_SETFOCUS, hook }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, + { WM_NCPAINT, sent|wparam|optional, 1 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS }, + { WM_MOVE, sent|defwinproc }, + { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, + { WM_NCCALCSIZE, sent|wparam|optional, TRUE }, + { WM_NCPAINT, sent|wparam|optional, 1 }, + { WM_ERASEBKGND, sent|optional }, + { WM_ACTIVATE, sent|wparam, 1 }, + { WM_GETTEXT, sent|optional }, + { WM_PAINT, sent|optional }, + { WM_GETTITLEBARINFOEX, sent|optional }, + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */ @@ -472,11 +577,11 @@ static const struct message WmShowMinOverlappedSeq[] = { { WM_GETMINMAXINFO, sent|defwinproc }, { WM_NCCALCSIZE, sent|wparam, TRUE }, { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, - { WM_NCPAINT, sent }, + { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_WINDOWPOSCHANGED, sent }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED }, + { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 }, { WM_NCCALCSIZE, sent|optional }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, @@ -485,6 +590,37 @@ static const struct message WmShowMinOverlappedSeq[] = { { WM_GETTEXT, sent|defwinproc|optional }, { WM_ACTIVATE, sent }, { WM_ACTIVATEAPP, sent|wparam, 0 }, + + /* Vista sometimes restores the window right away... */ + { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE }, + { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE }, + { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE }, + { WM_QUERYOPEN, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|optional|defwinproc }, + { WM_NCCALCSIZE, sent|optional|wparam, TRUE }, + { HCBT_ACTIVATE, hook|optional }, + { WM_ACTIVATEAPP, sent|optional|wparam, 1 }, + { WM_NCACTIVATE, sent|optional }, + { WM_GETTEXT, sent|optional }, + { WM_ACTIVATE, sent|optional|wparam, 1 }, + { HCBT_SETFOCUS, hook|optional }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { WM_SETFOCUS, sent|optional }, + { WM_NCPAINT, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED }, + { WM_ACTIVATE, sent|optional|wparam, 1 }, + { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE }, + { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE }, + + { WM_PAINT, sent|optional }, + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; /* ShowWindow(SW_HIDE) for a visible overlapped window */ @@ -511,10 +647,10 @@ static const struct message WmDestroyOverlappedSeq[] = { { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { 0x0090, sent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { WM_NCACTIVATE, sent|wparam, 0 }, - { WM_ACTIVATE, sent|wparam, 0 }, - { WM_ACTIVATEAPP, sent|wparam, 0 }, - { WM_KILLFOCUS, sent|wparam, 0 }, + { WM_NCACTIVATE, sent|optional|wparam, 0 }, + { WM_ACTIVATE, sent|optional }, + { WM_ACTIVATEAPP, sent|optional|wparam, 0 }, + { WM_KILLFOCUS, sent|optional|wparam, 0 }, { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 }, { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, @@ -546,17 +682,23 @@ static const struct message WmCreateMaxPopupSeq[] = { { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCPAINT, sent|wparam|optional, 1 }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE }, { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent|wparam, 1 }, { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, { WM_SYNCPAINT, sent|wparam|optional, 4 }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, + { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 }, + { WM_ERASEBKGND, sent|defwinproc|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE }, { 0 } }; @@ -590,17 +732,21 @@ static const struct message WmShowMaxPopupResizedSeq[] = { { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCPAINT, sent|wparam|optional, 1 }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent|wparam, 1 }, { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent }, /* WinNT4.0 sends WM_MOVE */ { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, @@ -619,16 +765,19 @@ static const struct message WmShowMaxPopupSeq[] = { { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent|wparam, 1 }, { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, { WM_SYNCPAINT, sent|wparam|optional, 4 }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, + { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 }, + { WM_ERASEBKGND, sent|defwinproc|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } @@ -651,14 +800,16 @@ static const struct message WmCreatePopupSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_ACTIVATEAPP, sent|wparam, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent|wparam, 1 }, { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, { WM_SYNCPAINT, sent|wparam|optional, 4 }, { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_ERASEBKGND, sent|optional }, @@ -671,6 +822,7 @@ static const struct message WmShowVisMaxPopupSeq[] = { { WM_GETMINMAXINFO, sent }, { WM_GETTEXT, sent|optional }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, + { WM_GETTEXT, sent|optional }, { WM_NCCALCSIZE, sent|wparam, TRUE }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_NCPAINT, sent|wparam|optional, 1 }, @@ -711,19 +863,19 @@ static const struct message WmCreateInvisiblePopupSeq[] = { * for a popup window with WS_VISIBLE style set */ static const struct message WmShowVisiblePopupSeq_2[] = { - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { 0 } }; /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE) * for a popup window with WS_VISIBLE style set */ static const struct message WmShowVisiblePopupSeq_3[] = { - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { HCBT_ACTIVATE, hook }, { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, 0 }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent|wparam, 1 }, { HCBT_SETFOCUS, hook }, { WM_KILLFOCUS, sent|parent }, @@ -732,6 +884,8 @@ static const struct message WmShowVisiblePopupSeq_3[] = { { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, + { WM_GETTEXT, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW }, { 0 } }; /* CreateWindow (for child window, not initially visible) */ @@ -810,7 +964,7 @@ static const struct message WmHideChildSeq2[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, - { WM_ERASEBKGND, sent|parent }, + { WM_ERASEBKGND, sent|parent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; @@ -844,12 +998,13 @@ static const struct message WmShowChildSeq_4[] = { /* ShowWindow(SW_MINIMIZE) for child with invisible parent */ static const struct message WmShowChildInvisibleParentSeq_1[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_CHILDACTIVATE, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED }, + { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* FIXME: Wine creates an icon/title window while Windows doesn't */ @@ -889,7 +1044,7 @@ static const struct message WmShowChildInvisibleParentSeq_3[] = { { WM_CHILDACTIVATE, sent }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED }, + { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* FIXME: Wine creates an icon/title window while Windows doesn't */ @@ -910,7 +1065,7 @@ static const struct message WmShowChildInvisibleParentSeq_4[] = { { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED }, + { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* FIXME: Wine creates an icon/title window while Windows doesn't */ @@ -970,6 +1125,13 @@ static const struct message WmDestroyChildSeq[] = { { WM_NCDESTROY, sent }, { 0 } }; +/* visible child window destroyed by thread exit */ +static const struct message WmExitThreadSeq[] = { + { WM_NCDESTROY, sent }, /* actually in grandchild */ + { WM_PAINT, sent|parent }, + { WM_ERASEBKGND, sent|parent|beginpaint }, + { 0 } +}; /* DestroyWindow for a visible child window with invisible parent */ static const struct message WmDestroyInvisibleChildSeq[] = { { HCBT_DESTROYWND, hook }, @@ -1082,6 +1244,12 @@ static const struct message WmCreateCustomDialogSeq[] = { { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, { WM_CREATE, sent }, { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_NOTIFYFORMAT, sent|optional }, + { WM_QUERYUISTATE, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_GETMINMAXINFO, sent|optional }, + { WM_NCCALCSIZE, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, @@ -1091,13 +1259,15 @@ static const struct message WmCreateCustomDialogSeq[] = { { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, + { WM_GETTEXT, sent|optional|defwinproc }, { WM_GETTEXT, sent|optional|defwinproc }, { WM_GETTEXT, sent|optional|defwinproc }, { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_ACTIVATE, sent|wparam, 1 }, + { WM_GETTEXT, sent|optional }, { WM_KILLFOCUS, sent|parent }, { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, @@ -1109,7 +1279,7 @@ static const struct message WmCreateCustomDialogSeq[] = { { WM_GETTEXT, sent|optional|defwinproc }, { WM_GETTEXT, sent|optional|defwinproc }, { WM_ERASEBKGND, sent }, - { WM_CTLCOLORDLG, sent|defwinproc }, + { WM_CTLCOLORDLG, sent|optional|defwinproc }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_GETTEXT, sent|optional }, { WM_GETTEXT, sent|optional }, @@ -1137,6 +1307,9 @@ static const struct message WmEndCustomDialogSeq[] = { { WM_ACTIVATE, sent|wparam, 0 }, { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_GETTEXT, sent|optional|defwinproc }, + { WM_GETTEXT, sent|optional|defwinproc }, { HCBT_SETFOCUS, hook }, { WM_KILLFOCUS, sent }, { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, @@ -1156,10 +1329,11 @@ static const struct message WmShowCustomDialogSeq[] = { { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, { WM_ACTIVATE, sent|wparam, 1 }, + { WM_GETTEXT, sent|optional }, { WM_KILLFOCUS, sent|parent }, { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 }, @@ -1195,15 +1369,15 @@ static const struct message WmModalDialogSeq[] = { { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, { WM_GETTEXT, sent|optional }, { WM_ACTIVATE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, - { WM_NCPAINT, sent }, + { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|optional }, - { WM_ERASEBKGND, sent }, - { WM_CTLCOLORDLG, sent }, + { WM_ERASEBKGND, sent|optional }, + { WM_CTLCOLORDLG, sent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_GETTEXT, sent|optional }, { WM_NCCALCSIZE, sent|optional }, @@ -1213,7 +1387,8 @@ static const struct message WmModalDialogSeq[] = { { WM_CTLCOLORDLG, sent|optional }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { WM_PAINT, sent|optional }, - { WM_CTLCOLORBTN, sent }, + { WM_CTLCOLORBTN, sent|optional }, + { WM_GETTITLEBARINFOEX, sent|optional }, { WM_ENTERIDLE, sent|parent|optional }, { WM_ENTERIDLE, sent|parent|optional }, { WM_ENTERIDLE, sent|parent|optional }, @@ -1247,6 +1422,7 @@ static const struct message WmModalDialogSeq[] = { { WM_ACTIVATE, sent|wparam, 0 }, { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, { HCBT_SETFOCUS, hook }, { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, @@ -1317,7 +1493,7 @@ static const struct message WmSetMenuVisibleSizeChangeSeq[] = { { WM_NCCALCSIZE, sent|wparam, 1 }, { 0x0093, sent|defwinproc|optional }, { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, - { WM_NCPAINT, sent }, /* wparam != 1 */ + { WM_NCPAINT, sent|optional }, /* wparam != 1 */ { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|defwinproc|optional }, { 0x0091, sent|defwinproc|optional }, @@ -1345,7 +1521,7 @@ static const struct message WmSetMenuVisibleSizeChangeSeq[] = { static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, - { WM_NCPAINT, sent }, /* wparam != 1 */ + { WM_NCPAINT, sent|optional }, /* wparam != 1 */ { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, { WM_ACTIVATE, sent|optional }, @@ -1359,7 +1535,7 @@ static const struct message WmDrawMenuBarSeq[] = { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, { 0x0093, sent|defwinproc|optional }, - { WM_NCPAINT, sent }, /* wparam != 1 */ + { WM_NCPAINT, sent|optional }, /* wparam != 1 */ { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|defwinproc|optional }, { 0x0091, sent|defwinproc|optional }, @@ -1388,6 +1564,8 @@ static const struct message WmEnableWindowSeq_1[] = { { WM_CANCELMODE, sent|wparam|lparam, 0, 0 }, { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { HCBT_SETFOCUS, hook|optional }, + { WM_KILLFOCUS, sent|optional }, { WM_ENABLE, sent|wparam|lparam, FALSE, 0 }, { 0 } }; @@ -1458,8 +1636,8 @@ static const struct message WmSetScrollRangeHV_NC_Seq[] = { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */ - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE }, + { WM_SIZE, sent|defwinproc|optional }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 }, { WM_GETTEXT, sent|optional }, @@ -1494,13 +1672,23 @@ static const struct message WmSHOWNAChildInvisParVis[] = { static const struct message WmSHOWNATopVisible[] = { { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, + { WM_NCPAINT, sent|wparam|optional, 1 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, { 0 } }; static const struct message WmSHOWNATopInvisible[] = { + { WM_NOTIFYFORMAT, sent|optional }, + { WM_QUERYUISTATE, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_GETMINMAXINFO, sent|optional }, + { WM_NCCALCSIZE, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, - { WM_NCPAINT, sent|wparam, 1 }, + { WM_NCPAINT, sent|wparam|optional, 1 }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, @@ -1515,12 +1703,15 @@ static const struct message WmSHOWNATopInvisible[] = { static int after_end_dialog, test_def_id; static int sequence_cnt, sequence_size; -static struct message* sequence; +static struct recvd_message* sequence; static int log_all_parent_messages; +static int paint_loop_done; /* user32 functions */ static HWND (WINAPI *pGetAncestor)(HWND,UINT); +static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO); static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG); +static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO); static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD); static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*); static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK); @@ -1539,7 +1730,9 @@ static void init_procs(void) } GET_PROC(user32, GetAncestor) + GET_PROC(user32, GetMenuInfo) GET_PROC(user32, NotifyWinEvent) + GET_PROC(user32, SetMenuInfo) GET_PROC(user32, SetWinEventHook) GET_PROC(user32, TrackMouseEvent) GET_PROC(user32, UnhookWinEvent) @@ -1549,24 +1742,154 @@ static void init_procs(void) #undef GET_PROC } -static void add_message(const struct message *msg) +static const char *get_winpos_flags(UINT flags) { + static char buffer[300]; + + buffer[0] = 0; +#define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0) + DUMP( SWP_SHOWWINDOW ); + DUMP( SWP_HIDEWINDOW ); + DUMP( SWP_NOACTIVATE ); + DUMP( SWP_FRAMECHANGED ); + DUMP( SWP_NOCOPYBITS ); + DUMP( SWP_NOOWNERZORDER ); + DUMP( SWP_NOSENDCHANGING ); + DUMP( SWP_DEFERERASE ); + DUMP( SWP_ASYNCWINDOWPOS ); + DUMP( SWP_NOZORDER ); + DUMP( SWP_NOREDRAW ); + DUMP( SWP_NOSIZE ); + DUMP( SWP_NOMOVE ); + DUMP( SWP_NOCLIENTSIZE ); + DUMP( SWP_NOCLIENTMOVE ); + if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags); + return buffer + 1; +#undef DUMP +} + +static BOOL ignore_message( UINT message ) +{ + /* these are always ignored */ + return (message >= 0xc000 || + message == WM_GETICON || + message == WM_GETOBJECT || + message == WM_TIMECHANGE || + message == WM_DISPLAYCHANGE || + message == WM_DEVICECHANGE); +} + + +#define add_message(msg) add_message_(__LINE__,msg); +static void add_message_(int line, const struct recvd_message *msg) +{ + struct recvd_message *seq; + if (!sequence) { sequence_size = 10; - sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) ); + sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) ); } if (sequence_cnt == sequence_size) { sequence_size *= 2; - sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) ); + sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) ); } assert(sequence); - sequence[sequence_cnt].message = msg->message; - sequence[sequence_cnt].flags = msg->flags; - sequence[sequence_cnt].wParam = msg->wParam; - sequence[sequence_cnt].lParam = msg->lParam; + seq = &sequence[sequence_cnt]; + seq->hwnd = msg->hwnd; + seq->message = msg->message; + seq->flags = msg->flags; + seq->wParam = msg->wParam; + seq->lParam = msg->lParam; + seq->line = line; + seq->descr = msg->descr; + seq->output[0] = 0; + + if (msg->descr) + { + if (msg->flags & hook) + { + static const char * const CBT_code_name[10] = + { + "HCBT_MOVESIZE", + "HCBT_MINMAX", + "HCBT_QS", + "HCBT_CREATEWND", + "HCBT_DESTROYWND", + "HCBT_ACTIVATE", + "HCBT_CLICKSKIPPED", + "HCBT_KEYSKIPPED", + "HCBT_SYSCOMMAND", + "HCBT_SETFOCUS" + }; + const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown"; + + sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx", + msg->descr, msg->message, code_name, msg->wParam, msg->lParam ); + } + else if (msg->flags & winevent_hook) + { + sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx", + msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam ); + } + else + { + switch (msg->message) + { + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam; + + sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s", + msg->descr, msg->hwnd, + (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED", + msg->wParam, msg->lParam, winpos->hwndInsertAfter, + winpos->x, winpos->y, winpos->cx, winpos->cy, + get_winpos_flags(winpos->flags) ); + + /* Log only documented flags, win2k uses 0x1000 and 0x2000 + * in the high word for internal purposes + */ + seq->wParam = winpos->flags & 0xffff; + /* We are not interested in the flags that don't match under XP and Win9x */ + seq->wParam &= ~SWP_NOZORDER; + break; + } + + case WM_DRAWITEM: + { + DRAW_ITEM_STRUCT di; + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam; + + sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x", + msg->descr, msg->hwnd, dis->CtlType, dis->CtlID, + dis->itemID, dis->itemAction, dis->itemState); + + di.u.lp = 0; + di.u.item.type = dis->CtlType; + di.u.item.ctl_id = dis->CtlID; + if (dis->CtlType == ODT_LISTBOX || + dis->CtlType == ODT_COMBOBOX || + dis->CtlType == ODT_MENU) + di.u.item.item_id = dis->itemID; + di.u.item.action = dis->itemAction; + di.u.item.state = dis->itemState; + + seq->lParam = di.u.lp; + break; + } + default: + if (msg->message >= 0xc000) return; /* ignore registered messages */ + sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx", + msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam ); + } + if (msg->flags & (sent|posted|parent|defwinproc|beginpaint)) + sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags ); + } + } sequence_cnt++; } @@ -1576,7 +1899,7 @@ static void flush_events(void) { MSG msg; int diff = 200; - int min_timeout = 50; + int min_timeout = 100; DWORD time = GetTickCount() + diff; while (diff > 0) @@ -1584,7 +1907,6 @@ static void flush_events(void) if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break; while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg ); diff = time - GetTickCount(); - min_timeout = 10; } } @@ -1595,16 +1917,93 @@ static void flush_sequence(void) sequence_cnt = sequence_size = 0; } +static void dump_sequence(const struct message *expected, const char *context, const char *file, int line) +{ + const struct recvd_message *actual = sequence; + unsigned int count = 0; + + trace_(file, line)("Failed sequence %s:\n", context ); + while (expected->message && actual->message) + { + if (actual->output[0]) + { + if (expected->flags & hook) + { + trace_(file, line)( " %u: expected: hook %04x - actual: %s\n", + count, expected->message, actual->output ); + } + else if (expected->flags & winevent_hook) + { + trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n", + count, expected->message, actual->output ); + } + else + { + trace_(file, line)( " %u: expected: msg %04x - actual: %s\n", + count, expected->message, actual->output ); + } + } + + if (expected->message == actual->message) + { + if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && + (expected->flags & optional)) + { + /* don't match messages if their defwinproc status differs */ + expected++; + } + else + { + expected++; + actual++; + } + } + /* silently drop winevent messages if there is no support for them */ + else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook)) + expected++; + else + { + expected++; + actual++; + } + count++; + } + + /* optional trailing messages */ + while (expected->message && ((expected->flags & optional) || + ((expected->flags & winevent_hook) && !hEvent_hook))) + { + trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message ); + expected++; + count++; + } + + if (expected->message) + { + trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message ); + return; + } + + while (actual->message && actual->output[0]) + { + trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output ); + actual++; + count++; + } +} + #define ok_sequence( exp, contx, todo) \ ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__) -static void ok_sequence_(const struct message *expected, const char *context, int todo, +static void ok_sequence_(const struct message *expected_list, const char *context, int todo, const char *file, int line) { - static const struct message end_of_sequence = { 0, 0, 0, 0 }; - const struct message *actual; - int failcount = 0; + static const struct recvd_message end_of_sequence; + const struct message *expected = expected_list; + const struct recvd_message *actual; + int failcount = 0, dump = 0; + unsigned int count = 0; add_message(&end_of_sequence); @@ -1612,97 +2011,132 @@ static void ok_sequence_(const struct message *expected, const char *context, in while (expected->message && actual->message) { - trace_( file, line)("expected %04x - actual %04x\n", expected->message, actual->message); - if (expected->message == actual->message) { if (expected->flags & wparam) { - if (expected->wParam != actual->wParam && todo) + if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo) { todo_wine { failcount ++; + if (strcmp(winetest_platform, "wine")) dump++; ok_( file, line) (FALSE, - "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - context, expected->message, expected->wParam, actual->wParam); + "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", + context, count, expected->message, expected->wParam, actual->wParam); } } else - ok_( file, line) (expected->wParam == actual->wParam, - "%s: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", - context, expected->message, expected->wParam, actual->wParam); + { + ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0, + "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", + context, count, expected->message, expected->wParam, actual->wParam); + if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++; + } + } if (expected->flags & lparam) { - if (expected->lParam != actual->lParam && todo) + if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo) { todo_wine { failcount ++; + if (strcmp(winetest_platform, "wine")) dump++; ok_( file, line) (FALSE, - "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - context, expected->message, expected->lParam, actual->lParam); + "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + context, count, expected->message, expected->lParam, actual->lParam); } } else - ok_( file, line) (expected->lParam == actual->lParam, - "%s: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", - context, expected->message, expected->lParam, actual->lParam); + { + ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0, + "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + context, count, expected->message, expected->lParam, actual->lParam); + if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++; + } + } + if ((expected->flags & optional) && + ((expected->flags ^ actual->flags) & (defwinproc|parent))) + { + /* don't match optional messages if their defwinproc or parent status differs */ + expected++; + count++; + continue; } if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo) { todo_wine { failcount ++; + if (strcmp(winetest_platform, "wine")) dump++; ok_( file, line) (FALSE, - "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", - context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); + "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n", + context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); } } else + { ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc), - "%s: the msg 0x%04x should %shave been sent by DefWindowProc\n", - context, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); + "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n", + context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT "); + if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++; + } + ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint), - "%s: the msg 0x%04x should %shave been sent by BeginPaint\n", - context, expected->message, (expected->flags & beginpaint) ? "" : "NOT "); + "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n", + context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT "); + if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++; + ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)), - "%s: the msg 0x%04x should have been %s\n", - context, expected->message, (expected->flags & posted) ? "posted" : "sent"); + "%s: %u: the msg 0x%04x should have been %s\n", + context, count, expected->message, (expected->flags & posted) ? "posted" : "sent"); + if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++; + ok_( file, line) ((expected->flags & parent) == (actual->flags & parent), - "%s: the msg 0x%04x was expected in %s\n", - context, expected->message, (expected->flags & parent) ? "parent" : "child"); + "%s: %u: the msg 0x%04x was expected in %s\n", + context, count, expected->message, (expected->flags & parent) ? "parent" : "child"); + if ((expected->flags & parent) != (actual->flags & parent)) dump++; + ok_( file, line) ((expected->flags & hook) == (actual->flags & hook), - "%s: the msg 0x%04x should have been sent by a hook\n", - context, expected->message); + "%s: %u: the msg 0x%04x should have been sent by a hook\n", + context, count, expected->message); + if ((expected->flags & hook) != (actual->flags & hook)) dump++; + ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook), - "%s: the msg 0x%04x should have been sent by a winevent hook\n", - context, expected->message); + "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n", + context, count, expected->message); + if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++; + expected++; actual++; } - /* silently drop winevent messages if there is no support for them */ - else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook)) + /* silently drop hook messages if there is no support for them */ + else if ((expected->flags & optional) || + ((expected->flags & hook) && !hCBT_hook) || + ((expected->flags & winevent_hook) && !hEvent_hook)) expected++; else if (todo) { failcount++; todo_wine { - ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, expected->message, actual->message); + if (strcmp(winetest_platform, "wine")) dump++; + ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n", + context, count, expected->message, actual->message); } - flush_sequence(); - return; + goto done; } else { - ok_( file, line) (FALSE, "%s: the msg 0x%04x was expected, but got msg 0x%04x instead\n", - context, expected->message, actual->message); + ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n", + context, count, expected->message, actual->message); + dump++; expected++; actual++; } + count++; } /* skip all optional trailing messages */ while (expected->message && ((expected->flags & optional) || + ((expected->flags & hook) && !hCBT_hook) || ((expected->flags & winevent_hook) && !hEvent_hook))) expected++; @@ -1711,25 +2145,34 @@ static void ok_sequence_(const struct message *expected, const char *context, in todo_wine { if (expected->message || actual->message) { failcount++; - ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", - context, expected->message, actual->message); + if (strcmp(winetest_platform, "wine")) dump++; + ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n", + context, count, expected->message, actual->message); } } } else { if (expected->message || actual->message) - ok_( file, line) (FALSE, "%s: the msg sequence is not complete: expected %04x - actual %04x\n", - context, expected->message, actual->message); + { + dump++; + ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n", + context, count, expected->message, actual->message); + } } if( todo && !failcount) /* succeeded yet marked todo */ todo_wine { + if (!strcmp(winetest_platform, "wine")) dump++; ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context); } +done: + if (dump) dump_sequence(expected_list, context, file, line); flush_sequence(); } +#define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT)) + /******************************** MDI test **********************************/ /* CreateWindow for MDI frame window, initially visible */ @@ -1741,6 +2184,12 @@ static const struct message WmCreateMDIframeSeq[] = { { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 }, { WM_CREATE, sent }, { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, + { WM_NOTIFYFORMAT, sent|optional }, + { WM_QUERYUISTATE, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_GETMINMAXINFO, sent|optional }, + { WM_NCCALCSIZE, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, @@ -1749,7 +2198,7 @@ static const struct message WmCreateMDIframeSeq[] = { { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */ { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */ - { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_NCACTIVATE, sent }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ACTIVATE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */ @@ -1770,10 +2219,10 @@ static const struct message WmCreateMDIframeSeq[] = { static const struct message WmDestroyMDIframeSeq[] = { { HCBT_DESTROYWND, hook }, { 0x0090, sent|optional }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */ - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */ { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */ { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */ @@ -1796,26 +2245,26 @@ static const struct message WmCreateMDIclientSeq[] = { { WM_MOVE, sent }, { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */ { WM_SHOWWINDOW, sent|wparam, 1 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; /* ShowWindow(SW_SHOW) for MDI client window */ static const struct message WmShowMDIclientSeq[] = { { WM_SHOWWINDOW, sent|wparam, 1 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; /* ShowWindow(SW_HIDE) for MDI client window */ static const struct message WmHideMDIclientSeq[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */ { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */ - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; /* DestroyWindow for MDI client window, initially visible */ @@ -1824,9 +2273,9 @@ static const struct message WmDestroyMDIclientSeq[] = { { 0x0090, sent|optional }, { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */ { WM_SHOWWINDOW, sent|wparam, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_DESTROY, sent }, { WM_NCDESTROY, sent }, @@ -1919,10 +2368,10 @@ static const struct message WmDestroyMDIchildVisibleSeq[] = { { 0x0090, sent|optional }, { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */ { WM_SHOWWINDOW, sent|wparam, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { WM_ERASEBKGND, sent|parent|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* { WM_DESTROY, sent } * Win9x: message sequence terminates here. @@ -2045,23 +2494,23 @@ static const struct message WmCreateMDIchildVisibleMaxSeq1[] = { { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED }, /* Win9x: message sequence terminates here. */ - { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, - { HCBT_SETFOCUS, hook }, /* in MDI client */ + { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 }, + { HCBT_SETFOCUS, hook|optional }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */ { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { WM_SETFOCUS, sent }, /* in MDI client */ - { HCBT_SETFOCUS, hook }, - { WM_KILLFOCUS, sent }, /* in MDI client */ + { WM_SETFOCUS, sent|optional }, /* in MDI client */ + { HCBT_SETFOCUS, hook|optional }, + { WM_KILLFOCUS, sent|optional }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { WM_SETFOCUS, sent|defwinproc }, - { WM_MDIACTIVATE, sent|defwinproc }, + { WM_SETFOCUS, sent|defwinproc|optional }, + { WM_MDIACTIVATE, sent|defwinproc|optional }, /* in MDI frame */ { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, @@ -2130,7 +2579,7 @@ static const struct message WmCreateMDIchildVisibleMaxSeq2[] = { { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, { HCBT_SETFOCUS, hook }, - { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */ + { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */ { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, @@ -2261,6 +2710,9 @@ static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = { { WM_CREATE, sent }, { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 }, { WM_SIZE, sent|wparam, SIZE_RESTORED }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */ + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */ + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */ { WM_MOVE, sent }, { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE }, { WM_GETMINMAXINFO, sent }, @@ -2470,12 +2922,12 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */ /* in MDI frame */ - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, - { WM_NCCALCSIZE, sent|wparam, 1 }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|defwinproc|optional }, { 0x0093, sent|defwinproc|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */ { 0x0093, sent|optional }, @@ -2535,10 +2987,10 @@ static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = { { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */ { WM_SHOWWINDOW, sent|wparam, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { WM_ERASEBKGND, sent|parent|optional }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, { WM_DESTROY, sent }, @@ -2554,19 +3006,19 @@ static const struct message WmMaximizeMDIchildInvisibleSeq[] = { { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, - { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, - { HCBT_SETFOCUS, hook }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 }, + { HCBT_SETFOCUS, hook|optional }, { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { WM_SETFOCUS, sent }, /* in MDI client */ - { HCBT_SETFOCUS, hook }, - { WM_KILLFOCUS, sent }, /* in MDI client */ + { WM_SETFOCUS, sent|optional }, /* in MDI client */ + { HCBT_SETFOCUS, hook|optional }, + { WM_KILLFOCUS, sent|optional }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { WM_SETFOCUS, sent|defwinproc }, - { WM_MDIACTIVATE, sent|defwinproc }, + { WM_SETFOCUS, sent|optional|defwinproc }, + { WM_MDIACTIVATE, sent|optional|defwinproc }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in MDI frame */ @@ -2587,19 +3039,19 @@ static const struct message WmMaximizeMDIchildInvisibleSeq2[] = { { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, - { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, - { HCBT_SETFOCUS, hook }, + { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 }, + { HCBT_SETFOCUS, hook|optional }, { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */ { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { WM_SETFOCUS, sent }, /* in MDI client */ - { HCBT_SETFOCUS, hook }, - { WM_KILLFOCUS, sent }, /* in MDI client */ + { WM_SETFOCUS, sent|optional }, /* in MDI client */ + { HCBT_SETFOCUS, hook|optional }, + { WM_KILLFOCUS, sent|optional }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */ { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, - { WM_SETFOCUS, sent|defwinproc }, - { WM_MDIACTIVATE, sent|defwinproc }, + { WM_SETFOCUS, sent|defwinproc|optional }, + { WM_MDIACTIVATE, sent|defwinproc|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ { 0 } @@ -2734,7 +3186,7 @@ static const struct message WmMinimizeMDIchildVisibleSeq[] = { { WM_NCCALCSIZE, sent|wparam, 1 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOCLIENTSIZE|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|defwinproc|wparam, SIZE_MINIMIZED }, + { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 }, { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */ @@ -2765,7 +3217,7 @@ static WNDPROC old_mdi_client_proc; static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct message msg; + struct recvd_message msg; /* do not log painting messages */ if (message != WM_PAINT && @@ -2775,38 +3227,14 @@ static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wPara message != WM_NCHITTEST && message != WM_GETTEXT && message != WM_MDIGETACTIVE && - message != WM_GETICON && - message != WM_DEVICECHANGE) + !ignore_message( message )) { - trace("mdi client: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - switch (message) - { - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); - break; - } - } - + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "mdi client"; add_message(&msg); } @@ -2815,9 +3243,9 @@ static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wPara static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; /* do not log painting messages */ if (message != WM_PAINT && @@ -2826,33 +3254,10 @@ static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, message != WM_ERASEBKGND && message != WM_NCHITTEST && message != WM_GETTEXT && - message != WM_GETICON && - message != WM_DEVICECHANGE) + !ignore_message( message )) { - trace("mdi child: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - switch (message) { - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); - break; - } - case WM_MDIACTIVATE: { HWND active, client = GetParent(hwnd); @@ -2867,11 +3272,13 @@ static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, } } + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "mdi child"; add_message(&msg); } @@ -2884,9 +3291,9 @@ static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; /* do not log painting messages */ if (message != WM_PAINT && @@ -2895,39 +3302,15 @@ static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, message != WM_ERASEBKGND && message != WM_NCHITTEST && message != WM_GETTEXT && - message != WM_GETICON && - message != WM_DEVICECHANGE) + !ignore_message( message )) { - trace("mdi frame: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - switch (message) - { - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); - break; - } - } - + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "mdi frame"; add_message(&msg); } @@ -2948,7 +3331,7 @@ static BOOL mdi_RegisterWindowClasses(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "MDI_frame_class"; @@ -3325,7 +3708,7 @@ static void test_mdi_messages(void) 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandleA(0), NULL); assert(mdi_child2); - ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", TRUE); + ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE); ok(IsZoomed(mdi_child2), "MDI child should be maximized\n"); ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n"); ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n"); @@ -3335,7 +3718,7 @@ static void test_mdi_messages(void) */ active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed); ok(active_child == mdi_child || /* win2k */ - !active_child, /* win9x */ + !active_child || active_child == mdi_child2, /* win9x */ "wrong active MDI child %p\n", active_child); flush_sequence(); @@ -3507,6 +3890,7 @@ static void test_WM_SETREDRAW(HWND hwnd) { DWORD style = GetWindowLongA(hwnd, GWL_STYLE); + flush_events(); flush_sequence(); SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0); @@ -3525,53 +3909,34 @@ static void test_WM_SETREDRAW(HWND hwnd) /* restore original WS_VISIBLE state */ SetWindowLongA(hwnd, GWL_STYLE, style); + flush_events(); flush_sequence(); } static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct message msg; + struct recvd_message msg; - trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - /* explicitly ignore WM_GETICON message */ - if (message == WM_GETICON) return 0; + if (ignore_message( message )) return 0; switch (message) { /* ignore */ case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: + case WM_NCMOUSELEAVE: case WM_SETCURSOR: - case WM_DEVICECHANGE: return 0; case WM_NCHITTEST: return HTCLIENT; - - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); - break; } - } + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "dialog"; add_message(&msg); if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL ); @@ -3611,7 +3976,6 @@ static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min xmin = 0xdeadbeef; xmax = 0xdeadbeef; - trace("Ignore GetScrollRange error below if you are on Win9x\n"); ret = GetScrollRange(hwnd, ctl, &xmin, &xmax); ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError()); ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE); @@ -3683,6 +4047,9 @@ static void test_scroll_messages(HWND hwnd) INT min, max; BOOL ret; + flush_events(); + flush_sequence(); + min = 0xdeadbeef; max = 0xdeadbeef; ret = GetScrollRange(hwnd, SB_CTL, &min, &max); @@ -3777,14 +4144,12 @@ static void test_showwindow(void) /* ShowWindow( SW_SHOWNA) for invisible top level window */ trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n"); ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" ); - ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", TRUE); - trace("done\n"); + ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE); /* ShowWindow( SW_SHOWNA) for now visible top level window */ trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n"); ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" ); ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE); - trace("done\n"); /* back to invisible */ ShowWindow(hchild, SW_HIDE); ShowWindow(hwnd, SW_HIDE); @@ -3793,21 +4158,18 @@ static void test_showwindow(void) trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n"); ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" ); ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE); - trace("done\n"); /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */ ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" ); flush_sequence(); trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n"); ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" ); ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE); - trace("done\n"); /* ShowWindow(SW_SHOWNA) with child visible and parent visible */ ShowWindow( hwnd, SW_SHOW); flush_sequence(); trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n"); ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" ); ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE); - trace("done\n"); /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */ ShowWindow( hchild, SW_HIDE); @@ -3815,7 +4177,6 @@ static void test_showwindow(void) trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n"); ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" ); ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE); - trace("done\n"); SetCapture(hchild); ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture()); @@ -3837,7 +4198,6 @@ static void test_showwindow(void) ok (hwnd != 0, "Failed to create popup window\n"); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE); - trace("done\n"); GetWindowRect(hwnd, &rc); ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) && @@ -3853,7 +4213,6 @@ static void test_showwindow(void) ShowWindow(hwnd, SW_SHOWMAXIMIZED); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE); - trace("done\n"); GetWindowRect(hwnd, &rc); ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) && @@ -3873,13 +4232,11 @@ static void test_showwindow(void) ok (hwnd != 0, "Failed to create popup window\n"); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE); - trace("done\n"); trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n"); ShowWindow(hwnd, SW_SHOWMAXIMIZED); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE); - trace("done\n"); DestroyWindow(hwnd); flush_sequence(); @@ -3892,7 +4249,6 @@ static void test_showwindow(void) ok (hwnd != 0, "Failed to create popup window\n"); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE); - trace("done\n"); DestroyWindow(hwnd); flush_sequence(); @@ -3906,13 +4262,11 @@ static void test_showwindow(void) ok (hwnd != 0, "Failed to create popup window\n"); ok(!IsZoomed(hwnd), "window should NOT be maximized\n"); ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE); - trace("done\n"); trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n"); ShowWindow(hwnd, SW_SHOWMAXIMIZED); ok(IsZoomed(hwnd), "window should be maximized\n"); ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE); - trace("done\n"); DestroyWindow(hwnd); flush_sequence(); } @@ -4030,7 +4384,39 @@ static const struct message WmInitEndSession_4[] = { /* Sending undocumented 0x3B message with wparam = 0x80000001 */ static const struct message WmInitEndSession_5[] = { { 0x003B, sent }, - { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 1, ENDSESSION_LOGOFF }, + { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF }, + { 0 } +}; + +static const struct message WmOptionalPaint[] = { + { WM_PAINT, sent|optional }, + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_GETTEXT, sent|beginpaint|defwinproc|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, + { 0 } +}; + +static const struct message WmZOrder[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 }, + { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 }, + { HCBT_ACTIVATE, hook }, + { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 }, + { WM_GETTEXT, sent|optional }, + { WM_NCCALCSIZE, sent|wparam|optional, 1 }, + { WM_ACTIVATEAPP, sent|wparam, 1, 0 }, + { WM_NCACTIVATE, sent|lparam, 1, 0 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam|lparam, 1, 0 }, + { HCBT_SETFOCUS, hook }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { WM_SETFOCUS, sent|wparam|defwinproc, 0 }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_GETTEXT, sent|optional }, + { WM_NCCALCSIZE, sent|optional }, { 0 } }; @@ -4047,7 +4433,7 @@ static void test_MsgWaitForMultipleObjects(HWND hwnd) ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret); - ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); + ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); @@ -4058,7 +4444,7 @@ static void test_MsgWaitForMultipleObjects(HWND hwnd) ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret); - ok(PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n"); + ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */ @@ -4071,9 +4457,9 @@ static void test_MsgWaitForMultipleObjects(HWND hwnd) ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE); ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret); - ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); + ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); - ok(PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); + ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message); } @@ -4101,40 +4487,54 @@ static void test_messages(void) test_WM_SETREDRAW(hwnd); SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE); + flush_events(); ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE); ok(IsWindowVisible(hwnd), "window should be visible at this point\n"); ok(GetActiveWindow() == hwnd, "window should be active\n"); ok(GetFocus() == hwnd, "window should have input focus\n"); ShowWindow(hwnd, SW_HIDE); - ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", TRUE); + flush_events(); + ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE); ShowWindow(hwnd, SW_SHOW); + flush_events(); ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE); ShowWindow(hwnd, SW_HIDE); + flush_events(); ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE); ShowWindow(hwnd, SW_SHOWMAXIMIZED); + flush_events(); ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE); - - ShowWindow(hwnd, SW_RESTORE); - /* FIXME: add ok_sequence() here */ flush_sequence(); + if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE) + { + ShowWindow(hwnd, SW_RESTORE); + flush_events(); + ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE); + flush_sequence(); + } + ShowWindow(hwnd, SW_MINIMIZE); + flush_events(); ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE); flush_sequence(); + if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE) + { ShowWindow(hwnd, SW_RESTORE); - /* FIXME: add ok_sequence() here */ + flush_events(); + ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE); flush_sequence(); + } ShowWindow(hwnd, SW_SHOW); - ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW):overlapped already visible", FALSE); + flush_events(); + ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE); - ok(GetActiveWindow() == hwnd, "window should be active\n"); - ok(GetFocus() == hwnd, "window should have input focus\n"); SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE); ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE); ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n"); @@ -4142,6 +4542,7 @@ static void test_messages(void) /* test WM_SETREDRAW on a visible top level window */ ShowWindow(hwnd, SW_SHOW); + flush_events(); test_WM_SETREDRAW(hwnd); trace("testing scroll APIs on a visible top level window %p\n", hwnd); @@ -4156,7 +4557,7 @@ static void test_messages(void) ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE ); flush_events(); flush_sequence(); - SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER ); + SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE ); ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE ); flush_events(); flush_sequence(); @@ -4284,7 +4685,7 @@ static void test_messages(void) ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE); flush_sequence(); SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE); - ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", TRUE); + ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE); DestroyWindow(hchild); /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually @@ -4461,42 +4862,70 @@ static void test_messages(void) flush_sequence(); res = SendMessage(hwnd, 0x3B, 0x8000000b, 0); + if (!res) + { + todo_wine win_skip( "Message 0x3b not supported\n" ); + goto done; + } ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE); - todo_wine ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res); res = SendMessage(hwnd, 0x3B, 0x0000000b, 0); ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE); - todo_wine ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res); res = SendMessage(hwnd, 0x3B, 0x0000000f, 0); ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE); - todo_wine ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res); flush_sequence(); res = SendMessage(hwnd, 0x3B, 0x80000008, 0); ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE); - todo_wine ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res); res = SendMessage(hwnd, 0x3B, 0x00000008, 0); ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE); - todo_wine ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res); res = SendMessage(hwnd, 0x3B, 0x80000004, 0); ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE); - todo_wine ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res); res = SendMessage(hwnd, 0x3B, 0x80000001, 0); ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE); - todo_wine ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res); +done: DestroyWindow(hwnd); flush_sequence(); } +static void test_setwindowpos(void) +{ + HWND hwnd; + RECT rc; + LRESULT res; + const INT winX = 100; + const INT winY = 100; + const INT sysX = GetSystemMetrics(SM_CXMINTRACK); + + hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0, + 0, 0, winX, winY, 0, + NULL, NULL, 0); + + GetWindowRect(hwnd, &rc); + expect(sysX, rc.right); + expect(winY, rc.bottom); + + flush_events(); + flush_sequence(); + res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0); + ok_sequence(WmZOrder, "Z-Order", TRUE); + ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res); + + GetWindowRect(hwnd, &rc); + expect(sysX, rc.right); + expect(winY, rc.bottom); + DestroyWindow(hwnd); +} + static void invisible_parent_tests(void) { HWND hparent, hchild; @@ -4663,6 +5092,8 @@ todo_wine { } /****************** button message test *************************/ +#define ID_BUTTON 0x000e + static const struct message WmSetFocusButtonSeq[] = { { HCBT_SETFOCUS, hook }, @@ -4670,7 +5101,9 @@ static const struct message WmSetFocusButtonSeq[] = { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam, 0 }, - { WM_CTLCOLORBTN, sent|defwinproc }, + { WM_CTLCOLORBTN, sent|parent }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) }, + { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmKillFocusButtonSeq[] = @@ -4678,9 +5111,13 @@ static const struct message WmKillFocusButtonSeq[] = { HCBT_SETFOCUS, hook }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam, 0 }, - { WM_CTLCOLORBTN, sent|defwinproc }, + { WM_CTLCOLORBTN, sent|parent }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) }, { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, + { WM_APP, sent|wparam|lparam, 0, 0 }, + { WM_PAINT, sent }, + { WM_CTLCOLORBTN, sent|parent }, { 0 } }; static const struct message WmSetFocusStaticSeq[] = @@ -4690,7 +5127,10 @@ static const struct message WmSetFocusStaticSeq[] = { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|wparam, 0 }, - { WM_CTLCOLORSTATIC, sent|defwinproc }, + { WM_CTLCOLORSTATIC, sent|parent }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) }, + { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */ + { WM_APP, sent|wparam|lparam, 0, 0 }, { 0 } }; static const struct message WmKillFocusStaticSeq[] = @@ -4698,9 +5138,42 @@ static const struct message WmKillFocusStaticSeq[] = { HCBT_SETFOCUS, hook }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam, 0 }, - { WM_CTLCOLORSTATIC, sent|defwinproc }, + { WM_CTLCOLORSTATIC, sent|parent }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) }, { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, + { WM_APP, sent|wparam|lparam, 0, 0 }, + { WM_PAINT, sent }, + { WM_CTLCOLORSTATIC, sent|parent }, + { 0 } +}; +static const struct message WmSetFocusOwnerdrawSeq[] = +{ + { HCBT_SETFOCUS, hook }, + { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent|wparam, 0 }, + { WM_CTLCOLORBTN, sent|parent }, + { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) }, + { WM_APP, sent|wparam|lparam, 0, 0 }, + { 0 } +}; +static const struct message WmKillFocusOwnerdrawSeq[] = +{ + { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_KILLFOCUS, sent|wparam, 0 }, + { WM_CTLCOLORBTN, sent|parent }, + { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) }, + { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, + { WM_APP, sent|wparam|lparam, 0, 0 }, + { WM_PAINT, sent }, + { WM_CTLCOLORBTN, sent|parent }, + { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 }, { 0 } }; static const struct message WmLButtonDownSeq[] = @@ -4736,29 +5209,77 @@ static const struct message WmSetFontButtonSeq[] = { WM_CTLCOLORBTN, sent|defwinproc }, { 0 } }; +static const struct message WmSetStyleButtonSeq[] = +{ + { BM_SETSTYLE, sent }, + { WM_APP, sent|wparam|lparam, 0, 0 }, + { WM_PAINT, sent }, + { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */ + { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */ + { WM_CTLCOLORBTN, sent|parent }, + { 0 } +}; +static const struct message WmSetStyleStaticSeq[] = +{ + { BM_SETSTYLE, sent }, + { WM_APP, sent|wparam|lparam, 0, 0 }, + { WM_PAINT, sent }, + { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */ + { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */ + { WM_CTLCOLORSTATIC, sent|parent }, + { 0 } +}; +static const struct message WmSetStyleUserSeq[] = +{ + { BM_SETSTYLE, sent }, + { WM_APP, sent|wparam|lparam, 0, 0 }, + { WM_PAINT, sent }, + { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */ + { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */ + { WM_CTLCOLORBTN, sent|parent }, + { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) }, + { 0 } +}; +static const struct message WmSetStyleOwnerdrawSeq[] = +{ + { BM_SETSTYLE, sent }, + { WM_APP, sent|wparam|lparam, 0, 0 }, + { WM_PAINT, sent }, + { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */ + { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */ + { WM_CTLCOLORBTN, sent|parent }, + { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */ + { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 }, + { 0 } +}; static WNDPROC old_button_proc; static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; - trace("button: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - /* explicitly ignore WM_GETICON message */ - if (message == WM_GETICON) return 0; + if (ignore_message( message )) return 0; + switch (message) + { + case WM_SYNCPAINT: + break; + case BM_SETSTATE: + ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture()); + /* fall through */ + default: + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "button"; add_message(&msg); - - if (message == BM_SETSTATE) - ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture()); + } defwndproc_counter++; ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam); @@ -4790,67 +5311,122 @@ static void test_button_messages(void) DWORD dlg_code; const struct message *setfocus; const struct message *killfocus; + const struct message *setstyle; } button[] = { { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON, - WmSetFocusButtonSeq, WmKillFocusButtonSeq }, + WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq }, { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON, - WmSetFocusButtonSeq, WmKillFocusButtonSeq }, + WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq }, { BS_CHECKBOX, DLGC_BUTTON, - WmSetFocusStaticSeq, WmKillFocusStaticSeq }, + WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq }, { BS_AUTOCHECKBOX, DLGC_BUTTON, - WmSetFocusStaticSeq, WmKillFocusStaticSeq }, + WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq }, { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON, - WmSetFocusStaticSeq, WmKillFocusStaticSeq }, + WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq }, { BS_3STATE, DLGC_BUTTON, - WmSetFocusStaticSeq, WmKillFocusStaticSeq }, + WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq }, { BS_AUTO3STATE, DLGC_BUTTON, - WmSetFocusStaticSeq, WmKillFocusStaticSeq }, + WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq }, { BS_GROUPBOX, DLGC_STATIC, - WmSetFocusStaticSeq, WmKillFocusStaticSeq }, + WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq }, { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON, - WmSetFocusButtonSeq, WmKillFocusButtonSeq }, + WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq }, { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON, - WmSetFocusStaticSeq, WmKillFocusStaticSeq }, + WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq }, { BS_OWNERDRAW, DLGC_BUTTON, - WmSetFocusButtonSeq, WmKillFocusButtonSeq } + WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq } }; unsigned int i; - HWND hwnd; + HWND hwnd, parent; DWORD dlg_code; HFONT zfont; + /* selection with VK_SPACE should capture button window */ + hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP, + 0, 0, 50, 14, 0, 0, 0, NULL); + ok(hwnd != 0, "Failed to create button window\n"); + ReleaseCapture(); + SetFocus(hwnd); + SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0); + ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n"); + SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0); + DestroyWindow(hwnd); + subclass_button(); + parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok(parent != 0, "Failed to create parent window\n"); + for (i = 0; i < sizeof(button)/sizeof(button[0]); i++) { - hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP, - 0, 0, 50, 14, 0, 0, 0, NULL); + MSG msg; + DWORD style; + + trace("button style %08x\n", button[i].style); + + hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY, + 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL); ok(hwnd != 0, "Failed to create button window\n"); + style = GetWindowLongA(hwnd, GWL_STYLE); + style &= ~(WS_CHILD | BS_NOTIFY); + /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */ + if (button[i].style == BS_USERBUTTON) + ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style); + else + ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style); + dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0); ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); SetFocus(0); + flush_events(); flush_sequence(); - trace("button style %08x\n", button[i].style); + log_all_parent_messages++; + + ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus()); SetFocus(hwnd); + SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */ + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg); ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE); SetFocus(0); + SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */ + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg); ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE); + ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus()); + + SendMessage(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE); + SendMessage(hwnd, WM_APP, 0, 0); /* place a separator mark here */ + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg); + ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE); + + style = GetWindowLongA(hwnd, GWL_STYLE); + style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY); + /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */ + ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style); + + log_all_parent_messages--; + DestroyWindow(hwnd); } + DestroyWindow(parent); + hwnd = CreateWindowExA(0, "my_button_class", "test", BS_PUSHBUTTON | WS_POPUP | WS_VISIBLE, 0, 0, 50, 14, 0, 0, 0, NULL); ok(hwnd != 0, "Failed to create button window\n"); - SetFocus(0); + SetForegroundWindow(hwnd); flush_events(); + + SetActiveWindow(hwnd); + SetFocus(0); flush_sequence(); SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0); @@ -4860,7 +5436,7 @@ static void test_button_messages(void) ok_sequence(WmLButtonUpSeq, "WM_LBUTTONUP on a button", FALSE); flush_sequence(); - zfont = (HFONT)GetStockObject(SYSTEM_FONT); + zfont = GetStockObject(SYSTEM_FONT); SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE); UpdateWindow(hwnd); ok_sequence(WmSetFontButtonSeq, "WM_SETFONT on a button", FALSE); @@ -4872,9 +5448,9 @@ static void test_button_messages(void) static const struct message WmSetFontStaticSeq[] = { { WM_SETFONT, sent }, - { WM_PAINT, sent|defwinproc }, + { WM_PAINT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|defwinproc|optional }, - { WM_CTLCOLORSTATIC, sent|defwinproc }, + { WM_CTLCOLORSTATIC, sent|defwinproc|optional }, { 0 } }; @@ -4882,20 +5458,19 @@ static WNDPROC old_static_proc; static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; - trace("static: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - /* explicitly ignore WM_GETICON message */ - if (message == WM_GETICON) return 0; + if (ignore_message( message )) return 0; + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "static"; add_message(&msg); defwndproc_counter++; @@ -4978,9 +5553,9 @@ static WNDPROC old_combobox_proc; static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; /* do not log painting messages */ if (message != WM_PAINT && @@ -4989,16 +5564,15 @@ static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wPara message != WM_ERASEBKGND && message != WM_NCHITTEST && message != WM_GETTEXT && - message != WM_GETICON && - message != WM_DEVICECHANGE) + !ignore_message( message )) { - trace("combo: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "combo"; add_message(&msg); } @@ -5077,21 +5651,21 @@ static const struct message WmImeKeydownMsgSeq_0[] = static const struct message WmImeKeydownMsgSeq_1[] = { - { WM_KEYDOWN, wparam, VK_RETURN }, - { WM_CHAR, wparam, VK_RETURN }, + { WM_KEYDOWN, optional|wparam, VK_RETURN }, + { WM_CHAR, optional|wparam, VK_RETURN }, { 0 } }; static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct message msg; - - trace("wmime_keydown_procA: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + struct recvd_message msg; + msg.hwnd = hwnd; msg.message = message; msg.flags = wparam|lparam; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "wmime_keydown"; add_message(&msg); return DefWindowProcA(hwnd, message, wParam, lParam); @@ -5108,7 +5682,7 @@ static void register_wmime_keydown_class(void) if (!RegisterClassA(&cls)) assert(0); } -void test_wmime_keydown_message(void) +static void test_wmime_keydown_message(void) { HWND hwnd; MSG msg; @@ -5233,7 +5807,7 @@ static const struct message WmInvalidateErasePaint[] = { { WM_PAINT, sent }, { WM_NCPAINT, sent|wparam|beginpaint, 1 }, { WM_GETTEXT, sent|beginpaint|defwinproc|optional }, - { WM_ERASEBKGND, sent|beginpaint }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; @@ -5241,7 +5815,7 @@ static const struct message WmInvalidateErasePaint2[] = { { WM_PAINT, sent }, { WM_NCPAINT, sent|beginpaint }, { WM_GETTEXT, sent|beginpaint|defwinproc|optional }, - { WM_ERASEBKGND, sent|beginpaint }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; @@ -5296,7 +5870,7 @@ static const struct message WmParentPaintNc[] = { { WM_PAINT, sent }, { WM_NCPAINT, sent|beginpaint }, { WM_GETTEXT, sent|beginpaint|defwinproc|optional }, - { WM_ERASEBKGND, sent|beginpaint }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; @@ -5304,7 +5878,7 @@ static const struct message WmChildPaintNc[] = { { WM_PAINT, sent }, { WM_NCPAINT, sent|beginpaint }, { WM_GETTEXT, sent|beginpaint|defwinproc|optional }, - { WM_ERASEBKGND, sent|beginpaint }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; @@ -5312,11 +5886,11 @@ static const struct message WmParentErasePaint[] = { { WM_PAINT, sent|parent }, { WM_NCPAINT, sent|parent|beginpaint }, { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional }, - { WM_ERASEBKGND, sent|parent|beginpaint }, + { WM_ERASEBKGND, sent|parent|beginpaint|optional }, { WM_PAINT, sent }, { WM_NCPAINT, sent|beginpaint }, { WM_GETTEXT, sent|beginpaint|defwinproc|optional }, - { WM_ERASEBKGND, sent|beginpaint }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; @@ -5401,13 +5975,15 @@ static void test_paint_messages(void) */ trace("testing ValidateRect(0, NULL)\n"); SetRectEmpty( &rect ); - ok(ValidateRect(0, &rect), "ValidateRect(0, &rc) should not fail\n"); + if (ValidateRect(0, &rect)) /* not supported on Win9x */ + { check_update_rgn( hwnd, hrgn ); ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE ); flush_events(); ok_sequence( WmPaint, "Paint", FALSE ); RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE ); check_update_rgn( hwnd, 0 ); + } trace("testing InvalidateRgn(0, NULL, FALSE)\n"); SetLastError(0xdeadbeef); @@ -5421,7 +5997,9 @@ static void test_paint_messages(void) trace("testing ValidateRgn(0, NULL)\n"); SetLastError(0xdeadbeef); ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n"); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error code %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || + broken( GetLastError() == 0xdeadbeef ) /* win9x */, + "wrong error code %d\n", GetLastError()); check_update_rgn( hwnd, 0 ); flush_events(); ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); @@ -5778,10 +6356,90 @@ static void test_paint_messages(void) flush_events(); ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE ); + ok(GetWindowLong( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n"); + ok(GetWindowLong( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n"); + + UpdateWindow( hparent ); + flush_events(); + flush_sequence(); + trace("testing SetWindowPos(-10000, -10000) on child\n"); + SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER ); + check_update_rgn( hchild, 0 ); + flush_events(); + +#if 0 /* this one doesn't pass under Wine yet */ + UpdateWindow( hparent ); + flush_events(); + flush_sequence(); + trace("testing ShowWindow(SW_MINIMIZE) on child\n"); + ShowWindow( hchild, SW_MINIMIZE ); + check_update_rgn( hchild, 0 ); + flush_events(); +#endif + + UpdateWindow( hparent ); + flush_events(); + flush_sequence(); + trace("testing SetWindowPos(-10000, -10000) on parent\n"); + SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER ); + check_update_rgn( hparent, 0 ); + flush_events(); + log_all_parent_messages--; DestroyWindow( hparent ); ok(!IsWindow(hchild), "child must be destroyed with its parent\n"); + /* tests for moving windows off-screen (needs simple WS_POPUP windows) */ + + hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok (hparent != 0, "Failed to create parent window\n"); + + hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE, + 10, 10, 100, 100, hparent, 0, 0, NULL); + ok (hchild != 0, "Failed to create child window\n"); + + ShowWindow( hparent, SW_SHOW ); + UpdateWindow( hparent ); + UpdateWindow( hchild ); + flush_events(); + flush_sequence(); + + /* moving child outside of parent boundaries changes update region */ + SetRect( &rect, 0, 0, 40, 40 ); + RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE ); + SetRectRgn( hrgn, 0, 0, 40, 40 ); + check_update_rgn( hchild, hrgn ); + MoveWindow( hchild, -10, 10, 100, 100, FALSE ); + SetRectRgn( hrgn, 10, 0, 40, 40 ); + check_update_rgn( hchild, hrgn ); + MoveWindow( hchild, -10, -10, 100, 100, FALSE ); + SetRectRgn( hrgn, 10, 10, 40, 40 ); + check_update_rgn( hchild, hrgn ); + + /* moving parent off-screen does too */ + SetRect( &rect, 0, 0, 100, 100 ); + RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN ); + SetRectRgn( hrgn, 0, 0, 100, 100 ); + check_update_rgn( hparent, hrgn ); + SetRectRgn( hrgn, 10, 10, 40, 40 ); + check_update_rgn( hchild, hrgn ); + MoveWindow( hparent, -20, -20, 200, 200, FALSE ); + SetRectRgn( hrgn, 20, 20, 100, 100 ); + check_update_rgn( hparent, hrgn ); + SetRectRgn( hrgn, 30, 30, 40, 40 ); + check_update_rgn( hchild, hrgn ); + + /* invalidated region is cropped by the parent rects */ + SetRect( &rect, 0, 0, 50, 50 ); + RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE ); + SetRectRgn( hrgn, 30, 30, 50, 50 ); + check_update_rgn( hchild, hrgn ); + + DestroyWindow( hparent ); + ok(!IsWindow(hchild), "child must be destroyed with its parent\n"); + flush_sequence(); + DeleteObject( hrgn ); DeleteObject( hrgn2 ); } @@ -5789,19 +6447,21 @@ static void test_paint_messages(void) struct wnd_event { HWND hwnd; - HANDLE event; + HANDLE grand_child; + HANDLE start_event; + HANDLE stop_event; }; static DWORD WINAPI thread_proc(void *param) { MSG msg; - struct wnd_event *wnd_event = (struct wnd_event *)param; + struct wnd_event *wnd_event = param; wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n"); - SetEvent(wnd_event->event); + SetEvent(wnd_event->start_event); while (GetMessage(&msg, 0, 0, 0)) { @@ -5814,6 +6474,54 @@ static DWORD WINAPI thread_proc(void *param) return 0; } +static DWORD CALLBACK create_grand_child_thread( void *param ) +{ + struct wnd_event *wnd_event = param; + HWND hchild; + MSG msg; + + hchild = CreateWindowExA(0, "TestWindowClass", "Test child", + WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL); + ok (hchild != 0, "Failed to create child window\n"); + flush_events(); + flush_sequence(); + SetEvent( wnd_event->start_event ); + + for (;;) + { + MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT); + if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */ + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg); + } + return 0; +} + +static DWORD CALLBACK create_child_thread( void *param ) +{ + struct wnd_event *wnd_event = param; + struct wnd_event child_event; + DWORD ret, tid; + MSG msg; + + child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child", + WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL); + ok (child_event.hwnd != 0, "Failed to create child window\n"); + SetFocus( child_event.hwnd ); + flush_events(); + flush_sequence(); + child_event.start_event = wnd_event->start_event; + wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid); + for (;;) + { + DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE); + if (ret != 1) break; + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg); + } + ret = WaitForSingleObject( wnd_event->stop_event, 5000 ); + ok( !ret, "WaitForSingleObject failed %x\n", ret ); + return 0; +} + static void test_interthread_messages(void) { HANDLE hThread; @@ -5825,19 +6533,19 @@ static void test_interthread_messages(void) struct wnd_event wnd_event; BOOL ret; - wnd_event.event = CreateEventW(NULL, 0, 0, NULL); - if (!wnd_event.event) + wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL); + if (!wnd_event.start_event) { - trace("skipping interthread message test under win9x\n"); + win_skip("skipping interthread message test under win9x\n"); return; } hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid); ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError()); - ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); - CloseHandle(wnd_event.event); + CloseHandle(wnd_event.start_event); SetLastError(0xdeadbeef); ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n"); @@ -5861,7 +6569,7 @@ static void test_interthread_messages(void) memset(buf, 0, sizeof(buf)); SetLastError(0xdeadbeef); len = DispatchMessageA(&msg); - ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY, + ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */ "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %d\n", len, GetLastError()); /* the following test causes an exception in user.exe under win9x */ @@ -5881,6 +6589,38 @@ static void test_interthread_messages(void) CloseHandle(hThread); ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n"); + + wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok (wnd_event.hwnd != 0, "Failed to create parent window\n"); + flush_sequence(); + log_all_parent_messages++; + wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL ); + wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL ); + hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid ); + for (;;) + { + ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE); + if (ret != 1) break; + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessage(&msg); +} + ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret ); + /* now wait for the thread without processing messages; this shouldn't deadlock */ + SetEvent( wnd_event.stop_event ); + ret = WaitForSingleObject( hThread, 5000 ); + ok( !ret, "WaitForSingleObject failed %x\n", ret ); + CloseHandle( hThread ); + + ret = WaitForSingleObject( wnd_event.grand_child, 5000 ); + ok( !ret, "WaitForSingleObject failed %x\n", ret ); + CloseHandle( wnd_event.grand_child ); + + CloseHandle( wnd_event.start_event ); + CloseHandle( wnd_event.stop_event ); + flush_events(); + ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE); + log_all_parent_messages--; + DestroyWindow( wnd_event.hwnd ); } @@ -6002,6 +6742,8 @@ static const struct message WmCtrlAltVkN[] = { { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */ { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 }, { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 }, + { WM_CHAR, optional }, + { WM_CHAR, sent|optional }, { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */ { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 }, { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 }, @@ -6090,19 +6832,19 @@ static const struct message WmAltPressRelease[] = { { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 }, { 0 } }; -static const struct message WmAltMouseButton[] = { - { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */ - { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 }, - { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 }, +static const struct message WmShiftMouseButton[] = { + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */ + { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 }, + { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 }, { WM_MOUSEMOVE, wparam|optional, 0, 0 }, { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 }, - { WM_LBUTTONDOWN, wparam, MK_LBUTTON, 0 }, - { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON, 0 }, - { WM_LBUTTONUP, wparam, 0, 0 }, - { WM_LBUTTONUP, sent|wparam, 0, 0 }, - { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */ - { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 }, - { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 }, + { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 }, + { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 }, + { WM_LBUTTONUP, wparam, MK_SHIFT, 0 }, + { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */ + { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 }, + { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 }, { 0 } }; static const struct message WmF1Seq[] = { @@ -6128,6 +6870,36 @@ static const struct message WmVkAppsSeq[] = { { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, (LPARAM)-1 }, { 0 } }; +static const struct message WmVkF10Seq[] = { + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */ + { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 }, + { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */ + { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 }, + { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 }, + { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU }, + { HCBT_SYSCOMMAND, hook }, + { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 }, + { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, + { WM_INITMENU, sent|defwinproc }, + { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE) }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 }, + + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */ + + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, }, + { WM_CAPTURECHANGED, sent|defwinproc }, + { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, + { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 }, + { WM_EXITMENULOOP, sent|defwinproc }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */ + { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 }, + { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 }, + { 0 } +}; static void pump_msg_loop(HWND hwnd, HACCEL hAccel) { @@ -6135,20 +6907,20 @@ static void pump_msg_loop(HWND hwnd, HACCEL hAccel) while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { - struct message log_msg; - - trace("accel: %p, %04x, %08lx, %08lx\n", msg.hwnd, msg.message, msg.wParam, msg.lParam); + struct recvd_message log_msg; /* ignore some unwanted messages */ if (msg.message == WM_MOUSEMOVE || - msg.message == WM_GETICON || - msg.message == WM_DEVICECHANGE) + msg.message == WM_TIMER || + ignore_message( msg.message )) continue; + log_msg.hwnd = msg.hwnd; log_msg.message = msg.message; log_msg.flags = wparam|lparam; log_msg.wParam = msg.wParam; log_msg.lParam = msg.lParam; + log_msg.descr = "accel"; add_message(&log_msg); if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg)) @@ -6162,6 +6934,7 @@ static void pump_msg_loop(HWND hwnd, HACCEL hAccel) static void test_accelerators(void) { RECT rc; + POINT pt; SHORT state; HACCEL hAccel; HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, @@ -6184,6 +6957,7 @@ static void test_accelerators(void) hAccel = LoadAccelerators(GetModuleHandleA(0), MAKEINTRESOURCE(1)); assert(hAccel != 0); + flush_events(); pump_msg_loop(hwnd, 0); flush_sequence(); @@ -6192,6 +6966,11 @@ static void test_accelerators(void) keybd_event('N', 0, 0, 0); keybd_event('N', 0, KEYEVENTF_KEYUP, 0); pump_msg_loop(hwnd, hAccel); + if (!sequence_cnt) /* we didn't get any message */ + { + skip( "queuing key events not supported\n" ); + goto done; + } ok_sequence(WmVkN, "VK_N press/release", FALSE); trace("testing Shift+VK_N press/release\n"); @@ -6309,6 +7088,7 @@ static void test_accelerators(void) ret = DestroyAcceleratorTable(hAccel); ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError()); + hAccel = 0; trace("testing Alt press/release\n"); flush_sequence(); @@ -6320,23 +7100,6 @@ static void test_accelerators(void) /* this test doesn't pass in Wine for managed windows */ ok_sequence(WmAltPressRelease, "Alt press/release", TRUE); - trace("testing Alt+MouseButton press/release\n"); - /* first, move mouse pointer inside of the window client area */ - GetClientRect(hwnd, &rc); - MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2); - rc.left += (rc.right - rc.left)/2; - rc.top += (rc.bottom - rc.top)/2; - SetCursorPos(rc.left, rc.top); - - flush_events(); - flush_sequence(); - keybd_event(VK_MENU, 0, 0, 0); - mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); - mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); - keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0); - pump_msg_loop(hwnd, 0); - ok_sequence(WmAltMouseButton, "Alt+MouseButton press/release", FALSE); - trace("testing VK_F1 press/release\n"); keybd_event(VK_F1, 0, 0, 0); keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0); @@ -6349,6 +7112,43 @@ static void test_accelerators(void) pump_msg_loop(hwnd, 0); ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE); + trace("testing VK_F10 press/release\n"); + keybd_event(VK_F10, 0, 0, 0); + keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_F10, 0, 0, 0); + keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0); + pump_msg_loop(hwnd, 0); + ok_sequence(WmVkF10Seq, "VK_F10 press/release", TRUE); + + trace("testing Shift+MouseButton press/release\n"); + /* first, move mouse pointer inside of the window client area */ + GetClientRect(hwnd, &rc); + MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2); + rc.left += (rc.right - rc.left)/2; + rc.top += (rc.bottom - rc.top)/2; + SetCursorPos(rc.left, rc.top); + SetActiveWindow(hwnd); + + flush_events(); + flush_sequence(); + GetCursorPos(&pt); + if (pt.x == rc.left && pt.y == rc.top) + { + int i; + keybd_event(VK_SHIFT, 0, 0, 0); + mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); + keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0); + pump_msg_loop(hwnd, 0); + for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break; + if (i < sequence_cnt) + ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE); + else + skip( "Shift+MouseButton event didn't get to the window\n" ); + } + +done: + if (hAccel) DestroyAcceleratorTable(hAccel); DestroyWindow(hwnd); } @@ -6357,15 +7157,12 @@ static void test_accelerators(void) static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; - static long beginpaint_counter = 0; + static LONG defwndproc_counter = 0; + static LONG beginpaint_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; - trace("%p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - /* explicitly ignore WM_GETICON message */ - if (message == WM_GETICON) return 0; + if (ignore_message( message )) return 0; switch (message) { @@ -6425,37 +7222,21 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, /* ignore */ case WM_MOUSEMOVE: + case WM_MOUSEACTIVATE: + case WM_NCMOUSEMOVE: case WM_SETCURSOR: - case WM_DEVICECHANGE: + case WM_IME_SELECT: return 0; - - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); - break; } - } + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; if (beginpaint_counter) msg.flags |= beginpaint; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "MsgCheckProc"; add_message(&msg); if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD)) @@ -6466,12 +7247,7 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, GetClientRect(parent, &rc); trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom); - - trace("ptReserved = (%d,%d)\n" - "ptMaxSize = (%d,%d)\n" - "ptMaxPosition = (%d,%d)\n" - "ptMinTrackSize = (%d,%d)\n" - "ptMaxTrackSize = (%d,%d)\n", + trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n", minmax->ptReserved.x, minmax->ptReserved.y, minmax->ptMaxSize.x, minmax->ptMaxSize.y, minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, @@ -6514,20 +7290,27 @@ static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPAR static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; - trace("popup: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + if (ignore_message( message )) return 0; - /* explicitly ignore WM_GETICON message */ - if (message == WM_GETICON) return 0; + switch (message) + { + case WM_QUERYENDSESSION: + case WM_ENDSESSION: + lParam &= ~0x01; /* Vista adds a 0x01 flag */ + break; + } + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "popup"; add_message(&msg); if (message == WM_CREATE) @@ -6545,23 +7328,18 @@ static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; - static long beginpaint_counter = 0; + static LONG defwndproc_counter = 0; + static LONG beginpaint_counter = 0; LRESULT ret; - struct message msg; - LPARAM logged_lParam; + struct recvd_message msg; - trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); + if (ignore_message( message )) return 0; - /* explicitly ignore WM_GETICON message */ - if (message == WM_GETICON) return 0; - - logged_lParam=lParam; if (log_all_parent_messages || message == WM_PARENTNOTIFY || message == WM_CANCELMODE || message == WM_SETFOCUS || message == WM_KILLFOCUS || message == WM_ENABLE || message == WM_ENTERIDLE || - message == WM_DRAWITEM || + message == WM_DRAWITEM || message == WM_COMMAND || message == WM_IME_SETCONTEXT) { switch (message) @@ -6571,6 +7349,7 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam return HTCLIENT; case WM_SETCURSOR: case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: return 0; case WM_ERASEBKGND: @@ -6582,53 +7361,16 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam ret, rc.left, rc.top, rc.right, rc.bottom); break; } - - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); - break; } - case WM_DRAWITEM: - { - /* encode DRAWITEMSTRUCT into an LPARAM */ - DRAW_ITEM_STRUCT di; - DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam; - - trace("WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x\n", - dis->CtlType, dis->CtlID, dis->itemID, dis->itemAction, dis->itemState); - - di.u.item.type = dis->CtlType; - di.u.item.ctl_id = dis->CtlID; - di.u.item.item_id = dis->itemID; - di.u.item.action = dis->itemAction; - di.u.item.state = dis->itemState; - - logged_lParam = di.u.lp; - break; - } - } - + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|parent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; if (beginpaint_counter) msg.flags |= beginpaint; msg.wParam = wParam; - msg.lParam = logged_lParam; + msg.lParam = lParam; + msg.descr = "parent"; add_message(&msg); } @@ -6651,14 +7393,11 @@ static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; - trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - /* explicitly ignore WM_GETICON message */ - if (message == WM_GETICON) return 0; + if (ignore_message( message )) return 0; if (test_def_id) { @@ -6670,34 +7409,13 @@ static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARA ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret); } - switch (message) - { - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); - break; - } - } - + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "dialog"; add_message(&msg); defwndproc_counter++; @@ -6707,53 +7425,11 @@ static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARA return ret; } -static void dump_winpos_flags(UINT flags) -{ - if (!winetest_debug) return; - - if (flags & SWP_SHOWWINDOW) printf("|SWP_SHOWWINDOW"); - if (flags & SWP_HIDEWINDOW) printf("|SWP_HIDEWINDOW"); - if (flags & SWP_NOACTIVATE) printf("|SWP_NOACTIVATE"); - if (flags & SWP_FRAMECHANGED) printf("|SWP_FRAMECHANGED"); - if (flags & SWP_NOCOPYBITS) printf("|SWP_NOCOPYBITS"); - if (flags & SWP_NOOWNERZORDER) printf("|SWP_NOOWNERZORDER"); - if (flags & SWP_NOSENDCHANGING) printf("|SWP_NOSENDCHANGING"); - if (flags & SWP_DEFERERASE) printf("|SWP_DEFERERASE"); - if (flags & SWP_ASYNCWINDOWPOS) printf("|SWP_ASYNCWINDOWPOS"); - if (flags & SWP_NOZORDER) printf("|SWP_NOZORDER"); - if (flags & SWP_NOREDRAW) printf("|SWP_NOREDRAW"); - if (flags & SWP_NOSIZE) printf("|SWP_NOSIZE"); - if (flags & SWP_NOMOVE) printf("|SWP_NOMOVE"); - if (flags & SWP_NOCLIENTSIZE) printf("|SWP_NOCLIENTSIZE"); - if (flags & SWP_NOCLIENTMOVE) printf("|SWP_NOCLIENTMOVE"); - -#define DUMPED_FLAGS \ - (SWP_NOSIZE | \ - SWP_NOMOVE | \ - SWP_NOZORDER | \ - SWP_NOREDRAW | \ - SWP_NOACTIVATE | \ - SWP_FRAMECHANGED | \ - SWP_SHOWWINDOW | \ - SWP_HIDEWINDOW | \ - SWP_NOCOPYBITS | \ - SWP_NOOWNERZORDER | \ - SWP_NOSENDCHANGING | \ - SWP_DEFERERASE | \ - SWP_ASYNCWINDOWPOS | \ - SWP_NOCLIENTSIZE | \ - SWP_NOCLIENTMOVE) - - if(flags & ~DUMPED_FLAGS) printf("|0x%04x", flags & ~DUMPED_FLAGS); - printf("\n"); -#undef DUMPED_FLAGS -} - static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; /* log only specific messages we are interested in */ switch (message) @@ -6764,49 +7440,25 @@ static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LP case WM_KILLFOCUS: #endif case WM_SHOWWINDOW: - trace("WM_SHOWWINDOW %ld\n", wParam); - break; case WM_SIZE: - trace("WM_SIZE %ld\n", wParam); - break; case WM_MOVE: - trace("WM_MOVE\n"); - break; case WM_GETMINMAXINFO: - trace("WM_GETMINMAXINFO\n"); - break; - case WM_WINDOWPOSCHANGING: case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - trace("flags: "); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); break; - } default: /* ignore */ /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/ return DefWindowProcA(hwnd, message, wParam, lParam); } + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "show"; add_message(&msg); defwndproc_counter++; @@ -6816,6 +7468,35 @@ static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LP return ret; } +static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CREATE: return 0; + case WM_PAINT: + { + MSG msg2; + static int i = 0; + + if (i < 256) + { + i++; + if (PeekMessageA(&msg2, 0, 0, 0, 1)) + { + TranslateMessage(&msg2); + DispatchMessage(&msg2); + } + i--; + } + else ok(broken(1), "infinite loop\n"); + if ( i == 0) + paint_loop_done = 1; + return DefWindowProcA(hWnd,msg,wParam,lParam); + } + } + return DefWindowProcA(hWnd,msg,wParam,lParam); +} + static BOOL RegisterWindowClasses(void) { WNDCLASSA cls; @@ -6827,7 +7508,7 @@ static BOOL RegisterWindowClasses(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "TestWindowClass"; @@ -6849,6 +7530,10 @@ static BOOL RegisterWindowClasses(void) cls.lpszClassName = "SimpleWindowClass"; if(!RegisterClassA(&cls)) return FALSE; + cls.lpfnWndProc = PaintLoopProcA; + cls.lpszClassName = "PaintLoopWindowClass"; + if(!RegisterClassA(&cls)) return FALSE; + cls.style = CS_NOCLOSE; cls.lpszClassName = "NoCloseWindowClass"; if(!RegisterClassA(&cls)) return FALSE; @@ -6876,27 +7561,37 @@ static BOOL RegisterWindowClasses(void) return TRUE; } -static HHOOK hCBT_hook; -static DWORD cbt_hook_thread_id; +static BOOL is_our_logged_class(HWND hwnd) +{ + char buf[256]; + + if (GetClassNameA(hwnd, buf, sizeof(buf))) + { + if (!lstrcmpiA(buf, "TestWindowClass") || + !lstrcmpiA(buf, "ShowWindowClass") || + !lstrcmpiA(buf, "TestParentClass") || + !lstrcmpiA(buf, "TestPopupClass") || + !lstrcmpiA(buf, "SimpleWindowClass") || + !lstrcmpiA(buf, "TestDialogClass") || + !lstrcmpiA(buf, "MDI_frame_class") || + !lstrcmpiA(buf, "MDI_client_class") || + !lstrcmpiA(buf, "MDI_child_class") || + !lstrcmpiA(buf, "my_button_class") || + !lstrcmpiA(buf, "my_edit_class") || + !lstrcmpiA(buf, "static") || + !lstrcmpiA(buf, "ListBox") || + !lstrcmpiA(buf, "ComboBox") || + !lstrcmpiA(buf, "MyDialogClass") || + !lstrcmpiA(buf, "#32770") || + !lstrcmpiA(buf, "#32768")) + return TRUE; + } + return FALSE; +} static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) { - static const char * const CBT_code_name[10] = { - "HCBT_MOVESIZE", - "HCBT_MINMAX", - "HCBT_QS", - "HCBT_CREATEWND", - "HCBT_DESTROYWND", - "HCBT_ACTIVATE", - "HCBT_CLICKSKIPPED", - "HCBT_KEYSKIPPED", - "HCBT_SYSCOMMAND", - "HCBT_SETFOCUS" }; - const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown"; HWND hwnd; - char buf[256]; - - trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam); ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n"); @@ -6908,12 +7603,14 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED) { - struct message msg; + struct recvd_message msg; + msg.hwnd = 0; msg.message = nCode; msg.flags = hook|wparam|lparam; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "CBT"; add_message(&msg); return CallNextHookEx(hCBT_hook, nCode, wParam, lParam); @@ -6936,34 +7633,18 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) /* Log also SetFocus(0) calls */ hwnd = wParam ? (HWND)wParam : (HWND)lParam; - if (GetClassNameA(hwnd, buf, sizeof(buf))) + if (is_our_logged_class(hwnd)) { - if (!lstrcmpiA(buf, "TestWindowClass") || - !lstrcmpiA(buf, "ShowWindowClass") || - !lstrcmpiA(buf, "TestParentClass") || - !lstrcmpiA(buf, "TestPopupClass") || - !lstrcmpiA(buf, "SimpleWindowClass") || - !lstrcmpiA(buf, "TestDialogClass") || - !lstrcmpiA(buf, "MDI_frame_class") || - !lstrcmpiA(buf, "MDI_client_class") || - !lstrcmpiA(buf, "MDI_child_class") || - !lstrcmpiA(buf, "my_button_class") || - !lstrcmpiA(buf, "my_edit_class") || - !lstrcmpiA(buf, "static") || - !lstrcmpiA(buf, "ListBox") || - !lstrcmpiA(buf, "ComboBox") || - !lstrcmpiA(buf, "MyDialogClass") || - !lstrcmpiA(buf, "#32770")) - { - struct message msg; + struct recvd_message msg; + msg.hwnd = hwnd; msg.message = nCode; msg.flags = hook|wparam|lparam; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "CBT"; add_message(&msg); } - } return CallNextHookEx(hCBT_hook, nCode, wParam, lParam); } @@ -6975,45 +7656,24 @@ static void CALLBACK win_event_proc(HWINEVENTHOOK hevent, DWORD thread_id, DWORD event_time) { - char buf[256]; - - trace("WEH:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n", - hevent, event, hwnd, object_id, child_id, thread_id, event_time); - ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n"); /* ignore mouse cursor events */ if (object_id == OBJID_CURSOR) return; - if (!hwnd || GetClassNameA(hwnd, buf, sizeof(buf))) + if (!hwnd || is_our_logged_class(hwnd)) { - if (!hwnd || - !lstrcmpiA(buf, "TestWindowClass") || - !lstrcmpiA(buf, "TestParentClass") || - !lstrcmpiA(buf, "TestPopupClass") || - !lstrcmpiA(buf, "SimpleWindowClass") || - !lstrcmpiA(buf, "TestDialogClass") || - !lstrcmpiA(buf, "MDI_frame_class") || - !lstrcmpiA(buf, "MDI_client_class") || - !lstrcmpiA(buf, "MDI_child_class") || - !lstrcmpiA(buf, "my_button_class") || - !lstrcmpiA(buf, "my_edit_class") || - !lstrcmpiA(buf, "static") || - !lstrcmpiA(buf, "ListBox") || - !lstrcmpiA(buf, "ComboBox") || - !lstrcmpiA(buf, "MyDialogClass") || - !lstrcmpiA(buf, "#32770")) - { - struct message msg; + struct recvd_message msg; + msg.hwnd = hwnd; msg.message = event; msg.flags = winevent_hook|wparam|lparam; msg.wParam = object_id; msg.lParam = child_id; + msg.descr = "WEH"; add_message(&msg); } } -} static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0}; static const WCHAR wszAnsi[] = {'U',0}; @@ -7035,7 +7695,7 @@ static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, static const struct message WmGetTextLengthAfromW[] = { { WM_GETTEXTLENGTH, sent }, - { WM_GETTEXT, sent }, + { WM_GETTEXT, sent|optional }, { 0 } }; @@ -7165,13 +7825,15 @@ static void test_message_conversion(void) newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ); lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 ); ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text), - NULL, 0, NULL, NULL ), + NULL, 0, NULL, NULL ) || + broken(lRes == lstrlenW(dummy_window_text) + 37), "got bad length %ld\n", lRes ); SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */ lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 ); ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text), - NULL, 0, NULL, NULL ), + NULL, 0, NULL, NULL ) || + broken(lRes == lstrlenW(dummy_window_text) + 37), "got bad length %ld\n", lRes ); ret = DestroyWindow(hwnd); @@ -7189,6 +7851,12 @@ static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime) { } +static VOID CALLBACK tfunc_crash(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime) +{ + /* Crash on purpose */ + *(volatile int *)0 = 2; +} + #define TIMER_ID 0x19 static DWORD WINAPI timer_thread_proc(LPVOID x) @@ -7210,6 +7878,7 @@ static void test_timers(void) { struct timer_info info; DWORD id; + MSG msg; info.hWnd = CreateWindow ("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW , @@ -7232,6 +7901,26 @@ static void test_timers(void) ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n"); ok(DestroyWindow(info.hWnd), "failed to destroy window\n"); + + /* Test timer callback with crash */ + SetLastError(0xdeadbeef); + info.hWnd = CreateWindowW(testWindowClassW, NULL, + WS_OVERLAPPEDWINDOW , + CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, + NULL, NULL, 0); + if ((!info.hWnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) || /* Win9x/Me */ + (!pGetMenuInfo)) /* Win95/NT4 */ + { + win_skip("Test would crash on Win9x/WinMe/NT4\n"); + DestroyWindow(info.hWnd); + return; +} + info.id = SetTimer(info.hWnd, TIMER_ID, 0, tfunc_crash); + ok(info.id, "SetTimer failed\n"); + Sleep(150); + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg); + + ok(DestroyWindow(info.hWnd), "failed to destroy window\n"); } static int count = 0; @@ -7352,20 +8041,19 @@ static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent, { char buf[256]; - trace("WEH_2:%p,event %08x,hwnd %p,obj %08x,id %08x,thread %08x,time %08x\n", - hevent, event, hwnd, object_id, child_id, thread_id, event_time); - if (GetClassNameA(hwnd, buf, sizeof(buf))) { if (!lstrcmpiA(buf, "TestWindowClass") || !lstrcmpiA(buf, "static")) { - struct message msg; + struct recvd_message msg; + msg.hwnd = hwnd; msg.message = event; msg.flags = winevent_hook|wparam|lparam; msg.wParam = object_id; msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2); + msg.descr = "WEH_2"; add_message(&msg); } } @@ -7379,16 +8067,16 @@ static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lP HWND hwnd; char buf[256]; - trace("CBT_2: %d, %08lx, %08lx\n", nCode, wParam, lParam); - if (nCode == HCBT_SYSCOMMAND) { - struct message msg; + struct recvd_message msg; + msg.hwnd = 0; msg.message = nCode; msg.flags = hook|wparam|lparam; msg.wParam = wParam; msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2; + msg.descr = "CBT_2"; add_message(&msg); return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam); @@ -7401,11 +8089,12 @@ static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lP /* we can't test for real mouse events */ if (mhll->flags & LLMHF_INJECTED) { - struct message msg; + struct recvd_message msg; memset (&msg, 0, sizeof (msg)); msg.message = wParam; msg.flags = hook; + msg.descr = "CBT_2"; add_message(&msg); } return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam); @@ -7419,12 +8108,14 @@ static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lP if (!lstrcmpiA(buf, "TestWindowClass") || !lstrcmpiA(buf, "static")) { - struct message msg; + struct recvd_message msg; + msg.hwnd = hwnd; msg.message = nCode; msg.flags = hook|wparam|lparam; msg.wParam = wParam; msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2; + msg.descr = "CBT_2"; add_message(&msg); } } @@ -7555,7 +8246,7 @@ static void test_winevents(void) hevent = CreateEventA(NULL, 0, 0, NULL); assert(hevent); - hwnd2 = (HWND)hevent; + hwnd2 = hevent; hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid); ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); @@ -7608,7 +8299,7 @@ static void test_winevents(void) ok_sequence(WmWinEventsSeq, "notify winevents", FALSE); /****** start of event filtering test *************/ - hhook = (HWINEVENTHOOK)pSetWinEventHook( + hhook = pSetWinEventHook( EVENT_OBJECT_SHOW, /* 0x8002 */ EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */ GetModuleHandleA(0), win_event_global_hook_proc, @@ -7618,7 +8309,7 @@ static void test_winevents(void) hevent = CreateEventA(NULL, 0, 0, NULL); assert(hevent); - hwnd2 = (HWND)hevent; + hwnd2 = hevent; hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid); ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); @@ -7647,16 +8338,14 @@ static void test_winevents(void) /****** end of event filtering test *************/ /****** start of out of context event test *************/ - hhook = (HWINEVENTHOOK)pSetWinEventHook( - EVENT_MIN, EVENT_MAX, - 0, win_event_global_hook_proc, - GetCurrentProcessId(), 0, + hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, + win_event_global_hook_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError()); hevent = CreateEventA(NULL, 0, 0, NULL); assert(hevent); - hwnd2 = (HWND)hevent; + hwnd2 = hevent; flush_sequence(); @@ -7697,13 +8386,13 @@ static void test_winevents(void) /* WH_MOUSE_LL is not supported on Win9x platforms */ if (!hCBT_global_hook) { - trace("Skipping WH_MOUSE_LL test on this platform\n"); + win_skip("Skipping WH_MOUSE_LL test on this platform\n"); goto skip_mouse_ll_hook_test; } hevent = CreateEventA(NULL, 0, 0, NULL); assert(hevent); - hwnd2 = (HWND)hevent; + hwnd2 = hevent; hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid); ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); @@ -7770,8 +8459,8 @@ static void test_set_hook(void) /* even process local incontext hooks require hmodule */ SetLastError(0xdeadbeef); - hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, - 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); + hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc, + GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n"); ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */ GetLastError() == 0xdeadbeef, /* Win9x */ @@ -7779,8 +8468,8 @@ static void test_set_hook(void) /* even thread local incontext hooks require hmodule */ SetLastError(0xdeadbeef); - hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, - 0, win_event_proc, GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT); + hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc, + GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT); ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n"); ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */ GetLastError() == 0xdeadbeef, /* Win9x */ @@ -7790,27 +8479,27 @@ static void test_set_hook(void) { /* these 3 tests don't pass under Win9x */ SetLastError(0xdeadbeef); - hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(1, 0, - 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); + hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc, + GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n"); ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError()); SetLastError(0xdeadbeef); - hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(-1, 1, - 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); + hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc, + GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n"); ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError()); SetLastError(0xdeadbeef); - hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, - 0, win_event_proc, 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT); + hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc, + 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT); ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n"); ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError()); } SetLastError(0xdeadbeef); - hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(0, 0, - 0, win_event_proc, GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); + hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc, + GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT); ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError()); ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError()); ret = pUnhookWinEvent(hwinevent_hook); @@ -7820,8 +8509,8 @@ todo_wine { /* This call succeeds under win2k SP4, but fails under Wine. Does win2k test/use passed process id? */ SetLastError(0xdeadbeef); - hwinevent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, - 0, win_event_proc, 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT); + hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc, + 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT); ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError()); ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError()); ret = pUnhookWinEvent(hwinevent_hook); @@ -7838,6 +8527,14 @@ todo_wine { static const struct message ScrollWindowPaint1[] = { { WM_PAINT, sent }, { WM_ERASEBKGND, sent|beginpaint }, + { WM_GETTEXTLENGTH, sent|optional }, + { WM_PAINT, sent|optional }, + { WM_NCPAINT, sent|beginpaint|optional }, + { WM_GETTEXT, sent|beginpaint|optional }, + { WM_GETTEXT, sent|beginpaint|optional }, + { WM_GETTEXT, sent|beginpaint|optional }, + { WM_GETTEXT, sent|beginpaint|defwinproc|optional }, + { WM_ERASEBKGND, sent|beginpaint|optional }, { 0 } }; @@ -7890,10 +8587,9 @@ static void test_scrollwindowex(void) trace("start scroll\n"); ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE); - todo_wine { /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */ + /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */ /* windows sometimes a WM_MOVE */ - ok_sequence(WmEmptySeq, "ScrollWindowEx", 0); - } + ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE); trace("end scroll\n"); flush_sequence(); flush_events(); @@ -7940,7 +8636,7 @@ static void test_DestroyWindow(void) { BOOL ret; HWND parent, child1, child2, child3, child4, test; - UINT child_id = WND_CHILD_ID + 1; + UINT_PTR child_id = WND_CHILD_ID + 1; parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); @@ -8138,8 +8834,11 @@ struct sendmsg_info static DWORD CALLBACK send_msg_thread( LPVOID arg ) { struct sendmsg_info *info = arg; + SetLastError( 0xdeadbeef ); info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL ); - if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT, "unexpected error %d\n", GetLastError()); + if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT || + broken(GetLastError() == 0), /* win9x */ + "unexpected error %d\n", GetLastError()); return 0; } @@ -8163,6 +8862,7 @@ static void test_SendMessageTimeout(void) HANDLE thread; struct sendmsg_info info; DWORD tid; + BOOL is_win9x; info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); @@ -8186,17 +8886,18 @@ static void test_SendMessageTimeout(void) ok( info.ret == 0, "SendMessageTimeout succeeded\n" ); ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); - /* 0 means infinite timeout */ + /* 0 means infinite timeout (but not on win9x) */ info.timeout = 0; info.ret = 0xdeadbeef; thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid ); Sleep(100); wait_for_thread( thread ); CloseHandle( thread ); - ok( info.ret == 1, "SendMessageTimeout failed\n" ); - ok_sequence( WmUser, "WmUser", FALSE ); + is_win9x = !info.ret; + if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); + else ok_sequence( WmUser, "WmUser", FALSE ); - /* timeout is treated as signed despite the prototype */ + /* timeout is treated as signed despite the prototype (but not on win9x) */ info.timeout = 0x7fffffff; info.ret = 0xdeadbeef; thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid ); @@ -8212,8 +8913,16 @@ static void test_SendMessageTimeout(void) Sleep(100); wait_for_thread( thread ); CloseHandle( thread ); + if (is_win9x) + { + ok( info.ret == 1, "SendMessageTimeout failed\n" ); + ok_sequence( WmUser, "WmUser", FALSE ); + } + else + { ok( info.ret == 0, "SendMessageTimeout succeeded\n" ); ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE ); + } /* now check for timeout during message processing */ SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc ); @@ -8340,20 +9049,19 @@ static WNDPROC old_edit_proc; static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; - trace("edit: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - /* explicitly ignore WM_GETICON message */ - if (message == WM_GETICON) return 0; + if (ignore_message( message )) return 0; + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "edit"; add_message(&msg); defwndproc_counter++; @@ -8478,13 +9186,24 @@ static const struct message WmKeyDownSkippedSeq[] = { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */ { 0 } }; +static const struct message WmKeyDownWasDownSkippedSeq[] = +{ + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */ + { 0 } +}; static const struct message WmKeyUpSkippedSeq[] = { { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */ { 0 } }; +static const struct message WmUserKeyUpSkippedSeq[] = +{ + { WM_USER, sent }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */ + { 0 } +}; -#define EV_START_STOP 0 +#define EV_STOP 0 #define EV_SENDMSG 1 #define EV_ACK 2 @@ -8499,9 +9218,8 @@ static DWORD CALLBACK send_msg_thread_2(void *param) DWORD ret; struct peekmsg_info *info = param; - trace("thread: waiting for start\n"); - WaitForSingleObject(info->hevent[EV_START_STOP], INFINITE); trace("thread: looping\n"); + SetEvent(info->hevent[EV_ACK]); while (1) { @@ -8509,13 +9227,14 @@ static DWORD CALLBACK send_msg_thread_2(void *param) switch (ret) { - case WAIT_OBJECT_0 + EV_START_STOP: + case WAIT_OBJECT_0 + EV_STOP: trace("thread: exiting\n"); return 0; case WAIT_OBJECT_0 + EV_SENDMSG: trace("thread: sending message\n"); - SendNotifyMessageA(info->hwnd, WM_USER, 0, 0); + ok( SendNotifyMessageA(info->hwnd, WM_USER, 0, 0), + "SendNotifyMessageA failed error %u\n", GetLastError()); SetEvent(info->hevent[EV_ACK]); break; @@ -8545,15 +9264,12 @@ static void test_PeekMessage(void) UpdateWindow(info.hwnd); SetFocus(info.hwnd); - info.hevent[EV_START_STOP] = CreateEventA(NULL, 0, 0, NULL); + info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL); info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL); info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL); hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid); - Sleep(100); - - trace("signalling to start looping\n"); - SetEvent(info.hevent[EV_START_STOP]); + WaitForSingleObject(info.hevent[EV_ACK], 10000); flush_events(); flush_sequence(); @@ -8566,6 +9282,11 @@ static void test_PeekMessage(void) qs_all_input &= ~QS_RAWINPUT; qs_input &= ~QS_RAWINPUT; } + if (qstatus & QS_POSTMESSAGE) + { + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ; + qstatus = GetQueueStatus(qs_all_input); + } ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); trace("signalling to send message\n"); @@ -8575,10 +9296,13 @@ static void test_PeekMessage(void) /* pass invalid QS_xxxx flags */ SetLastError(0xdeadbeef); qstatus = GetQueueStatus(0xffffffff); - ok(qstatus == 0, "GetQueueStatus should fail: %08x\n", qstatus); + ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus); + if (!qstatus) + { ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError()); - qstatus = GetQueueStatus(qs_all_input); + } + qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */ ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE), "wrong qstatus %08x\n", qstatus); @@ -8595,6 +9319,11 @@ static void test_PeekMessage(void) keybd_event('N', 0, 0, 0); keybd_event('N', 0, KEYEVENTF_KEYUP, 0); qstatus = GetQueueStatus(qs_all_input); + if (!(qstatus & MAKELONG(QS_KEY, QS_KEY))) + { + skip( "queuing key events not supported\n" ); + goto done; + } ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus); @@ -8618,9 +9347,19 @@ static void test_PeekMessage(void) msg.message = 0; ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16)); + if (ret && msg.message == WM_CHAR) + { + win_skip( "PM_QS_* flags not supported in PeekMessage\n" ); + goto done; + } ok(!ret, "PeekMessageA should have returned FALSE instead of msg %04x\n", msg.message); + if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */ + { + win_skip( "PM_QS_* flags not supported in PeekMessage\n" ); + goto done; + } ok_sequence(WmUser, "WmUser", FALSE); qstatus = GetQueueStatus(qs_all_input); @@ -8862,8 +9601,104 @@ todo_wine { ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + /* some GetMessage tests */ + + keybd_event('N', 0, 0, 0); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus); + + PostMessageA(info.hwnd, WM_CHAR, 'z', 0); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus); + + if (qstatus) + { + ret = GetMessageA( &msg, 0, 0, 0 ); + ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', + "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + ret, msg.message, msg.wParam); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus); + } + + if (qstatus) + { + ret = GetMessageA( &msg, 0, 0, 0 ); + ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N', + "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n", + ret, msg.message, msg.wParam); + ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + } + + keybd_event('N', 0, 0, 0); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus); + + PostMessageA(info.hwnd, WM_CHAR, 'z', 0); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus); + + if (qstatus & (QS_KEY << 16)) + { + ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP ); + ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N', + "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n", + ret, msg.message, msg.wParam); + ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus); + } + + if (qstatus) + { + ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR ); + ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', + "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + ret, msg.message, msg.wParam); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + } + + keybd_event('N', 0, KEYEVENTF_KEYUP, 0); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus); + + PostMessageA(info.hwnd, WM_CHAR, 'z', 0); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus); + + trace("signalling to send message\n"); + SetEvent(info.hevent[EV_SENDMSG]); + WaitForSingleObject(info.hevent[EV_ACK], INFINITE); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY), + "wrong qstatus %08x\n", qstatus); + + if (qstatus & (QS_KEY << 16)) + { + ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP ); + ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N', + "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n", + ret, msg.message, msg.wParam); + ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus); + } + + if (qstatus) + { + ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR ); + ok(ret && msg.message == WM_CHAR && msg.wParam == 'z', + "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n", + ret, msg.message, msg.wParam); + qstatus = GetQueueStatus(qs_all_input); + ok(qstatus == 0, "wrong qstatus %08x\n", qstatus); + } +done: trace("signalling to exit\n"); - SetEvent(info.hevent[EV_START_STOP]); + SetEvent(info.hevent[EV_STOP]); WaitForSingleObject(hthread, INFINITE); @@ -8886,10 +9721,11 @@ static void wait_move_event(HWND hwnd, int x, int y) while (GetTickCount() - time < 200 && !go) { ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE); go = ret && msg.pt.x > x && msg.pt.y > y; + if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT ); } } -#define STEP 20 +#define STEP 5 static void test_PeekMessage2(void) { HWND hwnd; @@ -8919,11 +9755,16 @@ static void test_PeekMessage2(void) /* Do initial mousemove, wait until we can see it and then do our test peek with PM_NOREMOVE. */ mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0); - wait_move_event(hwnd, 80, 80); + wait_move_event(hwnd, 100-STEP, 100-STEP); ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE); - ok(ret, "no message available\n"); - if (ret) { + if (!ret) + { + skip( "queuing mouse events not supported\n" ); + goto done; + } + else + { trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y); message = msg.message; time1 = msg.time; @@ -8937,7 +9778,7 @@ static void test_PeekMessage2(void) * Although the previous mousemove message was never removed, the * mousemove we now peek should reflect the recent mouse movements * because the input queue will merge the move events. */ - Sleep(2); + Sleep(100); mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0); wait_move_event(hwnd, x1, y1); @@ -8955,7 +9796,7 @@ static void test_PeekMessage2(void) } /* Have another go, to drive the point home */ - Sleep(2); + Sleep(100); mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0); wait_move_event(hwnd, x2, y2); @@ -8972,6 +9813,7 @@ static void test_PeekMessage2(void) ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3); } +done: DestroyWindow(hwnd); SetCursorPos(pos.x, pos.y); flush_events(); @@ -8983,6 +9825,7 @@ static void test_quit_message(void) BOOL ret; /* test using PostQuitMessage */ + flush_events(); PostQuitMessage(0xbeef); ret = PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); @@ -9043,8 +9886,8 @@ static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move) DWORD start_ticks, end_ticks; start_ticks = GetTickCount(); - /* add some deviation (5%) to cover not expected delays */ - start_ticks += timeout / 20; + /* add some deviation (50%) to cover not expected delays */ + start_ticks += timeout / 2; do { @@ -9055,12 +9898,14 @@ static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move) */ if (msg.message == WM_TIMER || msg.message == WM_SYSTIMER) { - struct message s_msg; + struct recvd_message s_msg; + s_msg.hwnd = msg.hwnd; s_msg.message = msg.message; s_msg.flags = sent|wparam|lparam; s_msg.wParam = msg.wParam; s_msg.lParam = msg.lParam; + s_msg.descr = "msg_loop"; add_message(&s_msg); } DispatchMessage(&msg); @@ -9124,17 +9969,20 @@ static void test_TrackMouseEvent(void) default_hover_time = 0xdeadbeef; SetLastError(0xdeadbeef); ret = SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0); - ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError()); + ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */ + "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError()); if (!ret) default_hover_time = 400; trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time); SetLastError(0xdeadbeef); ret = SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0); - ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError()); + ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */ + "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError()); if (!ret) hover_width = 4; SetLastError(0xdeadbeef); ret = SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0); - ok(ret, "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError()); + ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */ + "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError()); if (!ret) hover_height = 4; trace("hover rect is %u x %d\n", hover_width, hover_height); @@ -9150,6 +9998,7 @@ static void test_TrackMouseEvent(void) NULL, NULL, 0); assert(hchild); + SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); flush_events(); flush_sequence(); @@ -9160,7 +10009,8 @@ static void test_TrackMouseEvent(void) SetLastError(0xdeadbeef); ret = pTrackMouseEvent(&tme); ok(!ret, "TrackMouseEvent should fail\n"); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef), + "not expected error %u\n", GetLastError()); tme.cbSize = sizeof(tme); tme.dwFlags = TME_HOVER; @@ -9169,7 +10019,8 @@ static void test_TrackMouseEvent(void) SetLastError(0xdeadbeef); ret = pTrackMouseEvent(&tme); ok(!ret, "TrackMouseEvent should fail\n"); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), + "not expected error %u\n", GetLastError()); tme.cbSize = sizeof(tme); tme.dwFlags = TME_HOVER | TME_CANCEL; @@ -9178,7 +10029,8 @@ static void test_TrackMouseEvent(void) SetLastError(0xdeadbeef); ret = pTrackMouseEvent(&tme); ok(!ret, "TrackMouseEvent should fail\n"); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "not expected error %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), + "not expected error %u\n", GetLastError()); GetWindowRect(hwnd, &rc_parent); GetWindowRect(hchild, &rc_child); @@ -9199,7 +10051,24 @@ static void test_TrackMouseEvent(void) flush_sequence(); track_hover(hwnd, 0); - track_query(TME_HOVER, hwnd, default_hover_time); + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_QUERY; + tme.hwndTrack = (HWND)0xdeadbeef; + tme.dwHoverTime = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pTrackMouseEvent(&tme); + ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError()); + ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); + if (!tme.dwFlags) + { + skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" ); + DestroyWindow( hwnd ); + return; + } + ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags); + ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd); + ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n", + tme.dwHoverTime, default_hover_time); pump_msg_loop_timeout(default_hover_time, FALSE); ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE); @@ -9215,7 +10084,7 @@ static void test_TrackMouseEvent(void) track_query(TME_HOVER, hwnd, default_hover_time); - pump_msg_loop_timeout(default_hover_time / 2, FALSE); + pump_msg_loop_timeout(default_hover_time, FALSE); ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE); track_query(0, NULL, 0); @@ -9243,9 +10112,9 @@ static void test_TrackMouseEvent(void) static const struct message WmSetWindowRgn[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam, 1 }, - { WM_NCPAINT, sent }, /* wparam != 1 */ + { WM_NCPAINT, sent|optional }, /* wparam != 1 */ { WM_GETTEXT, sent|defwinproc|optional }, - { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */ + { WM_ERASEBKGND, sent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, { 0 } @@ -9260,14 +10129,24 @@ static const struct message WmSetWindowRgn_no_redraw[] = { }; static const struct message WmSetWindowRgn_clear[] = { - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ }, { WM_NCCALCSIZE, sent|wparam, 1 }, - { WM_NCPAINT, sent }, /* wparam != 1 */ + { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, { WM_NCCALCSIZE, sent|wparam|optional, 1 }, - { WM_NCPAINT, sent|optional }, /* wparam != 1 */ + { WM_NCPAINT, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { WM_NCCALCSIZE, sent|optional|wparam, 1 }, + { WM_NCPAINT, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCCALCSIZE, sent|optional|wparam, 1 }, + { WM_NCPAINT, sent|optional }, { WM_GETTEXT, sent|defwinproc|optional }, { WM_ERASEBKGND, sent|optional }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, @@ -9327,9 +10206,9 @@ static const struct message WmShow[] = { }; static const struct message WmShowNoActivate_1[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED }, - { WM_MOVE, sent|defwinproc }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED }, { 0 } }; @@ -9342,6 +10221,7 @@ static const struct message WmShowNoActivate_2[] = { { HCBT_SETFOCUS, hook|optional }, { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */ + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */ { 0 } }; @@ -9354,6 +10234,7 @@ static const struct message WmShowNA_1[] = { static const struct message WmShowNA_2[] = { { WM_SHOWWINDOW, sent|wparam, 1 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { 0 } }; static const struct message WmRestore_1[] = { @@ -9391,25 +10272,28 @@ static const struct message WmRestore_3[] = { { 0 } }; static const struct message WmRestore_4[] = { - { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, - { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED }, + { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED }, { 0 } }; static const struct message WmRestore_5[] = { - { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, - { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED }, + { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { HCBT_ACTIVATE, hook|optional }, + { HCBT_SETFOCUS, hook|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED }, { 0 } }; static const struct message WmHide_1[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { HCBT_ACTIVATE, hook|optional }, { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */ { 0 } }; @@ -9417,13 +10301,14 @@ static const struct message WmHide_2[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */ { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */ + { HCBT_ACTIVATE, hook|optional }, { 0 } }; static const struct message WmHide_3[] = { { WM_SHOWWINDOW, sent|wparam, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { HCBT_SETFOCUS, hook }, + { HCBT_SETFOCUS, hook|optional }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { 0 } }; @@ -9434,7 +10319,7 @@ static const struct message WmShowMinimized_1[] = { { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED }, + { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, { 0 } }; static const struct message WmMinimize_1[] = { @@ -9444,15 +10329,16 @@ static const struct message WmMinimize_1[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED }, + { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, { 0 } }; static const struct message WmMinimize_2[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE }, + { HCBT_SETFOCUS, hook|optional }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED }, + { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, { 0 } }; static const struct message WmMinimize_3[] = { @@ -9460,13 +10346,15 @@ static const struct message WmMinimize_3[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, - { WM_SIZE, sent|wparam|defwinproc, SIZE_MINIMIZED }, + { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, { 0 } }; static const struct message WmShowMinNoActivate[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGING, sent }, + { WM_WINDOWPOSCHANGED, sent }, + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 }, { 0 } }; static const struct message WmMinMax_1[] = { @@ -9475,10 +10363,24 @@ static const struct message WmMinMax_1[] = { }; static const struct message WmMinMax_2[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED }, + { WM_GETMINMAXINFO, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED }, + { HCBT_ACTIVATE, hook|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { HCBT_SETFOCUS, hook|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED }, + { HCBT_SETFOCUS, hook|optional }, { 0 } }; static const struct message WmMinMax_3[] = { { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE }, + { HCBT_SETFOCUS, hook|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_MOVE, sent|defwinproc|optional }, + { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 }, { 0 } }; static const struct message WmMinMax_4[] = { @@ -9501,26 +10403,28 @@ static const struct message WmShowMaximized_1[] = { static const struct message WmShowMaximized_2[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED }, { WM_GETMINMAXINFO, sent }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { HCBT_ACTIVATE, hook|optional }, + { WM_WINDOWPOSCHANGED, sent|optional }, { WM_MOVE, sent|optional }, /* Win9x doesn't send it */ { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */ - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, + { WM_WINDOWPOSCHANGING, sent|optional }, + { HCBT_SETFOCUS, hook|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED }, - { HCBT_SETFOCUS, hook }, + { HCBT_SETFOCUS, hook|optional }, { 0 } }; static const struct message WmShowMaximized_3[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED }, - { WM_GETMINMAXINFO, sent }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, + { WM_GETMINMAXINFO, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED }, - { WM_MOVE, sent|defwinproc }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED }, { 0 } }; @@ -9568,7 +10472,7 @@ static void test_ShowWindow(void) /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq, FALSE }, /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1, FALSE }, /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }, -/* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, TRUE }, +/* 32 */ { SW_HIDE, TRUE, 0, WmHide_3, FALSE }, /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE }, /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, /* what does this mean?! */ /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, FALSE }, @@ -9578,7 +10482,7 @@ static void test_ShowWindow(void) /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }, /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2, FALSE }, /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE }, -/* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, TRUE }, +/* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2, FALSE }, /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2, FALSE }, /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1, FALSE }, /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3, FALSE }, @@ -9587,7 +10491,7 @@ static void test_ShowWindow(void) /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3, FALSE }, /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq, FALSE }, /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE }, -/* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq, FALSE }, +/* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5, FALSE }, /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1, FALSE }, /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq, FALSE }, /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3, FALSE }, @@ -9645,41 +10549,16 @@ static void test_ShowWindow(void) static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - struct message msg; + struct recvd_message msg; - trace("dialog: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam); - - switch (message) - { - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *winpos = (WINDOWPOS *)lParam; - - trace("%s\n", (message == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", - winpos->hwnd, winpos->hwndInsertAfter, - winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - dump_winpos_flags(winpos->flags); - - /* Log only documented flags, win2k uses 0x1000 and 0x2000 - * in the high word for internal purposes - */ - wParam = winpos->flags & 0xffff; - /* We are not interested in the flags that don't match under XP and Win9x */ - wParam &= ~(SWP_NOZORDER); - break; - } - - /* explicitly ignore WM_GETICON message */ - case WM_GETICON: - return 0; - } + if (ignore_message( message )) return 0; + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; msg.wParam = wParam; msg.lParam = lParam; + msg.descr = "dialog"; add_message(&msg); /* calling DefDlgProc leads to a recursion under XP */ @@ -9869,6 +10748,167 @@ static void test_nullCallback(void) DestroyWindow(hwnd); } +/* SetActiveWindow( 0 ) hwnd visible */ +static const struct message SetActiveWindowSeq0[] = +{ + { HCBT_ACTIVATE, hook|optional }, + { WM_NCACTIVATE, sent|wparam, 0 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam, 0 }, + { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, + { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, + { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, + { WM_KILLFOCUS, sent|optional }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_NCACTIVATE, sent|wparam|optional, 1 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam|optional, 1 }, + { HCBT_SETFOCUS, hook|optional }, + { WM_KILLFOCUS, sent|defwinproc|optional }, + { WM_IME_SETCONTEXT, sent|defwinproc|optional }, + { WM_IME_SETCONTEXT, sent|defwinproc|optional }, + { WM_IME_SETCONTEXT, sent|optional }, + { WM_IME_SETCONTEXT, sent|optional }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { WM_SETFOCUS, sent|defwinproc|optional }, + { WM_GETTEXT, sent|optional }, + { 0 } +}; +/* SetActiveWindow( hwnd ) hwnd visible */ +static const struct message SetActiveWindowSeq1[] = +{ + { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, + { 0 } +}; +/* SetActiveWindow( popup ) hwnd visible, popup visible */ +static const struct message SetActiveWindowSeq2[] = +{ + { HCBT_ACTIVATE, hook }, + { WM_NCACTIVATE, sent|wparam, 0 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam, 0 }, + { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, + { WM_NCPAINT, sent|optional }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ERASEBKGND, sent|optional }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam, 1 }, + { HCBT_SETFOCUS, hook }, + { WM_KILLFOCUS, sent|defwinproc }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { WM_SETFOCUS, sent|defwinproc }, + { WM_GETTEXT, sent|optional }, + { 0 } +}; + +/* SetActiveWindow( hwnd ) hwnd not visible */ +static const struct message SetActiveWindowSeq3[] = +{ + { HCBT_ACTIVATE, hook }, + { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_ACTIVATEAPP, sent|wparam, 1 }, + { WM_ACTIVATEAPP, sent|wparam, 1 }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_ACTIVATE, sent|wparam, 1 }, + { HCBT_SETFOCUS, hook }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { WM_SETFOCUS, sent|defwinproc }, + { 0 } +}; +/* SetActiveWindow( popup ) hwnd not visible, popup not visible */ +static const struct message SetActiveWindowSeq4[] = +{ + { HCBT_ACTIVATE, hook }, + { WM_NCACTIVATE, sent|wparam, 0 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam, 0 }, + { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, + { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_GETTEXT, sent|defwinproc|optional }, + { WM_ACTIVATE, sent|wparam, 1 }, + { HCBT_SETFOCUS, hook }, + { WM_KILLFOCUS, sent|defwinproc }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 }, + { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 }, + { WM_SETFOCUS, sent|defwinproc }, + { 0 } +}; + + +static void test_SetActiveWindow(void) +{ + HWND hwnd, popup, ret; + + hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow", + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + + popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow", + WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP, + 100, 100, 200, 200, hwnd, 0, 0, NULL); + + ok(hwnd != 0, "Failed to create overlapped window\n"); + ok(popup != 0, "Failed to create popup window\n"); + SetForegroundWindow( popup ); + flush_sequence(); + + trace("SetActiveWindow(0)\n"); + ret = SetActiveWindow(0); + ok( ret == popup, "Failed to SetActiveWindow(0)\n"); + ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE); + flush_sequence(); + + trace("SetActiveWindow(hwnd), hwnd visible\n"); + ret = SetActiveWindow(hwnd); + if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE); + flush_sequence(); + + trace("SetActiveWindow(popup), hwnd visible, popup visible\n"); + ret = SetActiveWindow(popup); + ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n"); + ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE); + flush_sequence(); + + ShowWindow(hwnd, SW_HIDE); + ShowWindow(popup, SW_HIDE); + flush_sequence(); + + trace("SetActiveWindow(hwnd), hwnd not visible\n"); + ret = SetActiveWindow(hwnd); + ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret ); + ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE); + flush_sequence(); + + trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n"); + ret = SetActiveWindow(popup); + ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n"); + ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE); + flush_sequence(); + + trace("done\n"); + + DestroyWindow(hwnd); +} + static const struct message SetForegroundWindowSeq[] = { { WM_NCACTIVATE, sent|wparam, 0 }, @@ -9889,6 +10929,7 @@ static void test_SetForegroundWindow(void) WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); ok (hwnd != 0, "Failed to create overlapped window\n"); + SetForegroundWindow( hwnd ); flush_sequence(); trace("SetForegroundWindow( 0 )\n"); @@ -9918,7 +10959,7 @@ static void test_dbcs_wm_char(void) if (!pGetCPInfoExA) { - skip("GetCPInfoExA is not available\n"); + win_skip("GetCPInfoExA is not available\n"); return; } @@ -10225,7 +11266,7 @@ static const struct message wm_lb_click_0[] = { HCBT_SETFOCUS, hook }, { WM_KILLFOCUS, sent|parent }, { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 }, - { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, + { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, { WM_SETFOCUS, sent|defwinproc }, @@ -10251,6 +11292,23 @@ static const struct message wm_lb_click_0[] = { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) }, { 0 } }; +static const struct message wm_lb_deletestring[] = +{ + { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, + { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 }, + { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX }, + { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX }, + { 0 } +}; +static const struct message wm_lb_deletestring_reset[] = +{ + { LB_DELETESTRING, sent|wparam|lparam, 0, 0 }, + { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 }, + { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 }, + { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX }, + { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX }, + { 0 } +}; #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__) @@ -10258,9 +11316,9 @@ static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM); static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) { - static long defwndproc_counter = 0; + static LONG defwndproc_counter = 0; LRESULT ret; - struct message msg; + struct recvd_message msg; /* do not log painting messages */ if (message != WM_PAINT && @@ -10269,16 +11327,15 @@ static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPAR message != WM_ERASEBKGND && message != WM_NCHITTEST && message != WM_GETTEXT && - message != WM_GETICON && - message != WM_DEVICECHANGE) + !ignore_message( message )) { - trace("listbox: %p, %04x, %08lx, %08lx\n", hwnd, message, wp, lp); - + msg.hwnd = hwnd; msg.message = message; msg.flags = sent|wparam|lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wp; msg.lParam = lp; + msg.descr = "listbox"; add_message(&msg); } @@ -10300,7 +11357,9 @@ static void check_lb_state_dbg(HWND listbox, int count, int cur_sel, ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0); ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret); ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0); - ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret); + ok_(__FILE__, line)(ret == caret_index || + broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */ + "expected caret index %d, got %ld\n", caret_index, ret); ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0); ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret); } @@ -10360,16 +11419,605 @@ static void test_listbox_messages(void) check_lb_state(listbox, 3, 0, 0, 0); flush_sequence(); + trace("deleting item 0\n"); + ret = SendMessage(listbox, LB_DELETESTRING, 0, 0); + ok(ret == 2, "expected 2, got %ld\n", ret); + ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE ); + check_lb_state(listbox, 2, -1, 0, 0); + flush_sequence(); + + trace("deleting item 0\n"); + ret = SendMessage(listbox, LB_DELETESTRING, 0, 0); + ok(ret == 1, "expected 1, got %ld\n", ret); + ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE ); + check_lb_state(listbox, 1, -1, 0, 0); + flush_sequence(); + + trace("deleting item 0\n"); + ret = SendMessage(listbox, LB_DELETESTRING, 0, 0); + ok(ret == 0, "expected 0, got %ld\n", ret); + ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE ); + check_lb_state(listbox, 0, -1, 0, 0); + flush_sequence(); + + trace("deleting item 0\n"); + ret = SendMessage(listbox, LB_DELETESTRING, 0, 0); + ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret); + check_lb_state(listbox, 0, -1, 0, 0); + flush_sequence(); + log_all_parent_messages--; DestroyWindow(listbox); DestroyWindow(parent); } +/*************************** Menu test ******************************/ +static const struct message wm_popup_menu_1[] = +{ + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, + { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 }, + { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 }, + { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 }, + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' }, + { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 }, + { WM_INITMENU, sent|lparam, 0, 0 }, + { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) }, + { WM_INITMENUPOPUP, sent|lparam, 0, 1 }, + { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */ + { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 }, + { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */ + { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, + { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 }, + { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 }, + { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */ + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 }, + { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 }, + { 0 } +}; +static const struct message wm_popup_menu_2[] = +{ + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, + { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 }, + { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 }, + { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 }, + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' }, + { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 }, + { WM_INITMENU, sent|lparam, 0, 0 }, + { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, + { WM_INITMENUPOPUP, sent|lparam, 0, 0 }, + { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */ + { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */ + { HCBT_CREATEWND, hook }, + { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP + |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */ + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 }, + { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */ + { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */ + { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 }, + { HCBT_DESTROYWND, hook }, + { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, + { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */ + { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, + { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 }, + { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 }, + { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */ + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 }, + { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 }, + { 0 } +}; +static const struct message wm_popup_menu_3[] = +{ + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, + { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 }, + { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 }, + { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 }, + { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' }, + { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 }, + { WM_INITMENU, sent|lparam, 0, 0 }, + { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, + { WM_INITMENUPOPUP, sent|lparam, 0, 0 }, + { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */ + { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */ + { HCBT_CREATEWND, hook }, + { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP + |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */ + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 }, + { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */ + { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */ + { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 }, + { HCBT_DESTROYWND, hook }, + { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, + { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */ + { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 }, + { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 }, + { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 }, + { WM_COMMAND, sent|wparam|lparam, 100, 0 }, + { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 }, + { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 }, + { 0 } +}; + +static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) +{ + if (message == WM_ENTERIDLE || + message == WM_INITMENU || + message == WM_INITMENUPOPUP || + message == WM_MENUSELECT || + message == WM_PARENTNOTIFY || + message == WM_ENTERMENULOOP || + message == WM_EXITMENULOOP || + message == WM_UNINITMENUPOPUP || + message == WM_KEYDOWN || + message == WM_KEYUP || + message == WM_CHAR || + message == WM_SYSKEYDOWN || + message == WM_SYSKEYUP || + message == WM_SYSCHAR || + message == WM_COMMAND || + message == WM_MENUCOMMAND) + { + struct recvd_message msg; + + msg.hwnd = hwnd; + msg.message = message; + msg.flags = sent|wparam|lparam; + msg.wParam = wp; + msg.lParam = lp; + msg.descr = "parent_menu_proc"; + add_message(&msg); + } + + return DefWindowProcA(hwnd, message, wp, lp); +} + +static void set_menu_style(HMENU hmenu, DWORD style) +{ + MENUINFO mi; + BOOL ret; + + mi.cbSize = sizeof(mi); + mi.fMask = MIM_STYLE; + mi.dwStyle = style; + SetLastError(0xdeadbeef); + ret = pSetMenuInfo(hmenu, &mi); + ok(ret, "SetMenuInfo error %u\n", GetLastError()); +} + +static DWORD get_menu_style(HMENU hmenu) +{ + MENUINFO mi; + BOOL ret; + + mi.cbSize = sizeof(mi); + mi.fMask = MIM_STYLE; + mi.dwStyle = 0; + SetLastError(0xdeadbeef); + ret = pGetMenuInfo(hmenu, &mi); + ok(ret, "GetMenuInfo error %u\n", GetLastError()); + + return mi.dwStyle; +} + +static void test_menu_messages(void) +{ + MSG msg; + WNDCLASSA cls; + HMENU hmenu, hmenu_popup; + HWND hwnd; + DWORD style; + + if (!pGetMenuInfo || !pSetMenuInfo) + { + win_skip("GetMenuInfo and/or SetMenuInfo are not available\n"); + return; + } + cls.style = 0; + cls.lpfnWndProc = parent_menu_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "TestMenuClass"; + UnregisterClass(cls.lpszClassName, cls.hInstance); + if (!RegisterClassA(&cls)) assert(0); + + SetLastError(0xdeadbeef); + hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + hmenu = LoadMenuA(GetModuleHandle(0), MAKEINTRESOURCE(1)); + ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError()); + + SetMenu(hwnd, hmenu); + SetForegroundWindow( hwnd ); + + set_menu_style(hmenu, MNS_NOTIFYBYPOS); + style = get_menu_style(hmenu); + ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style); + + hmenu_popup = GetSubMenu(hmenu, 0); + ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n"); + style = get_menu_style(hmenu_popup); + ok(style == 0, "expected 0, got %u\n", style); + + hmenu_popup = GetSubMenu(hmenu_popup, 0); + ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n"); + style = get_menu_style(hmenu_popup); + ok(style == 0, "expected 0, got %u\n", style); + + /* Alt+E, Enter */ + trace("testing a popup menu command\n"); + flush_sequence(); + keybd_event(VK_MENU, 0, 0, 0); + keybd_event('E', 0, 0, 0); + keybd_event('E', 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_RETURN, 0, 0, 0); + keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0); + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (!sequence_cnt) /* we didn't get any message */ + { + skip( "queuing key events not supported\n" ); + goto done; + } + /* win98 queues only a WM_KEYUP and doesn't start menu tracking */ + if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU) + { + win_skip( "menu tracking through VK_MENU not supported\n" ); + goto done; + } + ok_sequence(wm_popup_menu_1, "popup menu command", FALSE); + + /* Alt+F, Right, Enter */ + trace("testing submenu of a popup menu command\n"); + flush_sequence(); + keybd_event(VK_MENU, 0, 0, 0); + keybd_event('F', 0, 0, 0); + keybd_event('F', 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_RIGHT, 0, 0, 0); + keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_RETURN, 0, 0, 0); + keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0); + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE); + + set_menu_style(hmenu, 0); + style = get_menu_style(hmenu); + ok(style == 0, "expected 0, got %u\n", style); + + hmenu_popup = GetSubMenu(hmenu, 0); + ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n"); + set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS); + style = get_menu_style(hmenu_popup); + ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style); + + hmenu_popup = GetSubMenu(hmenu_popup, 0); + ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n"); + style = get_menu_style(hmenu_popup); + ok(style == 0, "expected 0, got %u\n", style); + + /* Alt+F, Right, Enter */ + trace("testing submenu of a popup menu command\n"); + flush_sequence(); + keybd_event(VK_MENU, 0, 0, 0); + keybd_event('F', 0, 0, 0); + keybd_event('F', 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_RIGHT, 0, 0, 0); + keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0); + keybd_event(VK_RETURN, 0, 0, 0); + keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0); + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE); + +done: + DestroyWindow(hwnd); + DestroyMenu(hmenu); +} + + +static void test_paintingloop(void) +{ + HWND hwnd; + + paint_loop_done = 0; + hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass", + "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW, + 100, 100, 100, 100, 0, 0, 0, NULL ); + ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError()); + ShowWindow(hwnd,SW_NORMAL); + SetFocus(hwnd); + + while (!paint_loop_done) + { + MSG msg; + if (PeekMessageA(&msg, 0, 0, 0, 1)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + DestroyWindow(hwnd); +} + +static void test_defwinproc(void) +{ + HWND hwnd; + MSG msg; + int gotwmquit = FALSE; + hwnd = CreateWindowExA(0, "static", "test_defwndproc", WS_POPUP, 0,0,0,0,0,0,0, NULL); + assert(hwnd); + DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0); + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) { + if( msg.message == WM_QUIT) gotwmquit = TRUE; + DispatchMessageA( &msg ); + } + ok( gotwmquit == FALSE, "Unexpected WM_QUIT message!\n"); + DestroyWindow( hwnd); +} + +#define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd)) +static void clear_clipboard_(int line, HWND hWnd) +{ + BOOL succ; + succ = OpenClipboard(hWnd); + ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError()); + succ = EmptyClipboard(); + ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError()); + succ = CloseClipboard(); + ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError()); +} + +#define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got)) +static void expect_HWND_(int line, HWND expected, HWND got) +{ + ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got); +} + +static WNDPROC pOldViewerProc; + +static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static BOOL recursion_guard; + + if (message == WM_DRAWCLIPBOARD && !recursion_guard) + { + recursion_guard = TRUE; + clear_clipboard(hWnd); + recursion_guard = FALSE; + } + return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam); +} + +static void test_clipboard_viewers(void) +{ + static struct message wm_change_cb_chain[] = + { + { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 }, + { 0 } + }; + static const struct message wm_clipboard_destroyed[] = + { + { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 }, + { 0 } + }; + static struct message wm_clipboard_changed[] = + { + { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 }, + { 0 } + }; + static struct message wm_clipboard_changed_and_owned[] = + { + { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 }, + { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 }, + { 0 } + }; + + HINSTANCE hInst = GetModuleHandleA(NULL); + HWND hWnd1, hWnd2, hWnd3; + HWND hOrigViewer; + HWND hRet; + + hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + GetDesktopWindow(), NULL, hInst, NULL); + hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + GetDesktopWindow(), NULL, hInst, NULL); + hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3", + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + GetDesktopWindow(), NULL, hInst, NULL); + trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3); + assert(hWnd1 && hWnd2 && hWnd3); + + flush_sequence(); + + /* Test getting the clipboard viewer and setting the viewer to NULL. */ + hOrigViewer = GetClipboardViewer(); + hRet = SetClipboardViewer(NULL); + ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE); + expect_HWND(hOrigViewer, hRet); + expect_HWND(NULL, GetClipboardViewer()); + + /* Test registering hWnd1 as a viewer. */ + hRet = SetClipboardViewer(hWnd1); + wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner(); + ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE); + expect_HWND(NULL, hRet); + expect_HWND(hWnd1, GetClipboardViewer()); + + /* Test that changing the clipboard actually refreshes the registered viewer. */ + clear_clipboard(hWnd1); + wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner(); + ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE); + + /* Again, but with different owner. */ + clear_clipboard(hWnd2); + wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner(); + ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE); + + /* Test re-registering same window. */ + hRet = SetClipboardViewer(hWnd1); + wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner(); + ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE); + expect_HWND(hWnd1, hRet); + expect_HWND(hWnd1, GetClipboardViewer()); + + /* Test ChangeClipboardChain. */ + ChangeClipboardChain(hWnd2, hWnd3); + wm_change_cb_chain[0].wParam = (WPARAM) hWnd2; + wm_change_cb_chain[0].lParam = (LPARAM) hWnd3; + ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE); + expect_HWND(hWnd1, GetClipboardViewer()); + + ChangeClipboardChain(hWnd2, NULL); + wm_change_cb_chain[0].wParam = (WPARAM) hWnd2; + wm_change_cb_chain[0].lParam = 0; + ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE); + expect_HWND(hWnd1, GetClipboardViewer()); + + ChangeClipboardChain(NULL, hWnd2); + ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", TRUE); + expect_HWND(hWnd1, GetClipboardViewer()); + + /* Actually change clipboard viewer with ChangeClipboardChain. */ + ChangeClipboardChain(hWnd1, hWnd2); + ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE); + expect_HWND(hWnd2, GetClipboardViewer()); + + /* Test that no refresh messages are sent when viewer has unregistered. */ + clear_clipboard(hWnd2); + ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE); + + /* Register hWnd1 again. */ + ChangeClipboardChain(hWnd2, hWnd1); + ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE); + expect_HWND(hWnd1, GetClipboardViewer()); + + /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it + * changes the clipboard. When this happens, the system shouldn't send + * another WM_DRAWCLIPBOARD (as this could cause an infinite loop). + */ + pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc); + clear_clipboard(hWnd2); + /* The clipboard owner is changed in recursive_viewer_proc: */ + wm_clipboard_changed[0].wParam = (WPARAM) hWnd2; + ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE); + + /* Test unregistering. */ + ChangeClipboardChain(hWnd1, NULL); + ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE); + expect_HWND(NULL, GetClipboardViewer()); + + clear_clipboard(hWnd1); + ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE); + + DestroyWindow(hWnd1); + DestroyWindow(hWnd2); + DestroyWindow(hWnd3); + SetClipboardViewer(hOrigViewer); +} + +static void test_PostMessage(void) +{ + static const struct + { + HWND hwnd; + BOOL ret; + } data[] = + { + { HWND_TOP /* 0 */, TRUE }, + { HWND_BROADCAST, TRUE }, + { HWND_BOTTOM, TRUE }, + { HWND_TOPMOST, TRUE }, + { HWND_NOTOPMOST, FALSE }, + { HWND_MESSAGE, FALSE }, + { (HWND)0xdeadbeef, FALSE } + }; + int i; + HWND hwnd; + BOOL ret; + MSG msg; + static const WCHAR staticW[] = {'s','t','a','t','i','c',0}; + + SetLastError(0xdeadbeef); + hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL); + if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Skipping some PostMessage tests on Win9x/WinMe\n"); + return; + } + assert(hwnd); + + flush_events(); + + PostMessage(hwnd, WM_USER+1, 0x1234, 0x5678); + PostMessage(0, WM_USER+2, 0x5678, 0x1234); + + for (i = 0; i < sizeof(data)/sizeof(data[0]); i++) + { + memset(&msg, 0xab, sizeof(msg)); + ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE); + ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret); + if (data[i].ret) + { + if (data[i].hwnd) + ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 && + msg.wParam == 0x5678 && msg.lParam == 0x1234, + "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n", + i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam); + else + ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 && + msg.wParam == 0x1234 && msg.lParam == 0x5678, + "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n", + i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd); + } + } + + DestroyWindow(hwnd); + flush_events(); +} + START_TEST(msg) { BOOL ret; - FARPROC pIsWinEventHookInstalled = 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/ + BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/ init_procs(); @@ -10377,25 +12025,22 @@ START_TEST(msg) if (pSetWinEventHook) { - hEvent_hook = (HWINEVENTHOOK)pSetWinEventHook(EVENT_MIN, EVENT_MAX, - GetModuleHandleA(0), - win_event_proc, - 0, - GetCurrentThreadId(), + hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, + GetModuleHandleA(0), win_event_proc, + 0, GetCurrentThreadId(), WINEVENT_INCONTEXT); - assert(hEvent_hook); - - if (pIsWinEventHookInstalled) + if (pIsWinEventHookInstalled && hEvent_hook) { UINT event; for (event = EVENT_MIN; event <= EVENT_MAX; event++) ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event); } } + if (!hEvent_hook) win_skip( "no win event hook support\n" ); cbt_hook_thread_id = GetCurrentThreadId(); hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); - assert(hCBT_hook); + if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" ); test_winevents(); @@ -10410,11 +12055,13 @@ START_TEST(msg) hEvent_hook = 0; #endif + test_PostMessage(); test_ShowWindow(); test_PeekMessage(); test_PeekMessage2(); test_scrollwindowex(); test_messages(); + test_setwindowpos(); test_showwindow(); invisible_parent_tests(); test_mdi_messages(); @@ -10429,15 +12076,16 @@ START_TEST(msg) test_accelerators(); test_timers(); test_timers_no_wnd(); - test_set_hook(); + if (hCBT_hook) test_set_hook(); test_DestroyWindow(); test_DispatchMessage(); test_SendMessageTimeout(); test_edit_messages(); test_quit_message(); + test_SetActiveWindow(); if (!pTrackMouseEvent) - skip("TrackMouseEvent is not available\n"); + win_skip("TrackMouseEvent is not available\n"); else test_TrackMouseEvent(); @@ -10445,11 +12093,18 @@ START_TEST(msg) test_sys_menu(); test_dialog_messages(); test_nullCallback(); - test_SetForegroundWindow(); test_dbcs_wm_char(); + test_menu_messages(); + test_paintingloop(); + test_defwinproc(); + test_clipboard_viewers(); + /* keep it the last test, under Windows it tends to break the tests + * which rely on active/foreground windows being correct. + */ + test_SetForegroundWindow(); UnhookWindowsHookEx(hCBT_hook); - if (pUnhookWinEvent) + if (pUnhookWinEvent && hEvent_hook) { ret = pUnhookWinEvent(hEvent_hook); ok( ret, "UnhookWinEvent error %d\n", GetLastError()); @@ -10459,6 +12114,4 @@ START_TEST(msg) GetLastError() == 0xdeadbeef, /* Win9x */ "unexpected error %d\n", GetLastError()); } - else - skip("UnhookWinEvent is not available\n"); } diff --git a/rostests/winetests/user32/resource.c b/rostests/winetests/user32/resource.c index a8b6c08f3f6..b3118a75e35 100755 --- a/rostests/winetests/user32/resource.c +++ b/rostests/winetests/user32/resource.c @@ -40,7 +40,16 @@ static void test_LoadStringW(void) /* Check that the string which is returned by LoadStringW matches the string at the pointer returned by LoadStringW when called with buflen = 0 */ + SetLastError(0xdeadbeef); length1 = LoadStringW(hInst, 2, (WCHAR *) &resourcepointer, 0); /* get pointer to resource. */ + if (!length1) + { + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + win_skip( "LoadStringW not implemented\n" ); + else + win_skip( "LoadStringW does not return a pointer to the resource\n" ); + return; + } length2 = LoadStringW(hInst, 2, returnedstringw, sizeof(returnedstringw) /sizeof(WCHAR)); /* get resource string */ ok(length2 > 0, "LoadStringW failed to load resource 2, ret %d, err %d\n", length2, GetLastError()); ok(length1 == length2, "LoadStringW returned different values dependent on buflen. ret1 %d, ret2 %d\n", @@ -114,7 +123,8 @@ static void test_LoadStringA (void) "LoadString failed: ret %d err %d\n", ret, GetLastError()); ret = LoadStringA(hInst, 0, buf, 0); - ok( ret == -1, "LoadStringA did not return -1 when called with buflen = 0, got %d, err %d\n", + ok( ret == -1 || broken(ret == 0), + "LoadStringA did not return -1 when called with buflen = 0, got %d, err %d\n", ret, GetLastError()); } @@ -170,41 +180,43 @@ static void test_accel1(void) ok( hAccel != NULL, "create accelerator table\n"); r = CopyAcceleratorTable( hAccel, NULL, 0 ); - ok( r == n, "two entries in table\n"); + ok( r == n || broken(r == 2), /* win9x */ + "two entries in table %u/%u\n", r, n); - r = CopyAcceleratorTable( hAccel, &ac[0], r ); - ok( r == n, "still should be two entries in table\n"); + r = CopyAcceleratorTable( hAccel, &ac[0], n ); + ok( r == n || broken(r == 2), /* win9x */ + "still should be two entries in table %u/%u\n", r, n); n=0; - ok( ac[n].cmd == 1000, "cmd 0 not preserved\n"); - ok( ac[n].key == 'A', "key 0 not preserved\n"); - ok( ac[n].fVirt == (FVIRTKEY | FNOINVERT), "fVirt 0 not preserved\n"); + ok( ac[n].cmd == 1000, "cmd 0 not preserved got %x\n", ac[n].cmd); + ok( ac[n].key == 'A', "key 0 not preserved got %x\n", ac[n].key); + ok( ac[n].fVirt == (FVIRTKEY | FNOINVERT), "fVirt 0 not preserved got %x\n", ac[n].fVirt); - n++; - ok( ac[n].cmd == 0xffff, "cmd 1 not preserved\n"); - ok( ac[n].key == 0xffff, "key 1 not preserved\n"); - ok( ac[n].fVirt == 0x007f, "fVirt 1 not changed\n"); + if (++n == r) goto done; + ok( ac[n].cmd == 0xffff, "cmd 1 not preserved got %x\n", ac[n].cmd); + ok( ac[n].key == 0xffff, "key 1 not preserved got %x\n", ac[n].key); + ok( ac[n].fVirt == 0x007f, "fVirt 1 wrong got %x\n", ac[n].fVirt); - n++; - ok( ac[n].cmd == 0xfff0, "cmd 2 not preserved\n"); - ok( ac[n].key == 0x00ff, "key 2 not preserved\n"); - ok( ac[n].fVirt == 0x0070, "fVirt 2 not changed\n"); + if (++n == r) goto done; + ok( ac[n].cmd == 0xfff0, "cmd 2 not preserved got %x\n", ac[n].cmd); + ok( (ac[n].key & 0xff) == 0xff, "key 2 not preserved got %x\n", ac[n].key); + ok( ac[n].fVirt == 0x0070, "fVirt 2 wrong got %x\n", ac[n].fVirt); - n++; - ok( ac[n].cmd == 0xfff0, "cmd 3 not preserved\n"); - ok( ac[n].key == 0x00ff, "key 3 not preserved\n"); - ok( ac[n].fVirt == 0x0000, "fVirt 3 not changed\n"); - - n++; - ok( ac[n].cmd == 0xfff0, "cmd 4 not preserved\n"); - ok( ac[n].key == 0xffff, "key 4 not preserved\n"); - ok( ac[n].fVirt == 0x0001, "fVirt 4 not changed\n"); + if (++n == r) goto done; + ok( ac[n].cmd == 0xfff0, "cmd 3 not preserved got %x\n", ac[n].cmd); + ok( (ac[n].key & 0xff) == 0xff, "key 3 not preserved got %x\n", ac[n].key); + ok( ac[n].fVirt == 0x0000, "fVirt 3 wrong got %x\n", ac[n].fVirt); + if (++n == r) goto done; + ok( ac[n].cmd == 0xfff0, "cmd 4 not preserved got %x\n", ac[n].cmd); + ok( ac[n].key == 0xffff, "key 4 not preserved got %x\n", ac[n].key); + ok( ac[n].fVirt == 0x0001, "fVirt 4 wrong got %x\n", ac[n].fVirt); +done: r = DestroyAcceleratorTable( hAccel ); ok( r, "destroy accelerator table\n"); hAccel = CreateAcceleratorTable( &ac[0], 0 ); - ok( !hAccel, "zero elements should fail\n"); + ok( !hAccel || broken(hAccel != NULL), /* nt4 */ "zero elements should fail\n"); /* these will on crash win2k hAccel = CreateAcceleratorTable( NULL, 1 ); @@ -220,6 +232,7 @@ static void test_accel2(void) { ACCEL ac[2], out[2]; HACCEL hac; + int res; ac[0].cmd = 0; ac[0].fVirt = 0; @@ -236,8 +249,8 @@ static void test_accel2(void) /* try a zero count */ hac = CreateAcceleratorTable( &ac[0], 0 ); - ok( !hac , "fail\n"); - ok( !DestroyAcceleratorTable( hac ), "destroy failed\n"); + ok( !hac || broken(hac != NULL), /* nt4 */ "fail\n"); + if (!hac) ok( !DestroyAcceleratorTable( hac ), "destroy failed\n"); /* creating one accelerator should work */ hac = CreateAcceleratorTable( &ac[0], 1 ); @@ -248,9 +261,12 @@ static void test_accel2(void) /* how about two of the same type? */ hac = CreateAcceleratorTable( &ac[0], 2); ok( hac != NULL , "fail\n"); - ok( 2 == CopyAcceleratorTable( hac, NULL, 100 ), "copy null failed\n"); - ok( 2 == CopyAcceleratorTable( hac, NULL, 0 ), "copy null failed\n"); - ok( 2 == CopyAcceleratorTable( hac, NULL, 1 ), "copy null failed\n"); + res = CopyAcceleratorTable( hac, NULL, 100 ); + ok( res == 2 || broken(res == 0), /* win9x */ "copy null failed %d\n", res); + res = CopyAcceleratorTable( hac, NULL, 0 ); + ok( res == 2, "copy null failed %d\n", res); + res = CopyAcceleratorTable( hac, NULL, 1 ); + ok( res == 2 || broken(res == 0), /* win9x */ "copy null failed %d\n", res); ok( 1 == CopyAcceleratorTable( hac, out, 1 ), "copy 1 failed\n"); ok( 2 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n"); ok( DestroyAcceleratorTable( hac ), "destroy failed\n"); @@ -301,14 +317,18 @@ static void test_accel2(void) memset( ac, 0xff, sizeof ac ); hac = CreateAcceleratorTable( &ac[0], 2); ok( hac != NULL , "fail\n"); - ok( 2 == CopyAcceleratorTable( hac, out, 2 ), "copy 2 failed\n"); + res = CopyAcceleratorTable( hac, out, 2 ); + ok( res == 2 || broken(res == 1), /* win9x */ "copy 2 failed %d\n", res); /* ok( memcmp( ac, out, sizeof ac ), "tables not different\n"); */ ok( out[0].cmd == ac[0].cmd, "cmd modified\n"); ok( out[0].fVirt == (ac[0].fVirt&0x7f), "fVirt not modified\n"); ok( out[0].key == ac[0].key, "key modified\n"); + if (res == 2) + { ok( out[1].cmd == ac[1].cmd, "cmd modified\n"); ok( out[1].fVirt == (ac[1].fVirt&0x7f), "fVirt not modified\n"); ok( out[1].key == ac[1].key, "key modified\n"); + } ok( DestroyAcceleratorTable( hac ), "destroy failed\n"); } @@ -333,9 +353,13 @@ static void test_PrivateExtractIcons(void) { cIcons = pPrivateExtractIconsA(szShell32Dll, 0, 16, 16, ahIcon, aIconId, 3, 0); ok(cIcons == 3, "Three icons requested got cIcons=%d\n", cIcons); - cIcons = pPrivateExtractIconsA(szShell32Dll, 0, MAKELONG(32,16), MAKELONG(32,16), + /* count must be a multiple of two when getting two sizes */ + cIcons = pPrivateExtractIconsA(szShell32Dll, 0, MAKELONG(16,32), MAKELONG(16,32), ahIcon, aIconId, 3, 0); - ok(cIcons == 4, "Three icons requested, four expected, got cIcons=%d\n", cIcons); + ok(cIcons == 0 /* vista */ || cIcons == 4, "Three icons requested got cIcons=%d\n", cIcons); + cIcons = pPrivateExtractIconsA(szShell32Dll, 0, MAKELONG(16,32), MAKELONG(16,32), + ahIcon, aIconId, 4, 0); + ok(cIcons == 4, "Four icons requested got cIcons=%d\n", cIcons); } static void test_LoadImage(void) diff --git a/rostests/winetests/user32/resource.rc b/rostests/winetests/user32/resource.rc index 7da8a6c2d79..1869475f4a6 100755 --- a/rostests/winetests/user32/resource.rc +++ b/rostests/winetests/user32/resource.rc @@ -98,6 +98,13 @@ BEGIN PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 END +TEST_EMPTY_DIALOG DIALOG DISCARDABLE 0, 0, 186, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN +END + MULTI_EDIT_DIALOG DIALOG DISCARDABLE 0, 0, 160, 75 STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | DS_CENTER CAPTION "Multiple Edit Test" @@ -165,13 +172,16 @@ FONT 8, "MS Shell Dlg" { POPUP "&File" { - MENUITEM "&New", 100 + POPUP "&New..." + { + MENUITEM "&New file", 100 + } MENUITEM "&Open", 101 MENUITEM "&Save", 102 MENUITEM SEPARATOR MENUITEM "E&xit", 103 } - POPUP "Edit" + POPUP "&Edit" { MENUITEM "&Undo", 200 MENUITEM SEPARATOR diff --git a/rostests/winetests/user32/scroll.c b/rostests/winetests/user32/scroll.c index 3bc407a8641..68a2706249e 100644 --- a/rostests/winetests/user32/scroll.c +++ b/rostests/winetests/user32/scroll.c @@ -26,6 +26,7 @@ #include "wine/test.h" static HWND hScroll, hMainWnd; +static BOOL bThemeActive = FALSE; static LRESULT CALLBACK MyWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { @@ -54,15 +55,26 @@ static void scrollbar_test1(void) ret = EnableScrollBar( hScroll, SB_CTL, ESB_DISABLE_BOTH ); ok( ret, "The scrollbar should be disabled.\n" ); - todo_wine - { ok( !IsWindowEnabled( hScroll ), "The scrollbar window should be disabled.\n" ); - } ret = EnableScrollBar( hScroll, SB_CTL, ESB_ENABLE_BOTH ); ok( ret, "The scrollbar should be enabled.\n" ); ok( IsWindowEnabled( hScroll ), "The scrollbar window should be enabled.\n" ); + /* test buttons separately */ + ret = EnableScrollBar( hScroll, SB_CTL, ESB_DISABLE_LTUP ); + ok( ret, "The scrollbar LTUP button should be disabled.\n" ); + ok( IsWindowEnabled( hScroll ), "The scrollbar window should be enabled.\n" ); + ret = EnableScrollBar( hScroll, SB_CTL, ESB_ENABLE_BOTH ); + ok( ret, "The scrollbar should be enabled.\n" ); + ok( IsWindowEnabled( hScroll ), "The scrollbar window should be enabled.\n" ); + + ret = EnableScrollBar( hScroll, SB_CTL, ESB_DISABLE_RTDN ); + ok( ret, "The scrollbar RTDN button should be disabled.\n" ); + ok( IsWindowEnabled( hScroll ), "The scrollbar window should be enabled.\n" ); + ret = EnableScrollBar( hScroll, SB_CTL, ESB_ENABLE_BOTH ); + ok( ret, "The scrollbar should be enabled.\n" ); + ok( IsWindowEnabled( hScroll ), "The scrollbar window should be enabled.\n" ); } static void scrollbar_test2(void) @@ -127,9 +139,261 @@ static void scrollbar_test3(void) } +static void scrollbar_test4(void) +{ + BOOL ret; + SCROLLBARINFO sbi; + RECT rect; + BOOL (WINAPI *pGetScrollBarInfo)(HWND, LONG, LPSCROLLBARINFO); + + pGetScrollBarInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetScrollBarInfo"); + if (!pGetScrollBarInfo) + { + win_skip("GetScrollBarInfo is not available\n"); + return; + } + + /* Test GetScrollBarInfo to make sure it returns rcScrollBar in screen + * coordinates. */ + sbi.cbSize = sizeof(sbi); + ret = pGetScrollBarInfo( hScroll, OBJID_CLIENT, &sbi); + ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + GetWindowRect( hScroll, &rect ); + ok( ret, "The GetWindowRect() call should not fail.\n" ); + ok( !(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)), + "unexpected rgstate(0x%x)\n", sbi.rgstate[0]); + ok( EqualRect(&rect, &sbi.rcScrollBar), + "WindowRect(%d, %d, %d, %d) != rcScrollBar(%d, %d, %d, %d)\n", + rect.top, rect.left, rect.bottom, rect.right, + sbi.rcScrollBar.top, sbi.rcScrollBar.left, + sbi.rcScrollBar.bottom, sbi.rcScrollBar.right ); + + /* Test windows horizontal and vertical scrollbar to make sure rcScrollBar + * is still returned in screen coordinates by moving the window, and + * making sure that it shifts the rcScrollBar value. */ + ShowWindow( hMainWnd, SW_SHOW ); + sbi.cbSize = sizeof(sbi); + ret = pGetScrollBarInfo( hMainWnd, OBJID_HSCROLL, &sbi); + ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + GetWindowRect( hMainWnd, &rect ); + ok( ret, "The GetWindowRect() call should not fail.\n" ); + MoveWindow( hMainWnd, rect.left+5, rect.top+5, + rect.right-rect.left, rect.bottom-rect.top, TRUE ); + rect = sbi.rcScrollBar; + OffsetRect(&rect, 5, 5); + ret = pGetScrollBarInfo( hMainWnd, OBJID_HSCROLL, &sbi); + ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + ok( EqualRect(&rect, &sbi.rcScrollBar), + "PreviousRect(%d, %d, %d, %d) != CurrentRect(%d, %d, %d, %d)\n", + rect.top, rect.left, rect.bottom, rect.right, + sbi.rcScrollBar.top, sbi.rcScrollBar.left, + sbi.rcScrollBar.bottom, sbi.rcScrollBar.right ); + + sbi.cbSize = sizeof(sbi); + ret = pGetScrollBarInfo( hMainWnd, OBJID_VSCROLL, &sbi); + ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + GetWindowRect( hMainWnd, &rect ); + ok( ret, "The GetWindowRect() call should not fail.\n" ); + MoveWindow( hMainWnd, rect.left+5, rect.top+5, + rect.right-rect.left, rect.bottom-rect.top, TRUE ); + rect = sbi.rcScrollBar; + OffsetRect(&rect, 5, 5); + ret = pGetScrollBarInfo( hMainWnd, OBJID_VSCROLL, &sbi); + ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + ok( EqualRect(&rect, &sbi.rcScrollBar), + "PreviousRect(%d, %d, %d, %d) != CurrentRect(%d, %d, %d, %d)\n", + rect.top, rect.left, rect.bottom, rect.right, + sbi.rcScrollBar.top, sbi.rcScrollBar.left, + sbi.rcScrollBar.bottom, sbi.rcScrollBar.right ); +} + +/* some tests designed to show that Horizontal and Vertical + * window scroll bar info are not created independently */ +static void scrollbar_test_default( DWORD style) +{ + INT min, max, ret; + DWORD winstyle; + HWND hwnd; + SCROLLINFO si = { sizeof( SCROLLINFO), SIF_TRACKPOS }; + + hwnd = CreateWindowExA( 0, "static", "", WS_POPUP | style, + 0, 0, 10, 10, 0, 0, 0, NULL); + assert( hwnd != 0); + + ret = GetScrollRange( hwnd, SB_VERT, &min, &max); + ok( ret || + broken( !ret) /* Win 9x/ME */ , "GetScrollRange failed.\n"); + /* range is 0,0 if there are no H or V scroll bars. 0,100 otherwise */ + if( !( style & ( WS_VSCROLL | WS_HSCROLL))) + ok( min == 0 && max == 0, + "Scroll bar range is %d,%d. Expected 0,0. Style %08x\n", min, max, style); + else +todo_wine + ok(( min == 0 && max == 100) || + broken( min == 0 && max == 0), /* Win 9x/ME */ + "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + ret = GetScrollRange( hwnd, SB_HORZ, &min, &max); + ok( ret || + broken( !ret) /* Win 9x/ME */ , "GetScrollRange failed.\n"); + /* range is 0,0 if there are no H or V scroll bars. 0,100 otherwise */ + if( !( style & ( WS_VSCROLL | WS_HSCROLL))) + ok( min == 0 && max == 0, + "Scroll bar range is %d,%d. Expected 0,0. Style %08x\n", min, max, style); + else +todo_wine + ok(( min == 0 && max == 100) || + broken( min == 0 && max == 0), /* Win 9x/ME */ + "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + /* test GetScrollInfo, vist for vertical SB */ + ret = GetScrollInfo( hwnd, SB_VERT, &si); + /* should fail if no H orV scroll bar styles are present. Succeed otherwise */ + if( !( style & ( WS_VSCROLL | WS_HSCROLL))) + ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); + else +todo_wine + ok( ret || + broken( !ret), /* Win 9x/ME */ + "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + /* Same for Horizontal SB */ + ret = GetScrollInfo( hwnd, SB_HORZ, &si); + /* should fail if no H orV scroll bar styles are present. Succeed otherwise */ + if( !( style & ( WS_VSCROLL | WS_HSCROLL))) + ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); + else +todo_wine + ok( ret || + broken( !ret), /* Win 9x/ME */ + "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + /* now set the Vertical Scroll range to something that could be the default value it + * already has */; + ret = SetScrollRange( hwnd, SB_VERT, 0, 100, FALSE); + ok( ret, "SetScrollRange failed.\n"); + /* and request the Horizontal range */ + ret = GetScrollRange( hwnd, SB_HORZ, &min, &max); + ok( ret, "GetScrollRange failed.\n"); + /* now the range should be 0,100 in ALL cases */ + ok( min == 0 && max == 100, + "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + /* See what is different now for GetScrollRange */ + ret = GetScrollInfo( hwnd, SB_HORZ, &si); + /* should succeed in ALL cases */ + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ret = GetScrollInfo( hwnd, SB_VERT, &si); + /* should succeed in ALL cases */ + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + /* report the windows style */ + winstyle = GetWindowLongA( hwnd, GWL_STYLE ); + /* WS_VSCROLL added to the window style */ + if( !(style & WS_VSCROLL)) + { + if (bThemeActive || style != WS_HSCROLL) +todo_wine + ok( (winstyle & (WS_HSCROLL|WS_VSCROLL)) == ( style | WS_VSCROLL), + "unexpected style change %8lx expected %8lx\n", + (winstyle & (WS_HSCROLL|WS_VSCROLL)), style | WS_VSCROLL); + else + ok( (winstyle & (WS_HSCROLL|WS_VSCROLL)) == style || + broken((winstyle & (WS_HSCROLL|WS_VSCROLL)) == (WS_HSCROLL|WS_VSCROLL)), /* Win 9x/ME */ + "unexpected style change %8lx expected %8x\n", + (winstyle & (WS_HSCROLL|WS_VSCROLL)), style); + } + /* do the test again with H and V reversed. + * Start with a clean window */ + DestroyWindow( hwnd); + hwnd = CreateWindowExA( 0, "static", "", WS_POPUP | style, + 0, 0, 10, 10, 0, 0, 0, NULL); + assert( hwnd != 0); + /* Set Horizonta Scroll range to something that could be the default value it + * already has */; + ret = SetScrollRange( hwnd, SB_HORZ, 0, 100, FALSE); + ok( ret, "SetScrollRange failed.\n"); + /* and request the Vertical range */ + ret = GetScrollRange( hwnd, SB_VERT, &min, &max); + ok( ret, "GetScrollRange failed.\n"); + /* now the range should be 0,100 in ALL cases */ + ok( min == 0 && max == 100, + "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + /* See what is different now for GetScrollRange */ + ret = GetScrollInfo( hwnd, SB_HORZ, &si); + /* should succeed in ALL cases */ + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ret = GetScrollInfo( hwnd, SB_VERT, &si); + /* should succeed in ALL cases */ + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + /* report the windows style */ + winstyle = GetWindowLongA( hwnd, GWL_STYLE ); + /* WS_HSCROLL added to the window style */ + if( !(style & WS_HSCROLL)) + { + if (bThemeActive || style != WS_VSCROLL) +todo_wine + ok( (winstyle & (WS_HSCROLL|WS_VSCROLL)) == ( style | WS_HSCROLL), + "unexpected style change %8lx expected %8lx\n", + (winstyle & (WS_HSCROLL|WS_VSCROLL)), style | WS_HSCROLL); + else + ok( (winstyle & (WS_HSCROLL|WS_VSCROLL)) == style || + broken((winstyle & (WS_HSCROLL|WS_VSCROLL)) == (WS_HSCROLL|WS_VSCROLL)), /* Win 9x/ME */ + "unexpected style change %8lx expected %8x\n", + (winstyle & (WS_HSCROLL|WS_VSCROLL)), style); + } + /* Slightly change the test to use SetScrollInfo + * Start with a clean window */ + DestroyWindow( hwnd); + hwnd = CreateWindowExA( 0, "static", "", WS_POPUP | style, + 0, 0, 10, 10, 0, 0, 0, NULL); + assert( hwnd != 0); + /* set Horizontal position with SetScrollInfo */ + si.nPos = 0; + si.nMin = 11; + si.nMax = 22; + si.fMask |= SIF_RANGE; + ret = SetScrollInfo( hwnd, SB_HORZ, &si, FALSE); + ok( ret, "SetScrollInfo failed. Style is %08x\n", style); + /* and request the Vertical range */ + ret = GetScrollRange( hwnd, SB_VERT, &min, &max); + ok( ret, "GetScrollRange failed.\n"); + /* now the range should be 0,100 in ALL cases */ + ok( min == 0 && max == 100, + "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); + /* See what is different now for GetScrollRange */ + ret = GetScrollInfo( hwnd, SB_HORZ, &si); + /* should succeed in ALL cases */ + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + ret = GetScrollInfo( hwnd, SB_VERT, &si); + /* should succeed in ALL cases */ + ok( ret, "GetScrollInfo failed unexpectedly. Style is %08x\n", style); + /* also test if the window scroll bars are enabled */ + ret = EnableScrollBar( hwnd, SB_VERT, ESB_ENABLE_BOTH); + ok( !ret, "Vertical window scroll bar was not enabled\n"); + ret = EnableScrollBar( hwnd, SB_HORZ, ESB_ENABLE_BOTH); + ok( !ret, "Horizontal window scroll bar was not enabled\n"); + DestroyWindow( hwnd); + /* finally, check if adding a WS_[HV]SColl style of a window makes the scroll info + * available */ + if( style & (WS_HSCROLL | WS_VSCROLL)) return;/* only test if not yet set */ + /* Start with a clean window */ + DestroyWindow( hwnd); + hwnd = CreateWindowExA( 0, "static", "", WS_POPUP , + 0, 0, 10, 10, 0, 0, 0, NULL); + assert( hwnd != 0); + ret = GetScrollInfo( hwnd, SB_VERT, &si); + /* should fail */ + ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); + /* add scroll styles */ + winstyle = GetWindowLongA( hwnd, GWL_STYLE ); + SetWindowLongW( hwnd, GWL_STYLE, winstyle | WS_VSCROLL | WS_HSCROLL); + ret = GetScrollInfo( hwnd, SB_VERT, &si); + /* should still fail */ + ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); + /* clean up */ + DestroyWindow( hwnd); +} + START_TEST ( scroll ) { WNDCLASSA wc; + HMODULE hUxtheme; + BOOL (WINAPI * pIsThemeActive)(VOID); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; @@ -143,7 +407,8 @@ START_TEST ( scroll ) wc.lpfnWndProc = MyWndProc; RegisterClassA(&wc); - hMainWnd = CreateWindowExA( 0, "MyTestWnd", "Scroll", WS_OVERLAPPEDWINDOW, + hMainWnd = CreateWindowExA( 0, "MyTestWnd", "Scroll", + WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0 ); if ( !ok( hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n" ) ) @@ -154,6 +419,22 @@ START_TEST ( scroll ) scrollbar_test1(); scrollbar_test2(); scrollbar_test3(); + scrollbar_test4(); + + /* Some test results vary depending of theming being active or not */ + hUxtheme = LoadLibraryA("uxtheme.dll"); + if (hUxtheme) + { + pIsThemeActive = (void*)GetProcAddress(hUxtheme, "IsThemeActive"); + if (pIsThemeActive) + bThemeActive = pIsThemeActive(); + FreeLibrary(hUxtheme); + } + + scrollbar_test_default( 0); + scrollbar_test_default( WS_HSCROLL); + scrollbar_test_default( WS_VSCROLL); + scrollbar_test_default( WS_HSCROLL | WS_VSCROLL); DestroyWindow(hScroll); DestroyWindow(hMainWnd); diff --git a/rostests/winetests/user32/static.c b/rostests/winetests/user32/static.c index 7810db4e399..d04f725138a 100644 --- a/rostests/winetests/user32/static.c +++ b/rostests/winetests/user32/static.c @@ -33,12 +33,12 @@ static HWND hMainWnd; -#define expect_eq(expr, value, type, fmt) { type val = expr; ok(val == (value), #expr " expected " #fmt " got " #fmt "\n", (value), val); } +#define expect_eq(expr, value, type, fmt) { type val = expr; ok(val == (value), #expr " expected " fmt " got " fmt "\n", (value), val); } #define expect_rect(r, _left, _top, _right, _bottom) ok(r.left == _left && r.top == _top && \ r.bottom == _bottom && r.right == _right, "Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", \ r.left, r.top, r.right, r.bottom, _left, _top, _right, _bottom); -int g_nReceivedColorStatic = 0; +static int g_nReceivedColorStatic = 0; static HWND build_static(DWORD style) { @@ -56,6 +56,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara ok(GetClipRgn(hdc, hrgn) == 1, "Static controls during a WM_CTLCOLORSTATIC must have a clipping region\n"); DeleteObject(hrgn); g_nReceivedColorStatic++; + return (LRESULT) GetStockObject(BLACK_BRUSH); } break; } @@ -63,7 +64,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara return DefWindowProc(hwnd, msg, wparam, lparam); } -void test_updates(int style, int flags) +static void test_updates(int style, int flags) { RECT r1 = {20, 20, 30, 30}; HWND hStatic = build_static(style); @@ -81,7 +82,11 @@ void test_updates(int style, int flags) InvalidateRect(hStatic, NULL, FALSE); UpdateWindow(hStatic); - + if( (style & SS_TYPEMASK) == SS_BITMAP) { + HDC hdc = GetDC( hStatic); + COLORREF colour = GetPixel( hdc, 10, 10); + ok ( colour != 0, "pixel should NOT be painted black!\n"); + } if (style != SS_ETCHEDHORZ && style != SS_ETCHEDVERT) exp = 4; else @@ -89,6 +94,10 @@ void test_updates(int style, int flags) if (flags & TODO_COUNT) todo_wine { expect_eq(g_nReceivedColorStatic, exp, int, "%d"); } + else if ((style & SS_TYPEMASK) == SS_ICON || (style & SS_TYPEMASK) == SS_BITMAP) + ok( g_nReceivedColorStatic == exp || + broken(g_nReceivedColorStatic == 0), /* win9x */ + "expected %u got %u\n", exp, g_nReceivedColorStatic ); else expect_eq(g_nReceivedColorStatic, exp, int, "%d"); DestroyWindow(hStatic); @@ -108,7 +117,7 @@ START_TEST(static) wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); wndclass.lpszClassName = szClassName; wndclass.lpszMenuName = NULL; RegisterClassEx(&wndclass); @@ -121,6 +130,7 @@ START_TEST(static) test_updates(SS_SIMPLE, 0); test_updates(SS_ICON, 0); test_updates(SS_BITMAP, 0); + test_updates(SS_BITMAP | SS_CENTERIMAGE, 0); test_updates(SS_BLACKRECT, TODO_COUNT); test_updates(SS_WHITERECT, TODO_COUNT); test_updates(SS_ETCHEDHORZ, TODO_COUNT); diff --git a/rostests/winetests/user32/sysparams.c b/rostests/winetests/user32/sysparams.c index 8e95ffd7da3..0c76290f813 100755 --- a/rostests/winetests/user32/sysparams.c +++ b/rostests/winetests/user32/sysparams.c @@ -23,7 +23,8 @@ #include #undef _WIN32_WINNT -#define _WIN32_WINNT 0x0500 /* For SPI_GETMOUSEHOVERWIDTH and more */ +#define _WIN32_WINNT 0x0600 /* For SPI_GETMOUSEHOVERWIDTH and more */ +#define _WIN32_IE 0x0700 #include "wine/test.h" #include "windef.h" @@ -129,12 +130,16 @@ static HDC hdc; #define SPI_SETPOWEROFFACTIVE_VALNAME "PowerOffActive" #define SPI_SETDRAGFULLWINDOWS_REGKEY "Control Panel\\Desktop" #define SPI_SETDRAGFULLWINDOWS_VALNAME "DragFullWindows" +#define SPI_SETSNAPTODEFBUTTON_REGKEY "Control Panel\\Mouse" +#define SPI_SETSNAPTODEFBUTTON_VALNAME "SnapToDefaultButton" #define SPI_SETMOUSEHOVERWIDTH_REGKEY "Control Panel\\Mouse" #define SPI_SETMOUSEHOVERWIDTH_VALNAME "MouseHoverWidth" #define SPI_SETMOUSEHOVERHEIGHT_REGKEY "Control Panel\\Mouse" #define SPI_SETMOUSEHOVERHEIGHT_VALNAME "MouseHoverHeight" #define SPI_SETMOUSEHOVERTIME_REGKEY "Control Panel\\Mouse" #define SPI_SETMOUSEHOVERTIME_VALNAME "MouseHoverTime" +#define SPI_SETMOUSESCROLLCHARS_REGKEY "Control Panel\\Desktop" +#define SPI_SETMOUSESCROLLCHARS_VALNAME "WheelScrollChars" #define SPI_SETMOUSESCROLLLINES_REGKEY "Control Panel\\Desktop" #define SPI_SETMOUSESCROLLLINES_VALNAME "WheelScrollLines" #define SPI_SETMENUSHOWDELAY_REGKEY "Control Panel\\Desktop" @@ -151,6 +156,7 @@ static DWORD WINAPI SysParamsThreadFunc( LPVOID lpParam ); static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); static int change_counter; +static int change_setworkarea_param, change_iconverticalspacing_param; static int change_last_param; static int last_bpp; static BOOL displaychange_ok = FALSE, displaychange_test_active = FALSE; @@ -171,15 +177,31 @@ static LRESULT CALLBACK SysParamsTestWndProc( HWND hWnd, UINT msg, WPARAM wParam case WM_SETTINGCHANGE: if (change_counter>0) { /* ignore these messages caused by resizing of toolbars */ - if( wParam == SPI_SETWORKAREA || displaychange_test_active) break; - if( change_last_param == SPI_SETWORKAREA) { + if( wParam == SPI_SETWORKAREA){ + change_setworkarea_param = 1; + break; + } else if( wParam == SPI_ICONVERTICALSPACING) { + change_iconverticalspacing_param = 1; + break; + } else if( displaychange_test_active) + break; + if( !change_last_param){ change_last_param = wParam; break; } ok(0,"too many changes counter=%d last change=%d\n", change_counter,change_last_param); + change_counter++; + change_last_param = wParam; + break; } change_counter++; + change_last_param = change_setworkarea_param = change_iconverticalspacing_param =0; + if( wParam == SPI_SETWORKAREA) + change_setworkarea_param = 1; + else if( wParam == SPI_ICONVERTICALSPACING) + change_iconverticalspacing_param = 1; + else change_last_param = wParam; break; @@ -208,7 +230,9 @@ static void test_change_message( int action, int optional ) ok( 1 == change_counter, "Missed a message: change_counter=%d\n", change_counter ); change_counter = 0; - ok( action == change_last_param, + ok( action == change_last_param || + ( change_setworkarea_param && action == SPI_SETWORKAREA) || + ( change_iconverticalspacing_param && action == SPI_ICONVERTICALSPACING), "Wrong action got %d expected %d\n", change_last_param, action ); change_last_param = 0; } @@ -219,13 +243,13 @@ static BOOL test_error_msg ( int rc, const char *name ) if (rc==0) { - if (last_error==0xdeadbeef || last_error==ERROR_INVALID_SPI_VALUE) + if (last_error==0xdeadbeef || last_error==ERROR_INVALID_SPI_VALUE || last_error==ERROR_INVALID_PARAMETER) { - trace("%s not supported on this platform. Skipping test\n", name); + skip("%s not supported on this platform\n", name); } else if (last_error==ERROR_ACCESS_DENIED) { - trace("%s does not have privileges to run. Skipping test\n", name); + skip("%s does not have privileges to run\n", name); } else { @@ -250,7 +274,7 @@ static BOOL test_error_msg ( int rc, const char *name ) * lpsRegName - registry entry name * lpsTestValue - value to test */ -static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName1, LPCSTR valName2, LPCSTR testValue ) +static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName1, LPCSTR valName2, LPCSTR testValue, BOOL optional ) { CHAR value[MAX_PATH]; DWORD valueLen; @@ -336,16 +360,21 @@ static void _test_reg_key( LPCSTR subKey1, LPCSTR subKey2, LPCSTR valName1, LPCS } } } - ok(found,"Missing registry values: %s or %s in keys: %s or %s\n", + ok(found || optional, + "Missing registry values: %s or %s in keys: %s or %s\n", valName1, (valName2?valName2:""), subKey1, (subKey2?subKey2:"") ); } #define test_reg_key( subKey, valName, testValue ) \ - _test_reg_key( subKey, NULL, valName, NULL, testValue ) + _test_reg_key( subKey, NULL, valName, NULL, testValue, FALSE ) +#define test_reg_key_optional( subKey, valName, testValue ) \ + _test_reg_key( subKey, NULL, valName, NULL, testValue, TRUE ) #define test_reg_key_ex( subKey1, subKey2, valName, testValue ) \ - _test_reg_key( subKey1, subKey2, valName, NULL, testValue ) + _test_reg_key( subKey1, subKey2, valName, NULL, testValue, FALSE ) #define test_reg_key_ex2( subKey1, subKey2, valName1, valName2, testValue ) \ - _test_reg_key( subKey1, subKey2, valName1, valName2, testValue ) + _test_reg_key( subKey1, subKey2, valName1, valName2, testValue, FALSE ) +#define test_reg_key_ex2_optional( subKey1, subKey2, valName1, valName2, testValue ) \ + _test_reg_key( subKey1, subKey2, valName1, valName2, testValue, TRUE ) /* get a metric from the registry. If the value is negative * it is assumed to be in twips and converted to pixels */ @@ -454,6 +483,7 @@ static void test_SPI_SETBEEP( void ) /* 2 */ curr_val = TRUE; rc=SystemParametersInfoA( SPI_SETBEEP, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETBEEP")) return; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); test_change_message( SPI_SETBEEP, 0 ); test_reg_key( SPI_SETBEEP_REGKEY, @@ -507,8 +537,7 @@ static const char *setmouse_valuenames[3] = { /* * Runs check for one setting of spi_setmouse. */ -static void run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *proj_change, - int nchange ) +static BOOL run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *proj_change, int nchange ) { BOOL rc; INT mi[3]; @@ -537,6 +566,7 @@ static void run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *pro /* call ascii version on even calls or if unicode is not available */ rc=SystemParametersInfoA( SPI_SETMOUSE, 0, curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); } + if (!test_error_msg(rc,"SPI_SETMOUSE")) return FALSE; ok(rc!=0,"SystemParametersInfo: rc=%d err=%d\n",rc,GetLastError()); test_change_message( SPI_SETMOUSE, 0 ); @@ -578,6 +608,7 @@ static void run_spi_setmouse_test( int curr_val[], POINT *req_change, POINT *pro ok( proj_change[i].y == mv.y, "Projected dy equals real dy. May fail under high load.\n" ); } } + return TRUE; } static void test_SPI_SETMOUSE( void ) /* 4 */ @@ -607,7 +638,7 @@ static void test_SPI_SETMOUSE( void ) /* 4 */ if (!test_error_msg(rc,"SPI_{GET,SET}MOUSE")) return; - run_spi_setmouse_test( curr_val, req_change, proj_change1, nchange ); + if (!run_spi_setmouse_test( curr_val, req_change, proj_change1, nchange )) return; /* acceleration change */ curr_val[2] = 2; @@ -644,7 +675,7 @@ static void test_SPI_SETMOUSE( void ) /* 4 */ ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%d\n",rc,GetLastError()); } -static void test_setborder(UINT curr_val, int usesetborder, int dpi) +static BOOL test_setborder(UINT curr_val, int usesetborder, int dpi) { BOOL rc; UINT border, regval; @@ -656,12 +687,14 @@ static void test_setborder(UINT curr_val, int usesetborder, int dpi) ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); if( usesetborder) { rc=SystemParametersInfoA( SPI_SETBORDER, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETBORDER")) return FALSE; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); test_change_message( SPI_SETBORDER, 1 ); } else { /* set non client metrics */ ncm.iBorderWidth = curr_val; rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, 0, &ncm, SPIF_UPDATEINIFILE| SPIF_SENDCHANGE); + if (!test_error_msg(rc,"SPI_SETNONCLIENTMETRICS")) return FALSE; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); test_change_message( SPI_SETNONCLIENTMETRICS, 1 ); } @@ -687,6 +720,7 @@ static void test_setborder(UINT curr_val, int usesetborder, int dpi) eq( frame, GetSystemMetrics( SM_CYFRAME ), "SM_CYFRAME", "%d" ); eq( frame, GetSystemMetrics( SM_CXSIZEFRAME ), "SM_CXSIZEFRAME", "%d" ); eq( frame, GetSystemMetrics( SM_CYSIZEFRAME ), "SM_CYSIZEFRAME", "%d" ); + return TRUE; } static void test_SPI_SETBORDER( void ) /* 6 */ @@ -694,11 +728,15 @@ static void test_SPI_SETBORDER( void ) /* 6 */ BOOL rc; UINT old_border; NONCLIENTMETRICSA ncmsave; - INT CaptionWidth; + INT CaptionWidth, + PaddedBorderWidth; ncmsave.cbSize = sizeof( ncmsave); rc=SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncmsave, 0); - ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); + if( !rc) { + win_skip("SPI_GETNONCLIENTMETRICS is not available\n"); + return; + } /* CaptionWidth from the registry may have different value of iCaptionWidth * from the non client metrics (observed on WinXP). * Fix this so we can safely restore settings with the nonclientmetrics */ @@ -719,6 +757,13 @@ static void test_SPI_SETBORDER( void ) /* 6 */ rc=SystemParametersInfoA( SPI_GETBORDER, 0, &old_border, 0 ); if (!test_error_msg(rc,"SPI_{GET,SET}BORDER")) return; + /* FIXME: include new PaddedBorderWidth parameter */ + PaddedBorderWidth = ncmsave.iBorderWidth - old_border; + if( PaddedBorderWidth){ + win_skip( "Cannot reliably restore border width yet (PaddedBorderWidth = %d)\n", + PaddedBorderWidth); + return; + } /* This will restore sane values if the test hang previous run. */ if ( old_border == 7 || old_border == 20 ) old_border = 1; @@ -728,11 +773,11 @@ static void test_SPI_SETBORDER( void ) /* 6 */ * those platforms */ if( !iswin9x) { /* win2k3 fails if you set the same border twice, or if size is 0 */ - test_setborder(2, 1, dpi); + if (!test_setborder(2, 1, dpi)) return; test_setborder(1, 1, dpi); test_setborder(3, 1, dpi); } - test_setborder(1, 0, dpi); + if (!test_setborder(1, 0, dpi)) return; test_setborder(0, 0, dpi); test_setborder(3, 0, dpi); @@ -763,6 +808,7 @@ static void test_SPI_SETKEYBOARDSPEED( void ) /* 10 */ rc=SystemParametersInfoA( SPI_SETKEYBOARDSPEED, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETKEYBOARDSPEED")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); test_change_message( SPI_SETKEYBOARDSPEED, 0 ); sprintf( buf, "%d", vals[i] ); @@ -778,7 +824,7 @@ static void test_SPI_SETKEYBOARDSPEED( void ) /* 10 */ } /* test_SPI_ICONHORIZONTALSPACING helper */ -static void dotest_spi_iconhorizontalspacing( INT curr_val) +static BOOL dotest_spi_iconhorizontalspacing( INT curr_val) { BOOL rc; INT spacing, regval; @@ -786,6 +832,7 @@ static void dotest_spi_iconhorizontalspacing( INT curr_val) rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); + if (!test_error_msg(rc,"SPI_ICONHORIZONTALSPACING")) return FALSE; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); test_change_message( SPI_ICONHORIZONTALSPACING, 0 ); if( curr_val < 32) curr_val = 32; @@ -808,6 +855,7 @@ static void dotest_spi_iconhorizontalspacing( INT curr_val) rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im, FALSE ); ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); eq( im.iHorzSpacing, curr_val, "SPI_GETICONMETRICS", "%d" ); + return TRUE; } static void test_SPI_ICONHORIZONTALSPACING( void ) /* 13 */ @@ -822,7 +870,7 @@ static void test_SPI_ICONHORIZONTALSPACING( void ) /* 13 */ if (!test_error_msg(rc,"SPI_ICONHORIZONTALSPACING")) return; /* do not increase the value as it would upset the user's icon layout */ - dotest_spi_iconhorizontalspacing( old_spacing - 1); + if (!dotest_spi_iconhorizontalspacing( old_spacing - 1)) return; dotest_spi_iconhorizontalspacing( 10); /* minimum is 32 */ /* restore */ rc=SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, old_spacing, 0, SPIF_UPDATEINIFILE ); @@ -849,6 +897,7 @@ static void test_SPI_SETSCREENSAVETIMEOUT( void ) /* 14 */ rc=SystemParametersInfoA( SPI_SETSCREENSAVETIMEOUT, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETSCREENSAVETIMEOUT")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); test_change_message( SPI_SETSCREENSAVETIMEOUT, 0 ); sprintf( buf, "%d", vals[i] ); @@ -884,6 +933,7 @@ static void test_SPI_SETSCREENSAVEACTIVE( void ) /* 17 */ rc=SystemParametersInfoA( SPI_SETSCREENSAVEACTIVE, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETSCREENSAVEACTIVE")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); test_change_message( SPI_SETSCREENSAVEACTIVE, 0 ); test_reg_key( SPI_SETSCREENSAVEACTIVE_REGKEY, @@ -892,7 +942,8 @@ static void test_SPI_SETSCREENSAVEACTIVE( void ) /* 17 */ rc=SystemParametersInfoA( SPI_GETSCREENSAVEACTIVE, 0, &v, 0 ); ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); - eq( v, vals[i], "SPI_{GET,SET}SCREENSAVEACTIVE", "%d" ); + ok(v == vals[i] || broken(! v) /* Win 7 */, + "SPI_{GET,SET}SCREENSAVEACTIVE: got %d instead of %d\n", v, vals[i]); } rc=SystemParametersInfoA( SPI_SETSCREENSAVEACTIVE, old_b, 0, SPIF_UPDATEINIFILE ); @@ -924,6 +975,7 @@ static void test_SPI_SETKEYBOARDDELAY( void ) /* 23 */ rc=SystemParametersInfoA( SPI_SETKEYBOARDDELAY, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETKEYBOARDDELAY")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); test_change_message( SPI_SETKEYBOARDDELAY, 0 ); sprintf( buf, "%d", vals[i] ); @@ -941,7 +993,7 @@ static void test_SPI_SETKEYBOARDDELAY( void ) /* 23 */ /* test_SPI_ICONVERTICALSPACING helper */ -static void dotest_spi_iconverticalspacing( INT curr_val) +static BOOL dotest_spi_iconverticalspacing( INT curr_val) { BOOL rc; INT spacing, regval; @@ -949,6 +1001,7 @@ static void dotest_spi_iconverticalspacing( INT curr_val) rc=SystemParametersInfoA( SPI_ICONVERTICALSPACING, curr_val, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); + if (!test_error_msg(rc,"SPI_ICONVERTICALSPACING")) return FALSE; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); test_change_message( SPI_ICONVERTICALSPACING, 0 ); if( curr_val < 32) curr_val = 32; @@ -971,6 +1024,7 @@ static void dotest_spi_iconverticalspacing( INT curr_val) rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im, FALSE ); ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); eq( im.iVertSpacing, curr_val, "SPI_GETICONMETRICS", "%d" ); + return TRUE; } static void test_SPI_ICONVERTICALSPACING( void ) /* 24 */ @@ -985,7 +1039,7 @@ static void test_SPI_ICONVERTICALSPACING( void ) /* 24 */ if (!test_error_msg(rc,"SPI_ICONVERTICALSPACING")) return; /* do not increase the value as it would upset the user's icon layout */ - dotest_spi_iconverticalspacing( old_spacing - 1); + if (!dotest_spi_iconverticalspacing( old_spacing - 1)) return; /* same tests with a value less than the minimum 32 */ dotest_spi_iconverticalspacing( 10); /* restore */ @@ -1023,6 +1077,7 @@ static void test_SPI_SETICONTITLEWRAP( void ) /* 26 */ rc=SystemParametersInfoA( SPI_SETICONTITLEWRAP, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETICONTITLEWRAP")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); test_change_message( SPI_SETICONTITLEWRAP, 1 ); regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY2, @@ -1030,7 +1085,7 @@ static void test_SPI_SETICONTITLEWRAP( void ) /* 26 */ if( regval != vals[i]) regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY1, SPI_SETICONTITLEWRAP_VALNAME, dpi); - ok( regval == vals[i], + ok( regval == vals[i] || broken(regval == -1), /* win9x */ "wrong value in registry %d, expected %d\n", regval, vals[i] ); rc=SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0, &v, 0 ); @@ -1066,6 +1121,7 @@ static void test_SPI_SETMENUDROPALIGNMENT( void ) /* 28 */ rc=SystemParametersInfoA( SPI_SETMENUDROPALIGNMENT, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETMENUDROPALIGNMENT")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); test_change_message( SPI_SETMENUDROPALIGNMENT, 0 ); test_reg_key_ex( SPI_SETMENUDROPALIGNMENT_REGKEY1, @@ -1224,8 +1280,7 @@ static void test_SPI_SETMOUSEBUTTONSWAP( void ) /* 33 */ SetLastError(0xdeadbeef); rc=SystemParametersInfoA( SPI_SETMOUSEBUTTONSWAP, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); - if (!test_error_msg(rc,"SPI_{GET,SET}MOUSEBUTTONSWAP")) - break; + if (!test_error_msg(rc,"SPI_SETMOUSEBUTTONSWAP")) return; test_change_message( SPI_SETMOUSEBUTTONSWAP, 0 ); test_reg_key( SPI_SETMOUSEBUTTONSWAP_REGKEY, @@ -1281,6 +1336,7 @@ static void test_SPI_SETDRAGFULLWINDOWS( void ) /* 37 */ rc=SystemParametersInfoA( SPI_SETDRAGFULLWINDOWS, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETDRAGFULLWINDOWS")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); test_change_message( SPI_SETDRAGFULLWINDOWS, 0 ); test_reg_key( SPI_SETDRAGFULLWINDOWS_REGKEY, @@ -1321,7 +1377,7 @@ static void test_SPI_SETDRAGFULLWINDOWS( void ) /* 37 */ } #define TEST_NONCLIENTMETRICS_REG( ncm) \ -test_reg_metric2( SPI_SETBORDER_REGKEY2, SPI_SETBORDER_REGKEY, SPI_SETBORDER_VALNAME, (ncm).iBorderWidth);\ +/*FIXME: test_reg_metric2( SPI_SETBORDER_REGKEY2, SPI_SETBORDER_REGKEY, SPI_SETBORDER_VALNAME, (ncm).iBorderWidth);*/\ test_reg_metric( SPI_METRIC_REGKEY, SPI_SCROLLWIDTH_VALNAME, (ncm).iScrollWidth);\ test_reg_metric( SPI_METRIC_REGKEY, SPI_SCROLLHEIGHT_VALNAME, (ncm).iScrollHeight);\ /*FIXME: test_reg_metric( SPI_METRIC_REGKEY, SPI_CAPTIONWIDTH_VALNAME, (ncm).iCaptionWidth);*/\ @@ -1348,6 +1404,7 @@ static int get_tmheight( LOGFONTA *plf, int flag) } static void test_GetSystemMetrics( void); +static UINT smcxsmsize = 999999999; static void test_SPI_SETNONCLIENTMETRICS( void ) /* 44 */ { @@ -1364,11 +1421,13 @@ static void test_SPI_SETNONCLIENTMETRICS( void ) /* 44 */ Ncmstart.cbSize = sizeof(NONCLIENTMETRICSA); trace("testing SPI_{GET,SET}NONCLIENTMETRICS\n"); + change_counter = 0; SetLastError(0xdeadbeef); rc=SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &Ncmorig, FALSE ); if (!test_error_msg(rc,"SPI_{GET,SET}NONCLIENTMETRICS")) return; Ncmstart = Ncmorig; + smcxsmsize = Ncmstart.iSmCaptionWidth; /* SPI_GETNONCLIENTMETRICS returns some "cooked" values. For instance if the caption font height is higher than the CaptionHeight field, the latter is adjusted accordingly. To be able to restore these setting @@ -1408,6 +1467,7 @@ static void test_SPI_SETNONCLIENTMETRICS( void ) /* 44 */ rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, 0, &Ncmnew, SPIF_UPDATEINIFILE| SPIF_SENDCHANGE); + if (!test_error_msg(rc,"SPI_SETNONCLIENTMETRICS")) return; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); test_change_message( SPI_SETNONCLIENTMETRICS, 1 ); /* get them back */ @@ -1415,7 +1475,7 @@ static void test_SPI_SETNONCLIENTMETRICS( void ) /* 44 */ ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); /* test registry entries */ TEST_NONCLIENTMETRICS_REG( Ncmcur) - /* test the systemm metrics with these settings */ + /* test the system metrics with these settings */ test_GetSystemMetrics(); /* now for something invalid: increase the {menu|caption|smcaption} fonts by a large amount will increase the {menu|caption|smcaption} height*/ @@ -1450,19 +1510,22 @@ static void test_SPI_SETNONCLIENTMETRICS( void ) /* 44 */ "SmCaptionHeight: %d expected %d\n", Ncmcur.iSmCaptionHeight, expect); ok( Ncmcur.iCaptionWidth == 8 || + Ncmcur.iCaptionWidth == 12 || /* Vista, W7b */ Ncmcur.iCaptionWidth == Ncmstart.iCaptionWidth, /* with windows XP theme, the value never changes */ - "CaptionWidth: %d expected 8\n", Ncmcur.iCaptionWidth); + "CaptionWidth: %d expected 8, 12 or %d\n", Ncmcur.iCaptionWidth, Ncmstart.iCaptionWidth); ok( Ncmcur.iScrollWidth == 8, "ScrollWidth: %d expected 8\n", Ncmcur.iScrollWidth); ok( Ncmcur.iScrollHeight == 8, "ScrollHeight: %d expected 8\n", Ncmcur.iScrollHeight); - /* test the systemm metrics with these settings */ + /* test the system metrics with these settings */ test_GetSystemMetrics(); /* restore */ rc=SystemParametersInfoA( SPI_SETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &Ncmorig, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); test_change_message( SPI_SETNONCLIENTMETRICS, 0 ); ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%d\n",rc,GetLastError()); + /* test the system metrics with these settings */ + test_GetSystemMetrics(); } static void test_SPI_SETMINIMIZEDMETRICS( void ) /* 44 */ @@ -1504,6 +1567,7 @@ static void test_SPI_SETMINIMIZEDMETRICS( void ) /* 44 */ lpMm_cur.iArrange = 5; rc=SystemParametersInfoA( SPI_SETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &lpMm_cur, SPIF_UPDATEINIFILE ); + if (!test_error_msg(rc,"SPI_SETMINIMIZEDMETRICS")) return; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); /* read them back */ rc=SystemParametersInfoA( SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &lpMm_new, FALSE ); @@ -1610,9 +1674,11 @@ static void test_SPI_SETICONMETRICS( void ) /* 46 */ return; /* check some registry values */ regval = metricfromreg( SPI_ICONHORIZONTALSPACING_REGKEY, SPI_ICONHORIZONTALSPACING_VALNAME, dpi); - ok( regval==im_orig.iHorzSpacing, "wrong value in registry %d, expected %d\n", regval, im_orig.iHorzSpacing); + ok( regval==im_orig.iHorzSpacing || broken(regval == -1), /* nt4 */ + "wrong value in registry %d, expected %d\n", regval, im_orig.iHorzSpacing); regval = metricfromreg( SPI_ICONVERTICALSPACING_REGKEY, SPI_ICONVERTICALSPACING_VALNAME, dpi); - ok( regval==im_orig.iVertSpacing, "wrong value in registry %d, expected %d\n", regval, im_orig.iVertSpacing); + ok( regval==im_orig.iVertSpacing || broken(regval == -1), /* nt4 */ + "wrong value in registry %d, expected %d\n", regval, im_orig.iVertSpacing); regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY2, SPI_SETICONTITLEWRAP_VALNAME, dpi); if( regval != im_orig.iTitleWrap) regval = metricfromreg( SPI_SETICONTITLEWRAP_REGKEY1, SPI_SETICONTITLEWRAP_VALNAME, dpi); @@ -1644,6 +1710,7 @@ static void test_SPI_SETICONMETRICS( void ) /* 46 */ strcpy( im_cur.lfFont.lfFaceName, "MS Sans Serif"); rc=SystemParametersInfoA( SPI_SETICONMETRICS, sizeof(ICONMETRICSA), &im_cur, SPIF_UPDATEINIFILE ); + if (!test_error_msg(rc,"SPI_SETICONMETRICS")) return; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); rc=SystemParametersInfoA( SPI_GETICONMETRICS, sizeof(ICONMETRICSA), &im_new, FALSE ); @@ -1731,25 +1798,34 @@ static void test_SPI_SETWORKAREA( void ) /* 47 */ curr_val.bottom = old_area.bottom-1; rc=SystemParametersInfoA( SPI_SETWORKAREA, 0, &curr_val, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETWORKAREA")) return; ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); - test_change_message( SPI_SETWORKAREA, 0 ); rc=SystemParametersInfoA( SPI_GETWORKAREA, 0, &area, 0 ); ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); + if( !EqualRect( &area, &curr_val)) /* no message if rect has not changed */ + test_change_message( SPI_SETWORKAREA, 0); eq( area.left, curr_val.left, "left", "%d" ); eq( area.top, curr_val.top, "top", "%d" ); - eq( area.right, curr_val.right, "right", "%d" ); - eq( area.bottom, curr_val.bottom, "bottom", "%d" ); - + /* size may be rounded */ + ok( area.right >= curr_val.right - 16 && area.right < curr_val.right + 16, + "right: got %d instead of %d\n", area.right, curr_val.right ); + ok( area.bottom >= curr_val.bottom - 16 && area.bottom < curr_val.bottom + 16, + "bottom: got %d instead of %d\n", area.bottom, curr_val.bottom ); + curr_val = area; rc=SystemParametersInfoA( SPI_SETWORKAREA, 0, &old_area, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%d\n",rc,GetLastError()); - test_change_message( SPI_SETWORKAREA, 0 ); rc=SystemParametersInfoA( SPI_GETWORKAREA, 0, &area, 0 ); ok(rc!=0,"SystemParametersInfoA: rc=%d err=%d\n",rc,GetLastError()); + if( !EqualRect( &area, &curr_val)) /* no message if rect has not changed */ + test_change_message( SPI_SETWORKAREA, 0 ); eq( area.left, old_area.left, "left", "%d" ); eq( area.top, old_area.top, "top", "%d" ); - eq( area.right, old_area.right, "right", "%d" ); - eq( area.bottom, old_area.bottom, "bottom", "%d" ); + /* size may be rounded */ + ok( area.right >= old_area.right - 16 && area.right < old_area.right + 16, + "right: got %d instead of %d\n", area.right, old_area.right ); + ok( area.bottom >= old_area.bottom - 16 && area.bottom < old_area.bottom + 16, + "bottom: got %d instead of %d\n", area.bottom, old_area.bottom ); } static void test_SPI_SETSHOWSOUNDS( void ) /* 57 */ @@ -1772,8 +1848,9 @@ static void test_SPI_SETSHOWSOUNDS( void ) /* 57 */ rc=SystemParametersInfoA( SPI_SETSHOWSOUNDS, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETSHOWSOUNDS")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); - test_change_message( SPI_SETSHOWSOUNDS, 0 ); + test_change_message( SPI_SETSHOWSOUNDS, 1 ); test_reg_key( SPI_SETSHOWSOUNDS_REGKEY, SPI_SETSHOWSOUNDS_VALNAME, vals[i] ? "1" : "0" ); @@ -1808,8 +1885,9 @@ static void test_SPI_SETKEYBOARDPREF( void ) /* 69 */ rc=SystemParametersInfoA( SPI_SETKEYBOARDPREF, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETKEYBOARDPREF")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); - test_change_message( SPI_SETKEYBOARDPREF, 0 ); + test_change_message( SPI_SETKEYBOARDPREF, 1 ); test_reg_key_ex2( SPI_SETKEYBOARDPREF_REGKEY, SPI_SETKEYBOARDPREF_REGKEY_LEGACY, SPI_SETKEYBOARDPREF_VALNAME, SPI_SETKEYBOARDPREF_VALNAME_LEGACY, vals[i] ? "1" : "0" ); @@ -1842,9 +1920,10 @@ static void test_SPI_SETSCREENREADER( void ) /* 71 */ rc=SystemParametersInfoA( SPI_SETSCREENREADER, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETSCREENREADER")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); - test_change_message( SPI_SETSCREENREADER, 0 ); - test_reg_key_ex2( SPI_SETSCREENREADER_REGKEY, SPI_SETSCREENREADER_REGKEY_LEGACY, + test_change_message( SPI_SETSCREENREADER, 1 ); + test_reg_key_ex2_optional( SPI_SETSCREENREADER_REGKEY, SPI_SETSCREENREADER_REGKEY_LEGACY, SPI_SETSCREENREADER_VALNAME, SPI_SETSCREENREADER_VALNAME_LEGACY, vals[i] ? "1" : "0" ); @@ -1877,6 +1956,7 @@ static void test_SPI_SETFONTSMOOTHING( void ) /* 75 */ rc=SystemParametersInfoA( SPI_SETFONTSMOOTHING, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETFONTSMOOTHING")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); test_change_message( SPI_SETFONTSMOOTHING, 0 ); test_reg_key( SPI_SETFONTSMOOTHING_REGKEY, @@ -1911,15 +1991,21 @@ static void test_SPI_SETLOWPOWERACTIVE( void ) /* 85 */ rc=SystemParametersInfoA( SPI_SETLOWPOWERACTIVE, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETLOWPOWERACTIVE")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); - test_change_message( SPI_SETLOWPOWERACTIVE, 0 ); - test_reg_key( SPI_SETLOWPOWERACTIVE_REGKEY, + test_change_message( SPI_SETLOWPOWERACTIVE, 1 ); + test_reg_key_optional( SPI_SETLOWPOWERACTIVE_REGKEY, SPI_SETLOWPOWERACTIVE_VALNAME, vals[i] ? "1" : "0" ); + /* SPI_SETLOWPOWERACTIVE is not persistent in win2k3 and above */ + v = 0xdeadbeef; rc=SystemParametersInfoA( SPI_GETLOWPOWERACTIVE, 0, &v, 0 ); ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); - eq( v, vals[i], "SPI_GETLOWPOWERACTIVE", "%d" ); + ok(v == vals[i] || + broken(v == (0xdead0000 | vals[i])) || /* win98 only sets the low word */ + v == 0, /* win2k3 */ + "SPI_GETLOWPOWERACTIVE: got %d instead of 0 or %d\n", v, vals[i]); } rc=SystemParametersInfoA( SPI_SETLOWPOWERACTIVE, old_b, 0, SPIF_UPDATEINIFILE ); @@ -1945,21 +2031,62 @@ static void test_SPI_SETPOWEROFFACTIVE( void ) /* 86 */ rc=SystemParametersInfoA( SPI_SETPOWEROFFACTIVE, vals[i], 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE ); + if (!test_error_msg(rc,"SPI_SETPOWEROFFACTIVE")) return; ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); - test_change_message( SPI_SETPOWEROFFACTIVE, 0 ); - test_reg_key( SPI_SETPOWEROFFACTIVE_REGKEY, + test_change_message( SPI_SETPOWEROFFACTIVE, 1 ); + test_reg_key_optional( SPI_SETPOWEROFFACTIVE_REGKEY, SPI_SETPOWEROFFACTIVE_VALNAME, vals[i] ? "1" : "0" ); + /* SPI_SETPOWEROFFACTIVE is not persistent in win2k3 and above */ + v = 0xdeadbeef; rc=SystemParametersInfoA( SPI_GETPOWEROFFACTIVE, 0, &v, 0 ); ok(rc!=0,"%d: rc=%d err=%d\n",i,rc,GetLastError()); - eq( v, vals[i], "SPI_GETPOWEROFFACTIVE", "%d" ); + ok(v == vals[i] || + broken(v == (0xdead0000 | vals[i])) || /* win98 only sets the low word */ + v == 0, /* win2k3 */ + "SPI_GETPOWEROFFACTIVE: got %d instead of 0 or %d\n", v, vals[i]); } rc=SystemParametersInfoA( SPI_SETPOWEROFFACTIVE, old_b, 0, SPIF_UPDATEINIFILE ); ok(rc!=0,"***warning*** failed to restore the original value: rc=%d err=%d\n",rc,GetLastError()); } +static void test_SPI_SETSNAPTODEFBUTTON( void ) /* 95 */ +{ + BOOL rc; + BOOL old_b; + const UINT vals[]={TRUE,FALSE}; + unsigned int i; + + trace("testing SPI_{GET,SET}SNAPTODEFBUTTON\n"); + SetLastError(0xdeadbeef); + rc=SystemParametersInfoA( SPI_GETSNAPTODEFBUTTON, 0, &old_b, 0 ); + if (!test_error_msg(rc,"SPI_GETSNAPTODEFBUTTON")) + return; + + for (i=0;i= 0 ? CaptionWidthfromreg : ncm.iCaptionWidth, 8) + + GetSystemMetrics( SM_CYSIZE) + 4 + 4 * avcwCaption + 2 * GetSystemMetrics( SM_CXFRAME)); ok_gsm( SM_CYMIN, GetSystemMetrics( SM_CYCAPTION) + 2 * GetSystemMetrics( SM_CYFRAME)); ok_gsm_2( SM_CXSIZE, @@ -2464,8 +2652,9 @@ static void test_GetSystemMetrics( void) /* SM_SECURE */ ok_gsm( SM_CXEDGE, 2); ok_gsm( SM_CYEDGE, 2); - ok_gsm( SM_CXMINSPACING, GetSystemMetrics( SM_CXMINIMIZED) + minim.iHorzGap ); - ok_gsm( SM_CYMINSPACING, GetSystemMetrics( SM_CYMINIMIZED) + minim.iVertGap ); + /* sign-extension for iHorzGap/iVertGap is broken on Win9x */ + ok_gsm( SM_CXMINSPACING, GetSystemMetrics( SM_CXMINIMIZED) + (short)minim.iHorzGap ); + ok_gsm( SM_CYMINSPACING, GetSystemMetrics( SM_CYMINIMIZED) + (short)minim.iVertGap ); /* SM_CXSMICON */ /* SM_CYSMICON */ ok_gsm( SM_CYSMCAPTION, ncm.iSmCaptionHeight + 1); @@ -2481,10 +2670,17 @@ static void test_GetSystemMetrics( void) /* SM_ARRANGE */ ok_gsm( SM_CXMINIMIZED, minim.iWidth + 6); ok_gsm( SM_CYMINIMIZED, GetSystemMetrics( SM_CYCAPTION) + 5); - ok_gsm( SM_CXMAXTRACK, GetSystemMetrics( SM_CXVIRTUALSCREEN) + - 4 + 2 * GetSystemMetrics( SM_CXFRAME)); - ok_gsm( SM_CYMAXTRACK, GetSystemMetrics( SM_CYVIRTUALSCREEN) + - 4 + 2 * GetSystemMetrics( SM_CYFRAME)); + screen.cx = GetSystemMetrics( SM_CXVIRTUALSCREEN ); + screen.cy = GetSystemMetrics( SM_CYVIRTUALSCREEN ); + if (!screen.cx || !screen.cy) /* not supported on NT4 */ + { + screen.cx = GetSystemMetrics( SM_CXSCREEN ); + screen.cy = GetSystemMetrics( SM_CYSCREEN ); + } + ok_gsm_2( SM_CXMAXTRACK, screen.cx + 4 + 2 * GetSystemMetrics(SM_CXFRAME), + screen.cx - 4 + 2 * GetSystemMetrics(SM_CXFRAME)); /* Vista */ + ok_gsm_2( SM_CYMAXTRACK, screen.cy + 4 + 2 * GetSystemMetrics(SM_CYFRAME), + screen.cy - 4 + 2 * GetSystemMetrics(SM_CYFRAME)); /* Vista */ /* the next two cannot really be tested as they depend on (application) * toolbars */ /* SM_CXMAXIMIZED */ @@ -2522,8 +2718,8 @@ static void test_GetSystemMetrics( void) ncm.iBorderWidth, ncm.iCaptionWidth, ncm.iCaptionHeight, IconSpacing, IconVerticalSpacing); trace( "MenuHeight %d MenuWidth %d ScrollHeight %d ScrollWidth %d SmCaptionHeight %d SmCaptionWidth %d\n", ncm.iMenuHeight, ncm.iMenuWidth, ncm.iScrollHeight, ncm.iScrollWidth, ncm.iSmCaptionHeight, ncm.iSmCaptionWidth); - trace( "Captionfontchar width %d MenuFont %d,%d CaptionWidth from registry: %d\n", - avcwCaption, tmMenuFont.tmHeight, tmMenuFont.tmExternalLeading, CaptionWidth); + trace( "Captionfontchar width %d MenuFont %d,%d CaptionWidth from registry: %d screen %d,%d\n", + avcwCaption, tmMenuFont.tmHeight, tmMenuFont.tmExternalLeading, CaptionWidthfromreg, screen.cx, screen.cy); } ReleaseDC( 0, hdc); } @@ -2536,12 +2732,14 @@ static void test_EnumDisplaySettings(void) DWORD num; memset(&devmode, 0, sizeof(devmode)); - devmode.dmSize = sizeof(devmode); + /* Win95 doesn't handle ENUM_CURRENT_SETTINGS correctly */ EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devmode); hdc = GetDC(0); val = GetDeviceCaps(hdc, BITSPIXEL); - ok(devmode.dmBitsPerPel == val, "GetDeviceCaps(BITSPIXEL) returned %d, EnumDisplaySettings returned %d\n", + ok(devmode.dmBitsPerPel == val || + broken(devmode.dmDeviceName[0] == 0), /* Win95 */ + "GetDeviceCaps(BITSPIXEL) returned %d, EnumDisplaySettings returned %d\n", val, devmode.dmBitsPerPel); val = GetDeviceCaps(hdc, NUMCOLORS); @@ -2604,8 +2802,8 @@ START_TEST(sysparams) wc.lpfnWndProc = SysParamsTestWndProc; wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; wc.hInstance = hInstance; - wc.hIcon = LoadIconA( 0, (LPSTR)IDI_APPLICATION ); - wc.hCursor = LoadCursorA( 0, (LPSTR)IDC_ARROW ); + wc.hIcon = LoadIconA( 0, IDI_APPLICATION ); + wc.hCursor = LoadCursorA( 0, IDC_ARROW ); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 ); wc.lpszMenuName = 0; wc.cbClsExtra = 0; diff --git a/rostests/winetests/user32/text.c b/rostests/winetests/user32/text.c index 1e096501640..3ea046ae149 100755 --- a/rostests/winetests/user32/text.c +++ b/rostests/winetests/user32/text.c @@ -27,6 +27,8 @@ #include "winuser.h" #include "winerror.h" +#define MODIFIED(rect) (rect.left == 10 && rect.right != 100 && rect.top == 10 && rect.bottom != 100) +#define EMPTY(rect) (rect.left == rect.right && rect.bottom == rect.top) static void test_DrawTextCalcRect(void) { @@ -40,9 +42,11 @@ static void test_DrawTextCalcRect(void) 's','t','r','i','n','g','\0'}; static CHAR emptystring[] = ""; static WCHAR emptystringW[] = { 0 }; - INT textlen, textheight; + INT textlen, textheight, heightcheck; RECT rect = { 0, 0, 100, 0 }; BOOL ret; + DRAWTEXTPARAMS dtp; + BOOL conform_xp = TRUE; /* Initialization */ hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, @@ -76,7 +80,7 @@ static void test_DrawTextCalcRect(void) ok( textheight, "DrawTextA error %u\n", GetLastError()); trace("MM_HIENGLISH rect.bottom %d\n", rect.bottom); - todo_wine ok(rect.bottom < 0, "In MM_HIENGLISH, DrawText with " + ok(rect.bottom < 0, "In MM_HIENGLISH, DrawText with " "DT_CALCRECT should return a negative rectangle bottom. " "(bot=%d)\n", rect.bottom); @@ -105,64 +109,458 @@ static void test_DrawTextCalcRect(void) rect.bottom); /* empty or null text should in some cases calc an empty rectangle */ - /* note: testing the function's return value is useless, it differs - * ( 0 or 1) on every Windows version I tried */ + SetRect( &rect, 10,10, 100, 100); - textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT, NULL ); - ok( !(rect.left == rect.right && rect.bottom == rect.top), - "rectangle should NOT be empty.\n"); + heightcheck = textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + if (textheight != 0) /* Windows 98 */ + { + win_skip("XP conformity failed, skipping XP tests. Probably win9x\n"); + conform_xp = FALSE; + } + else + ok(textheight==0,"Got textheight from DrawTextExA\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextA(hdc, text, 0, &rect, DT_CALCRECT); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + SetRect( &rect, 10,10, 100, 100); SetLastError( 0); - textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT, NULL ); - ok( (rect.left == rect.right && rect.bottom == rect.top), - "rectangle should be empty.\n"); + heightcheck = textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT, NULL ); + ok( EMPTY(rect), + "rectangle should be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextExA\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT); + ok( EMPTY(rect), + "rectangle should be empty got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + SetRect( &rect, 10,10, 100, 100); SetLastError( 0); - textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT, NULL ); - ok( (rect.left == rect.right && rect.bottom == rect.top), - "rectangle should be empty.\n"); + heightcheck = textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT, NULL ); + ok( EMPTY(rect) || !MODIFIED(rect), + "rectangle should be empty or not modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + if (!textheight) /* Windows NT 4 */ + { + if (conform_xp) + win_skip("XP conformity failed, skipping XP tests. Probably winNT\n"); + conform_xp = FALSE; + } + else + ok(textheight!=0,"Failed to get textheight from DrawTextExA\n"); + SetRect( &rect, 10,10, 100, 100); - textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT, NULL ); - ok( !(rect.left == rect.right && rect.bottom == rect.top), - "rectangle should NOT be empty.\n"); + textheight = DrawTextA(hdc, NULL, -1, &rect, DT_CALCRECT); + ok( EMPTY(rect) || !MODIFIED(rect), + "rectangle should be empty or NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight!=0,"Failed to get textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + SetRect( &rect, 10,10, 100, 100); + heightcheck = textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExA\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextA(hdc, NULL, 0, &rect, DT_CALCRECT); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + /* DT_SINGLELINE tests */ + + SetRect( &rect, 10,10, 100, 100); + heightcheck = textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExA\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextA(hdc, text, 0, &rect, DT_CALCRECT|DT_SINGLELINE); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + SetRect( &rect, 10,10, 100, 100); + SetLastError( 0); + heightcheck = textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL ); + ok( !EMPTY(rect) && MODIFIED(rect), + "rectangle should be modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextExA\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT|DT_SINGLELINE); + ok( !EMPTY(rect) && MODIFIED (rect), + "rectangle should be modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + SetRect( &rect, 10,10, 100, 100); + SetLastError( 0); + heightcheck = textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL ); + ok( (!EMPTY(rect) && MODIFIED(rect)) || !MODIFIED(rect), + "rectangle should be modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight!=0,"Failed to get textheight from DrawTextExA\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextA(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE); + ok( (!EMPTY(rect) && MODIFIED(rect)) || !MODIFIED(rect), + "rectangle should be modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight!=0,"Failed to get textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + SetRect( &rect, 10,10, 100, 100); + heightcheck = textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExA\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextA(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + /* further tests with 0 count, NULL and empty strings */ + heightcheck = textheight = DrawTextA(hdc, text, 0, &rect, 0); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextA\n"); + textheight = DrawTextExA(hdc, text, 0, &rect, 0, NULL ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextA(hdc, emptystring, 0, &rect, 0); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextA\n"); + textheight = DrawTextExA(hdc, emptystring, 0, &rect, 0, NULL ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextA(hdc, NULL, 0, &rect, 0); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextA\n"); + textheight = DrawTextExA(hdc, NULL, 0, &rect, 0, NULL ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextA(hdc, emptystring, -1, &rect, 0); + ok(textheight!=0,"Failed to get textheight from DrawTextA\n"); + textheight = DrawTextExA(hdc, emptystring, -1, &rect, 0, NULL ); + ok(textheight!=0,"Failed to get textheight from DrawTextExA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextA(hdc, NULL, -1, &rect, 0); + if (conform_xp) + ok(textheight!=0,"Failed to get textheight from DrawTextA\n"); + textheight = DrawTextExA(hdc, NULL, -1, &rect, 0, NULL ); + if (conform_xp) + ok(textheight!=0,"Failed to get textheight from DrawTextExA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextA(hdc, NULL, 10, &rect, 0); + ok(textheight==0,"Got textheight from DrawTextA\n"); + textheight = DrawTextExA(hdc, NULL, 10, &rect, 0, NULL ); + ok(textheight==0,"Got textheight from DrawTextA\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + + /* invalid dtp size test */ + dtp.cbSize = -1; /* Invalid */ + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExA(hdc, text, 0, &rect, 0, &dtp); + ok(textheight==0,"Got textheight from DrawTextExA\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExA(hdc, emptystring, 0, &rect, 0, &dtp); + ok(textheight==0,"Got textheight from DrawTextExA\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExA(hdc, NULL, 0, &rect, 0, &dtp); + ok(textheight==0,"Got textheight from DrawTextExA\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExA(hdc, emptystring, -1, &rect, 0, &dtp); + ok(textheight==0,"Got textheight from DrawTextExA\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExA(hdc, NULL, -1, &rect, 0, &dtp); + ok(textheight==0,"Got textheight from DrawTextExA\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + + /* Margin calculations */ + dtp.cbSize = sizeof(dtp); + dtp.iLeftMargin = 0; + dtp.iRightMargin = 0; + SetRect( &rect, 0, 0, 0, 0); + DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp); + textlen = rect.right; /* Width without margin */ + dtp.iLeftMargin = 8; + SetRect( &rect, 0, 0, 0, 0); + DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp); + ok(rect.right==dtp.iLeftMargin+textlen ,"Incorrect left margin calculated rc(%d,%d)\n", rect.left, rect.right); + dtp.iLeftMargin = 0; + dtp.iRightMargin = 8; + SetRect( &rect, 0, 0, 0, 0); + DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp); + ok(rect.right==dtp.iRightMargin+textlen ,"Incorrect right margin calculated rc(%d,%d)\n", rect.left, rect.right); /* Wide char versions */ SetRect( &rect, 10,10, 100, 100); SetLastError( 0); - textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT, NULL ); + heightcheck = textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT, NULL ); if( GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) { - ok( !(rect.left == rect.right && rect.bottom == rect.top), - "rectangle should NOT be empty.\n"); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextExW\n"); + SetRect( &rect, 10,10, 100, 100); - textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT, NULL ); - ok( (rect.left == rect.right && rect.bottom == rect.top), - "rectangle should be empty.\n"); + textheight = DrawTextW(hdc, textW, 0, &rect, DT_CALCRECT); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + SetRect( &rect, 10,10, 100, 100); - textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT, NULL ); - ok( !(rect.left == rect.right && rect.bottom == rect.top), - "rectangle should NOT be empty.\n"); + heightcheck = textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT, NULL ); + ok( EMPTY(rect), + "rectangle should be empty got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextExW\n"); + SetRect( &rect, 10,10, 100, 100); - textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT, NULL ); - ok( !(rect.left == rect.right && rect.bottom == rect.top), - "rectangle should NOT be empty.\n"); + textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT); + ok( EMPTY(rect), + "rectangle should be empty got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + SetRect( &rect, 10,10, 100, 100); + heightcheck = textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (textheight) /* windows 2000 */ + { + if (conform_xp) + win_skip("XP conformity failed, skipping XP tests. Probably win 2000\n"); + conform_xp = FALSE; + } + else + ok(textheight==0,"Got textheight from DrawTextExW\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextW(hdc, NULL, 0, &rect, DT_CALCRECT); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + if (conform_xp) { + /* Crashes on NT4 */ + SetRect( &rect, 10,10, 100, 100); + heightcheck = textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight==0,"Got textheight from DrawTextExW\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextW(hdc, NULL, -1, &rect, DT_CALCRECT); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight==0,"Got textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + } + + + /* DT_SINGLELINE tests */ + + heightcheck = textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextExW\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextW(hdc, textW, 0, &rect, DT_CALCRECT|DT_SINGLELINE); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + SetRect( &rect, 10,10, 100, 100); + heightcheck = textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL ); + ok( !EMPTY(rect) && MODIFIED(rect), + "rectangle should be modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextExW\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT|DT_SINGLELINE); + ok( !EMPTY(rect) && MODIFIED(rect), + "rectangle should be modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight!=0,"Failed to get textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + if (conform_xp) { + /* Crashes on NT4 */ + SetRect( &rect, 10,10, 100, 100); + heightcheck = textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight==0,"Got textheight from DrawTextExW\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextW(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + ok(textheight==0,"Got textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + } + + SetRect( &rect, 10,10, 100, 100); + heightcheck = textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL ); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExW\n"); + + SetRect( &rect, 10,10, 100, 100); + textheight = DrawTextW(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE); + ok( !EMPTY(rect) && !MODIFIED(rect), + "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", + rect.left, rect.top, rect.right, rect.bottom ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + + /* further tests with NULL and empty strings */ + heightcheck = textheight = DrawTextW(hdc, textW, 0, &rect, 0); + ok(textheight!=0,"Failed to get textheight from DrawTextW\n"); + textheight = DrawTextExW(hdc, textW, 0, &rect, 0, NULL ); + ok(textheight!=0,"Failed to get textheight from DrawTextExW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextW(hdc, emptystringW, 0, &rect, 0); + ok(textheight!=0,"Failed to get textheight from DrawTextW\n"); + textheight = DrawTextExW(hdc, emptystringW, 0, &rect, 0, NULL ); + ok(textheight!=0,"Failed to get textheight from DrawTextExW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextW(hdc, NULL, 0, &rect, 0); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextW\n"); + textheight = DrawTextExW(hdc, NULL, 0, &rect, 0, NULL ); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextW(hdc, emptystringW, -1, &rect, 0); + ok(textheight!=0,"Failed to get textheight from DrawTextW\n"); + textheight = DrawTextExW(hdc, emptystringW, -1, &rect, 0, NULL ); + ok(textheight!=0,"Failed to get textheight from DrawTextExW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + if (conform_xp) { + /* Crashes on NT4 */ + heightcheck = textheight = DrawTextW(hdc, NULL, -1, &rect, 0); + ok(textheight==0,"Got textheight from DrawTextW\n"); + textheight = DrawTextExW(hdc, NULL, -1, &rect, 0, NULL ); + ok(textheight==0,"Got textheight from DrawTextExW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + heightcheck = textheight = DrawTextW(hdc, NULL, 10, &rect, 0); + ok(textheight==0,"Got textheight from DrawTextW\n"); + textheight = DrawTextExW(hdc, NULL, 10, &rect, 0, NULL ); + ok(textheight==0,"Got textheight from DrawTextW\n"); + ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n"); + } + + dtp.cbSize = -1; /* Invalid */ + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExW(hdc, textW, 0, &rect, 0, &dtp); + ok(textheight!=0,"Failed to get textheight from DrawTextExW\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExW(hdc, emptystringW, 0, &rect, 0, &dtp); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExW\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExW(hdc, NULL, 0, &rect, 0, &dtp); + if (conform_xp) + ok(textheight==0,"Got textheight from DrawTextExW\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExW(hdc, emptystringW, -1, &rect, 0, &dtp); + ok(textheight==0,"Got textheight from DrawTextExW\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + if (conform_xp) { + /* Crashes on NT4 */ + dtp.uiLengthDrawn = 1337; + textheight = DrawTextExW(hdc, NULL, -1, &rect, 0, &dtp); + ok(textheight==0,"Got textheight from DrawTextExW\n"); + ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn); + } } /* More test cases from bug 12226 */ SetRect(&rect, 0, 0, 0, 0); textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE); - todo_wine ok(textheight, "DrawTextA error %u\n", GetLastError()); + ok(textheight, "DrawTextA error %u\n", GetLastError()); ok(0 == rect.left, "expected 0, got %d\n", rect.left); ok(0 == rect.right, "expected 0, got %d\n", rect.right); ok(0 == rect.top, "expected 0, got %d\n", rect.top); - todo_wine ok(rect.bottom, "rect.bottom should not be 0\n"); + ok(rect.bottom, "rect.bottom should not be 0\n"); SetRect(&rect, 0, 0, 0, 0); textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE); - todo_wine ok(textheight, "DrawTextW error %u\n", GetLastError()); + if (!textheight && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip( "DrawTextW not implemented\n" ); + } + else + { + ok(textheight, "DrawTextW error %u\n", GetLastError()); ok(0 == rect.left, "expected 0, got %d\n", rect.left); ok(0 == rect.right, "expected 0, got %d\n", rect.right); ok(0 == rect.top, "expected 0, got %d\n", rect.top); - todo_wine ok(rect.bottom, "rect.bottom should not be 0\n"); + ok(rect.bottom, "rect.bottom should not be 0\n"); + } SelectObject(hdc, hOldFont); ret = DeleteObject(hFont); @@ -292,13 +690,13 @@ static void test_DrawState(void) SetLastError(0xdeadbeef); ret = DrawState(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, strlen(text), 0, 0, 10, 10, DST_TEXT); - ok(!ret, "DrawState succeeded\n"); + ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n"); ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError()); SetLastError(0xdeadbeef); ret = DrawState(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, 0, 0, 0, 10, 10, DST_TEXT); - ok(!ret, "DrawState succeeded\n"); + ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n"); ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError()); ReleaseDC(hwnd, hdc); diff --git a/rostests/winetests/user32/user32.rbuild b/rostests/winetests/user32/user32.rbuild index 6d07e360485..57c850cd9f3 100644 --- a/rostests/winetests/user32/user32.rbuild +++ b/rostests/winetests/user32/user32.rbuild @@ -1,16 +1,13 @@ - . - - 0x0600 - 0x609 + include/reactos/wine + ntdll user32 gdi32 advapi32 - kernel32 broadcast.c class.c clipboard.c @@ -37,4 +34,3 @@ testlist.c resource.rc - diff --git a/rostests/winetests/user32/win.c b/rostests/winetests/user32/win.c index 5b391eb4e19..16597bacdd7 100644 --- a/rostests/winetests/user32/win.c +++ b/rostests/winetests/user32/win.c @@ -46,6 +46,12 @@ void dump_region(HRGN hrgn); static HWND (WINAPI *pGetAncestor)(HWND,UINT); static BOOL (WINAPI *pGetWindowInfo)(HWND,WINDOWINFO*); +static UINT (WINAPI *pGetWindowModuleFileNameA)(HWND,LPSTR,UINT); +static BOOL (WINAPI *pGetLayeredWindowAttributes)(HWND,COLORREF*,BYTE*,DWORD*); +static BOOL (WINAPI *pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); +static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO); +static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD); +static int (WINAPI *pGetWindowRgnBox)(HWND,LPRECT); static BOOL test_lbuttondown_flag; static HWND hwndMessage; @@ -58,12 +64,22 @@ static DWORD our_pid; #define COUNTOF(arr) (sizeof(arr)/sizeof(arr[0])) +static void dump_minmax_info( const MINMAXINFO *minmax ) +{ + trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n", + minmax->ptReserved.x, minmax->ptReserved.y, + minmax->ptMaxSize.x, minmax->ptMaxSize.y, + minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, + minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y, + minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y); +} + /* try to make sure pending X events have been processed before continuing */ static void flush_events( BOOL remove_messages ) { MSG msg; int diff = 200; - int min_timeout = 50; + int min_timeout = 100; DWORD time = GetTickCount() + diff; while (diff > 0) @@ -72,7 +88,7 @@ static void flush_events( BOOL remove_messages ) if (remove_messages) while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg ); diff = time - GetTickCount(); - min_timeout = 10; + min_timeout = 50; } } @@ -102,6 +118,16 @@ static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_ } } +static BOOL ignore_message( UINT message ) +{ + /* these are always ignored */ + return (message >= 0xc000 || + message == WM_GETICON || + message == WM_GETOBJECT || + message == WM_TIMECHANGE || + message == WM_DEVICECHANGE); +} + static BOOL CALLBACK EnumChildProc( HWND hwndChild, LPARAM lParam) { (*(LPINT)lParam)++; @@ -141,8 +167,10 @@ static void test_parent_owner(void) SetLastError(0xdeadbeef); test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL ); - ok( GetLastError() == ERROR_TLW_WITH_WSCHILD, "CreateWindowExA should call SetLastError\n" ); ok( !test, "WS_CHILD without parent created\n" ); + ok( GetLastError() == ERROR_TLW_WITH_WSCHILD || + broken(GetLastError() == 0xdeadbeef), /* win9x */ + "CreateWindowExA error %u\n", GetLastError() ); /* desktop window */ check_parents( desktop, 0, 0, 0, 0, 0, 0 ); @@ -541,6 +569,60 @@ static void test_parent_owner(void) DestroyWindow( owner ); } +static BOOL CALLBACK enum_proc( HWND hwnd, LPARAM lParam) +{ + (*(LPINT)lParam)++; + if (*(LPINT)lParam > 2) return FALSE; + return TRUE; +} +static DWORD CALLBACK enum_thread( void *arg ) +{ + INT count; + HWND hwnd[3]; + BOOL ret; + MSG msg; + + PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE ); /* make sure we have a message queue */ + + count = 0; + ret = EnumThreadWindows( GetCurrentThreadId(), enum_proc, (LPARAM)&count ); + ok( ret, "EnumThreadWindows should have returned TRUE\n" ); + ok( count == 0, "count should be 0 got %d\n", count ); + + hwnd[0] = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", WS_POPUP, + 0, 0, 100, 100, 0, 0, 0, NULL ); + count = 0; + ret = EnumThreadWindows( GetCurrentThreadId(), enum_proc, (LPARAM)&count ); + ok( ret, "EnumThreadWindows should have returned TRUE\n" ); + if (count != 2) /* Vista gives us two windows for the price of one */ + { + ok( count == 1, "count should be 1 got %d\n", count ); + hwnd[2] = CreateWindowExA(0, "ToolWindowClass", "Tool window 2", WS_POPUP, + 0, 0, 100, 100, 0, 0, 0, NULL ); + } + else hwnd[2] = 0; + + hwnd[1] = CreateWindowExA(0, "ToolWindowClass", "Tool window 3", WS_POPUP, + 0, 0, 100, 100, 0, 0, 0, NULL ); + count = 0; + ret = EnumThreadWindows( GetCurrentThreadId(), enum_proc, (LPARAM)&count ); + ok( !ret, "EnumThreadWindows should have returned FALSE\n" ); + ok( count == 3, "count should be 3 got %d\n", count ); + + if (hwnd[2]) DestroyWindow(hwnd[2]); + DestroyWindow(hwnd[1]); + DestroyWindow(hwnd[0]); + return 0; +} + +/* test EnumThreadWindows in a separate thread */ +static void test_enum_thread_windows(void) +{ + DWORD id; + HANDLE handle = CreateThread( NULL, 0, enum_thread, 0, 0, &id ); + ok( !WaitForSingleObject( handle, 10000 ), "wait failed\n" ); + CloseHandle( handle ); +} static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { @@ -550,14 +632,8 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR { MINMAXINFO* minmax = (MINMAXINFO *)lparam; - trace("hwnd %p, WM_GETMINMAXINFO, %08lx, %08lx\n", hwnd, wparam, lparam); - trace("ptReserved (%d,%d), ptMaxSize (%d,%d), ptMaxPosition (%d,%d)\n" - " ptMinTrackSize (%d,%d), ptMaxTrackSize (%d,%d)\n", - minmax->ptReserved.x, minmax->ptReserved.y, - minmax->ptMaxSize.x, minmax->ptMaxSize.y, - minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, - minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y, - minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y); + trace("WM_GETMINMAXINFO: hwnd %p, %08lx, %08lx\n", hwnd, wparam, lparam); + dump_minmax_info( minmax ); SetWindowLongPtrA(hwnd, GWLP_USERDATA, 0x20031021); break; } @@ -565,8 +641,7 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR { BOOL is_win9x = GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == 0; WINDOWPOS *winpos = (WINDOWPOS *)lparam; - trace("main: WM_WINDOWPOSCHANGING\n"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", + trace("main: WM_WINDOWPOSCHANGING %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); if (!(winpos->flags & SWP_NOMOVE)) @@ -586,8 +661,7 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR { RECT rc1, rc2; WINDOWPOS *winpos = (WINDOWPOS *)lparam; - trace("main: WM_WINDOWPOSCHANGED\n"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", + trace("main: WM_WINDOWPOSCHANGED %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); ok(winpos->x >= -32768 && winpos->x <= 32767, "bad winpos->x %d\n", winpos->x); @@ -597,22 +671,21 @@ static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR ok(winpos->cy >= 0 && winpos->cy <= 32767, "bad winpos->cy %d\n", winpos->cy); GetWindowRect(hwnd, &rc1); - trace("window: (%d,%d)-(%d,%d)\n", rc1.left, rc1.top, rc1.right, rc1.bottom); SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy); /* note: winpos coordinates are relative to parent */ MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2); - trace("pos: (%d,%d)-(%d,%d)\n", rc2.left, rc2.top, rc2.right, rc2.bottom); if (0) { /* Uncomment this once the test succeeds in all cases */ - ok(EqualRect(&rc1, &rc2), "rects do not match\n"); - } + ok(EqualRect(&rc1, &rc2), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n", + rc1.left, rc1.top, rc1.right, rc1.bottom, rc2.left, rc2.top, rc2.right, rc2.bottom ); GetClientRect(hwnd, &rc2); DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1); MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2); ok(EqualRect(&rc1, &rc2), "rects do not match (%d,%d-%d,%d) / (%d,%d-%d,%d)\n", rc1.left, rc1.top, rc1.right, rc1.bottom, rc2.left, rc2.top, rc2.right, rc2.bottom ); + } break; } case WM_NCCREATE: @@ -651,13 +724,7 @@ static LRESULT WINAPI tool_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPAR MINMAXINFO* minmax = (MINMAXINFO *)lparam; trace("hwnd %p, WM_GETMINMAXINFO, %08lx, %08lx\n", hwnd, wparam, lparam); - trace("ptReserved (%d,%d), ptMaxSize (%d,%d), ptMaxPosition (%d,%d)\n" - " ptMinTrackSize (%d,%d), ptMaxTrackSize (%d,%d)\n", - minmax->ptReserved.x, minmax->ptReserved.y, - minmax->ptMaxSize.x, minmax->ptMaxSize.y, - minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, - minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y, - minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y); + dump_minmax_info( minmax ); SetWindowLongPtrA(hwnd, GWLP_USERDATA, 0x20031021); break; } @@ -691,7 +758,7 @@ static BOOL RegisterWindowClasses(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "MainWindowClass"; @@ -704,7 +771,7 @@ static BOOL RegisterWindowClasses(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "ToolWindowClass"; @@ -714,34 +781,34 @@ static BOOL RegisterWindowClasses(void) return TRUE; } -static void verify_window_info(HWND hwnd, const WINDOWINFO *info) +static void verify_window_info(const char *hook, HWND hwnd, const WINDOWINFO *info) { RECT rcWindow, rcClient; DWORD status; - ok(IsWindow(hwnd), "bad window handle\n"); + ok(IsWindow(hwnd), "bad window handle %p in hook %s\n", hwnd, hook); GetWindowRect(hwnd, &rcWindow); - ok(EqualRect(&rcWindow, &info->rcWindow), "wrong rcWindow\n"); + ok(EqualRect(&rcWindow, &info->rcWindow), "wrong rcWindow for %p in hook %s\n", hwnd, hook); GetClientRect(hwnd, &rcClient); /* translate to screen coordinates */ MapWindowPoints(hwnd, 0, (LPPOINT)&rcClient, 2); - ok(EqualRect(&rcClient, &info->rcClient), "wrong rcClient\n"); + ok(EqualRect(&rcClient, &info->rcClient), "wrong rcClient for %p in hook %s\n", hwnd, hook); ok(info->dwStyle == (DWORD)GetWindowLongA(hwnd, GWL_STYLE), - "wrong dwStyle: %08x != %08x\n", info->dwStyle, GetWindowLongA(hwnd, GWL_STYLE)); - /* Windows reports a not documented exstyle 0x800 in WINDOWINFO, but - * doesn't return it in GetWindowLong(hwnd, GWL_EXSTYLE). + "wrong dwStyle: %08x != %08x for %p in hook %s\n", + info->dwStyle, GetWindowLongA(hwnd, GWL_STYLE), hwnd, hook); + /* Windows reports some undocumented exstyles in WINDOWINFO, but + * doesn't return them in GetWindowLong(hwnd, GWL_EXSTYLE). */ - ok((info->dwExStyle & ~0x800) == (DWORD)GetWindowLongA(hwnd, GWL_EXSTYLE), - "wrong dwExStyle: %08x != %08x\n", info->dwExStyle, GetWindowLongA(hwnd, GWL_EXSTYLE)); + ok((info->dwExStyle & ~0xe0000800) == (DWORD)GetWindowLongA(hwnd, GWL_EXSTYLE), + "wrong dwExStyle: %08x != %08x for %p in hook %s\n", + info->dwExStyle, GetWindowLongA(hwnd, GWL_EXSTYLE), hwnd, hook); status = (GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0; - ok(info->dwWindowStatus == status, "wrong dwWindowStatus: %04x != %04x\n", - info->dwWindowStatus, status); - - trace("rcWindow: %d,%d - %d,%d\n", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom); - trace("rcClient: %d,%d - %d,%d\n", rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); + if (GetForegroundWindow()) + ok(info->dwWindowStatus == status, "wrong dwWindowStatus: %04x != %04x active %p fg %p in hook %s\n", + info->dwWindowStatus, status, GetActiveWindow(), GetForegroundWindow(), hook); /* win2k and XP return broken border info in GetWindowInfo most of * the time, so there is no point in testing it. @@ -754,10 +821,11 @@ static void verify_window_info(HWND hwnd, const WINDOWINFO *info) ok(info->cyWindowBorders == border, "wrong cyWindowBorders %d != %d\n", info->cyWindowBorders, border); #endif - ok(info->atomWindowType == GetClassLongA(hwnd, GCW_ATOM), "wrong atomWindowType\n"); + ok(info->atomWindowType == GetClassLongA(hwnd, GCW_ATOM), "wrong atomWindowType for %p in hook %s\n", + hwnd, hook); ok(info->wCreatorVersion == 0x0400 /* NT4, Win2000, XP, Win2003 */ || info->wCreatorVersion == 0x0500 /* Vista */, - "wrong wCreatorVersion %04x\n", info->wCreatorVersion); + "wrong wCreatorVersion %04x for %p in hook %s\n", info->wCreatorVersion, hwnd, hook); } static void FixedAdjustWindowRectEx(RECT* rc, LONG style, BOOL menu, LONG exstyle) @@ -781,15 +849,14 @@ static void test_nonclient_area(HWND hwnd) RECT rc_window, rc_client, rc; BOOL menu; BOOL is_win9x = GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == 0; + LRESULT ret; style = GetWindowLongA(hwnd, GWL_STYLE); exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE); menu = !(style & WS_CHILD) && GetMenu(hwnd) != 0; GetWindowRect(hwnd, &rc_window); - trace("window: (%d,%d)-(%d,%d)\n", rc_window.left, rc_window.top, rc_window.right, rc_window.bottom); GetClientRect(hwnd, &rc_client); - trace("client: (%d,%d)-(%d,%d)\n", rc_client.left, rc_client.top, rc_client.right, rc_client.bottom); /* avoid some cases when things go wrong */ if (IsRectEmpty(&rc_window) || IsRectEmpty(&rc_client) || @@ -799,15 +866,23 @@ static void test_nonclient_area(HWND hwnd) MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2); FixedAdjustWindowRectEx(&rc, style, menu, exstyle); - trace("calc window: (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); - ok(EqualRect(&rc, &rc_window), "window rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d\n", style, exstyle, menu); + ok(EqualRect(&rc, &rc_window), + "window rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d, win=(%d,%d)-(%d,%d), calc=(%d,%d)-(%d,%d)\n", + style, exstyle, menu, rc_window.left, rc_window.top, rc_window.right, rc_window.bottom, + rc.left, rc.top, rc.right, rc.bottom); CopyRect(&rc, &rc_window); DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc); MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2); - trace("calc client: (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); - ok(EqualRect(&rc, &rc_client), "client rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d\n", style, exstyle, menu); + ok(EqualRect(&rc, &rc_client), + "client rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d client=(%d,%d)-(%d,%d), calc=(%d,%d)-(%d,%d)\n", + style, exstyle, menu, rc_client.left, rc_client.top, rc_client.right, rc_client.bottom, + rc.left, rc.top, rc.right, rc.bottom); + + /* NULL rectangle shouldn't crash */ + ret = DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, 0); + ok(ret == 0, "NULL rectangle returned %ld instead of 0\n", ret); /* Win9x doesn't like WM_NCCALCSIZE with synthetic data and crashes */; if (is_win9x) @@ -818,14 +893,14 @@ static void test_nonclient_area(HWND hwnd) CopyRect(&rc_window, &rc_client); MapWindowPoints(hwnd, 0, (LPPOINT)&rc_window, 2); FixedAdjustWindowRectEx(&rc_window, style, menu, exstyle); - trace("calc window: (%d,%d)-(%d,%d)\n", - rc_window.left, rc_window.top, rc_window.right, rc_window.bottom); CopyRect(&rc, &rc_window); DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc); MapWindowPoints(0, hwnd, (LPPOINT)&rc, 2); - trace("calc client: (%d,%d)-(%d,%d)\n", rc.left, rc.top, rc.right, rc.bottom); - ok(EqualRect(&rc, &rc_client), "synthetic rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d\n", style, exstyle, menu); + ok(EqualRect(&rc, &rc_client), + "synthetic rect does not match: style:exstyle=0x%08x:0x%08x, menu=%d, client=(%d,%d)-(%d,%d), calc=(%d,%d)-(%d,%d)\n", + style, exstyle, menu, rc_client.left, rc_client.top, rc_client.right, rc_client.bottom, + rc.left, rc.top, rc.right, rc.bottom); } static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) @@ -842,25 +917,7 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) "HCBT_SYSCOMMAND", "HCBT_SETFOCUS" }; const char *code_name = (nCode >= 0 && nCode <= HCBT_SETFOCUS) ? CBT_code_name[nCode] : "Unknown"; - - trace("CBT: %d (%s), %08lx, %08lx\n", nCode, code_name, wParam, lParam); - - /* on HCBT_DESTROYWND window state is undefined */ - if (nCode != HCBT_DESTROYWND && IsWindow((HWND)wParam)) - { - if (pGetWindowInfo) - { - WINDOWINFO info; - - /* Win98 actually does check the info.cbSize and doesn't allow - * it to be anything except sizeof(WINDOWINFO), while Win95, Win2k, - * WinXP do not check it at all. - */ - info.cbSize = sizeof(WINDOWINFO); - ok(pGetWindowInfo((HWND)wParam, &info), "GetWindowInfo should not fail\n"); - verify_window_info((HWND)wParam, &info); - } - } + HWND hwnd = (HWND)wParam; switch (nCode) { @@ -871,64 +928,95 @@ static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam) LONG style; CBT_CREATEWNDA *createwnd = (CBT_CREATEWNDA *)lParam; trace("HCBT_CREATEWND: hwnd %p, parent %p, style %08x\n", - (HWND)wParam, createwnd->lpcs->hwndParent, createwnd->lpcs->style); + hwnd, createwnd->lpcs->hwndParent, createwnd->lpcs->style); ok(createwnd->hwndInsertAfter == HWND_TOP, "hwndInsertAfter should be always HWND_TOP\n"); + if (pGetWindowInfo) + { + WINDOWINFO info; + info.cbSize = sizeof(WINDOWINFO); + ok(pGetWindowInfo(hwnd, &info), "GetWindowInfo should not fail\n"); + verify_window_info(code_name, hwnd, &info); + } + /* WS_VISIBLE should be turned off yet */ style = createwnd->lpcs->style & ~WS_VISIBLE; - ok(style == GetWindowLongA((HWND)wParam, GWL_STYLE), + ok(style == GetWindowLongA(hwnd, GWL_STYLE), "style of hwnd and style in the CREATESTRUCT do not match: %08x != %08x\n", - GetWindowLongA((HWND)wParam, GWL_STYLE), style); + GetWindowLongA(hwnd, GWL_STYLE), style); if (0) { /* Uncomment this once the test succeeds in all cases */ if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) { - ok(GetParent((HWND)wParam) == hwndMessage, + ok(GetParent(hwnd) == hwndMessage, "wrong result from GetParent %p: message window %p\n", - GetParent((HWND)wParam), hwndMessage); + GetParent(hwnd), hwndMessage); } else - ok(!GetParent((HWND)wParam), "GetParent should return 0 at this point\n"); + ok(!GetParent(hwnd), "GetParent should return 0 at this point\n"); - ok(!GetWindow((HWND)wParam, GW_OWNER), "GW_OWNER should be set to 0 at this point\n"); + ok(!GetWindow(hwnd, GW_OWNER), "GW_OWNER should be set to 0 at this point\n"); } if (0) { /* while NT assigns GW_HWNDFIRST/LAST some values at this point, * Win9x still has them set to 0. */ - ok(GetWindow((HWND)wParam, GW_HWNDFIRST) != 0, "GW_HWNDFIRST should not be set to 0 at this point\n"); - ok(GetWindow((HWND)wParam, GW_HWNDLAST) != 0, "GW_HWNDLAST should not be set to 0 at this point\n"); + ok(GetWindow(hwnd, GW_HWNDFIRST) != 0, "GW_HWNDFIRST should not be set to 0 at this point\n"); + ok(GetWindow(hwnd, GW_HWNDLAST) != 0, "GW_HWNDLAST should not be set to 0 at this point\n"); } - ok(!GetWindow((HWND)wParam, GW_HWNDPREV), "GW_HWNDPREV should be set to 0 at this point\n"); - ok(!GetWindow((HWND)wParam, GW_HWNDNEXT), "GW_HWNDNEXT should be set to 0 at this point\n"); + ok(!GetWindow(hwnd, GW_HWNDPREV), "GW_HWNDPREV should be set to 0 at this point\n"); + ok(!GetWindow(hwnd, GW_HWNDNEXT), "GW_HWNDNEXT should be set to 0 at this point\n"); if (0) { /* Uncomment this once the test succeeds in all cases */ if (pGetAncestor) { - ok(pGetAncestor((HWND)wParam, GA_PARENT) == hwndMessage, "GA_PARENT should be set to hwndMessage at this point\n"); - ok(pGetAncestor((HWND)wParam, GA_ROOT) == (HWND)wParam, - "GA_ROOT is set to %p, expected %p\n", pGetAncestor((HWND)wParam, GA_ROOT), (HWND)wParam); + ok(pGetAncestor(hwnd, GA_PARENT) == hwndMessage, "GA_PARENT should be set to hwndMessage at this point\n"); + ok(pGetAncestor(hwnd, GA_ROOT) == hwnd, + "GA_ROOT is set to %p, expected %p\n", pGetAncestor(hwnd, GA_ROOT), hwnd); if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) - ok(pGetAncestor((HWND)wParam, GA_ROOTOWNER) == hwndMessage, + ok(pGetAncestor(hwnd, GA_ROOTOWNER) == hwndMessage, "GA_ROOTOWNER should be set to hwndMessage at this point\n"); else - ok(pGetAncestor((HWND)wParam, GA_ROOTOWNER) == (HWND)wParam, - "GA_ROOTOWNER is set to %p, expected %p\n", pGetAncestor((HWND)wParam, GA_ROOTOWNER), (HWND)wParam); + ok(pGetAncestor(hwnd, GA_ROOTOWNER) == hwnd, + "GA_ROOTOWNER is set to %p, expected %p\n", pGetAncestor(hwnd, GA_ROOTOWNER), hwnd); } - ok(GetWindowRect((HWND)wParam, &rc), "GetWindowRect failed\n"); + ok(GetWindowRect(hwnd, &rc), "GetWindowRect failed\n"); ok(EqualRect(&rc, &rc_null), "window rect should be set to 0 HCBT_CREATEWND\n"); - ok(GetClientRect((HWND)wParam, &rc), "GetClientRect failed\n"); + ok(GetClientRect(hwnd, &rc), "GetClientRect failed\n"); ok(EqualRect(&rc, &rc_null), "client rect should be set to 0 on HCBT_CREATEWND\n"); } break; } + case HCBT_MOVESIZE: + case HCBT_MINMAX: + case HCBT_ACTIVATE: + case HCBT_SETFOCUS: + if (pGetWindowInfo && IsWindow(hwnd)) + { + WINDOWINFO info; + + /* Win98 actually does check the info.cbSize and doesn't allow + * it to be anything except sizeof(WINDOWINFO), while Win95, Win2k, + * WinXP do not check it at all. + */ + info.cbSize = sizeof(WINDOWINFO); + ok(pGetWindowInfo(hwnd, &info), "GetWindowInfo should not fail\n"); + verify_window_info(code_name, hwnd, &info); + } + break; + /* on HCBT_DESTROYWND window state is undefined */ + case HCBT_DESTROYWND: + trace( "HCBT_DESTROYWND: hwnd %p\n", hwnd ); + break; + default: + break; } return CallNextHookEx(hhook, nCode, wParam, lParam); @@ -963,16 +1051,24 @@ static void test_shell_window(void) DWORD pid; HANDLE hProcess; + GetWindowThreadProcessId(shellWindow, &pid); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + if (!hProcess) + { + skip( "cannot get access to shell process\n" ); + return; + } + + SetLastError(0xdeadbeef); ret = DestroyWindow(shellWindow); error = GetLastError(); ok(!ret, "DestroyWindow(shellWindow)\n"); /* passes on Win XP, but not on Win98 */ - ok(error==ERROR_ACCESS_DENIED, "ERROR_ACCESS_DENIED after DestroyWindow(shellWindow)\n"); + ok(error==ERROR_ACCESS_DENIED || error == 0xdeadbeef, + "got %u after DestroyWindow(shellWindow)\n", error); /* close old shell instance */ - GetWindowThreadProcessId(shellWindow, &pid); - hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); ret = TerminateProcess(hProcess, 0); ok(ret, "termination of previous shell process failed: GetLastError()=%d\n", GetLastError()); WaitForSingleObject(hProcess, INFINITE); /* wait for termination */ @@ -1062,10 +1158,11 @@ static void test_shell_window(void) static char mdi_lParam_test_message[] = "just a test string"; -static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) +static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) { MDICREATESTRUCTA mdi_cs; HWND mdi_child; + INT_PTR id; static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0}; static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0}; BOOL isWin9x = FALSE; @@ -1081,14 +1178,16 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) mdi_cs.lParam = (LPARAM)mdi_lParam_test_message; mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); mdi_cs.style = 0x7fffffff; /* without WS_POPUP */ mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1101,7 +1200,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) else { ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1122,7 +1222,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) } else { - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1134,7 +1235,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) mdi_client, GetModuleHandle(0), (LPARAM)mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1145,7 +1247,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) mdi_client, GetModuleHandle(0), (LPARAM)mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1162,7 +1265,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) else { ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1184,7 +1288,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) } else { - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1194,9 +1299,10 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1205,9 +1311,10 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1216,7 +1323,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES) { ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n"); @@ -1224,7 +1331,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) else { ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1236,7 +1344,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); if (!mdi_child) { if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) @@ -1246,7 +1354,8 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) } else { - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == first_id, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == first_id, "wrong child id %ld\n", id); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); } @@ -1259,7 +1368,7 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, parent, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); ok(!mdi_child, "WS_EX_MDICHILD with a not MDIClient parent should fail\n"); } @@ -1268,9 +1377,10 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == 0, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == 0, "wrong child id %ld\n", id); DestroyWindow(mdi_child); mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child", @@ -1278,9 +1388,10 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == 0, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == 0, "wrong child id %ld\n", id); DestroyWindow(mdi_child); /* maximized child */ @@ -1289,9 +1400,10 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == 0, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == 0, "wrong child id %ld\n", id); DestroyWindow(mdi_child); trace("Creating maximized child with a caption\n"); @@ -1300,9 +1412,10 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == 0, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == 0, "wrong child id %ld\n", id); DestroyWindow(mdi_child); trace("Creating maximized child with a caption and a thick frame\n"); @@ -1311,9 +1424,10 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT first_id) CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), - (LPVOID)mdi_lParam_test_message); + mdi_lParam_test_message); ok(mdi_child != 0, "MDI child creation failed\n"); - ok(GetWindowLongPtrA(mdi_child, GWLP_ID) == 0, "wrong child id %d\n", GetWindowLongPtrA(mdi_child, GWLP_ID)); + id = GetWindowLongPtrA(mdi_child, GWLP_ID); + ok(id == 0, "wrong child id %ld\n", id); DestroyWindow(mdi_child); } @@ -1351,7 +1465,7 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L case WM_CREATE: { CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; - MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs->lpCreateParams; + MDICREATESTRUCTA *mdi_cs = cs->lpCreateParams; ok(cs->dwExStyle & WS_EX_MDICHILD, "WS_EX_MDICHILD should be set\n"); ok(mdi_cs->lParam == (LPARAM)mdi_lParam_test_message, "wrong mdi_cs->lParam\n"); @@ -1421,17 +1535,7 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */ AdjustWindowRectEx(&rc, style, 0, exstyle); trace("MDI child: calculated max window size = (%d x %d)\n", rc.right-rc.left, rc.bottom-rc.top); - - trace("ptReserved = (%d,%d)\n" - "ptMaxSize = (%d,%d)\n" - "ptMaxPosition = (%d,%d)\n" - "ptMinTrackSize = (%d,%d)\n" - "ptMaxTrackSize = (%d,%d)\n", - minmax->ptReserved.x, minmax->ptReserved.y, - minmax->ptMaxSize.x, minmax->ptMaxSize.y, - minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, - minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y, - minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y); + dump_minmax_info( minmax ); ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %d != %d\n", minmax->ptMaxSize.x, rc.right - rc.left); @@ -1440,17 +1544,8 @@ static LRESULT WINAPI mdi_child_wnd_proc_1(HWND hwnd, UINT msg, WPARAM wparam, L DefMDIChildProcA(hwnd, msg, wparam, lparam); - trace("DefMDIChildProc returned:\n" - "ptReserved = (%d,%d)\n" - "ptMaxSize = (%d,%d)\n" - "ptMaxPosition = (%d,%d)\n" - "ptMinTrackSize = (%d,%d)\n" - "ptMaxTrackSize = (%d,%d)\n", - minmax->ptReserved.x, minmax->ptReserved.y, - minmax->ptMaxSize.x, minmax->ptMaxSize.y, - minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, - minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y, - minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y); + trace("DefMDIChildProc returned:\n"); + dump_minmax_info( minmax ); MDI_ChildGetMinMaxInfo(client, hwnd, &my_minmax); ok(minmax->ptMaxSize.x == my_minmax.ptMaxSize.x, "default width of maximized child %d != %d\n", @@ -1485,8 +1580,8 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L { CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; - trace("%s\n", (msg == WM_NCCREATE) ? "WM_NCCREATE" : "WM_CREATE"); - trace("x %d, y %d, cx %d, cy %d\n", cs->x, cs->y, cs->cx, cs->cy); + trace("%s: x %d, y %d, cx %d, cy %d\n", (msg == WM_NCCREATE) ? "WM_NCCREATE" : "WM_CREATE", + cs->x, cs->y, cs->cx, cs->cy); ok(!(cs->dwExStyle & WS_EX_MDICHILD), "WS_EX_MDICHILD should not be set\n"); ok(cs->lpCreateParams == mdi_lParam_test_message, "wrong cs->lpCreateParams\n"); @@ -1515,30 +1610,17 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L MINMAXINFO *minmax = (MINMAXINFO *)lparam; LONG style, exstyle; - trace("WM_GETMINMAXINFO\n"); - style = GetWindowLongA(hwnd, GWL_STYLE); exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE); GetClientRect(parent, &rc); - trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom); + trace("WM_GETMINMAXINFO: parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom); GetClientRect(parent, &rc); if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */ AdjustWindowRectEx(&rc, style, 0, exstyle); - trace("calculated max child window size = (%d x %d)\n", rc.right-rc.left, rc.bottom-rc.top); - - trace("ptReserved = (%d,%d)\n" - "ptMaxSize = (%d,%d)\n" - "ptMaxPosition = (%d,%d)\n" - "ptMinTrackSize = (%d,%d)\n" - "ptMaxTrackSize = (%d,%d)\n", - minmax->ptReserved.x, minmax->ptReserved.y, - minmax->ptMaxSize.x, minmax->ptMaxSize.y, - minmax->ptMaxPosition.x, minmax->ptMaxPosition.y, - minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y, - minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y); + dump_minmax_info( minmax ); ok(minmax->ptMaxSize.x == rc.right - rc.left, "default width of maximized child %d != %d\n", minmax->ptMaxSize.x, rc.right - rc.left); @@ -1553,18 +1635,19 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L RECT rc1, rc2; GetWindowRect(hwnd, &rc1); - trace("window: (%d,%d)-(%d,%d)\n", rc1.left, rc1.top, rc1.right, rc1.bottom); SetRect(&rc2, winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy); /* note: winpos coordinates are relative to parent */ MapWindowPoints(GetParent(hwnd), 0, (LPPOINT)&rc2, 2); - trace("pos: (%d,%d)-(%d,%d)\n", rc2.left, rc2.top, rc2.right, rc2.bottom); - ok(EqualRect(&rc1, &rc2), "rects do not match\n"); - + ok(EqualRect(&rc1, &rc2), "rects do not match, window=(%d,%d)-(%d,%d) pos=(%d,%d)-(%d,%d)\n", + rc1.left, rc1.top, rc1.right, rc1.bottom, + rc2.left, rc2.top, rc2.right, rc2.bottom); GetWindowRect(hwnd, &rc1); GetClientRect(hwnd, &rc2); DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)&rc1); MapWindowPoints(0, hwnd, (LPPOINT)&rc1, 2); - ok(EqualRect(&rc1, &rc2), "rects do not match\n"); + ok(EqualRect(&rc1, &rc2), "rects do not match, window=(%d,%d)-(%d,%d) client=(%d,%d)-(%d,%d)\n", + rc1.left, rc1.top, rc1.right, rc1.bottom, + rc2.left, rc2.top, rc2.right, rc2.bottom); } /* fall through */ case WM_WINDOWPOSCHANGING: @@ -1572,20 +1655,18 @@ static LRESULT WINAPI mdi_child_wnd_proc_2(HWND hwnd, UINT msg, WPARAM wparam, L WINDOWPOS *winpos = (WINDOWPOS *)lparam; WINDOWPOS my_winpos = *winpos; - trace("%s\n", (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED"); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", + trace("%s: %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", + (msg == WM_WINDOWPOSCHANGING) ? "WM_WINDOWPOSCHANGING" : "WM_WINDOWPOSCHANGED", winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); DefWindowProcA(hwnd, msg, wparam, lparam); - trace("%p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", + ok(!memcmp(&my_winpos, winpos, sizeof(WINDOWPOS)), + "DefWindowProc should not change WINDOWPOS: %p after %p, x %d, y %d, cx %d, cy %d flags %08x\n", winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y, winpos->cx, winpos->cy, winpos->flags); - ok(!memcmp(&my_winpos, winpos, sizeof(WINDOWPOS)), - "DefWindowProc should not change WINDOWPOS values\n"); - return 1; } } @@ -1615,7 +1696,7 @@ static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPA /* tests depend on a not zero MDIClient size */ 0, 0, rc.right, rc.bottom, hwnd, 0, GetModuleHandle(0), - (LPVOID)&client_cs); + &client_cs); assert(mdi_client); test_MDI_create(hwnd, mdi_client, client_cs.idFirstChild); DestroyWindow(mdi_client); @@ -1627,7 +1708,7 @@ static LRESULT WINAPI mdi_main_wnd_procA(HWND hwnd, UINT msg, WPARAM wparam, LPA /* tests depend on a not zero MDIClient size */ 0, 0, rc.right, rc.bottom, hwnd, 0, GetModuleHandle(0), - (LPVOID)&client_cs); + &client_cs); assert(mdi_client); test_MDI_create(hwnd, mdi_client, client_cs.idFirstChild); DestroyWindow(mdi_client); @@ -1693,7 +1774,7 @@ static BOOL mdi_RegisterWindowClasses(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "MDI_parent_Class"; @@ -1738,9 +1819,9 @@ static void test_icons(void) { WNDCLASSEXA cls; HWND hwnd; - HICON icon = LoadIconA(0, (LPSTR)IDI_APPLICATION); - HICON icon2 = LoadIconA(0, (LPSTR)IDI_QUESTION); - HICON small_icon = LoadImageA(0, (LPSTR)IDI_APPLICATION, IMAGE_ICON, + HICON icon = LoadIconA(0, IDI_APPLICATION); + HICON icon2 = LoadIconA(0, IDI_QUESTION); + HICON small_icon = LoadImageA(0, IDI_APPLICATION, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED ); HICON res; @@ -1750,9 +1831,9 @@ static void test_icons(void) cls.cbClsExtra = 0; cls.cbWndExtra = 0; cls.hInstance = 0; - cls.hIcon = LoadIconA(0, (LPSTR)IDI_HAND); + cls.hIcon = LoadIconA(0, IDI_HAND); cls.hIconSm = small_icon; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "IconWindowClass"; @@ -1899,7 +1980,8 @@ static void test_SetMenu(HWND parent) /* test whether we can destroy a menu assigned to a window */ retok = DestroyMenu(hMenu); ok( retok, "DestroyMenu error %d\n", GetLastError()); - ok(!IsMenu(hMenu), "menu handle should be not valid after DestroyMenu\n"); + retok = IsMenu(hMenu); + ok(!retok || broken(retok) /* nt4 */, "menu handle should be not valid after DestroyMenu\n"); ret = GetMenu(parent); /* This test fails on Win9x */ if (!is_win9x) @@ -1972,7 +2054,7 @@ static void test_SetMenu(HWND parent) static void test_window_tree(HWND parent, const DWORD *style, const int *order, int total) { HWND child[5], hwnd; - int i; + INT_PTR i; assert(total <= 5); @@ -1993,7 +2075,7 @@ static void test_window_tree(HWND parent, const DWORD *style, const int *order, else child[i] = CreateWindowExA(0, "static", "", style[i], 0,0,10,10, parent, (HMENU)i, 0, NULL); - trace("child[%d] = %p\n", i, child[i]); + trace("child[%ld] = %p\n", i, child[i]); ok(child[i] != 0, "CreateWindowEx failed to create child window\n"); } @@ -2004,8 +2086,8 @@ static void test_window_tree(HWND parent, const DWORD *style, const int *order, for (i = 0; i < total; i++) { - trace("hwnd[%d] = %p\n", i, hwnd); - ok(child[order[i]] == hwnd, "Z order of child #%d is wrong\n", i); + trace("hwnd[%ld] = %p\n", i, hwnd); + ok(child[order[i]] == hwnd, "Z order of child #%ld is wrong\n", i); hwnd = GetWindow(hwnd, GW_HWNDNEXT); } @@ -2059,8 +2141,10 @@ static void check_z_order_debug(HWND hwnd, HWND next, HWND prev, HWND owner, test = GetWindow(hwnd, GW_HWNDNEXT); /* skip foreign windows */ - while (test && (GetWindowThreadProcessId(test, NULL) != our_pid || - ULongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0))) + while (test && test != next && + (GetWindowThreadProcessId(test, NULL) != our_pid || + UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0) || + GetWindow(test, GW_OWNER) == next)) { /*trace("skipping next %p (%p)\n", test, UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)));*/ test = GetWindow(test, GW_HWNDNEXT); @@ -2069,8 +2153,10 @@ static void check_z_order_debug(HWND hwnd, HWND next, HWND prev, HWND owner, test = GetWindow(hwnd, GW_HWNDPREV); /* skip foreign windows */ - while (test && (GetWindowThreadProcessId(test, NULL) != our_pid || - ULongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0))) + while (test && test != prev && + (GetWindowThreadProcessId(test, NULL) != our_pid || + UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)) != GetModuleHandle(0) || + GetWindow(test, GW_OWNER) == hwnd)) { /*trace("skipping prev %p (%p)\n", test, UlongToHandle(GetWindowLongPtr(test, GWLP_HINSTANCE)));*/ test = GetWindow(test, GW_HWNDPREV); @@ -2197,9 +2283,23 @@ static void test_vis_rgn( HWND hwnd ) ReleaseDC( hwnd, hdc ); } +static LRESULT WINAPI set_focus_on_activate_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + if (msg == WM_ACTIVATE && LOWORD(wp) == WA_ACTIVE) + { + HWND child = GetWindow(hwnd, GW_CHILD); + ok(child != 0, "couldn't find child window\n"); + SetFocus(child); + ok(GetFocus() == child, "Focus should be on child %p\n", child); + return 0; + } + return DefWindowProc(hwnd, msg, wp, lp); +} + static void test_SetFocus(HWND hwnd) { - HWND child; + HWND child, child2; + WNDPROC old_wnd_proc; /* check if we can set focus to non-visible windows */ @@ -2225,6 +2325,14 @@ static void test_SetFocus(HWND hwnd) ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child ); ok( GetFocus() == hwnd, "Focus should be on parent %p, not %p\n", hwnd, GetFocus() ); ShowWindow(child, SW_SHOW); + child2 = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, child, 0, 0, NULL); + assert(child2); + ShowWindow(child2, SW_SHOW); + SetFocus(child2); + ShowWindow(child, SW_HIDE); + ok( !(GetWindowLong(child,GWL_STYLE) & WS_VISIBLE), "Child %p is visible\n", child ); + ok( GetFocus() == child2, "Focus should be on %p, not %p\n", child2, GetFocus() ); + ShowWindow(child, SW_SHOW); SetFocus(child); ok( GetFocus() == child, "Focus should be on child %p\n", child ); SetWindowPos(child,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_HIDEWINDOW); @@ -2246,22 +2354,51 @@ static void test_SetFocus(HWND hwnd) ok( GetFocus() == child, "Focus should still be on child %p\n", child ); EnableWindow(hwnd, TRUE); + ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); + ShowWindow(hwnd, SW_SHOWMINIMIZED); + ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); +todo_wine + ok( GetFocus() != child, "Focus should not be on child %p\n", child ); + ok( GetFocus() != hwnd, "Focus should not be on parent %p\n", hwnd ); + ShowWindow(hwnd, SW_RESTORE); + ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); + ok( GetFocus() == hwnd, "Focus should be on parent %p\n", hwnd ); + ShowWindow(hwnd, SW_SHOWMINIMIZED); + ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); + ok( GetFocus() != child, "Focus should not be on child %p\n", child ); +todo_wine + ok( GetFocus() != hwnd, "Focus should not be on parent %p\n", hwnd ); + old_wnd_proc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)set_focus_on_activate_proc); + ShowWindow(hwnd, SW_RESTORE); + ok( GetActiveWindow() == hwnd, "parent window %p should be active\n", hwnd); +todo_wine + ok( GetFocus() == child, "Focus should be on child %p, not %p\n", child, GetFocus() ); + + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)old_wnd_proc); + + DestroyWindow( child2 ); DestroyWindow( child ); } -static void check_wnd_state(HWND active, HWND foreground, HWND focus, HWND capture) +#define check_wnd_state(a,b,c,d) check_wnd_state_(__FILE__,__LINE__,a,b,c,d) +static void check_wnd_state_(const char *file, int line, + HWND active, HWND foreground, HWND focus, HWND capture) { - ok(active == GetActiveWindow(), "GetActiveWindow() = %p\n", GetActiveWindow()); - if (foreground) - ok(foreground == GetForegroundWindow(), "GetForegroundWindow() = %p\n", GetForegroundWindow()); - ok(focus == GetFocus(), "GetFocus() = %p\n", GetFocus()); - ok(capture == GetCapture(), "GetCapture() = %p\n", GetCapture()); + ok_(file, line)(active == GetActiveWindow(), "GetActiveWindow() = %p\n", GetActiveWindow()); + /* only check foreground if it belongs to the current thread */ + /* foreground can be moved to a different app pretty much at any time */ + if (foreground && GetForegroundWindow() && + GetWindowThreadProcessId(GetForegroundWindow(), NULL) == GetCurrentThreadId()) + ok_(file, line)(foreground == GetForegroundWindow(), "GetForegroundWindow() = %p\n", GetForegroundWindow()); + ok_(file, line)(focus == GetFocus(), "GetFocus() = %p\n", GetFocus()); + ok_(file, line)(capture == GetCapture(), "GetCapture() = %p\n", GetCapture()); } static void test_SetActiveWindow(HWND hwnd) { HWND hwnd2; + flush_events( TRUE ); ShowWindow(hwnd, SW_HIDE); SetFocus(0); SetActiveWindow(0); @@ -2274,10 +2411,12 @@ static void test_SetActiveWindow(HWND hwnd) hwnd2 = SetActiveWindow(0); ok(hwnd2 == hwnd, "SetActiveWindow returned %p instead of %p\n", hwnd2, hwnd); + if (!GetActiveWindow()) /* doesn't always work on vista */ + { check_wnd_state(0, 0, 0, 0); - hwnd2 = SetActiveWindow(hwnd); ok(hwnd2 == 0, "SetActiveWindow returned %p instead of 0\n", hwnd2); + } check_wnd_state(hwnd, hwnd, hwnd, 0); SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW); @@ -2317,6 +2456,7 @@ static void test_SetForegroundWindow(HWND hwnd) BOOL ret; HWND hwnd2; + flush_events( TRUE ); ShowWindow(hwnd, SW_HIDE); SetFocus(0); SetActiveWindow(0); @@ -2329,16 +2469,25 @@ static void test_SetForegroundWindow(HWND hwnd) hwnd2 = SetActiveWindow(0); ok(hwnd2 == hwnd, "SetActiveWindow(0) returned %p instead of %p\n", hwnd2, hwnd); + if (GetActiveWindow() == hwnd) /* doesn't always work on vista */ + check_wnd_state(hwnd, hwnd, hwnd, 0); + else check_wnd_state(0, 0, 0, 0); ret = SetForegroundWindow(hwnd); - ok(ret, "SetForegroundWindow returned FALSE instead of TRUE\n"); + if (!ret) + { + skip( "SetForegroundWindow not working\n" ); + return; + } check_wnd_state(hwnd, hwnd, hwnd, 0); SetLastError(0xdeadbeef); ret = SetForegroundWindow(0); ok(!ret, "SetForegroundWindow returned TRUE instead of FALSE\n"); - ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got error %d expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || + broken(GetLastError() == 0xdeadbeef), /* win9x */ + "got error %d expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError()); check_wnd_state(hwnd, hwnd, hwnd, 0); SetWindowPos(hwnd,0,0,0,0,0,SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW); @@ -2358,7 +2507,7 @@ static void test_SetForegroundWindow(HWND hwnd) /*trace("testing SetForegroundWindow on an invisible window %p\n", hwnd);*/ ret = SetForegroundWindow(hwnd); - ok(ret, "SetForegroundWindow returned FALSE instead of TRUE\n"); + ok(ret || broken(!ret), /* win98 */ "SetForegroundWindow returned FALSE instead of TRUE\n"); check_wnd_state(hwnd, hwnd, hwnd, 0); ShowWindow(hwnd, SW_SHOW); @@ -2440,7 +2589,10 @@ static LRESULT WINAPI button_hook_proc(HWND button, UINT msg, WPARAM wparam, LPA static void test_capture_1(void) { - HWND button, capture; + HWND button, capture, oldFocus, oldActive; + + oldFocus = GetFocus(); + oldActive = GetActiveWindow(); capture = GetCapture(); ok(capture == 0, "GetCapture() = %p\n", capture); @@ -2458,14 +2610,16 @@ static void test_capture_1(void) check_wnd_state(button, 0, button, button); DestroyWindow(button); - check_wnd_state(0, 0, 0, 0); + check_wnd_state(oldActive, 0, oldFocus, 0); } static void test_capture_2(void) { - HWND button, hwnd, capture; + HWND button, hwnd, capture, oldFocus, oldActive; - check_wnd_state(0, 0, 0, 0); + oldFocus = GetFocus(); + oldActive = GetActiveWindow(); + check_wnd_state(oldActive, 0, oldFocus, 0); button = CreateWindowExA(0, "button", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL); assert(button); @@ -2515,7 +2669,7 @@ static void test_capture_2(void) check_wnd_state(button, button, button, 0); DestroyWindow(button); - check_wnd_state(0, 0, 0, 0); + check_wnd_state(oldActive, 0, oldFocus, 0); } static void test_capture_3(HWND hwnd1, HWND hwnd2) @@ -2543,12 +2697,24 @@ static void test_capture_3(HWND hwnd1, HWND hwnd2) ok (ret, "releasecapture did not return TRUE after second try.\n"); } +/* PeekMessage wrapper that ignores the messages we don't care about */ +static BOOL peek_message( MSG *msg ) +{ + BOOL ret; + do + { + ret = PeekMessageA(msg, 0, 0, 0, PM_REMOVE); + } while (ret && (msg->message == WM_TIMER || ignore_message(msg->message))); + return ret; +} + static void test_keyboard_input(HWND hwnd) { MSG msg; BOOL ret; - ShowWindow(hwnd, SW_SHOW); + flush_events( TRUE ); + SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_SHOWWINDOW); UpdateWindow(hwnd); flush_events( TRUE ); @@ -2560,25 +2726,31 @@ static void test_keyboard_input(HWND hwnd) flush_events( TRUE ); PostMessageA(hwnd, WM_KEYDOWN, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = peek_message(&msg); + ok( ret, "no message available\n"); ok(msg.hwnd == hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + ret = peek_message(&msg); ok( !ret, "message %04x available\n", msg.message); ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus()); PostThreadMessageA(GetCurrentThreadId(), WM_KEYDOWN, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = peek_message(&msg); + ok(ret, "no message available\n"); ok(!msg.hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + ret = peek_message(&msg); ok( !ret, "message %04x available\n", msg.message); ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus()); keybd_event(VK_SPACE, 0, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + if (!peek_message(&msg)) + { + skip( "keybd_event didn't work, skipping keyboard test\n" ); + return; + } ok(msg.hwnd == hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + ret = peek_message(&msg); ok( !ret, "message %04x available\n", msg.message); SetFocus(0); @@ -2587,28 +2759,49 @@ static void test_keyboard_input(HWND hwnd) flush_events( TRUE ); PostMessageA(hwnd, WM_KEYDOWN, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = peek_message(&msg); + ok(ret, "no message available\n"); ok(msg.hwnd == hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + ret = peek_message(&msg); ok( !ret, "message %04x available\n", msg.message); ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus()); PostThreadMessageA(GetCurrentThreadId(), WM_KEYDOWN, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = peek_message(&msg); + ok(ret, "no message available\n"); ok(!msg.hwnd && msg.message == WM_KEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + ret = peek_message(&msg); ok( !ret, "message %04x available\n", msg.message); ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus()); keybd_event(VK_SPACE, 0, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = peek_message(&msg); + ok(ret, "no message available\n"); ok(msg.hwnd == hwnd && msg.message == WM_SYSKEYDOWN, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + ret = peek_message(&msg); ok( !ret, "message %04x available\n", msg.message); } +static BOOL wait_for_message( MSG *msg ) +{ + BOOL ret; + + for (;;) + { + ret = peek_message(msg); + if (ret) + { + if (msg->message == WM_PAINT) DispatchMessage(msg); + else break; + } + else if (MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT ) == WAIT_TIMEOUT) break; + } + if (!ret) msg->message = 0; + return ret; +} + static void test_mouse_input(HWND hwnd) { RECT rc; @@ -2621,6 +2814,7 @@ static void test_mouse_input(HWND hwnd) ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); + SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); GetWindowRect(hwnd, &rc); trace("main window %p: (%d,%d)-(%d,%d)\n", hwnd, rc.left, rc.top, rc.right, rc.bottom); @@ -2631,6 +2825,7 @@ static void test_mouse_input(HWND hwnd) assert(popup != 0); ShowWindow(popup, SW_SHOW); UpdateWindow(popup); + SetWindowPos( popup, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); GetWindowRect(popup, &rc); trace("popup window %p: (%d,%d)-(%d,%d)\n", popup, rc.left, rc.top, rc.right, rc.bottom); @@ -2641,16 +2836,25 @@ static void test_mouse_input(HWND hwnd) SetCursorPos(x, y); GetCursorPos(&pt); - ok(x == pt.x && y == pt.y, "wrong cursor pos (%d,%d), expected (%d,%d)\n", pt.x, pt.y, x, y); + if (x != pt.x || y != pt.y) + { + skip( "failed to set mouse position, skipping mouse input tests\n" ); + goto done; + } flush_events( TRUE ); - /* Check that setting the same position will generate WM_MOUSEMOVE */ + /* Check that setting the same position may generate WM_MOUSEMOVE */ SetCursorPos(x, y); msg.message = 0; - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); - ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ok(msg.pt.x == x && msg.pt.y == y, "wrong message coords (%d,%d)/(%d,%d)\n", x, y, msg.pt.x, msg.pt.y); + ret = peek_message(&msg); + if (ret) + { + ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", + msg.hwnd, msg.message); + ok(msg.pt.x == x && msg.pt.y == y, "wrong message coords (%d,%d)/(%d,%d)\n", + x, y, msg.pt.x, msg.pt.y); + } /* force the system to update its internal queue mouse position, * otherwise it won't generate relative mouse movements below. @@ -2660,31 +2864,37 @@ static void test_mouse_input(HWND hwnd) msg.message = 0; mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); - ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message); + flush_events( FALSE ); /* FIXME: SetCursorPos in Wine generates additional WM_MOUSEMOVE message */ - if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) - ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_TIMER || ignore_message(msg.message)) continue; + ok(msg.hwnd == popup && msg.message == WM_MOUSEMOVE, + "hwnd %p message %04x\n", msg.hwnd, msg.message); + } + ret = peek_message(&msg); ok( !ret, "message %04x available\n", msg.message); mouse_event(MOUSEEVENTF_MOVE, -1, -1, 0, 0); ShowWindow(popup, SW_HIDE); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = wait_for_message( &msg ); + if (ret) ok(msg.hwnd == hwnd && msg.message == WM_MOUSEMOVE, "hwnd %p message %04x\n", msg.hwnd, msg.message); flush_events( TRUE ); mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0); ShowWindow(hwnd, SW_HIDE); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + ret = wait_for_message( &msg ); ok( !ret, "message %04x available\n", msg.message); flush_events( TRUE ); /* test mouse clicks */ ShowWindow(hwnd, SW_SHOW); + SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); flush_events( TRUE ); ShowWindow(popup, SW_SHOW); + SetWindowPos( popup, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE ); flush_events( TRUE ); mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); @@ -2692,35 +2902,37 @@ static void test_mouse_input(HWND hwnd) mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, 0), "no message available\n"); - ok(msg.hwnd == popup && msg.message == WM_LBUTTONDOWN, "hwnd %p/%p message %04x\n", - msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = wait_for_message( &msg ); + if (!ret) + { + skip( "simulating mouse click doesn't work, skipping mouse button tests\n" ); + goto done; + } + if (msg.message == WM_MOUSEMOVE) /* win2k has an extra WM_MOUSEMOVE here */ + { + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); + } + ok(msg.hwnd == popup && msg.message == WM_LBUTTONDOWN, "hwnd %p/%p message %04x\n", msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, 0), "no message available\n"); - ok(msg.hwnd == popup && msg.message == WM_LBUTTONUP, "hwnd %p/%p message %04x\n", - msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); ok(msg.hwnd == popup && msg.message == WM_LBUTTONUP, "hwnd %p/%p message %04x\n", msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, 0), "no message available\n"); - ok(msg.hwnd == popup && msg.message == WM_LBUTTONDBLCLK, "hwnd %p/%p message %04x\n", - msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); ok(msg.hwnd == popup && msg.message == WM_LBUTTONDBLCLK, "hwnd %p/%p message %04x\n", msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, 0), "no message available\n"); - ok(msg.hwnd == popup && msg.message == WM_LBUTTONUP, "hwnd %p/%p message %04x\n", - msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); ok(msg.hwnd == popup && msg.message == WM_LBUTTONUP, "hwnd %p/%p message %04x\n", msg.hwnd, popup, msg.message); - ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE); + ret = peek_message(&msg); ok(!ret, "message %04x available\n", msg.message); ShowWindow(popup, SW_HIDE); @@ -2731,10 +2943,12 @@ static void test_mouse_input(HWND hwnd) mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); ok(msg.hwnd == hwnd && msg.message == WM_LBUTTONDOWN, "hwnd %p/%p message %04x\n", msg.hwnd, hwnd, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); ok(msg.hwnd == hwnd && msg.message == WM_LBUTTONUP, "hwnd %p/%p message %04x\n", msg.hwnd, hwnd, msg.message); @@ -2742,13 +2956,14 @@ static void test_mouse_input(HWND hwnd) SendMessageA(hwnd, WM_COMMAND, (WPARAM)popup, 0); test_lbuttondown_flag = FALSE; - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ret = wait_for_message( &msg ); + ok(ret, "no message available\n"); ok(msg.hwnd == popup && msg.message == WM_LBUTTONDOWN, "hwnd %p/%p message %04x\n", msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ok(peek_message(&msg), "no message available\n"); ok(msg.hwnd == popup && msg.message == WM_LBUTTONUP, "hwnd %p/%p message %04x\n", msg.hwnd, popup, msg.message); - ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "no message available\n"); + ok(peek_message(&msg), "no message available\n"); /* Test WM_MOUSEACTIVATE */ #define TEST_MOUSEACTIVATE(A,B) \ @@ -2780,6 +2995,7 @@ static void test_mouse_input(HWND hwnd) TEST_MOUSEACTIVATE(HTCLOSE,MA_ACTIVATE); TEST_MOUSEACTIVATE(HTHELP,MA_ACTIVATE); +done: /* Clear any messages left behind by WM_MOUSEACTIVATE tests */ flush_events( TRUE ); @@ -2825,13 +3041,13 @@ static void test_validatergn(HWND hwnd) static void nccalchelper(HWND hwnd, INT x, INT y, RECT *prc) { + RECT rc; MoveWindow( hwnd, 0, 0, x, y, 0); GetWindowRect( hwnd, prc); - trace("window rect is %d,%d - %d,%d\n", - prc->left,prc->top,prc->right,prc->bottom); + rc = *prc; DefWindowProcA(hwnd, WM_NCCALCSIZE, 0, (LPARAM)prc); - trace("nccalc rect is %d,%d - %d,%d\n", - prc->left,prc->top,prc->right,prc->bottom); + trace("window rect is %d,%d - %d,%d, nccalc rect is %d,%d - %d,%d\n", + rc.left,rc.top,rc.right,rc.bottom, prc->left,prc->top,prc->right,prc->bottom); } static void test_nccalcscroll(HWND parent) @@ -2970,7 +3186,7 @@ static LRESULT WINAPI StyleCheckProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM case WM_NCCREATE: case WM_CREATE: lpcs = (LPCREATESTRUCT)lparam; - lpss = (LPSTYLESTRUCT)lpcs->lpCreateParams; + lpss = lpcs->lpCreateParams; if (lpss) { if ((lpcs->dwExStyle & WS_EX_DLGMODALFRAME) || @@ -3065,6 +3281,59 @@ static void test_window_styles(void) check_window_style(0, WS_EX_APPWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_APPWINDOW|WS_EX_WINDOWEDGE); } +static void test_scrollwindow( HWND hwnd) +{ + HDC hdc; + RECT rc, rc2, rc3; + COLORREF colr; + + ShowWindow( hwnd, SW_SHOW); + UpdateWindow( hwnd); + flush_events( TRUE ); + GetClientRect( hwnd, &rc); + hdc = GetDC( hwnd); + /* test ScrollWindow(Ex) with no clip rectangle */ + /* paint the lower half of the window black */ + rc2 = rc; + rc2.top = ( rc2.top + rc2.bottom) / 2; + FillRect( hdc, &rc2, GetStockObject(BLACK_BRUSH)); + /* paint the upper half of the window white */ + rc2.bottom = rc2.top; + rc2.top =0; + FillRect( hdc, &rc2, GetStockObject(WHITE_BRUSH)); + /* scroll lower half up */ + rc2 = rc; + rc2.top = ( rc2.top + rc2.bottom) / 2; + ScrollWindowEx( hwnd, 0, - rc2.top, &rc2, NULL, NULL, NULL, SW_ERASE); + flush_events(FALSE); + /* expected: black should have scrolled to the upper half */ + colr = GetPixel( hdc, (rc2.left+rc2.right)/ 2, rc2.bottom / 4 ); + ok ( colr == 0, "pixel should be black, color is %08x\n", colr); + /* Repeat that test of ScrollWindow(Ex) now with clip rectangle */ + /* paint the lower half of the window black */ + rc2 = rc; + rc2.top = ( rc2.top + rc2.bottom) / 2; + FillRect( hdc, &rc2, GetStockObject(BLACK_BRUSH)); + /* paint the upper half of the window white */ + rc2.bottom = rc2.top; + rc2.top =0; + FillRect( hdc, &rc2, GetStockObject(WHITE_BRUSH)); + /* scroll lower half up */ + rc2 = rc; + rc2.top = ( rc2.top + rc2.bottom) / 2; + rc3 = rc; + rc3.left = rc3.right / 4; + rc3.right -= rc3.right / 4; + ScrollWindowEx( hwnd, 0, - rc2.top, &rc2, &rc3, NULL, NULL, SW_ERASE); + flush_events(FALSE); + /* expected: black should have scrolled to the upper half */ + colr = GetPixel( hdc, (rc2.left+rc2.right)/ 2, rc2.bottom / 4 ); + ok ( colr == 0, "pixel should be black, color is %08x\n", colr); + + /* clean up */ + ReleaseDC( hwnd, hdc); +} + static void test_scrollvalidate( HWND parent) { HDC hdc; @@ -3219,7 +3488,12 @@ static void test_scroll(void) 100, 100, 200, 200, 0, 0, 0, NULL); /* horizontal */ ret = GetScrollRange( hwnd, SB_HORZ, &min, &max); - ok( ret, "GetScrollRange returns FALSE\n"); + if (!ret) /* win9x */ + { + win_skip( "GetScrollRange doesn't work\n" ); + DestroyWindow( hwnd); + return; + } ok( min == 0, "minimum scroll pos is %d (should be zero)\n", min); ok( max == 0, "maximum scroll pos is %d (should be zero)\n", min); si.cbSize = sizeof( si); @@ -3302,8 +3576,6 @@ static void test_scrolldc( HWND parent) SetRectRgn( tmprgn, 25, 35, 35, 75); CombineRgn(exprgn, exprgn, tmprgn, RGN_OR); ok(EqualRgn(exprgn, hrgn), "wrong update region\n"); - colr = GetPixel( hdc, 80, 80); - ok ( colr == 0, "pixel should be black, color is %08x\n", colr); trace("update rect: %d,%d - %d,%d\n", rcu.left, rcu.top, rcu.right, rcu.bottom); if (winetest_debug > 0) dump_region(hrgn); @@ -3321,9 +3593,17 @@ static void test_params(void) INT rc; /* Just a param check */ + if (pGetMonitorInfoA) + { SetLastError(0xdeadbeef); rc = GetWindowText(hwndMain2, NULL, 1024); ok( rc==0, "GetWindowText: rc=%d err=%d\n",rc,GetLastError()); + } + else + { + /* Skips actually on Win95 and NT4 */ + win_skip("Test would crash on Win95\n"); + } SetLastError(0xdeadbeef); hwnd=CreateWindow("LISTBOX", "TestList", @@ -3331,7 +3611,9 @@ static void test_params(void) 0, 0, 100, 100, NULL, (HMENU)1, NULL, 0); - ok(!hwnd, "CreateWindow with invalid menu handle should fail\n"); + ok(!hwnd || broken(hwnd != NULL), /* w2k3 sp2 */ + "CreateWindow with invalid menu handle should fail\n"); + if (!hwnd) ok(GetLastError() == ERROR_INVALID_MENU_HANDLE || /* NT */ GetLastError() == 0xdeadbeef, /* Win9x */ "wrong last error value %d\n", GetLastError()); @@ -3486,7 +3768,7 @@ static void test_redrawnow(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "RedrawWindowClass"; @@ -3503,7 +3785,8 @@ static void test_redrawnow(void) ShowWindow(hwndMain, SW_SHOW); ok( WMPAINT_count == 0, "Multiple unexpected WM_PAINT calls %d\n", WMPAINT_count); RedrawWindow(hwndMain, NULL,NULL,RDW_UPDATENOW | RDW_ALLCHILDREN); - ok( WMPAINT_count == 1, "Multiple unexpected WM_PAINT calls %d\n", WMPAINT_count); + ok( WMPAINT_count == 1 || broken(WMPAINT_count == 0), /* sometimes on win9x */ + "Multiple unexpected WM_PAINT calls %d\n", WMPAINT_count); redrawComplete = TRUE; ok( WMPAINT_count < 10, "RedrawWindow (RDW_UPDATENOW) never completed (%d)\n", WMPAINT_count); @@ -3533,18 +3816,19 @@ static LRESULT WINAPI parentdc_window_procA(HWND hwnd, UINT msg, WPARAM wparam, switch (msg) { case WM_PAINT: - trace("doing WM_PAINT on %p\n", hwnd); GetClientRect(hwnd, &rc); CopyRect(&t->client, &rc); - trace("client rect (%d, %d)-(%d, %d)\n", rc.left, rc.top, rc.right, rc.bottom); GetWindowRect(hwnd, &rc); - trace("window rect (%d, %d)-(%d, %d)\n", rc.left, rc.top, rc.right, rc.bottom); + trace("WM_PAINT: hwnd %p, client rect (%d,%d)-(%d,%d), window rect (%d,%d)-(%d,%d)\n", hwnd, + t->client.left, t->client.top, t->client.right, t->client.bottom, + rc.left, rc.top, rc.right, rc.bottom); BeginPaint(hwnd, &ps); CopyRect(&t->paint, &ps.rcPaint); GetClipBox(ps.hdc, &rc); CopyRect(&t->clip, &rc); - trace("clip rect (%d, %d)-(%d, %d)\n", rc.left, rc.top, rc.right, rc.bottom); - trace("paint rect (%d, %d)-(%d, %d)\n", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); + trace("clip rect (%d,%d)-(%d,%d), paint rect (%d,%d)-(%d,%d)\n", + rc.left, rc.top, rc.right, rc.bottom, + ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); EndPaint(hwnd, &ps); return 0; } @@ -3655,7 +3939,7 @@ static void test_csparentdc(void) clsMain.cbWndExtra = 0; clsMain.hInstance = GetModuleHandleA(0); clsMain.hIcon = 0; - clsMain.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + clsMain.hCursor = LoadCursorA(0, IDC_ARROW); clsMain.hbrBackground = GetStockObject(WHITE_BRUSH); clsMain.lpszMenuName = NULL; clsMain.lpszClassName = "ParentDcMainWindowClass"; @@ -3671,7 +3955,7 @@ static void test_csparentdc(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "ParentDcWindowClass"; @@ -3695,6 +3979,7 @@ static void test_csparentdc(void) ShowWindow(hwndMain, SW_SHOW); ShowWindow(hwnd1, SW_SHOW); ShowWindow(hwnd2, SW_SHOW); + SetWindowPos(hwndMain, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); flush_events( TRUE ); zero_parentdc_test(&test_answer); @@ -3898,7 +4183,7 @@ static LRESULT CALLBACK minmax_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM l } static int expected_cx, expected_cy; -static RECT expected_rect; +static RECT expected_rect, broken_rect; static LRESULT CALLBACK winsizes_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { @@ -3920,10 +4205,16 @@ static LRESULT CALLBACK winsizes_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM GetWindowRect( hwnd, &rect ); trace( "hwnd %p msg %x size %dx%d rect %d,%d-%d,%d\n", hwnd, msg, cs->cx, cs->cy, rect.left, rect.top, rect.right, rect.bottom ); - ok( cs->cx == expected_cx, "wrong x size %d/%d\n", cs->cx, expected_cx ); - ok( cs->cy == expected_cy, "wrong y size %d/%d\n", cs->cy, expected_cy ); - ok( rect.right - rect.left == expected_rect.right - expected_rect.left && - rect.bottom - rect.top == expected_rect.bottom - expected_rect.top, + ok( cs->cx == expected_cx || broken(cs->cx == (short)expected_cx), + "wrong x size %d/%d\n", cs->cx, expected_cx ); + ok( cs->cy == expected_cy || broken(cs->cy == (short)expected_cy), + "wrong y size %d/%d\n", cs->cy, expected_cy ); + ok( (rect.right - rect.left == expected_rect.right - expected_rect.left && + rect.bottom - rect.top == expected_rect.bottom - expected_rect.top) || + broken( rect.right - rect.left == broken_rect.right - broken_rect.left && + rect.bottom - rect.top == broken_rect.bottom - broken_rect.top) || + broken( rect.right - rect.left == (short)broken_rect.right - (short)broken_rect.left && + rect.bottom - rect.top == (short)broken_rect.bottom - (short)broken_rect.top), "wrong rect %d,%d-%d,%d / %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom, expected_rect.left, expected_rect.top, expected_rect.right, expected_rect.bottom ); @@ -3956,10 +4247,15 @@ static void test_CreateWindow(void) ok(GetMenu(window) == (HMENU)menu, "GetMenu error %d\n", GetLastError()) #define expect_style(window, style)\ - ok(GetWindowLong(window, GWL_STYLE) == (style), "expected style %x != %x\n", (LONG)(style), GetWindowLong(window, GWL_STYLE)) + ok((ULONG)GetWindowLong(window, GWL_STYLE) == (style), "expected style %x != %x\n", (LONG)(style), GetWindowLong(window, GWL_STYLE)) #define expect_ex_style(window, ex_style)\ - ok(GetWindowLong(window, GWL_EXSTYLE) == (ex_style), "expected ex_style %x != %x\n", (LONG)(ex_style), GetWindowLong(window, GWL_EXSTYLE)) + ok((ULONG)GetWindowLong(window, GWL_EXSTYLE) == (ex_style), "expected ex_style %x != %x\n", (LONG)(ex_style), GetWindowLong(window, GWL_EXSTYLE)) + +#define expect_gle_broken_9x(gle)\ + ok(GetLastError() == gle ||\ + broken(GetLastError() == 0xdeadbeef),\ + "IsMenu set error %d\n", GetLastError()) hmenu = CreateMenu(); assert(hmenu != 0); @@ -4017,7 +4313,7 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); hmenu = CreateMenu(); assert(hmenu != 0); @@ -4031,7 +4327,7 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); hmenu = CreateMenu(); assert(hmenu != 0); @@ -4045,7 +4341,7 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); hmenu = CreateMenu(); assert(hmenu != 0); @@ -4059,14 +4355,16 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); /* WS_CHILD | WS_POPUP */ SetLastError(0xdeadbeef); hwnd = CreateWindowEx(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_POPUP, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(!hwnd, "CreateWindowEx should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n"); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + if (hwnd) + DestroyWindow(hwnd); hmenu = CreateMenu(); assert(hmenu != 0); @@ -4080,13 +4378,15 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); SetLastError(0xdeadbeef); hwnd = CreateWindowEx(WS_EX_APPWINDOW, "static", NULL, WS_CHILD | WS_POPUP | WS_CAPTION, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(!hwnd, "CreateWindowEx should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n"); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + if (hwnd) + DestroyWindow(hwnd); hmenu = CreateMenu(); assert(hmenu != 0); @@ -4100,13 +4400,15 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); SetLastError(0xdeadbeef); hwnd = CreateWindowEx(0, "static", NULL, WS_CHILD | WS_POPUP, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(!hwnd, "CreateWindowEx should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n"); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + if (hwnd) + DestroyWindow(hwnd); hmenu = CreateMenu(); assert(hmenu != 0); @@ -4120,13 +4422,15 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); SetLastError(0xdeadbeef); hwnd = CreateWindowEx(0, "static", NULL, WS_CHILD | WS_POPUP | WS_CAPTION, 0, 0, 100, 100, parent, (HMENU)1, 0, NULL); - ok(!hwnd, "CreateWindowEx should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + ok(!hwnd || broken(hwnd != 0 /* Win9x */), "CreateWindowEx should fail\n"); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); + if (hwnd) + DestroyWindow(hwnd); hmenu = CreateMenu(); assert(hmenu != 0); @@ -4140,7 +4444,7 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); SetLastError(0xdeadbeef); ok(!IsMenu(hmenu), "IsMenu should fail\n"); - ok(GetLastError() == ERROR_INVALID_MENU_HANDLE, "IsMenu set error %d\n", GetLastError()); + expect_gle_broken_9x(ERROR_INVALID_MENU_HANDLE); /* test child window sizing */ cls.style = 0; @@ -4149,7 +4453,7 @@ static void test_CreateWindow(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandle(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "MinMax_WndClass"; @@ -4204,15 +4508,17 @@ static void test_CreateWindow(void) expected_cx = expected_cy = 200000; SetRect( &expected_rect, 0, 0, 200000, 200000 ); + broken_rect = expected_rect; hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, 300000, 300000, 200000, 200000, parent, 0, 0, NULL); ok( hwnd != 0, "creation failed err %u\n", GetLastError()); GetClientRect( hwnd, &rc ); - ok( rc.right == 200000, "invalid rect right %u\n", rc.right ); - ok( rc.bottom == 200000, "invalid rect bottom %u\n", rc.bottom ); + ok( rc.right == 200000 || broken(rc.right == (short)200000), "invalid rect right %u\n", rc.right ); + ok( rc.bottom == 200000 || broken(rc.bottom == (short)200000), "invalid rect bottom %u\n", rc.bottom ); DestroyWindow(hwnd); expected_cx = expected_cy = -10; SetRect( &expected_rect, 0, 0, 0, 0 ); + SetRect( &broken_rect, 0, 0, -10, -10 ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -20, -20, -10, -10, parent, 0, 0, NULL); ok( hwnd != 0, "creation failed err %u\n", GetLastError()); GetClientRect( hwnd, &rc ); @@ -4222,6 +4528,7 @@ static void test_CreateWindow(void) expected_cx = expected_cy = -200000; SetRect( &expected_rect, 0, 0, 0, 0 ); + SetRect( &broken_rect, 0, 0, -200000, -200000 ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -300000, -300000, -200000, -200000, parent, 0, 0, NULL); ok( hwnd != 0, "creation failed err %u\n", GetLastError()); GetClientRect( hwnd, &rc ); @@ -4229,6 +4536,33 @@ static void test_CreateWindow(void) ok( rc.bottom == 0, "invalid rect bottom %u\n", rc.bottom ); DestroyWindow(hwnd); + /* we need a parent at 0,0 so that child coordinates match */ + DestroyWindow(parent); + parent = CreateWindowEx(0, "MinMax_WndClass", NULL, WS_POPUP, 0, 0, 100, 100, 0, 0, 0, NULL); + ok(parent != 0, "CreateWindowEx error %d\n", GetLastError()); + + expected_cx = 100; + expected_cy = 0x7fffffff; + SetRect( &expected_rect, 10, 10, 110, 0x7fffffff ); + SetRect( &broken_rect, 10, 10, 110, 0x7fffffffU + 10 ); + hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, 10, 10, 100, 0x7fffffff, parent, 0, 0, NULL); + ok( hwnd != 0, "creation failed err %u\n", GetLastError()); + GetClientRect( hwnd, &rc ); + ok( rc.right == 100, "invalid rect right %u\n", rc.right ); + ok( rc.bottom == 0x7fffffff - 10 || broken(rc.bottom == 0), "invalid rect bottom %u\n", rc.bottom ); + DestroyWindow(hwnd); + + expected_cx = 0x7fffffff; + expected_cy = 0x7fffffff; + SetRect( &expected_rect, 20, 10, 0x7fffffff, 0x7fffffff ); + SetRect( &broken_rect, 20, 10, 0x7fffffffU + 20, 0x7fffffffU + 10 ); + hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, 20, 10, 0x7fffffff, 0x7fffffff, parent, 0, 0, NULL); + ok( hwnd != 0, "creation failed err %u\n", GetLastError()); + GetClientRect( hwnd, &rc ); + ok( rc.right == 0x7fffffff - 20 || broken(rc.right == 0), "invalid rect right %u\n", rc.right ); + ok( rc.bottom == 0x7fffffff - 10 || broken(rc.bottom == 0), "invalid rect bottom %u\n", rc.bottom ); + DestroyWindow(hwnd); + /* top level window */ expected_cx = expected_cy = 200000; SetRect( &expected_rect, 0, 0, GetSystemMetrics(SM_CXMAXTRACK), GetSystemMetrics(SM_CYMAXTRACK) ); @@ -4244,6 +4578,7 @@ static void test_CreateWindow(void) UnregisterClass("MinMax_WndClass", GetModuleHandle(0)); UnregisterClass("Sizes_WndClass", GetModuleHandle(0)); +#undef expect_gle_broken_9x #undef expect_menu #undef expect_style #undef expect_ex_style @@ -4278,7 +4613,7 @@ static void test_SetWindowLong(void) SetLastError(0xdeadbeef); retval = SetWindowLongPtr(hwndMain, GWLP_WNDPROC, 0); - ok((WNDPROC)retval == main_window_procA, + ok((WNDPROC)retval == main_window_procA || broken(!retval), /* win9x */ "SetWindowLongPtr on invalid window proc should have returned address of main_window_procA instead of 0x%lx\n", retval); ok(GetLastError() == 0xdeadbeef, "SetWindowLongPtr shouldn't have set the last error, instead of setting it to %d\n", GetLastError()); retval = GetWindowLongPtr(hwndMain, GWLP_WNDPROC); @@ -4325,7 +4660,9 @@ static void test_ShowWindow(void) ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); GetWindowRect(hwnd, &rc); - ok(EqualRect(&rcMain, &rc), "rects should match\n"); + ok(EqualRect(&rcMain, &rc), "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n", + rcMain.left, rcMain.top, rcMain.right, rcMain.bottom, + rc.left, rc.top, rc.right, rc.bottom); ret = ShowWindow(hwnd, SW_SHOW); ok(!ret, "not expected ret: %lu\n", ret); @@ -4335,7 +4672,9 @@ static void test_ShowWindow(void) ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); GetWindowRect(hwnd, &rc); - ok(EqualRect(&rcMain, &rc), "rects should match\n"); + ok(EqualRect(&rcMain, &rc), "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n", + rcMain.left, rcMain.top, rcMain.right, rcMain.bottom, + rc.left, rc.top, rc.right, rc.bottom); ret = ShowWindow(hwnd, SW_MINIMIZE); ok(ret, "not expected ret: %lu\n", ret); @@ -4355,7 +4694,9 @@ static void test_ShowWindow(void) ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); GetWindowRect(hwnd, &rc); - ok(EqualRect(&rcMain, &rc), "rects should match\n"); + ok(EqualRect(&rcMain, &rc), "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n", + rcMain.left, rcMain.top, rcMain.right, rcMain.bottom, + rc.left, rc.top, rc.right, rc.bottom); ret = EnableWindow(hwnd, FALSE); ok(!ret, "not expected ret: %lu\n", ret); @@ -4370,7 +4711,9 @@ static void test_ShowWindow(void) ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); GetWindowRect(hwnd, &rc); - ok(EqualRect(&rcMain, &rc), "rects should match\n"); + ok(EqualRect(&rcMain, &rc), "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n", + rcMain.left, rcMain.top, rcMain.right, rcMain.bottom, + rc.left, rc.top, rc.right, rc.bottom); ret = DefWindowProc(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); ok(!ret, "not expected ret: %lu\n", ret); @@ -4380,7 +4723,9 @@ static void test_ShowWindow(void) ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); GetWindowRect(hwnd, &rc); - ok(EqualRect(&rcMain, &rc), "rects should match\n"); + ok(EqualRect(&rcMain, &rc), "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n", + rcMain.left, rcMain.top, rcMain.right, rcMain.bottom, + rc.left, rc.top, rc.right, rc.bottom); ret = ShowWindow(hwnd, SW_MINIMIZE); ok(ret, "not expected ret: %lu\n", ret); @@ -4410,7 +4755,9 @@ static void test_ShowWindow(void) ok(!(style & WS_MINIMIZE), "window should not be minimized\n"); ok(!(style & WS_MAXIMIZE), "window should not be maximized\n"); GetWindowRect(hwnd, &rc); - ok(EqualRect(&rcMain, &rc), "rects should match\n"); + ok(EqualRect(&rcMain, &rc), "expected (%d,%d)-(%d,%d), got (%d,%d)-(%d,%d)\n", + rcMain.left, rcMain.top, rcMain.right, rcMain.bottom, + rc.left, rc.top, rc.right, rc.bottom); ret = DefWindowProc(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); ok(!ret, "not expected ret: %lu\n", ret); @@ -4517,7 +4864,7 @@ static void test_GetUpdateRect(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = classNameA; @@ -4602,11 +4949,8 @@ static LRESULT CALLBACK TestExposedRegion_WndProc(HWND hwnd, UINT msg, WPARAM wP if(waitResult != WAIT_TIMEOUT) { GetUpdateRect(hwnd, &updateRect, FALSE); -todo_wine -{ - ok(!IsRectEmpty(&updateRect), "Exposed rect should not be empty\n"); + ok(IsRectEmpty(&updateRect), "Exposed rect should be empty\n"); } - } return 1; } @@ -4631,38 +4975,832 @@ static void test_Expose(void) DestroyWindow(mw); } -START_TEST(win) +static LRESULT CALLBACK TestNCRedraw_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" ); - pGetWindowInfo = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetWindowInfo" ); + static UINT ncredrawflags; + PAINTSTRUCT ps; - hwndMain = CreateWindowExA(0, "static", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL); - if (hwndMain) + switch(msg) { - ok(!GetParent(hwndMain), "GetParent should return 0 for message only windows\n"); + case WM_CREATE: + ncredrawflags = *(UINT *) (((CREATESTRUCT *)lParam)->lpCreateParams); + return 0; + case WM_NCPAINT: + RedrawWindow(hwnd, NULL, NULL, ncredrawflags); + break; + case WM_PAINT: + BeginPaint(hwnd, &ps); + EndPaint(hwnd, &ps); + return 0; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +static void run_NCRedrawLoop(UINT flags) +{ + HWND hwnd; + MSG msg; + + UINT loopcount = 0; + + hwnd = CreateWindowA("TestNCRedrawClass", "MainWindow", + WS_OVERLAPPEDWINDOW, 0, 0, 200, 100, + NULL, NULL, 0, &flags); + ShowWindow(hwnd, SW_SHOW); + UpdateWindow(hwnd); + while(PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE) != 0) + { + if (msg.message == WM_PAINT) loopcount++; + if (loopcount >= 100) break; + TranslateMessage(&msg); + DispatchMessage(&msg); + MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT); + } + if (flags == (RDW_INVALIDATE | RDW_FRAME)) + todo_wine ok(loopcount < 100, "Detected infinite WM_PAINT loop (%x).\n", flags); + else + ok(loopcount < 100, "Detected infinite WM_PAINT loop (%x).\n", flags); + DestroyWindow(hwnd); +} + +static void test_NCRedraw(void) +{ + WNDCLASSA wndclass; + + wndclass.lpszClassName = "TestNCRedrawClass"; + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = TestNCRedraw_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = 0; + wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); + wndclass.lpszMenuName = NULL; + + RegisterClassA(&wndclass); + + run_NCRedrawLoop(RDW_INVALIDATE | RDW_FRAME); + run_NCRedrawLoop(RDW_INVALIDATE); +} + +static void test_GetWindowModuleFileName(void) +{ + HWND hwnd; + HINSTANCE hinst; + UINT ret1, ret2; + char buf1[MAX_PATH], buf2[MAX_PATH]; + + if (!pGetWindowModuleFileNameA) + { + win_skip("GetWindowModuleFileNameA is not available\n"); + return; + } + + hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0, 0, 0, 0, NULL); + assert(hwnd); + + hinst = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE); + ok(hinst == 0 || broken(hinst == GetModuleHandle(0)), /* win9x */ "expected 0, got %p\n", hinst); + + buf1[0] = 0; + SetLastError(0xdeadbeef); + ret1 = GetModuleFileName(hinst, buf1, sizeof(buf1)); + ok(ret1, "GetModuleFileName error %u\n", GetLastError()); + + buf2[0] = 0; + SetLastError(0xdeadbeef); + ret2 = pGetWindowModuleFileNameA(hwnd, buf2, sizeof(buf2)); + ok(ret2 || broken(!ret2), /* nt4 sp 3 */ + "GetWindowModuleFileNameA error %u\n", GetLastError()); + + if (ret2) + { + ok(ret1 == ret2 || broken(ret2 == ret1 + 1), /* win98 */ "%u != %u\n", ret1, ret2); + ok(!strcmp(buf1, buf2), "%s != %s\n", buf1, buf2); + } + hinst = GetModuleHandle(0); + + SetLastError(0xdeadbeef); + ret2 = GetModuleFileName(hinst, buf2, ret1 - 2); + ok(ret2 == ret1 - 2 || broken(ret2 == ret1 - 3), /* win98 */ + "expected %u, got %u\n", ret1 - 2, ret2); + ok(GetLastError() == 0xdeadbeef /* XP */ || + GetLastError() == ERROR_INSUFFICIENT_BUFFER, /* win2k3, vista */ + "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret2 = GetModuleFileName(hinst, buf2, 0); + ok(!ret2, "GetModuleFileName should return 0\n"); + ok(GetLastError() == 0xdeadbeef /* XP */ || + GetLastError() == ERROR_INSUFFICIENT_BUFFER, /* win2k3, vista */ + "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret2 = pGetWindowModuleFileNameA(hwnd, buf2, ret1 - 2); + ok(ret2 == ret1 - 2 || broken(ret2 == ret1 - 3) /* win98 */ || broken(!ret2), /* nt4 sp3 */ + "expected %u, got %u\n", ret1 - 2, ret2); + ok(GetLastError() == 0xdeadbeef /* XP */ || + GetLastError() == ERROR_INSUFFICIENT_BUFFER, /* win2k3, vista */ + "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret2 = pGetWindowModuleFileNameA(hwnd, buf2, 0); + ok(!ret2, "expected 0, got %u\n", ret2); + ok(GetLastError() == 0xdeadbeef /* XP */ || + GetLastError() == ERROR_INSUFFICIENT_BUFFER, /* win2k3, vista */ + "expected 0xdeadbeef or ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + + DestroyWindow(hwnd); + + buf2[0] = 0; + hwnd = (HWND)0xdeadbeef; + SetLastError(0xdeadbeef); + ret1 = pGetWindowModuleFileNameA(hwnd, buf1, sizeof(buf1)); + ok(!ret1, "expected 0, got %u\n", ret1); + ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef), /* win9x */ + "expected ERROR_INVALID_WINDOW_HANDLE, got %u\n", GetLastError()); + + hwnd = FindWindow("Shell_TrayWnd", NULL); + ok(IsWindow(hwnd) || broken(!hwnd), "got invalid tray window %p\n", hwnd); + SetLastError(0xdeadbeef); + ret1 = pGetWindowModuleFileNameA(hwnd, buf1, sizeof(buf1)); + ok(!ret1 || broken(ret1), /* win98 */ "expected 0, got %u\n", ret1); + + if (!ret1) /* inter-process GetWindowModuleFileName works on win9x, so don't test the desktop there */ + { + ret1 = GetModuleFileName(0, buf1, sizeof(buf1)); + hwnd = GetDesktopWindow(); + ok(IsWindow(hwnd), "got invalid desktop window %p\n", hwnd); + SetLastError(0xdeadbeef); + ret2 = pGetWindowModuleFileNameA(hwnd, buf2, sizeof(buf2)); + ok(!ret2 || + ret1 == ret2 || /* vista */ + broken(ret2), /* some win98 return user.exe as file name */ + "expected 0 or %u, got %u %s\n", ret1, ret2, buf2); + } +} + +static void test_hwnd_message(void) +{ + static const WCHAR mainwindowclassW[] = {'M','a','i','n','W','i','n','d','o','w','C','l','a','s','s',0}; + static const WCHAR message_windowW[] = {'m','e','s','s','a','g','e',' ','w','i','n','d','o','w',0}; + + HWND parent = 0, hwnd, found; + RECT rect; + + /* HWND_MESSAGE is not supported below w2k, but win9x return != 0 + on CreateWindowExA and crash later in the test. + Use UNICODE here to fail on win9x */ + hwnd = CreateWindowExW(0, mainwindowclassW, message_windowW, WS_CAPTION | WS_VISIBLE, + 100, 100, 200, 200, HWND_MESSAGE, 0, 0, NULL); + if (!hwnd) + { + win_skip("CreateWindowExW with parent HWND_MESSAGE failed\n"); + return; + } + + ok( !GetParent(hwnd), "GetParent should return 0 for message only windows\n" ); if (pGetAncestor) { - hwndMessage = pGetAncestor(hwndMain, GA_PARENT); - ok(hwndMessage != 0, "GetAncestor(GA_PARENT) should not return 0 for message only windows\n"); - trace("hwndMessage %p\n", hwndMessage); + char buffer[100]; + HWND root, desktop = GetDesktopWindow(); + + parent = pGetAncestor(hwnd, GA_PARENT); + ok(parent != 0, "GetAncestor(GA_PARENT) should not return 0 for message windows\n"); + ok(parent != desktop, "GetAncestor(GA_PARENT) should not return desktop for message windows\n"); + root = pGetAncestor(hwnd, GA_ROOT); + ok(root == hwnd, "GetAncestor(GA_ROOT) should return hwnd for message windows\n"); + ok( !pGetAncestor(parent, GA_PARENT) || broken(pGetAncestor(parent, GA_PARENT) != 0), /* win2k */ + "parent shouldn't have parent %p\n", pGetAncestor(parent, GA_PARENT) ); + trace("parent %p root %p desktop %p\n", parent, root, desktop); + if (!GetClassNameA( parent, buffer, sizeof(buffer) )) buffer[0] = 0; + ok( !lstrcmpi( buffer, "Message" ), "wrong parent class '%s'\n", buffer ); + GetWindowRect( parent, &rect ); + ok( rect.left == 0 && rect.right == 100 && rect.top == 0 && rect.bottom == 100, + "wrong parent rect %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); } - DestroyWindow(hwndMain); + GetWindowRect( hwnd, &rect ); + ok( rect.left == 100 && rect.right == 300 && rect.top == 100 && rect.bottom == 300, + "wrong window rect %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom ); + + /* test FindWindow behavior */ + + found = FindWindowExA( 0, 0, 0, "message window" ); + ok( found == hwnd, "didn't find message window %p/%p\n", found, hwnd ); + SetLastError(0xdeadbeef); + found = FindWindowExA( GetDesktopWindow(), 0, 0, "message window" ); + ok( found == 0, "found message window %p/%p\n", found, hwnd ); + ok( GetLastError() == 0xdeadbeef, "expected deadbeef, got %d\n", GetLastError() ); + if (parent) + { + found = FindWindowExA( parent, 0, 0, "message window" ); + ok( found == hwnd, "didn't find message window %p/%p\n", found, hwnd ); } + + /* test IsChild behavior */ + + if (parent) ok( !IsChild( parent, hwnd ), "HWND_MESSAGE is child of top window\n" ); + + /* test IsWindowVisible behavior */ + + ok( !IsWindowVisible( hwnd ), "HWND_MESSAGE window is visible\n" ); + if (parent) ok( !IsWindowVisible( parent ), "HWND_MESSAGE parent is visible\n" ); + + DestroyWindow(hwnd); +} + +static void test_layered_window(void) +{ + HWND hwnd; + COLORREF key = 0; + BYTE alpha = 0; + DWORD flags = 0; + BOOL ret; + + if (!pGetLayeredWindowAttributes || !pSetLayeredWindowAttributes) + { + win_skip( "layered windows not supported\n" ); + return; + } + hwnd = CreateWindowExA(0, "MainWindowClass", "message window", WS_CAPTION, + 100, 100, 200, 200, 0, 0, 0, NULL); + assert( hwnd ); + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( !ret, "GetLayeredWindowAttributes should fail on non-layered window\n" ); + ret = pSetLayeredWindowAttributes( hwnd, 0, 0, LWA_ALPHA ); + ok( !ret, "SetLayeredWindowAttributes should fail on non-layered window\n" ); + SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED ); + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( !ret, "GetLayeredWindowAttributes should fail on layered but not initialized window\n" ); + ret = pSetLayeredWindowAttributes( hwnd, 0x123456, 44, LWA_ALPHA ); + ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); + ok( key == 0x123456 || key == 0, "wrong color key %x\n", key ); + ok( alpha == 44, "wrong alpha %u\n", alpha ); + ok( flags == LWA_ALPHA, "wrong flags %x\n", flags ); + + /* clearing WS_EX_LAYERED resets attributes */ + SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED ); + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( !ret, "GetLayeredWindowAttributes should fail on no longer layered window\n" ); + SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED ); + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( !ret, "GetLayeredWindowAttributes should fail on layered but not initialized window\n" ); + ret = pSetLayeredWindowAttributes( hwnd, 0x654321, 22, LWA_COLORKEY | LWA_ALPHA ); + ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); + ok( key == 0x654321, "wrong color key %x\n", key ); + ok( alpha == 22, "wrong alpha %u\n", alpha ); + ok( flags == (LWA_COLORKEY | LWA_ALPHA), "wrong flags %x\n", flags ); + + ret = pSetLayeredWindowAttributes( hwnd, 0x888888, 33, LWA_COLORKEY ); + ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); + alpha = 0; + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); + ok( key == 0x888888, "wrong color key %x\n", key ); + /* alpha not changed on vista if LWA_ALPHA is not set */ + ok( alpha == 22 || alpha == 33, "wrong alpha %u\n", alpha ); + ok( flags == LWA_COLORKEY, "wrong flags %x\n", flags ); + + /* color key may or may not be changed without LWA_COLORKEY */ + ret = pSetLayeredWindowAttributes( hwnd, 0x999999, 44, 0 ); + ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); + alpha = 0; + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); + ok( key == 0x888888 || key == 0x999999, "wrong color key %x\n", key ); + ok( alpha == 22 || alpha == 44, "wrong alpha %u\n", alpha ); + ok( flags == 0, "wrong flags %x\n", flags ); + + /* default alpha and color key is 0 */ + SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED ); + SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED ); + ret = pSetLayeredWindowAttributes( hwnd, 0x222222, 55, 0 ); + ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" ); + ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags ); + ok( ret, "GetLayeredWindowAttributes should succeed on layered window\n" ); + ok( key == 0 || key == 0x222222, "wrong color key %x\n", key ); + ok( alpha == 0 || alpha == 55, "wrong alpha %u\n", alpha ); + ok( flags == 0, "wrong flags %x\n", flags ); + + DestroyWindow( hwnd ); +} + +static MONITORINFO mi; + +static LRESULT CALLBACK fullscreen_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + switch (msg) + { + case WM_NCCREATE: + { + CREATESTRUCTA *cs = (CREATESTRUCTA *)lp; + trace("WM_NCCREATE: rect %d,%d-%d,%d\n", cs->x, cs->y, cs->cx, cs->cy); + ok(cs->x == mi.rcMonitor.left && cs->y == mi.rcMonitor.top && + cs->cx == mi.rcMonitor.right && cs->cy == mi.rcMonitor.bottom, + "expected %d,%d-%d,%d, got %d,%d-%d,%d\n", + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + cs->x, cs->y, cs->cx, cs->cy); + break; + } + case WM_GETMINMAXINFO: + { + MINMAXINFO *minmax = (MINMAXINFO *)lp; + dump_minmax_info(minmax); + ok(minmax->ptMaxPosition.x <= mi.rcMonitor.left, "%d <= %d\n", minmax->ptMaxPosition.x, mi.rcMonitor.left); + ok(minmax->ptMaxPosition.y <= mi.rcMonitor.top, "%d <= %d\n", minmax->ptMaxPosition.y, mi.rcMonitor.top); + ok(minmax->ptMaxSize.x >= mi.rcMonitor.right, "%d >= %d\n", minmax->ptMaxSize.x, mi.rcMonitor.right); + ok(minmax->ptMaxSize.y >= mi.rcMonitor.bottom, "%d >= %d\n", minmax->ptMaxSize.y, mi.rcMonitor.bottom); + break; + } + } + return DefWindowProc(hwnd, msg, wp, lp); +} + +static void test_fullscreen(void) +{ + static const DWORD t_style[] = { + WS_OVERLAPPED, WS_POPUP, WS_CHILD, WS_THICKFRAME, WS_DLGFRAME + }; + static const DWORD t_ex_style[] = { + 0, WS_EX_APPWINDOW, WS_EX_TOOLWINDOW + }; + WNDCLASS cls; + HWND hwnd; + int i, j; + POINT pt; + RECT rc; + HMONITOR hmon; + LRESULT ret; + + if (!pGetMonitorInfoA || !pMonitorFromPoint) + { + win_skip("GetMonitorInfoA or MonitorFromPoint are not available on this platform\n"); + return; + } + + pt.x = pt.y = 0; + SetLastError(0xdeadbeef); + hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); + ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError()); + + mi.cbSize = sizeof(mi); + SetLastError(0xdeadbeef); + ret = pGetMonitorInfoA(hmon, &mi); + ok(ret, "GetMonitorInfo error %u\n", GetLastError()); + trace("monitor (%d,%d-%d,%d), work (%d,%d-%d,%d)\n", + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom); + + cls.style = 0; + cls.lpfnWndProc = fullscreen_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandle(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "fullscreen_class"; + RegisterClass(&cls); + + for (i = 0; i < sizeof(t_style)/sizeof(t_style[0]); i++) + { + DWORD style, ex_style; + + /* avoid a WM interaction */ + assert(!(t_style[i] & WS_VISIBLE)); + + for (j = 0; j < sizeof(t_ex_style)/sizeof(t_ex_style[0]); j++) + { + int fixup; + + style = t_style[i]; + ex_style = t_ex_style[j]; + + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_MAXIMIZE; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_MAXIMIZE | WS_CAPTION; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_CAPTION | WS_MAXIMIZEBOX; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_MAXIMIZE | WS_CAPTION | WS_MAXIMIZEBOX; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + /* Windows makes a maximized window slightly larger (to hide the borders?) */ + fixup = min(abs(rc.left), abs(rc.top)); + InflateRect(&rc, -fixup, -fixup); + ok(rc.left >= mi.rcWork.left && rc.top <= mi.rcWork.top && + rc.right <= mi.rcWork.right && rc.bottom <= mi.rcWork.bottom, + "%#x/%#x: window rect %d,%d-%d,%d must be in %d,%d-%d,%d\n", + ex_style, style, rc.left, rc.top, rc.right, rc.bottom, + mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom); + DestroyWindow(hwnd); + + style = t_style[i] | WS_MAXIMIZE | WS_MAXIMIZEBOX; + hwnd = CreateWindowExA(ex_style, "fullscreen_class", NULL, style, + mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, + GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + ok(hwnd != 0, "%d: CreateWindowExA(%#x/%#x) failed\n", i, ex_style, style); + GetWindowRect(hwnd, &rc); + trace("%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + /* Windows makes a maximized window slightly larger (to hide the borders?) */ + fixup = min(abs(rc.left), abs(rc.top)); + InflateRect(&rc, -fixup, -fixup); + if (style & (WS_CHILD | WS_POPUP)) + ok(rc.left <= mi.rcMonitor.left && rc.top <= mi.rcMonitor.top && + rc.right >= mi.rcMonitor.right && rc.bottom >= mi.rcMonitor.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); else - trace("CreateWindowExA with parent HWND_MESSAGE failed\n"); + ok(rc.left >= mi.rcWork.left && rc.top <= mi.rcWork.top && + rc.right <= mi.rcWork.right && rc.bottom <= mi.rcWork.bottom, + "%#x/%#x: window rect %d,%d-%d,%d\n", ex_style, style, rc.left, rc.top, rc.right, rc.bottom); + DestroyWindow(hwnd); + } + } + + UnregisterClass("fullscreen_class", GetModuleHandle(0)); +} + +static BOOL test_thick_child_got_minmax; +static const char * test_thick_child_name; +static LONG test_thick_child_style; +static LONG test_thick_child_exStyle; + +static LRESULT WINAPI test_thick_child_size_winproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + MINMAXINFO* minmax; + int expectedMinTrackX; + int expectedMinTrackY; + int actualMinTrackX; + int actualMinTrackY; + int expectedMaxTrackX; + int expectedMaxTrackY; + int actualMaxTrackX; + int actualMaxTrackY; + int expectedMaxSizeX; + int expectedMaxSizeY; + int actualMaxSizeX; + int actualMaxSizeY; + int expectedPosX; + int expectedPosY; + int actualPosX; + int actualPosY; + LONG adjustedStyle; + RECT rect; + switch (msg) + { + case WM_GETMINMAXINFO: + { + minmax = (MINMAXINFO *)lparam; + trace("hwnd %p, WM_GETMINMAXINFO, %08lx, %08lx\n", hwnd, wparam, lparam); + dump_minmax_info( minmax ); + + test_thick_child_got_minmax = TRUE; + + + adjustedStyle = test_thick_child_style; + if ((adjustedStyle & WS_CAPTION) == WS_CAPTION) + adjustedStyle &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */ + GetClientRect(GetParent(hwnd), &rect); + AdjustWindowRectEx(&rect, adjustedStyle, FALSE, test_thick_child_exStyle); + + if (test_thick_child_style & (WS_DLGFRAME | WS_BORDER)) + { + expectedMinTrackX = GetSystemMetrics(SM_CXMINTRACK); + expectedMinTrackY = GetSystemMetrics(SM_CYMINTRACK); + } + else + { + expectedMinTrackX = -2 * rect.left; + expectedMinTrackY = -2 * rect.top; + } + actualMinTrackX = minmax->ptMinTrackSize.x; + actualMinTrackY = minmax->ptMinTrackSize.y; + + ok(actualMinTrackX == expectedMinTrackX && actualMinTrackY == expectedMinTrackY, + "expected minTrack %dx%d, actual minTrack %dx%d for %s\n", + expectedMinTrackX, expectedMinTrackY, actualMinTrackX, actualMinTrackY, + test_thick_child_name); + + actualMaxTrackX = minmax->ptMaxTrackSize.x; + actualMaxTrackY = minmax->ptMaxTrackSize.y; + expectedMaxTrackX = GetSystemMetrics(SM_CXMAXTRACK); + expectedMaxTrackY = GetSystemMetrics(SM_CYMAXTRACK); + ok(actualMaxTrackX == expectedMaxTrackX && actualMaxTrackY == expectedMaxTrackY, + "expected maxTrack %dx%d, actual maxTrack %dx%d for %s\n", + expectedMaxTrackX, expectedMaxTrackY, actualMaxTrackX, actualMaxTrackY, + test_thick_child_name); + + expectedMaxSizeX = rect.right - rect.left; + expectedMaxSizeY = rect.bottom - rect.top; + actualMaxSizeX = minmax->ptMaxSize.x; + actualMaxSizeY = minmax->ptMaxSize.y; + + ok(actualMaxSizeX == expectedMaxSizeX && actualMaxSizeY == expectedMaxSizeY, + "expected maxSize %dx%d, actual maxSize %dx%d for %s\n", + expectedMaxSizeX, expectedMaxSizeY, actualMaxSizeX, actualMaxSizeY, + test_thick_child_name); + + + expectedPosX = rect.left; + expectedPosY = rect.top; + actualPosX = minmax->ptMaxPosition.x; + actualPosY = minmax->ptMaxPosition.y; + ok(actualPosX == expectedPosX && actualPosY == expectedPosY, + "expected maxPosition (%d/%d), actual maxPosition (%d/%d) for %s\n", + expectedPosX, expectedPosY, actualPosX, actualPosY, test_thick_child_name); + + break; + } + } + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +#define NUMBER_OF_THICK_CHILD_TESTS 16 +static void test_thick_child_size(HWND parentWindow) +{ + BOOL success; + RECT childRect; + RECT adjustedParentRect; + HWND childWindow; + LONG childWidth; + LONG childHeight; + LONG expectedWidth; + LONG expectedHeight; + WNDCLASSA cls; + LPCTSTR className = "THICK_CHILD_CLASS"; + int i; + LONG adjustedStyle; + static const LONG styles[NUMBER_OF_THICK_CHILD_TESTS] = { + WS_CHILD | WS_VISIBLE | WS_THICKFRAME, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME | WS_BORDER, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_BORDER, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME | WS_BORDER, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_BORDER, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME | WS_BORDER, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_BORDER, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME | WS_BORDER, + WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_BORDER, + }; + + static const LONG exStyles[NUMBER_OF_THICK_CHILD_TESTS] = { + 0, + 0, + 0, + 0, + WS_EX_DLGMODALFRAME, + WS_EX_DLGMODALFRAME, + WS_EX_DLGMODALFRAME, + WS_EX_DLGMODALFRAME, + WS_EX_STATICEDGE, + WS_EX_STATICEDGE, + WS_EX_STATICEDGE, + WS_EX_STATICEDGE, + WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME, + WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME, + WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME, + WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME, + }; + static const char *styleName[NUMBER_OF_THICK_CHILD_TESTS] = { + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME | WS_BORDER", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_BORDER", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME, exstyle= WS_EX_DLGMODALFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME exstyle= WS_EX_DLGMODALFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME | WS_BORDER exstyle= WS_EX_DLGMODALFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_BORDER exstyle= WS_EX_DLGMODALFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME exstyle= WS_EX_STATICEDGE", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME exstyle= WS_EX_STATICEDGE", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME | WS_BORDER exstyle= WS_EX_STATICEDGE", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_BORDER exstyle= WS_EX_STATICEDGE", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME, exstyle= WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME exstyle= WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_DLGFRAME | WS_BORDER exstyle= WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME", + "style=WS_CHILD | WS_VISIBLE | WS_THICKFRAME | WS_BORDER exstyle= WS_EX_STATICEDGE | WS_EX_DLGMODALFRAME", + }; + + cls.style = 0; + cls.lpfnWndProc = test_thick_child_size_winproc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = className; + SetLastError(0xdeadbeef); + ok(RegisterClassA(&cls),"RegisterClassA failed, error: %u\n", GetLastError()); + + for(i = 0; i < NUMBER_OF_THICK_CHILD_TESTS; i++) + { + test_thick_child_name = styleName[i]; + test_thick_child_style = styles[i]; + test_thick_child_exStyle = exStyles[i]; + test_thick_child_got_minmax = FALSE; + + SetLastError(0xdeadbeef); + childWindow = CreateWindowEx( exStyles[i], className, "", styles[i], 0, 0, 0, 0, parentWindow, 0, GetModuleHandleA(0), NULL ); + ok(childWindow != NULL, "Failed to create child window, error: %u\n", GetLastError()); + + ok(test_thick_child_got_minmax, "Got no WM_GETMINMAXINFO\n"); + + SetLastError(0xdeadbeef); + success = GetWindowRect(childWindow, &childRect); + ok(success,"GetWindowRect call failed, error: %u\n", GetLastError()); + childWidth = childRect.right - childRect.left; + childHeight = childRect.bottom - childRect.top; + + adjustedStyle = styles[i]; + if ((adjustedStyle & WS_CAPTION) == WS_CAPTION) + adjustedStyle &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */ + GetClientRect(GetParent(childWindow), &adjustedParentRect); + AdjustWindowRectEx(&adjustedParentRect, adjustedStyle, FALSE, test_thick_child_exStyle); + + + if (test_thick_child_style & (WS_DLGFRAME | WS_BORDER)) + { + expectedWidth = GetSystemMetrics(SM_CXMINTRACK); + expectedHeight = GetSystemMetrics(SM_CYMINTRACK); + } + else + { + expectedWidth = -2 * adjustedParentRect.left; + expectedHeight = -2 * adjustedParentRect.top; + } + + ok((childWidth == expectedWidth) && (childHeight == expectedHeight), + "size of window (%s) is wrong: expected size %dx%d != actual size %dx%d\n", + test_thick_child_name, expectedWidth, expectedHeight, childWidth, childHeight); + + SetLastError(0xdeadbeef); + success = DestroyWindow(childWindow); + ok(success,"DestroyWindow call failed, error: %u\n", GetLastError()); + } + ok(UnregisterClass(className, GetModuleHandleA(0)),"UnregisterClass call failed\n"); +} + +static void test_handles( HWND full_hwnd ) +{ + HWND hwnd = full_hwnd; + BOOL ret; + RECT rect; + + SetLastError( 0xdeadbeef ); + ret = GetWindowRect( hwnd, &rect ); + ok( ret, "GetWindowRect failed for %p err %u\n", hwnd, GetLastError() ); + +#ifdef _WIN64 + if ((ULONG_PTR)full_hwnd >> 32) + hwnd = (HWND)((ULONG_PTR)full_hwnd & ~0u); + else + hwnd = (HWND)((ULONG_PTR)full_hwnd | ((ULONG_PTR)~0u << 32)); + SetLastError( 0xdeadbeef ); + ret = GetWindowRect( hwnd, &rect ); + ok( ret, "GetWindowRect failed for %p err %u\n", hwnd, GetLastError() ); + + hwnd = (HWND)(((ULONG_PTR)full_hwnd & ~0u) | ((ULONG_PTR)0x1234 << 32)); + SetLastError( 0xdeadbeef ); + ret = GetWindowRect( hwnd, &rect ); + ok( ret, "GetWindowRect failed for %p err %u\n", hwnd, GetLastError() ); + + hwnd = (HWND)(((ULONG_PTR)full_hwnd & 0xffff) | ((ULONG_PTR)0x9876 << 16)); + SetLastError( 0xdeadbeef ); + ret = GetWindowRect( hwnd, &rect ); + ok( !ret, "GetWindowRect succeeded for %p\n", hwnd ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); + + hwnd = (HWND)(((ULONG_PTR)full_hwnd & 0xffff) | ((ULONG_PTR)0x12345678 << 16)); + SetLastError( 0xdeadbeef ); + ret = GetWindowRect( hwnd, &rect ); + ok( !ret, "GetWindowRect succeeded for %p\n", hwnd ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() ); +#endif +} + +static void test_winregion(void) +{ + HWND hwnd; + RECT r; + int ret; + HRGN hrgn; + + if (!pGetWindowRgnBox) + { + win_skip("GetWindowRgnBox not supported\n"); + return; + } + + hwnd = CreateWindowExA(0, "static", NULL, WS_VISIBLE, 10, 10, 10, 10, NULL, 0, 0, NULL); + /* NULL prect */ + SetLastError(0xdeadbeef); + ret = pGetWindowRgnBox(hwnd, NULL); + ok( ret == ERROR, "Expected ERROR, got %d\n", ret); + ok( GetLastError() == 0xdeadbeef, "Expected , got %d\n", GetLastError()); + + hrgn = CreateRectRgn(2, 3, 10, 15); + ok( hrgn != NULL, "Region creation failed\n"); + if (hrgn) + { + SetWindowRgn(hwnd, hrgn, FALSE); + + SetLastError(0xdeadbeef); + ret = pGetWindowRgnBox(hwnd, NULL); + ok( ret == ERROR, "Expected ERROR, got %d\n", ret); + ok( GetLastError() == 0xdeadbeef, "Expected , got %d\n", GetLastError()); + + r.left = r.top = r.right = r.bottom = 0; + ret = pGetWindowRgnBox(hwnd, &r); + ok( ret == SIMPLEREGION, "Expected SIMPLEREGION, got %d\n", ret); + ok( r.left == 2 && r.top == 3 && r.right == 10 && r.bottom == 15, + "Expected (2,3,10,15), got (%d,%d,%d,%d)\n", r.left, r.top, + r.right, r.bottom); + DeleteObject(hrgn); + } + DestroyWindow(hwnd); +} + +START_TEST(win) +{ + HMODULE user32 = GetModuleHandleA( "user32.dll" ); + pGetAncestor = (void *)GetProcAddress( user32, "GetAncestor" ); + pGetWindowInfo = (void *)GetProcAddress( user32, "GetWindowInfo" ); + pGetWindowModuleFileNameA = (void *)GetProcAddress( user32, "GetWindowModuleFileNameA" ); + pGetLayeredWindowAttributes = (void *)GetProcAddress( user32, "GetLayeredWindowAttributes" ); + pSetLayeredWindowAttributes = (void *)GetProcAddress( user32, "SetLayeredWindowAttributes" ); + pGetMonitorInfoA = (void *)GetProcAddress( user32, "GetMonitorInfoA" ); + pMonitorFromPoint = (void *)GetProcAddress( user32, "MonitorFromPoint" ); + pGetWindowRgnBox = (void *)GetProcAddress( user32, "GetWindowRgnBox" ); if (!RegisterWindowClasses()) assert(0); hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); - assert(hhook); + if (!hhook) win_skip( "Cannot set CBT hook, skipping some tests\n" ); hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, 100, 100, 200, 200, 0, 0, GetModuleHandle(0), NULL); - test_nonclient_area(hwndMain); - hwndMain2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, @@ -4674,8 +5812,12 @@ START_TEST(win) our_pid = GetWindowThreadProcessId(hwndMain, NULL); /* Add the tests below this line */ + test_thick_child_size(hwndMain); + test_fullscreen(); + test_hwnd_message(); + test_nonclient_area(hwndMain); test_params(); - + test_GetWindowModuleFileName(); test_capture_1(); test_capture_2(); test_capture_3(hwndMain, hwndMain2); @@ -4683,7 +5825,7 @@ START_TEST(win) test_CreateWindow(); test_parent_owner(); test_SetParent(); - test_shell_window(); + test_enum_thread_windows(); test_mdi(); test_icons(); @@ -4691,7 +5833,7 @@ START_TEST(win) test_SetMenu(hwndMain); test_SetFocus(hwndMain); test_SetActiveWindow(hwndMain); - test_SetForegroundWindow(hwndMain); + test_NCRedraw(); test_children_zorder(hwndMain); test_popup_zorder(hwndMain2, hwndMain); @@ -4699,6 +5841,7 @@ START_TEST(win) test_mouse_input(hwndMain); test_validatergn(hwndMain); test_nccalcscroll( hwndMain); + test_scrollwindow( hwndMain); test_scrollvalidate( hwndMain); test_scrolldc( hwndMain); test_scroll(); @@ -4711,10 +5854,19 @@ START_TEST(win) test_csparentdc(); test_SetWindowLong(); test_ShowWindow(); - test_gettext(); + if (0) test_gettext(); /* crashes on NT4 */ test_GetUpdateRect(); test_Expose(); + test_layered_window(); + + test_SetForegroundWindow(hwndMain); +// test_shell_window(); + test_handles( hwndMain ); + test_winregion(); /* add the tests above this line */ - UnhookWindowsHookEx(hhook); + if (hhook) UnhookWindowsHookEx(hhook); + + DestroyWindow(hwndMain2); + DestroyWindow(hwndMain); } diff --git a/rostests/winetests/user32/winstation.c b/rostests/winetests/user32/winstation.c index 42f2644b295..596e9ffd8d6 100755 --- a/rostests/winetests/user32/winstation.c +++ b/rostests/winetests/user32/winstation.c @@ -53,7 +53,7 @@ static void register_class(void) cls.cbWndExtra = 0; cls.hInstance = GetModuleHandleA(0); cls.hIcon = 0; - cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hCursor = LoadCursorA(0, IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpszMenuName = NULL; cls.lpszClassName = "WinStationClass"; @@ -122,7 +122,9 @@ static void test_handles(void) flags = 0; ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" ); - ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", w1 ); + ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) || + broken(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), /* set on nt4 */ + "handle %p PROTECT_FROM_CLOSE set\n", w1 ); ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0, TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); @@ -201,7 +203,11 @@ static void test_handles(void) ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() ); SetLastError( 0xdeadbeef ); - ok( !CloseHandle(d1), "closing thread desktop handle failed\n" ); + if (CloseHandle( d1 )) /* succeeds on nt4 */ + { + win_skip( "NT4 desktop handle management is completely different\n" ); + return; + } ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() ); ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0, diff --git a/rostests/winetests/user32/wsprintf.c b/rostests/winetests/user32/wsprintf.c index c0ca1c6703a..bca16bd9f86 100755 --- a/rostests/winetests/user32/wsprintf.c +++ b/rostests/winetests/user32/wsprintf.c @@ -45,7 +45,7 @@ static void wsprintfWTest(void) rc=wsprintfW(buf, fmt, -1); if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { - skip("wsprintfW is not implemented\n"); + win_skip("wsprintfW is not implemented\n"); return; } ok(rc == 10, "wsPrintfW length failure: rc=%d error=%d\n",rc,GetLastError()); @@ -59,12 +59,12 @@ static void wsprintfWTest(void) static void CharUpperTest(void) { - int i,out,failed; + INT_PTR i,out,failed; failed = 0; for (i=0;i<256;i++) { - out = (int) CharUpper((LPTSTR)i); + out = (INT_PTR)CharUpper((LPTSTR)i); /* printf("%0x ",out); */ if ((out >> 16) != 0) { @@ -72,17 +72,17 @@ static void CharUpperTest(void) break; } } - ok(!failed,"CharUpper failed - 16bit input (0x%0x) returned 32bit result (0x%0x)\n",i,out); + ok(!failed,"CharUpper failed - 16bit input (0x%0lx) returned 32bit result (0x%0lx)\n",i,out); } static void CharLowerTest(void) { - int i,out,failed; + INT_PTR i,out,failed; failed = 0; for (i=0;i<256;i++) { - out = (int) CharLower((LPTSTR)i); + out = (INT_PTR)CharLower((LPTSTR)i); /* printf("%0x ",out); */ if ((out >> 16) != 0) { @@ -90,7 +90,7 @@ static void CharLowerTest(void) break; } } - ok(!failed,"CharLower failed - 16bit input (0x%0x) returned 32bit result (0x%0x)\n",i,out); + ok(!failed,"CharLower failed - 16bit input (0x%0lx) returned 32bit result (0x%0lx)\n",i,out); } diff --git a/rostests/winetests/userenv/testlist.c b/rostests/winetests/userenv/testlist.c new file mode 100644 index 00000000000..1c6517a0eff --- /dev/null +++ b/rostests/winetests/userenv/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_userenv(void); + +const struct test winetest_testlist[] = +{ + { "userenv", func_userenv }, + { 0, 0 } +}; diff --git a/rostests/winetests/userenv/userenv.c b/rostests/winetests/userenv/userenv.c new file mode 100644 index 00000000000..7c1228beb0a --- /dev/null +++ b/rostests/winetests/userenv/userenv.c @@ -0,0 +1,197 @@ +/* + * Unit test suite for userenv functions + * + * Copyright 2008 Google (Lei Zhang) + * + * 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 + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" + +#include "userenv.h" + +#include "wine/test.h" + +#define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT)) +#define expect_env(EXPECTED,GOT,VAR) ok((GOT)==(EXPECTED), "Expected %d, got %d for %s (%d)\n", (EXPECTED), (GOT), (VAR), j) + +struct profile_item +{ + const char * name; + const int todo[4]; +}; + +/* Helper function for retrieving environment variables */ +static BOOL get_env(const WCHAR * env, const char * var, char ** result) +{ + const WCHAR * p = env; + int envlen, varlen, buflen; + char buf[256]; + + if (!env || !var || !result) return FALSE; + + varlen = strlen(var); + do + { + if (!WideCharToMultiByte( CP_ACP, 0, p, -1, buf, sizeof(buf), NULL, NULL )) buf[sizeof(buf)-1] = 0; + envlen = strlen(buf); + if (CompareStringA(GetThreadLocale(), NORM_IGNORECASE|LOCALE_USE_CP_ACP, buf, min(envlen, varlen), var, varlen) == CSTR_EQUAL) + { + if (buf[varlen] == '=') + { + buflen = strlen(buf); + *result = HeapAlloc(GetProcessHeap(), 0, buflen + 1); + if (!*result) return FALSE; + memcpy(*result, buf, buflen + 1); + return TRUE; + } + } + while (*p) p++; + p++; + } while (*p); + return FALSE; +} + +static void test_create_env(void) +{ + BOOL r; + HANDLE htok; + WCHAR * env[4]; + char * st; + int i, j; + + static const struct profile_item common_vars[] = { + { "ComSpec", { 1, 1, 0, 0 } }, + { "COMPUTERNAME", { 1, 1, 1, 1 } }, + { "NUMBER_OF_PROCESSORS", { 1, 1, 0, 0 } }, + { "OS", { 1, 1, 0, 0 } }, + { "PROCESSOR_ARCHITECTURE", { 1, 1, 0, 0 } }, + { "PROCESSOR_IDENTIFIER", { 1, 1, 0, 0 } }, + { "PROCESSOR_LEVEL", { 1, 1, 0, 0 } }, + { "PROCESSOR_REVISION", { 1, 1, 0, 0 } }, + { "SystemDrive", { 1, 1, 0, 0 } }, + { "SystemRoot", { 1, 1, 0, 0 } }, + { "windir", { 1, 1, 0, 0 } } + }; + static const struct profile_item common_post_nt4_vars[] = { + { "ALLUSERSPROFILE", { 1, 1, 0, 0 } }, + { "TEMP", { 1, 1, 0, 0 } }, + { "TMP", { 1, 1, 0, 0 } }, + { "CommonProgramFiles", { 1, 1, 1, 1 } }, + { "ProgramFiles", { 1, 1, 0, 0 } } + }; + static const struct profile_item htok_vars[] = { + { "PATH", { 1, 1, 0, 0 } }, + { "USERPROFILE", { 1, 1, 0, 0 } } + }; + + r = SetEnvironmentVariableA("WINE_XYZZY", "ZZYZX"); + expect(TRUE, r); + + if (0) + { + /* Crashes on NT4 */ + r = CreateEnvironmentBlock(NULL, NULL, FALSE); + expect(FALSE, r); + } + + r = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &htok); + expect(TRUE, r); + + if (0) + { + /* Crashes on NT4 */ + r = CreateEnvironmentBlock(NULL, htok, FALSE); + expect(FALSE, r); + } + + r = CreateEnvironmentBlock((LPVOID) &env[0], NULL, FALSE); + expect(TRUE, r); + + r = CreateEnvironmentBlock((LPVOID) &env[1], htok, FALSE); + expect(TRUE, r); + + r = CreateEnvironmentBlock((LPVOID) &env[2], NULL, TRUE); + expect(TRUE, r); + + r = CreateEnvironmentBlock((LPVOID) &env[3], htok, TRUE); + expect(TRUE, r); + + /* Test for common environment variables (NT4 and higher) */ + for (i = 0; i < sizeof(common_vars)/sizeof(common_vars[0]); i++) + { + for (j = 0; j < 4; j++) + { + r = get_env(env[j], common_vars[i].name, &st); + if (common_vars[i].todo[j]) + todo_wine expect_env(TRUE, r, common_vars[i].name); + else + expect_env(TRUE, r, common_vars[i].name); + } + } + + /* Test for common environment variables (post NT4) */ + if (!GetEnvironmentVariableA("ALLUSERSPROFILE", NULL, 0)) + { + win_skip("Some environment variables are not present on NT4\n"); + } + else + { + for (i = 0; i < sizeof(common_post_nt4_vars)/sizeof(common_post_nt4_vars[0]); i++) + { + for (j = 0; j < 4; j++) + { + r = get_env(env[j], common_post_nt4_vars[i].name, &st); + if (common_post_nt4_vars[i].todo[j]) + todo_wine expect_env(TRUE, r, common_post_nt4_vars[i].name); + else + expect_env(TRUE, r, common_post_nt4_vars[i].name); + } + } + } + + /* Test for environment variables with values that depends on htok */ + for (i = 0; i < sizeof(htok_vars)/sizeof(htok_vars[0]); i++) + { + for (j = 0; j < 4; j++) + { + r = get_env(env[j], htok_vars[i].name, &st); + if (htok_vars[i].todo[j]) + todo_wine expect_env(TRUE, r, htok_vars[i].name); + else + expect_env(TRUE, r, htok_vars[i].name); + } + } + + r = get_env(env[0], "WINE_XYZZY", &st); + expect(FALSE, r); + r = get_env(env[1], "WINE_XYZZY", &st); + expect(FALSE, r); + r = get_env(env[2], "WINE_XYZZY", &st); + expect(TRUE, r); + r = get_env(env[3], "WINE_XYZZY", &st); + expect(TRUE, r); +} + +START_TEST(userenv) +{ + test_create_env(); +} diff --git a/rostests/winetests/userenv/userenv.rbuild b/rostests/winetests/userenv/userenv.rbuild new file mode 100644 index 00000000000..1b14029ad23 --- /dev/null +++ b/rostests/winetests/userenv/userenv.rbuild @@ -0,0 +1,10 @@ + + . + + userenv.c + testlist.c + wine + userenv + advapi32 + ntdll + diff --git a/rostests/winetests/usp10/usp10.c b/rostests/winetests/usp10/usp10.c index 070590468eb..1eefee0509a 100644 --- a/rostests/winetests/usp10/usp10.c +++ b/rostests/winetests/usp10/usp10.c @@ -40,10 +40,12 @@ static void test_ScriptShape(HDC hdc) BOOL ret; HRESULT hr; SCRIPT_CACHE sc = NULL; - WORD glyphs[4]; + WORD glyphs[4], logclust[4]; SCRIPT_VISATTR attrs[4]; SCRIPT_ITEM items[2]; int nb, widths[4]; + GOFFSET offset[4]; + ABC abc[4]; hr = ScriptItemize(NULL, 4, 2, NULL, NULL, items, NULL); ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr); @@ -61,14 +63,39 @@ static void test_ScriptShape(HDC hdc) hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, NULL); ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr); + hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb); + ok(hr == E_PENDING, "ScriptShape should return E_PENDING not %08x\n", hr); + hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb); + ok(!hr || + hr == E_INVALIDARG, /* Vista, W2K8 */ + "ScriptShape should return S_OK or E_INVALIDARG, not %08x\n", hr); + ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n"); + + hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb); ok(!hr, "ScriptShape should return S_OK not %08x\n", hr); ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n"); + hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb); + ok(!hr, "ScriptShape should return S_OK not %08x\n", hr); + hr = ScriptPlace(hdc, &sc, glyphs, 4, NULL, &items[0].a, widths, NULL, NULL); ok(hr == E_INVALIDARG, "ScriptPlace should return E_INVALIDARG not %08x\n", hr); - hr = ScriptPlace(hdc, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, NULL); + hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, NULL); + ok(hr == E_PENDING || + hr == E_INVALIDARG, /* Vista, W2K8 */ + "ScriptPlace should return E_PENDING or E_INVALIDARG, not %08x\n", hr); + + hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, offset, NULL); + ok(hr == E_PENDING, "ScriptPlace should return E_PENDING not %08x\n", hr); + + hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, abc); + ok(hr == E_PENDING || + hr == E_INVALIDARG, /* Vista, W2K8 */ + "ScriptPlace should return E_PENDING or E_INVALIDARG, not %08x\n", hr); + + hr = ScriptPlace(hdc, &sc, glyphs, 4, attrs, &items[0].a, widths, offset, NULL); ok(!hr, "ScriptPlace should return S_OK not %08x\n", hr); ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n"); @@ -615,22 +642,26 @@ static void test_ScriptXtoX(void) * This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables * ****************************************************************************************/ { + static const WCHAR test[] = {'t', 'e', 's', 't',0}; + SCRIPT_ITEM items[2]; int iX, iCP; int cChars; int cGlyphs; WORD pwLogClust[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; SCRIPT_VISATTR psva[10]; int piAdvance[10] = {200, 190, 210, 180, 170, 204, 189, 195, 212, 203}; - SCRIPT_ANALYSIS psa; int piCP, piX; int piTrailing; BOOL fTrailing; HRESULT hr; + hr = ScriptItemize(test, lstrlenW(test), sizeof(items)/sizeof(items[0]), NULL, NULL, items, NULL); + ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr); + iX = -1; cChars = 10; cGlyphs = 10; - hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing); + hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing); ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr); if (piTrailing) ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP); @@ -640,7 +671,7 @@ static void test_ScriptXtoX(void) iX = 1954; cChars = 10; cGlyphs = 10; - hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing); + hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing); ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr); if (piTrailing) /* win2k3 */ ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP); @@ -650,7 +681,7 @@ static void test_ScriptXtoX(void) iX = 779; cChars = 10; cGlyphs = 10; - hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing); + hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing); ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr); ok(piCP == 3 || piCP == -1, /* win2k3 */ @@ -660,7 +691,7 @@ static void test_ScriptXtoX(void) iX = 780; cChars = 10; cGlyphs = 10; - hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing); + hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing); ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr); ok(piCP == 3 || piCP == -1, /* win2k3 */ @@ -670,7 +701,7 @@ static void test_ScriptXtoX(void) iX = 868; cChars = 10; cGlyphs = 10; - hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing); + hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing); ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr); ok(piCP == 4 || piCP == -1, /* win2k3 */ @@ -679,7 +710,7 @@ static void test_ScriptXtoX(void) iX = 0; cChars = 10; cGlyphs = 10; - hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing); + hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing); ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr); ok(piCP == 0 || piCP == 10, /* win2k3 */ @@ -688,14 +719,14 @@ static void test_ScriptXtoX(void) iX = 195; cChars = 10; cGlyphs = 10; - hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing); + hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing); ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr); ok(piCP == 0, "iX=%d should return piCP=0 not %d\n", iX, piCP); iX = 196; cChars = 10; cGlyphs = 10; - hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing); + hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing); ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr); ok(piCP == 1 || piCP == 0, /* win2k3 */ @@ -705,7 +736,7 @@ static void test_ScriptXtoX(void) fTrailing = FALSE; cChars = 10; cGlyphs = 10; - hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX); + hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX); ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr); ok(piX == 976 || piX == 100, /* win2k3 */ @@ -715,7 +746,7 @@ static void test_ScriptXtoX(void) fTrailing = TRUE; cChars = 10; cGlyphs = 10; - hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX); + hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX); ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr); ok(piX == 1171 || piX == 80, /* win2k3 */ @@ -725,7 +756,7 @@ static void test_ScriptXtoX(void) fTrailing = FALSE; cChars = 10; cGlyphs = 10; - hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX); + hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX); ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr); ok(piX == 1171 || piX == 80, /* win2k3 */ @@ -735,7 +766,7 @@ static void test_ScriptXtoX(void) fTrailing = FALSE; cChars = 10; cGlyphs = 10; - hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX); + hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX); ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr); ok(piX == 1953 || piX == 0, /* win2k3 */ @@ -745,7 +776,7 @@ static void test_ScriptXtoX(void) fTrailing = TRUE; cChars = 10; cGlyphs = 10; - hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX); + hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX); ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr); ok(piX == 1953 || piX == 0, /* win2k3 */ @@ -1086,184 +1117,6 @@ static void test_ScriptLayout(void) } } -static const struct -{ - LGRPID group; - LCID lcid; - SCRIPT_DIGITSUBSTITUTE sds; - DWORD uDefaultLanguage; - DWORD fContextDigits; - WORD fDigitSubstitute; -} -subst_data[] = -{ - { 0x01, 0x00403, { 9, 3, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00406, { 9, 6, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00407, { 9, 7, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00409, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0040a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0040b, { 9, 11, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0040c, { 9, 12, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0040f, { 9, 15, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00410, { 9, 16, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00413, { 9, 19, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00414, { 9, 20, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00416, { 9, 22, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0041d, { 9, 29, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00421, { 9, 33, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0042d, { 9, 45, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00432, { 9, 50, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00434, { 9, 52, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00435, { 9, 53, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00436, { 9, 54, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00438, { 9, 56, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0043a, { 9, 58, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0043b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0043e, { 9, 62, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00441, { 9, 65, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00452, { 9, 82, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00456, { 9, 86, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0046b, { 9, 107, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0046c, { 9, 108, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00481, { 9, 129, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00807, { 9, 7, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00809, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0080a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0080c, { 9, 12, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00810, { 9, 16, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00813, { 9, 19, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00814, { 9, 20, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00816, { 9, 22, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0081d, { 9, 29, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0083b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0083e, { 9, 62, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0086b, { 9, 107, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00c07, { 9, 7, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00c09, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00c0a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00c0c, { 9, 12, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00c3b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x00c6b, { 9, 107, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x01007, { 9, 7, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x01009, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0100a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0100c, { 9, 12, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0103b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x01407, { 9, 7, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x01409, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0140a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0140c, { 9, 12, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0143b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x01809, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0180a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0180c, { 9, 12, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0183b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x01c09, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x01c0a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x01c3b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x02009, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0200a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0203b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x02409, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0240a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0243b, { 9, 59, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x02809, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0280a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x02c09, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x02c0a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x03009, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0300a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x03409, { 9, 9, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0340a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0380a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x03c0a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0400a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0440a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0480a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x04c0a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x0500a, { 9, 10, 1, 0 }, 9, 0, 0 }, - { 0x01, 0x10407, { 9, 7, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x00405, { 9, 5, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x0040e, { 9, 14, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x00415, { 9, 21, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x00418, { 9, 24, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x0041a, { 9, 26, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x0041b, { 9, 27, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x0041c, { 9, 28, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x00424, { 9, 36, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x0081a, { 9, 26, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x0101a, { 9, 26, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x0141a, { 9, 26, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x0181a, { 9, 26, 1, 0 }, 9, 0, 0 }, - { 0x02, 0x1040e, { 9, 14, 1, 0 }, 9, 0, 0 }, - { 0x03, 0x00425, { 9, 37, 1, 0 }, 9, 0, 0 }, - { 0x03, 0x00426, { 9, 38, 1, 0 }, 9, 0, 0 }, - { 0x03, 0x00427, { 9, 39, 1, 0 }, 9, 0, 0 }, - { 0x04, 0x00408, { 9, 8, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00402, { 9, 2, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00419, { 9, 25, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00422, { 9, 34, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00423, { 9, 35, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x0042f, { 9, 47, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x0043f, { 9, 63, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00440, { 9, 64, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00444, { 9, 68, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00450, { 9, 80, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x0082c, { 9, 44, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00843, { 9, 67, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x00c1a, { 9, 26, 1, 0 }, 9, 0, 0 }, - { 0x05, 0x01c1a, { 9, 26, 1, 0 }, 9, 0, 0 }, - { 0x06, 0x0041f, { 9, 31, 1, 0 }, 9, 0, 0 }, - { 0x06, 0x0042c, { 9, 44, 1, 0 }, 9, 0, 0 }, - { 0x06, 0x00443, { 9, 67, 1, 0 }, 9, 0, 0 }, - { 0x07, 0x00411, { 9, 17, 1, 0 }, 9, 0, 0 }, - { 0x08, 0x00412, { 9, 18, 1, 0 }, 9, 0, 0 }, - { 0x09, 0x00404, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x09, 0x00c04, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x09, 0x01404, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x09, 0x21404, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x09, 0x30404, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x0a, 0x00804, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x0a, 0x01004, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x0a, 0x20804, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x0a, 0x21004, { 9, 4, 1, 0 }, 9, 0, 0 }, - { 0x0b, 0x0041e, { 9, 30, 1, 0 }, 9, 0, 0 }, - { 0x0c, 0x0040d, { 9, 13, 1, 0 }, 9, 0, 0 }, - { 0x0d, 0x00401, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x00420, { 9, 32, 1, 0 }, 9, 0, 0 }, - { 0x0d, 0x00429, { 41, 41, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x0045a, { 9, 90, 1, 0 }, 9, 0, 0 }, - { 0x0d, 0x00465, { 9, 101, 1, 0 }, 9, 0, 0 }, - { 0x0d, 0x00801, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x00c01, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x01001, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x01401, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x01801, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x01c01, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x02001, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x02401, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x02801, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x02c01, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x03001, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x03401, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x03801, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x03c01, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0d, 0x04001, { 1, 1, 0, 0 }, 9, 0, 0 }, - { 0x0e, 0x0042a, { 9, 42, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x00439, { 9, 57, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x00446, { 9, 70, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x00447, { 9, 71, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x00449, { 9, 73, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x0044a, { 9, 74, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x0044b, { 9, 75, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x0044e, { 9, 78, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x0044f, { 9, 79, 1, 0 }, 9, 0, 0 }, - { 0x0f, 0x00457, { 9, 87, 1, 0 }, 9, 0, 0 }, - { 0x10, 0x00437, { 9, 55, 1, 0 }, 9, 0, 0 }, - { 0x10, 0x10437, { 9, 55, 1, 0 }, 9, 0, 0 }, - { 0x11, 0x0042b, { 9, 43, 1, 0 }, 9, 0, 0 } -}; - static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam) { HRESULT hr; @@ -1271,7 +1124,6 @@ static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR l SCRIPT_CONTROL sc; SCRIPT_STATE ss; LCID lcid_old; - unsigned int i; if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE; @@ -1288,21 +1140,6 @@ static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR l hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss); ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr); - for (i = 0; i < sizeof(subst_data)/sizeof(subst_data[0]); i++) - { - if (group == subst_data[i].group && lcid == subst_data[i].lcid) - { - ok(!memcmp(&sds, &subst_data[i].sds, sizeof(sds)), - "substitution data does not match\n"); - - ok(sc.uDefaultLanguage == subst_data[i].uDefaultLanguage, - "sc.uDefaultLanguage does not match\n"); - ok(sc.fContextDigits == subst_data[i].fContextDigits, - "sc.fContextDigits does not match\n"); - ok(ss.fDigitSubstitute == subst_data[i].fDigitSubstitute, - "ss.fDigitSubstitute does not match\n"); - } - } SetThreadLocale(lcid_old); return TRUE; } @@ -1339,13 +1176,19 @@ static void test_digit_substitution(void) if (!pEnumLanguageGroupLocalesA) { - trace("EnumLanguageGroupLocalesA not available on this platform\n"); + win_skip("EnumLanguageGroupLocalesA not available on this platform\n"); return; } for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++) { ret = pEnumLanguageGroupLocalesA(enum_proc, groups[i], 0, 0); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("EnumLanguageGroupLocalesA not implemented on this platform\n"); + break; + } + ok(ret, "EnumLanguageGroupLocalesA failed unexpectedly: %u\n", GetLastError()); } } @@ -1369,6 +1212,87 @@ static void test_ScriptGetProperties(void) ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr); } +static void test_ScriptBreak(void) +{ + static const WCHAR test[] = {' ','\r','\n',0}; + SCRIPT_ITEM items[4]; + SCRIPT_LOGATTR la; + HRESULT hr; + + hr = ScriptItemize(test, 3, 4, NULL, NULL, items, NULL); + ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr); + + memset(&la, 0, sizeof(la)); + hr = ScriptBreak(test, 1, &items[0].a, &la); + ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr); + + ok(!la.fSoftBreak, "fSoftBreak set\n"); + ok(la.fWhiteSpace, "fWhiteSpace not set\n"); + ok(la.fCharStop, "fCharStop not set\n"); + ok(!la.fWordStop, "fWordStop set\n"); + ok(!la.fInvalid, "fInvalid set\n"); + ok(!la.fReserved, "fReserved set\n"); + + memset(&la, 0, sizeof(la)); + hr = ScriptBreak(test + 1, 1, &items[1].a, &la); + ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr); + + ok(!la.fSoftBreak, "fSoftBreak set\n"); + ok(!la.fWhiteSpace, "fWhiteSpace set\n"); + ok(la.fCharStop, "fCharStop not set\n"); + ok(!la.fWordStop, "fWordStop set\n"); + ok(!la.fInvalid, "fInvalid set\n"); + ok(!la.fReserved, "fReserved set\n"); + + memset(&la, 0, sizeof(la)); + hr = ScriptBreak(test + 2, 1, &items[2].a, &la); + ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr); + + ok(!la.fSoftBreak, "fSoftBreak set\n"); + ok(!la.fWhiteSpace, "fWhiteSpace set\n"); + ok(la.fCharStop, "fCharStop not set\n"); + ok(!la.fWordStop, "fWordStop set\n"); + ok(!la.fInvalid, "fInvalid set\n"); + ok(!la.fReserved, "fReserved set\n"); +} + +static void test_newlines(void) +{ + static const WCHAR test1[] = {'t','e','x','t','\r','t','e','x','t',0}; + static const WCHAR test2[] = {'t','e','x','t','\n','t','e','x','t',0}; + static const WCHAR test3[] = {'t','e','x','t','\r','\n','t','e','x','t',0}; + static const WCHAR test4[] = {'t','e','x','t','\n','\r','t','e','x','t',0}; + static const WCHAR test5[] = {'1','2','3','4','\n','\r','1','2','3','4',0}; + SCRIPT_ITEM items[5]; + HRESULT hr; + int count; + + count = 0; + hr = ScriptItemize(test1, lstrlenW(test1), 5, NULL, NULL, items, &count); + ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr); + ok(count == 3, "got %d expected 3\n", count); + + count = 0; + hr = ScriptItemize(test2, lstrlenW(test2), 5, NULL, NULL, items, &count); + ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr); + ok(count == 3, "got %d expected 3\n", count); + + count = 0; + hr = ScriptItemize(test3, lstrlenW(test3), 5, NULL, NULL, items, &count); + ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr); + ok(count == 4, "got %d expected 4\n", count); + + count = 0; + hr = ScriptItemize(test4, lstrlenW(test4), 5, NULL, NULL, items, &count); + ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr); + ok(count == 4, "got %d expected 4\n", count); + + count = 0; + hr = ScriptItemize(test5, lstrlenW(test5), 5, NULL, NULL, items, &count); + ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr); + ok(count == 4, "got %d expected 4\n", count); +} + START_TEST(usp10) { HWND hwnd; @@ -1390,7 +1314,7 @@ START_TEST(usp10) ok( hdc != NULL, "HDC failed to be created %p\n", hdc); memset(&lf, 0, sizeof(LOGFONTA)); - lstrcpyA(lf.lfFaceName, "Symbol"); + lstrcpyA(lf.lfFaceName, "Tahoma"); lf.lfHeight = 10; lf.lfWeight = 3; lf.lfWidth = 10; @@ -1413,6 +1337,8 @@ START_TEST(usp10) test_ScriptLayout(); test_digit_substitution(); test_ScriptGetProperties(); + test_ScriptBreak(); + test_newlines(); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); diff --git a/rostests/winetests/usp10/usp10.rbuild b/rostests/winetests/usp10/usp10.rbuild index c1ae4bf968f..94457b5edd8 100644 --- a/rostests/winetests/usp10/usp10.rbuild +++ b/rostests/winetests/usp10/usp10.rbuild @@ -3,15 +3,13 @@ . - 0x600 - 0x600 + usp10.c testlist.c wine usp10 user32 gdi32 - kernel32 ntdll diff --git a/rostests/winetests/uxtheme/system.c b/rostests/winetests/uxtheme/system.c index ef9c08a2522..46e60a7f674 100644 --- a/rostests/winetests/uxtheme/system.c +++ b/rostests/winetests/uxtheme/system.c @@ -85,10 +85,6 @@ static void test_IsThemed(void) SetLastError(0xdeadbeef); bThemeActive = pIsThemeActive(); trace("Theming is %s\n", (bThemeActive) ? "active" : "inactive"); - todo_wine - ok( GetLastError() == ERROR_SUCCESS, - "Expected ERROR_SUCCESS, got 0x%08x\n", - GetLastError()); /* This test is not themed */ SetLastError(0xdeadbeef); @@ -101,7 +97,6 @@ static void test_IsThemed(void) /* Although Wine currently returns FALSE, the logic behind it is wrong. It is not a todo_wine though in the testing sense */ ok( bAppThemed == FALSE, "Expected FALSE as this test executable is not (yet) themed.\n"); - todo_wine ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); @@ -260,7 +255,7 @@ static void test_OpenThemeData(void) ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n", GetLastError()); - trace("No active theme, skipping rest of OpenThemeData tests\n"); + skip("No active theme, skipping rest of OpenThemeData tests\n"); return; } @@ -382,7 +377,7 @@ static void test_GetCurrentThemeName(void) hRes = pGetCurrentThemeName(currentTheme, 2, NULL, 0, NULL, 0); if (bThemeActive) todo_wine - ok( LOWORD(hRes) == ERROR_INSUFFICIENT_BUFFER, "Expected 0x8007007A, got 0x%08x\n", hRes); + ok(hRes == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, @@ -396,7 +391,7 @@ static void test_GetCurrentThemeName(void) currentSize, sizeof(currentSize) / sizeof(WCHAR)); if (bThemeActive) todo_wine - ok( LOWORD(hRes) == ERROR_INSUFFICIENT_BUFFER, "Expected 0x8007007A, got 0x%08x\n", hRes); + ok(hRes == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, diff --git a/rostests/winetests/uxtheme/uxtheme.rbuild b/rostests/winetests/uxtheme/uxtheme.rbuild index dd6c47418fa..8876207bb33 100644 --- a/rostests/winetests/uxtheme/uxtheme.rbuild +++ b/rostests/winetests/uxtheme/uxtheme.rbuild @@ -3,13 +3,11 @@ . - 0x600 - 0x600 + system.c testlist.c wine user32 - kernel32 ntdll diff --git a/rostests/winetests/version/info.c b/rostests/winetests/version/info.c index 9a6bcf4c932..edf607c9120 100644 --- a/rostests/winetests/version/info.c +++ b/rostests/winetests/version/info.c @@ -167,7 +167,7 @@ static void test_info_size(void) } } else - trace("skipping GetModuleFileNameA(NULL,..) failed\n"); + trace("skipping GetSystemDirectoryA(mypath,..) failed\n"); create_file("test.txt"); @@ -248,6 +248,13 @@ static void test_info(void) if (!boolret) goto cleanup; + boolret = VerQueryValueA( pVersionInfo, NULL, (LPVOID *)&pFixedVersionInfo, &uiLength ); + ok (boolret || GetLastError() == NO_ERROR /* Win98 */, + "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); + + boolret = VerQueryValueA( pVersionInfo, "", (LPVOID *)&pFixedVersionInfo, &uiLength ); + ok (boolret, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); + boolret = VerQueryValueA( pVersionInfo, backslash, (LPVOID *)&pFixedVersionInfo, &uiLength ); ok (boolret, "VerQueryValueA failed: GetLastError = %u\n", GetLastError()); if (!boolret) @@ -286,6 +293,7 @@ static void test_32bit_win(void) WCHAR mypathW[MAX_PATH]; char rootA[] = "\\"; WCHAR rootW[] = { '\\', 0 }; + WCHAR emptyW[] = { 0 }; char varfileinfoA[] = "\\VarFileInfo\\Translation"; WCHAR varfileinfoW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o', '\\','T','r','a','n','s','l','a','t','i','o','n', 0 }; @@ -324,7 +332,7 @@ static void test_32bit_win(void) GetModuleFileNameW(NULL, mypathW, MAX_PATH); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("GetModuleFileNameW not existing on this platform, skipping comparison between A- and W-calls\n"); + win_skip("GetModuleFileNameW not existing on this platform, skipping comparison between A- and W-calls\n"); is_unicode_enabled = FALSE; } @@ -375,7 +383,7 @@ static void test_32bit_win(void) if (is_unicode_enabled) { - VS_VERSION_INFO_STRUCT32 *vvis = (VS_VERSION_INFO_STRUCT32 *)pVersionInfoW; + VS_VERSION_INFO_STRUCT32 *vvis = pVersionInfoW; ok ( retvalW == ((vvis->wLength * 2) + 4) || retvalW == (vvis->wLength * 1.5), "Structure is not of the correct size\n"); } @@ -392,6 +400,15 @@ static void test_32bit_win(void) if (is_unicode_enabled) { + if(0) + { /* This causes Vista and w2k8 to crash */ + retW = VerQueryValueW( pVersionInfoW, NULL, (LPVOID *)&pBufW, &uiLengthW ); + ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError()); + } + + retW = VerQueryValueW( pVersionInfoW, emptyW, (LPVOID *)&pBufW, &uiLengthW ); + ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError()); + retW = VerQueryValueW( pVersionInfoW, rootW, (LPVOID *)&pBufW, &uiLengthW ); ok (retW, "VerQueryValueW failed: GetLastError = %u\n", GetLastError()); ok ( uiLengthA == sizeof(VS_FIXEDFILEINFO), "Size (%d) doesn't match the size of the VS_FIXEDFILEINFO struct\n", uiLengthA); diff --git a/rostests/winetests/version/install.c b/rostests/winetests/version/install.c index ada860ca4cf..6fc19bbe08e 100644 --- a/rostests/winetests/version/install.c +++ b/rostests/winetests/version/install.c @@ -165,7 +165,48 @@ static void test_find_file(void) } } +static void test_install_file(void) +{ + CHAR tmpname[MAX_PATH]; + UINT size = MAX_PATH; + DWORD rc; + static const CHAR szSrcFileName[] = "nofile.txt"; + static const CHAR szDestFileName[] = "nofile2.txt"; + static const CHAR szSrcDir[] = "D:\\oes\\not\\exist"; + static const CHAR szDestDir[] = "D:\\oes\\not\\exist\\either"; + static const CHAR szCurDir[] = "C:\\"; + + /* testing Invalid Parameters */ + memset(tmpname,0,sizeof(tmpname)); + rc = VerInstallFileA(0x0, NULL, NULL, NULL, NULL, NULL, tmpname, &size); + ok (rc == 0x10000 && tmpname[0]==0," expected return 0x10000 and no tempname, got %08x/\'%s\'\n",rc,tmpname); + memset(tmpname,0,sizeof(tmpname)); + size = MAX_PATH; + rc = VerInstallFileA(0x0, szSrcFileName, NULL, NULL, NULL, NULL, tmpname, &size); + ok (rc == 0x10000 && tmpname[0]==0," expected return 0x10000 and no tempname, got %08x/\'%s\'\n",rc,tmpname); + memset(tmpname,0,sizeof(tmpname)); + size = MAX_PATH; + rc = VerInstallFileA(0x0, szSrcFileName, szDestFileName, NULL, NULL, NULL, tmpname, &size); + ok (rc == 0x10000 && tmpname[0]==0," expected return 0x10000 and no tempname, got %08x/\'%s\'\n",rc,tmpname); + memset(tmpname,0,sizeof(tmpname)); + size = MAX_PATH; + rc = VerInstallFileA(0x0, szSrcFileName, szDestFileName, szSrcDir, NULL, NULL, tmpname, &size); + ok (rc == 0x10000 && tmpname[0]==0," expected return 0x10000 and no tempname, got %08x/\'%s\'\n",rc,tmpname); + + /* Source file does not exist*/ + + memset(tmpname,0,sizeof(tmpname)); + size = MAX_PATH; + rc = VerInstallFileA(0x0, szSrcFileName, szDestFileName, szSrcDir, szDestDir, NULL, tmpname, &size); + ok (rc == 0x10000 && tmpname[0]==0," expected return 0x10000 and no tempname, got %08x/\'%s\'\n",rc,tmpname); + memset(tmpname,0,sizeof(tmpname)); + size = MAX_PATH; + rc = VerInstallFileA(0x0, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, tmpname, &size); + ok (rc == 0x10000 && tmpname[0]==0," expected return 0x10000 and no tempname, got %08x/\'%s\'\n",rc,tmpname); +} + START_TEST(install) { test_find_file(); + test_install_file(); } diff --git a/rostests/winetests/version/version.rbuild b/rostests/winetests/version/version.rbuild index 119d262d8ab..b46ca7e68ab 100644 --- a/rostests/winetests/version/version.rbuild +++ b/rostests/winetests/version/version.rbuild @@ -3,15 +3,13 @@ . - 0x600 - 0x600 + info.c install.c version.rc testlist.c wine version - kernel32 ntdll diff --git a/rostests/winetests/winetest/winetest.rbuild b/rostests/winetests/winetest/winetest.rbuild index d060cdedfbe..e23523412a0 100644 --- a/rostests/winetests/winetest/winetest.rbuild +++ b/rostests/winetests/winetest/winetest.rbuild @@ -2,15 +2,13 @@ . - 0x600 - 0x501 + comctl32 version user32 gdi32 advapi32 ws2_32 - kernel32 gui.c main.c send.c diff --git a/rostests/winetests/winhttp/notification.c b/rostests/winetests/winhttp/notification.c new file mode 100644 index 00000000000..de8508adc90 --- /dev/null +++ b/rostests/winetests/winhttp/notification.c @@ -0,0 +1,392 @@ +/* + * test status notifications + * + * Copyright 2008 Hans Leidekker for CodeWeavers + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static const WCHAR user_agent[] = {'w','i','n','e','t','e','s','t',0}; + +enum api +{ + winhttp_connect = 1, + winhttp_open_request, + winhttp_send_request, + winhttp_receive_response, + winhttp_query_data, + winhttp_read_data, + winhttp_write_data, + winhttp_close_handle +}; + +struct notification +{ + enum api function; /* api responsible for notification */ + unsigned int status; /* status received */ + int todo; + int ignore; +}; + +struct info +{ + enum api function; + const struct notification *test; + unsigned int count; + unsigned int index; + HANDLE wait; + unsigned int line; +}; + +static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID buffer, DWORD buflen ) +{ + BOOL status_ok, function_ok; + struct info *info = (struct info *)context; + unsigned int i = info->index; + + if (status == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED) + { + DWORD size = sizeof(struct info *); + WinHttpQueryOption( handle, WINHTTP_OPTION_CONTEXT_VALUE, &info, &size ); + } + ok(i < info->count, "unexpected notification 0x%08x\n", status); + if (i >= info->count) return; + + status_ok = (info->test[i].status == status); + function_ok = (info->test[i].function == info->function); + if (!info->test[i].ignore && !info->test[i].todo) + { + ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[i].status, status); + ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[i].function, info->function); + } + else if (!info->test[i].ignore) + { + todo_wine ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[i].status, status); + if (status_ok) + { + todo_wine ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[i].function, info->function); + } + } + if (status_ok) info->index++; + if (status & WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS) SetEvent( info->wait ); +} + +static const struct notification cache_test[] = +{ + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, 0 }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 1 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 1 } +}; + +static void setup_test( struct info *info, enum api function, unsigned int line ) +{ + info->function = function; + info->line = line; +} + +static void test_connection_cache( void ) +{ + static const WCHAR codeweavers[] = {'w','w','w','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0}; + + HANDLE ses, con, req; + DWORD size, status; + BOOL ret; + struct info info, *context = &info; + + info.test = cache_test; + info.count = sizeof(cache_test) / sizeof(cache_test[0]); + info.index = 0; + info.wait = NULL; + + ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); + ok(ses != NULL, "failed to open session %u\n", GetLastError()); + + WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + + ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); + ok(ret, "failed to set context value %u\n", GetLastError()); + + setup_test( &info, winhttp_connect, __LINE__ ); + con = WinHttpConnect( ses, codeweavers, 0, 0 ); + ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + + setup_test( &info, winhttp_open_request, __LINE__ ); + req = WinHttpOpenRequest( con, NULL, NULL, NULL, NULL, NULL, 0 ); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + setup_test( &info, winhttp_send_request, __LINE__ ); + ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); + ok(ret, "failed to send request %u\n", GetLastError()); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + ret = WinHttpReceiveResponse( req, NULL ); + ok(ret, "failed to receive response %u\n", GetLastError()); + + size = sizeof(status); + ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + ok(ret, "failed unexpectedly %u\n", GetLastError()); + ok(status == 200, "request failed unexpectedly %u\n", status); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + WinHttpCloseHandle( req ); + WinHttpCloseHandle( con ); + WinHttpCloseHandle( ses ); + + Sleep(2000); /* make sure connection is evicted from cache */ + + info.index = 0; + + ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); + ok(ses != NULL, "failed to open session %u\n", GetLastError()); + + WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + + ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); + ok(ret, "failed to set context value %u\n", GetLastError()); + + setup_test( &info, winhttp_connect, __LINE__ ); + con = WinHttpConnect( ses, codeweavers, 0, 0 ); + ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + + setup_test( &info, winhttp_open_request, __LINE__ ); + req = WinHttpOpenRequest( con, NULL, NULL, NULL, NULL, NULL, 0 ); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + ret = WinHttpSetOption( req, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); + ok(ret, "failed to set context value %u\n", GetLastError()); + + setup_test( &info, winhttp_send_request, __LINE__ ); + ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); + ok(ret, "failed to send request %u\n", GetLastError()); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + ret = WinHttpReceiveResponse( req, NULL ); + ok(ret, "failed to receive response %u\n", GetLastError()); + + size = sizeof(status); + ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + ok(ret, "failed unexpectedly %u\n", GetLastError()); + ok(status == 200, "request failed unexpectedly %u\n", status); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + WinHttpCloseHandle( req ); + WinHttpCloseHandle( con ); + WinHttpCloseHandle( ses ); +} + +static const struct notification redirect_test[] = +{ + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, 0 }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 1 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 1 } +}; + +static void test_redirect( void ) +{ + static const WCHAR codeweavers[] = {'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0}; + + HANDLE ses, con, req; + DWORD size, status; + BOOL ret; + struct info info, *context = &info; + + info.test = redirect_test; + info.count = sizeof(redirect_test) / sizeof(redirect_test[0]); + info.index = 0; + info.wait = NULL; + + ses = WinHttpOpen( user_agent, 0, NULL, NULL, 0 ); + ok(ses != NULL, "failed to open session %u\n", GetLastError()); + + WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + + ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); + ok(ret, "failed to set context value %u\n", GetLastError()); + + setup_test( &info, winhttp_connect, __LINE__ ); + con = WinHttpConnect( ses, codeweavers, 0, 0 ); + ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + + setup_test( &info, winhttp_open_request, __LINE__ ); + req = WinHttpOpenRequest( con, NULL, NULL, NULL, NULL, NULL, 0 ); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + setup_test( &info, winhttp_send_request, __LINE__ ); + ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + ret = WinHttpReceiveResponse( req, NULL ); + ok(ret, "failed to receive response %u\n", GetLastError()); + + size = sizeof(status); + ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + ok(ret, "failed unexpectedly %u\n", GetLastError()); + ok(status == 200, "request failed unexpectedly %u\n", status); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + WinHttpCloseHandle( req ); + WinHttpCloseHandle( con ); + WinHttpCloseHandle( ses ); +} + +static const struct notification async_test[] = +{ + { winhttp_connect, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, 0 }, + { winhttp_open_request, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, 0 }, + { winhttp_send_request, WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REDIRECT, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_REQUEST_SENT, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0 }, + { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, 0 }, + { winhttp_query_data, WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, 0 }, + { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, 0, 1 }, + { winhttp_read_data, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, 0, 1 }, + { winhttp_read_data, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, 0, 1 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 0 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 1 }, + { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, 1 } +}; + +static void test_async( void ) +{ + static const WCHAR codeweavers[] = {'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0}; + + HANDLE ses, con, req; + DWORD size, status; + BOOL ret; + struct info info, *context = &info; + char buffer[1024]; + + info.test = async_test; + info.count = sizeof(async_test) / sizeof(async_test[0]); + info.index = 0; + info.wait = CreateEvent( NULL, FALSE, FALSE, NULL ); + + ses = WinHttpOpen( user_agent, 0, NULL, NULL, WINHTTP_FLAG_ASYNC ); + ok(ses != NULL, "failed to open session %u\n", GetLastError()); + + WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); + + ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) ); + ok(ret, "failed to set context value %u\n", GetLastError()); + + setup_test( &info, winhttp_connect, __LINE__ ); + con = WinHttpConnect( ses, codeweavers, 0, 0 ); + ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + + setup_test( &info, winhttp_open_request, __LINE__ ); + req = WinHttpOpenRequest( con, NULL, NULL, NULL, NULL, NULL, 0 ); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + setup_test( &info, winhttp_send_request, __LINE__ ); + ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 ); + ok(ret, "failed to send request %u\n", GetLastError()); + + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_receive_response, __LINE__ ); + ret = WinHttpReceiveResponse( req, NULL ); + ok(ret, "failed to receive response %u\n", GetLastError()); + + WaitForSingleObject( info.wait, INFINITE ); + + size = sizeof(status); + ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL ); + ok(ret, "failed unexpectedly %u\n", GetLastError()); + ok(status == 200, "request failed unexpectedly %u\n", status); + + setup_test( &info, winhttp_query_data, __LINE__ ); + ret = WinHttpQueryDataAvailable( req, NULL ); + ok(ret, "failed to query data available %u\n", GetLastError()); + + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_read_data, __LINE__ ); + ret = WinHttpReadData( req, buffer, sizeof(buffer), NULL ); + ok(ret, "failed to query data available %u\n", GetLastError()); + + WaitForSingleObject( info.wait, INFINITE ); + + setup_test( &info, winhttp_close_handle, __LINE__ ); + WinHttpCloseHandle( req ); + WinHttpCloseHandle( con ); + WinHttpCloseHandle( ses ); + CloseHandle( info.wait ); +} + +START_TEST (notification) +{ + test_connection_cache(); + test_redirect(); + Sleep(2000); /* make sure previous connection is evicted from cache */ + test_async(); +} diff --git a/rostests/winetests/winhttp/testlist.c b/rostests/winetests/winhttp/testlist.c new file mode 100644 index 00000000000..36f226a2bfb --- /dev/null +++ b/rostests/winetests/winhttp/testlist.c @@ -0,0 +1,19 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_winhttp(void); +extern void func_notification(void); +extern void func_url(void); + +const struct test winetest_testlist[] = +{ + { "winhttp", func_winhttp }, + { "notification", func_notification }, + { "url", func_url }, + { 0, 0 } +}; diff --git a/rostests/winetests/winhttp/url.c b/rostests/winetests/winhttp/url.c new file mode 100644 index 00000000000..da149b07f60 --- /dev/null +++ b/rostests/winetests/winhttp/url.c @@ -0,0 +1,581 @@ +/* + * Copyright 2008 Hans Leidekker + * + * 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 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winhttp.h" + +#include "wine/test.h" + +#define ICU_ESCAPE 0x80000000 + +static WCHAR empty[] = {0}; +static WCHAR ftp[] = {'f','t','p',0}; +static WCHAR http[] = {'h','t','t','p',0}; +static WCHAR winehq[] = {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; +static WCHAR username[] = {'u','s','e','r','n','a','m','e',0}; +static WCHAR password[] = {'p','a','s','s','w','o','r','d',0}; +static WCHAR about[] = {'/','s','i','t','e','/','a','b','o','u','t',0}; +static WCHAR query[] = {'?','q','u','e','r','y',0}; +static WCHAR escape[] = {' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',':',';','<','=','>','?','@','[','\\',']','^','_','`','{','|','}','~',0}; + +static const WCHAR url1[] = + {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; +static const WCHAR url2[] = + {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; +static const WCHAR url3[] = {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':',0}; +static const WCHAR url4[] = + {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; +static const WCHAR url5[] = {'h','t','t','p',':','/','/',0}; +static const WCHAR url6[] = + {'f','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','8','0','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; +static const WCHAR url7[] = + {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','4','2','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; +static const WCHAR url8[] = + {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t', + '%','2','0','!','%','2','2','%','2','3','$','%','2','5','&','\'','(',')','*','+',',','-','.','/',':',';','%','3','C','=','%','3','E','?','@','%', + '5','B','%','5','C','%','5','D','%','5','E','_','%','6','0','%','7','B','%','7','C','%','7','D','%','7','E',0}; +static const WCHAR url9[] = + {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','0','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; +static const WCHAR url10[] = + {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','8','0','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; +static const WCHAR url11[] = + {'h','t','t','p','s',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g',':','4','4','3','/','s','i','t','e','/','a','b','o','u','t','?','q','u','e','r','y',0}; + + + +static const WCHAR url_k1[] = + {'h','t','t','p',':','/','/','u','s','e','r','n','a','m','e',':','p','a','s','s','w','o','r','d', + '@','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','s','i','t','e','/','a','b','o','u','t',0}; +static const WCHAR url_k2[] = + {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; +static const WCHAR url_k3[] = + {'h','t','t','p','s',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','p','o','s','t','?',0}; +static const WCHAR url_k4[] = + {'H','T','T','P',':','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; +static const WCHAR url_k5[] = + {'h','t','t','p',':','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; +static const WCHAR url_k6[] = + {'w','w','w','.','w','i','n','e','h','q','.','o','r','g',0}; +static const WCHAR url_k7[] = + {'w','w','w',0}; +static const WCHAR url_k8[] = + {'h','t','t','p',0}; +static const WCHAR url_k9[] = + {'h','t','t','p',':','/','/','w','i','n','e','h','q','?',0}; +static const WCHAR url_k10[] = + {'h','t','t','p',':','/','/','w','i','n','e','h','q','/','p','o','s','t',';','a',0}; + +static const char *debugstr_w(LPCWSTR str) +{ + static char buf[1024]; + WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); + return buf; +} + +static void fill_url_components( URL_COMPONENTS *uc ) +{ + uc->dwStructSize = sizeof(URL_COMPONENTS); + uc->lpszScheme = http; + uc->dwSchemeLength = lstrlenW( uc->lpszScheme ); + uc->nScheme = INTERNET_SCHEME_HTTP; + uc->lpszHostName = winehq; + uc->dwHostNameLength = lstrlenW( uc->lpszHostName ); + uc->nPort = 80; + uc->lpszUserName = username; + uc->dwUserNameLength = lstrlenW( uc->lpszUserName ); + uc->lpszPassword = password; + uc->dwPasswordLength = lstrlenW( uc->lpszPassword ); + uc->lpszUrlPath = about; + uc->dwUrlPathLength = lstrlenW( uc->lpszUrlPath ); + uc->lpszExtraInfo = query; + uc->dwExtraInfoLength = lstrlenW( uc->lpszExtraInfo ); +} + +static void WinHttpCreateUrl_test( void ) +{ + URL_COMPONENTS uc; + WCHAR *url; + DWORD len; + BOOL ret; + + /* NULL components */ + len = ~0u; + SetLastError( 0xdeadbeef ); + ret = WinHttpCreateUrl( NULL, 0, NULL, &len ); + ok( !ret, "expected failure\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); + ok( len == ~0u, "expected len ~0u got %u\n", len ); + + /* zero'ed components */ + memset( &uc, 0, sizeof(URL_COMPONENTS) ); + SetLastError( 0xdeadbeef ); + ret = WinHttpCreateUrl( &uc, 0, NULL, &len ); + ok( !ret, "expected failure\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); + ok( len == ~0u, "expected len ~0u got %u\n", len ); + + /* valid components, NULL url, NULL length */ + fill_url_components( &uc ); + SetLastError( 0xdeadbeef ); + ret = WinHttpCreateUrl( &uc, 0, NULL, NULL ); + ok( !ret, "expected failure\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); + ok( len == ~0u, "expected len ~0u got %u\n", len ); + + /* valid components, NULL url */ + SetLastError( 0xdeadbeef ); + ret = WinHttpCreateUrl( &uc, 0, NULL, &len ); + ok( !ret, "expected failure\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError() ); + ok( len == 57, "expected len 57 got %u\n", len ); + + /* correct size, NULL url */ + fill_url_components( &uc ); + SetLastError( 0xdeadbeef ); + ret = WinHttpCreateUrl( &uc, 0, NULL, &len ); + ok( !ret, "expected failure\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError() ); + ok( len == 57, "expected len 57 got %u\n", len ); + + /* valid components, allocated url, short length */ + SetLastError( 0xdeadbeef ); + url = HeapAlloc( GetProcessHeap(), 0, 256 * sizeof(WCHAR) ); + url[0] = 0; + len = 2; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( !ret, "expected failure\n" ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER got %u\n", GetLastError() ); + ok( len == 57, "expected len 57 got %u\n", len ); + + /* allocated url, NULL scheme */ + uc.lpszScheme = NULL; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 56, "expected len 56 got %u\n", len ); + ok( !lstrcmpW( url, url1 ), "url doesn't match\n" ); + + /* allocated url, 0 scheme */ + fill_url_components( &uc ); + uc.nScheme = 0; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 56, "expected len 56 got %u\n", len ); + + /* valid components, allocated url */ + fill_url_components( &uc ); + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 56, "expected len 56 got %d\n", len ); + ok( !lstrcmpW( url, url1 ), "url doesn't match\n" ); + + /* valid username, NULL password */ + fill_url_components( &uc ); + uc.lpszPassword = NULL; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + + /* valid username, empty password */ + fill_url_components( &uc ); + uc.lpszPassword = empty; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 56, "expected len 56 got %u\n", len ); + ok( !lstrcmpW( url, url3 ), "url doesn't match\n" ); + + /* valid password, NULL username */ + fill_url_components( &uc ); + SetLastError( 0xdeadbeef ); + uc.lpszUserName = NULL; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( !ret, "expected failure\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", GetLastError() ); + + /* valid password, empty username */ + fill_url_components( &uc ); + uc.lpszUserName = empty; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n"); + + /* NULL username, NULL password */ + fill_url_components( &uc ); + uc.lpszUserName = NULL; + uc.lpszPassword = NULL; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 38, "expected len 38 got %u\n", len ); + ok( !lstrcmpW( url, url4 ), "url doesn't match\n" ); + + /* empty username, empty password */ + fill_url_components( &uc ); + uc.lpszUserName = empty; + uc.lpszPassword = empty; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 56, "expected len 56 got %u\n", len ); + ok( !lstrcmpW( url, url5 ), "url doesn't match\n" ); + + /* nScheme has lower precedence than lpszScheme */ + fill_url_components( &uc ); + uc.lpszScheme = ftp; + uc.dwSchemeLength = lstrlenW( uc.lpszScheme ); + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == lstrlenW( url6 ), "expected len %d got %u\n", lstrlenW( url6 ) + 1, len ); + ok( !lstrcmpW( url, url6 ), "url doesn't match\n" ); + + /* non-standard port */ + uc.lpszScheme = http; + uc.dwSchemeLength = lstrlenW( uc.lpszScheme ); + uc.nPort = 42; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 59, "expected len 59 got %u\n", len ); + ok( !lstrcmpW( url, url7 ), "url doesn't match\n" ); + + /* escape extra info */ + fill_url_components( &uc ); + uc.lpszExtraInfo = escape; + uc.dwExtraInfoLength = lstrlenW( uc.lpszExtraInfo ); + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, ICU_ESCAPE, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 113, "expected len 113 got %u\n", len ); + ok( !lstrcmpW( url, url8 ), "url doesn't match\n" ); + + /* NULL lpszScheme, 0 nScheme and nPort */ + fill_url_components( &uc ); + uc.lpszScheme = NULL; + uc.dwSchemeLength = 0; + uc.nScheme = 0; + uc.nPort = 0; + url[0] = 0; + len = 256; + ret = WinHttpCreateUrl( &uc, 0, url, &len ); + ok( ret, "expected success\n" ); + ok( len == 58, "expected len 58 got %u\n", len ); + ok( !lstrcmpW( url, url9 ), "url doesn't match\n" ); + + HeapFree( GetProcessHeap(), 0, url ); +} + +static void reset_url_components( URL_COMPONENTS *uc ) +{ + memset( uc, 0, sizeof(URL_COMPONENTS) ); + uc->dwStructSize = sizeof(URL_COMPONENTS); + uc->dwSchemeLength = ~0u; + uc->dwHostNameLength = ~0u; + uc->nPort = 0; + uc->dwUserNameLength = ~0u; + uc->dwPasswordLength = ~0u; + uc->dwUrlPathLength = ~0u; + uc->dwExtraInfoLength = ~0u; +} + +static void WinHttpCrackUrl_test( void ) +{ + URL_COMPONENTSW uc; + WCHAR scheme[20], user[20], pass[20], host[20], path[40], extra[20]; + DWORD error; + BOOL ret; + + /* buffers of sufficient length */ + scheme[0] = 0; + user[0] = 0; + pass[0] = 0; + host[0] = 0; + path[0] = 0; + extra[0] = 0; + + uc.dwStructSize = sizeof(URL_COMPONENTS); + uc.nScheme = 0; + uc.lpszScheme = scheme; + uc.dwSchemeLength = 20; + uc.lpszUserName = user; + uc.dwUserNameLength = 20; + uc.lpszPassword = pass; + uc.dwPasswordLength = 20; + uc.lpszHostName = host; + uc.dwHostNameLength = 20; + uc.nPort = 0; + uc.lpszUrlPath = path; + uc.dwUrlPathLength = 40; + uc.lpszExtraInfo = extra; + uc.dwExtraInfoLength = 20; + + ret = WinHttpCrackUrl( url1, 0, 0, &uc ); + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.nScheme == INTERNET_SCHEME_HTTP, "unexpected scheme\n" ); + ok( !memcmp( uc.lpszScheme, http, sizeof(http) ), "unexpected scheme\n" ); + ok( uc.dwSchemeLength == 4, "unexpected scheme length\n" ); + ok( !memcmp( uc.lpszUserName, username, sizeof(username) ), "unexpected username\n" ); + ok( uc.dwUserNameLength == 8, "unexpected username length\n" ); + ok( !memcmp( uc.lpszPassword, password, sizeof(password) ), "unexpected password\n" ); + ok( uc.dwPasswordLength == 8, "unexpected password length\n" ); + ok( !memcmp( uc.lpszHostName, winehq, sizeof(winehq) ), "unexpected hostname\n" ); + ok( uc.dwHostNameLength == 14, "unexpected hostname length\n" ); + ok( uc.nPort == 80, "unexpected port: %u\n", uc.nPort ); + ok( !memcmp( uc.lpszUrlPath, about, sizeof(about) ), "unexpected path\n" ); + ok( uc.dwUrlPathLength == 11, "unexpected path length\n" ); + ok( !memcmp( uc.lpszExtraInfo, query, sizeof(query) ), "unexpected extra info\n" ); + ok( uc.dwExtraInfoLength == 6, "unexpected extra info length\n" ); + + /* buffer of insufficient length */ + scheme[0] = 0; + uc.dwSchemeLength = 1; + + SetLastError( 0xdeadbeef ); + ret = WinHttpCrackUrl( url1, 0, 0, &uc ); + error = GetLastError(); + ok( !ret, "WinHttpCrackUrl failed\n" ); + ok( error == ERROR_INSUFFICIENT_BUFFER, "WinHttpCrackUrl failed\n" ); + ok( uc.dwSchemeLength == 5, "unexpected scheme length: %u\n", uc.dwSchemeLength ); + + /* no buffers */ + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k1, 0, 0,&uc); + + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.nScheme == INTERNET_SCHEME_HTTP, "unexpected scheme\n" ); + ok( uc.lpszScheme == url_k1,"unexpected scheme\n" ); + ok( uc.dwSchemeLength == 4, "unexpected scheme length\n" ); + ok( uc.lpszUserName == url_k1 + 7, "unexpected username\n" ); + ok( uc.dwUserNameLength == 8, "unexpected username length\n" ); + ok( uc.lpszPassword == url_k1 + 16, "unexpected password\n" ); + ok( uc.dwPasswordLength == 8, "unexpected password length\n" ); + ok( uc.lpszHostName == url_k1 + 25, "unexpected hostname\n" ); + ok( uc.dwHostNameLength == 14, "unexpected hostname length\n" ); + ok( uc.nPort == 80, "unexpected port: %u\n", uc.nPort ); + ok( uc.lpszUrlPath == url_k1 + 39, "unexpected path\n" ); + ok( uc.dwUrlPathLength == 11, "unexpected path length\n" ); + ok( uc.lpszExtraInfo == url_k1 + 50, "unexpected extra info\n" ); + ok( uc.dwExtraInfoLength == 0, "unexpected extra info length\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k2, 0, 0,&uc); + + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.nScheme == INTERNET_SCHEME_HTTP, "unexpected scheme\n" ); + ok( uc.lpszScheme == url_k2, "unexpected scheme\n" ); + ok( uc.dwSchemeLength == 4, "unexpected scheme length\n" ); + ok( uc.lpszUserName == NULL ,"unexpected username\n" ); + ok( uc.dwUserNameLength == 0, "unexpected username length\n" ); + ok( uc.lpszPassword == NULL, "unexpected password\n" ); + ok( uc.dwPasswordLength == 0, "unexpected password length\n" ); + ok( uc.lpszHostName == url_k2 + 7, "unexpected hostname\n" ); + ok( uc.dwHostNameLength == 14, "unexpected hostname length\n" ); + ok( uc.nPort == 80, "unexpected port: %u\n", uc.nPort ); + ok( uc.lpszUrlPath == url_k2 + 21, "unexpected path\n" ); + ok( uc.dwUrlPathLength == 0, "unexpected path length\n" ); + ok( uc.lpszExtraInfo == url_k2 + 21, "unexpected extra info\n" ); + ok( uc.dwExtraInfoLength == 0, "unexpected extra info length\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k3, 0, 0, &uc ); + + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.nScheme == INTERNET_SCHEME_HTTPS, "unexpected scheme\n" ); + ok( uc.lpszScheme == url_k3, "unexpected scheme\n" ); + ok( uc.dwSchemeLength == 5, "unexpected scheme length\n" ); + ok( uc.lpszUserName == NULL, "unexpected username\n" ); + ok( uc.dwUserNameLength == 0, "unexpected username length\n" ); + ok( uc.lpszPassword == NULL, "unexpected password\n" ); + ok( uc.dwPasswordLength == 0, "unexpected password length\n" ); + ok( uc.lpszHostName == url_k3 + 8, "unexpected hostname\n" ); + ok( uc.dwHostNameLength == 14, "unexpected hostname length\n" ); + ok( uc.nPort == 443, "unexpected port: %u\n", uc.nPort ); + ok( uc.lpszUrlPath == url_k3 + 22, "unexpected path\n" ); + ok( uc.dwUrlPathLength == 5, "unexpected path length\n" ); + ok( uc.lpszExtraInfo == url_k3 + 27, "unexpected extra info\n" ); + ok( uc.dwExtraInfoLength == 1, "unexpected extra info length\n" ); + + /* bad parameters */ + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k4, 0, 0, &uc ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k5, 0, 0, &uc ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k6, 0, 0, &uc ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k7, 0, 0, &uc ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k8, 0, 0, &uc ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k9, 0, 0, &uc ); + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.lpszUrlPath == url_k9 + 14, "unexpected path\n" ); + ok( uc.dwUrlPathLength == 0, "unexpected path length\n" ); + ok( uc.lpszExtraInfo == url_k9 + 14, "unexpected extra info\n" ); + ok( uc.dwExtraInfoLength == 0, "unexpected extra info length\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url_k10, 0, 0, &uc ); + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.lpszUrlPath == url_k10 + 13, "unexpected path\n" ); + ok( uc.dwUrlPathLength == 7, "unexpected path length\n" ); + ok( uc.lpszExtraInfo == url_k10 + 20, "unexpected extra info\n" ); + ok( uc.dwExtraInfoLength == 0, "unexpected extra info length\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url5, 0, 0, &uc ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( empty, 0, 0, &uc ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + ret = WinHttpCrackUrl( url1, 0, 0, NULL ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + ret = WinHttpCrackUrl( NULL, 0, 0, &uc ); + ok( !ret, "WinHttpCrackUrl failed\n" ); + + /* decoding without buffers */ + reset_url_components( &uc ); + SetLastError(0xdeadbeef); + ret = WinHttpCrackUrl( url8, 0, ICU_DECODE, &uc ); + error = GetLastError(); + ok( !ret, "WinHttpCrackUrl failed\n" ); + ok( error == ERROR_INVALID_PARAMETER, "WinHttpCrackUrl failed\n" ); + + /* decoding with buffers */ + uc.lpszScheme = scheme; + uc.dwSchemeLength = 20; + uc.lpszUserName = user; + uc.dwUserNameLength = 20; + uc.lpszPassword = pass; + uc.dwPasswordLength = 20; + uc.lpszHostName = host; + uc.dwHostNameLength = 20; + uc.nPort = 0; + uc.lpszUrlPath = path; + uc.dwUrlPathLength = 40; + uc.lpszExtraInfo = extra; + uc.dwExtraInfoLength = 20; + path[0] = 0; + + ret = WinHttpCrackUrl( url8, 0, ICU_DECODE, &uc ); + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( !memcmp( uc.lpszUrlPath + 11, escape, 21 * sizeof(WCHAR) ), "unexpected path\n" ); + ok( uc.dwUrlPathLength == 32, "unexpected path length\n" ); + ok( !memcmp( uc.lpszExtraInfo, escape + 21, 12 * sizeof(WCHAR) ), "unexpected extra info\n" ); + ok( uc.dwExtraInfoLength == 12, "unexpected extra info length\n" ); + + /* Urls with specified port numbers */ + /* decoding with buffers */ + uc.lpszScheme = scheme; + uc.dwSchemeLength = 20; + uc.lpszUserName = user; + uc.dwUserNameLength = 20; + uc.lpszPassword = pass; + uc.dwPasswordLength = 20; + uc.lpszHostName = host; + uc.dwHostNameLength = 20; + uc.nPort = 0; + uc.lpszUrlPath = path; + uc.dwUrlPathLength = 40; + uc.lpszExtraInfo = extra; + uc.dwExtraInfoLength = 20; + path[0] = 0; + + ret = WinHttpCrackUrl( url7, 0, 0, &uc ); + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( !memcmp( uc.lpszHostName, winehq, sizeof(winehq) ), "unexpected host name: %s\n", debugstr_w(uc.lpszHostName) ); + ok( uc.dwHostNameLength == 14, "unexpected host name length: %d\n", uc.dwHostNameLength ); + ok( uc.nPort == 42, "unexpected port: %u\n", uc.nPort ); + + /* decoding without buffers */ + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url9, 0, 0, &uc ); + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.nPort == 0, "unexpected port: %u\n", uc.nPort ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url10, 0, 0, &uc ); + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.nPort == 80, "unexpected port: %u\n", uc.nPort ); + + reset_url_components( &uc ); + ret = WinHttpCrackUrl( url11, 0, 0, &uc ); + ok( ret, "WinHttpCrackUrl failed\n" ); + ok( uc.nPort == 443, "unexpected port: %u\n", uc.nPort ); + + reset_url_components( &uc ); + SetLastError( 0xdeadbeef ); + ret = WinHttpCrackUrl( empty, 0, 0, &uc ); + error = GetLastError(); + ok( !ret, "WinHttpCrackUrl succeeded\n" ); + ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %u, expected ERROR_WINHTTP_UNRECOGNIZED_SCHEME\n", error ); + + reset_url_components( &uc ); + SetLastError( 0xdeadbeef ); + ret = WinHttpCrackUrl( http, 0, 0, &uc ); + error = GetLastError(); + ok( !ret, "WinHttpCrackUrl succeeded\n" ); + ok( error == ERROR_WINHTTP_UNRECOGNIZED_SCHEME, "got %u, expected ERROR_WINHTTP_UNRECOGNIZED_SCHEME\n", error ); +} + +START_TEST (url) +{ + WinHttpCreateUrl_test(); + WinHttpCrackUrl_test(); +} diff --git a/rostests/winetests/winhttp/winhttp.c b/rostests/winetests/winhttp/winhttp.c new file mode 100644 index 00000000000..74e1c9a12ec --- /dev/null +++ b/rostests/winetests/winhttp/winhttp.c @@ -0,0 +1,830 @@ +/* + * WinHTTP - tests + * + * Copyright 2008 Google (Zac Brown) + * + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static const WCHAR test_useragent[] = + {'W','i','n','e',' ','R','e','g','r','e','s','s','i','o','n',' ','T','e','s','t',0}; +static const WCHAR test_server[] = {'w','i','n','e','h','q','.','o','r','g',0}; + +static void test_QueryOption(void) +{ + BOOL ret; + HINTERNET session, request, connection; + DWORD feature, size; + + SetLastError(0xdeadbeef); + session = WinHttpOpen(test_useragent, 0, 0, 0, 0); + ok(session != NULL, "WinHttpOpen failed to open session, error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, NULL); + ok(!ret, "should fail to set redirect policy %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + + size = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, &size); + ok(!ret, "should fail to query option\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + ok(size == 4, "expected 4, got %u\n", size); + + feature = 0xdeadbeef; + size = sizeof(feature) - 1; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size); + ok(!ret, "should fail to query option\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + ok(size == 4, "expected 4, got %u\n", size); + + feature = 0xdeadbeef; + size = sizeof(feature) + 1; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size); + ok(ret, "failed to query option %u\n", GetLastError()); + ok(size == sizeof(feature), "WinHttpQueryOption should set the size: %u\n", size); + ok(feature == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP, + "expected WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP, got %#x\n", feature); + + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, NULL, sizeof(feature)); + ok(!ret, "should fail to set redirect policy %u\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + + feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature) - 1); + ok(!ret, "should fail to set redirect policy %u\n", GetLastError()); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + + feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature) + 1); + ok(!ret, "should fail to set redirect policy %u\n", GetLastError()); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + + feature = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, sizeof(feature)); + ok(ret, "failed to set redirect policy %u\n", GetLastError()); + + feature = 0xdeadbeef; + size = sizeof(feature); + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size); + ok(ret, "failed to query option %u\n", GetLastError()); + ok(feature == WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS, + "expected WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS, got %#x\n", feature); + + feature = WINHTTP_DISABLE_COOKIES; + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(session, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); + ok(!ret, "should fail to set disable feature for a session\n"); + ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, + "expected ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, got %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + connection = WinHttpConnect(session, test_server, INTERNET_DEFAULT_HTTP_PORT, 0); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u\n", GetLastError()); + + feature = WINHTTP_DISABLE_COOKIES; + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(connection, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); + ok(!ret, "should fail to set disable feature for a connection\n"); + ok(GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, + "expected ERROR_WINHTTP_INCORRECT_HANDLE_TYPE, got %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + request = WinHttpOpenRequest(connection, NULL, NULL, NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED) + { + skip("Network unreachable, skipping the test\n"); + goto done; + } + + feature = 0xdeadbeef; + size = sizeof(feature); + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, &size); + ok(!ret, "should fail to query disable feature for a request\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + + feature = 0; + size = sizeof(feature); + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); + ok(ret, "failed to set feature %u\n", GetLastError()); + + feature = 0xffffffff; + size = sizeof(feature); + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); + ok(ret, "failed to set feature %u\n", GetLastError()); + + feature = WINHTTP_DISABLE_COOKIES; + size = sizeof(feature); + SetLastError(0xdeadbeef); + ret = WinHttpSetOption(request, WINHTTP_OPTION_DISABLE_FEATURE, &feature, sizeof(feature)); + ok(ret, "failed to set feature %u\n", GetLastError()); + + size = 0; + SetLastError(0xdeadbeef); + ret = WinHttpQueryOption(request, WINHTTP_OPTION_DISABLE_FEATURE, NULL, &size); + ok(!ret, "should fail to query disable feature for a request\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WinHttpCloseHandle(request); + ok(ret, "WinHttpCloseHandle failed on closing request: %u\n", GetLastError()); + +done: + SetLastError(0xdeadbeef); + ret = WinHttpCloseHandle(connection); + ok(ret, "WinHttpCloseHandle failed on closing connection: %u\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = WinHttpCloseHandle(session); + ok(ret, "WinHttpCloseHandle failed on closing session: %u\n", GetLastError()); +} + +static void test_OpenRequest (void) +{ + BOOL ret; + HINTERNET session, request, connection; + + session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + ok(session != NULL, "WinHttpOpen failed to open session.\n"); + + /* Test with a bad server name */ + SetLastError(0xdeadbeef); + connection = WinHttpConnect(session, NULL, INTERNET_DEFAULT_HTTP_PORT, 0); + ok (connection == NULL, "WinHttpConnect succeeded in opening connection to NULL server argument.\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); + + /* Test with a valid server name */ + connection = WinHttpConnect (session, test_server, INTERNET_DEFAULT_HTTP_PORT, 0); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", GetLastError()); + + request = WinHttpOpenRequest(connection, NULL, NULL, NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED) + { + skip("Network unreachable, skipping.\n"); + goto done; + } + ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %u.\n", GetLastError()); + + ret = WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0); + ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError()); + ret = WinHttpCloseHandle(request); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret); + + done: + ret = WinHttpCloseHandle(connection); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing connection, got %d.\n", ret); + ret = WinHttpCloseHandle(session); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing session, got %d.\n", ret); + +} + +static void test_SendRequest (void) +{ + HINTERNET session, request, connection; + DWORD header_len, optional_len, total_len; + DWORD bytes_rw; + BOOL ret; + CHAR buffer[256]; + int i; + + static const WCHAR test_site[] = {'c','r','o','s','s','o','v','e','r','.', + 'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0}; + static const WCHAR content_type[] = + {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ','a','p','p','l','i','c','a','t','i','o','n', + '/','x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o','d','e','d',0}; + static const WCHAR test_file[] = {'/','p','o','s','t','t','e','s','t','.','p','h','p',0}; + static const WCHAR test_verb[] = {'P','O','S','T',0}; + static CHAR post_data[] = "mode=Test"; + static CHAR test_post[] = "mode => Test\\0\n"; + + header_len = -1L; + total_len = optional_len = sizeof(post_data); + memset(buffer, 0xff, sizeof(buffer)); + + session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + ok(session != NULL, "WinHttpOpen failed to open session.\n"); + + connection = WinHttpConnect (session, test_site, INTERNET_DEFAULT_HTTP_PORT, 0); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", GetLastError()); + + request = WinHttpOpenRequest(connection, test_verb, test_file, NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_BYPASS_PROXY_CACHE); + if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED) + { + skip("Network unreachable, skipping.\n"); + goto done; + } + ok(request != NULL, "WinHttpOpenrequest failed to open a request, error: %u.\n", GetLastError()); + + ret = WinHttpSendRequest(request, content_type, header_len, post_data, optional_len, total_len, 0); + ok(ret == TRUE, "WinHttpSendRequest failed: %u\n", GetLastError()); + + for (i = 3; post_data[i]; i++) + { + bytes_rw = -1; + ret = WinHttpWriteData(request, &post_data[i], 1, &bytes_rw); + ok(ret == TRUE, "WinHttpWriteData failed: %u.\n", GetLastError()); + ok(bytes_rw == 1, "WinHttpWriteData failed, wrote %u bytes instead of 1 byte.\n", bytes_rw); + } + + ret = WinHttpReceiveResponse(request, NULL); + ok(ret == TRUE, "WinHttpReceiveResponse failed: %u.\n", GetLastError()); + + bytes_rw = -1; + ret = WinHttpReadData(request, buffer, sizeof(buffer) - 1, &bytes_rw); + ok(ret == TRUE, "WinHttpReadData failed: %u.\n", GetLastError()); + + ok(bytes_rw == strlen(test_post), "Read %u bytes instead of %d.\n", bytes_rw, lstrlen(test_post)); + ok(strncmp(buffer, test_post, bytes_rw) == 0, "Data read did not match, got '%s'.\n", buffer); + + ret = WinHttpCloseHandle(request); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret); + done: + ret = WinHttpCloseHandle(connection); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing connection, got %d.\n", ret); + ret = WinHttpCloseHandle(session); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing session, got %d.\n", ret); +} + +static void test_WinHttpTimeFromSystemTime(void) +{ + BOOL ret; + static const SYSTEMTIME time = {2008, 7, 1, 28, 10, 5, 52, 0}; + static const WCHAR expected_string[] = + {'M','o','n',',',' ','2','8',' ','J','u','l',' ','2','0','0','8',' ', + '1','0',':','0','5',':','5','2',' ','G','M','T',0}; + WCHAR time_string[WINHTTP_TIME_FORMAT_BUFSIZE+1]; + + ret = WinHttpTimeFromSystemTime(&time, time_string); + ok(ret == TRUE, "WinHttpTimeFromSystemTime failed: %u\n", GetLastError()); + ok(memcmp(time_string, expected_string, sizeof(expected_string)) == 0, + "Time string returned did not match expected time string.\n"); +} + +static void test_WinHttpTimeToSystemTime(void) +{ + BOOL ret; + SYSTEMTIME time; + static const SYSTEMTIME expected_time = {2008, 7, 1, 28, 10, 5, 52, 0}; + static const WCHAR time_string1[] = + {'M','o','n',',',' ','2','8',' ','J','u','l',' ','2','0','0','8',' ', + + '1','0',':','0','5',':','5','2',' ','G','M','T','\n',0}; + static const WCHAR time_string2[] = + {' ','m','o','n',' ','2','8',' ','j','u','l',' ','2','0','0','8',' ', + '1','0',' ','0','5',' ','5','2','\n',0}; + + ret = WinHttpTimeToSystemTime(time_string1, &time); + ok(ret == TRUE, "WinHttpTimeToSystemTime failed: %u\n", GetLastError()); + ok(memcmp(&time, &expected_time, sizeof(SYSTEMTIME)) == 0, + "Returned SYSTEMTIME structure did not match expected SYSTEMTIME structure.\n"); + + ret = WinHttpTimeToSystemTime(time_string2, &time); + ok(ret == TRUE, "WinHttpTimeToSystemTime failed: %u\n", GetLastError()); + ok(memcmp(&time, &expected_time, sizeof(SYSTEMTIME)) == 0, + "Returned SYSTEMTIME structure did not match expected SYSTEMTIME structure.\n"); +} + +static void test_WinHttpAddHeaders(void) +{ + HINTERNET session, request, connection; + BOOL ret; + WCHAR buffer[MAX_PATH]; + WCHAR check_buffer[MAX_PATH]; + DWORD index, len, oldlen; + + static const WCHAR test_site[] = {'c','r','o','s','s','o','v','e','r','.', + 'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0}; + static const WCHAR test_file[] = {'/','p','o','s','t','t','e','s','t','.','p','h','p',0}; + static const WCHAR test_verb[] = {'P','O','S','T',0}; + + static const WCHAR test_header_begin[] = + {'P','O','S','T',' ','/','p','o','s','t','t','e','s','t','.','p','h','p',' ','H','T','T','P','/','1'}; + static const WCHAR test_header_end[] = {'\r','\n','\r','\n',0}; + static const WCHAR test_header_name[] = {'W','a','r','n','i','n','g',0}; + + static const WCHAR test_flag_coalesce[] = {'t','e','s','t','2',',',' ','t','e','s','t','4',0}; + static const WCHAR test_flag_coalesce_comma[] = + {'t','e','s','t','2',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',0}; + static const WCHAR test_flag_coalesce_semicolon[] = + {'t','e','s','t','2',',',' ','t','e','s','t','4',',',' ','t','e','s','t','5',';',' ','t','e','s','t','6',0}; + + static const WCHAR field[] = {'f','i','e','l','d',0}; + static const WCHAR value[] = {'v','a','l','u','e',' ',0}; + + static const WCHAR test_headers[][14] = + { + {'W','a','r','n','i','n','g',':','t','e','s','t','1',0}, + {'W','a','r','n','i','n','g',':','t','e','s','t','2',0}, + {'W','a','r','n','i','n','g',':','t','e','s','t','3',0}, + {'W','a','r','n','i','n','g',':','t','e','s','t','4',0}, + {'W','a','r','n','i','n','g',':','t','e','s','t','5',0}, + {'W','a','r','n','i','n','g',':','t','e','s','t','6',0}, + {'W','a','r','n','i','n','g',':','t','e','s','t','7',0}, + {0}, + {':',0}, + {'a',':',0}, + {':','b',0}, + {'c','d',0}, + {' ','e',' ',':','f',0}, + {'f','i','e','l','d',':',' ','v','a','l','u','e',' ',0} + }; + static const WCHAR test_indices[][6] = + { + {'t','e','s','t','1',0}, + {'t','e','s','t','2',0}, + {'t','e','s','t','3',0}, + {'t','e','s','t','4',0} + }; + + session = WinHttpOpen(test_useragent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + ok(session != NULL, "WinHttpOpen failed to open session.\n"); + + connection = WinHttpConnect (session, test_site, INTERNET_DEFAULT_HTTP_PORT, 0); + ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %u.\n", GetLastError()); + + request = WinHttpOpenRequest(connection, test_verb, test_file, NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + if (request == NULL && GetLastError() == ERROR_WINHTTP_NAME_NOT_RESOLVED) + { + skip("Network unreachable, skipping.\n"); + goto done; + } + ok(request != NULL, "WinHttpOpenRequest failed to open a request, error: %u.\n", GetLastError()); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, found 'Warning' header.\n"); + ret = WinHttpAddRequestHeaders(request, test_headers[0], -1L, WINHTTP_ADDREQ_FLAG_ADD); + ok(ret == TRUE, "WinHttpAddRequestHeader failed to add new header, got %d with error %u.\n", ret, GetLastError()); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed: header index not incremented\n"); + ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, "WinHttpQueryHeaders failed: incorrect string returned\n"); + ok(len == 5*sizeof(WCHAR), "WinHttpQueryHeaders failed: invalid length returned, expected 5, got %d\n", len); + + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded, second index should not exist.\n"); + + /* Try to fetch the header info with a buffer that's big enough to fit the + * string but not the NULL terminator. + */ + index = 0; + len = 5*sizeof(WCHAR); + memset(check_buffer, 0xab, sizeof(check_buffer)); + memcpy(buffer, check_buffer, sizeof(buffer)); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded with a buffer that's too small.\n"); + ok(memcmp(buffer, check_buffer, sizeof(buffer)) == 0, + "WinHttpQueryHeaders failed, modified the buffer when it should not have.\n"); + ok(len == 6*sizeof(WCHAR), "WinHttpQueryHeaders returned invalid length, expected 12, got %d\n", len); + + /* Try with a NULL buffer */ + index = 0; + len = sizeof(buffer); + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, NULL, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); + ok(index == 0, "WinHttpQueryHeaders incorrectly incremented header index.\n"); + + /* Try with a NULL buffer and a length that's too small */ + index = 0; + len = 10; + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, NULL, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICENT_BUFFER, go %u\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); + ok(index == 0, "WinHttpQueryHeaders incorrectly incremented header index.\n"); + + index = 0; + len = 0; + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, NULL, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); + ok(index == 0, "WinHttpQueryHeaders failed: index was incremented.\n"); + + /* valid query */ + oldlen = len; + index = 0; + len = sizeof(buffer); + memset(buffer, 0xff, sizeof(buffer)); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: got %d\n", ret); + ok(len + sizeof(WCHAR) <= oldlen, "WinHttpQueryHeaders resulting length longer than advertized.\n"); + ok((len < sizeof(buffer) - sizeof(WCHAR)) && buffer[len / sizeof(WCHAR)] == 0, "WinHttpQueryHeaders did not append NULL terminator\n"); + ok(len == lstrlenW(buffer) * sizeof(WCHAR), "WinHttpQueryHeaders returned incorrect length.\n"); + ok(memcmp(buffer, test_header_begin, sizeof(test_header_begin)) == 0, + "WinHttpQueryHeaders returned invalid beginning of header string.\n"); + ok(memcmp(buffer + lstrlenW(buffer) - 4, test_header_end, sizeof(test_header_end)) == 0, + "WinHttpQueryHeaders returned invalid end of header string.\n"); + ok(index == 0, "WinHttpQueryHeaders incremented header index.\n"); + + index = 0; + len = 0; + SetLastError(0xdeadbeef); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, NULL, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders unexpectedly succeeded.\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "WinHttpQueryHeaders set incorrect error: expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); + ok(len > 40, "WinHttpQueryHeaders returned invalid length: expected greater than 40, got %d\n", len); + ok(index == 0, "WinHttpQueryHeaders failed: index was incremented.\n"); + + oldlen = len; + index = 0; + len = sizeof(buffer); + memset(buffer, 0xff, sizeof(buffer)); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed %u\n", GetLastError()); + ok(len + sizeof(WCHAR) <= oldlen, "resulting length longer than advertized\n"); + ok((len < sizeof(buffer) - sizeof(WCHAR)) && !buffer[len / sizeof(WCHAR)] && !buffer[len / sizeof(WCHAR) - 1], + "no double NULL terminator\n"); + ok(!memcmp(buffer, test_header_begin, sizeof(test_header_begin)), "invalid beginning of header string\n"); + ok(index == 0, "header index was incremented\n"); + + /* tests for more indices */ + ret = WinHttpAddRequestHeaders(request, test_headers[1], -1L, WINHTTP_ADDREQ_FLAG_ADD); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header: %d\n", ret); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[0], sizeof(test_indices[0])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[2], -1L, WINHTTP_ADDREQ_FLAG_REPLACE); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed to add duplicate header.\n"); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + /* add if new flag */ + ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW); + ok(ret == FALSE, "WinHttpAddRequestHeaders incorrectly replaced existing header.\n"); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[1], sizeof(test_indices[1])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); + + /* coalesce flag */ + ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_COALESCE); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE.\n"); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_flag_coalesce, sizeof(test_flag_coalesce)) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); + + /* coalesce with comma flag */ + ret = WinHttpAddRequestHeaders(request, test_headers[4], -1L, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA.\n"); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_flag_coalesce_comma, sizeof(test_flag_coalesce_comma)) == 0, + "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); + + + /* coalesce with semicolon flag */ + ret = WinHttpAddRequestHeaders(request, test_headers[5], -1L, WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON.\n"); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_flag_coalesce_semicolon, sizeof(test_flag_coalesce_semicolon)) == 0, + "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); + + /* add and replace flags */ + ret = WinHttpAddRequestHeaders(request, test_headers[3], -1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE); + ok(ret == TRUE, "WinHttpAddRequestHeaders failed with flag WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE.\n"); + + index = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 1, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[2], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == TRUE, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(index == 2, "WinHttpQueryHeaders failed to increment index.\n"); + ok(memcmp(buffer, test_indices[3], sizeof(test_indices[2])) == 0, "WinHttpQueryHeaders returned incorrect string.\n"); + + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + test_header_name, buffer, &len, &index); + ok(ret == FALSE, "WinHttpQueryHeaders succeeded unexpectedly, found third header.\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[8], ~0u, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[9], ~0u, WINHTTP_ADDREQ_FLAG_ADD); + ok(ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[10], ~0u, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[11], ~0u, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[12], ~0u, WINHTTP_ADDREQ_FLAG_ADD); + ok(!ret, "WinHttpAddRequestHeaders failed\n"); + + ret = WinHttpAddRequestHeaders(request, test_headers[13], ~0u, WINHTTP_ADDREQ_FLAG_ADD); + ok(ret, "WinHttpAddRequestHeaders failed\n"); + + index = 0; + buffer[0] = 0; + len = sizeof(buffer); + ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS, + field, buffer, &len, &index); + ok(ret, "WinHttpQueryHeaders failed: %u\n", GetLastError()); + ok(!memcmp(buffer, value, sizeof(value)), "unexpected result\n"); + + ret = WinHttpCloseHandle(request); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing request, got %d.\n", ret); + done: + ret = WinHttpCloseHandle(connection); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing connection, got %d.\n", ret); + ret = WinHttpCloseHandle(session); + ok(ret == TRUE, "WinHttpCloseHandle failed on closing session, got %d.\n", ret); + +} + +static void test_secure_connection(void) +{ + static const WCHAR google[] = {'w','w','w','.','g','o','o','g','l','e','.','c','o','m',0}; + + HANDLE ses, con, req; + DWORD size, status, policy, bitness; + BOOL ret; + CERT_CONTEXT *cert; + + ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %u\n", GetLastError()); + + policy = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; + ret = WinHttpSetOption(ses, WINHTTP_OPTION_REDIRECT_POLICY, &policy, sizeof(policy)); + ok(ret, "failed to set redirect policy %u\n", GetLastError()); + + con = WinHttpConnect(ses, google, 443, 0); + ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + + /* try without setting WINHTTP_FLAG_SECURE */ + req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); + ok(ret, "failed to send request %u\n", GetLastError()); + + ret = WinHttpReceiveResponse(req, NULL); + ok(!ret, "succeeded unexpectedly\n"); + + size = 0; + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, NULL, &size, NULL); + ok(!ret, "succeeded unexpectedly\n"); + + WinHttpCloseHandle(req); + + req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, WINHTTP_FLAG_SECURE); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); + ok(ret, "failed to send request %u\n", GetLastError()); + + size = sizeof(cert); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &size ); + ok(ret, "failed to retrieve certificate context %u\n", GetLastError()); + + size = sizeof(bitness); + ret = WinHttpQueryOption(req, WINHTTP_OPTION_SECURITY_KEY_BITNESS, &bitness, &size ); + ok(ret, "failed to retrieve key bitness %u\n", GetLastError()); + + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %u\n", GetLastError()); + + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); + ok(ret, "failed unexpectedly %u\n", GetLastError()); + ok(status == 200, "request failed unexpectedly %u\n", status); + + size = 0; + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, NULL, &size, NULL); + ok(!ret, "succeeded unexpectedly\n"); + + WinHttpCloseHandle(req); + WinHttpCloseHandle(con); + WinHttpCloseHandle(ses); +} + +static void test_request_parameter_defaults(void) +{ + static const WCHAR empty[] = {0}; + static const WCHAR codeweavers[] = {'c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0}; + + HANDLE ses, con, req; + DWORD size, status; + BOOL ret; + + ses = WinHttpOpen(test_useragent, 0, NULL, NULL, 0); + ok(ses != NULL, "failed to open session %u\n", GetLastError()); + + con = WinHttpConnect(ses, codeweavers, 0, 0); + ok(con != NULL, "failed to open a connection %u\n", GetLastError()); + + req = WinHttpOpenRequest(con, NULL, NULL, NULL, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); + ok(ret, "failed to send request %u\n", GetLastError()); + + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %u\n", GetLastError()); + + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); + ok(ret, "failed unexpectedly %u\n", GetLastError()); + ok(status == 200, "request failed unexpectedly %u\n", status); + + WinHttpCloseHandle(req); + + req = WinHttpOpenRequest(con, empty, empty, empty, NULL, NULL, 0); + ok(req != NULL, "failed to open a request %u\n", GetLastError()); + + ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0); + ok(ret, "failed to send request %u\n", GetLastError()); + + ret = WinHttpReceiveResponse(req, NULL); + ok(ret, "failed to receive response %u\n", GetLastError()); + + size = sizeof(status); + ret = WinHttpQueryHeaders(req, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL); + ok(ret, "failed unexpectedly %u\n", GetLastError()); + ok(status == 200, "request failed unexpectedly %u\n", status); + + WinHttpCloseHandle(req); + WinHttpCloseHandle(con); + WinHttpCloseHandle(ses); +} + +START_TEST (winhttp) +{ + test_OpenRequest(); + test_SendRequest(); + test_WinHttpTimeFromSystemTime(); + test_WinHttpTimeToSystemTime(); + test_WinHttpAddHeaders(); + test_secure_connection(); + test_request_parameter_defaults(); + test_QueryOption(); +} diff --git a/rostests/winetests/winhttp/winhttp.rbuild b/rostests/winetests/winhttp/winhttp.rbuild new file mode 100644 index 00000000000..3e5de6d1731 --- /dev/null +++ b/rostests/winetests/winhttp/winhttp.rbuild @@ -0,0 +1,15 @@ + + + + + . + + notification.c + testlist.c + url.c + winhttp.c + wine + winhttp + ntdll + + diff --git a/rostests/winetests/wininet/ftp.c b/rostests/winetests/wininet/ftp.c index 992bce99feb..1aec393b353 100644 --- a/rostests/winetests/wininet/ftp.c +++ b/rostests/winetests/wininet/ftp.c @@ -25,7 +25,6 @@ * TODO: * Add W-function tests. * Add missing function tests: - * FtpFindFirstFile * FtpGetFileSize * FtpSetCurrentDirectory */ @@ -66,6 +65,8 @@ static void test_connect(HINTERNET hInternet) * anonymous : NULL * NULL : IEUser@ * NULL : NULL + * "" : IEUser@ + * "" : NULL */ SetLastError(0xdeadbeef); @@ -85,6 +86,13 @@ static void test_connect(HINTERNET hInternet) ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + hFtp = InternetConnect(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "", "IEUser@", + INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0); + ok(!hFtp, "Expected InternetConnect to fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* Using a NULL username and password will be interpreted as anonymous ftp. The username will be 'anonymous' the password * is created via some simple heuristics (see dlls/wininet/ftp.c). * On Wine this registry key is not set by default so (NULL, NULL) will result in anonymous ftp with an (most likely) not @@ -103,6 +111,20 @@ static void test_connect(HINTERNET hInternet) ok ( hFtp != NULL, "InternetConnect failed : %d\n", GetLastError()); ok ( GetLastError() == ERROR_SUCCESS, "ERROR_SUCCESS, got %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + hFtp = InternetConnect(hInternet, "ftp.winehq.org", INTERNET_DEFAULT_FTP_PORT, "", NULL, + INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0); + if (!hFtp) + { + ok(GetLastError() == ERROR_INTERNET_LOGIN_FAILURE, + "Expected ERROR_INTERNET_LOGIN_FAILURE, got %d\n", GetLastError()); +} + else + { + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } } static void test_createdir(HINTERNET hFtp, HINTERNET hConnect) @@ -259,7 +281,6 @@ static void test_getfile(HINTERNET hFtp, HINTERNET hConnect) ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR, "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError()); /* Currently Wine always creates the local file (even on failure) which is not correct, hence the test */ - todo_wine ok (GetFileAttributesA("should_also_be_non_existing_deadbeef") == INVALID_FILE_ATTRIBUTES, "Local file should not have been created\n"); @@ -280,7 +301,6 @@ static void test_getfile(HINTERNET hFtp, HINTERNET hConnect) ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR, "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError()); /* Currently Wine always creates the local file (even on failure) which is not correct, hence the test */ - todo_wine ok (GetFileAttributesA("should_also_be_non_existing_deadbeef") == INVALID_FILE_ATTRIBUTES, "Local file should not have been created\n"); @@ -387,7 +407,9 @@ static void test_openfile(HINTERNET hFtp, HINTERNET hConnect) SetLastError(0xdeadbeef); hOpenFile = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0); ok ( hOpenFile != NULL, "Expected FtpOpenFileA to succeed\n"); - ok ( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", GetLastError()); + ok ( GetLastError() == ERROR_SUCCESS || + broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* Win98 */ + "Expected ERROR_SUCCESS, got %u\n", GetLastError()); if (hOpenFile) { @@ -685,7 +707,7 @@ static void test_command(HINTERNET hFtp, HINTERNET hConnect) if (!pFtpCommandA) { - skip("FtpCommandA() is not available. Skipping the Ftp command tests\n"); + win_skip("FtpCommandA() is not available. Skipping the Ftp command tests\n"); return; } @@ -700,6 +722,89 @@ static void test_command(HINTERNET hFtp, HINTERNET hConnect) } } +static void test_find_first_file(HINTERNET hFtp, HINTERNET hConnect) +{ + WIN32_FIND_DATA findData; + HINTERNET hSearch; + HINTERNET hSearch2; + HINTERNET hOpenFile; + + /* NULL as the search file ought to return the first file in the directory */ + SetLastError(0xdeadbeef); + hSearch = FtpFindFirstFileA(hFtp, NULL, &findData, 0, 0); + ok ( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" ); + + /* This should fail as the previous handle wasn't closed */ + SetLastError(0xdeadbeef); + hSearch2 = FtpFindFirstFileA(hFtp, "welcome.msg", &findData, 0, 0); + todo_wine ok ( hSearch2 == NULL, "Expected FtpFindFirstFileA to fail\n" ); + todo_wine ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS, + "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError() ); + InternetCloseHandle(hSearch2); /* Just in case */ + + InternetCloseHandle(hSearch); + + /* Try a valid filename in a subdirectory search */ + SetLastError(0xdeadbeef); + hSearch = FtpFindFirstFileA(hFtp, "pub/wine", &findData, 0, 0); + todo_wine ok ( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" ); + InternetCloseHandle(hSearch); + + /* Try a valid filename in a subdirectory wildcard search */ + SetLastError(0xdeadbeef); + hSearch = FtpFindFirstFileA(hFtp, "pub/w*", &findData, 0, 0); + todo_wine ok ( hSearch != NULL, "Expected FtpFindFirstFileA to pass\n" ); + InternetCloseHandle(hSearch); + + /* Try an invalid wildcard search */ + SetLastError(0xdeadbeef); + hSearch = FtpFindFirstFileA(hFtp, "*/w*", &findData, 0, 0); + ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" ); + InternetCloseHandle(hSearch); /* Just in case */ + + /* Try FindFirstFile between FtpOpenFile and InternetCloseHandle */ + SetLastError(0xdeadbeef); + hOpenFile = FtpOpenFileA(hFtp, "welcome.msg", GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0); + ok ( hOpenFile != NULL, "Expected FtpOpenFileA to succeed\n" ); + ok ( GetLastError() == ERROR_SUCCESS || + broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* Win98 */ + "Expected ERROR_SUCCESS, got %u\n", GetLastError() ); + + /* This should fail as the OpenFile handle wasn't closed */ + SetLastError(0xdeadbeef); + hSearch = FtpFindFirstFileA(hFtp, "welcome.msg", &findData, 0, 0); + ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" ); + ok ( GetLastError() == ERROR_FTP_TRANSFER_IN_PROGRESS, + "Expected ERROR_FTP_TRANSFER_IN_PROGRESS, got %d\n", GetLastError() ); + InternetCloseHandle(hSearch); /* Just in case */ + + InternetCloseHandle(hOpenFile); + + /* Test using a nonexistent filename */ + SetLastError(0xdeadbeef); + hSearch = FtpFindFirstFileA(hFtp, "this_file_should_not_exist", &findData, 0, 0); + ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" ); + todo_wine ok ( GetLastError() == ERROR_INTERNET_EXTENDED_ERROR, + "Expected ERROR_INTERNET_EXTENDED_ERROR, got %d\n", GetLastError() ); + InternetCloseHandle(hSearch); /* Just in case */ + + /* Test using a nonexistent filename and a wildcard */ + SetLastError(0xdeadbeef); + hSearch = FtpFindFirstFileA(hFtp, "this_file_should_not_exist*", &findData, 0, 0); + ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" ); + todo_wine ok ( GetLastError() == ERROR_NO_MORE_FILES, + "Expected ERROR_NO_MORE_FILES, got %d\n", GetLastError() ); + InternetCloseHandle(hSearch); /* Just in case */ + + /* Test using an invalid handle type */ + SetLastError(0xdeadbeef); + hSearch = FtpFindFirstFileA(hConnect, "welcome.msg", &findData, 0, 0); + ok ( hSearch == NULL, "Expected FtpFindFirstFileA to fail\n" ); + ok ( GetLastError() == ERROR_INTERNET_INCORRECT_HANDLE_TYPE, + "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError() ); + InternetCloseHandle(hSearch); /* Just in case */ +} + static void test_get_current_dir(HINTERNET hFtp, HINTERNET hConnect) { BOOL bRet; @@ -708,7 +813,7 @@ static void test_get_current_dir(HINTERNET hFtp, HINTERNET hConnect) if (!pFtpCommandA) { - skip("FtpCommandA() is not available. Skipping the Ftp get_current_dir tests\n"); + win_skip("FtpCommandA() is not available. Skipping the Ftp get_current_dir tests\n"); return; } @@ -830,6 +935,7 @@ START_TEST(ftp) test_removedir(hFtp, hHttp); test_renamefile(hFtp, hHttp); test_command(hFtp, hHttp); + test_find_first_file(hFtp, hHttp); test_get_current_dir(hFtp, hHttp); InternetCloseHandle(hHttp); diff --git a/rostests/winetests/wininet/generated.c b/rostests/winetests/wininet/generated.c index e88b3bfeb13..38933efce6f 100644 --- a/rostests/winetests/wininet/generated.c +++ b/rostests/winetests/wininet/generated.c @@ -1,4 +1,4 @@ -/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* File generated automatically from tools/winapi/tests.dat; do not edit! */ /* This file can be copied, modified and distributed without restriction. */ /* @@ -31,22 +31,14 @@ * Windows API extension */ -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) -# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) -#elif defined(__GNUC__) -# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) -#else -/* FIXME: Not sure if is possible to do without compiler extension */ -#endif - #if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) # define _TYPE_ALIGNMENT(type) __alignof(type) #elif defined(__GNUC__) # define _TYPE_ALIGNMENT(type) __alignof__(type) #else /* - * FIXME: Not sure if is possible to do without compiler extension - * (if type is not just a name that is, if so the normal) + * FIXME: May not be possible without a compiler extension + * (if type is not just a name that is, otherwise the normal * TYPE_ALIGNMENT can be used) */ #endif @@ -63,857 +55,1275 @@ * Test helper macros */ -#ifdef FIELD_ALIGNMENT -# define TEST_FIELD_ALIGNMENT(type, field, align) \ - ok(FIELD_ALIGNMENT(type, field) == align, \ - "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ - (int)FIELD_ALIGNMENT(type, field)) +#ifdef _WIN64 + +# define TEST_TYPE_SIZE(type, size) +# define TEST_TYPE_ALIGN(type, align) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) +# define TEST_FIELD_OFFSET(type, field, offset) + #else -# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) + +# define TEST_TYPE_SIZE(type, size) C_ASSERT(sizeof(type) == size); + +# ifdef TYPE_ALIGNMENT +# define TEST_TYPE_ALIGN(type, align) C_ASSERT(TYPE_ALIGNMENT(type) == align); +#else +# define TEST_TYPE_ALIGN(type, align) #endif -#define TEST_FIELD_OFFSET(type, field, offset) \ - ok(FIELD_OFFSET(type, field) == offset, \ - "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ - (long int)FIELD_OFFSET(type, field)) - -#ifdef _TYPE_ALIGNMENT -#define TEST__TYPE_ALIGNMENT(type, align) \ - ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +# ifdef _TYPE_ALIGNMENT +# define TEST_TARGET_ALIGN(type, align) C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align); +# define TEST_FIELD_ALIGN(type, field, align) C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align); #else -# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_TARGET_ALIGN(type, align) +# define TEST_FIELD_ALIGN(type, field, align) #endif -#ifdef TYPE_ALIGNMENT -#define TEST_TYPE_ALIGNMENT(type, align) \ - ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) -#else -# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset); + #endif -#define TEST_TYPE_SIZE(type, size) \ - ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) +#define TEST_TARGET_SIZE(type, size) TEST_TYPE_SIZE(*(type)0, size) +#define TEST_FIELD_SIZE(type, field, size) TEST_TYPE_SIZE((((type*)0)->field), size) +#define TEST_TYPE_SIGNED(type) C_ASSERT((type) -1 < 0); +#define TEST_TYPE_UNSIGNED(type) C_ASSERT((type) -1 > 0); -/*********************************************************************** - * Test macros - */ - -#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ - TEST_TYPE_SIZE(field_type, field_size); \ - TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ - TEST_FIELD_OFFSET(type, field_name, field_offset); \ - -#define TEST_TYPE(type, size, align) \ - TEST_TYPE_ALIGNMENT(type, align); \ - TEST_TYPE_SIZE(type, size) - -#define TEST_TYPE_POINTER(type, size, align) \ - TEST__TYPE_ALIGNMENT(*(type)0, align); \ - TEST_TYPE_SIZE(*(type)0, size) - -#define TEST_TYPE_SIGNED(type) \ - ok((type) -1 < 0, "(" #type ") -1 < 0\n"); - -#define TEST_TYPE_UNSIGNED(type) \ - ok((type) -1 > 0, "(" #type ") -1 > 0\n"); static void test_pack_GOPHER_ABSTRACT_ATTRIBUTE_TYPEA(void) { /* GOPHER_ABSTRACT_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 8, 4); - TEST_FIELD(GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, LPCSTR, ShortAbstract, 0, 4, 4); - TEST_FIELD(GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, LPCSTR, AbstractFile, 4, 4, 4); + TEST_TYPE_SIZE (GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 8) + TEST_TYPE_ALIGN (GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, ShortAbstract, 4) + TEST_FIELD_ALIGN (GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, ShortAbstract, 4) + TEST_FIELD_OFFSET(GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, ShortAbstract, 0) + TEST_FIELD_SIZE (GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, AbstractFile, 4) + TEST_FIELD_ALIGN (GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, AbstractFile, 4) + TEST_FIELD_OFFSET(GOPHER_ABSTRACT_ATTRIBUTE_TYPEA, AbstractFile, 4) } static void test_pack_GOPHER_ABSTRACT_ATTRIBUTE_TYPEW(void) { /* GOPHER_ABSTRACT_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 8, 4); - TEST_FIELD(GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, LPCWSTR, ShortAbstract, 0, 4, 4); - TEST_FIELD(GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, LPCWSTR, AbstractFile, 4, 4, 4); + TEST_TYPE_SIZE (GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 8) + TEST_TYPE_ALIGN (GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, ShortAbstract, 4) + TEST_FIELD_ALIGN (GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, ShortAbstract, 4) + TEST_FIELD_OFFSET(GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, ShortAbstract, 0) + TEST_FIELD_SIZE (GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, AbstractFile, 4) + TEST_FIELD_ALIGN (GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, AbstractFile, 4) + TEST_FIELD_OFFSET(GOPHER_ABSTRACT_ATTRIBUTE_TYPEW, AbstractFile, 4) } static void test_pack_GOPHER_ADMIN_ATTRIBUTE_TYPEA(void) { /* GOPHER_ADMIN_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_ADMIN_ATTRIBUTE_TYPEA, 8, 4); - TEST_FIELD(GOPHER_ADMIN_ATTRIBUTE_TYPEA, LPCSTR, Comment, 0, 4, 4); - TEST_FIELD(GOPHER_ADMIN_ATTRIBUTE_TYPEA, LPCSTR, EmailAddress, 4, 4, 4); + TEST_TYPE_SIZE (GOPHER_ADMIN_ATTRIBUTE_TYPEA, 8) + TEST_TYPE_ALIGN (GOPHER_ADMIN_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_ADMIN_ATTRIBUTE_TYPEA, Comment, 4) + TEST_FIELD_ALIGN (GOPHER_ADMIN_ATTRIBUTE_TYPEA, Comment, 4) + TEST_FIELD_OFFSET(GOPHER_ADMIN_ATTRIBUTE_TYPEA, Comment, 0) + TEST_FIELD_SIZE (GOPHER_ADMIN_ATTRIBUTE_TYPEA, EmailAddress, 4) + TEST_FIELD_ALIGN (GOPHER_ADMIN_ATTRIBUTE_TYPEA, EmailAddress, 4) + TEST_FIELD_OFFSET(GOPHER_ADMIN_ATTRIBUTE_TYPEA, EmailAddress, 4) } static void test_pack_GOPHER_ADMIN_ATTRIBUTE_TYPEW(void) { /* GOPHER_ADMIN_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_ADMIN_ATTRIBUTE_TYPEW, 8, 4); - TEST_FIELD(GOPHER_ADMIN_ATTRIBUTE_TYPEW, LPCWSTR, Comment, 0, 4, 4); - TEST_FIELD(GOPHER_ADMIN_ATTRIBUTE_TYPEW, LPCWSTR, EmailAddress, 4, 4, 4); + TEST_TYPE_SIZE (GOPHER_ADMIN_ATTRIBUTE_TYPEW, 8) + TEST_TYPE_ALIGN (GOPHER_ADMIN_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_ADMIN_ATTRIBUTE_TYPEW, Comment, 4) + TEST_FIELD_ALIGN (GOPHER_ADMIN_ATTRIBUTE_TYPEW, Comment, 4) + TEST_FIELD_OFFSET(GOPHER_ADMIN_ATTRIBUTE_TYPEW, Comment, 0) + TEST_FIELD_SIZE (GOPHER_ADMIN_ATTRIBUTE_TYPEW, EmailAddress, 4) + TEST_FIELD_ALIGN (GOPHER_ADMIN_ATTRIBUTE_TYPEW, EmailAddress, 4) + TEST_FIELD_OFFSET(GOPHER_ADMIN_ATTRIBUTE_TYPEW, EmailAddress, 4) } static void test_pack_GOPHER_ASK_ATTRIBUTE_TYPEA(void) { /* GOPHER_ASK_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_ASK_ATTRIBUTE_TYPEA, 8, 4); - TEST_FIELD(GOPHER_ASK_ATTRIBUTE_TYPEA, LPCSTR, QuestionType, 0, 4, 4); - TEST_FIELD(GOPHER_ASK_ATTRIBUTE_TYPEA, LPCSTR, QuestionText, 4, 4, 4); + TEST_TYPE_SIZE (GOPHER_ASK_ATTRIBUTE_TYPEA, 8) + TEST_TYPE_ALIGN (GOPHER_ASK_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_ASK_ATTRIBUTE_TYPEA, QuestionType, 4) + TEST_FIELD_ALIGN (GOPHER_ASK_ATTRIBUTE_TYPEA, QuestionType, 4) + TEST_FIELD_OFFSET(GOPHER_ASK_ATTRIBUTE_TYPEA, QuestionType, 0) + TEST_FIELD_SIZE (GOPHER_ASK_ATTRIBUTE_TYPEA, QuestionText, 4) + TEST_FIELD_ALIGN (GOPHER_ASK_ATTRIBUTE_TYPEA, QuestionText, 4) + TEST_FIELD_OFFSET(GOPHER_ASK_ATTRIBUTE_TYPEA, QuestionText, 4) } static void test_pack_GOPHER_ASK_ATTRIBUTE_TYPEW(void) { /* GOPHER_ASK_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_ASK_ATTRIBUTE_TYPEW, 8, 4); - TEST_FIELD(GOPHER_ASK_ATTRIBUTE_TYPEW, LPCWSTR, QuestionType, 0, 4, 4); - TEST_FIELD(GOPHER_ASK_ATTRIBUTE_TYPEW, LPCWSTR, QuestionText, 4, 4, 4); + TEST_TYPE_SIZE (GOPHER_ASK_ATTRIBUTE_TYPEW, 8) + TEST_TYPE_ALIGN (GOPHER_ASK_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_ASK_ATTRIBUTE_TYPEW, QuestionType, 4) + TEST_FIELD_ALIGN (GOPHER_ASK_ATTRIBUTE_TYPEW, QuestionType, 4) + TEST_FIELD_OFFSET(GOPHER_ASK_ATTRIBUTE_TYPEW, QuestionType, 0) + TEST_FIELD_SIZE (GOPHER_ASK_ATTRIBUTE_TYPEW, QuestionText, 4) + TEST_FIELD_ALIGN (GOPHER_ASK_ATTRIBUTE_TYPEW, QuestionText, 4) + TEST_FIELD_OFFSET(GOPHER_ASK_ATTRIBUTE_TYPEW, QuestionText, 4) } static void test_pack_GOPHER_ATTRIBUTE_ENUMERATORA(void) { /* GOPHER_ATTRIBUTE_ENUMERATORA */ - TEST_TYPE(GOPHER_ATTRIBUTE_ENUMERATORA, 4, 4); + TEST_TYPE_SIZE (GOPHER_ATTRIBUTE_ENUMERATORA, 4) + TEST_TYPE_ALIGN (GOPHER_ATTRIBUTE_ENUMERATORA, 4) } static void test_pack_GOPHER_ATTRIBUTE_ENUMERATORW(void) { /* GOPHER_ATTRIBUTE_ENUMERATORW */ - TEST_TYPE(GOPHER_ATTRIBUTE_ENUMERATORW, 4, 4); + TEST_TYPE_SIZE (GOPHER_ATTRIBUTE_ENUMERATORW, 4) + TEST_TYPE_ALIGN (GOPHER_ATTRIBUTE_ENUMERATORW, 4) } static void test_pack_GOPHER_ATTRIBUTE_TYPEA(void) { /* GOPHER_ATTRIBUTE_TYPEA (pack 4) */ - TEST_FIELD(GOPHER_ATTRIBUTE_TYPEA, DWORD, CategoryId, 0, 4, 4); - TEST_FIELD(GOPHER_ATTRIBUTE_TYPEA, DWORD, AttributeId, 4, 4, 4); + TEST_FIELD_SIZE (GOPHER_ATTRIBUTE_TYPEA, CategoryId, 4) + TEST_FIELD_ALIGN (GOPHER_ATTRIBUTE_TYPEA, CategoryId, 4) + TEST_FIELD_OFFSET(GOPHER_ATTRIBUTE_TYPEA, CategoryId, 0) + TEST_FIELD_SIZE (GOPHER_ATTRIBUTE_TYPEA, AttributeId, 4) + TEST_FIELD_ALIGN (GOPHER_ATTRIBUTE_TYPEA, AttributeId, 4) + TEST_FIELD_OFFSET(GOPHER_ATTRIBUTE_TYPEA, AttributeId, 4) } static void test_pack_GOPHER_ATTRIBUTE_TYPEW(void) { /* GOPHER_ATTRIBUTE_TYPEW (pack 4) */ - TEST_FIELD(GOPHER_ATTRIBUTE_TYPEW, DWORD, CategoryId, 0, 4, 4); - TEST_FIELD(GOPHER_ATTRIBUTE_TYPEW, DWORD, AttributeId, 4, 4, 4); + TEST_FIELD_SIZE (GOPHER_ATTRIBUTE_TYPEW, CategoryId, 4) + TEST_FIELD_ALIGN (GOPHER_ATTRIBUTE_TYPEW, CategoryId, 4) + TEST_FIELD_OFFSET(GOPHER_ATTRIBUTE_TYPEW, CategoryId, 0) + TEST_FIELD_SIZE (GOPHER_ATTRIBUTE_TYPEW, AttributeId, 4) + TEST_FIELD_ALIGN (GOPHER_ATTRIBUTE_TYPEW, AttributeId, 4) + TEST_FIELD_OFFSET(GOPHER_ATTRIBUTE_TYPEW, AttributeId, 4) } static void test_pack_GOPHER_FIND_DATAA(void) { /* GOPHER_FIND_DATAA (pack 4) */ - TEST_TYPE(GOPHER_FIND_DATAA, 808, 4); - TEST_FIELD(GOPHER_FIND_DATAA, CHAR[MAX_GOPHER_DISPLAY_TEXT + 1], DisplayString, 0, 129, 1); - TEST_FIELD(GOPHER_FIND_DATAA, DWORD, GopherType, 132, 4, 4); - TEST_FIELD(GOPHER_FIND_DATAA, DWORD, SizeLow, 136, 4, 4); - TEST_FIELD(GOPHER_FIND_DATAA, DWORD, SizeHigh, 140, 4, 4); - TEST_FIELD(GOPHER_FIND_DATAA, FILETIME, LastModificationTime, 144, 8, 4); - TEST_FIELD(GOPHER_FIND_DATAA, CHAR[MAX_GOPHER_LOCATOR_LENGTH + 1], Locator, 152, 654, 1); + TEST_TYPE_SIZE (GOPHER_FIND_DATAA, 808) + TEST_TYPE_ALIGN (GOPHER_FIND_DATAA, 4) + TEST_FIELD_SIZE (GOPHER_FIND_DATAA, DisplayString, 129) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAA, DisplayString, 1) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAA, DisplayString, 0) + TEST_FIELD_SIZE (GOPHER_FIND_DATAA, GopherType, 4) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAA, GopherType, 4) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAA, GopherType, 132) + TEST_FIELD_SIZE (GOPHER_FIND_DATAA, SizeLow, 4) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAA, SizeLow, 4) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAA, SizeLow, 136) + TEST_FIELD_SIZE (GOPHER_FIND_DATAA, SizeHigh, 4) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAA, SizeHigh, 4) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAA, SizeHigh, 140) + TEST_FIELD_SIZE (GOPHER_FIND_DATAA, LastModificationTime, 8) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAA, LastModificationTime, 4) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAA, LastModificationTime, 144) + TEST_FIELD_SIZE (GOPHER_FIND_DATAA, Locator, 654) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAA, Locator, 1) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAA, Locator, 152) } static void test_pack_GOPHER_FIND_DATAW(void) { /* GOPHER_FIND_DATAW (pack 4) */ - TEST_TYPE(GOPHER_FIND_DATAW, 1588, 4); - TEST_FIELD(GOPHER_FIND_DATAW, WCHAR[MAX_GOPHER_DISPLAY_TEXT + 1], DisplayString, 0, 258, 2); - TEST_FIELD(GOPHER_FIND_DATAW, DWORD, GopherType, 260, 4, 4); - TEST_FIELD(GOPHER_FIND_DATAW, DWORD, SizeLow, 264, 4, 4); - TEST_FIELD(GOPHER_FIND_DATAW, DWORD, SizeHigh, 268, 4, 4); - TEST_FIELD(GOPHER_FIND_DATAW, FILETIME, LastModificationTime, 272, 8, 4); - TEST_FIELD(GOPHER_FIND_DATAW, WCHAR[MAX_GOPHER_LOCATOR_LENGTH + 1], Locator, 280, 1308, 2); + TEST_TYPE_SIZE (GOPHER_FIND_DATAW, 1588) + TEST_TYPE_ALIGN (GOPHER_FIND_DATAW, 4) + TEST_FIELD_SIZE (GOPHER_FIND_DATAW, DisplayString, 258) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAW, DisplayString, 2) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAW, DisplayString, 0) + TEST_FIELD_SIZE (GOPHER_FIND_DATAW, GopherType, 4) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAW, GopherType, 4) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAW, GopherType, 260) + TEST_FIELD_SIZE (GOPHER_FIND_DATAW, SizeLow, 4) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAW, SizeLow, 4) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAW, SizeLow, 264) + TEST_FIELD_SIZE (GOPHER_FIND_DATAW, SizeHigh, 4) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAW, SizeHigh, 4) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAW, SizeHigh, 268) + TEST_FIELD_SIZE (GOPHER_FIND_DATAW, LastModificationTime, 8) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAW, LastModificationTime, 4) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAW, LastModificationTime, 272) + TEST_FIELD_SIZE (GOPHER_FIND_DATAW, Locator, 1308) + TEST_FIELD_ALIGN (GOPHER_FIND_DATAW, Locator, 2) + TEST_FIELD_OFFSET(GOPHER_FIND_DATAW, Locator, 280) } static void test_pack_GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE(void) { /* GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE (pack 4) */ - TEST_TYPE(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 24, 4); - TEST_FIELD(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, INT, DegreesNorth, 0, 4, 4); - TEST_FIELD(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, INT, MinutesNorth, 4, 4, 4); - TEST_FIELD(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, INT, SecondsNorth, 8, 4, 4); - TEST_FIELD(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, INT, DegreesEast, 12, 4, 4); - TEST_FIELD(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, INT, MinutesEast, 16, 4, 4); - TEST_FIELD(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, INT, SecondsEast, 20, 4, 4); + TEST_TYPE_SIZE (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 24) + TEST_TYPE_ALIGN (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 4) + TEST_FIELD_SIZE (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, DegreesNorth, 4) + TEST_FIELD_ALIGN (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, DegreesNorth, 4) + TEST_FIELD_OFFSET(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, DegreesNorth, 0) + TEST_FIELD_SIZE (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, MinutesNorth, 4) + TEST_FIELD_ALIGN (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, MinutesNorth, 4) + TEST_FIELD_OFFSET(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, MinutesNorth, 4) + TEST_FIELD_SIZE (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, SecondsNorth, 4) + TEST_FIELD_ALIGN (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, SecondsNorth, 4) + TEST_FIELD_OFFSET(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, SecondsNorth, 8) + TEST_FIELD_SIZE (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, DegreesEast, 4) + TEST_FIELD_ALIGN (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, DegreesEast, 4) + TEST_FIELD_OFFSET(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, DegreesEast, 12) + TEST_FIELD_SIZE (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, MinutesEast, 4) + TEST_FIELD_ALIGN (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, MinutesEast, 4) + TEST_FIELD_OFFSET(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, MinutesEast, 16) + TEST_FIELD_SIZE (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, SecondsEast, 4) + TEST_FIELD_ALIGN (GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, SecondsEast, 4) + TEST_FIELD_OFFSET(GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, SecondsEast, 20) } static void test_pack_GOPHER_LOCATION_ATTRIBUTE_TYPEA(void) { /* GOPHER_LOCATION_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_LOCATION_ATTRIBUTE_TYPEA, 4, 4); - TEST_FIELD(GOPHER_LOCATION_ATTRIBUTE_TYPEA, LPCSTR, Location, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_LOCATION_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (GOPHER_LOCATION_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_LOCATION_ATTRIBUTE_TYPEA, Location, 4) + TEST_FIELD_ALIGN (GOPHER_LOCATION_ATTRIBUTE_TYPEA, Location, 4) + TEST_FIELD_OFFSET(GOPHER_LOCATION_ATTRIBUTE_TYPEA, Location, 0) } static void test_pack_GOPHER_LOCATION_ATTRIBUTE_TYPEW(void) { /* GOPHER_LOCATION_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_LOCATION_ATTRIBUTE_TYPEW, 4, 4); - TEST_FIELD(GOPHER_LOCATION_ATTRIBUTE_TYPEW, LPCWSTR, Location, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_LOCATION_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (GOPHER_LOCATION_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_LOCATION_ATTRIBUTE_TYPEW, Location, 4) + TEST_FIELD_ALIGN (GOPHER_LOCATION_ATTRIBUTE_TYPEW, Location, 4) + TEST_FIELD_OFFSET(GOPHER_LOCATION_ATTRIBUTE_TYPEW, Location, 0) } static void test_pack_GOPHER_MOD_DATE_ATTRIBUTE_TYPE(void) { /* GOPHER_MOD_DATE_ATTRIBUTE_TYPE (pack 4) */ - TEST_TYPE(GOPHER_MOD_DATE_ATTRIBUTE_TYPE, 8, 4); - TEST_FIELD(GOPHER_MOD_DATE_ATTRIBUTE_TYPE, FILETIME, DateAndTime, 0, 8, 4); + TEST_TYPE_SIZE (GOPHER_MOD_DATE_ATTRIBUTE_TYPE, 8) + TEST_TYPE_ALIGN (GOPHER_MOD_DATE_ATTRIBUTE_TYPE, 4) + TEST_FIELD_SIZE (GOPHER_MOD_DATE_ATTRIBUTE_TYPE, DateAndTime, 8) + TEST_FIELD_ALIGN (GOPHER_MOD_DATE_ATTRIBUTE_TYPE, DateAndTime, 4) + TEST_FIELD_OFFSET(GOPHER_MOD_DATE_ATTRIBUTE_TYPE, DateAndTime, 0) } static void test_pack_GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA(void) { /* GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4, 4); - TEST_FIELD(GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, LPCSTR, Organization, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, Organization, 4) + TEST_FIELD_ALIGN (GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, Organization, 4) + TEST_FIELD_OFFSET(GOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, Organization, 0) } static void test_pack_GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW(void) { /* GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4, 4); - TEST_FIELD(GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, LPCWSTR, Organization, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, Organization, 4) + TEST_FIELD_ALIGN (GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, Organization, 4) + TEST_FIELD_OFFSET(GOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, Organization, 0) } static void test_pack_GOPHER_PROVIDER_ATTRIBUTE_TYPEA(void) { /* GOPHER_PROVIDER_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4, 4); - TEST_FIELD(GOPHER_PROVIDER_ATTRIBUTE_TYPEA, LPCSTR, Provider, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (GOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_PROVIDER_ATTRIBUTE_TYPEA, Provider, 4) + TEST_FIELD_ALIGN (GOPHER_PROVIDER_ATTRIBUTE_TYPEA, Provider, 4) + TEST_FIELD_OFFSET(GOPHER_PROVIDER_ATTRIBUTE_TYPEA, Provider, 0) } static void test_pack_GOPHER_PROVIDER_ATTRIBUTE_TYPEW(void) { /* GOPHER_PROVIDER_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4, 4); - TEST_FIELD(GOPHER_PROVIDER_ATTRIBUTE_TYPEW, LPCWSTR, Provider, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (GOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_PROVIDER_ATTRIBUTE_TYPEW, Provider, 4) + TEST_FIELD_ALIGN (GOPHER_PROVIDER_ATTRIBUTE_TYPEW, Provider, 4) + TEST_FIELD_OFFSET(GOPHER_PROVIDER_ATTRIBUTE_TYPEW, Provider, 0) } static void test_pack_GOPHER_SCORE_ATTRIBUTE_TYPE(void) { /* GOPHER_SCORE_ATTRIBUTE_TYPE (pack 4) */ - TEST_TYPE(GOPHER_SCORE_ATTRIBUTE_TYPE, 4, 4); - TEST_FIELD(GOPHER_SCORE_ATTRIBUTE_TYPE, INT, Score, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_SCORE_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (GOPHER_SCORE_ATTRIBUTE_TYPE, 4) + TEST_FIELD_SIZE (GOPHER_SCORE_ATTRIBUTE_TYPE, Score, 4) + TEST_FIELD_ALIGN (GOPHER_SCORE_ATTRIBUTE_TYPE, Score, 4) + TEST_FIELD_OFFSET(GOPHER_SCORE_ATTRIBUTE_TYPE, Score, 0) } static void test_pack_GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE(void) { /* GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE (pack 4) */ - TEST_TYPE(GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 8, 4); - TEST_FIELD(GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, INT, LowerBound, 0, 4, 4); - TEST_FIELD(GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, INT, UpperBound, 4, 4, 4); + TEST_TYPE_SIZE (GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 8) + TEST_TYPE_ALIGN (GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 4) + TEST_FIELD_SIZE (GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, LowerBound, 4) + TEST_FIELD_ALIGN (GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, LowerBound, 4) + TEST_FIELD_OFFSET(GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, LowerBound, 0) + TEST_FIELD_SIZE (GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, UpperBound, 4) + TEST_FIELD_ALIGN (GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, UpperBound, 4) + TEST_FIELD_OFFSET(GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, UpperBound, 4) } static void test_pack_GOPHER_SITE_ATTRIBUTE_TYPEA(void) { /* GOPHER_SITE_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_SITE_ATTRIBUTE_TYPEA, 4, 4); - TEST_FIELD(GOPHER_SITE_ATTRIBUTE_TYPEA, LPCSTR, Site, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_SITE_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (GOPHER_SITE_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_SITE_ATTRIBUTE_TYPEA, Site, 4) + TEST_FIELD_ALIGN (GOPHER_SITE_ATTRIBUTE_TYPEA, Site, 4) + TEST_FIELD_OFFSET(GOPHER_SITE_ATTRIBUTE_TYPEA, Site, 0) } static void test_pack_GOPHER_SITE_ATTRIBUTE_TYPEW(void) { /* GOPHER_SITE_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_SITE_ATTRIBUTE_TYPEW, 4, 4); - TEST_FIELD(GOPHER_SITE_ATTRIBUTE_TYPEW, LPCWSTR, Site, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_SITE_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (GOPHER_SITE_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_SITE_ATTRIBUTE_TYPEW, Site, 4) + TEST_FIELD_ALIGN (GOPHER_SITE_ATTRIBUTE_TYPEW, Site, 4) + TEST_FIELD_OFFSET(GOPHER_SITE_ATTRIBUTE_TYPEW, Site, 0) } static void test_pack_GOPHER_TIMEZONE_ATTRIBUTE_TYPE(void) { /* GOPHER_TIMEZONE_ATTRIBUTE_TYPE (pack 4) */ - TEST_TYPE(GOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4, 4); - TEST_FIELD(GOPHER_TIMEZONE_ATTRIBUTE_TYPE, INT, Zone, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (GOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4) + TEST_FIELD_SIZE (GOPHER_TIMEZONE_ATTRIBUTE_TYPE, Zone, 4) + TEST_FIELD_ALIGN (GOPHER_TIMEZONE_ATTRIBUTE_TYPE, Zone, 4) + TEST_FIELD_OFFSET(GOPHER_TIMEZONE_ATTRIBUTE_TYPE, Zone, 0) } static void test_pack_GOPHER_TTL_ATTRIBUTE_TYPE(void) { /* GOPHER_TTL_ATTRIBUTE_TYPE (pack 4) */ - TEST_TYPE(GOPHER_TTL_ATTRIBUTE_TYPE, 4, 4); - TEST_FIELD(GOPHER_TTL_ATTRIBUTE_TYPE, DWORD, Ttl, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_TTL_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (GOPHER_TTL_ATTRIBUTE_TYPE, 4) + TEST_FIELD_SIZE (GOPHER_TTL_ATTRIBUTE_TYPE, Ttl, 4) + TEST_FIELD_ALIGN (GOPHER_TTL_ATTRIBUTE_TYPE, Ttl, 4) + TEST_FIELD_OFFSET(GOPHER_TTL_ATTRIBUTE_TYPE, Ttl, 0) } static void test_pack_GOPHER_UNKNOWN_ATTRIBUTE_TYPEA(void) { /* GOPHER_UNKNOWN_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4, 4); - TEST_FIELD(GOPHER_UNKNOWN_ATTRIBUTE_TYPEA, LPCSTR, Text, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (GOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_UNKNOWN_ATTRIBUTE_TYPEA, Text, 4) + TEST_FIELD_ALIGN (GOPHER_UNKNOWN_ATTRIBUTE_TYPEA, Text, 4) + TEST_FIELD_OFFSET(GOPHER_UNKNOWN_ATTRIBUTE_TYPEA, Text, 0) } static void test_pack_GOPHER_UNKNOWN_ATTRIBUTE_TYPEW(void) { /* GOPHER_UNKNOWN_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4, 4); - TEST_FIELD(GOPHER_UNKNOWN_ATTRIBUTE_TYPEW, LPCWSTR, Text, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (GOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_UNKNOWN_ATTRIBUTE_TYPEW, Text, 4) + TEST_FIELD_ALIGN (GOPHER_UNKNOWN_ATTRIBUTE_TYPEW, Text, 4) + TEST_FIELD_OFFSET(GOPHER_UNKNOWN_ATTRIBUTE_TYPEW, Text, 0) } static void test_pack_GOPHER_VERONICA_ATTRIBUTE_TYPE(void) { /* GOPHER_VERONICA_ATTRIBUTE_TYPE (pack 4) */ - TEST_TYPE(GOPHER_VERONICA_ATTRIBUTE_TYPE, 4, 4); - TEST_FIELD(GOPHER_VERONICA_ATTRIBUTE_TYPE, BOOL, TreeWalk, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_VERONICA_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (GOPHER_VERONICA_ATTRIBUTE_TYPE, 4) + TEST_FIELD_SIZE (GOPHER_VERONICA_ATTRIBUTE_TYPE, TreeWalk, 4) + TEST_FIELD_ALIGN (GOPHER_VERONICA_ATTRIBUTE_TYPE, TreeWalk, 4) + TEST_FIELD_OFFSET(GOPHER_VERONICA_ATTRIBUTE_TYPE, TreeWalk, 0) } static void test_pack_GOPHER_VERSION_ATTRIBUTE_TYPEA(void) { /* GOPHER_VERSION_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_VERSION_ATTRIBUTE_TYPEA, 4, 4); - TEST_FIELD(GOPHER_VERSION_ATTRIBUTE_TYPEA, LPCSTR, Version, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_VERSION_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (GOPHER_VERSION_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_VERSION_ATTRIBUTE_TYPEA, Version, 4) + TEST_FIELD_ALIGN (GOPHER_VERSION_ATTRIBUTE_TYPEA, Version, 4) + TEST_FIELD_OFFSET(GOPHER_VERSION_ATTRIBUTE_TYPEA, Version, 0) } static void test_pack_GOPHER_VERSION_ATTRIBUTE_TYPEW(void) { /* GOPHER_VERSION_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_VERSION_ATTRIBUTE_TYPEW, 4, 4); - TEST_FIELD(GOPHER_VERSION_ATTRIBUTE_TYPEW, LPCWSTR, Version, 0, 4, 4); + TEST_TYPE_SIZE (GOPHER_VERSION_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (GOPHER_VERSION_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_VERSION_ATTRIBUTE_TYPEW, Version, 4) + TEST_FIELD_ALIGN (GOPHER_VERSION_ATTRIBUTE_TYPEW, Version, 4) + TEST_FIELD_OFFSET(GOPHER_VERSION_ATTRIBUTE_TYPEW, Version, 0) } static void test_pack_GOPHER_VIEW_ATTRIBUTE_TYPEA(void) { /* GOPHER_VIEW_ATTRIBUTE_TYPEA (pack 4) */ - TEST_TYPE(GOPHER_VIEW_ATTRIBUTE_TYPEA, 12, 4); - TEST_FIELD(GOPHER_VIEW_ATTRIBUTE_TYPEA, LPCSTR, ContentType, 0, 4, 4); - TEST_FIELD(GOPHER_VIEW_ATTRIBUTE_TYPEA, LPCSTR, Language, 4, 4, 4); - TEST_FIELD(GOPHER_VIEW_ATTRIBUTE_TYPEA, DWORD, Size, 8, 4, 4); + TEST_TYPE_SIZE (GOPHER_VIEW_ATTRIBUTE_TYPEA, 12) + TEST_TYPE_ALIGN (GOPHER_VIEW_ATTRIBUTE_TYPEA, 4) + TEST_FIELD_SIZE (GOPHER_VIEW_ATTRIBUTE_TYPEA, ContentType, 4) + TEST_FIELD_ALIGN (GOPHER_VIEW_ATTRIBUTE_TYPEA, ContentType, 4) + TEST_FIELD_OFFSET(GOPHER_VIEW_ATTRIBUTE_TYPEA, ContentType, 0) + TEST_FIELD_SIZE (GOPHER_VIEW_ATTRIBUTE_TYPEA, Language, 4) + TEST_FIELD_ALIGN (GOPHER_VIEW_ATTRIBUTE_TYPEA, Language, 4) + TEST_FIELD_OFFSET(GOPHER_VIEW_ATTRIBUTE_TYPEA, Language, 4) + TEST_FIELD_SIZE (GOPHER_VIEW_ATTRIBUTE_TYPEA, Size, 4) + TEST_FIELD_ALIGN (GOPHER_VIEW_ATTRIBUTE_TYPEA, Size, 4) + TEST_FIELD_OFFSET(GOPHER_VIEW_ATTRIBUTE_TYPEA, Size, 8) } static void test_pack_GOPHER_VIEW_ATTRIBUTE_TYPEW(void) { /* GOPHER_VIEW_ATTRIBUTE_TYPEW (pack 4) */ - TEST_TYPE(GOPHER_VIEW_ATTRIBUTE_TYPEW, 12, 4); - TEST_FIELD(GOPHER_VIEW_ATTRIBUTE_TYPEW, LPCWSTR, ContentType, 0, 4, 4); - TEST_FIELD(GOPHER_VIEW_ATTRIBUTE_TYPEW, LPCWSTR, Language, 4, 4, 4); - TEST_FIELD(GOPHER_VIEW_ATTRIBUTE_TYPEW, DWORD, Size, 8, 4, 4); + TEST_TYPE_SIZE (GOPHER_VIEW_ATTRIBUTE_TYPEW, 12) + TEST_TYPE_ALIGN (GOPHER_VIEW_ATTRIBUTE_TYPEW, 4) + TEST_FIELD_SIZE (GOPHER_VIEW_ATTRIBUTE_TYPEW, ContentType, 4) + TEST_FIELD_ALIGN (GOPHER_VIEW_ATTRIBUTE_TYPEW, ContentType, 4) + TEST_FIELD_OFFSET(GOPHER_VIEW_ATTRIBUTE_TYPEW, ContentType, 0) + TEST_FIELD_SIZE (GOPHER_VIEW_ATTRIBUTE_TYPEW, Language, 4) + TEST_FIELD_ALIGN (GOPHER_VIEW_ATTRIBUTE_TYPEW, Language, 4) + TEST_FIELD_OFFSET(GOPHER_VIEW_ATTRIBUTE_TYPEW, Language, 4) + TEST_FIELD_SIZE (GOPHER_VIEW_ATTRIBUTE_TYPEW, Size, 4) + TEST_FIELD_ALIGN (GOPHER_VIEW_ATTRIBUTE_TYPEW, Size, 4) + TEST_FIELD_OFFSET(GOPHER_VIEW_ATTRIBUTE_TYPEW, Size, 8) } static void test_pack_GROUPID(void) { /* GROUPID */ - TEST_TYPE(GROUPID, 8, 8); - TEST_TYPE_SIGNED(GROUPID); + TEST_TYPE_SIZE (GROUPID, 8) + TEST_TYPE_ALIGN (GROUPID, 8) + TEST_TYPE_SIGNED(GROUPID) } static void test_pack_HINTERNET(void) { /* HINTERNET */ - TEST_TYPE(HINTERNET, 4, 4); + TEST_TYPE_SIZE (HINTERNET, 4) + TEST_TYPE_ALIGN (HINTERNET, 4) } static void test_pack_HTTP_VERSION_INFO(void) { /* HTTP_VERSION_INFO (pack 4) */ - TEST_TYPE(HTTP_VERSION_INFO, 8, 4); - TEST_FIELD(HTTP_VERSION_INFO, DWORD, dwMajorVersion, 0, 4, 4); - TEST_FIELD(HTTP_VERSION_INFO, DWORD, dwMinorVersion, 4, 4, 4); + TEST_TYPE_SIZE (HTTP_VERSION_INFO, 8) + TEST_TYPE_ALIGN (HTTP_VERSION_INFO, 4) + TEST_FIELD_SIZE (HTTP_VERSION_INFO, dwMajorVersion, 4) + TEST_FIELD_ALIGN (HTTP_VERSION_INFO, dwMajorVersion, 4) + TEST_FIELD_OFFSET(HTTP_VERSION_INFO, dwMajorVersion, 0) + TEST_FIELD_SIZE (HTTP_VERSION_INFO, dwMinorVersion, 4) + TEST_FIELD_ALIGN (HTTP_VERSION_INFO, dwMinorVersion, 4) + TEST_FIELD_OFFSET(HTTP_VERSION_INFO, dwMinorVersion, 4) } static void test_pack_INTERNET_ASYNC_RESULT(void) { /* INTERNET_ASYNC_RESULT (pack 4) */ - TEST_TYPE(INTERNET_ASYNC_RESULT, 8, 4); - TEST_FIELD(INTERNET_ASYNC_RESULT, DWORD, dwResult, 0, 4, 4); - TEST_FIELD(INTERNET_ASYNC_RESULT, DWORD, dwError, 4, 4, 4); + TEST_TYPE_SIZE (INTERNET_ASYNC_RESULT, 8) + TEST_TYPE_ALIGN (INTERNET_ASYNC_RESULT, 4) + TEST_FIELD_SIZE (INTERNET_ASYNC_RESULT, dwResult, 4) + TEST_FIELD_ALIGN (INTERNET_ASYNC_RESULT, dwResult, 4) + TEST_FIELD_OFFSET(INTERNET_ASYNC_RESULT, dwResult, 0) + TEST_FIELD_SIZE (INTERNET_ASYNC_RESULT, dwError, 4) + TEST_FIELD_ALIGN (INTERNET_ASYNC_RESULT, dwError, 4) + TEST_FIELD_OFFSET(INTERNET_ASYNC_RESULT, dwError, 4) } static void test_pack_INTERNET_AUTH_NOTIFY_DATA(void) { /* INTERNET_AUTH_NOTIFY_DATA (pack 4) */ - TEST_TYPE(INTERNET_AUTH_NOTIFY_DATA, 16, 4); - TEST_FIELD(INTERNET_AUTH_NOTIFY_DATA, DWORD, cbStruct, 0, 4, 4); - TEST_FIELD(INTERNET_AUTH_NOTIFY_DATA, DWORD, dwOptions, 4, 4, 4); - TEST_FIELD(INTERNET_AUTH_NOTIFY_DATA, PFN_AUTH_NOTIFY, pfnNotify, 8, 4, 4); - TEST_FIELD(INTERNET_AUTH_NOTIFY_DATA, DWORD, dwContext, 12, 4, 4); + TEST_TYPE_SIZE (INTERNET_AUTH_NOTIFY_DATA, 16) + TEST_TYPE_ALIGN (INTERNET_AUTH_NOTIFY_DATA, 4) + TEST_FIELD_SIZE (INTERNET_AUTH_NOTIFY_DATA, cbStruct, 4) + TEST_FIELD_ALIGN (INTERNET_AUTH_NOTIFY_DATA, cbStruct, 4) + TEST_FIELD_OFFSET(INTERNET_AUTH_NOTIFY_DATA, cbStruct, 0) + TEST_FIELD_SIZE (INTERNET_AUTH_NOTIFY_DATA, dwOptions, 4) + TEST_FIELD_ALIGN (INTERNET_AUTH_NOTIFY_DATA, dwOptions, 4) + TEST_FIELD_OFFSET(INTERNET_AUTH_NOTIFY_DATA, dwOptions, 4) + TEST_FIELD_SIZE (INTERNET_AUTH_NOTIFY_DATA, pfnNotify, 4) + TEST_FIELD_ALIGN (INTERNET_AUTH_NOTIFY_DATA, pfnNotify, 4) + TEST_FIELD_OFFSET(INTERNET_AUTH_NOTIFY_DATA, pfnNotify, 8) + TEST_FIELD_SIZE (INTERNET_AUTH_NOTIFY_DATA, dwContext, 4) + TEST_FIELD_ALIGN (INTERNET_AUTH_NOTIFY_DATA, dwContext, 4) + TEST_FIELD_OFFSET(INTERNET_AUTH_NOTIFY_DATA, dwContext, 12) } static void test_pack_INTERNET_BUFFERSA(void) { /* INTERNET_BUFFERSA (pack 4) */ - TEST_TYPE(INTERNET_BUFFERSA, 40, 4); - TEST_FIELD(INTERNET_BUFFERSA, DWORD, dwStructSize, 0, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, struct _INTERNET_BUFFERSA *, Next, 4, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, LPCSTR, lpcszHeader, 8, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, DWORD, dwHeadersLength, 12, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, DWORD, dwHeadersTotal, 16, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, LPVOID, lpvBuffer, 20, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, DWORD, dwBufferLength, 24, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, DWORD, dwBufferTotal, 28, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, DWORD, dwOffsetLow, 32, 4, 4); - TEST_FIELD(INTERNET_BUFFERSA, DWORD, dwOffsetHigh, 36, 4, 4); + TEST_TYPE_SIZE (INTERNET_BUFFERSA, 40) + TEST_TYPE_ALIGN (INTERNET_BUFFERSA, 4) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, dwStructSize, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, dwStructSize, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, dwStructSize, 0) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, Next, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, Next, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, Next, 4) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, lpcszHeader, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, lpcszHeader, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, lpcszHeader, 8) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, dwHeadersLength, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, dwHeadersLength, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, dwHeadersLength, 12) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, dwHeadersTotal, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, dwHeadersTotal, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, dwHeadersTotal, 16) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, lpvBuffer, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, lpvBuffer, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, lpvBuffer, 20) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, dwBufferLength, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, dwBufferLength, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, dwBufferLength, 24) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, dwBufferTotal, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, dwBufferTotal, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, dwBufferTotal, 28) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, dwOffsetLow, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, dwOffsetLow, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, dwOffsetLow, 32) + TEST_FIELD_SIZE (INTERNET_BUFFERSA, dwOffsetHigh, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSA, dwOffsetHigh, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSA, dwOffsetHigh, 36) } static void test_pack_INTERNET_BUFFERSW(void) { /* INTERNET_BUFFERSW (pack 4) */ - TEST_TYPE(INTERNET_BUFFERSW, 40, 4); - TEST_FIELD(INTERNET_BUFFERSW, DWORD, dwStructSize, 0, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, struct _INTERNET_BUFFERSW *, Next, 4, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, LPCWSTR, lpcszHeader, 8, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, DWORD, dwHeadersLength, 12, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, DWORD, dwHeadersTotal, 16, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, LPVOID, lpvBuffer, 20, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, DWORD, dwBufferLength, 24, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, DWORD, dwBufferTotal, 28, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, DWORD, dwOffsetLow, 32, 4, 4); - TEST_FIELD(INTERNET_BUFFERSW, DWORD, dwOffsetHigh, 36, 4, 4); + TEST_TYPE_SIZE (INTERNET_BUFFERSW, 40) + TEST_TYPE_ALIGN (INTERNET_BUFFERSW, 4) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, dwStructSize, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, dwStructSize, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, dwStructSize, 0) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, Next, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, Next, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, Next, 4) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, lpcszHeader, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, lpcszHeader, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, lpcszHeader, 8) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, dwHeadersLength, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, dwHeadersLength, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, dwHeadersLength, 12) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, dwHeadersTotal, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, dwHeadersTotal, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, dwHeadersTotal, 16) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, lpvBuffer, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, lpvBuffer, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, lpvBuffer, 20) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, dwBufferLength, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, dwBufferLength, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, dwBufferLength, 24) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, dwBufferTotal, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, dwBufferTotal, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, dwBufferTotal, 28) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, dwOffsetLow, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, dwOffsetLow, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, dwOffsetLow, 32) + TEST_FIELD_SIZE (INTERNET_BUFFERSW, dwOffsetHigh, 4) + TEST_FIELD_ALIGN (INTERNET_BUFFERSW, dwOffsetHigh, 4) + TEST_FIELD_OFFSET(INTERNET_BUFFERSW, dwOffsetHigh, 36) } static void test_pack_INTERNET_CACHE_ENTRY_INFOA(void) { /* INTERNET_CACHE_ENTRY_INFOA (pack 4) */ - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, DWORD, dwStructSize, 0, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, LPSTR, lpszSourceUrlName, 4, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, LPSTR, lpszLocalFileName, 8, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, DWORD, CacheEntryType, 12, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, DWORD, dwUseCount, 16, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, DWORD, dwHitRate, 20, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, DWORD, dwSizeLow, 24, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, DWORD, dwSizeHigh, 28, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, FILETIME, LastModifiedTime, 32, 8, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, FILETIME, ExpireTime, 40, 8, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, FILETIME, LastAccessTime, 48, 8, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, FILETIME, LastSyncTime, 56, 8, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, LPBYTE, lpHeaderInfo, 64, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, DWORD, dwHeaderInfoSize, 68, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOA, LPSTR, lpszFileExtension, 72, 4, 4); + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, dwStructSize, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, dwStructSize, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, dwStructSize, 0) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, lpszSourceUrlName, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, lpszSourceUrlName, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, lpszSourceUrlName, 4) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, lpszLocalFileName, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, lpszLocalFileName, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, lpszLocalFileName, 8) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, CacheEntryType, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, CacheEntryType, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, CacheEntryType, 12) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, dwUseCount, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, dwUseCount, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, dwUseCount, 16) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, dwHitRate, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, dwHitRate, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, dwHitRate, 20) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, dwSizeLow, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, dwSizeLow, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, dwSizeLow, 24) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, dwSizeHigh, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, dwSizeHigh, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, dwSizeHigh, 28) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, LastModifiedTime, 8) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, LastModifiedTime, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, LastModifiedTime, 32) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, ExpireTime, 8) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, ExpireTime, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, ExpireTime, 40) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, LastAccessTime, 8) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, LastAccessTime, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, LastAccessTime, 48) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, LastSyncTime, 8) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, LastSyncTime, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, LastSyncTime, 56) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, lpHeaderInfo, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, lpHeaderInfo, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, lpHeaderInfo, 64) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, dwHeaderInfoSize, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, dwHeaderInfoSize, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, dwHeaderInfoSize, 68) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOA, lpszFileExtension, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOA, lpszFileExtension, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOA, lpszFileExtension, 72) } static void test_pack_INTERNET_CACHE_ENTRY_INFOW(void) { /* INTERNET_CACHE_ENTRY_INFOW (pack 4) */ - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, DWORD, dwStructSize, 0, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, LPWSTR, lpszSourceUrlName, 4, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, LPWSTR, lpszLocalFileName, 8, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, DWORD, CacheEntryType, 12, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, DWORD, dwUseCount, 16, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, DWORD, dwHitRate, 20, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, DWORD, dwSizeLow, 24, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, DWORD, dwSizeHigh, 28, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, FILETIME, LastModifiedTime, 32, 8, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, FILETIME, ExpireTime, 40, 8, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, FILETIME, LastAccessTime, 48, 8, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, FILETIME, LastSyncTime, 56, 8, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, LPBYTE, lpHeaderInfo, 64, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, DWORD, dwHeaderInfoSize, 68, 4, 4); - TEST_FIELD(INTERNET_CACHE_ENTRY_INFOW, LPWSTR, lpszFileExtension, 72, 4, 4); + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, dwStructSize, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, dwStructSize, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, dwStructSize, 0) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, lpszSourceUrlName, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, lpszSourceUrlName, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, lpszSourceUrlName, 4) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, lpszLocalFileName, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, lpszLocalFileName, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, lpszLocalFileName, 8) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, CacheEntryType, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, CacheEntryType, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, CacheEntryType, 12) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, dwUseCount, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, dwUseCount, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, dwUseCount, 16) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, dwHitRate, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, dwHitRate, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, dwHitRate, 20) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, dwSizeLow, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, dwSizeLow, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, dwSizeLow, 24) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, dwSizeHigh, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, dwSizeHigh, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, dwSizeHigh, 28) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, LastModifiedTime, 8) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, LastModifiedTime, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, LastModifiedTime, 32) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, ExpireTime, 8) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, ExpireTime, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, ExpireTime, 40) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, LastAccessTime, 8) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, LastAccessTime, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, LastAccessTime, 48) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, LastSyncTime, 8) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, LastSyncTime, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, LastSyncTime, 56) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, lpHeaderInfo, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, lpHeaderInfo, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, lpHeaderInfo, 64) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, dwHeaderInfoSize, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, dwHeaderInfoSize, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, dwHeaderInfoSize, 68) + TEST_FIELD_SIZE (INTERNET_CACHE_ENTRY_INFOW, lpszFileExtension, 4) + TEST_FIELD_ALIGN (INTERNET_CACHE_ENTRY_INFOW, lpszFileExtension, 4) + TEST_FIELD_OFFSET(INTERNET_CACHE_ENTRY_INFOW, lpszFileExtension, 72) } static void test_pack_INTERNET_CERTIFICATE_INFOA(void) { /* INTERNET_CERTIFICATE_INFOA (pack 4) */ - TEST_TYPE(INTERNET_CERTIFICATE_INFOA, 40, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOA, FILETIME, ftExpiry, 0, 8, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOA, FILETIME, ftStart, 8, 8, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOA, LPSTR, lpszSubjectInfo, 16, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOA, LPSTR, lpszIssuerInfo, 20, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOA, LPSTR, lpszProtocolName, 24, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOA, LPSTR, lpszSignatureAlgName, 28, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOA, LPSTR, lpszEncryptionAlgName, 32, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOA, DWORD, dwKeySize, 36, 4, 4); + TEST_TYPE_SIZE (INTERNET_CERTIFICATE_INFOA, 40) + TEST_TYPE_ALIGN (INTERNET_CERTIFICATE_INFOA, 4) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOA, ftExpiry, 8) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOA, ftExpiry, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOA, ftExpiry, 0) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOA, ftStart, 8) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOA, ftStart, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOA, ftStart, 8) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOA, lpszSubjectInfo, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOA, lpszSubjectInfo, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOA, lpszSubjectInfo, 16) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOA, lpszIssuerInfo, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOA, lpszIssuerInfo, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOA, lpszIssuerInfo, 20) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOA, lpszProtocolName, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOA, lpszProtocolName, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOA, lpszProtocolName, 24) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOA, lpszSignatureAlgName, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOA, lpszSignatureAlgName, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOA, lpszSignatureAlgName, 28) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOA, lpszEncryptionAlgName, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOA, lpszEncryptionAlgName, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOA, lpszEncryptionAlgName, 32) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOA, dwKeySize, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOA, dwKeySize, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOA, dwKeySize, 36) } static void test_pack_INTERNET_CERTIFICATE_INFOW(void) { /* INTERNET_CERTIFICATE_INFOW (pack 4) */ - TEST_TYPE(INTERNET_CERTIFICATE_INFOW, 40, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOW, FILETIME, ftExpiry, 0, 8, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOW, FILETIME, ftStart, 8, 8, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOW, LPWSTR, lpszSubjectInfo, 16, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOW, LPWSTR, lpszIssuerInfo, 20, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOW, LPWSTR, lpszProtocolName, 24, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOW, LPWSTR, lpszSignatureAlgName, 28, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOW, LPWSTR, lpszEncryptionAlgName, 32, 4, 4); - TEST_FIELD(INTERNET_CERTIFICATE_INFOW, DWORD, dwKeySize, 36, 4, 4); + TEST_TYPE_SIZE (INTERNET_CERTIFICATE_INFOW, 40) + TEST_TYPE_ALIGN (INTERNET_CERTIFICATE_INFOW, 4) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOW, ftExpiry, 8) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOW, ftExpiry, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOW, ftExpiry, 0) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOW, ftStart, 8) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOW, ftStart, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOW, ftStart, 8) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOW, lpszSubjectInfo, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOW, lpszSubjectInfo, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOW, lpszSubjectInfo, 16) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOW, lpszIssuerInfo, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOW, lpszIssuerInfo, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOW, lpszIssuerInfo, 20) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOW, lpszProtocolName, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOW, lpszProtocolName, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOW, lpszProtocolName, 24) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOW, lpszSignatureAlgName, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOW, lpszSignatureAlgName, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOW, lpszSignatureAlgName, 28) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOW, lpszEncryptionAlgName, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOW, lpszEncryptionAlgName, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOW, lpszEncryptionAlgName, 32) + TEST_FIELD_SIZE (INTERNET_CERTIFICATE_INFOW, dwKeySize, 4) + TEST_FIELD_ALIGN (INTERNET_CERTIFICATE_INFOW, dwKeySize, 4) + TEST_FIELD_OFFSET(INTERNET_CERTIFICATE_INFOW, dwKeySize, 36) } static void test_pack_INTERNET_CONNECTED_INFO(void) { /* INTERNET_CONNECTED_INFO (pack 4) */ - TEST_TYPE(INTERNET_CONNECTED_INFO, 8, 4); - TEST_FIELD(INTERNET_CONNECTED_INFO, DWORD, dwConnectedState, 0, 4, 4); - TEST_FIELD(INTERNET_CONNECTED_INFO, DWORD, dwFlags, 4, 4, 4); + TEST_TYPE_SIZE (INTERNET_CONNECTED_INFO, 8) + TEST_TYPE_ALIGN (INTERNET_CONNECTED_INFO, 4) + TEST_FIELD_SIZE (INTERNET_CONNECTED_INFO, dwConnectedState, 4) + TEST_FIELD_ALIGN (INTERNET_CONNECTED_INFO, dwConnectedState, 4) + TEST_FIELD_OFFSET(INTERNET_CONNECTED_INFO, dwConnectedState, 0) + TEST_FIELD_SIZE (INTERNET_CONNECTED_INFO, dwFlags, 4) + TEST_FIELD_ALIGN (INTERNET_CONNECTED_INFO, dwFlags, 4) + TEST_FIELD_OFFSET(INTERNET_CONNECTED_INFO, dwFlags, 4) } static void test_pack_INTERNET_PORT(void) { /* INTERNET_PORT */ - TEST_TYPE(INTERNET_PORT, 2, 2); - TEST_TYPE_UNSIGNED(INTERNET_PORT); + TEST_TYPE_SIZE (INTERNET_PORT, 2) + TEST_TYPE_ALIGN (INTERNET_PORT, 2) + TEST_TYPE_UNSIGNED(INTERNET_PORT) } static void test_pack_INTERNET_PROXY_INFOA(void) { /* INTERNET_PROXY_INFOA (pack 4) */ - TEST_TYPE(INTERNET_PROXY_INFOA, 12, 4); - TEST_FIELD(INTERNET_PROXY_INFOA, DWORD, dwAccessType, 0, 4, 4); - TEST_FIELD(INTERNET_PROXY_INFOA, LPCSTR, lpszProxy, 4, 4, 4); - TEST_FIELD(INTERNET_PROXY_INFOA, LPCSTR, lpszProxyBypass, 8, 4, 4); + TEST_TYPE_SIZE (INTERNET_PROXY_INFOA, 12) + TEST_TYPE_ALIGN (INTERNET_PROXY_INFOA, 4) + TEST_FIELD_SIZE (INTERNET_PROXY_INFOA, dwAccessType, 4) + TEST_FIELD_ALIGN (INTERNET_PROXY_INFOA, dwAccessType, 4) + TEST_FIELD_OFFSET(INTERNET_PROXY_INFOA, dwAccessType, 0) + TEST_FIELD_SIZE (INTERNET_PROXY_INFOA, lpszProxy, 4) + TEST_FIELD_ALIGN (INTERNET_PROXY_INFOA, lpszProxy, 4) + TEST_FIELD_OFFSET(INTERNET_PROXY_INFOA, lpszProxy, 4) + TEST_FIELD_SIZE (INTERNET_PROXY_INFOA, lpszProxyBypass, 4) + TEST_FIELD_ALIGN (INTERNET_PROXY_INFOA, lpszProxyBypass, 4) + TEST_FIELD_OFFSET(INTERNET_PROXY_INFOA, lpszProxyBypass, 8) } static void test_pack_INTERNET_PROXY_INFOW(void) { /* INTERNET_PROXY_INFOW (pack 4) */ - TEST_TYPE(INTERNET_PROXY_INFOW, 12, 4); - TEST_FIELD(INTERNET_PROXY_INFOW, DWORD, dwAccessType, 0, 4, 4); - TEST_FIELD(INTERNET_PROXY_INFOW, LPCWSTR, lpszProxy, 4, 4, 4); - TEST_FIELD(INTERNET_PROXY_INFOW, LPCWSTR, lpszProxyBypass, 8, 4, 4); + TEST_TYPE_SIZE (INTERNET_PROXY_INFOW, 12) + TEST_TYPE_ALIGN (INTERNET_PROXY_INFOW, 4) + TEST_FIELD_SIZE (INTERNET_PROXY_INFOW, dwAccessType, 4) + TEST_FIELD_ALIGN (INTERNET_PROXY_INFOW, dwAccessType, 4) + TEST_FIELD_OFFSET(INTERNET_PROXY_INFOW, dwAccessType, 0) + TEST_FIELD_SIZE (INTERNET_PROXY_INFOW, lpszProxy, 4) + TEST_FIELD_ALIGN (INTERNET_PROXY_INFOW, lpszProxy, 4) + TEST_FIELD_OFFSET(INTERNET_PROXY_INFOW, lpszProxy, 4) + TEST_FIELD_SIZE (INTERNET_PROXY_INFOW, lpszProxyBypass, 4) + TEST_FIELD_ALIGN (INTERNET_PROXY_INFOW, lpszProxyBypass, 4) + TEST_FIELD_OFFSET(INTERNET_PROXY_INFOW, lpszProxyBypass, 8) } static void test_pack_INTERNET_STATUS_CALLBACK(void) { /* INTERNET_STATUS_CALLBACK */ - TEST_TYPE(INTERNET_STATUS_CALLBACK, 4, 4); + TEST_TYPE_SIZE (INTERNET_STATUS_CALLBACK, 4) + TEST_TYPE_ALIGN (INTERNET_STATUS_CALLBACK, 4) } static void test_pack_INTERNET_VERSION_INFO(void) { /* INTERNET_VERSION_INFO (pack 4) */ - TEST_TYPE(INTERNET_VERSION_INFO, 8, 4); - TEST_FIELD(INTERNET_VERSION_INFO, DWORD, dwMajorVersion, 0, 4, 4); - TEST_FIELD(INTERNET_VERSION_INFO, DWORD, dwMinorVersion, 4, 4, 4); + TEST_TYPE_SIZE (INTERNET_VERSION_INFO, 8) + TEST_TYPE_ALIGN (INTERNET_VERSION_INFO, 4) + TEST_FIELD_SIZE (INTERNET_VERSION_INFO, dwMajorVersion, 4) + TEST_FIELD_ALIGN (INTERNET_VERSION_INFO, dwMajorVersion, 4) + TEST_FIELD_OFFSET(INTERNET_VERSION_INFO, dwMajorVersion, 0) + TEST_FIELD_SIZE (INTERNET_VERSION_INFO, dwMinorVersion, 4) + TEST_FIELD_ALIGN (INTERNET_VERSION_INFO, dwMinorVersion, 4) + TEST_FIELD_OFFSET(INTERNET_VERSION_INFO, dwMinorVersion, 4) } static void test_pack_LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 8, 4); + TEST_TYPE_SIZE (LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 8) + TEST_TARGET_ALIGN(LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 8, 4); + TEST_TYPE_SIZE (LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 8) + TEST_TARGET_ALIGN(LPGOPHER_ABSTRACT_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_ADMIN_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_ADMIN_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_ADMIN_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_ADMIN_ATTRIBUTE_TYPEA, 8, 4); + TEST_TYPE_SIZE (LPGOPHER_ADMIN_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_ADMIN_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_ADMIN_ATTRIBUTE_TYPEA, 8) + TEST_TARGET_ALIGN(LPGOPHER_ADMIN_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_ADMIN_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_ADMIN_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_ADMIN_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_ADMIN_ATTRIBUTE_TYPEW, 8, 4); + TEST_TYPE_SIZE (LPGOPHER_ADMIN_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_ADMIN_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_ADMIN_ATTRIBUTE_TYPEW, 8) + TEST_TARGET_ALIGN(LPGOPHER_ADMIN_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_ASK_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_ASK_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_ASK_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_ASK_ATTRIBUTE_TYPEA, 8, 4); + TEST_TYPE_SIZE (LPGOPHER_ASK_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_ASK_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_ASK_ATTRIBUTE_TYPEA, 8) + TEST_TARGET_ALIGN(LPGOPHER_ASK_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_ASK_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_ASK_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_ASK_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_ASK_ATTRIBUTE_TYPEW, 8, 4); + TEST_TYPE_SIZE (LPGOPHER_ASK_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_ASK_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_ASK_ATTRIBUTE_TYPEW, 8) + TEST_TARGET_ALIGN(LPGOPHER_ASK_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_ATTRIBUTE_TYPEA, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_ATTRIBUTE_TYPEW, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_FIND_DATAA(void) { /* LPGOPHER_FIND_DATAA */ - TEST_TYPE(LPGOPHER_FIND_DATAA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_FIND_DATAA, 808, 4); + TEST_TYPE_SIZE (LPGOPHER_FIND_DATAA, 4) + TEST_TYPE_ALIGN (LPGOPHER_FIND_DATAA, 4) + TEST_TARGET_SIZE (LPGOPHER_FIND_DATAA, 808) + TEST_TARGET_ALIGN(LPGOPHER_FIND_DATAA, 4) } static void test_pack_LPGOPHER_FIND_DATAW(void) { /* LPGOPHER_FIND_DATAW */ - TEST_TYPE(LPGOPHER_FIND_DATAW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_FIND_DATAW, 1588, 4); + TEST_TYPE_SIZE (LPGOPHER_FIND_DATAW, 4) + TEST_TYPE_ALIGN (LPGOPHER_FIND_DATAW, 4) + TEST_TARGET_SIZE (LPGOPHER_FIND_DATAW, 1588) + TEST_TARGET_ALIGN(LPGOPHER_FIND_DATAW, 4) } static void test_pack_LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE(void) { /* LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE */ - TEST_TYPE(LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 24, 4); + TEST_TYPE_SIZE (LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 4) + TEST_TARGET_SIZE (LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 24) + TEST_TARGET_ALIGN(LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, 4) } static void test_pack_LPGOPHER_LOCATION_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_LOCATION_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_LOCATION_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_LOCATION_ATTRIBUTE_TYPEA, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_LOCATION_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_LOCATION_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_LOCATION_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_ALIGN(LPGOPHER_LOCATION_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_LOCATION_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_LOCATION_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_LOCATION_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_LOCATION_ATTRIBUTE_TYPEW, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_LOCATION_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_LOCATION_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_LOCATION_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_ALIGN(LPGOPHER_LOCATION_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE(void) { /* LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE */ - TEST_TYPE(LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE, 8, 4); + TEST_TYPE_SIZE (LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE, 4) + TEST_TARGET_SIZE (LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE, 8) + TEST_TARGET_ALIGN(LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE, 4) } static void test_pack_LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_ALIGN(LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_ALIGN(LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_PROVIDER_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_PROVIDER_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_ALIGN(LPGOPHER_PROVIDER_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_PROVIDER_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_PROVIDER_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_ALIGN(LPGOPHER_PROVIDER_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_SCORE_ATTRIBUTE_TYPE(void) { /* LPGOPHER_SCORE_ATTRIBUTE_TYPE */ - TEST_TYPE(LPGOPHER_SCORE_ATTRIBUTE_TYPE, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_SCORE_ATTRIBUTE_TYPE, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_SCORE_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (LPGOPHER_SCORE_ATTRIBUTE_TYPE, 4) + TEST_TARGET_SIZE (LPGOPHER_SCORE_ATTRIBUTE_TYPE, 4) + TEST_TARGET_ALIGN(LPGOPHER_SCORE_ATTRIBUTE_TYPE, 4) } static void test_pack_LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE(void) { /* LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE */ - TEST_TYPE(LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 8, 4); + TEST_TYPE_SIZE (LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 4) + TEST_TARGET_SIZE (LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 8) + TEST_TARGET_ALIGN(LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, 4) } static void test_pack_LPGOPHER_SITE_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_SITE_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_SITE_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_SITE_ATTRIBUTE_TYPEA, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_SITE_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_SITE_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_SITE_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_ALIGN(LPGOPHER_SITE_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_SITE_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_SITE_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_SITE_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_SITE_ATTRIBUTE_TYPEW, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_SITE_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_SITE_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_SITE_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_ALIGN(LPGOPHER_SITE_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE(void) { /* LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE */ - TEST_TYPE(LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4) + TEST_TARGET_SIZE (LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4) + TEST_TARGET_ALIGN(LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE, 4) } static void test_pack_LPGOPHER_TTL_ATTRIBUTE_TYPE(void) { /* LPGOPHER_TTL_ATTRIBUTE_TYPE */ - TEST_TYPE(LPGOPHER_TTL_ATTRIBUTE_TYPE, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_TTL_ATTRIBUTE_TYPE, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_TTL_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (LPGOPHER_TTL_ATTRIBUTE_TYPE, 4) + TEST_TARGET_SIZE (LPGOPHER_TTL_ATTRIBUTE_TYPE, 4) + TEST_TARGET_ALIGN(LPGOPHER_TTL_ATTRIBUTE_TYPE, 4) } static void test_pack_LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_ALIGN(LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_ALIGN(LPGOPHER_UNKNOWN_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_VERONICA_ATTRIBUTE_TYPE(void) { /* LPGOPHER_VERONICA_ATTRIBUTE_TYPE */ - TEST_TYPE(LPGOPHER_VERONICA_ATTRIBUTE_TYPE, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_VERONICA_ATTRIBUTE_TYPE, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_VERONICA_ATTRIBUTE_TYPE, 4) + TEST_TYPE_ALIGN (LPGOPHER_VERONICA_ATTRIBUTE_TYPE, 4) + TEST_TARGET_SIZE (LPGOPHER_VERONICA_ATTRIBUTE_TYPE, 4) + TEST_TARGET_ALIGN(LPGOPHER_VERONICA_ATTRIBUTE_TYPE, 4) } static void test_pack_LPGOPHER_VERSION_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_VERSION_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_VERSION_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_VERSION_ATTRIBUTE_TYPEA, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_VERSION_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_VERSION_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_VERSION_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_ALIGN(LPGOPHER_VERSION_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_VERSION_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_VERSION_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_VERSION_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_VERSION_ATTRIBUTE_TYPEW, 4, 4); + TEST_TYPE_SIZE (LPGOPHER_VERSION_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_VERSION_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_VERSION_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_ALIGN(LPGOPHER_VERSION_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPGOPHER_VIEW_ATTRIBUTE_TYPEA(void) { /* LPGOPHER_VIEW_ATTRIBUTE_TYPEA */ - TEST_TYPE(LPGOPHER_VIEW_ATTRIBUTE_TYPEA, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_VIEW_ATTRIBUTE_TYPEA, 12, 4); + TEST_TYPE_SIZE (LPGOPHER_VIEW_ATTRIBUTE_TYPEA, 4) + TEST_TYPE_ALIGN (LPGOPHER_VIEW_ATTRIBUTE_TYPEA, 4) + TEST_TARGET_SIZE (LPGOPHER_VIEW_ATTRIBUTE_TYPEA, 12) + TEST_TARGET_ALIGN(LPGOPHER_VIEW_ATTRIBUTE_TYPEA, 4) } static void test_pack_LPGOPHER_VIEW_ATTRIBUTE_TYPEW(void) { /* LPGOPHER_VIEW_ATTRIBUTE_TYPEW */ - TEST_TYPE(LPGOPHER_VIEW_ATTRIBUTE_TYPEW, 4, 4); - TEST_TYPE_POINTER(LPGOPHER_VIEW_ATTRIBUTE_TYPEW, 12, 4); + TEST_TYPE_SIZE (LPGOPHER_VIEW_ATTRIBUTE_TYPEW, 4) + TEST_TYPE_ALIGN (LPGOPHER_VIEW_ATTRIBUTE_TYPEW, 4) + TEST_TARGET_SIZE (LPGOPHER_VIEW_ATTRIBUTE_TYPEW, 12) + TEST_TARGET_ALIGN(LPGOPHER_VIEW_ATTRIBUTE_TYPEW, 4) } static void test_pack_LPHINTERNET(void) { /* LPHINTERNET */ - TEST_TYPE(LPHINTERNET, 4, 4); - TEST_TYPE_POINTER(LPHINTERNET, 4, 4); + TEST_TYPE_SIZE (LPHINTERNET, 4) + TEST_TYPE_ALIGN (LPHINTERNET, 4) + TEST_TARGET_SIZE (LPHINTERNET, 4) + TEST_TARGET_ALIGN(LPHINTERNET, 4) } static void test_pack_LPHTTP_VERSION_INFO(void) { /* LPHTTP_VERSION_INFO */ - TEST_TYPE(LPHTTP_VERSION_INFO, 4, 4); - TEST_TYPE_POINTER(LPHTTP_VERSION_INFO, 8, 4); + TEST_TYPE_SIZE (LPHTTP_VERSION_INFO, 4) + TEST_TYPE_ALIGN (LPHTTP_VERSION_INFO, 4) + TEST_TARGET_SIZE (LPHTTP_VERSION_INFO, 8) + TEST_TARGET_ALIGN(LPHTTP_VERSION_INFO, 4) } static void test_pack_LPINTERNET_ASYNC_RESULT(void) { /* LPINTERNET_ASYNC_RESULT */ - TEST_TYPE(LPINTERNET_ASYNC_RESULT, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_ASYNC_RESULT, 8, 4); + TEST_TYPE_SIZE (LPINTERNET_ASYNC_RESULT, 4) + TEST_TYPE_ALIGN (LPINTERNET_ASYNC_RESULT, 4) + TEST_TARGET_SIZE (LPINTERNET_ASYNC_RESULT, 8) + TEST_TARGET_ALIGN(LPINTERNET_ASYNC_RESULT, 4) } static void test_pack_LPINTERNET_BUFFERSA(void) { /* LPINTERNET_BUFFERSA */ - TEST_TYPE(LPINTERNET_BUFFERSA, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_BUFFERSA, 40, 4); + TEST_TYPE_SIZE (LPINTERNET_BUFFERSA, 4) + TEST_TYPE_ALIGN (LPINTERNET_BUFFERSA, 4) + TEST_TARGET_SIZE (LPINTERNET_BUFFERSA, 40) + TEST_TARGET_ALIGN(LPINTERNET_BUFFERSA, 4) } static void test_pack_LPINTERNET_BUFFERSW(void) { /* LPINTERNET_BUFFERSW */ - TEST_TYPE(LPINTERNET_BUFFERSW, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_BUFFERSW, 40, 4); + TEST_TYPE_SIZE (LPINTERNET_BUFFERSW, 4) + TEST_TYPE_ALIGN (LPINTERNET_BUFFERSW, 4) + TEST_TARGET_SIZE (LPINTERNET_BUFFERSW, 40) + TEST_TARGET_ALIGN(LPINTERNET_BUFFERSW, 4) } static void test_pack_LPINTERNET_CACHE_ENTRY_INFOA(void) { /* LPINTERNET_CACHE_ENTRY_INFOA */ - TEST_TYPE(LPINTERNET_CACHE_ENTRY_INFOA, 4, 4); + TEST_TYPE_SIZE (LPINTERNET_CACHE_ENTRY_INFOA, 4) + TEST_TYPE_ALIGN (LPINTERNET_CACHE_ENTRY_INFOA, 4) } static void test_pack_LPINTERNET_CACHE_ENTRY_INFOW(void) { /* LPINTERNET_CACHE_ENTRY_INFOW */ - TEST_TYPE(LPINTERNET_CACHE_ENTRY_INFOW, 4, 4); + TEST_TYPE_SIZE (LPINTERNET_CACHE_ENTRY_INFOW, 4) + TEST_TYPE_ALIGN (LPINTERNET_CACHE_ENTRY_INFOW, 4) } static void test_pack_LPINTERNET_CERTIFICATE_INFOA(void) { /* LPINTERNET_CERTIFICATE_INFOA */ - TEST_TYPE(LPINTERNET_CERTIFICATE_INFOA, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_CERTIFICATE_INFOA, 40, 4); + TEST_TYPE_SIZE (LPINTERNET_CERTIFICATE_INFOA, 4) + TEST_TYPE_ALIGN (LPINTERNET_CERTIFICATE_INFOA, 4) + TEST_TARGET_SIZE (LPINTERNET_CERTIFICATE_INFOA, 40) + TEST_TARGET_ALIGN(LPINTERNET_CERTIFICATE_INFOA, 4) } static void test_pack_LPINTERNET_CERTIFICATE_INFOW(void) { /* LPINTERNET_CERTIFICATE_INFOW */ - TEST_TYPE(LPINTERNET_CERTIFICATE_INFOW, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_CERTIFICATE_INFOW, 40, 4); + TEST_TYPE_SIZE (LPINTERNET_CERTIFICATE_INFOW, 4) + TEST_TYPE_ALIGN (LPINTERNET_CERTIFICATE_INFOW, 4) + TEST_TARGET_SIZE (LPINTERNET_CERTIFICATE_INFOW, 40) + TEST_TARGET_ALIGN(LPINTERNET_CERTIFICATE_INFOW, 4) } static void test_pack_LPINTERNET_CONNECTED_INFO(void) { /* LPINTERNET_CONNECTED_INFO */ - TEST_TYPE(LPINTERNET_CONNECTED_INFO, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_CONNECTED_INFO, 8, 4); + TEST_TYPE_SIZE (LPINTERNET_CONNECTED_INFO, 4) + TEST_TYPE_ALIGN (LPINTERNET_CONNECTED_INFO, 4) + TEST_TARGET_SIZE (LPINTERNET_CONNECTED_INFO, 8) + TEST_TARGET_ALIGN(LPINTERNET_CONNECTED_INFO, 4) } static void test_pack_LPINTERNET_PORT(void) { /* LPINTERNET_PORT */ - TEST_TYPE(LPINTERNET_PORT, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_PORT, 2, 2); + TEST_TYPE_SIZE (LPINTERNET_PORT, 4) + TEST_TYPE_ALIGN (LPINTERNET_PORT, 4) + TEST_TARGET_SIZE (LPINTERNET_PORT, 2) + TEST_TARGET_ALIGN(LPINTERNET_PORT, 2) } static void test_pack_LPINTERNET_PROXY_INFOA(void) { /* LPINTERNET_PROXY_INFOA */ - TEST_TYPE(LPINTERNET_PROXY_INFOA, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_PROXY_INFOA, 12, 4); + TEST_TYPE_SIZE (LPINTERNET_PROXY_INFOA, 4) + TEST_TYPE_ALIGN (LPINTERNET_PROXY_INFOA, 4) + TEST_TARGET_SIZE (LPINTERNET_PROXY_INFOA, 12) + TEST_TARGET_ALIGN(LPINTERNET_PROXY_INFOA, 4) } static void test_pack_LPINTERNET_PROXY_INFOW(void) { /* LPINTERNET_PROXY_INFOW */ - TEST_TYPE(LPINTERNET_PROXY_INFOW, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_PROXY_INFOW, 12, 4); + TEST_TYPE_SIZE (LPINTERNET_PROXY_INFOW, 4) + TEST_TYPE_ALIGN (LPINTERNET_PROXY_INFOW, 4) + TEST_TARGET_SIZE (LPINTERNET_PROXY_INFOW, 12) + TEST_TARGET_ALIGN(LPINTERNET_PROXY_INFOW, 4) } static void test_pack_LPINTERNET_STATUS_CALLBACK(void) { /* LPINTERNET_STATUS_CALLBACK */ - TEST_TYPE(LPINTERNET_STATUS_CALLBACK, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_STATUS_CALLBACK, 4, 4); + TEST_TYPE_SIZE (LPINTERNET_STATUS_CALLBACK, 4) + TEST_TYPE_ALIGN (LPINTERNET_STATUS_CALLBACK, 4) + TEST_TARGET_SIZE (LPINTERNET_STATUS_CALLBACK, 4) + TEST_TARGET_ALIGN(LPINTERNET_STATUS_CALLBACK, 4) } static void test_pack_LPINTERNET_VERSION_INFO(void) { /* LPINTERNET_VERSION_INFO */ - TEST_TYPE(LPINTERNET_VERSION_INFO, 4, 4); - TEST_TYPE_POINTER(LPINTERNET_VERSION_INFO, 8, 4); + TEST_TYPE_SIZE (LPINTERNET_VERSION_INFO, 4) + TEST_TYPE_ALIGN (LPINTERNET_VERSION_INFO, 4) + TEST_TARGET_SIZE (LPINTERNET_VERSION_INFO, 8) + TEST_TARGET_ALIGN(LPINTERNET_VERSION_INFO, 4) } static void test_pack_LPURL_COMPONENTSA(void) { /* LPURL_COMPONENTSA */ - TEST_TYPE(LPURL_COMPONENTSA, 4, 4); + TEST_TYPE_SIZE (LPURL_COMPONENTSA, 4) + TEST_TYPE_ALIGN (LPURL_COMPONENTSA, 4) } static void test_pack_LPURL_COMPONENTSW(void) { /* LPURL_COMPONENTSW */ - TEST_TYPE(LPURL_COMPONENTSW, 4, 4); + TEST_TYPE_SIZE (LPURL_COMPONENTSW, 4) + TEST_TYPE_ALIGN (LPURL_COMPONENTSW, 4) } static void test_pack_PFN_AUTH_NOTIFY(void) { /* PFN_AUTH_NOTIFY */ - TEST_TYPE(PFN_AUTH_NOTIFY, 4, 4); + TEST_TYPE_SIZE (PFN_AUTH_NOTIFY, 4) + TEST_TYPE_ALIGN (PFN_AUTH_NOTIFY, 4) } static void test_pack_PFN_DIAL_HANDLER(void) { /* PFN_DIAL_HANDLER */ - TEST_TYPE(PFN_DIAL_HANDLER, 4, 4); + TEST_TYPE_SIZE (PFN_DIAL_HANDLER, 4) + TEST_TYPE_ALIGN (PFN_DIAL_HANDLER, 4) } static void test_pack_URL_COMPONENTSA(void) { /* URL_COMPONENTSA (pack 4) */ - TEST_FIELD(URL_COMPONENTSA, DWORD, dwStructSize, 0, 4, 4); - TEST_FIELD(URL_COMPONENTSA, LPSTR, lpszScheme, 4, 4, 4); - TEST_FIELD(URL_COMPONENTSA, DWORD, dwSchemeLength, 8, 4, 4); + TEST_FIELD_SIZE (URL_COMPONENTSA, dwStructSize, 4) + TEST_FIELD_ALIGN (URL_COMPONENTSA, dwStructSize, 4) + TEST_FIELD_OFFSET(URL_COMPONENTSA, dwStructSize, 0) + TEST_FIELD_SIZE (URL_COMPONENTSA, lpszScheme, 4) + TEST_FIELD_ALIGN (URL_COMPONENTSA, lpszScheme, 4) + TEST_FIELD_OFFSET(URL_COMPONENTSA, lpszScheme, 4) + TEST_FIELD_SIZE (URL_COMPONENTSA, dwSchemeLength, 4) + TEST_FIELD_ALIGN (URL_COMPONENTSA, dwSchemeLength, 4) + TEST_FIELD_OFFSET(URL_COMPONENTSA, dwSchemeLength, 8) } static void test_pack_URL_COMPONENTSW(void) { /* URL_COMPONENTSW (pack 4) */ - TEST_FIELD(URL_COMPONENTSW, DWORD, dwStructSize, 0, 4, 4); - TEST_FIELD(URL_COMPONENTSW, LPWSTR, lpszScheme, 4, 4, 4); - TEST_FIELD(URL_COMPONENTSW, DWORD, dwSchemeLength, 8, 4, 4); + TEST_FIELD_SIZE (URL_COMPONENTSW, dwStructSize, 4) + TEST_FIELD_ALIGN (URL_COMPONENTSW, dwStructSize, 4) + TEST_FIELD_OFFSET(URL_COMPONENTSW, dwStructSize, 0) + TEST_FIELD_SIZE (URL_COMPONENTSW, lpszScheme, 4) + TEST_FIELD_ALIGN (URL_COMPONENTSW, lpszScheme, 4) + TEST_FIELD_OFFSET(URL_COMPONENTSW, lpszScheme, 4) + TEST_FIELD_SIZE (URL_COMPONENTSW, dwSchemeLength, 4) + TEST_FIELD_ALIGN (URL_COMPONENTSW, dwSchemeLength, 4) + TEST_FIELD_OFFSET(URL_COMPONENTSW, dwSchemeLength, 8) } static void test_pack(void) @@ -1024,5 +1434,9 @@ static void test_pack(void) START_TEST(generated) { +#ifdef _WIN64 + ok(0, "The type size / alignment tests don't support Win64 yet\n"); +#else test_pack(); +#endif } diff --git a/rostests/winetests/wininet/http.c b/rostests/winetests/wininet/http.c index 705fcac6020..3404cfa5584 100644 --- a/rostests/winetests/wininet/http.c +++ b/rostests/winetests/wininet/http.c @@ -31,7 +31,7 @@ #include "wine/test.h" -#define TEST_URL "http://www.winehq.org/site/about" +#define TEST_URL "http://test.winehq.org/hello.html" static BOOL first_connection_to_test_url = TRUE; @@ -43,6 +43,12 @@ static BOOL first_connection_to_test_url = TRUE; #define SET_EXPECT(status) \ SET_EXPECT2(status, 1) +#define SET_OPTIONAL2(status, num) \ + optional[status] = num + +#define SET_OPTIONAL(status) \ + SET_OPTIONAL2(status, 1) + /* SET_WINE_ALLOW's should be used with an appropriate * todo_wine CHECK_NOTIFIED at a later point in the code */ #define SET_WINE_ALLOW2(status, num) \ @@ -53,7 +59,7 @@ static BOOL first_connection_to_test_url = TRUE; #define CHECK_EXPECT(status) \ do { \ - if (!expect[status] && wine_allow[status]) \ + if (!expect[status] && !optional[status] && wine_allow[status]) \ { \ todo_wine ok(expect[status], "unexpected status %d (%s)\n", status, \ status < MAX_INTERNET_STATUS && status_string[status][0] != 0 ? \ @@ -62,10 +68,11 @@ static BOOL first_connection_to_test_url = TRUE; } \ else \ { \ - ok(expect[status], "unexpected status %d (%s)\n", status, \ + ok(expect[status] || optional[status], "unexpected status %d (%s)\n", status, \ status < MAX_INTERNET_STATUS && status_string[status][0] != 0 ? \ status_string[status] : "unknown"); \ - expect[status]--; \ + if (expect[status]) expect[status]--; \ + else optional[status]--; \ } \ notified[status]++; \ }while(0) @@ -73,11 +80,12 @@ static BOOL first_connection_to_test_url = TRUE; /* CLEAR_NOTIFIED used in cases when notification behavior * differs between Windows versions */ #define CLEAR_NOTIFIED(status) \ - expect[status] = wine_allow[status] = notified[status] = 0; + expect[status] = optional[status] = wine_allow[status] = notified[status] = 0; #define CHECK_NOTIFIED2(status, num) \ do { \ - ok(notified[status] == (num), "expected status %d (%s) %d times, received %d times\n", \ + ok(notified[status] + optional[status] == (num), \ + "expected status %d (%s) %d times, received %d times\n", \ status, status < MAX_INTERNET_STATUS && status_string[status][0] != 0 ? \ status_string[status] : "unknown", (num), notified[status]); \ CLEAR_NOTIFIED(status); \ @@ -91,17 +99,13 @@ static BOOL first_connection_to_test_url = TRUE; #define MAX_INTERNET_STATUS (INTERNET_STATUS_COOKIE_HISTORY+1) #define MAX_STATUS_NAME 50 -static int expect[MAX_INTERNET_STATUS], wine_allow[MAX_INTERNET_STATUS], - notified[MAX_INTERNET_STATUS]; +static int expect[MAX_INTERNET_STATUS], optional[MAX_INTERNET_STATUS], + wine_allow[MAX_INTERNET_STATUS], notified[MAX_INTERNET_STATUS]; static CHAR status_string[MAX_INTERNET_STATUS][MAX_STATUS_NAME]; static HANDLE hCompleteEvent; static INTERNET_STATUS_CALLBACK (WINAPI *pInternetSetStatusCallbackA)(HINTERNET ,INTERNET_STATUS_CALLBACK); -static BOOL (WINAPI *pInternetTimeFromSystemTimeA)(CONST SYSTEMTIME *,DWORD ,LPSTR ,DWORD); -static BOOL (WINAPI *pInternetTimeFromSystemTimeW)(CONST SYSTEMTIME *,DWORD ,LPWSTR ,DWORD); -static BOOL (WINAPI *pInternetTimeToSystemTimeA)(LPCSTR ,SYSTEMTIME *,DWORD); -static BOOL (WINAPI *pInternetTimeToSystemTimeW)(LPCWSTR ,SYSTEMTIME *,DWORD); static VOID WINAPI callback( @@ -238,7 +242,6 @@ static VOID WINAPI callback( static void InternetReadFile_test(int flags) { BOOL res; - DWORD rc; CHAR buffer[4000]; DWORD length; DWORD out; @@ -261,7 +264,7 @@ static void InternetReadFile_test(int flags) SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED); trace("InternetConnectA <--\n"); - hic=InternetConnectA(hi, "www.winehq.org", INTERNET_INVALID_PORT_NUMBER, + hic=InternetConnectA(hi, "test.winehq.org", INTERNET_INVALID_PORT_NUMBER, NULL, NULL, INTERNET_SERVICE_HTTP, 0x0, 0xdeadbeef); ok((hic != 0x0),"InternetConnect failed with error %u\n", GetLastError()); trace("InternetConnectA -->\n"); @@ -270,11 +273,9 @@ static void InternetReadFile_test(int flags) CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED); SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED); - SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME); - SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED); trace("HttpOpenRequestA <--\n"); - hor = HttpOpenRequestA(hic, "GET", "/about/", NULL, NULL, types, + hor = HttpOpenRequestA(hic, "GET", "/testredirect", NULL, NULL, types, INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RESYNCHRONIZE, 0xdeadbead); if (hor == 0x0 && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) { @@ -294,23 +295,28 @@ static void InternetReadFile_test(int flags) length = sizeof(buffer); res = InternetQueryOptionA(hor, INTERNET_OPTION_URL, buffer, &length); ok(res, "InternetQueryOptionA(INTERNET_OPTION_URL) failed: %u\n", GetLastError()); - ok(!strcmp(buffer, "http://www.winehq.org/about/"), "Wrong URL %s\n", buffer); + ok(!strcmp(buffer, "http://test.winehq.org/testredirect"), "Wrong URL %s\n", buffer); + + length = sizeof(buffer); + res = HttpQueryInfoA(hor, HTTP_QUERY_RAW_HEADERS, buffer, &length, 0x0); + ok(res, "HttpQueryInfoA(HTTP_QUERY_RAW_HEADERS) failed with error %d\n", GetLastError()); + ok(length == 0, "HTTP_QUERY_RAW_HEADERS: expected length 0, but got %d\n", length); + ok(!strcmp(buffer, ""), "HTTP_QUERY_RAW_HEADERS: expected string \"\", but got \"%s\"\n", buffer); CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED); - todo_wine - { CHECK_NOT_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME); CHECK_NOT_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED); - } if (first_connection_to_test_url) { SET_EXPECT(INTERNET_STATUS_RESOLVING_NAME); SET_EXPECT(INTERNET_STATUS_NAME_RESOLVED); + SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME); + SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED); } else { - SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME); - SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED); + SET_WINE_ALLOW2(INTERNET_STATUS_RESOLVING_NAME,2); + SET_WINE_ALLOW2(INTERNET_STATUS_NAME_RESOLVED,2); } SET_WINE_ALLOW(INTERNET_STATUS_CONNECTING_TO_SERVER); SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER); @@ -320,7 +326,11 @@ static void InternetReadFile_test(int flags) SET_EXPECT2(INTERNET_STATUS_REQUEST_SENT, 2); SET_EXPECT2(INTERNET_STATUS_RECEIVING_RESPONSE, 2); SET_EXPECT2(INTERNET_STATUS_RESPONSE_RECEIVED, 2); + SET_OPTIONAL2(INTERNET_STATUS_CLOSING_CONNECTION, 2); + SET_OPTIONAL2(INTERNET_STATUS_CONNECTION_CLOSED, 2); SET_EXPECT(INTERNET_STATUS_REDIRECT); + SET_OPTIONAL(INTERNET_STATUS_CONNECTING_TO_SERVER); + SET_OPTIONAL(INTERNET_STATUS_CONNECTED_TO_SERVER); if (flags & INTERNET_FLAG_ASYNC) SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE); else @@ -328,12 +338,12 @@ static void InternetReadFile_test(int flags) trace("HttpSendRequestA -->\n"); SetLastError(0xdeadbeef); - rc = HttpSendRequestA(hor, "", -1, NULL, 0); + res = HttpSendRequestA(hor, "", -1, NULL, 0); if (flags & INTERNET_FLAG_ASYNC) - ok(((rc == 0)&&(GetLastError() == ERROR_IO_PENDING)), + ok(!res && (GetLastError() == ERROR_IO_PENDING), "Asynchronous HttpSendRequest NOT returning 0 with error ERROR_IO_PENDING\n"); else - ok((rc != 0) || GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED, + ok(res || (GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED), "Synchronous HttpSendRequest returning 0, error %u\n", GetLastError()); trace("HttpSendRequestA <--\n"); @@ -358,41 +368,41 @@ static void InternetReadFile_test(int flags) if (flags & INTERNET_FLAG_ASYNC) CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE); else - todo_wine CHECK_NOT_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE); + CHECK_NOT_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE); /* Sent on WinXP only if first_connection_to_test_url is TRUE, on Win98 always sent */ CLEAR_NOTIFIED(INTERNET_STATUS_CONNECTING_TO_SERVER); CLEAR_NOTIFIED(INTERNET_STATUS_CONNECTED_TO_SERVER); length = 4; - rc = InternetQueryOptionA(hor,INTERNET_OPTION_REQUEST_FLAGS,&out,&length); - trace("Option 0x17 -> %i %i\n",rc,out); + res = InternetQueryOptionA(hor,INTERNET_OPTION_REQUEST_FLAGS,&out,&length); + ok(res, "InternetQueryOptionA(INTERNET_OPTION_REQUEST) failed with error %d\n", GetLastError()); length = 100; - rc = InternetQueryOptionA(hor,INTERNET_OPTION_URL,buffer,&length); - trace("Option 0x22 -> %i %s\n",rc,buffer); + res = InternetQueryOptionA(hor,INTERNET_OPTION_URL,buffer,&length); + ok(res, "InternetQueryOptionA(INTERNET_OPTION_URL) failed with error %d\n", GetLastError()); - length = 4000; - rc = HttpQueryInfoA(hor,HTTP_QUERY_RAW_HEADERS,buffer,&length,0x0); + length = sizeof(buffer); + res = HttpQueryInfoA(hor,HTTP_QUERY_RAW_HEADERS,buffer,&length,0x0); + ok(res, "HttpQueryInfoA(HTTP_QUERY_RAW_HEADERS) failed with error %d\n", GetLastError()); buffer[length]=0; - trace("Option 0x16 -> %i %s\n",rc,buffer); length = sizeof(buffer); res = InternetQueryOptionA(hor, INTERNET_OPTION_URL, buffer, &length); ok(res, "InternetQueryOptionA(INTERNET_OPTION_URL) failed: %u\n", GetLastError()); - ok(!strcmp(buffer, "http://www.winehq.org/site/about"), "Wrong URL %s\n", buffer); + ok(!strcmp(buffer, "http://test.winehq.org/hello.html"), "Wrong URL %s\n", buffer); length = 16; - rc = HttpQueryInfoA(hor,HTTP_QUERY_CONTENT_LENGTH,&buffer,&length,0x0); - trace("Option 0x5 -> %i %s (%u)\n",rc,buffer,GetLastError()); + res = HttpQueryInfoA(hor,HTTP_QUERY_CONTENT_LENGTH,&buffer,&length,0x0); + trace("Option 0x5 -> %i %s (%u)\n",res,buffer,GetLastError()); length = 100; - rc = HttpQueryInfoA(hor,HTTP_QUERY_CONTENT_TYPE,buffer,&length,0x0); + res = HttpQueryInfoA(hor,HTTP_QUERY_CONTENT_TYPE,buffer,&length,0x0); buffer[length]=0; - trace("Option 0x1 -> %i %s\n",rc,buffer); + trace("Option 0x1 -> %i %s\n",res,buffer); SetLastError(0xdeadbeef); - rc = InternetReadFile(NULL, buffer, 100, &length); - ok(!rc, "InternetReadFile should have failed\n"); + res = InternetReadFile(NULL, buffer, 100, &length); + ok(!res, "InternetReadFile should have failed\n"); ok(GetLastError() == ERROR_INVALID_HANDLE, "InternetReadFile should have set last error to ERROR_INVALID_HANDLE instead of %u\n", GetLastError()); @@ -400,19 +410,17 @@ static void InternetReadFile_test(int flags) length = 100; trace("Entering Query loop\n"); - SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION); - SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED); while (TRUE) { if (flags & INTERNET_FLAG_ASYNC) SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE); - rc = InternetQueryDataAvailable(hor,&length,0x0,0x0); - ok(!(rc == 0 && length != 0),"InternetQueryDataAvailable failed with non-zero length\n"); - ok(rc != 0 || ((flags & INTERNET_FLAG_ASYNC) && GetLastError() == ERROR_IO_PENDING), + res = InternetQueryDataAvailable(hor,&length,0x0,0x0); + ok(!(!res && length != 0),"InternetQueryDataAvailable failed with non-zero length\n"); + ok(res || ((flags & INTERNET_FLAG_ASYNC) && GetLastError() == ERROR_IO_PENDING), "InternetQueryDataAvailable failed, error %d\n", GetLastError()); if (flags & INTERNET_FLAG_ASYNC) { - if (rc != 0) + if (res) { CHECK_NOT_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE); } @@ -428,31 +436,32 @@ static void InternetReadFile_test(int flags) char *buffer; buffer = HeapAlloc(GetProcessHeap(),0,length+1); - rc = InternetReadFile(hor,buffer,length,&length); + res = InternetReadFile(hor,buffer,length,&length); buffer[length]=0; - trace("ReadFile -> %i %i\n",rc,length); + trace("ReadFile -> %s %i\n",res?"TRUE":"FALSE",length); HeapFree(GetProcessHeap(),0,buffer); } if (length == 0) break; } - /* WinXP does not send, but Win98 does */ - CLEAR_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION); - CLEAR_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED); + CHECK_NOTIFIED2(INTERNET_STATUS_CLOSING_CONNECTION, 2); + CHECK_NOTIFIED2(INTERNET_STATUS_CONNECTION_CLOSED, 2); abort: + trace("aborting\n"); SET_EXPECT2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0)); if (hor != 0x0) { SET_WINE_ALLOW(INTERNET_STATUS_CLOSING_CONNECTION); SET_WINE_ALLOW(INTERNET_STATUS_CONNECTION_CLOSED); SetLastError(0xdeadbeef); - rc = InternetCloseHandle(hor); - ok ((rc != 0), "InternetCloseHandle of handle opened by HttpOpenRequestA failed\n"); + trace("closing\n"); + res = InternetCloseHandle(hor); + ok (res, "InternetCloseHandle of handle opened by HttpOpenRequestA failed\n"); SetLastError(0xdeadbeef); - rc = InternetCloseHandle(hor); - ok ((rc == 0), "Double close of handle opened by HttpOpenRequestA succeeded\n"); + res = InternetCloseHandle(hor); + ok (!res, "Double close of handle opened by HttpOpenRequestA succeeded\n"); ok (GetLastError() == ERROR_INVALID_HANDLE, "Double close of handle should have set ERROR_INVALID_HANDLE instead of %u\n", GetLastError()); @@ -463,8 +472,9 @@ abort: * INTERNET_STATUS_HANDLE_CLOSING notifications matches the number expected. */ if (hi != 0x0) { SET_WINE_ALLOW(INTERNET_STATUS_HANDLE_CLOSING); - rc = InternetCloseHandle(hi); - ok ((rc != 0), "InternetCloseHandle of handle opened by InternetOpenA failed\n"); + trace("closing 2\n"); + res = InternetCloseHandle(hi); + ok (res, "InternetCloseHandle of handle opened by InternetOpenA failed\n"); if (flags & INTERNET_FLAG_ASYNC) Sleep(100); } @@ -507,7 +517,7 @@ static void InternetReadFileExA_test(int flags) SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED); trace("InternetConnectA <--\n"); - hic=InternetConnectA(hi, "www.winehq.org", INTERNET_INVALID_PORT_NUMBER, + hic=InternetConnectA(hi, "test.winehq.org", INTERNET_INVALID_PORT_NUMBER, NULL, NULL, INTERNET_SERVICE_HTTP, 0x0, 0xdeadbeef); ok((hic != 0x0),"InternetConnect failed with error %u\n", GetLastError()); trace("InternetConnectA -->\n"); @@ -516,11 +526,9 @@ static void InternetReadFileExA_test(int flags) CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED); SET_EXPECT(INTERNET_STATUS_HANDLE_CREATED); - SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME); - SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED); trace("HttpOpenRequestA <--\n"); - hor = HttpOpenRequestA(hic, "GET", "/about/", NULL, NULL, types, + hor = HttpOpenRequestA(hic, "GET", "/testredirect", NULL, NULL, types, INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RESYNCHRONIZE, 0xdeadbead); if (hor == 0x0 && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) { @@ -538,20 +546,19 @@ static void InternetReadFileExA_test(int flags) if (hor == 0x0) goto abort; CHECK_NOTIFIED(INTERNET_STATUS_HANDLE_CREATED); - todo_wine - { CHECK_NOT_NOTIFIED(INTERNET_STATUS_RESOLVING_NAME); CHECK_NOT_NOTIFIED(INTERNET_STATUS_NAME_RESOLVED); - } if (first_connection_to_test_url) { SET_EXPECT(INTERNET_STATUS_RESOLVING_NAME); SET_EXPECT(INTERNET_STATUS_NAME_RESOLVED); + SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME); + SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED); } else { - SET_WINE_ALLOW(INTERNET_STATUS_RESOLVING_NAME); - SET_WINE_ALLOW(INTERNET_STATUS_NAME_RESOLVED); + SET_WINE_ALLOW2(INTERNET_STATUS_RESOLVING_NAME,2); + SET_WINE_ALLOW2(INTERNET_STATUS_NAME_RESOLVED,2); } SET_WINE_ALLOW(INTERNET_STATUS_CONNECTING_TO_SERVER); SET_EXPECT(INTERNET_STATUS_CONNECTING_TO_SERVER); @@ -561,7 +568,11 @@ static void InternetReadFileExA_test(int flags) SET_EXPECT2(INTERNET_STATUS_REQUEST_SENT, 2); SET_EXPECT2(INTERNET_STATUS_RECEIVING_RESPONSE, 2); SET_EXPECT2(INTERNET_STATUS_RESPONSE_RECEIVED, 2); + SET_OPTIONAL2(INTERNET_STATUS_CLOSING_CONNECTION, 2); + SET_OPTIONAL2(INTERNET_STATUS_CONNECTION_CLOSED, 2); SET_EXPECT(INTERNET_STATUS_REDIRECT); + SET_OPTIONAL(INTERNET_STATUS_CONNECTING_TO_SERVER); + SET_OPTIONAL(INTERNET_STATUS_CONNECTED_TO_SERVER); if (flags & INTERNET_FLAG_ASYNC) SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE); else @@ -595,6 +606,8 @@ static void InternetReadFileExA_test(int flags) CHECK_NOTIFIED2(INTERNET_STATUS_REQUEST_SENT, 2); CHECK_NOTIFIED2(INTERNET_STATUS_RECEIVING_RESPONSE, 2); CHECK_NOTIFIED2(INTERNET_STATUS_RESPONSE_RECEIVED, 2); + CHECK_NOTIFIED2(INTERNET_STATUS_CLOSING_CONNECTION, 2); + CHECK_NOTIFIED2(INTERNET_STATUS_CONNECTION_CLOSED, 2); CHECK_NOTIFIED(INTERNET_STATUS_REDIRECT); if (flags & INTERNET_FLAG_ASYNC) CHECK_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE); @@ -626,10 +639,13 @@ static void InternetReadFileExA_test(int flags) inetbuffers.lpvBuffer = NULL; inetbuffers.dwOffsetHigh = 1234; inetbuffers.dwOffsetLow = 5678; - SET_WINE_ALLOW(INTERNET_STATUS_RECEIVING_RESPONSE); - SET_WINE_ALLOW(INTERNET_STATUS_RESPONSE_RECEIVED); + SET_EXPECT(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_EXPECT(INTERNET_STATUS_RESPONSE_RECEIVED); + SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION); + SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED); rc = InternetReadFileEx(hor, &inetbuffers, 0, 0xdeadcafe); ok(rc, "InternetReadFileEx failed with error %u\n", GetLastError()); + trace("read %i bytes\n", inetbuffers.dwBufferLength); todo_wine { CHECK_NOT_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE); @@ -654,9 +670,11 @@ static void InternetReadFileExA_test(int flags) inetbuffers.dwOffsetHigh = 1234; inetbuffers.dwOffsetLow = 5678; - SET_EXPECT(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_WINE_ALLOW(INTERNET_STATUS_RECEIVING_RESPONSE); + SET_WINE_ALLOW(INTERNET_STATUS_RESPONSE_RECEIVED); + SET_EXPECT(INTERNET_STATUS_CLOSING_CONNECTION); + SET_EXPECT(INTERNET_STATUS_CONNECTION_CLOSED); SET_EXPECT(INTERNET_STATUS_REQUEST_COMPLETE); - SET_EXPECT(INTERNET_STATUS_RESPONSE_RECEIVED); rc = InternetReadFileExA(hor, &inetbuffers, IRF_ASYNC | IRF_USE_CONTEXT, 0xcafebabe); if (!rc) { @@ -682,8 +700,10 @@ static void InternetReadFileExA_test(int flags) CHECK_NOT_NOTIFIED(INTERNET_STATUS_REQUEST_COMPLETE); if (inetbuffers.dwBufferLength) { - CHECK_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE); - CHECK_NOTIFIED(INTERNET_STATUS_RESPONSE_RECEIVED); + todo_wine { + CHECK_NOT_NOTIFIED(INTERNET_STATUS_RECEIVING_RESPONSE); + CHECK_NOT_NOTIFIED(INTERNET_STATUS_RESPONSE_RECEIVED); + } } else { @@ -735,16 +755,12 @@ abort: Sleep(100); CHECK_NOTIFIED2(INTERNET_STATUS_HANDLE_CLOSING, (hor != 0x0) + (hic != 0x0)); } - if (hor != 0x0) todo_wine - { + /* to enable once Wine is fixed to never send it CHECK_NOT_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION); CHECK_NOT_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED); - } - else - { - CHECK_NOT_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION); - CHECK_NOT_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED); - } + */ + CLEAR_NOTIFIED(INTERNET_STATUS_CLOSING_CONNECTION); + CLEAR_NOTIFIED(INTERNET_STATUS_CONNECTION_CLOSED); CloseHandle(hCompleteEvent); first_connection_to_test_url = FALSE; } @@ -779,91 +795,6 @@ static void InternetOpenUrlA_test(void) InternetCloseHandle(myhinternet); } -static void InternetTimeFromSystemTimeA_test(void) -{ - BOOL ret; - static const SYSTEMTIME time = { 2005, 1, 5, 7, 12, 6, 35, 0 }; - char string[INTERNET_RFC1123_BUFSIZE]; - static const char expect[] = "Fri, 07 Jan 2005 12:06:35 GMT"; - - ret = pInternetTimeFromSystemTimeA( &time, INTERNET_RFC1123_FORMAT, string, sizeof(string) ); - ok( ret, "InternetTimeFromSystemTimeA failed (%u)\n", GetLastError() ); - - ok( !memcmp( string, expect, sizeof(expect) ), - "InternetTimeFromSystemTimeA failed (%u)\n", GetLastError() ); -} - -static void InternetTimeFromSystemTimeW_test(void) -{ - BOOL ret; - static const SYSTEMTIME time = { 2005, 1, 5, 7, 12, 6, 35, 0 }; - WCHAR string[INTERNET_RFC1123_BUFSIZE + 1]; - static const WCHAR expect[] = { 'F','r','i',',',' ','0','7',' ','J','a','n',' ','2','0','0','5',' ', - '1','2',':','0','6',':','3','5',' ','G','M','T',0 }; - - ret = pInternetTimeFromSystemTimeW( &time, INTERNET_RFC1123_FORMAT, string, sizeof(string) ); - ok( ret, "InternetTimeFromSystemTimeW failed (%u)\n", GetLastError() ); - - ok( !memcmp( string, expect, sizeof(expect) ), - "InternetTimeFromSystemTimeW failed (%u)\n", GetLastError() ); -} - -static void InternetTimeToSystemTimeA_test(void) -{ - BOOL ret; - SYSTEMTIME time; - static const SYSTEMTIME expect = { 2005, 1, 5, 7, 12, 6, 35, 0 }; - static const char string[] = "Fri, 07 Jan 2005 12:06:35 GMT"; - static const char string2[] = " fri 7 jan 2005 12 06 35"; - - ret = pInternetTimeToSystemTimeA( string, &time, 0 ); - ok( ret, "InternetTimeToSystemTimeA failed (%u)\n", GetLastError() ); - ok( !memcmp( &time, &expect, sizeof(expect) ), - "InternetTimeToSystemTimeA failed (%u)\n", GetLastError() ); - - ret = pInternetTimeToSystemTimeA( string2, &time, 0 ); - ok( ret, "InternetTimeToSystemTimeA failed (%u)\n", GetLastError() ); - ok( !memcmp( &time, &expect, sizeof(expect) ), - "InternetTimeToSystemTimeA failed (%u)\n", GetLastError() ); -} - -static void InternetTimeToSystemTimeW_test(void) -{ - BOOL ret; - SYSTEMTIME time; - static const SYSTEMTIME expect = { 2005, 1, 5, 7, 12, 6, 35, 0 }; - static const WCHAR string[] = { 'F','r','i',',',' ','0','7',' ','J','a','n',' ','2','0','0','5',' ', - '1','2',':','0','6',':','3','5',' ','G','M','T',0 }; - static const WCHAR string2[] = { ' ','f','r','i',' ','7',' ','j','a','n',' ','2','0','0','5',' ', - '1','2',' ','0','6',' ','3','5',0 }; - static const WCHAR string3[] = { 'F','r',0 }; - - ret = pInternetTimeToSystemTimeW( NULL, NULL, 0 ); - ok( !ret, "InternetTimeToSystemTimeW succeeded (%u)\n", GetLastError() ); - - ret = pInternetTimeToSystemTimeW( NULL, &time, 0 ); - ok( !ret, "InternetTimeToSystemTimeW succeeded (%u)\n", GetLastError() ); - - ret = pInternetTimeToSystemTimeW( string, NULL, 0 ); - ok( !ret, "InternetTimeToSystemTimeW succeeded (%u)\n", GetLastError() ); - - ret = pInternetTimeToSystemTimeW( string, &time, 0 ); - ok( ret, "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); - - ret = pInternetTimeToSystemTimeW( string, &time, 0 ); - ok( ret, "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); - ok( !memcmp( &time, &expect, sizeof(expect) ), - "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); - - ret = pInternetTimeToSystemTimeW( string2, &time, 0 ); - ok( ret, "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); - ok( !memcmp( &time, &expect, sizeof(expect) ), - "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); - - ret = pInternetTimeToSystemTimeW( string3, &time, 0 ); - ok( ret, "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); -} - static void HttpSendRequestEx_test(void) { HINTERNET hSession; @@ -891,7 +822,7 @@ static void HttpSendRequestEx_test(void) NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); if (!hRequest && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) { - trace( "Network unreachable, skipping test\n" ); + skip( "Network unreachable, skipping test\n" ); goto done; } ok( hRequest != NULL, "Failed to open request handle err %u\n", GetLastError()); @@ -951,14 +882,14 @@ static void InternetOpenRequest_test(void) ok(connect == NULL, "InternetConnectA should have failed\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "InternetConnectA with blank server named should have failed with ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); - connect = InternetConnectA(session, "winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, + connect = InternetConnectA(session, "test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); - ok(connect != NULL, "Unable to connect to http://winehq.org with error %d\n", GetLastError()); + ok(connect != NULL, "Unable to connect to http://test.winehq.org with error %d\n", GetLastError()); request = HttpOpenRequestA(connect, NULL, "/", NULL, NULL, types, INTERNET_FLAG_NO_CACHE_WRITE, 0); if (!request && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) { - trace( "Network unreachable, skipping test\n" ); + skip( "Network unreachable, skipping test\n" ); goto done; } ok(request != NULL, "Failed to open request handle err %u\n", GetLastError()); @@ -993,14 +924,14 @@ static void test_http_cache(void) session = InternetOpenA("Wine Regression Test", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); ok(session != NULL ,"Unable to open Internet session\n"); - connect = InternetConnectA(session, "www.winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, + connect = InternetConnectA(session, "test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); - ok(connect != NULL, "Unable to connect to http://winehq.org with error %d\n", GetLastError()); + ok(connect != NULL, "Unable to connect to http://test.winehq.org with error %d\n", GetLastError()); - request = HttpOpenRequestA(connect, NULL, "/site/about", NULL, NULL, types, INTERNET_FLAG_NEED_FILE, 0); + request = HttpOpenRequestA(connect, NULL, "/hello.html", NULL, NULL, types, INTERNET_FLAG_NEED_FILE, 0); if (!request && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) { - trace( "Network unreachable, skipping test\n" ); + skip( "Network unreachable, skipping test\n" ); ok(InternetCloseHandle(connect), "Close connect handle failed\n"); ok(InternetCloseHandle(session), "Close session handle failed\n"); @@ -1012,7 +943,7 @@ static void test_http_cache(void) size = sizeof(url); ret = InternetQueryOptionA(request, INTERNET_OPTION_URL, url, &size); ok(ret, "InternetQueryOptionA(INTERNET_OPTION_url) failed: %u\n", GetLastError()); - ok(!strcmp(url, "http://www.winehq.org/site/about"), "Wrong URL %s\n", url); + ok(!strcmp(url, "http://test.winehq.org/hello.html"), "Wrong URL %s\n", url); size = sizeof(file_name); ret = InternetQueryOptionA(request, INTERNET_OPTION_DATAFILE_NAME, file_name, &size); @@ -1031,26 +962,28 @@ static void test_http_cache(void) FILE_ATTRIBUTE_NORMAL, NULL); ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError()); file_size = GetFileSize(file, NULL); - ok(file_size == 0, "file size=%d\n", file_size); + todo_wine ok(file_size == 106, "file size = %u\n", file_size); + size = sizeof(buf); ret = InternetReadFile(request, buf, sizeof(buf), &size); ok(ret, "InternetReadFile failed: %u\n", GetLastError()); - ok(size == sizeof(buf), "size=%d\n", size); + ok(size == 100, "size = %u\n", size); file_size = GetFileSize(file, NULL); - ok(file_size == sizeof(buf), "file size=%d\n", file_size); + todo_wine ok(file_size == 106, "file size = %u\n", file_size); CloseHandle(file); ok(InternetCloseHandle(request), "Close request handle failed\n"); file = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file == INVALID_HANDLE_VALUE, "CreateFile succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError()=%u, expected ERROR_FILE_NOT_FOUND\n", GetLastError()); + todo_wine ok(file != INVALID_HANDLE_VALUE, "CreateFile succeeded\n"); + CloseHandle(file); request = HttpOpenRequestA(connect, NULL, "/", NULL, NULL, types, INTERNET_FLAG_NO_CACHE_WRITE, 0); ok(request != NULL, "Failed to open request handle err %u\n", GetLastError()); + size = sizeof(file_name); ret = InternetQueryOptionA(request, INTERNET_OPTION_DATAFILE_NAME, file_name, &size); ok(!ret, "InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) succeeded\n"); ok(GetLastError() == ERROR_INTERNET_ITEM_NOT_FOUND, "GetLastError()=%u\n", GetLastError()); @@ -1061,17 +994,14 @@ static void test_http_cache(void) size = sizeof(file_name); ret = InternetQueryOptionA(request, INTERNET_OPTION_DATAFILE_NAME, file_name, &size); - ok(!ret, "InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) succeeded\n"); - ok(GetLastError() == ERROR_INTERNET_ITEM_NOT_FOUND, "GetLastError()=%u\n", GetLastError()); - ok(!size, "size = %d\n", size); + todo_wine ok(ret, "InternetQueryOptionA(INTERNET_OPTION_DATAFILE_NAME) failed %u\n", GetLastError()); file = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file == INVALID_HANDLE_VALUE, "CreateFile succeeded\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError()=%u, expected ERROR_FILE_NOT_FOUND\n", GetLastError()); + todo_wine ok(file != INVALID_HANDLE_VALUE, "CreateFile succeeded\n"); + CloseHandle(file); ok(InternetCloseHandle(request), "Close request handle failed\n"); - ok(InternetCloseHandle(connect), "Close connect handle failed\n"); ok(InternetCloseHandle(session), "Close session handle failed\n"); } @@ -1082,7 +1012,9 @@ static void HttpHeaders_test(void) HINTERNET hConnect; HINTERNET hRequest; CHAR buffer[256]; + WCHAR wbuffer[256]; DWORD len = 256; + DWORD oldlen; DWORD index = 0; hSession = InternetOpen("Wine Regression Test", @@ -1096,7 +1028,7 @@ static void HttpHeaders_test(void) NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); if (!hRequest && GetLastError() == ERROR_INTERNET_NAME_NOT_RESOLVED) { - trace( "Network unreachable, skipping test\n" ); + skip( "Network unreachable, skipping test\n" ); goto done; } ok( hRequest != NULL, "Failed to open request handle\n"); @@ -1160,19 +1092,57 @@ static void HttpHeaders_test(void) ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected last error: %d\n", GetLastError()); ok(len > 40, "Invalid length (exp. more than 40, got %d)\n", len); ok(index == 0, "Index was incremented\n"); + oldlen = len; /* bytes; at least long enough to hold buffer & nul */ /* a working query */ index = 0; len = sizeof(buffer); + memset(buffer, 'x', sizeof(buffer)); ok(HttpQueryInfo(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF|HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer,&len,&index),"Unable to query header\n"); + ok(len + sizeof(CHAR) <= oldlen, "Result longer than advertised\n"); + ok((len < sizeof(buffer)-sizeof(CHAR)) && (buffer[len/sizeof(CHAR)] == 0),"No NUL at end\n"); + ok(len == strlen(buffer) * sizeof(CHAR), "Length wrong\n"); /* what's in the middle differs between Wine and Windows so currently we check only the beginning and the end */ ok(strncmp(buffer, "POST /posttest.php HTTP/1", 25)==0, "Invalid beginning of headers string\n"); ok(strcmp(buffer + strlen(buffer) - 4, "\r\n\r\n")==0, "Invalid end of headers string\n"); ok(index == 0, "Index was incremented\n"); + /* Like above two tests, but for W version */ + index = 0; + len = 0; + SetLastError(0xdeadbeef); + ok(HttpQueryInfoW(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF|HTTP_QUERY_FLAG_REQUEST_HEADERS, + NULL,&len,&index) == FALSE,"Query worked\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected last error: %d\n", GetLastError()); + ok(len > 80, "Invalid length (exp. more than 80, got %d)\n", len); + ok(index == 0, "Index was incremented\n"); + oldlen = len; /* bytes; at least long enough to hold buffer & nul */ + + /* a working query */ + index = 0; + len = sizeof(wbuffer); + memset(wbuffer, 'x', sizeof(wbuffer)); + ok(HttpQueryInfoW(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF|HTTP_QUERY_FLAG_REQUEST_HEADERS, + wbuffer,&len,&index),"Unable to query header\n"); + ok(len + sizeof(WCHAR) <= oldlen, "Result longer than advertised\n"); + ok(len == lstrlenW(wbuffer) * sizeof(WCHAR), "Length wrong\n"); + ok((len < sizeof(wbuffer)-sizeof(WCHAR)) && (wbuffer[len/sizeof(WCHAR)] == 0),"No NUL at end\n"); + ok(index == 0, "Index was incremented\n"); + + /* end of W version tests */ + + /* Without HTTP_QUERY_FLAG_REQUEST_HEADERS */ + index = 0; + len = sizeof(buffer); + memset(buffer, 'x', sizeof(buffer)); + ok(HttpQueryInfo(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF, + buffer,&len,&index) == TRUE,"Query failed\n"); + ok(len == 2, "Expected 2, got %d\n", len); + ok(strcmp(buffer, "\r\n") == 0, "Expected CRLF, got '%s'\n", buffer); + ok(index == 0, "Index was incremented\n"); ok(HttpAddRequestHeaders(hRequest,"Warning:test2",-1,HTTP_ADDREQ_FLAG_ADD), "Failed to add duplicate header using HTTP_ADDREQ_FLAG_ADD\n"); @@ -1304,7 +1274,16 @@ static void HttpHeaders_test(void) strcpy(buffer,"Warning"); ok(HttpQueryInfo(hRequest,HTTP_QUERY_CUSTOM|HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer,&len,&index)==0,"Third Header Should Not Exist\n"); + /* Ensure that blank headers are ignored and don't cause a failure */ + ok(HttpAddRequestHeaders(hRequest,"\r\nBlankTest:value\r\n\r\n",-1, HTTP_ADDREQ_FLAG_ADD_IF_NEW), "Failed to add header with blank entries in list\n"); + index = 0; + len = sizeof(buffer); + strcpy(buffer,"BlankTest"); + ok(HttpQueryInfo(hRequest,HTTP_QUERY_CUSTOM|HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer,&len,&index),"Unable to query header\n"); + ok(index == 1, "Index was not incremented\n"); + ok(strcmp(buffer,"value")==0, "incorrect string was returned(%s)\n",buffer); + ok(InternetCloseHandle(hRequest), "Close request handle failed\n"); done: ok(InternetCloseHandle(hConnect), "Close connect handle failed\n"); @@ -1319,6 +1298,15 @@ static const char okmsg[] = "Server: winetest\r\n" "\r\n"; +static const char okmsg2[] = +"HTTP/1.1 200 OK\r\n" +"Date: Mon, 01 Dec 2008 13:44:34 GMT\r\n" +"Server: winetest\r\n" +"Content-Length: 0\r\n" +"Set-Cookie: one\r\n" +"Set-Cookie: two\r\n" +"\r\n"; + static const char notokmsg[] = "HTTP/1.1 400 Bad Request\r\n" "Server: winetest\r\n" @@ -1327,8 +1315,16 @@ static const char notokmsg[] = static const char noauthmsg[] = "HTTP/1.1 401 Unauthorized\r\n" "Server: winetest\r\n" +"Connection: close\r\n" +"WWW-Authenticate: Basic realm=\"placebo\"\r\n" "\r\n"; +static const char noauthmsg2[] = +"HTTP/1.0 401 Anonymous requests or requests on unsecure channel are not allowed\r\n" +"HTTP/1.0 401 Anonymous requests or requests on unsecure channel are not allowed" +"\0d`0|6\n" +"Server: winetest\r\n"; + static const char proxymsg[] = "HTTP/1.1 407 Proxy Authentication Required\r\n" "Server: winetest\r\n" @@ -1356,6 +1352,8 @@ static DWORD CALLBACK server_thread(LPVOID param) char buffer[0x100]; WSADATA wsaData; int last_request = 0; + char host_header[22]; + static int test_b = 0; WSAStartup(MAKEWORD(1,1), &wsaData); @@ -1379,6 +1377,8 @@ static DWORD CALLBACK server_thread(LPVOID param) SetEvent(si->hEvent); + sprintf(host_header, "Host: localhost:%d", si->port); + do { c = accept(s, NULL, NULL); @@ -1394,7 +1394,6 @@ static DWORD CALLBACK server_thread(LPVOID param) buffer[i-3] == '\r' && buffer[i-1] == '\r') break; } - if (strstr(buffer, "GET /test1")) { if (!strstr(buffer, "Content-Length: 0")) @@ -1405,7 +1404,6 @@ static DWORD CALLBACK server_thread(LPVOID param) else send(c, notokmsg, sizeof notokmsg-1, 0); } - if (strstr(buffer, "/test2")) { if (strstr(buffer, "Proxy-Authorization: Basic bWlrZToxMTAx")) @@ -1416,7 +1414,6 @@ static DWORD CALLBACK server_thread(LPVOID param) else send(c, proxymsg, sizeof proxymsg-1, 0); } - if (strstr(buffer, "/test3")) { if (strstr(buffer, "Authorization: Basic dXNlcjpwd2Q=")) @@ -1424,7 +1421,6 @@ static DWORD CALLBACK server_thread(LPVOID param) else send(c, noauthmsg, sizeof noauthmsg-1, 0); } - if (strstr(buffer, "/test4")) { if (strstr(buffer, "Connection: Close")) @@ -1432,8 +1428,9 @@ static DWORD CALLBACK server_thread(LPVOID param) else send(c, notokmsg, sizeof notokmsg-1, 0); } - - if (strstr(buffer, "POST /test5")) + if (strstr(buffer, "POST /test5") || + strstr(buffer, "RPC_IN_DATA /test5") || + strstr(buffer, "RPC_OUT_DATA /test5")) { if (strstr(buffer, "Content-Length: 0")) { @@ -1443,7 +1440,6 @@ static DWORD CALLBACK server_thread(LPVOID param) else send(c, notokmsg, sizeof notokmsg-1, 0); } - if (strstr(buffer, "GET /test6")) { send(c, contmsg, sizeof contmsg-1, 0); @@ -1451,7 +1447,71 @@ static DWORD CALLBACK server_thread(LPVOID param) send(c, okmsg, sizeof okmsg-1, 0); send(c, page1, sizeof page1-1, 0); } - + if (strstr(buffer, "POST /test7")) + { + if (strstr(buffer, "Content-Length: 100")) + { + send(c, okmsg, sizeof okmsg-1, 0); + send(c, page1, sizeof page1-1, 0); + } + else + send(c, notokmsg, sizeof notokmsg-1, 0); + } + if (strstr(buffer, "/test8")) + { + if (!strstr(buffer, "Connection: Close") && + strstr(buffer, "Connection: Keep-Alive") && + !strstr(buffer, "Cache-Control: no-cache") && + !strstr(buffer, "Pragma: no-cache") && + strstr(buffer, host_header)) + send(c, okmsg, sizeof okmsg-1, 0); + else + send(c, notokmsg, sizeof notokmsg-1, 0); + } + if (strstr(buffer, "/test9")) + { + if (!strstr(buffer, "Connection: Close") && + !strstr(buffer, "Connection: Keep-Alive") && + !strstr(buffer, "Cache-Control: no-cache") && + !strstr(buffer, "Pragma: no-cache") && + strstr(buffer, host_header)) + send(c, okmsg, sizeof okmsg-1, 0); + else + send(c, notokmsg, sizeof notokmsg-1, 0); + } + if (strstr(buffer, "/testA")) + { + if (!strstr(buffer, "Connection: Close") && + !strstr(buffer, "Connection: Keep-Alive") && + (strstr(buffer, "Cache-Control: no-cache") || + strstr(buffer, "Pragma: no-cache")) && + strstr(buffer, host_header)) + send(c, okmsg, sizeof okmsg-1, 0); + else + send(c, notokmsg, sizeof notokmsg-1, 0); + } + if (!test_b && strstr(buffer, "/testB HTTP/1.1")) + { + test_b = 1; + send(c, okmsg, sizeof okmsg-1, 0); + recvfrom(c, buffer, sizeof buffer, 0, NULL, NULL); + send(c, okmsg, sizeof okmsg-1, 0); + } + if (strstr(buffer, "/testC")) + { + if (strstr(buffer, "Cookie: cookie=biscuit")) + send(c, okmsg, sizeof okmsg-1, 0); + else + send(c, notokmsg, sizeof notokmsg-1, 0); + } + if (strstr(buffer, "/testD")) + { + send(c, okmsg2, sizeof okmsg2-1, 0); + } + if (strstr(buffer, "/testE")) + { + send(c, noauthmsg2, sizeof noauthmsg2-1, 0); + } if (strstr(buffer, "GET /quit")) { send(c, okmsg, sizeof okmsg-1, 0); @@ -1569,7 +1629,7 @@ static void test_proxy_direct(int port) ok(hi != NULL, "open failed\n"); /* try connect without authorization */ - hc = InternetConnect(hi, "www.winehq.org/", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + hc = InternetConnect(hi, "test.winehq.org/", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); ok(hc != NULL, "connect failed\n"); hr = HttpOpenRequest(hc, NULL, "/test2", NULL, NULL, NULL, 0, 0); @@ -1627,7 +1687,7 @@ static void test_header_handling_order(int port) request = HttpOpenRequest(connect, NULL, "/test3", NULL, NULL, types, INTERNET_FLAG_KEEP_CONNECTION, 0); ok(request != NULL, "HttpOpenRequest failed\n"); - ret = HttpAddRequestHeaders(request, authorization, ~0UL, HTTP_ADDREQ_FLAG_ADD); + ret = HttpAddRequestHeaders(request, authorization, ~0u, HTTP_ADDREQ_FLAG_ADD); ok(ret, "HttpAddRequestHeaders failed\n"); ret = HttpSendRequest(request, NULL, 0, NULL, 0); @@ -1644,9 +1704,243 @@ static void test_header_handling_order(int port) request = HttpOpenRequest(connect, NULL, "/test4", NULL, NULL, types, INTERNET_FLAG_KEEP_CONNECTION, 0); ok(request != NULL, "HttpOpenRequest failed\n"); - ret = HttpSendRequest(request, connection, ~0UL, NULL, 0); + ret = HttpSendRequest(request, connection, ~0u, NULL, 0); ok(ret, "HttpSendRequest failed\n"); + status = 0; + size = sizeof(status); + ret = HttpQueryInfo( request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL ); + ok(ret, "HttpQueryInfo failed\n"); + ok(status == 200 || status == 400 /* IE6 */, "got status %u, expected 200 or 400\n", status); + + InternetCloseHandle(request); + + request = HttpOpenRequest(connect, "POST", "/test7", NULL, NULL, types, INTERNET_FLAG_KEEP_CONNECTION, 0); + ok(request != NULL, "HttpOpenRequest failed\n"); + + ret = HttpAddRequestHeaders(request, "Content-Length: 100\r\n", ~0u, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + ok(ret, "HttpAddRequestHeaders failed\n"); + + ret = HttpSendRequest(request, connection, ~0u, NULL, 0); + ok(ret, "HttpSendRequest failed\n"); + + status = 0; + size = sizeof(status); + ret = HttpQueryInfo( request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL ); + ok(ret, "HttpQueryInfo failed\n"); + ok(status == 200 || status == 400 /* IE6 */, "got status %u, expected 200 or 400\n", status); + + InternetCloseHandle(request); + InternetCloseHandle(connect); + InternetCloseHandle(session); +} + +static void test_connection_header(int port) +{ + HINTERNET ses, con, req; + DWORD size, status; + BOOL ret; + + ses = InternetOpen("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(ses != NULL, "InternetOpen failed\n"); + + con = InternetConnect(ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(con != NULL, "InternetConnect failed\n"); + + req = HttpOpenRequest(con, NULL, "/test8", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(req, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed\n"); + + status = 0; + size = sizeof(status); + ret = HttpQueryInfo(req, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL); + ok(ret, "HttpQueryInfo failed\n"); + ok(status == 200, "request failed with status %u\n", status); + + InternetCloseHandle(req); + + req = HttpOpenRequest(con, NULL, "/test9", NULL, NULL, NULL, 0, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(req, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed\n"); + + status = 0; + size = sizeof(status); + ret = HttpQueryInfo(req, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL); + ok(ret, "HttpQueryInfo failed\n"); + ok(status == 200, "request failed with status %u\n", status); + + InternetCloseHandle(req); + + req = HttpOpenRequest(con, NULL, "/test9", NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(req, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed\n"); + + status = 0; + size = sizeof(status); + ret = HttpQueryInfo(req, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL); + ok(ret, "HttpQueryInfo failed\n"); + ok(status == 200, "request failed with status %u\n", status); + + InternetCloseHandle(req); + + req = HttpOpenRequest(con, "POST", "/testA", NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(req, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed\n"); + + status = 0; + size = sizeof(status); + ret = HttpQueryInfo(req, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL); + ok(ret, "HttpQueryInfo failed\n"); + ok(status == 200, "request failed with status %u\n", status); + + InternetCloseHandle(req); + InternetCloseHandle(con); + InternetCloseHandle(ses); +} + +static void test_http1_1(int port) +{ + HINTERNET ses, con, req; + BOOL ret; + + ses = InternetOpen("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(ses != NULL, "InternetOpen failed\n"); + + con = InternetConnect(ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(con != NULL, "InternetConnect failed\n"); + + req = HttpOpenRequest(con, NULL, "/testB", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(req, NULL, 0, NULL, 0); + if (ret) + { + InternetCloseHandle(req); + + req = HttpOpenRequest(con, NULL, "/testB", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(req, NULL, 0, NULL, 0); + todo_wine + ok(ret, "HttpSendRequest failed\n"); + } + + InternetCloseHandle(req); + InternetCloseHandle(con); + InternetCloseHandle(ses); +} + +static void test_HttpSendRequestW(int port) +{ + static const WCHAR header[] = {'U','A','-','C','P','U',':',' ','x','8','6',0}; + HINTERNET ses, con, req; + DWORD error; + BOOL ret; + + ses = InternetOpen("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, INTERNET_FLAG_ASYNC); + ok(ses != NULL, "InternetOpen failed\n"); + + con = InternetConnect(ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(con != NULL, "InternetConnect failed\n"); + + req = HttpOpenRequest(con, NULL, "/test1", NULL, NULL, NULL, 0, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + SetLastError(0xdeadbeef); + ret = HttpSendRequestW(req, header, ~0u, NULL, 0); + error = GetLastError(); + ok(!ret, "HttpSendRequestW succeeded\n"); + ok(error == ERROR_IO_PENDING || + broken(error == ERROR_HTTP_HEADER_NOT_FOUND) || /* IE6 */ + broken(error == ERROR_INVALID_PARAMETER), /* IE5 */ + "got %u expected ERROR_IO_PENDING\n", error); + + InternetCloseHandle(req); + InternetCloseHandle(con); + InternetCloseHandle(ses); +} + +static void test_cookie_header(int port) +{ + HINTERNET ses, con, req; + DWORD size, status, error; + BOOL ret; + char buffer[64]; + + ses = InternetOpen("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(ses != NULL, "InternetOpen failed\n"); + + con = InternetConnect(ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(con != NULL, "InternetConnect failed\n"); + + InternetSetCookie("http://localhost", "cookie", "biscuit"); + + req = HttpOpenRequest(con, NULL, "/testC", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); + ok(req != NULL, "HttpOpenRequest failed\n"); + + buffer[0] = 0; + size = sizeof(buffer); + SetLastError(0xdeadbeef); + ret = HttpQueryInfo(req, HTTP_QUERY_COOKIE | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); + error = GetLastError(); + ok(!ret, "HttpQueryInfo succeeded\n"); + ok(error == ERROR_HTTP_HEADER_NOT_FOUND, "got %u expected ERROR_HTTP_HEADER_NOT_FOUND\n", error); + + ret = HttpAddRequestHeaders(req, "Cookie: cookie=not biscuit\r\n", ~0u, HTTP_ADDREQ_FLAG_ADD); + ok(ret, "HttpAddRequestHeaders failed: %u\n", GetLastError()); + + buffer[0] = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(req, HTTP_QUERY_COOKIE | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); + ok(ret, "HttpQueryInfo failed: %u\n", GetLastError()); + ok(!strcmp(buffer, "cookie=not biscuit"), "got '%s' expected \'cookie=not biscuit\'\n", buffer); + + ret = HttpSendRequest(req, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed: %u\n", GetLastError()); + + status = 0; + size = sizeof(status); + ret = HttpQueryInfo(req, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL); + ok(ret, "HttpQueryInfo failed\n"); + ok(status == 200, "request failed with status %u\n", status); + + buffer[0] = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(req, HTTP_QUERY_COOKIE | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); + ok(ret, "HttpQueryInfo failed: %u\n", GetLastError()); + ok(!strcmp(buffer, "cookie=biscuit"), "got '%s' expected \'cookie=biscuit\'\n", buffer); + + InternetCloseHandle(req); + InternetCloseHandle(con); + InternetCloseHandle(ses); +} + +static void test_basic_authentication(int port) +{ + HINTERNET session, connect, request; + DWORD size, status; + BOOL ret; + + session = InternetOpen("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(session != NULL, "InternetOpen failed\n"); + + connect = InternetConnect(session, "localhost", port, "user", "pwd", INTERNET_SERVICE_HTTP, 0, 0); + ok(connect != NULL, "InternetConnect failed\n"); + + request = HttpOpenRequest(connect, NULL, "/test3", NULL, NULL, NULL, 0, 0); + ok(request != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(request, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed %u\n", GetLastError()); + status = 0; size = sizeof(status); ret = HttpQueryInfo( request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL ); @@ -1658,6 +1952,153 @@ static void test_header_handling_order(int port) InternetCloseHandle(session); } +static void test_invalid_response_headers(int port) +{ + HINTERNET session, connect, request; + DWORD size, status; + BOOL ret; + char buffer[256]; + + session = InternetOpen("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(session != NULL, "InternetOpen failed\n"); + + connect = InternetConnect(session, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(connect != NULL, "InternetConnect failed\n"); + + request = HttpOpenRequest(connect, NULL, "/testE", NULL, NULL, NULL, 0, 0); + ok(request != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(request, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed %u\n", GetLastError()); + + status = 0; + size = sizeof(status); + ret = HttpQueryInfo( request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL ); + ok(ret, "HttpQueryInfo failed\n"); + ok(status == 401, "unexpected status %u\n", status); + + buffer[0] = 0; + size = sizeof(buffer); + ret = HttpQueryInfo( request, HTTP_QUERY_RAW_HEADERS, buffer, &size, NULL); + ok(ret, "HttpQueryInfo failed\n"); + ok(!strcmp(buffer, "HTTP/1.0 401 Anonymous requests or requests on unsecure channel are not allowed"), + "headers wrong \"%s\"\n", buffer); + + buffer[0] = 0; + size = sizeof(buffer); + ret = HttpQueryInfo( request, HTTP_QUERY_SERVER, buffer, &size, NULL); + ok(ret, "HttpQueryInfo failed\n"); + ok(!strcmp(buffer, "winetest"), "server wrong \"%s\"\n", buffer); + + InternetCloseHandle(request); + InternetCloseHandle(connect); + InternetCloseHandle(session); +} + +static void test_HttpQueryInfo(int port) +{ + HINTERNET hi, hc, hr; + DWORD size, index; + char buffer[1024]; + BOOL ret; + + hi = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + ok(hi != NULL, "InternetOpen failed\n"); + + hc = InternetConnect(hi, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + ok(hc != NULL, "InternetConnect failed\n"); + + hr = HttpOpenRequest(hc, NULL, "/testD", NULL, NULL, NULL, 0, 0); + ok(hr != NULL, "HttpOpenRequest failed\n"); + + ret = HttpSendRequest(hr, NULL, 0, NULL, 0); + ok(ret, "HttpSendRequest failed\n"); + + index = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_HOST | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 1, "expected 1 got %u\n", index); + + index = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_DATE | HTTP_QUERY_FLAG_SYSTEMTIME, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 1, "expected 1 got %u\n", index); + + index = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_RAW_HEADERS, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 0, "expected 0 got %u\n", index); + + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_RAW_HEADERS, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 0, "expected 0 got %u\n", index); + + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_RAW_HEADERS_CRLF, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 0, "expected 0 got %u\n", index); + + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_STATUS_TEXT, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 0, "expected 0 got %u\n", index); + + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_VERSION, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 0, "expected 0 got %u\n", index); + + index = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_STATUS_CODE, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 0, "expected 0 got %u\n", index); + + index = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 0, "expected 0 got %u\n", index); + + index = 0xdeadbeef; + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_FORWARDED, buffer, &size, &index); + ok(!ret, "HttpQueryInfo succeeded\n"); + ok(index == 0xdeadbeef, "expected 0xdeadbeef got %u\n", index); + + index = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_SERVER, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 1, "expected 1 got %u\n", index); + + index = 0; + size = sizeof(buffer); + strcpy(buffer, "Server"); + ret = HttpQueryInfo(hr, HTTP_QUERY_CUSTOM, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 1, "expected 1 got %u\n", index); + + index = 0; + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_SET_COOKIE, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 1, "expected 1 got %u\n", index); + + size = sizeof(buffer); + ret = HttpQueryInfo(hr, HTTP_QUERY_SET_COOKIE, buffer, &size, &index); + ok(ret, "HttpQueryInfo failed %u\n", GetLastError()); + ok(index == 2, "expected 2 got %u\n", index); + + InternetCloseHandle(hr); + InternetCloseHandle(hc); + InternetCloseHandle(hi); +} + static void test_http_connection(void) { struct server_info si; @@ -1680,7 +2121,16 @@ static void test_http_connection(void) test_proxy_direct(si.port); test_header_handling_order(si.port); test_basic_request(si.port, "POST", "/test5"); + test_basic_request(si.port, "RPC_IN_DATA", "/test5"); + test_basic_request(si.port, "RPC_OUT_DATA", "/test5"); test_basic_request(si.port, "GET", "/test6"); + test_connection_header(si.port); + test_http1_1(si.port); + test_cookie_header(si.port); + test_basic_authentication(si.port); + test_invalid_response_headers(si.port); + test_HttpQueryInfo(si.port); + test_HttpSendRequestW(si.port); /* send the basic request again to shutdown the server thread */ test_basic_request(si.port, "GET", "/quit"); @@ -1700,10 +2150,10 @@ static void test_user_agent_header(void) ses = InternetOpen("Gizmo5", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); ok(ses != NULL, "InternetOpen failed\n"); - con = InternetConnect(ses, "www.winehq.org", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + con = InternetConnect(ses, "test.winehq.org", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); ok(con != NULL, "InternetConnect failed\n"); - req = HttpOpenRequest(con, "GET", "/", "HTTP/1.0", NULL, NULL, 0, 0); + req = HttpOpenRequest(con, "GET", "/hello.html", "HTTP/1.0", NULL, NULL, 0, 0); ok(req != NULL, "HttpOpenRequest failed\n"); size = sizeof(buffer); @@ -1712,7 +2162,7 @@ static void test_user_agent_header(void) ok(!ret, "HttpQueryInfo succeeded\n"); ok(err == ERROR_HTTP_HEADER_NOT_FOUND, "expected ERROR_HTTP_HEADER_NOT_FOUND, got %u\n", err); - ret = HttpAddRequestHeaders(req, "User-Agent: Gizmo Project\r\n", ~0UL, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + ret = HttpAddRequestHeaders(req, "User-Agent: Gizmo Project\r\n", ~0u, HTTP_ADDREQ_FLAG_ADD_IF_NEW); ok(ret, "HttpAddRequestHeaders succeeded\n"); size = sizeof(buffer); @@ -1732,7 +2182,7 @@ static void test_user_agent_header(void) ok(!ret, "HttpQueryInfo succeeded\n"); ok(err == ERROR_HTTP_HEADER_NOT_FOUND, "expected ERROR_HTTP_HEADER_NOT_FOUND, got %u\n", err); - ret = HttpAddRequestHeaders(req, "Accept: audio/*, image/*, text/*\r\nUser-Agent: Gizmo Project\r\n", ~0UL, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + ret = HttpAddRequestHeaders(req, "Accept: audio/*, image/*, text/*\r\nUser-Agent: Gizmo Project\r\n", ~0u, HTTP_ADDREQ_FLAG_ADD_IF_NEW); ok(ret, "HttpAddRequestHeaders failed\n"); buffer[0] = 0; @@ -1749,7 +2199,7 @@ static void test_user_agent_header(void) static void test_bogus_accept_types_array(void) { HINTERNET ses, con, req; - static const char *types[] = { (const char *)6240, "*/*", "%p", "", "*/*", NULL }; + static const char *types[] = { (const char *)6240, "*/*", "%p", "", (const char *)0xffffffff, "*/*", NULL }; DWORD size; char buffer[32]; BOOL ret; @@ -1764,13 +2214,288 @@ static void test_bogus_accept_types_array(void) size = sizeof(buffer); ret = HttpQueryInfo(req, HTTP_QUERY_ACCEPT | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); ok(ret, "HttpQueryInfo failed: %u\n", GetLastError()); - ok(!strcmp(buffer, "*/*, %p, */*"), "got '%s' expected '*/*, %%p, */*'\n", buffer); + ok(!strcmp(buffer, ", */*, %p, , , */*") || /* IE6 */ + !strcmp(buffer, "*/*, %p, */*"), + "got '%s' expected '*/*, %%p, */*' or ', */*, %%p, , , */*'\n", buffer); InternetCloseHandle(req); InternetCloseHandle(con); InternetCloseHandle(ses); } +struct context +{ + HANDLE event; + HINTERNET req; +}; + +static void WINAPI cb(HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID info, DWORD size) +{ + INTERNET_ASYNC_RESULT *result = info; + struct context *ctx = (struct context *)context; + + trace("%p 0x%08lx %u %p 0x%08x\n", handle, context, status, info, size); + + if (status == INTERNET_STATUS_REQUEST_COMPLETE) + { + trace("request handle: 0x%08lx\n", result->dwResult); + ctx->req = (HINTERNET)result->dwResult; + SetEvent(ctx->event); + } + if (status == INTERNET_STATUS_HANDLE_CLOSING) + { + DWORD type = INTERNET_HANDLE_TYPE_CONNECT_HTTP, size = sizeof(type); + + if (InternetQueryOption(handle, INTERNET_OPTION_HANDLE_TYPE, &type, &size)) + ok(type != INTERNET_HANDLE_TYPE_CONNECT_HTTP, "unexpected callback\n"); + SetEvent(ctx->event); + } +} + +static void test_open_url_async(void) +{ + BOOL ret; + HINTERNET ses, req; + DWORD size, error; + struct context ctx; + ULONG type; + + ctx.req = NULL; + ctx.event = CreateEvent(NULL, TRUE, FALSE, "Z:_home_hans_jaman-installer.exe_ev1"); + + ses = InternetOpen("AdvancedInstaller", 0, NULL, NULL, INTERNET_FLAG_ASYNC); + ok(ses != NULL, "InternetOpen failed\n"); + + SetLastError(0xdeadbeef); + ret = InternetSetOptionA(NULL, INTERNET_OPTION_CALLBACK, &cb, sizeof(DWORD_PTR)); + error = GetLastError(); + ok(!ret, "InternetSetOptionA succeeded\n"); + ok(error == ERROR_INTERNET_INCORRECT_HANDLE_TYPE, "got %u expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE\n", error); + + ret = InternetSetOptionA(ses, INTERNET_OPTION_CALLBACK, &cb, sizeof(DWORD_PTR)); + error = GetLastError(); + ok(!ret, "InternetSetOptionA failed\n"); + ok(error == ERROR_INTERNET_OPTION_NOT_SETTABLE, "got %u expected ERROR_INTERNET_OPTION_NOT_SETTABLE\n", error); + + pInternetSetStatusCallbackA(ses, cb); + ResetEvent(ctx.event); + + req = InternetOpenUrl(ses, "http://test.winehq.org", NULL, 0, 0, (DWORD_PTR)&ctx); + ok(!req && GetLastError() == ERROR_IO_PENDING, "InternetOpenUrl failed\n"); + + WaitForSingleObject(ctx.event, INFINITE); + + type = 0; + size = sizeof(type); + ret = InternetQueryOption(ctx.req, INTERNET_OPTION_HANDLE_TYPE, &type, &size); + ok(ret, "InternetQueryOption failed: %u\n", GetLastError()); + ok(type == INTERNET_HANDLE_TYPE_HTTP_REQUEST, + "expected INTERNET_HANDLE_TYPE_HTTP_REQUEST, got %u\n", type); + + size = 0; + ret = HttpQueryInfo(ctx.req, HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &size, NULL); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "HttpQueryInfo failed\n"); + ok(size > 0, "expected size > 0\n"); + + ResetEvent(ctx.event); + InternetCloseHandle(ctx.req); + WaitForSingleObject(ctx.event, INFINITE); + + InternetCloseHandle(ses); + CloseHandle(ctx.event); +} + +enum api +{ + internet_connect = 1, + http_open_request, + http_send_request_ex, + internet_writefile, + http_end_request, + internet_close_handle +}; + +struct notification +{ + enum api function; /* api responsible for notification */ + unsigned int status; /* status received */ + int async; /* delivered from another thread? */ + int todo; +}; + +struct info +{ + enum api function; + const struct notification *test; + unsigned int count; + unsigned int index; + HANDLE wait; + DWORD thread; + unsigned int line; +}; + +static CRITICAL_SECTION notification_cs; + +static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID buffer, DWORD buflen ) +{ + BOOL status_ok, function_ok; + struct info *info = (struct info *)context; + unsigned int i; + + EnterCriticalSection( ¬ification_cs ); + + if (status == INTERNET_STATUS_HANDLE_CREATED) + { + DWORD size = sizeof(struct info *); + HttpQueryInfoA( handle, INTERNET_OPTION_CONTEXT_VALUE, &info, &size, 0 ); + } + i = info->index; + if (i >= info->count) + { + LeaveCriticalSection( ¬ification_cs ); + return; + } + + status_ok = (info->test[i].status == status); + function_ok = (info->test[i].function == info->function); + + if (!info->test[i].todo) + { + ok( status_ok, "%u: expected status %u got %u\n", info->line, info->test[i].status, status ); + ok( function_ok, "%u: expected function %u got %u\n", info->line, info->test[i].function, info->function ); + + if (info->test[i].async) + ok(info->thread != GetCurrentThreadId(), "%u: expected thread %u got %u\n", + info->line, info->thread, GetCurrentThreadId()); + } + else + { + todo_wine ok( status_ok, "%u: expected status %u got %u\n", info->line, info->test[i].status, status ); + if (status_ok) + todo_wine ok( function_ok, "%u: expected function %u got %u\n", info->line, info->test[i].function, info->function ); + } + if (i == info->count - 1 || info->test[i].function != info->test[i + 1].function) SetEvent( info->wait ); + info->index++; + + LeaveCriticalSection( ¬ification_cs ); +} + +static void setup_test( struct info *info, enum api function, unsigned int line ) +{ + info->function = function; + info->line = line; +} + +static const struct notification async_send_request_ex_test[] = +{ + { internet_connect, INTERNET_STATUS_HANDLE_CREATED, 0 }, + { http_open_request, INTERNET_STATUS_HANDLE_CREATED, 0 }, + { http_send_request_ex, INTERNET_STATUS_RESOLVING_NAME, 1 }, + { http_send_request_ex, INTERNET_STATUS_NAME_RESOLVED, 1 }, + { http_send_request_ex, INTERNET_STATUS_CONNECTING_TO_SERVER, 1 }, + { http_send_request_ex, INTERNET_STATUS_CONNECTED_TO_SERVER, 1 }, + { http_send_request_ex, INTERNET_STATUS_SENDING_REQUEST, 1 }, + { http_send_request_ex, INTERNET_STATUS_REQUEST_SENT, 1 }, + { http_send_request_ex, INTERNET_STATUS_REQUEST_COMPLETE, 1 }, + { internet_writefile, INTERNET_STATUS_SENDING_REQUEST, 0 }, + { internet_writefile, INTERNET_STATUS_REQUEST_SENT, 0 }, + { http_end_request, INTERNET_STATUS_RECEIVING_RESPONSE, 1 }, + { http_end_request, INTERNET_STATUS_RESPONSE_RECEIVED, 1 }, + { http_end_request, INTERNET_STATUS_REQUEST_COMPLETE, 1 }, + { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING, 0, 1 }, + { internet_close_handle, INTERNET_STATUS_HANDLE_CLOSING, 0, 1 } +}; + +static void test_async_HttpSendRequestEx(void) +{ + BOOL ret; + HINTERNET ses, req, con; + struct info info; + DWORD size, written, error; + INTERNET_BUFFERSA b; + static const char *accept[2] = {"*/*", NULL}; + static char data[] = "Public ID=codeweavers"; + char buffer[32]; + + InitializeCriticalSection( ¬ification_cs ); + + info.test = async_send_request_ex_test; + info.count = sizeof(async_send_request_ex_test)/sizeof(async_send_request_ex_test[0]); + info.index = 0; + info.wait = CreateEvent( NULL, FALSE, FALSE, NULL ); + info.thread = GetCurrentThreadId(); + + ses = InternetOpen( "winetest", 0, NULL, NULL, INTERNET_FLAG_ASYNC ); + ok( ses != NULL, "InternetOpen failed\n" ); + + pInternetSetStatusCallbackA( ses, check_notification ); + + setup_test( &info, internet_connect, __LINE__ ); + con = InternetConnect( ses, "crossover.codeweavers.com", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)&info ); + ok( con != NULL, "InternetConnect failed %u\n", GetLastError() ); + + WaitForSingleObject( info.wait, 10000 ); + + setup_test( &info, http_open_request, __LINE__ ); + req = HttpOpenRequest( con, "POST", "posttest.php", NULL, NULL, accept, 0, (DWORD_PTR)&info ); + ok( req != NULL, "HttpOpenRequest failed %u\n", GetLastError() ); + + WaitForSingleObject( info.wait, 10000 ); + + memset( &b, 0, sizeof(INTERNET_BUFFERSA) ); + b.dwStructSize = sizeof(INTERNET_BUFFERSA); + b.lpcszHeader = "Content-Type: application/x-www-form-urlencoded"; + b.dwHeadersLength = strlen( b.lpcszHeader ); + b.dwBufferTotal = strlen( data ); + + setup_test( &info, http_send_request_ex, __LINE__ ); + ret = HttpSendRequestExA( req, &b, NULL, 0x28, 0 ); + ok( !ret && GetLastError() == ERROR_IO_PENDING, "HttpSendRequestExA failed %d %u\n", ret, GetLastError() ); + + WaitForSingleObject( info.wait, 10000 ); + + size = sizeof(buffer); + SetLastError( 0xdeadbeef ); + ret = HttpQueryInfoA( req, HTTP_QUERY_CONTENT_ENCODING, buffer, &size, 0 ); + error = GetLastError(); + ok( !ret, "HttpQueryInfoA failed %u\n", GetLastError() ); + todo_wine + ok( error == ERROR_INTERNET_INCORRECT_HANDLE_STATE, + "expected ERROR_INTERNET_INCORRECT_HANDLE_STATE got %u\n", error ); + + written = 0; + size = strlen( data ); + setup_test( &info, internet_writefile, __LINE__ ); + ret = InternetWriteFile( req, data, size, &written ); + ok( ret, "InternetWriteFile failed %u\n", GetLastError() ); + ok( written == size, "expected %u got %u\n", written, size ); + + WaitForSingleObject( info.wait, 10000 ); + + SetLastError( 0xdeadbeef ); + ret = HttpEndRequestA( req, (void *)data, 0x28, 0 ); + error = GetLastError(); + ok( !ret, "HttpEndRequestA succeeded\n" ); + ok( error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", error ); + + SetLastError( 0xdeadbeef ); + setup_test( &info, http_end_request, __LINE__ ); + ret = HttpEndRequestA( req, NULL, 0x28, 0 ); + error = GetLastError(); + ok( !ret, "HttpEndRequestA succeeded\n" ); + ok( error == ERROR_IO_PENDING, "expected ERROR_IO_PENDING got %u\n", error ); + + WaitForSingleObject( info.wait, 10000 ); + + setup_test( &info, internet_close_handle, __LINE__ ); + InternetCloseHandle( req ); + InternetCloseHandle( con ); + InternetCloseHandle( ses ); + + WaitForSingleObject( info.wait, 10000 ); + CloseHandle( info.wait ); +} + #define STATUS_STRING(status) \ memcpy(status_string[status], #status, sizeof(CHAR) * \ (strlen(#status) < MAX_STATUS_NAME ? \ @@ -1779,6 +2504,7 @@ static void test_bogus_accept_types_array(void) static void init_status_tests(void) { memset(expect, 0, sizeof(expect)); + memset(optional, 0, sizeof(optional)); memset(wine_allow, 0, sizeof(wine_allow)); memset(notified, 0, sizeof(notified)); memset(status_string, 0, sizeof(status_string)); @@ -1816,10 +2542,6 @@ START_TEST(http) HMODULE hdll; hdll = GetModuleHandleA("wininet.dll"); pInternetSetStatusCallbackA = (void*)GetProcAddress(hdll, "InternetSetStatusCallbackA"); - pInternetTimeFromSystemTimeA = (void*)GetProcAddress(hdll, "InternetTimeFromSystemTimeA"); - pInternetTimeFromSystemTimeW = (void*)GetProcAddress(hdll, "InternetTimeFromSystemTimeW"); - pInternetTimeToSystemTimeA = (void*)GetProcAddress(hdll, "InternetTimeToSystemTimeA"); - pInternetTimeToSystemTimeW = (void*)GetProcAddress(hdll, "InternetTimeToSystemTimeW"); if (!pInternetSetStatusCallbackA) skip("skipping the InternetReadFile tests\n"); @@ -1829,19 +2551,12 @@ START_TEST(http) InternetReadFile_test(INTERNET_FLAG_ASYNC); InternetReadFile_test(0); InternetReadFileExA_test(INTERNET_FLAG_ASYNC); + test_open_url_async(); + test_async_HttpSendRequestEx(); } InternetOpenRequest_test(); test_http_cache(); InternetOpenUrlA_test(); - if (!pInternetTimeFromSystemTimeA) - skip("skipping the InternetTime tests\n"); - else - { - InternetTimeFromSystemTimeA_test(); - InternetTimeFromSystemTimeW_test(); - InternetTimeToSystemTimeA_test(); - InternetTimeToSystemTimeW_test(); - } HttpSendRequestEx_test(); HttpHeaders_test(); test_http_connection(); diff --git a/rostests/winetests/wininet/internet.c b/rostests/winetests/wininet/internet.c index 15495db514d..1be6008bbe5 100644 --- a/rostests/winetests/wininet/internet.c +++ b/rostests/winetests/wininet/internet.c @@ -27,6 +27,16 @@ #include "wine/test.h" +static BOOL (WINAPI *pCreateUrlCacheContainerA)(DWORD, DWORD, DWORD, DWORD, + DWORD, DWORD, DWORD, DWORD); +static BOOL (WINAPI *pCreateUrlCacheContainerW)(DWORD, DWORD, DWORD, DWORD, + DWORD, DWORD, DWORD, DWORD); +static BOOL (WINAPI *pInternetTimeFromSystemTimeA)(CONST SYSTEMTIME *,DWORD ,LPSTR ,DWORD); +static BOOL (WINAPI *pInternetTimeFromSystemTimeW)(CONST SYSTEMTIME *,DWORD ,LPWSTR ,DWORD); +static BOOL (WINAPI *pInternetTimeToSystemTimeA)(LPCSTR ,SYSTEMTIME *,DWORD); +static BOOL (WINAPI *pInternetTimeToSystemTimeW)(LPCWSTR ,SYSTEMTIME *,DWORD); +static BOOL (WINAPI *pIsDomainLegalCookieDomainW)(LPCWSTR, LPCWSTR); + /* ############################### */ static void test_InternetCanonicalizeUrlA(void) @@ -73,6 +83,16 @@ static void test_InternetCanonicalizeUrlA(void) "got %u and %u with size %u for '%s' (%d)\n", res, GetLastError(), dwSize, buffer, lstrlenA(buffer)); + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + dwSize = sizeof(buffer); + SetLastError(0xdeadbeef); + res = InternetCanonicalizeUrlA("file:///C:/Program%20Files/Atmel/AVR%20Tools/STK500/STK500.xml", buffer, &dwSize, ICU_DECODE | ICU_NO_ENCODE); + ok(res, "InternetCanonicalizeUrlA failed %u\n", GetLastError()); + ok(dwSize == lstrlenA(buffer), "got %d expected %d\n", dwSize, lstrlenA(buffer)); + todo_wine ok(!lstrcmpA("file://C:\\Program Files\\Atmel\\AVR Tools\\STK500\\STK500.xml", buffer), + "got %s expected 'file://C:\\Program Files\\Atmel\\AVR Tools\\STK500\\STK500.xml'\n", buffer); + /* buffer is larger as the required size */ memset(buffer, '#', sizeof(buffer)-1); buffer[sizeof(buffer)-1] = '\0'; @@ -113,6 +133,12 @@ static void test_InternetCanonicalizeUrlA(void) "got %u and %u with size %u for '%s' (%d)\n", res, GetLastError(), dwSize, buffer, lstrlenA(buffer)); + /* test with trailing space */ + dwSize = 256; + res = InternetCanonicalizeUrlA("http://www.winehq.org/index.php?x= ", buffer, &dwSize, ICU_BROWSER_MODE); + ok(res == 1, "InternetCanonicalizeUrlA failed\n"); + ok(!strcmp(buffer, "http://www.winehq.org/index.php?x="), "Trailing space should have been stripped even in ICU_BROWSER_MODE (%s)\n", buffer); + res = InternetSetOptionA(NULL, 0xdeadbeef, buffer, sizeof(buffer)); ok(!res, "InternetSetOptionA succeeded\n"); ok(GetLastError() == ERROR_INTERNET_INVALID_OPTION, @@ -133,23 +159,29 @@ static void test_InternetQueryOptionA(void) hinet = InternetOpenA(useragent,INTERNET_OPEN_TYPE_DIRECT,NULL,NULL, 0); ok((hinet != 0x0),"InternetOpen Failed\n"); + SetLastError(0xdeadbeef); + retval=InternetQueryOptionA(NULL,INTERNET_OPTION_USER_AGENT,NULL,&len); + err=GetLastError(); + ok(retval == 0,"Got wrong return value %d\n",retval); + ok(err == ERROR_INTERNET_INCORRECT_HANDLE_TYPE, "Got wrong error code%d\n",err); + SetLastError(0xdeadbeef); len=strlen(useragent)+1; retval=InternetQueryOptionA(hinet,INTERNET_OPTION_USER_AGENT,NULL,&len); err=GetLastError(); ok(len == strlen(useragent)+1,"Got wrong user agent length %d instead of %d\n",len,lstrlenA(useragent)); ok(retval == 0,"Got wrong return value %d\n",retval); - todo_wine ok(err == ERROR_INSUFFICIENT_BUFFER, "Got wrong error code%d\n",err); + ok(err == ERROR_INSUFFICIENT_BUFFER, "Got wrong error code %d\n",err); SetLastError(0xdeadbeef); len=strlen(useragent)+1; buffer=HeapAlloc(GetProcessHeap(),0,len); retval=InternetQueryOptionA(hinet,INTERNET_OPTION_USER_AGENT,buffer,&len); err=GetLastError(); - todo_wine ok(retval == 1,"Got wrong return value %d\n",retval); + ok(retval == 1,"Got wrong return value %d\n",retval); if (retval) { - todo_wine ok(!strcmp(useragent,buffer),"Got wrong user agent string %s instead of %s\n",buffer,useragent); + ok(!strcmp(useragent,buffer),"Got wrong user agent string %s instead of %s\n",buffer,useragent); todo_wine ok(len == strlen(useragent),"Got wrong user agent length %d instead of %d\n",len,lstrlenA(useragent)); } ok(err == 0xdeadbeef, "Got wrong error code %d\n",err); @@ -160,12 +192,12 @@ static void test_InternetQueryOptionA(void) buffer=HeapAlloc(GetProcessHeap(),0,100); retval=InternetQueryOptionA(hinet,INTERNET_OPTION_USER_AGENT,buffer,&len); err=GetLastError(); - todo_wine ok(len == strlen(useragent) + 1,"Got wrong user agent length %d instead of %d\n", len, lstrlenA(useragent) + 1); + ok(len == strlen(useragent) + 1,"Got wrong user agent length %d instead of %d\n", len, lstrlenA(useragent) + 1); ok(!retval, "Got wrong return value %d\n", retval); - todo_wine ok(err == ERROR_INSUFFICIENT_BUFFER, "Got wrong error code %d\n", err); + ok(err == ERROR_INSUFFICIENT_BUFFER, "Got wrong error code %d\n", err); HeapFree(GetProcessHeap(),0,buffer); - hurl = InternetConnectA(hinet,"www.winehq.com",INTERNET_DEFAULT_HTTP_PORT,NULL,NULL,INTERNET_SERVICE_HTTP,0,0); + hurl = InternetConnectA(hinet,"www.winehq.org",INTERNET_DEFAULT_HTTP_PORT,NULL,NULL,INTERNET_SERVICE_HTTP,0,0); SetLastError(0xdeadbeef); len=0; @@ -173,7 +205,7 @@ static void test_InternetQueryOptionA(void) err=GetLastError(); ok(len == 0,"Got wrong user agent length %d instead of 0\n",len); ok(retval == 0,"Got wrong return value %d\n",retval); - todo_wine ok(err == ERROR_INTERNET_INCORRECT_HANDLE_TYPE, "Got wrong error code %d\n",err); + ok(err == ERROR_INTERNET_INCORRECT_HANDLE_TYPE, "Got wrong error code %d\n",err); InternetCloseHandle(hurl); InternetCloseHandle(hinet); @@ -185,9 +217,9 @@ static void test_InternetQueryOptionA(void) len=0; retval=InternetQueryOptionA(hinet,INTERNET_OPTION_USER_AGENT,NULL,&len); err=GetLastError(); - todo_wine ok(len == 1,"Got wrong user agent length %d instead of %d\n",len,1); + ok(len == 1,"Got wrong user agent length %d instead of %d\n",len,1); ok(retval == 0,"Got wrong return value %d\n",retval); - todo_wine ok(err == ERROR_INSUFFICIENT_BUFFER, "Got wrong error code%d\n",err); + ok(err == ERROR_INSUFFICIENT_BUFFER, "Got wrong error code%d\n",err); InternetCloseHandle(hinet); @@ -199,7 +231,7 @@ static void test_InternetQueryOptionA(void) err=GetLastError(); todo_wine ok(len == 1,"Got wrong user agent length %d instead of %d\n",len,1); ok(retval == 0,"Got wrong return value %d\n",retval); - todo_wine ok(err == ERROR_INSUFFICIENT_BUFFER, "Got wrong error code%d\n",err); + ok(err == ERROR_INSUFFICIENT_BUFFER, "Got wrong error code%d\n",err); InternetCloseHandle(hinet); } @@ -216,6 +248,111 @@ static void test_get_cookie(void) ret ? "TRUE" : "FALSE", GetLastError()); } + +static void test_complicated_cookie(void) +{ + DWORD len; + BOOL ret; + + CHAR buffer[1024]; + + ret = InternetSetCookie("http://www.example.com/bar",NULL,"A=B; domain=.example.com"); + ok(ret == TRUE,"InternetSetCookie failed\n"); + ret = InternetSetCookie("http://www.example.com/bar",NULL,"C=D; domain=.example.com; path=/"); + ok(ret == TRUE,"InternetSetCookie failed\n"); + + /* Technically illegal! domain should require 2 dots, but native wininet accepts it */ + ret = InternetSetCookie("http://www.example.com",NULL,"E=F; domain=example.com"); + ok(ret == TRUE,"InternetSetCookie failed\n"); + ret = InternetSetCookie("http://www.example.com",NULL,"G=H; domain=.example.com; path=/foo"); + ok(ret == TRUE,"InternetSetCookie failed\n"); + ret = InternetSetCookie("http://www.example.com/bar.html",NULL,"I=J; domain=.example.com"); + ok(ret == TRUE,"InternetSetCookie failed\n"); + ret = InternetSetCookie("http://www.example.com/bar/",NULL,"K=L; domain=.example.com"); + ok(ret == TRUE,"InternetSetCookie failed\n"); + ret = InternetSetCookie("http://www.example.com/bar/",NULL,"M=N; domain=.example.com; path=/foo/"); + ok(ret == TRUE,"InternetSetCookie failed\n"); + ret = InternetSetCookie("http://www.example.com/bar/",NULL,"O=P; secure; path=/bar"); + ok(ret == TRUE,"InternetSetCookie failed\n"); + + len = 1024; + ret = InternetGetCookie("http://testing.example.com", NULL, buffer, &len); + ok(strstr(buffer,"A=B")!=NULL,"A=B missing\n"); + ok(strstr(buffer,"C=D")!=NULL,"C=D missing\n"); + ok(strstr(buffer,"E=F")!=NULL,"E=F missing\n"); + ok(strstr(buffer,"G=H")==NULL,"G=H present\n"); + ok(strstr(buffer,"I=J")!=NULL,"I=J missing\n"); + ok(strstr(buffer,"K=L")==NULL,"K=L present\n"); + ok(strstr(buffer,"M=N")==NULL,"M=N present\n"); + ok(strstr(buffer,"O=P")==NULL,"O=P present\n"); + + len = 1024; + ret = InternetGetCookie("http://testing.example.com/foobar", NULL, buffer, &len); + ok(strstr(buffer,"A=B")!=NULL,"A=B missing\n"); + ok(strstr(buffer,"C=D")!=NULL,"C=D missing\n"); + ok(strstr(buffer,"E=F")!=NULL,"E=F missing\n"); + ok(strstr(buffer,"G=H")==NULL,"G=H present\n"); + ok(strstr(buffer,"I=J")!=NULL,"I=J missing\n"); + ok(strstr(buffer,"K=L")==NULL,"K=L present\n"); + ok(strstr(buffer,"M=N")==NULL,"M=N present\n"); + ok(strstr(buffer,"O=P")==NULL,"O=P present\n"); + + len = 1024; + ret = InternetGetCookie("http://testing.example.com/foobar/", NULL, buffer, &len); + ok(strstr(buffer,"A=B")!=NULL,"A=B missing\n"); + ok(strstr(buffer,"C=D")!=NULL,"C=D missing\n"); + ok(strstr(buffer,"E=F")!=NULL,"E=F missing\n"); + ok(strstr(buffer,"G=H")!=NULL,"G=H missing\n"); + ok(strstr(buffer,"I=J")!=NULL,"I=J missing\n"); + ok(strstr(buffer,"K=L")==NULL,"K=L present\n"); + ok(strstr(buffer,"M=N")==NULL,"M=N present\n"); + ok(strstr(buffer,"O=P")==NULL,"O=P present\n"); + + len = 1024; + ret = InternetGetCookie("http://testing.example.com/foo/bar", NULL, buffer, &len); + ok(strstr(buffer,"A=B")!=NULL,"A=B missing\n"); + ok(strstr(buffer,"C=D")!=NULL,"C=D missing\n"); + ok(strstr(buffer,"E=F")!=NULL,"E=F missing\n"); + ok(strstr(buffer,"G=H")!=NULL,"G=H missing\n"); + ok(strstr(buffer,"I=J")!=NULL,"I=J missing\n"); + ok(strstr(buffer,"K=L")==NULL,"K=L present\n"); + ok(strstr(buffer,"M=N")!=NULL,"M=N missing\n"); + ok(strstr(buffer,"O=P")==NULL,"O=P present\n"); + + len = 1024; + ret = InternetGetCookie("http://testing.example.com/barfoo", NULL, buffer, &len); + ok(strstr(buffer,"A=B")!=NULL,"A=B missing\n"); + ok(strstr(buffer,"C=D")!=NULL,"C=D missing\n"); + ok(strstr(buffer,"E=F")!=NULL,"E=F missing\n"); + ok(strstr(buffer,"G=H")==NULL,"G=H present\n"); + ok(strstr(buffer,"I=J")!=NULL,"I=J missing\n"); + ok(strstr(buffer,"K=L")==NULL,"K=L present\n"); + ok(strstr(buffer,"M=N")==NULL,"M=N present\n"); + ok(strstr(buffer,"O=P")==NULL,"O=P present\n"); + + len = 1024; + ret = InternetGetCookie("http://testing.example.com/barfoo/", NULL, buffer, &len); + ok(strstr(buffer,"A=B")!=NULL,"A=B missing\n"); + ok(strstr(buffer,"C=D")!=NULL,"C=D missing\n"); + ok(strstr(buffer,"E=F")!=NULL,"E=F missing\n"); + ok(strstr(buffer,"G=H")==NULL,"G=H present\n"); + ok(strstr(buffer,"I=J")!=NULL,"I=J missing\n"); + ok(strstr(buffer,"K=L")==NULL,"K=L present\n"); + ok(strstr(buffer,"M=N")==NULL,"M=N present\n"); + ok(strstr(buffer,"O=P")==NULL,"O=P present\n"); + + len = 1024; + ret = InternetGetCookie("http://testing.example.com/bar/foo", NULL, buffer, &len); + ok(strstr(buffer,"A=B")!=NULL,"A=B missing\n"); + ok(strstr(buffer,"C=D")!=NULL,"C=D missing\n"); + ok(strstr(buffer,"E=F")!=NULL,"E=F missing\n"); + ok(strstr(buffer,"G=H")==NULL,"G=H present\n"); + ok(strstr(buffer,"I=J")!=NULL,"I=J missing\n"); + ok(strstr(buffer,"K=L")!=NULL,"K=L missing\n"); + ok(strstr(buffer,"M=N")==NULL,"M=N present\n"); + ok(strstr(buffer,"O=P")==NULL,"O=P present\n"); +} + static void test_null(void) { HINTERNET hi, hc; @@ -228,7 +365,13 @@ static void test_null(void) BOOL r; DWORD sz; + SetLastError(0xdeadbeef); hi = InternetOpenW(NULL, 0, NULL, NULL, 0); + if (hi == NULL && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Internet*W functions are not implemented\n"); + return; + } ok(hi != NULL, "open failed\n"); hc = InternetConnectW(hi, NULL, 0, NULL, NULL, 0, 0, 0); @@ -248,7 +391,8 @@ static void test_null(void) ok(hc == NULL, "connect failed\n"); hc = InternetOpenUrlW(hi, NULL, NULL, 0, 0, 0); - ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_INTERNET_UNRECOGNIZED_SCHEME, "wrong error\n"); ok(hc == NULL, "connect failed\n"); hc = InternetOpenUrlW(hi, szServer, NULL, 0, 0, 0); @@ -339,13 +483,353 @@ static void test_version(void) ok(version.dwMinorVersion == 2, "dwMinorVersion=%d, expected 2\n", version.dwMinorVersion); } +static void InternetTimeFromSystemTimeA_test(void) +{ + BOOL ret; + static const SYSTEMTIME time = { 2005, 1, 5, 7, 12, 6, 35, 0 }; + char string[INTERNET_RFC1123_BUFSIZE]; + static const char expect[] = "Fri, 07 Jan 2005 12:06:35 GMT"; + DWORD error; + + ret = pInternetTimeFromSystemTimeA( &time, INTERNET_RFC1123_FORMAT, string, sizeof(string) ); + ok( ret, "InternetTimeFromSystemTimeA failed (%u)\n", GetLastError() ); + + ok( !memcmp( string, expect, sizeof(expect) ), + "InternetTimeFromSystemTimeA failed (%u)\n", GetLastError() ); + + /* test NULL time parameter */ + SetLastError(0xdeadbeef); + ret = pInternetTimeFromSystemTimeA( NULL, INTERNET_RFC1123_FORMAT, string, sizeof(string) ); + error = GetLastError(); + ok( !ret, "InternetTimeFromSystemTimeA should have returned FALSE\n" ); + ok( error == ERROR_INVALID_PARAMETER, + "InternetTimeFromSystemTimeA failed with ERROR_INVALID_PARAMETER instead of %u\n", + error ); + + /* test NULL string parameter */ + SetLastError(0xdeadbeef); + ret = pInternetTimeFromSystemTimeA( &time, INTERNET_RFC1123_FORMAT, NULL, sizeof(string) ); + error = GetLastError(); + ok( !ret, "InternetTimeFromSystemTimeA should have returned FALSE\n" ); + ok( error == ERROR_INVALID_PARAMETER, + "InternetTimeFromSystemTimeA failed with ERROR_INVALID_PARAMETER instead of %u\n", + error ); + + /* test invalid format parameter */ + SetLastError(0xdeadbeef); + ret = pInternetTimeFromSystemTimeA( &time, INTERNET_RFC1123_FORMAT + 1, string, sizeof(string) ); + error = GetLastError(); + ok( !ret, "InternetTimeFromSystemTimeA should have returned FALSE\n" ); + ok( error == ERROR_INVALID_PARAMETER, + "InternetTimeFromSystemTimeA failed with ERROR_INVALID_PARAMETER instead of %u\n", + error ); + + /* test too small buffer size */ + SetLastError(0xdeadbeef); + ret = pInternetTimeFromSystemTimeA( &time, INTERNET_RFC1123_FORMAT, string, 0 ); + error = GetLastError(); + ok( !ret, "InternetTimeFromSystemTimeA should have returned FALSE\n" ); + ok( error == ERROR_INSUFFICIENT_BUFFER, + "InternetTimeFromSystemTimeA failed with ERROR_INSUFFICIENT_BUFFER instead of %u\n", + error ); +} + +static void InternetTimeFromSystemTimeW_test(void) +{ + BOOL ret; + static const SYSTEMTIME time = { 2005, 1, 5, 7, 12, 6, 35, 0 }; + WCHAR string[INTERNET_RFC1123_BUFSIZE + 1]; + static const WCHAR expect[] = { 'F','r','i',',',' ','0','7',' ','J','a','n',' ','2','0','0','5',' ', + '1','2',':','0','6',':','3','5',' ','G','M','T',0 }; + DWORD error; + + ret = pInternetTimeFromSystemTimeW( &time, INTERNET_RFC1123_FORMAT, string, sizeof(string) ); + ok( ret, "InternetTimeFromSystemTimeW failed (%u)\n", GetLastError() ); + + ok( !memcmp( string, expect, sizeof(expect) ), + "InternetTimeFromSystemTimeW failed (%u)\n", GetLastError() ); + + /* test NULL time parameter */ + SetLastError(0xdeadbeef); + ret = pInternetTimeFromSystemTimeW( NULL, INTERNET_RFC1123_FORMAT, string, sizeof(string) ); + error = GetLastError(); + ok( !ret, "InternetTimeFromSystemTimeW should have returned FALSE\n" ); + ok( error == ERROR_INVALID_PARAMETER, + "InternetTimeFromSystemTimeW failed with ERROR_INVALID_PARAMETER instead of %u\n", + error ); + + /* test NULL string parameter */ + SetLastError(0xdeadbeef); + ret = pInternetTimeFromSystemTimeW( &time, INTERNET_RFC1123_FORMAT, NULL, sizeof(string) ); + error = GetLastError(); + ok( !ret, "InternetTimeFromSystemTimeW should have returned FALSE\n" ); + ok( error == ERROR_INVALID_PARAMETER, + "InternetTimeFromSystemTimeW failed with ERROR_INVALID_PARAMETER instead of %u\n", + error ); + + /* test invalid format parameter */ + SetLastError(0xdeadbeef); + ret = pInternetTimeFromSystemTimeW( &time, INTERNET_RFC1123_FORMAT + 1, string, sizeof(string) ); + error = GetLastError(); + ok( !ret, "InternetTimeFromSystemTimeW should have returned FALSE\n" ); + ok( error == ERROR_INVALID_PARAMETER, + "InternetTimeFromSystemTimeW failed with ERROR_INVALID_PARAMETER instead of %u\n", + error ); + + /* test too small buffer size */ + SetLastError(0xdeadbeef); + ret = pInternetTimeFromSystemTimeW( &time, INTERNET_RFC1123_FORMAT, string, sizeof(string)/sizeof(string[0]) ); + error = GetLastError(); + ok( !ret, "InternetTimeFromSystemTimeW should have returned FALSE\n" ); + ok( error == ERROR_INSUFFICIENT_BUFFER, + "InternetTimeFromSystemTimeW failed with ERROR_INSUFFICIENT_BUFFER instead of %u\n", + error ); +} + +static void InternetTimeToSystemTimeA_test(void) +{ + BOOL ret; + SYSTEMTIME time; + static const SYSTEMTIME expect = { 2005, 1, 5, 7, 12, 6, 35, 0 }; + static const char string[] = "Fri, 07 Jan 2005 12:06:35 GMT"; + static const char string2[] = " fri 7 jan 2005 12 06 35"; + + ret = pInternetTimeToSystemTimeA( string, &time, 0 ); + ok( ret, "InternetTimeToSystemTimeA failed (%u)\n", GetLastError() ); + ok( !memcmp( &time, &expect, sizeof(expect) ), + "InternetTimeToSystemTimeA failed (%u)\n", GetLastError() ); + + ret = pInternetTimeToSystemTimeA( string2, &time, 0 ); + ok( ret, "InternetTimeToSystemTimeA failed (%u)\n", GetLastError() ); + ok( !memcmp( &time, &expect, sizeof(expect) ), + "InternetTimeToSystemTimeA failed (%u)\n", GetLastError() ); +} + +static void InternetTimeToSystemTimeW_test(void) +{ + BOOL ret; + SYSTEMTIME time; + static const SYSTEMTIME expect = { 2005, 1, 5, 7, 12, 6, 35, 0 }; + static const WCHAR string[] = { 'F','r','i',',',' ','0','7',' ','J','a','n',' ','2','0','0','5',' ', + '1','2',':','0','6',':','3','5',' ','G','M','T',0 }; + static const WCHAR string2[] = { ' ','f','r','i',' ','7',' ','j','a','n',' ','2','0','0','5',' ', + '1','2',' ','0','6',' ','3','5',0 }; + static const WCHAR string3[] = { 'F','r',0 }; + + ret = pInternetTimeToSystemTimeW( NULL, NULL, 0 ); + ok( !ret, "InternetTimeToSystemTimeW succeeded (%u)\n", GetLastError() ); + + ret = pInternetTimeToSystemTimeW( NULL, &time, 0 ); + ok( !ret, "InternetTimeToSystemTimeW succeeded (%u)\n", GetLastError() ); + + ret = pInternetTimeToSystemTimeW( string, NULL, 0 ); + ok( !ret, "InternetTimeToSystemTimeW succeeded (%u)\n", GetLastError() ); + + ret = pInternetTimeToSystemTimeW( string, &time, 0 ); + ok( ret, "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); + + ret = pInternetTimeToSystemTimeW( string, &time, 0 ); + ok( ret, "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); + ok( !memcmp( &time, &expect, sizeof(expect) ), + "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); + + ret = pInternetTimeToSystemTimeW( string2, &time, 0 ); + ok( ret, "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); + ok( !memcmp( &time, &expect, sizeof(expect) ), + "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); + + ret = pInternetTimeToSystemTimeW( string3, &time, 0 ); + ok( ret, "InternetTimeToSystemTimeW failed (%u)\n", GetLastError() ); +} + +static void test_IsDomainLegalCookieDomainW(void) +{ + BOOL ret; + DWORD error; + static const WCHAR empty[] = {0}; + static const WCHAR dot[] = {'.',0}; + static const WCHAR uk[] = {'u','k',0}; + static const WCHAR com[] = {'c','o','m',0}; + static const WCHAR dot_com[] = {'.','c','o','m',0}; + static const WCHAR gmail_com[] = {'g','m','a','i','l','.','c','o','m',0}; + static const WCHAR dot_gmail_com[] = {'.','g','m','a','i','l','.','c','o','m',0}; + static const WCHAR mail_gmail_com[] = {'m','a','i','l','.','g','m','a','i','l','.','c','o','m',0}; + static const WCHAR gmail_co_uk[] = {'g','m','a','i','l','.','c','o','.','u','k',0}; + static const WCHAR co_uk[] = {'c','o','.','u','k',0}; + static const WCHAR dot_co_uk[] = {'.','c','o','.','u','k',0}; + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(NULL, NULL); + error = GetLastError(); + if (!ret && error == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("IsDomainLegalCookieDomainW is not implemented\n"); + return; + } + ok(!ret || + broken(ret), /* IE6 */ + "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(com, NULL); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(NULL, gmail_com); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(empty, gmail_com); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_NAME || + broken(error == ERROR_INVALID_PARAMETER), /* IE6 */ + "got %u expected ERROR_INVALID_NAME\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(com, empty); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_NAME || + broken(error == ERROR_INVALID_PARAMETER), /* IE6 */ + "got %u expected ERROR_INVALID_NAME\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(gmail_com, dot); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_NAME || + broken(error == 0xdeadbeef), /* IE6 */ + "got %u expected ERROR_INVALID_NAME\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(dot, gmail_com); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_NAME || + broken(error == 0xdeadbeef), /* IE6 */ + "got %u expected ERROR_INVALID_NAME\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(com, com); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == 0xdeadbeef, "got %u expected 0xdeadbeef\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(com, dot_com); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_NAME || + broken(error == 0xdeadbeef), /* IE6 */ + "got %u expected ERROR_INVALID_NAME\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(dot_com, com); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_NAME || + broken(error == 0xdeadbeef), /* IE6 */ + "got %u expected ERROR_INVALID_NAME\n", error); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(com, gmail_com); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_SXS_KEY_NOT_FOUND || + error == 0xdeadbeef, /* up to IE7 */ + "got %u expected ERROR_SXS_KEY_NOT_FOUND or 0xdeadbeef\n", error); + + ret = pIsDomainLegalCookieDomainW(gmail_com, gmail_com); + ok(ret, "IsDomainLegalCookieDomainW failed\n"); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(gmail_co_uk, co_uk); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_SXS_KEY_NOT_FOUND || /* IE8 on XP */ + error == ERROR_FILE_NOT_FOUND || /* IE8 on Vista */ + error == 0xdeadbeef, /* up to IE7 */ + "got %u expected ERROR_SXS_KEY_NOT_FOUND, ERROR_FILE_NOT_FOUND or " + "0xdeadbeef\n", error); + + ret = pIsDomainLegalCookieDomainW(uk, co_uk); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + + ret = pIsDomainLegalCookieDomainW(gmail_co_uk, dot_co_uk); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + + ret = pIsDomainLegalCookieDomainW(gmail_co_uk, gmail_co_uk); + ok(ret, "IsDomainLegalCookieDomainW failed\n"); + + ret = pIsDomainLegalCookieDomainW(gmail_com, com); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + + SetLastError(0xdeadbeef); + ret = pIsDomainLegalCookieDomainW(dot_gmail_com, mail_gmail_com); + error = GetLastError(); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + ok(error == ERROR_INVALID_NAME || + broken(error == 0xdeadbeef), /* IE6 */ + "got %u expected ERROR_INVALID_NAME\n", error); + + ret = pIsDomainLegalCookieDomainW(gmail_com, mail_gmail_com); + ok(ret, "IsDomainLegalCookieDomainW failed\n"); + + ret = pIsDomainLegalCookieDomainW(mail_gmail_com, gmail_com); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + + ret = pIsDomainLegalCookieDomainW(mail_gmail_com, com); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + + ret = pIsDomainLegalCookieDomainW(dot_gmail_com, mail_gmail_com); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); + + ret = pIsDomainLegalCookieDomainW(mail_gmail_com, dot_gmail_com); + ok(!ret, "IsDomainLegalCookieDomainW succeeded\n"); +} + /* ############################### */ START_TEST(internet) { + HMODULE hdll; + hdll = GetModuleHandleA("wininet.dll"); + pCreateUrlCacheContainerA = (void*)GetProcAddress(hdll, "CreateUrlCacheContainerA"); + pCreateUrlCacheContainerW = (void*)GetProcAddress(hdll, "CreateUrlCacheContainerW"); + pInternetTimeFromSystemTimeA = (void*)GetProcAddress(hdll, "InternetTimeFromSystemTimeA"); + pInternetTimeFromSystemTimeW = (void*)GetProcAddress(hdll, "InternetTimeFromSystemTimeW"); + pInternetTimeToSystemTimeA = (void*)GetProcAddress(hdll, "InternetTimeToSystemTimeA"); + pInternetTimeToSystemTimeW = (void*)GetProcAddress(hdll, "InternetTimeToSystemTimeW"); + pIsDomainLegalCookieDomainW = (void*)GetProcAddress(hdll, (LPCSTR)117); + test_InternetCanonicalizeUrlA(); test_InternetQueryOptionA(); test_get_cookie(); + test_complicated_cookie(); test_version(); test_null(); + + if (!pInternetTimeFromSystemTimeA) + win_skip("skipping the InternetTime tests\n"); + else + { + InternetTimeFromSystemTimeA_test(); + InternetTimeFromSystemTimeW_test(); + InternetTimeToSystemTimeA_test(); + InternetTimeToSystemTimeW_test(); +} + if (pIsDomainLegalCookieDomainW && + ((void*)pIsDomainLegalCookieDomainW == (void*)pCreateUrlCacheContainerA || + (void*)pIsDomainLegalCookieDomainW == (void*)pCreateUrlCacheContainerW)) + win_skip("IsDomainLegalCookieDomainW is not available on systems with IE5\n"); + else if (!pIsDomainLegalCookieDomainW) + win_skip("IsDomainLegalCookieDomainW (or ordinal 117) is not available\n"); + else + test_IsDomainLegalCookieDomainW(); } diff --git a/rostests/winetests/wininet/url.c b/rostests/winetests/wininet/url.c index ccc56076bad..a39251277c8 100644 --- a/rostests/winetests/wininet/url.c +++ b/rostests/winetests/wininet/url.c @@ -52,6 +52,7 @@ #define CREATE_URL10 "about://host/blank" #define CREATE_URL11 "about:" #define CREATE_URL12 "http://www.winehq.org:65535" +#define CREATE_URL13 "http://localhost/?test=123" static void copy_compsA( URL_COMPONENTSA *src, @@ -268,6 +269,7 @@ static void InternetCrackUrlW_test(void) '=','I','D','E','&','A','C','T','I','O','N','=','I','D','E','_','D','E','F','A', 'U','L','T', 0 }; static const WCHAR url2[] = { '.','.','/','R','i','t','z','.','x','m','l',0 }; + static const WCHAR url3[] = { 'h','t','t','p',':','/','/','x','.','o','r','g',0 }; URL_COMPONENTSW comp; WCHAR scheme[20], host[20], user[20], pwd[20], urlpart[50], extra[50]; DWORD error; @@ -297,14 +299,25 @@ static void InternetCrackUrlW_test(void) SetLastError(0xdeadbeef); r = InternetCrackUrlW(NULL, 0, 0, &comp ); error = GetLastError(); + if (!r && error == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("InternetCrackUrlW is not implemented\n"); + return; + } ok( !r, "InternetCrackUrlW succeeded unexpectedly\n"); - ok( error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", error); + ok( error == ERROR_INVALID_PARAMETER || + broken(error == ERROR_INTERNET_UNRECOGNIZED_SCHEME), /* IE5 */ + "expected ERROR_INVALID_PARAMETER got %u\n", error); + if (error == ERROR_INVALID_PARAMETER) + { + /* Crashes on IE5 */ SetLastError(0xdeadbeef); r = InternetCrackUrlW(url, 0, 0, NULL ); error = GetLastError(); ok( !r, "InternetCrackUrlW succeeded unexpectedly\n"); ok( error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", error); + } r = InternetCrackUrlW(url, 0, 0, &comp ); ok( r, "failed to crack url\n"); @@ -389,6 +402,32 @@ static void InternetCrackUrlW_test(void) "InternetCrackUrl should have failed with error ERROR_INTERNET_UNRECOGNIZED_SCHEME instead of error %d\n", GetLastError()); } + + /* Test to see whether cracking a URL without a filename initializes urlpart */ + urlpart[0]=0xba; + scheme[0]=0; + extra[0]=0; + host[0]=0; + user[0]=0; + pwd[0]=0; + memset(&comp, 0, sizeof comp); + comp.dwStructSize = sizeof comp; + comp.lpszScheme = scheme; + comp.dwSchemeLength = sizeof scheme; + comp.lpszHostName = host; + comp.dwHostNameLength = sizeof host; + comp.lpszUserName = user; + comp.dwUserNameLength = sizeof user; + comp.lpszPassword = pwd; + comp.dwPasswordLength = sizeof pwd; + comp.lpszUrlPath = urlpart; + comp.dwUrlPathLength = sizeof urlpart; + comp.lpszExtraInfo = extra; + comp.dwExtraInfoLength = sizeof extra; + r = InternetCrackUrlW(url3, 0, 0, &comp ); + ok( r, "InternetCrackUrlW failed unexpectedly\n"); + ok( host[0] == 'x', "host should be x.org\n"); + ok( urlpart[0] == 0, "urlpart should be empty\n"); } static void fill_url_components(LPURL_COMPONENTS lpUrlComponents) @@ -428,9 +467,12 @@ static void InternetCreateUrlA_test(void) http[] = "http", https[] = "https", winehq[] = "www.winehq.org", + localhost[] = "localhost", username[] = "username", password[] = "password", + root[] = "/", site_about[] = "/site/about", + extra_info[] = "?test=123", about[] = "about", blank[] = "blank", host[] = "host"; @@ -744,6 +786,26 @@ static void InternetCreateUrlA_test(void) ok(!strcmp(szUrl, CREATE_URL12), "Expected %s, got %s\n", CREATE_URL12, szUrl); HeapFree(GetProcessHeap(), 0, szUrl); + + memset(&urlComp, 0, sizeof(urlComp)); + urlComp.dwStructSize = sizeof(URL_COMPONENTS); + urlComp.lpszScheme = http; + urlComp.dwSchemeLength = strlen(urlComp.lpszScheme); + urlComp.lpszHostName = localhost; + urlComp.dwHostNameLength = strlen(urlComp.lpszHostName); + urlComp.nPort = 80; + urlComp.lpszUrlPath = root; + urlComp.dwUrlPathLength = strlen(urlComp.lpszUrlPath); + urlComp.lpszExtraInfo = extra_info; + urlComp.dwExtraInfoLength = strlen(urlComp.lpszExtraInfo); + len = 256; + szUrl = HeapAlloc(GetProcessHeap(), 0, len); + InternetCreateUrlA(&urlComp, ICU_ESCAPE, szUrl, &len); + ok(ret, "Expected success\n"); + ok(len == strlen(CREATE_URL13), "Got len %u\n", len); + ok(!strcmp(szUrl, CREATE_URL13), "Expected \"%s\", got \"%s\"\n", CREATE_URL13, szUrl); + + HeapFree(GetProcessHeap(), 0, szUrl); } START_TEST(url) diff --git a/rostests/winetests/wininet/urlcache.c b/rostests/winetests/wininet/urlcache.c index 6570d5a9eba..d13597626de 100644 --- a/rostests/winetests/wininet/urlcache.c +++ b/rostests/winetests/wininet/urlcache.c @@ -30,6 +30,9 @@ #define TEST_URL "http://urlcachetest.winehq.org/index.html" +static BOOL (WINAPI *pDeleteUrlCacheEntryA)(LPCSTR); +static BOOL (WINAPI *pUnlockUrlCacheEntryFileA)(LPCSTR,DWORD); + static char filenameA[MAX_PATH + 1]; static void check_cache_entry_infoA(const char *returnedfrom, LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo) @@ -109,9 +112,42 @@ static void test_GetUrlCacheEntryInfoExA(void) check_cache_entry_infoA("GetUrlCacheEntryInfoEx", lpCacheEntryInfo); + cbCacheEntryInfo = 100000; + SetLastError(0xdeadbeef); + ret = GetUrlCacheEntryInfoEx(TEST_URL, NULL, &cbCacheEntryInfo, NULL, NULL, NULL, 0); + ok(!ret, "GetUrlCacheEntryInfoEx with zero-length buffer should fail\n"); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetUrlCacheEntryInfoEx should have set last error to ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); } +static void test_RetrieveUrlCacheEntryA(void) +{ + BOOL ret; + DWORD cbCacheEntryInfo; + + cbCacheEntryInfo = 0; + SetLastError(0xdeadbeef); + ret = RetrieveUrlCacheEntryFile(NULL, NULL, &cbCacheEntryInfo, 0); + ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); + + if (0) + { + /* Crashes on Win9x, NT4 and W2K */ + SetLastError(0xdeadbeef); + ret = RetrieveUrlCacheEntryFile(TEST_URL, NULL, NULL, 0); + ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); + } + + SetLastError(0xdeadbeef); + cbCacheEntryInfo = 100000; + ret = RetrieveUrlCacheEntryFile(NULL, NULL, &cbCacheEntryInfo, 0); + ok(!ret, "RetrieveUrlCacheEntryFile should have failed\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "RetrieveUrlCacheEntryFile should have set last error to ERROR_INVALID_PARAMETER instead of %d\n", GetLastError()); +} + static void test_urlcacheA(void) { BOOL ret; @@ -150,23 +186,45 @@ static void test_urlcacheA(void) HeapFree(GetProcessHeap(), 0, lpCacheEntryInfo); - ret = UnlockUrlCacheEntryFile(TEST_URL, 0); - ok(ret, "UnlockUrlCacheEntryFile failed with error %d\n", GetLastError()); + if (pUnlockUrlCacheEntryFileA) + { + ret = pUnlockUrlCacheEntryFileA(TEST_URL, 0); + ok(ret, "UnlockUrlCacheEntryFileA failed with error %d\n", GetLastError()); + } /* test Find*UrlCacheEntry functions */ test_find_url_cache_entriesA(); test_GetUrlCacheEntryInfoExA(); + test_RetrieveUrlCacheEntryA(); - ret = DeleteUrlCacheEntry(TEST_URL); - ok(ret, "DeleteUrlCacheEntry failed with error %d\n", GetLastError()); + if (pDeleteUrlCacheEntryA) + { + ret = pDeleteUrlCacheEntryA(TEST_URL); + ok(ret, "DeleteUrlCacheEntryA failed with error %d\n", GetLastError()); + } ret = DeleteFile(filenameA); todo_wine ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND, "local file should no longer exist\n"); } +static void test_FindCloseUrlCache(void) +{ + BOOL r; + DWORD err; + r = FindCloseUrlCache(NULL); + err = GetLastError(); + ok(0 == r, "expected 0, got %d\n", r); + ok(ERROR_INVALID_HANDLE == err, "expected %d, got %d\n", ERROR_INVALID_HANDLE, err); +} + START_TEST(urlcache) { + HMODULE hdll; + hdll = GetModuleHandleA("wininet.dll"); + pDeleteUrlCacheEntryA = (void*)GetProcAddress(hdll, "DeleteUrlCacheEntryA"); + pUnlockUrlCacheEntryFileA = (void*)GetProcAddress(hdll, "UnlockUrlCacheEntryFileA"); test_urlcacheA(); + test_FindCloseUrlCache(); } diff --git a/rostests/winetests/wininet/wininet.rbuild b/rostests/winetests/wininet/wininet.rbuild index 5c759d72084..4edfeed88fd 100644 --- a/rostests/winetests/wininet/wininet.rbuild +++ b/rostests/winetests/wininet/wininet.rbuild @@ -3,12 +3,10 @@ . - 0x600 - 0x600 + wine wininet ws2_32 - kernel32 ntdll ftp.c generated.c diff --git a/rostests/winetests/winmm/capture.c b/rostests/winetests/winmm/capture.c new file mode 100644 index 00000000000..c46d35a64f4 --- /dev/null +++ b/rostests/winetests/winmm/capture.c @@ -0,0 +1,724 @@ +/* + * Test winmm sound capture in each sound format + * + * Copyright (c) 2002 Francois Gouget + * + * 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 + */ + +#include +#include +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "mmsystem.h" +#define NOBITMAP +#include "mmreg.h" + +extern GUID KSDATAFORMAT_SUBTYPE_PCM; +extern GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + +#include "winmm_test.h" + +static const char * wave_in_error(MMRESULT error) +{ + static char msg[1024]; + static char long_msg[1100]; + MMRESULT rc; + + rc = waveInGetErrorText(error, msg, sizeof(msg)); + if (rc != MMSYSERR_NOERROR) + sprintf(long_msg, "waveInGetErrorText(%x) failed with error %x", error, rc); + else + sprintf(long_msg, "%s(%s)", mmsys_error(error), msg); + return long_msg; +} + +static void check_position(int device, HWAVEIN win, DWORD bytes, + LPWAVEFORMATEX pwfx ) +{ + MMTIME mmtime; + DWORD samples; + double duration; + MMRESULT rc; + DWORD returned; + + samples=bytes/(pwfx->wBitsPerSample/8*pwfx->nChannels); + duration=((double)samples)/pwfx->nSamplesPerSec; + + mmtime.wType = TIME_BYTES; + rc=waveInGetPosition(win, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveInGetPosition(%s): rc=%s\n",dev_name(device),wave_in_error(rc)); + if (mmtime.wType != TIME_BYTES && winetest_debug > 1) + trace("waveInGetPosition(%s): TIME_BYTES not supported, returned %s\n", + dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveInGetPosition(%s): returned %d bytes, " + "should be %d\n", dev_name(device), returned, bytes); + + mmtime.wType = TIME_SAMPLES; + rc=waveInGetPosition(win, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveInGetPosition(%s): rc=%s\n",dev_name(device),wave_in_error(rc)); + if (mmtime.wType != TIME_SAMPLES && winetest_debug > 1) + trace("waveInGetPosition(%s): TIME_SAMPLES not supported, " + "returned %s\n",dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveInGetPosition(%s): returned %d samples, " + "should be %d\n", dev_name(device), bytes_to_samples(returned, pwfx), + bytes_to_samples(bytes, pwfx)); + + mmtime.wType = TIME_MS; + rc=waveInGetPosition(win, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveInGetPosition(%s): rc=%s\n",dev_name(device),wave_in_error(rc)); + if (mmtime.wType != TIME_MS && winetest_debug > 1) + trace("waveInGetPosition(%s): TIME_MS not supported, returned %s\n", + dev_name(device), wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveInGetPosition(%s): returned %d ms, " + "should be %d\n", dev_name(device), bytes_to_ms(returned, pwfx), + bytes_to_ms(bytes, pwfx)); + + mmtime.wType = TIME_SMPTE; + rc=waveInGetPosition(win, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveInGetPosition(%s): rc=%s\n",dev_name(device),wave_in_error(rc)); + if (mmtime.wType != TIME_SMPTE && winetest_debug > 1) + trace("waveInGetPosition(%s): TIME_SMPTE not supported, returned %s\n", + dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveInGetPosition(%s): SMPTE test failed\n", + dev_name(device)); + + mmtime.wType = TIME_MIDI; + rc=waveInGetPosition(win, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveInGetPosition(%s): rc=%s\n",dev_name(device),wave_in_error(rc)); + if (mmtime.wType != TIME_MIDI && winetest_debug > 1) + trace("waveInGetPosition(%s): TIME_MIDI not supported, returned %s\n", + dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveInGetPosition(%s): MIDI test failed\n", + dev_name(device)); + + mmtime.wType = TIME_TICKS; + rc=waveInGetPosition(win, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveInGetPosition(%s): rc=%s\n",dev_name(device),wave_in_error(rc)); + if (mmtime.wType != TIME_TICKS && winetest_debug > 1) + trace("waveInGetPosition(%s): TIME_TICKS not supported, returned %s\n", + dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveInGetPosition(%s): TICKS test failed\n", + dev_name(device)); +} + +static void wave_in_test_deviceIn(int device, LPWAVEFORMATEX pwfx, DWORD format, DWORD flags, LPWAVEINCAPS pcaps) +{ + HWAVEIN win; + HANDLE hevent; + WAVEHDR frag; + MMRESULT rc; + DWORD res; + WORD nChannels = pwfx->nChannels; + WORD wBitsPerSample = pwfx->wBitsPerSample; + DWORD nSamplesPerSec = pwfx->nSamplesPerSec; + + hevent=CreateEvent(NULL,FALSE,FALSE,NULL); + ok(hevent!=NULL,"CreateEvent(): error=%d\n",GetLastError()); + if (hevent==NULL) + return; + + win=NULL; + rc=waveInOpen(&win,device,pwfx,(DWORD_PTR)hevent,0,CALLBACK_EVENT|flags); + /* Note: Win9x doesn't know WAVE_FORMAT_DIRECT */ + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_BADDEVICEID || + rc==MMSYSERR_NOTENABLED || rc==MMSYSERR_NODRIVER || + rc==MMSYSERR_ALLOCATED || + ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + (flags & WAVE_FORMAT_DIRECT) && !(pcaps->dwFormats & format)) || + ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + (!(flags & WAVE_FORMAT_DIRECT) || (flags & WAVE_MAPPED)) && + !(pcaps->dwFormats & format)) || + (rc==MMSYSERR_INVALFLAG && (flags & WAVE_FORMAT_DIRECT)), + "waveInOpen(%s): format=%dx%2dx%d flags=%lx(%s) rc=%s\n", + dev_name(device),pwfx->nSamplesPerSec,pwfx->wBitsPerSample, + pwfx->nChannels,CALLBACK_EVENT|flags, + wave_open_flags(CALLBACK_EVENT|flags),wave_in_error(rc)); + if ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + (flags & WAVE_FORMAT_DIRECT) && (pcaps->dwFormats & format)) + trace(" Reason: The device lists this format as supported in it's " + "capabilities but opening it failed.\n"); + if ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + !(pcaps->dwFormats & format)) + trace("waveInOpen(%s): format=%dx%2dx%d %s rc=%s failed but format " + "not supported so OK.\n",dev_name(device),pwfx->nSamplesPerSec, + pwfx->wBitsPerSample,pwfx->nChannels, + flags & WAVE_FORMAT_DIRECT ? "flags=WAVE_FORMAT_DIRECT" : + flags & WAVE_MAPPED ? "flags=WAVE_MAPPED" : "", mmsys_error(rc)); + if (rc!=MMSYSERR_NOERROR) { + CloseHandle(hevent); + return; + } + res=WaitForSingleObject(hevent,1000); + ok(res==WAIT_OBJECT_0,"WaitForSingleObject failed for open\n"); + + ok(pwfx->nChannels==nChannels && + pwfx->wBitsPerSample==wBitsPerSample && + pwfx->nSamplesPerSec==nSamplesPerSec, + "got the wrong format: %dx%2dx%d instead of %dx%2dx%d\n", + pwfx->nSamplesPerSec, pwfx->wBitsPerSample, + pwfx->nChannels, nSamplesPerSec, wBitsPerSample, nChannels); + + /* Check that the position is 0 at start */ + check_position(device, win, 0, pwfx); + + frag.lpData=HeapAlloc(GetProcessHeap(), 0, pwfx->nAvgBytesPerSec); + frag.dwBufferLength=pwfx->nAvgBytesPerSec; + frag.dwBytesRecorded=0; + frag.dwUser=0; + frag.dwFlags=0; + frag.dwLoops=0; + frag.lpNext=0; + + rc=waveInPrepareHeader(win, &frag, sizeof(frag)); + ok(rc==MMSYSERR_NOERROR, "waveInPrepareHeader(%s): rc=%s\n", + dev_name(device),wave_in_error(rc)); + ok(frag.dwFlags&WHDR_PREPARED,"waveInPrepareHeader(%s): prepared flag " + "not set\n",dev_name(device)); + + if (winetest_interactive && rc==MMSYSERR_NOERROR) { + trace("Recording for 1 second at %5dx%2dx%d %s %s\n", + pwfx->nSamplesPerSec, pwfx->wBitsPerSample,pwfx->nChannels, + get_format_str(pwfx->wFormatTag), + flags & WAVE_FORMAT_DIRECT ? "WAVE_FORMAT_DIRECT" : + flags & WAVE_MAPPED ? "WAVE_MAPPED" : ""); + rc=waveInAddBuffer(win, &frag, sizeof(frag)); + ok(rc==MMSYSERR_NOERROR,"waveInAddBuffer(%s): rc=%s\n", + dev_name(device),wave_in_error(rc)); + + /* Check that the position is 0 at start */ + check_position(device, win, 0, pwfx); + + rc=waveInStart(win); + ok(rc==MMSYSERR_NOERROR,"waveInStart(%s): rc=%s\n", + dev_name(device),wave_in_error(rc)); + + res = WaitForSingleObject(hevent,1200); + ok(res==WAIT_OBJECT_0,"WaitForSingleObject failed for header\n"); + ok(frag.dwFlags&WHDR_DONE,"WHDR_DONE not set in frag.dwFlags\n"); + ok(frag.dwBytesRecorded==pwfx->nAvgBytesPerSec, + "frag.dwBytesRecorded=%d, should=%d\n", + frag.dwBytesRecorded,pwfx->nAvgBytesPerSec); + + /* stop playing on error */ + if (res!=WAIT_OBJECT_0) { + rc=waveInStop(win); + ok(rc==MMSYSERR_NOERROR, + "waveInStop(%s): rc=%s\n",dev_name(device),wave_in_error(rc)); + } + } + + rc=waveInUnprepareHeader(win, &frag, sizeof(frag)); + ok(rc==MMSYSERR_NOERROR,"waveInUnprepareHeader(%s): rc=%s\n", + dev_name(device),wave_in_error(rc)); + + rc=waveInClose(win); + ok(rc==MMSYSERR_NOERROR, + "waveInClose(%s): rc=%s\n",dev_name(device),wave_in_error(rc)); + res=WaitForSingleObject(hevent,1000); + ok(res==WAIT_OBJECT_0,"WaitForSingleObject failed for close\n"); + + if (winetest_interactive) + { + /* + * Now play back what we recorded + */ + HWAVEOUT wout; + + trace("Playing back recorded sound\n"); + rc=waveOutOpen(&wout,WAVE_MAPPER,pwfx,(DWORD_PTR)hevent,0,CALLBACK_EVENT); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_BADDEVICEID || + rc==MMSYSERR_NOTENABLED || rc==MMSYSERR_NODRIVER || + rc==MMSYSERR_ALLOCATED || + ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + !(pcaps->dwFormats & format)), + "waveOutOpen(%s) format=%dx%2dx%d flags=%lx(%s) rc=%s\n", + dev_name(device),pwfx->nSamplesPerSec,pwfx->wBitsPerSample, + pwfx->nChannels,CALLBACK_EVENT|flags, + wave_open_flags(CALLBACK_EVENT),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) + { + rc=waveOutPrepareHeader(wout, &frag, sizeof(frag)); + ok(rc==MMSYSERR_NOERROR,"waveOutPrepareHeader(%s): rc=%s\n", + dev_name(device),wave_out_error(rc)); + + if (rc==MMSYSERR_NOERROR) + { + WaitForSingleObject(hevent,INFINITE); + rc=waveOutWrite(wout, &frag, sizeof(frag)); + ok(rc==MMSYSERR_NOERROR,"waveOutWrite(%s): rc=%s\n", + dev_name(device),wave_out_error(rc)); + WaitForSingleObject(hevent,INFINITE); + + rc=waveOutUnprepareHeader(wout, &frag, sizeof(frag)); + ok(rc==MMSYSERR_NOERROR,"waveOutUnprepareHeader(%s): rc=%s\n", + dev_name(device),wave_out_error(rc)); + } + rc=waveOutClose(wout); + ok(rc==MMSYSERR_NOERROR,"waveOutClose(%s): rc=%s\n", + dev_name(device),wave_out_error(rc)); + } + else + trace("Unable to play back the recorded sound\n"); + } + + HeapFree(GetProcessHeap(), 0, frag.lpData); + CloseHandle(hevent); +} + +static void wave_in_test_device(UINT_PTR device) +{ + WAVEINCAPSA capsA; + WAVEINCAPSW capsW; + WAVEFORMATEX format,oformat; + WAVEFORMATEXTENSIBLE wfex; + HWAVEIN win; + MMRESULT rc; + UINT f; + WCHAR * nameW; + CHAR * nameA; + DWORD size; + DWORD dwPageSize; + BYTE * twoPages; + SYSTEM_INFO sSysInfo; + DWORD flOldProtect; + BOOL res; + + GetSystemInfo(&sSysInfo); + dwPageSize = sSysInfo.dwPageSize; + + rc=waveInGetDevCapsA(device,&capsA,sizeof(capsA)); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_BADDEVICEID || + rc==MMSYSERR_NODRIVER, + "waveInGetDevCapsA(%s): failed to get capabilities: rc=%s\n", + dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER) + return; + + rc=waveInGetDevCapsW(device,&capsW,sizeof(capsW)); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED, + "waveInGetDevCapsW(%s): MMSYSERR_NOERROR or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(device),wave_in_error(rc)); + + rc=waveInGetDevCapsA(device,NULL,sizeof(capsA)); + ok(rc==MMSYSERR_INVALPARAM, + "waveInGetDevCapsA(%s): MMSYSERR_INVALPARAM expected, got %s\n", + dev_name(device),wave_in_error(rc)); + + rc=waveInGetDevCapsW(device,NULL,sizeof(capsW)); + ok(rc==MMSYSERR_INVALPARAM || rc==MMSYSERR_NOTSUPPORTED, + "waveInGetDevCapsW(%s): MMSYSERR_INVALPARAM or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(device),wave_in_error(rc)); + + if (0) + { + /* FIXME: this works on windows but crashes wine */ + rc=waveInGetDevCapsA(device,(LPWAVEINCAPSA)1,sizeof(capsA)); + ok(rc==MMSYSERR_INVALPARAM, + "waveInGetDevCapsA(%s): MMSYSERR_INVALPARAM expected, got %s\n", + dev_name(device),wave_in_error(rc)); + + rc=waveInGetDevCapsW(device,(LPWAVEINCAPSW)1,sizeof(capsW)); + ok(rc==MMSYSERR_INVALPARAM || rc==MMSYSERR_NOTSUPPORTED, + "waveInGetDevCapsW(%s): MMSYSERR_INVALPARAM or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(device),wave_in_error(rc)); + } + + rc=waveInGetDevCapsA(device,&capsA,4); + ok(rc==MMSYSERR_NOERROR, + "waveInGetDevCapsA(%s): MMSYSERR_NOERROR expected, got %s\n", + dev_name(device),wave_in_error(rc)); + + rc=waveInGetDevCapsW(device,&capsW,4); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED || + rc==MMSYSERR_INVALPARAM, /* Vista, W2K8 */ + "waveInGetDevCapsW(%s): unexpected return value %s\n", + dev_name(device),wave_in_error(rc)); + + nameA=NULL; + rc=waveInMessage((HWAVEIN)device, DRV_QUERYDEVICEINTERFACESIZE, + (DWORD_PTR)&size, 0); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_INVALPARAM || + rc==MMSYSERR_NOTSUPPORTED, + "waveInMessage(%s): failed to get interface size: rc=%s\n", + dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + nameW = HeapAlloc(GetProcessHeap(), 0, size); + rc=waveInMessage((HWAVEIN)device, DRV_QUERYDEVICEINTERFACE, + (DWORD_PTR)nameW, size); + ok(rc==MMSYSERR_NOERROR,"waveInMessage(%s): failed to get interface " + "name: rc=%s\n",dev_name(device),wave_in_error(rc)); + ok(lstrlenW(nameW)+1==size/sizeof(WCHAR), + "got an incorrect size %d\n", size); + if (rc==MMSYSERR_NOERROR) { + nameA = HeapAlloc(GetProcessHeap(), 0, size/sizeof(WCHAR)); + WideCharToMultiByte(CP_ACP, 0, nameW, size/sizeof(WCHAR), + nameA, size/sizeof(WCHAR), NULL, NULL); + } + HeapFree(GetProcessHeap(), 0, nameW); + } else if (rc==MMSYSERR_NOTSUPPORTED) { + nameA=HeapAlloc(GetProcessHeap(), 0, sizeof("not supported")); + strcpy(nameA, "not supported"); + } + + trace(" %s: \"%s\" (%s) %d.%d (%d:%d)\n",dev_name(device),capsA.szPname, + (nameA?nameA:"failed"),capsA.vDriverVersion >> 8, + capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid); + trace(" channels=%d formats=%05x\n", + capsA.wChannels,capsA.dwFormats); + + HeapFree(GetProcessHeap(), 0, nameA); + + for (f=0;fwFormatTag=WAVE_FORMAT_PCM; + pwfx->nChannels=1; + pwfx->wBitsPerSample=8; + pwfx->nSamplesPerSec=22050; + pwfx->nBlockAlign=pwfx->nChannels*pwfx->wBitsPerSample/8; + pwfx->nAvgBytesPerSec=pwfx->nSamplesPerSec*pwfx->nBlockAlign; + wave_in_test_deviceIn(device,pwfx,WAVE_FORMAT_2M08,0, &capsA); + if (device != WAVE_MAPPER) { + wave_in_test_deviceIn(device,pwfx,WAVE_FORMAT_2M08, + WAVE_FORMAT_DIRECT, &capsA); + wave_in_test_deviceIn(device,pwfx,WAVE_FORMAT_2M08, + WAVE_MAPPED, &capsA); + } + } + VirtualFree(twoPages, 2 * dwPageSize, MEM_RELEASE); + } + + /* Testing invalid format: 2 MHz sample rate */ + format.wFormatTag=WAVE_FORMAT_PCM; + format.nChannels=2; + format.wBitsPerSample=16; + format.nSamplesPerSec=2000000; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + oformat=format; + rc=waveInOpen(&win,device,&format,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==WAVERR_BADFORMAT || rc==MMSYSERR_INVALFLAG || + rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): opening the device with 2 MHz sample rate should fail: " + " rc=%s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + trace(" got %dx%2dx%d for %dx%2dx%d\n", + format.nSamplesPerSec, format.wBitsPerSample, + format.nChannels, + oformat.nSamplesPerSec, oformat.wBitsPerSample, + oformat.nChannels); + waveInClose(win); + } + + /* test non PCM formats */ + format.wFormatTag=WAVE_FORMAT_MULAW; + format.nChannels=1; + format.wBitsPerSample=8; + format.nSamplesPerSec=8000; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + rc=waveInOpen(&win,device,&format,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): returned: %s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveInClose(win); + wave_in_test_deviceIn(device,&format,0,0,&capsA); + } else + trace("waveInOpen(%s): WAVE_FORMAT_MULAW not supported\n", + dev_name(device)); + + format.wFormatTag=WAVE_FORMAT_ADPCM; + format.nChannels=2; + format.wBitsPerSample=4; + format.nSamplesPerSec=22050; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + rc=waveInOpen(&win,device,&format,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): returned: %s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveInClose(win); + wave_in_test_deviceIn(device,&format,0,0,&capsA); + } else + trace("waveInOpen(%s): WAVE_FORMAT_ADPCM not supported\n", + dev_name(device)); + + /* test if WAVEFORMATEXTENSIBLE supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=2; + wfex.Format.wBitsPerSample=16; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveInOpen(&win,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): returned: %s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveInClose(win); + wave_in_test_deviceIn(device,&wfex.Format,0,0,&capsA); + } else + trace("waveInOpen(%s): WAVE_FORMAT_EXTENSIBLE not supported\n", + dev_name(device)); + + /* test if 4 channels supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=4; + wfex.Format.wBitsPerSample=16; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveInOpen(&win,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): returned: %s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveInClose(win); + wave_in_test_deviceIn(device,&wfex.Format,0,0,&capsA); + } else + trace("waveInOpen(%s): 4 channels not supported\n", + dev_name(device)); + + /* test if 6 channels supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=6; + wfex.Format.wBitsPerSample=16; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveInOpen(&win,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): returned: %s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveInClose(win); + wave_in_test_deviceIn(device,&wfex.Format,0,0,&capsA); + } else + trace("waveInOpen(%s): 6 channels not supported\n", + dev_name(device)); + + if (0) + { + /* FIXME: ALSA doesn't like this */ + /* test if 24 bit samples supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=2; + wfex.Format.wBitsPerSample=24; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveInOpen(&win,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): returned: %s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveInClose(win); + wave_in_test_deviceIn(device,&wfex.Format,0,0,&capsA); + } else + trace("waveInOpen(%s): 24 bit samples not supported\n", + dev_name(device)); + } + + /* test if 32 bit samples supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=2; + wfex.Format.wBitsPerSample=32; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveInOpen(&win,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): returned: %s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveInClose(win); + wave_in_test_deviceIn(device,&wfex.Format,0,0,&capsA); + } else + trace("waveInOpen(%s): 32 bit samples not supported\n", + dev_name(device)); + + /* test if 32 bit float samples supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=2; + wfex.Format.wBitsPerSample=32; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + rc=waveInOpen(&win,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveInOpen(%s): returned: %s\n",dev_name(device),wave_in_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveInClose(win); + wave_in_test_deviceIn(device,&wfex.Format,0,0,&capsA); + } else + trace("waveInOpen(%s): 32 bit float samples not supported\n", + dev_name(device)); +} + +static void wave_in_tests(void) +{ + WAVEINCAPSA capsA; + WAVEINCAPSW capsW; + WAVEFORMATEX format; + HWAVEIN win; + MMRESULT rc; + UINT ndev,d; + + ndev=waveInGetNumDevs(); + trace("found %d WaveIn devices\n",ndev); + + rc=waveInGetDevCapsA(ndev+1,&capsA,sizeof(capsA)); + ok(rc==MMSYSERR_BADDEVICEID, + "waveInGetDevCapsA(%s): MMSYSERR_BADDEVICEID expected, got %s\n", + dev_name(ndev+1),wave_in_error(rc)); + + rc=waveInGetDevCapsA(WAVE_MAPPER,&capsA,sizeof(capsA)); + if (ndev>0) + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NODRIVER, + "waveInGetDevCapsA(%s): MMSYSERR_NOERROR or MMSYSERR_NODRIVER " + "expected, got %s\n",dev_name(WAVE_MAPPER),wave_in_error(rc)); + else + ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER, + "waveInGetDevCapsA(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NODRIVER " + "expected, got %s\n",dev_name(WAVE_MAPPER),wave_in_error(rc)); + + rc=waveInGetDevCapsW(ndev+1,&capsW,sizeof(capsW)); + ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NOTSUPPORTED, + "waveInGetDevCapsW(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(ndev+1),wave_in_error(rc)); + + rc=waveInGetDevCapsW(WAVE_MAPPER,&capsW,sizeof(capsW)); + if (ndev>0) + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NODRIVER || + rc==MMSYSERR_NOTSUPPORTED, + "waveInGetDevCapsW(%s): MMSYSERR_NOERROR or MMSYSERR_NODRIVER or " + "MMSYSERR_NOTSUPPORTED expected, got %s\n", + dev_name(ndev+1),wave_in_error(rc)); + else + ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER || + rc==MMSYSERR_NOTSUPPORTED, + "waveInGetDevCapsW(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NODRIVER or" + "MMSYSERR_NOTSUPPORTED expected, got %s\n", + dev_name(ndev+1),wave_in_error(rc)); + + format.wFormatTag=WAVE_FORMAT_PCM; + format.nChannels=2; + format.wBitsPerSample=16; + format.nSamplesPerSec=44100; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + rc=waveInOpen(&win,ndev+1,&format,0,0,CALLBACK_NULL); + ok(rc==MMSYSERR_BADDEVICEID, + "waveInOpen(%s): MMSYSERR_BADDEVICEID expected, got %s\n", + dev_name(ndev+1),wave_in_error(rc)); + + for (d=0;d0) + wave_in_test_device(WAVE_MAPPER); +} + +START_TEST(capture) +{ + wave_in_tests(); +} diff --git a/rostests/winetests/winmm/mci.c b/rostests/winetests/winmm/mci.c new file mode 100644 index 00000000000..5f8698507a8 --- /dev/null +++ b/rostests/winetests/winmm/mci.c @@ -0,0 +1,70 @@ +/* + * Test winmm mci + * + * Copyright 2006 Jan Zerebecki + * + * 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 + */ + +#include "wine/test.h" +#include "winuser.h" +#include "mmsystem.h" + +START_TEST(mci) +{ + int err; + const char command_open[] = "open new type waveaudio alias mysound"; + const char command_close_my[] = "close mysound notify"; + const char command_close_all[] = "close all notify"; + const char command_sysinfo[] = "sysinfo waveaudio quantity open"; + MSG msg; + char buf[1024]; + HWND hwnd; + + hwnd = CreateWindowExA(0, "static", "winmm test", WS_POPUP, 0,0,100,100, + 0, 0, 0, NULL); + + err = mciSendString(command_open, NULL, 0, NULL); + ok(!err,"mciSendString(%s, NULL, 0 , NULL) returned error: %d\n", command_open, err); + + err = mciSendString(command_close_my, NULL, 0, hwnd); + ok(!err,"mciSendString(%s, NULL, 0 , NULL) returned error: %d\n", command_close_my, err); + + ok(PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n"); + ok(msg.hwnd == hwnd, "Didn't get the handle to our test window\n"); + ok(msg.message == MM_MCINOTIFY, "got %04x instead of MM_MCINOTIFY\n", msg.message); + ok(msg.wParam == MCI_NOTIFY_SUCCESSFUL, "got %08lx instead of MCI_NOTIFY_SUCCESSFUL\n", msg.wParam); + + err = mciSendString(command_close_all, NULL, 0, NULL); + todo_wine ok(!err,"mciSendString(%s, NULL, 0 , NULL) returned error: %d\n", command_close_all, err); + + memset(buf, 0, sizeof(buf)); + err = mciSendString(command_close_all, buf, sizeof(buf), hwnd); + todo_wine ok(!err,"mciSendString(%s, buf, sizeof(buf) , NULL) returned error: %d\n", command_close_all, err); + ok(buf[0] == 0, "mciSendString(%s, buf, sizeof(buf) , NULL) changed output buffer: %s\n", command_close_all, buf); + + memset(buf, 0, sizeof(buf)); + err = mciSendString(command_sysinfo, buf, sizeof(buf), NULL); + ok(!err,"mciSendString(%s, buf, sizeof(buf) , NULL) returned error: %d\n", command_sysinfo, err); + todo_wine ok(buf[0] == '0' && buf[1] == 0, "mciSendString(%s, buf, sizeof(buf) , NULL), expected output buffer '0', got: '%s'\n", command_sysinfo, buf); + + err = mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_NOTIFY, 0); + todo_wine ok(err == MCIERR_INVALID_DEVICE_ID || + broken(!err), /* Win9x and WinMe */ + "mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_NOTIFY, NULL) returned %d instead of %d\n", + err, MCIERR_INVALID_DEVICE_ID); + + DestroyWindow(hwnd); +} diff --git a/rostests/winetests/winmm/mixer.c b/rostests/winetests/winmm/mixer.c new file mode 100644 index 00000000000..59627a7b38f --- /dev/null +++ b/rostests/winetests/winmm/mixer.c @@ -0,0 +1,1065 @@ +/* + * Test mixer + * + * Copyright (c) 2004 Robert Reif + * + * 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 + */ + +/* + * To Do: + * add interactive tests + */ + +#include +#include +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "mmsystem.h" + +#include "winmm_test.h" + +static const char * line_flags(DWORD fdwLine) +{ + static char flags[100]; + BOOL first=TRUE; + flags[0]=0; + if (fdwLine&MIXERLINE_LINEF_ACTIVE) { + strcat(flags,"MIXERLINE_LINEF_ACTIVE"); + first=FALSE; + } + if (fdwLine&MIXERLINE_LINEF_DISCONNECTED) { + if (!first) + strcat(flags, "|"); + + strcat(flags,"MIXERLINE_LINEF_DISCONNECTED"); + first=FALSE; + } + + if (fdwLine&MIXERLINE_LINEF_SOURCE) { + if (!first) + strcat(flags, "|"); + + strcat(flags,"MIXERLINE_LINEF_SOURCE"); + } + + return flags; +} + +static const char * component_type(DWORD dwComponentType) +{ +#define TYPE_TO_STR(x) case x: return #x + switch (dwComponentType) { + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_UNDEFINED); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_DIGITAL); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_LINE); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_MONITOR); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_HEADPHONES); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_TELEPHONE); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_WAVEIN); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_VOICEIN); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_DIGITAL); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_LINE); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY); + TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_ANALOG); + } +#undef TYPE_TO_STR + return "UNKNOWN"; +} + +static const char * target_type(DWORD dwType) +{ +#define TYPE_TO_STR(x) case x: return #x + switch (dwType) { + TYPE_TO_STR(MIXERLINE_TARGETTYPE_UNDEFINED); + TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEOUT); + TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEIN); + TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIOUT); + TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIIN); + TYPE_TO_STR(MIXERLINE_TARGETTYPE_AUX); + } +#undef TYPE_TO_STR + return "UNKNOWN"; +} + +static const char * control_type(DWORD dwControlType) +{ +#define TYPE_TO_STR(x) case x: return #x + switch (dwControlType) { + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_CUSTOM); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEANMETER); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNEDMETER); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PEAKMETER); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEAN); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_ONOFF); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUTE); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MONO); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_LOUDNESS); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_STEREOENH); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS_BOOST); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BUTTON); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_DECIBELS); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNED); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNED); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PERCENT); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SLIDER); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PAN); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_QSOUNDPAN); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_FADER); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_VOLUME); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_TREBLE); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_EQUALIZER); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SINGLESELECT); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUX); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MIXER); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MICROTIME); + TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MILLITIME); + } +#undef TYPE_TO_STR + return "UNKNOWN"; +} + +static const char * control_flags(DWORD fdwControl) +{ + static char flags[100]; + BOOL first=TRUE; + flags[0]=0; + if (fdwControl&MIXERCONTROL_CONTROLF_UNIFORM) { + strcat(flags,"MIXERCONTROL_CONTROLF_UNIFORM"); + first=FALSE; + } + if (fdwControl&MIXERCONTROL_CONTROLF_MULTIPLE) { + if (!first) + strcat(flags, "|"); + + strcat(flags,"MIXERCONTROL_CONTROLF_MULTIPLE"); + first=FALSE; + } + + if (fdwControl&MIXERCONTROL_CONTROLF_DISABLED) { + if (!first) + strcat(flags, "|"); + + strcat(flags,"MIXERCONTROL_CONTROLF_DISABLED"); + } + + return flags; +} + +static void test_mixerClose(HMIXER mix) +{ + MMRESULT rc; + + rc = mixerClose(mix); + ok(rc == MMSYSERR_NOERROR || rc == MMSYSERR_INVALHANDLE, + "mixerClose: MMSYSERR_NOERROR or MMSYSERR_INVALHANDLE expected, got %s\n", + mmsys_error(rc)); +} + +static void mixer_test_controlA(HMIXER mix, LPMIXERCONTROLA control) +{ + MMRESULT rc; + + if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) || + (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) { + MIXERCONTROLDETAILS details; + MIXERCONTROLDETAILS_UNSIGNED value; + + details.cbStruct = sizeof(MIXERCONTROLDETAILS); + details.dwControlID = control->dwControlID; + details.cChannels = 1; + U(details).cMultipleItems = 0; + details.paDetails = &value; + details.cbDetails = sizeof(value); + + /* read the current control value */ + rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR && winetest_interactive) { + MIXERCONTROLDETAILS new_details; + MIXERCONTROLDETAILS_UNSIGNED new_value; + + trace(" Value=%d\n",value.dwValue); + + if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum) + new_value.dwValue = value.dwValue + control->Metrics.cSteps; + else + new_value.dwValue = value.dwValue - control->Metrics.cSteps; + + new_details.cbStruct = sizeof(MIXERCONTROLDETAILS); + new_details.dwControlID = control->dwControlID; + new_details.cChannels = 1; + U(new_details).cMultipleItems = 0; + new_details.paDetails = &new_value; + new_details.cbDetails = sizeof(new_value); + + /* change the control value by one step */ + rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + MIXERCONTROLDETAILS ret_details; + MIXERCONTROLDETAILS_UNSIGNED ret_value; + + ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS); + ret_details.dwControlID = control->dwControlID; + ret_details.cChannels = 1; + U(ret_details).cMultipleItems = 0; + ret_details.paDetails = &ret_value; + ret_details.cbDetails = sizeof(ret_value); + + /* read back the new control value */ + rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + /* result may not match exactly because of rounding */ + ok(abs(ret_value.dwValue-new_value.dwValue)<=1, + "Couldn't change value from %d to %d, returned %d\n", + value.dwValue,new_value.dwValue,ret_value.dwValue); + + if (abs(ret_value.dwValue-new_value.dwValue)<=1) { + details.cbStruct = sizeof(MIXERCONTROLDETAILS); + details.dwControlID = control->dwControlID; + details.cChannels = 1; + U(details).cMultipleItems = 0; + details.paDetails = &value; + details.cbDetails = sizeof(value); + + /* restore original value */ + rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + } + } + } + } + } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) || + (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) || + (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) { + MIXERCONTROLDETAILS details; + MIXERCONTROLDETAILS_BOOLEAN value; + + details.cbStruct = sizeof(MIXERCONTROLDETAILS); + details.dwControlID = control->dwControlID; + details.cChannels = 1; + U(details).cMultipleItems = 0; + details.paDetails = &value; + details.cbDetails = sizeof(value); + + rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR && winetest_interactive) { + MIXERCONTROLDETAILS new_details; + MIXERCONTROLDETAILS_BOOLEAN new_value; + + trace(" Value=%d\n",value.fValue); + + if (value.fValue == FALSE) + new_value.fValue = TRUE; + else + new_value.fValue = FALSE; + + new_details.cbStruct = sizeof(MIXERCONTROLDETAILS); + new_details.dwControlID = control->dwControlID; + new_details.cChannels = 1; + U(new_details).cMultipleItems = 0; + new_details.paDetails = &new_value; + new_details.cbDetails = sizeof(new_value); + + /* change the control value by one step */ + rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + MIXERCONTROLDETAILS ret_details; + MIXERCONTROLDETAILS_BOOLEAN ret_value; + + ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS); + ret_details.dwControlID = control->dwControlID; + ret_details.cChannels = 1; + U(ret_details).cMultipleItems = 0; + ret_details.paDetails = &ret_value; + ret_details.cbDetails = sizeof(ret_value); + + /* read back the new control value */ + rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + /* result may not match exactly because of rounding */ + ok(ret_value.fValue==new_value.fValue, + "Couldn't change value from %d to %d, returned %d\n", + value.fValue,new_value.fValue,ret_value.fValue); + + if (ret_value.fValue==new_value.fValue) { + details.cbStruct = sizeof(MIXERCONTROLDETAILS); + details.dwControlID = control->dwControlID; + details.cChannels = 1; + U(details).cMultipleItems = 0; + details.paDetails = &value; + details.cbDetails = sizeof(value); + + /* restore original value */ + rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + } + } + } + } + } else { + /* FIXME */ + } +} + +static void mixer_test_deviceA(int device) +{ + MIXERCAPSA capsA; + HMIXER mix; + MMRESULT rc; + DWORD d,s,ns,nc; + + rc=mixerGetDevCapsA(device,0,sizeof(capsA)); + ok(rc==MMSYSERR_INVALPARAM, + "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n", + mmsys_error(rc)); + + rc=mixerGetDevCapsA(device,&capsA,4); + ok(rc==MMSYSERR_NOERROR, + "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + + rc=mixerGetDevCapsA(device,&capsA,sizeof(capsA)); + ok(rc==MMSYSERR_NOERROR, + "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + + if (winetest_interactive) { + trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%d\n", device, + capsA.szPname, capsA.vDriverVersion >> 8, + capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid, + capsA.cDestinations); + } else { + trace(" %d: \"%s\" %d.%d (%d:%d)\n", device, + capsA.szPname, capsA.vDriverVersion >> 8, + capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid); + } + + rc=mixerOpen(&mix, device, 0, 0, 0); + ok(rc==MMSYSERR_NOERROR, + "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + for (d=0;d> 8, + mixerlineA.Target.vDriverVersion & 0xff, + mixerlineA.Target.wMid, mixerlineA.Target.wPid); + } + ns=mixerlineA.cConnections; + for(s=0;s> 8, + mixerlineA.Target.vDriverVersion & 0xff, + mixerlineA.Target.wMid, mixerlineA.Target.wPid); + } + if (mixerlineA.cControls) { + array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + mixerlineA.cControls*sizeof(MIXERCONTROLA)); + if (array) { + memset(&controls, 0, sizeof(controls)); + + rc=mixerGetLineControlsA((HMIXEROBJ)mix,0, + MIXER_GETLINECONTROLSF_ALL); + ok(rc==MMSYSERR_INVALPARAM, + "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): " + "MMSYSERR_INVALPARAM expected, got %s\n", + mmsys_error(rc)); + + rc=mixerGetLineControlsA((HMIXEROBJ)mix,&controls,-1); + ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM, + "mixerGetLineControlsA(-1): " + "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n", + mmsys_error(rc)); + + controls.cbStruct = sizeof(MIXERLINECONTROLSA); + controls.cControls = mixerlineA.cControls; + controls.dwLineID = mixerlineA.dwLineID; + controls.pamxctrl = array; + controls.cbmxctrl = sizeof(MIXERCONTROLA); + + /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID + * and MIXER_GETLINECONTROLSF_ONEBYTYPE + */ + rc=mixerGetLineControlsA((HMIXEROBJ)mix,&controls, + MIXER_GETLINECONTROLSF_ALL); + ok(rc==MMSYSERR_NOERROR, + "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + for(nc=0;ncdwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) || + (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) { + MIXERCONTROLDETAILS details; + MIXERCONTROLDETAILS_UNSIGNED value; + + details.cbStruct = sizeof(MIXERCONTROLDETAILS); + details.dwControlID = control->dwControlID; + details.cChannels = 1; + U(details).cMultipleItems = 0; + details.paDetails = &value; + details.cbDetails = sizeof(value); + + /* read the current control value */ + rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR && winetest_interactive) { + MIXERCONTROLDETAILS new_details; + MIXERCONTROLDETAILS_UNSIGNED new_value; + + trace(" Value=%d\n",value.dwValue); + + if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum) + new_value.dwValue = value.dwValue + control->Metrics.cSteps; + else + new_value.dwValue = value.dwValue - control->Metrics.cSteps; + + new_details.cbStruct = sizeof(MIXERCONTROLDETAILS); + new_details.dwControlID = control->dwControlID; + new_details.cChannels = 1; + U(new_details).cMultipleItems = 0; + new_details.paDetails = &new_value; + new_details.cbDetails = sizeof(new_value); + + /* change the control value by one step */ + rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + MIXERCONTROLDETAILS ret_details; + MIXERCONTROLDETAILS_UNSIGNED ret_value; + + ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS); + ret_details.dwControlID = control->dwControlID; + ret_details.cChannels = 1; + U(ret_details).cMultipleItems = 0; + ret_details.paDetails = &ret_value; + ret_details.cbDetails = sizeof(ret_value); + + /* read back the new control value */ + rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + /* result may not match exactly because of rounding */ + ok(abs(ret_value.dwValue-new_value.dwValue)<=1, + "Couldn't change value from %d to %d, returned %d\n", + value.dwValue,new_value.dwValue,ret_value.dwValue); + + if (abs(ret_value.dwValue-new_value.dwValue)<=1) { + details.cbStruct = sizeof(MIXERCONTROLDETAILS); + details.dwControlID = control->dwControlID; + details.cChannels = 1; + U(details).cMultipleItems = 0; + details.paDetails = &value; + details.cbDetails = sizeof(value); + + /* restore original value */ + rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + } + } + } + } + } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) || + (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) || + (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) { + MIXERCONTROLDETAILS details; + MIXERCONTROLDETAILS_BOOLEAN value; + + details.cbStruct = sizeof(MIXERCONTROLDETAILS); + details.dwControlID = control->dwControlID; + details.cChannels = 1; + U(details).cMultipleItems = 0; + details.paDetails = &value; + details.cbDetails = sizeof(value); + + rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR && winetest_interactive) { + MIXERCONTROLDETAILS new_details; + MIXERCONTROLDETAILS_BOOLEAN new_value; + + trace(" Value=%d\n",value.fValue); + + if (value.fValue == FALSE) + new_value.fValue = TRUE; + else + new_value.fValue = FALSE; + + new_details.cbStruct = sizeof(MIXERCONTROLDETAILS); + new_details.dwControlID = control->dwControlID; + new_details.cChannels = 1; + U(new_details).cMultipleItems = 0; + new_details.paDetails = &new_value; + new_details.cbDetails = sizeof(new_value); + + /* change the control value by one step */ + rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + MIXERCONTROLDETAILS ret_details; + MIXERCONTROLDETAILS_BOOLEAN ret_value; + + ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS); + ret_details.dwControlID = control->dwControlID; + ret_details.cChannels = 1; + U(ret_details).cMultipleItems = 0; + ret_details.paDetails = &ret_value; + ret_details.cbDetails = sizeof(ret_value); + + /* read back the new control value */ + rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + /* result may not match exactly because of rounding */ + ok(ret_value.fValue==new_value.fValue, + "Couldn't change value from %d to %d, returned %d\n", + value.fValue,new_value.fValue,ret_value.fValue); + + if (ret_value.fValue==new_value.fValue) { + details.cbStruct = sizeof(MIXERCONTROLDETAILS); + details.dwControlID = control->dwControlID; + details.cChannels = 1; + U(details).cMultipleItems = 0; + details.paDetails = &value; + details.cbDetails = sizeof(value); + + /* restore original value */ + rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE); + ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + } + } + } + } + } else { + /* FIXME */ + } +} + +static void mixer_test_deviceW(int device) +{ + MIXERCAPSW capsW; + HMIXER mix; + MMRESULT rc; + DWORD d,s,ns,nc; + char szShortName[MIXER_SHORT_NAME_CHARS]; + char szName[MIXER_LONG_NAME_CHARS]; + char szPname[MAXPNAMELEN]; + + rc=mixerGetDevCapsW(device,0,sizeof(capsW)); + ok(rc==MMSYSERR_INVALPARAM, + "mixerGetDevCapsW: MMSYSERR_INVALPARAM expected, got %s\n", + mmsys_error(rc)); + + rc=mixerGetDevCapsW(device,&capsW,4); + ok(rc==MMSYSERR_NOERROR || + rc==MMSYSERR_INVALPARAM, /* Vista and W2K8 */ + "mixerGetDevCapsW: MMSYSERR_NOERROR or MMSYSERR_INVALPARAM expected, got %s\n", + mmsys_error(rc)); + + rc=mixerGetDevCapsW(device,&capsW,sizeof(capsW)); + ok(rc==MMSYSERR_NOERROR, + "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + + WideCharToMultiByte(CP_ACP,0,capsW.szPname, MAXPNAMELEN,szPname, + MAXPNAMELEN,NULL,NULL); + if (winetest_interactive) { + trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%d\n", device, + szPname, capsW.vDriverVersion >> 8, + capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid, + capsW.cDestinations); + } else { + trace(" %d: \"%s\" %d.%d (%d:%d)\n", device, + szPname, capsW.vDriverVersion >> 8, + capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid); + } + + + rc=mixerOpen(&mix, device, 0, 0, 0); + ok(rc==MMSYSERR_NOERROR, + "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + for (d=0;d> 8, + mixerlineW.Target.vDriverVersion & 0xff, + mixerlineW.Target.wMid, mixerlineW.Target.wPid); + } + ns=mixerlineW.cConnections; + for(s=0;s> 8, + mixerlineW.Target.vDriverVersion & 0xff, + mixerlineW.Target.wMid, mixerlineW.Target.wPid); + } + if (mixerlineW.cControls) { + array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + mixerlineW.cControls*sizeof(MIXERCONTROLW)); + if (array) { + rc=mixerGetLineControlsW((HMIXEROBJ)mix,0, + MIXER_GETLINECONTROLSF_ALL); + ok(rc==MMSYSERR_INVALPARAM, + "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): " + "MMSYSERR_INVALPARAM expected, got %s\n", + mmsys_error(rc)); + rc=mixerGetLineControlsW((HMIXEROBJ)mix,&controls, + -1); + ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM, + "mixerGetLineControlsA(-1): " + "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n", + mmsys_error(rc)); + + controls.cbStruct = sizeof(MIXERLINECONTROLSW); + controls.cControls = mixerlineW.cControls; + controls.dwLineID = mixerlineW.dwLineID; + controls.pamxctrl = array; + controls.cbmxctrl = sizeof(MIXERCONTROLW); + + /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID + * and MIXER_GETLINECONTROLSF_ONEBYTYPE + */ + rc=mixerGetLineControlsW((HMIXEROBJ)mix,&controls, + MIXER_GETLINECONTROLSF_ALL); + ok(rc==MMSYSERR_NOERROR, + "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): " + "MMSYSERR_NOERROR expected, got %s\n", + mmsys_error(rc)); + if (rc==MMSYSERR_NOERROR) { + for(nc=0;nc +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "mmsystem.h" +#include "vfw.h" +#include "wine/test.h" + +static DWORD RIFF_buf[] = +{ + FOURCC_RIFF, 32*sizeof(DWORD), mmioFOURCC('A','V','I',' '), + FOURCC_LIST, 29*sizeof(DWORD), listtypeAVIHEADER, ckidAVIMAINHDR, + sizeof(MainAVIHeader), 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, + 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,0xdeadbeef, + 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,0xdeadbeef, + 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, + FOURCC_LIST, 10*sizeof(DWORD),listtypeSTREAMHEADER, ckidSTREAMHEADER, + 7*sizeof(DWORD), streamtypeVIDEO, 0xdeadbeef, 0xdeadbeef, + 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void test_mmioDescend(char *fname) +{ + MMRESULT ret; + HMMIO hmmio; + MMIOINFO mmio; + MMCKINFO ckRiff, ckList, ck; + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = sizeof(RIFF_buf); + mmio.pchBuffer = (char *)RIFF_buf; + hmmio = mmioOpen(fname, &mmio, MMIO_READ); + if (fname && !hmmio) + { + skip("%s file is missing, skipping the test\n", fname); + return; + } + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + /* first normal RIFF AVI parsing */ + ret = mmioDescend(hmmio, &ckRiff, NULL, 0); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ckRiff.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ckRiff.ckid); + ok(ckRiff.fccType == formtypeAVI, "wrong fccType: %04x\n", ckRiff.fccType); + trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n", + (LPCSTR)&ckRiff.ckid, ckRiff.cksize, (LPCSTR)&ckRiff.fccType, + ckRiff.dwDataOffset, ckRiff.dwFlags); + + ret = mmioDescend(hmmio, &ckList, &ckRiff, 0); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ckList.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ckList.ckid); + ok(ckList.fccType == listtypeAVIHEADER, "wrong fccType: %04x\n", ckList.fccType); + trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n", + (LPCSTR)&ckList.ckid, ckList.cksize, (LPCSTR)&ckList.fccType, + ckList.dwDataOffset, ckList.dwFlags); + + ret = mmioDescend(hmmio, &ck, &ckList, 0); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ck.ckid == ckidAVIMAINHDR, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType == 0, "wrong fccType: %04x\n", ck.fccType); + trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n", + (LPCSTR)&ck.ckid, ck.cksize, (LPCSTR)&ck.fccType, + ck.dwDataOffset, ck.dwFlags); + + /* Skip chunk data */ + mmioSeek(hmmio, ck.cksize, SEEK_CUR); + + ret = mmioDescend(hmmio, &ckList, &ckList, 0); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ckList.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ckList.ckid); + ok(ckList.fccType == listtypeSTREAMHEADER, "wrong fccType: %04x\n", ckList.fccType); + trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n", + (LPCSTR)&ckList.ckid, ckList.cksize, (LPCSTR)&ckList.fccType, + ckList.dwDataOffset, ckList.dwFlags); + + ret = mmioDescend(hmmio, &ck, &ckList, 0); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ck.ckid == ckidSTREAMHEADER, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType == 0, "wrong fccType: %04x\n", ck.fccType); + trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n", + (LPCSTR)&ck.ckid, ck.cksize, (LPCSTR)&ck.fccType, + ck.dwDataOffset, ck.dwFlags); + + /* test various mmioDescend flags */ + + mmioSeek(hmmio, 0, SEEK_SET); + memset(&ck, 0x66, sizeof(ck)); + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDRIFF); + ok(ret == MMIOERR_CHUNKNOTFOUND || + ret == MMIOERR_INVALIDFILE, "mmioDescend returned %u\n", ret); + + mmioSeek(hmmio, 0, SEEK_SET); + memset(&ck, 0x66, sizeof(ck)); + ck.ckid = 0; + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDRIFF); + ok(ret == MMIOERR_CHUNKNOTFOUND || + ret == MMIOERR_INVALIDFILE, "mmioDescend returned %u\n", ret); + + mmioSeek(hmmio, 0, SEEK_SET); + memset(&ck, 0x66, sizeof(ck)); + ck.fccType = 0; + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDRIFF); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ck.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType == formtypeAVI, "wrong fccType: %04x\n", ck.fccType); + + mmioSeek(hmmio, 0, SEEK_SET); + memset(&ck, 0x66, sizeof(ck)); + ret = mmioDescend(hmmio, &ck, NULL, 0); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ck.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType == formtypeAVI, "wrong fccType: %04x\n", ck.fccType); + + /* do NOT seek, use current file position */ + memset(&ck, 0x66, sizeof(ck)); + ck.fccType = 0; + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDLIST); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ck.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType == listtypeAVIHEADER, "wrong fccType: %04x\n", ck.fccType); + + mmioSeek(hmmio, 0, SEEK_SET); + memset(&ck, 0x66, sizeof(ck)); + ck.ckid = 0; + ck.fccType = listtypeAVIHEADER; + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDCHUNK); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ck.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType == formtypeAVI, "wrong fccType: %04x\n", ck.fccType); + + /* do NOT seek, use current file position */ + memset(&ck, 0x66, sizeof(ck)); + ck.ckid = FOURCC_LIST; + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDCHUNK); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ck.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType == listtypeAVIHEADER, "wrong fccType: %04x\n", ck.fccType); + + mmioSeek(hmmio, 0, SEEK_SET); + memset(&ck, 0x66, sizeof(ck)); + ck.ckid = FOURCC_RIFF; + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDCHUNK); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ck.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType == formtypeAVI, "wrong fccType: %04x\n", ck.fccType); + + /* do NOT seek, use current file position */ + memset(&ckList, 0x66, sizeof(ckList)); + ckList.ckid = 0; + ret = mmioDescend(hmmio, &ckList, &ck, MMIO_FINDCHUNK); + ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret); + ok(ckList.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ckList.ckid); + ok(ckList.fccType == listtypeAVIHEADER, "wrong fccType: %04x\n", ckList.fccType); + + mmioSeek(hmmio, 0, SEEK_SET); + memset(&ck, 0x66, sizeof(ck)); + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDCHUNK); + ok(ret == MMIOERR_CHUNKNOTFOUND || + ret == MMIOERR_INVALIDFILE, "mmioDescend returned %u\n", ret); + ok(ck.ckid != 0x66666666, "wrong ckid: %04x\n", ck.ckid); + ok(ck.fccType != 0x66666666, "wrong fccType: %04x\n", ck.fccType); + ok(ck.dwDataOffset != 0x66666666, "wrong dwDataOffset: %04x\n", ck.dwDataOffset); + + mmioSeek(hmmio, 0, SEEK_SET); + memset(&ck, 0x66, sizeof(ck)); + ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDRIFF); + ok(ret == MMIOERR_CHUNKNOTFOUND || + ret == MMIOERR_INVALIDFILE, "mmioDescend returned %u\n", ret); + + mmioClose(hmmio, 0); +} + +static void test_mmioOpen(char *fname) +{ + char buf[256]; + MMRESULT ret; + HMMIO hmmio; + MMIOINFO mmio; + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = sizeof(buf); + mmio.pchBuffer = buf; + hmmio = mmioOpen(fname, &mmio, MMIO_READ); + if (fname && !hmmio) + { + skip("%s file is missing, skipping the test\n", fname); + return; + } + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == sizeof(buf), "got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer); + + mmioClose(hmmio, 0); + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = 0; + mmio.pchBuffer = buf; + hmmio = mmioOpen(fname, &mmio, MMIO_READ); + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == 0, "expected 0, got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer); + + mmioClose(hmmio, 0); + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = 0; + mmio.pchBuffer = NULL; + hmmio = mmioOpen(fname, &mmio, MMIO_READ); + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == 0, "expected 0, got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer == NULL, "expected NULL\n"); + + mmioClose(hmmio, 0); + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = 256; + mmio.pchBuffer = NULL; + hmmio = mmioOpen(fname, &mmio, MMIO_READ); + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == (MMIO_READ|MMIO_ALLOCBUF), "expected MMIO_READ|MMIO_ALLOCBUF, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == 256, "expected 256, got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer != NULL, "expected not NULL\n"); + + mmioClose(hmmio, 0); + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = sizeof(buf); + mmio.pchBuffer = buf; + hmmio = mmioOpen(fname, &mmio, MMIO_READ | MMIO_ALLOCBUF); + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == sizeof(buf), "got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer); + + mmioClose(hmmio, 0); + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = 0; + mmio.pchBuffer = NULL; + hmmio = mmioOpen(fname, &mmio, MMIO_READ | MMIO_ALLOCBUF); + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == (MMIO_READ|MMIO_ALLOCBUF), "expected MMIO_READ|MMIO_ALLOCBUF, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == MMIO_DEFAULTBUFFER, "expected MMIO_DEFAULTBUFFER, got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer != NULL, "expected not NULL\n"); + + mmioClose(hmmio, 0); + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = 256; + mmio.pchBuffer = NULL; + hmmio = mmioOpen(fname, &mmio, MMIO_READ | MMIO_ALLOCBUF); + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == (MMIO_READ|MMIO_ALLOCBUF), "expected MMIO_READ|MMIO_ALLOCBUF, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == 256, "expected 256, got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer != NULL, "expected not NULL\n"); + + mmioClose(hmmio, 0); + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = 0; + mmio.pchBuffer = buf; + hmmio = mmioOpen(fname, &mmio, MMIO_READ | MMIO_ALLOCBUF); + if (!hmmio && mmio.wErrorRet == ERROR_BAD_FORMAT) + { + /* Seen on Win9x, WinMe but also XP-SP1 */ + skip("Some Windows versions don't like a 0 size and a given buffer\n"); + return; + } + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == MMIO_DEFAULTBUFFER, "expected MMIO_DEFAULTBUFFER, got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer); + + mmioClose(hmmio, 0); +} + +static void test_mmioSetBuffer(char *fname) +{ + char buf[256]; + MMRESULT ret; + HMMIO hmmio; + MMIOINFO mmio; + + memset(&mmio, 0, sizeof(mmio)); + mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM; + mmio.cchBuffer = sizeof(buf); + mmio.pchBuffer = buf; + hmmio = mmioOpen(fname, &mmio, MMIO_READ); + if (fname && !hmmio) + { + skip("%s file is missing, skipping the test\n", fname); + return; + } + ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == sizeof(buf), "got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer); + + ret = mmioSetBuffer(hmmio, NULL, 0, 0); + ok(ret == MMSYSERR_NOERROR, "mmioSetBuffer error %u\n", ret); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == 0, "got not 0\n"); + ok(mmio.pchBuffer == NULL, "got not NULL buf\n"); + + ret = mmioSetBuffer(hmmio, NULL, 0, MMIO_ALLOCBUF); + ok(ret == MMSYSERR_NOERROR, "mmioSetBuffer error %u\n", ret); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == 0, "got not 0\n"); + ok(mmio.pchBuffer == NULL, "got not NULL buf\n"); + + ret = mmioSetBuffer(hmmio, buf, 0, MMIO_ALLOCBUF); + ok(ret == MMSYSERR_NOERROR, "mmioSetBuffer error %u\n", ret); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == 0, "got not 0\n"); + ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer); + + ret = mmioSetBuffer(hmmio, NULL, 256, MMIO_WRITE|MMIO_ALLOCBUF); + ok(ret == MMSYSERR_NOERROR, "mmioSetBuffer error %u\n", ret); + + memset(&mmio, 0, sizeof(mmio)); + ret = mmioGetInfo(hmmio, &mmio, 0); + ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret); + ok(mmio.dwFlags == (MMIO_READ|MMIO_ALLOCBUF), "expected MMIO_READ|MMIO_ALLOCBUF, got %x\n", mmio.dwFlags); + ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet); + ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc); + ok(mmio.cchBuffer == 256, "got %u\n", mmio.cchBuffer); + ok(mmio.pchBuffer != NULL, "expected not NULL\n"); + ok(mmio.pchBuffer != buf, "expected != buf\n"); + + mmioClose(hmmio, 0); +} + +START_TEST(mmio) +{ + char fname[] = "msrle.avi"; + + test_mmioDescend(NULL); + test_mmioDescend(fname); + test_mmioOpen(NULL); + test_mmioOpen(fname); + test_mmioSetBuffer(NULL); + test_mmioSetBuffer(fname); +} diff --git a/rostests/winetests/winmm/testlist.c b/rostests/winetests/winmm/testlist.c new file mode 100644 index 00000000000..e61d92d6422 --- /dev/null +++ b/rostests/winetests/winmm/testlist.c @@ -0,0 +1,25 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_capture(void); +extern void func_mci(void); +extern void func_mixer(void); +extern void func_mmio(void); +extern void func_timer(void); +extern void func_wave(void); + +const struct test winetest_testlist[] = +{ + { "capture", func_capture }, + { "mci", func_mci }, + { "mixer", func_mixer }, + { "mmio", func_mmio }, + { "timer", func_timer }, + { "wave", func_wave }, + { 0, 0 } +}; diff --git a/rostests/winetests/winmm/timer.c b/rostests/winetests/winmm/timer.c new file mode 100644 index 00000000000..7ac86b99371 --- /dev/null +++ b/rostests/winetests/winmm/timer.c @@ -0,0 +1,218 @@ +/* + * Test winmm timer + * + * Copyright (c) 2005 Robert Reif + * + * 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 + */ + +#include +#include +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "mmsystem.h" +#define NOBITMAP +#include "mmreg.h" + +#include "winmm_test.h" + +static TIMECAPS tc; + +static void test_timeGetDevCaps(void) +{ + MMRESULT rc; + + rc = timeGetDevCaps(&tc, 0); + ok(rc == TIMERR_NOCANDO || rc == MMSYSERR_INVALPARAM, + "timeGetDevCaps() returned %s, should have returned TIMERR_NOCANDO " + "or MMSYSERR_INVALPARAM\n", mmsys_error(rc)); + + rc = timeGetDevCaps(0, sizeof(tc)); + ok(rc == TIMERR_NOCANDO || rc == TIMERR_STRUCT, + "timeGetDevCaps() returned %s, should have returned TIMERR_NOCANDO " + "or TIMERR_STRUCT\n", mmsys_error(rc)); + + rc = timeGetDevCaps(0, 0); + ok(rc == TIMERR_NOCANDO || rc == MMSYSERR_INVALPARAM, + "timeGetDevCaps() returned %s, should have returned TIMERR_NOCANDO " + "or MMSYSERR_INVALPARAM\n", mmsys_error(rc)); + + rc = timeGetDevCaps(&tc, sizeof(tc)); + ok(rc == TIMERR_NOERROR, "timeGetDevCaps() returned %s, " + "should have returned TIMERR_NOERROR\n", mmsys_error(rc)); + + if (rc == TIMERR_NOERROR) + trace("wPeriodMin = %u, wPeriodMax = %u\n", + tc.wPeriodMin, tc.wPeriodMax); +} + +#define NUM_SAMPLES 100 + +static DWORD count = 0; +static DWORD times[NUM_SAMPLES]; + +static void CALLBACK testTimeProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, + DWORD_PTR dw1, DWORD_PTR dw2) +{ + if (count < NUM_SAMPLES) + times[count++] = timeGetTime(); +} + +static void test_timer(UINT period, UINT resolution) +{ + MMRESULT rc; + UINT i, id, delta; + DWORD dwMin = 0xffffffff, dwMax = 0; + double sum = 0.0; + double deviation = 0.0; + + count = 0; + + for (i = 0; i < NUM_SAMPLES; i++) + times[i] = 0; + + rc = timeBeginPeriod(period); + ok(rc == TIMERR_NOERROR, "timeBeginPeriod(%u) returned %s, " + "should have returned TIMERR_NOERROR\n", period, mmsys_error(rc)); + if (rc != TIMERR_NOERROR) + return; + + id = timeSetEvent(period, resolution, testTimeProc, 0, TIME_PERIODIC); + ok(id != 0, "timeSetEvent(%u, %u, %p, 0, TIME_PERIODIC) returned %d, " + "should have returned id > 0\n", period, resolution, testTimeProc, id); + if (id == 0) + return; + + Sleep((NUM_SAMPLES * period) + (2 * period)); + + rc = timeEndPeriod(period); + ok(rc == TIMERR_NOERROR, "timeEndPeriod(%u) returned %s, " + "should have returned TIMERR_NOERROR\n", period, mmsys_error(rc)); + if (rc != TIMERR_NOERROR) + return; + + rc = timeKillEvent(id); + ok(rc == TIMERR_NOERROR, "timeKillEvent(%u) returned %s, " + "should have returned TIMERR_NOERROR\n", id, mmsys_error(rc)); + + trace("period = %u, resolution = %u\n", period, resolution); + + for (i = 0; i < count; i++) + { + if (i == 0) + { + if (winetest_debug > 1) + trace("time[%d] = %u\n", i, times[i]); + } + else + { + delta = times[i] - times[i - 1]; + + if (winetest_debug > 1) + trace("time[%d] = %u delta = %d\n", i, times[i], delta); + + sum += delta; + deviation += ((delta - period) * (delta - period)); + + if (delta < dwMin) + dwMin = delta; + + if (delta > dwMax) + dwMax = delta; + } + } + + trace("min = %u, max = %u, average = %f, standard deviation = %f\n", + dwMin, dwMax, sum / (count - 1), sqrt(deviation / (count - 2))); +} + +static const char * get_priority(int priority) +{ + static char tmp[32]; +#define STR(x) case x: return #x + switch(priority) { + STR(THREAD_PRIORITY_LOWEST); + STR(THREAD_PRIORITY_BELOW_NORMAL); + STR(THREAD_PRIORITY_NORMAL); + STR(THREAD_PRIORITY_HIGHEST); + STR(THREAD_PRIORITY_ABOVE_NORMAL); + STR(THREAD_PRIORITY_TIME_CRITICAL); + STR(THREAD_PRIORITY_IDLE); + } + sprintf(tmp, "UNKNOWN(%d)", priority); + return tmp; +} + +static int priority = 0; +static BOOL fired = FALSE; + +static void CALLBACK priorityTimeProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, + DWORD_PTR dw1, DWORD_PTR dw2) +{ + priority = GetThreadPriority(GetCurrentThread()); + ok(priority!=THREAD_PRIORITY_ERROR_RETURN, "GetThreadPriority() failed, GetLastError() = %u\n", GetLastError()); + fired = TRUE; +} + +static void test_priority(void) +{ + UINT id; + + id = timeSetEvent(100, 100, priorityTimeProc, 0, TIME_ONESHOT); + ok(id != 0, "timeSetEvent(100, 100, %p, 0, TIME_ONESHOT) returned %d, " + "should have returned id > 0\n", priorityTimeProc, id); + if (id == 0) + return; + + Sleep(200); + + ok(fired == TRUE, "Callback not called\n"); + if (fired) + { + ok(priority == THREAD_PRIORITY_TIME_CRITICAL, + "thread priority is %s, should be THREAD_PRIORITY_TIME_CRITICAL\n", + get_priority(priority)); + } +} + +START_TEST(timer) +{ + test_timeGetDevCaps(); + + if (tc.wPeriodMin <= 1) { + test_timer(1, 0); + test_timer(1, 1); + } + + if (tc.wPeriodMin <= 10) { + test_timer(10, 0); + test_timer(10, 1); + test_timer(10, 10); + } + + if (tc.wPeriodMin <= 20) { + test_timer(20, 0); + test_timer(20, 1); + test_timer(20, 10); + test_timer(20, 20); + } + + test_priority(); +} diff --git a/rostests/winetests/winmm/wave.c b/rostests/winetests/winmm/wave.c new file mode 100644 index 00000000000..6a4786a5951 --- /dev/null +++ b/rostests/winetests/winmm/wave.c @@ -0,0 +1,1465 @@ +/* + * Test winmm sound playback in each sound format + * + * Copyright (c) 2002 Francois Gouget + * + * 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 + */ + +#include +#include +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" +#include "mmsystem.h" +#define NOBITMAP +#include "mmreg.h" +#include "ks.h" +#include "ksmedia.h" + +#include "winmm_test.h" + +static void test_multiple_waveopens(void) +{ + HWAVEOUT handle1, handle2; + MMRESULT ret; + WAVEFORMATEX wfx; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = 1; + wfx.nSamplesPerSec = 11025; + wfx.nBlockAlign = 1; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + wfx.wBitsPerSample = 8; + wfx.cbSize = 0; + + ret = waveOutOpen(&handle1, 0, &wfx, 0, 0, 0); + if (ret != MMSYSERR_NOERROR) + { + skip("Could not do the duplicate waveopen test\n"); + return; + } + + ret = waveOutOpen(&handle2, 0, &wfx, 0, 0, 0); + /* Modern Windows allows for wave-out devices to be opened multiple times. + * Some Wine audio drivers allow that and some don't. To avoid false alarms + * for those that do, don't "todo_wine ok(...)" on success. + */ + if (ret != MMSYSERR_NOERROR) + { + todo_wine ok(ret == MMSYSERR_NOERROR || broken(ret == MMSYSERR_ALLOCATED), /* winME */ + "second waveOutOpen returns: %x\n", ret); + } + else + waveOutClose(handle2); + + waveOutClose(handle1); +} + +/* + * Note that in most of this test we may get MMSYSERR_BADDEVICEID errors + * at about any time if the user starts another application that uses the + * sound device. So we should not report these as test failures. + * + * This test can play a test tone. But this only makes sense if someone + * is going to carefully listen to it, and would only bother everyone else. + * So this is only done if the test is being run in interactive mode. + */ + +#define PI 3.14159265358979323846 +static char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size) +{ + int i,j; + int nb_samples; + char* buf; + char* b; + WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE*)wfx; + + nb_samples=(int)(duration*wfx->nSamplesPerSec); + *size=nb_samples*wfx->nBlockAlign; + b=buf=HeapAlloc(GetProcessHeap(), 0, *size); + for (i=0;inSamplesPerSec); + if (wfx->wBitsPerSample==8) { + unsigned char sample=(unsigned char)((double)127.5*(y+1.0)); + for (j = 0; j < wfx->nChannels; j++) + *b++=sample; + } else if (wfx->wBitsPerSample==16) { + signed short sample=(signed short)((double)32767.5*y-0.5); + for (j = 0; j < wfx->nChannels; j++) { + b[0]=sample & 0xff; + b[1]=sample >> 8; + b+=2; + } + } else if (wfx->wBitsPerSample==24) { + signed int sample=(signed int)(((double)0x7fffff+0.5)*y-0.5); + for (j = 0; j < wfx->nChannels; j++) { + b[0]=sample & 0xff; + b[1]=(sample >> 8) & 0xff; + b[2]=(sample >> 16) & 0xff; + b+=3; + } + } else if ((wfx->wBitsPerSample==32) && ((wfx->wFormatTag == WAVE_FORMAT_PCM) || + ((wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) && + IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)))) { + signed int sample=(signed int)(((double)0x7fffffff+0.5)*y-0.5); + for (j = 0; j < wfx->nChannels; j++) { + b[0]=sample & 0xff; + b[1]=(sample >> 8) & 0xff; + b[2]=(sample >> 16) & 0xff; + b[3]=(sample >> 24) & 0xff; + b+=4; + } + } else if ((wfx->wBitsPerSample==32) && (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) && + IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { + union { float f; char c[4]; } sample; + sample.f=(float)y; + for (j = 0; j < wfx->nChannels; j++) { + b[0]=sample.c[0]; + b[1]=sample.c[1]; + b[2]=sample.c[2]; + b[3]=sample.c[3]; + b+=4; + } + } + } + return buf; +} + +static char* wave_generate_silence(WAVEFORMATEX* wfx, double duration, DWORD* size) +{ + int i,j; + int nb_samples; + char* buf; + char* b; + WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE*)wfx; + + nb_samples=(int)(duration*wfx->nSamplesPerSec); + *size=nb_samples*wfx->nBlockAlign; + b=buf=HeapAlloc(GetProcessHeap(), 0, *size); + for (i=0;iwBitsPerSample==8) { + for (j = 0; j < wfx->nChannels; j++) + *b++=128; + } else if (wfx->wBitsPerSample==16) { + for (j = 0; j < wfx->nChannels; j++) { + b[0]=0; + b[1]=0; + b+=2; + } + } else if (wfx->wBitsPerSample==24) { + for (j = 0; j < wfx->nChannels; j++) { + b[0]=0; + b[1]=0; + b[2]=0; + b+=3; + } + } else if ((wfx->wBitsPerSample==32) && ((wfx->wFormatTag == WAVE_FORMAT_PCM) || + ((wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) && + IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)))) { + for (j = 0; j < wfx->nChannels; j++) { + b[0]=0; + b[1]=0; + b[2]=0; + b[3]=0; + b+=4; + } + } else if ((wfx->wBitsPerSample==32) && (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) && + IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { + union { float f; char c[4]; } sample; + sample.f=0; + for (j = 0; j < wfx->nChannels; j++) { + b[0]=sample.c[0]; + b[1]=sample.c[1]; + b[2]=sample.c[2]; + b[3]=sample.c[3]; + b+=4; + } + } + } + return buf; +} + +const char * dev_name(int device) +{ + static char name[16]; + if (device == WAVE_MAPPER) + return "WAVE_MAPPER"; + sprintf(name, "%d", device); + return name; +} + +const char* mmsys_error(MMRESULT error) +{ +#define ERR_TO_STR(dev) case dev: return #dev + static char unknown[32]; + switch (error) { + ERR_TO_STR(MMSYSERR_NOERROR); + ERR_TO_STR(MMSYSERR_ERROR); + ERR_TO_STR(MMSYSERR_BADDEVICEID); + ERR_TO_STR(MMSYSERR_NOTENABLED); + ERR_TO_STR(MMSYSERR_ALLOCATED); + ERR_TO_STR(MMSYSERR_INVALHANDLE); + ERR_TO_STR(MMSYSERR_NODRIVER); + ERR_TO_STR(MMSYSERR_NOMEM); + ERR_TO_STR(MMSYSERR_NOTSUPPORTED); + ERR_TO_STR(MMSYSERR_BADERRNUM); + ERR_TO_STR(MMSYSERR_INVALFLAG); + ERR_TO_STR(MMSYSERR_INVALPARAM); + ERR_TO_STR(WAVERR_BADFORMAT); + ERR_TO_STR(WAVERR_STILLPLAYING); + ERR_TO_STR(WAVERR_UNPREPARED); + ERR_TO_STR(WAVERR_SYNC); + ERR_TO_STR(MIDIERR_UNPREPARED); + ERR_TO_STR(MIDIERR_STILLPLAYING); + ERR_TO_STR(MIDIERR_NOTREADY); + ERR_TO_STR(MIDIERR_NODEVICE); + ERR_TO_STR(MIDIERR_INVALIDSETUP); + ERR_TO_STR(TIMERR_NOCANDO); + ERR_TO_STR(TIMERR_STRUCT); + ERR_TO_STR(JOYERR_PARMS); + ERR_TO_STR(JOYERR_NOCANDO); + ERR_TO_STR(JOYERR_UNPLUGGED); + ERR_TO_STR(MIXERR_INVALLINE); + ERR_TO_STR(MIXERR_INVALCONTROL); + ERR_TO_STR(MIXERR_INVALVALUE); + ERR_TO_STR(MMIOERR_FILENOTFOUND); + ERR_TO_STR(MMIOERR_OUTOFMEMORY); + ERR_TO_STR(MMIOERR_CANNOTOPEN); + ERR_TO_STR(MMIOERR_CANNOTCLOSE); + ERR_TO_STR(MMIOERR_CANNOTREAD); + ERR_TO_STR(MMIOERR_CANNOTWRITE); + ERR_TO_STR(MMIOERR_CANNOTSEEK); + ERR_TO_STR(MMIOERR_CANNOTEXPAND); + ERR_TO_STR(MMIOERR_CHUNKNOTFOUND); + ERR_TO_STR(MMIOERR_UNBUFFERED); + } + sprintf(unknown, "Unknown(0x%08x)", error); + return unknown; +#undef ERR_TO_STR +} + +const char* wave_out_error(MMRESULT error) +{ + static char msg[1024]; + static char long_msg[1100]; + MMRESULT rc; + + rc = waveOutGetErrorText(error, msg, sizeof(msg)); + if (rc != MMSYSERR_NOERROR) + sprintf(long_msg, "waveOutGetErrorText(%x) failed with error %x", + error, rc); + else + sprintf(long_msg, "%s(%s)", mmsys_error(error), msg); + return long_msg; +} + +const char * wave_open_flags(DWORD flags) +{ + static char msg[1024]; + int first = TRUE; + msg[0] = 0; + if ((flags & CALLBACK_TYPEMASK) == CALLBACK_EVENT) { + strcat(msg, "CALLBACK_EVENT"); + first = FALSE; + } + if ((flags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION) { + if (!first) strcat(msg, "|"); + strcat(msg, "CALLBACK_FUNCTION"); + first = FALSE; + } + if ((flags & CALLBACK_TYPEMASK) == CALLBACK_NULL) { + if (!first) strcat(msg, "|"); + strcat(msg, "CALLBACK_NULL"); + first = FALSE; + } + if ((flags & CALLBACK_TYPEMASK) == CALLBACK_THREAD) { + if (!first) strcat(msg, "|"); + strcat(msg, "CALLBACK_THREAD"); + first = FALSE; + } + if ((flags & CALLBACK_TYPEMASK) == CALLBACK_WINDOW) { + if (!first) strcat(msg, "|"); + strcat(msg, "CALLBACK_WINDOW"); + first = FALSE; + } + if ((flags & WAVE_ALLOWSYNC) == WAVE_ALLOWSYNC) { + if (!first) strcat(msg, "|"); + strcat(msg, "WAVE_ALLOWSYNC"); + first = FALSE; + } + if ((flags & WAVE_FORMAT_DIRECT) == WAVE_FORMAT_DIRECT) { + if (!first) strcat(msg, "|"); + strcat(msg, "WAVE_FORMAT_DIRECT"); + first = FALSE; + } + if ((flags & WAVE_FORMAT_QUERY) == WAVE_FORMAT_QUERY) { + if (!first) strcat(msg, "|"); + strcat(msg, "WAVE_FORMAT_QUERY"); + first = FALSE; + } + if ((flags & WAVE_MAPPED) == WAVE_MAPPED) { + if (!first) strcat(msg, "|"); + strcat(msg, "WAVE_MAPPED"); + first = FALSE; + } + return msg; +} + +static const char * wave_header_flags(DWORD flags) +{ +#define WHDR_MASK (WHDR_BEGINLOOP|WHDR_DONE|WHDR_ENDLOOP|WHDR_INQUEUE|WHDR_PREPARED) + static char msg[1024]; + int first = TRUE; + msg[0] = 0; + if (flags & WHDR_BEGINLOOP) { + strcat(msg, "WHDR_BEGINLOOP"); + first = FALSE; + } + if (flags & WHDR_DONE) { + if (!first) strcat(msg, " "); + strcat(msg, "WHDR_DONE"); + first = FALSE; + } + if (flags & WHDR_ENDLOOP) { + if (!first) strcat(msg, " "); + strcat(msg, "WHDR_ENDLOOP"); + first = FALSE; + } + if (flags & WHDR_INQUEUE) { + if (!first) strcat(msg, " "); + strcat(msg, "WHDR_INQUEUE"); + first = FALSE; + } + if (flags & WHDR_PREPARED) { + if (!first) strcat(msg, " "); + strcat(msg, "WHDR_PREPARED"); + first = FALSE; + } + if (flags & ~WHDR_MASK) { + char temp[32]; + sprintf(temp, "UNKNOWN(0x%08x)", flags & ~WHDR_MASK); + if (!first) strcat(msg, " "); + strcat(msg, temp); + } + return msg; +} + +static const char * wave_out_caps(DWORD dwSupport) +{ +#define ADD_FLAG(f) if (dwSupport & f) strcat(msg, " " #f) + static char msg[256]; + msg[0] = 0; + + ADD_FLAG(WAVECAPS_PITCH); + ADD_FLAG(WAVECAPS_PLAYBACKRATE); + ADD_FLAG(WAVECAPS_VOLUME); + ADD_FLAG(WAVECAPS_LRVOLUME); + ADD_FLAG(WAVECAPS_SYNC); + ADD_FLAG(WAVECAPS_SAMPLEACCURATE); + + return msg[0] ? msg + 1 : ""; +#undef ADD_FLAG +} + +const char * wave_time_format(UINT type) +{ + static char msg[32]; +#define TIME_FORMAT(f) case f: return #f + switch (type) { + TIME_FORMAT(TIME_MS); + TIME_FORMAT(TIME_SAMPLES); + TIME_FORMAT(TIME_BYTES); + TIME_FORMAT(TIME_SMPTE); + TIME_FORMAT(TIME_MIDI); + TIME_FORMAT(TIME_TICKS); + } +#undef TIME_FORMAT + sprintf(msg, "Unknown(0x%04x)", type); + return msg; +} + +const char * get_format_str(WORD format) +{ + static char msg[32]; +#define WAVE_FORMAT(f) case f: return #f + switch (format) { + WAVE_FORMAT(WAVE_FORMAT_PCM); + WAVE_FORMAT(WAVE_FORMAT_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_IBM_CVSD); + WAVE_FORMAT(WAVE_FORMAT_ALAW); + WAVE_FORMAT(WAVE_FORMAT_MULAW); + WAVE_FORMAT(WAVE_FORMAT_OKI_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_IMA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_MEDIASPACE_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_SIERRA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_G723_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_DIGISTD); + WAVE_FORMAT(WAVE_FORMAT_DIGIFIX); + WAVE_FORMAT(WAVE_FORMAT_DIALOGIC_OKI_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_YAMAHA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_SONARC); + WAVE_FORMAT(WAVE_FORMAT_DSPGROUP_TRUESPEECH); + WAVE_FORMAT(WAVE_FORMAT_ECHOSC1); + WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF36); + WAVE_FORMAT(WAVE_FORMAT_APTX); + WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF10); + WAVE_FORMAT(WAVE_FORMAT_DOLBY_AC2); + WAVE_FORMAT(WAVE_FORMAT_GSM610); + WAVE_FORMAT(WAVE_FORMAT_ANTEX_ADPCME); + WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_VQLPC); + WAVE_FORMAT(WAVE_FORMAT_DIGIREAL); + WAVE_FORMAT(WAVE_FORMAT_DIGIADPCM); + WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_CR10); + WAVE_FORMAT(WAVE_FORMAT_NMS_VBXADPCM); + WAVE_FORMAT(WAVE_FORMAT_G721_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_MPEG); + WAVE_FORMAT(WAVE_FORMAT_MPEGLAYER3); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH8); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH10); + WAVE_FORMAT(WAVE_FORMAT_FM_TOWNS_SND); + WAVE_FORMAT(WAVE_FORMAT_OLIGSM); + WAVE_FORMAT(WAVE_FORMAT_OLIADPCM); + WAVE_FORMAT(WAVE_FORMAT_OLICELP); + WAVE_FORMAT(WAVE_FORMAT_OLISBC); + WAVE_FORMAT(WAVE_FORMAT_OLIOPR); + WAVE_FORMAT(WAVE_FORMAT_DEVELOPMENT); + WAVE_FORMAT(WAVE_FORMAT_EXTENSIBLE); + } +#undef WAVE_FORMAT + sprintf(msg, "Unknown(0x%04x)", format); + return msg; +} + +DWORD bytes_to_samples(DWORD bytes, LPWAVEFORMATEX pwfx) +{ + return bytes / pwfx->nBlockAlign; +} + +DWORD bytes_to_ms(DWORD bytes, LPWAVEFORMATEX pwfx) +{ + return bytes_to_samples(bytes, pwfx) * 1000 / pwfx->nSamplesPerSec; +} + +DWORD time_to_bytes(LPMMTIME mmtime, LPWAVEFORMATEX pwfx) +{ + if (mmtime->wType == TIME_BYTES) + return mmtime->u.cb; + else if (mmtime->wType == TIME_SAMPLES) + return mmtime->u.sample * pwfx->nBlockAlign; + else if (mmtime->wType == TIME_MS) + return mmtime->u.ms * pwfx->nAvgBytesPerSec / 1000; + else if (mmtime->wType == TIME_SMPTE) + return ((mmtime->u.smpte.hour * 60.0 * 60.0) + + (mmtime->u.smpte.min * 60.0) + + (mmtime->u.smpte.sec) + + (mmtime->u.smpte.frame / 30.0)) * pwfx->nAvgBytesPerSec; + + trace("FIXME: time_to_bytes() type not supported\n"); + return -1; +} + +static void check_position(int device, HWAVEOUT wout, DWORD bytes, + LPWAVEFORMATEX pwfx ) +{ + MMTIME mmtime; + DWORD samples; + double duration; + MMRESULT rc; + DWORD returned; + + samples=bytes/(pwfx->wBitsPerSample/8*pwfx->nChannels); + duration=((double)samples)/pwfx->nSamplesPerSec; + + mmtime.wType = TIME_BYTES; + rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + if (mmtime.wType != TIME_BYTES && winetest_debug > 1) + trace("waveOutGetPosition(%s): TIME_BYTES not supported, returned %s\n", + dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveOutGetPosition(%s): returned %d bytes, " + "should be %d\n", dev_name(device), returned, bytes); + + mmtime.wType = TIME_SAMPLES; + rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + if (mmtime.wType != TIME_SAMPLES && winetest_debug > 1) + trace("waveOutGetPosition(%s): TIME_SAMPLES not supported, " + "returned %s\n",dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveOutGetPosition(%s): returned %d samples " + "(%d bytes), should be %d (%d bytes)\n", dev_name(device), + bytes_to_samples(returned, pwfx), returned, + bytes_to_samples(bytes, pwfx), bytes); + + mmtime.wType = TIME_MS; + rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + if (mmtime.wType != TIME_MS && winetest_debug > 1) + trace("waveOutGetPosition(%s): TIME_MS not supported, returned %s\n", + dev_name(device), wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveOutGetPosition(%s): returned %d ms, " + "(%d bytes), should be %d (%d bytes)\n", dev_name(device), + bytes_to_ms(returned, pwfx), returned, + bytes_to_ms(bytes, pwfx), bytes); + + mmtime.wType = TIME_SMPTE; + rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + if (mmtime.wType != TIME_SMPTE && winetest_debug > 1) + trace("waveOutGetPosition(%s): TIME_SMPTE not supported, returned %s\n", + dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveOutGetPosition(%s): SMPTE test failed\n", + dev_name(device)); + + mmtime.wType = TIME_MIDI; + rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + if (mmtime.wType != TIME_MIDI && winetest_debug > 1) + trace("waveOutGetPosition(%s): TIME_MIDI not supported, returned %s\n", + dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveOutGetPosition(%s): MIDI test failed\n", + dev_name(device)); + + mmtime.wType = TIME_TICKS; + rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime)); + ok(rc==MMSYSERR_NOERROR, + "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + if (mmtime.wType != TIME_TICKS && winetest_debug > 1) + trace("waveOutGetPosition(%s): TIME_TICKS not supported, returned %s\n", + dev_name(device),wave_time_format(mmtime.wType)); + returned = time_to_bytes(&mmtime, pwfx); + ok(returned == bytes, "waveOutGetPosition(%s): TICKS test failed\n", + dev_name(device)); +} + +static void CALLBACK callback_func(HWAVEOUT hwo, UINT uMsg, + DWORD_PTR dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + SetEvent((HANDLE)dwInstance); +} + +static DWORD WINAPI callback_thread(LPVOID lpParameter) +{ + MSG msg; + + PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); /* make sure the thread has a message queue */ + SetEvent(lpParameter); + + while (GetMessage(&msg, 0, 0, 0)) { + UINT message = msg.message; + /* for some reason XP sends a WM_USER message before WOM_OPEN */ + ok (message == WOM_OPEN || message == WOM_DONE || + message == WOM_CLOSE || message == WM_USER || message == WM_APP, + "GetMessage returned unexpected message: %u\n", message); + if (message == WOM_OPEN || message == WOM_DONE || message == WOM_CLOSE) + SetEvent(lpParameter); + else if (message == WM_APP) { + SetEvent(lpParameter); + return 0; + } + } + + return 0; +} + +static void wave_out_test_deviceOut(int device, double duration, + int headers, int loops, + LPWAVEFORMATEX pwfx, DWORD format, + DWORD flags, LPWAVEOUTCAPS pcaps, + BOOL interactive, BOOL sine, BOOL pause) +{ + HWAVEOUT wout; + HANDLE hevent; + WAVEHDR *frags = 0; + MMRESULT rc; + DWORD volume; + WORD nChannels = pwfx->nChannels; + WORD wBitsPerSample = pwfx->wBitsPerSample; + DWORD nSamplesPerSec = pwfx->nSamplesPerSec; + BOOL has_volume = pcaps->dwSupport & WAVECAPS_VOLUME ? TRUE : FALSE; + double paused = 0.0; + DWORD_PTR callback = 0; + DWORD_PTR callback_instance = 0; + HANDLE thread = 0; + DWORD thread_id; + char * buffer; + DWORD length; + DWORD frag_length; + int i, j; + + hevent=CreateEvent(NULL,FALSE,FALSE,NULL); + ok(hevent!=NULL,"CreateEvent(): error=%d\n",GetLastError()); + if (hevent==NULL) + return; + + if ((flags & CALLBACK_TYPEMASK) == CALLBACK_EVENT) { + callback = (DWORD_PTR)hevent; + callback_instance = 0; + } else if ((flags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION) { + callback = (DWORD_PTR)callback_func; + callback_instance = (DWORD_PTR)hevent; + } else if ((flags & CALLBACK_TYPEMASK) == CALLBACK_THREAD) { + thread = CreateThread(NULL, 0, callback_thread, hevent, 0, &thread_id); + if (thread) { + /* make sure thread is running */ + WaitForSingleObject(hevent,10000); + callback = thread_id; + callback_instance = 0; + } else { + trace("CreateThread() failed\n"); + CloseHandle(hevent); + return; + } + } else if ((flags & CALLBACK_TYPEMASK) == CALLBACK_WINDOW) { + trace("CALLBACK_THREAD not implemented\n"); + CloseHandle(hevent); + return; + } else if (flags & CALLBACK_TYPEMASK) { + trace("Undefined callback type!\n"); + CloseHandle(hevent); + return; + } else { + trace("CALLBACK_NULL not implemented\n"); + CloseHandle(hevent); + return; + } + wout=NULL; + rc=waveOutOpen(&wout,device,pwfx,callback,callback_instance,flags); + /* Note: Win9x doesn't know WAVE_FORMAT_DIRECT */ + /* It is acceptable to fail on formats that are not specified to work */ + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_BADDEVICEID || + rc==MMSYSERR_NOTENABLED || rc==MMSYSERR_NODRIVER || + rc==MMSYSERR_ALLOCATED || + ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + (flags & WAVE_FORMAT_DIRECT) && !(pcaps->dwFormats & format)) || + ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + (!(flags & WAVE_FORMAT_DIRECT) || (flags & WAVE_MAPPED)) && + !(pcaps->dwFormats & format)) || + (rc==MMSYSERR_INVALFLAG && (flags & WAVE_FORMAT_DIRECT)), + "waveOutOpen(%s): format=%dx%2dx%d flags=%lx(%s) rc=%s\n", + dev_name(device),pwfx->nSamplesPerSec,pwfx->wBitsPerSample, + pwfx->nChannels,CALLBACK_EVENT|flags, + wave_open_flags(CALLBACK_EVENT|flags),wave_out_error(rc)); + if ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + (flags & WAVE_FORMAT_DIRECT) && (pcaps->dwFormats & format)) + trace(" Reason: The device lists this format as supported in it's " + "capabilities but opening it failed.\n"); + if ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) && + !(pcaps->dwFormats & format)) + trace("waveOutOpen(%s): format=%dx%2dx%d %s rc=%s failed but format " + "not supported so OK.\n", dev_name(device), pwfx->nSamplesPerSec, + pwfx->wBitsPerSample,pwfx->nChannels, + flags & WAVE_FORMAT_DIRECT ? "flags=WAVE_FORMAT_DIRECT" : + flags & WAVE_MAPPED ? "flags=WAVE_MAPPED" : "", mmsys_error(rc)); + if (rc!=MMSYSERR_NOERROR) + goto EXIT; + + WaitForSingleObject(hevent,10000); + + ok(pwfx->nChannels==nChannels && + pwfx->wBitsPerSample==wBitsPerSample && + pwfx->nSamplesPerSec==nSamplesPerSec, + "got the wrong format: %dx%2dx%d instead of %dx%2dx%d\n", + pwfx->nSamplesPerSec, pwfx->wBitsPerSample, + pwfx->nChannels, nSamplesPerSec, wBitsPerSample, nChannels); + + frags = HeapAlloc(GetProcessHeap(), 0, headers * sizeof(WAVEHDR)); + + if (sine) + buffer=wave_generate_la(pwfx,duration / (loops + 1),&length); + else + buffer=wave_generate_silence(pwfx,duration / (loops + 1),&length); + + rc=waveOutGetVolume(wout,0); + ok(rc==MMSYSERR_INVALPARAM,"waveOutGetVolume(%s,0) expected " + "MMSYSERR_INVALPARAM, got %s\n", dev_name(device),wave_out_error(rc)); + rc=waveOutGetVolume(wout,&volume); + if (rc == MMSYSERR_NOTSUPPORTED) has_volume = FALSE; + ok(has_volume ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED, + "waveOutGetVolume(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + + /* make sure fragment length is a multiple of block size */ + frag_length = ((length / headers) / pwfx->nBlockAlign) * pwfx->nBlockAlign; + + for (i = 0; i < headers; i++) { + frags[i].lpData=buffer + (i * frag_length); + if (i != (headers-1)) + frags[i].dwBufferLength=frag_length; + else { + /* use remainder of buffer for last fragment */ + frags[i].dwBufferLength=length - (i * frag_length); + } + frags[i].dwFlags=0; + frags[i].dwLoops=0; + rc=waveOutPrepareHeader(wout, &frags[i], sizeof(frags[0])); + ok(rc==MMSYSERR_NOERROR, + "waveOutPrepareHeader(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + } + + if (interactive && rc==MMSYSERR_NOERROR) { + DWORD start; + trace("Playing %g second %s at %5dx%2dx%d %2d header%s %d loop%s %d bytes %s %s\n",duration, + sine ? "440Hz tone" : "silence",pwfx->nSamplesPerSec, + pwfx->wBitsPerSample,pwfx->nChannels, headers, headers > 1 ? "s": " ", + loops, loops == 1 ? " " : "s", length * (loops + 1), + get_format_str(pwfx->wFormatTag), + wave_open_flags(flags)); + if (sine && has_volume && volume == 0) + trace("*** Warning the sound is muted, you will not hear the test\n"); + + /* Check that the position is 0 at start */ + check_position(device, wout, 0, pwfx); + + rc=waveOutSetVolume(wout,0x20002000); + ok(has_volume ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED, + "waveOutSetVolume(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + + rc=waveOutSetVolume(wout,volume); + ok(has_volume ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED, + "waveOutSetVolume(%s): rc=%s\n",dev_name(device),wave_out_error(rc)); + + start=GetTickCount(); + + rc=waveOutWrite(wout, &frags[0], sizeof(frags[0])); + ok(rc==MMSYSERR_NOERROR,"waveOutWrite(%s): rc=%s\n", + dev_name(device),wave_out_error(rc)); + + ok(frags[0].dwFlags==(WHDR_PREPARED|WHDR_INQUEUE), + "WHDR_INQUEUE WHDR_PREPARED expected, got= %s\n", + wave_header_flags(frags[0].dwFlags)); + + rc=waveOutWrite(wout, &frags[0], sizeof(frags[0])); + ok(rc==WAVERR_STILLPLAYING, + "waveOutWrite(%s): WAVE_STILLPLAYING expected, got %s\n", + dev_name(device),wave_out_error(rc)); + + ok(frags[0].dwFlags==(WHDR_PREPARED|WHDR_INQUEUE), + "WHDR_INQUEUE WHDR_PREPARED expected, got %s\n", + wave_header_flags(frags[0].dwFlags)); + + if (headers == 1 && loops == 0 && pause) { + paused = duration / 2; + Sleep(paused * 1000); + rc=waveOutPause(wout); + ok(rc==MMSYSERR_NOERROR,"waveOutPause(%s): rc=%s\n", + dev_name(device),wave_out_error(rc)); + trace("pausing for %g seconds\n", paused); + Sleep(paused * 1000); + rc=waveOutRestart(wout); + ok(rc==MMSYSERR_NOERROR,"waveOutRestart(%s): rc=%s\n", + dev_name(device),wave_out_error(rc)); + } + + for (j = 0; j <= loops; j++) { + for (i = 0; i < headers; i++) { + /* don't do last one */ + if (!((j == loops) && (i == (headers - 1)))) { + if (j > 0) + frags[(i+1) % headers].dwFlags = WHDR_PREPARED; + rc=waveOutWrite(wout, &frags[(i+1) % headers], sizeof(frags[0])); + ok(rc==MMSYSERR_NOERROR,"waveOutWrite(%s, header[%d]): rc=%s\n", + dev_name(device),(i+1)%headers,wave_out_error(rc)); + } + WaitForSingleObject(hevent,10000); + } + } + + for (i = 0; i < headers; i++) { + ok(frags[i].dwFlags==(WHDR_DONE|WHDR_PREPARED) || + broken((flags & CALLBACK_TYPEMASK)==CALLBACK_EVENT && + frags[i].dwFlags==(WHDR_DONE|WHDR_PREPARED|0x1000)), /* < NT4 */ + "(%02d) WHDR_DONE WHDR_PREPARED expected, got %s\n", + i, wave_header_flags(frags[i].dwFlags)); + } + check_position(device, wout, length * (loops + 1), pwfx); + } + + for (i = 0; i < headers; i++) { + rc=waveOutUnprepareHeader(wout, &frags[i], sizeof(frags[0])); + ok(rc==MMSYSERR_NOERROR, + "waveOutUnprepareHeader(%s): rc=%s\n",dev_name(device), + wave_out_error(rc)); + } + HeapFree(GetProcessHeap(), 0, buffer); + + rc=waveOutClose(wout); + ok(rc==MMSYSERR_NOERROR,"waveOutClose(%s): rc=%s\n",dev_name(device), + wave_out_error(rc)); + WaitForSingleObject(hevent,10000); +EXIT: + if ((flags & CALLBACK_TYPEMASK) == CALLBACK_THREAD) { + PostThreadMessage(thread_id, WM_APP, 0, 0); + WaitForSingleObject(hevent,10000); + } + CloseHandle(hevent); + HeapFree(GetProcessHeap(), 0, frags); +} + +static void wave_out_test_device(UINT_PTR device) +{ + WAVEOUTCAPSA capsA; + WAVEOUTCAPSW capsW; + WAVEFORMATEX format, oformat; + WAVEFORMATEXTENSIBLE wfex; + IMAADPCMWAVEFORMAT wfa; + HWAVEOUT wout; + MMRESULT rc; + UINT f; + WCHAR * nameW; + CHAR * nameA; + DWORD size; + DWORD dwPageSize; + BYTE * twoPages; + SYSTEM_INFO sSysInfo; + DWORD flOldProtect; + BOOL res; + + GetSystemInfo(&sSysInfo); + dwPageSize = sSysInfo.dwPageSize; + + rc=waveOutGetDevCapsA(device,&capsA,sizeof(capsA)); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_BADDEVICEID || + rc==MMSYSERR_NODRIVER, + "waveOutGetDevCapsA(%s): failed to get capabilities: rc=%s\n", + dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER) + return; + + rc=waveOutGetDevCapsW(device,&capsW,sizeof(capsW)); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED, + "waveOutGetDevCapsW(%s): MMSYSERR_NOERROR or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(device),wave_out_error(rc)); + + rc=waveOutGetDevCapsA(device,0,sizeof(capsA)); + ok(rc==MMSYSERR_INVALPARAM, + "waveOutGetDevCapsA(%s): MMSYSERR_INVALPARAM expected, " + "got %s\n",dev_name(device),wave_out_error(rc)); + + rc=waveOutGetDevCapsW(device,0,sizeof(capsW)); + ok(rc==MMSYSERR_INVALPARAM || rc==MMSYSERR_NOTSUPPORTED, + "waveOutGetDevCapsW(%s): MMSYSERR_INVALPARAM or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(device),wave_out_error(rc)); + + if (0) + { + /* FIXME: this works on windows but crashes wine */ + rc=waveOutGetDevCapsA(device,(LPWAVEOUTCAPSA)1,sizeof(capsA)); + ok(rc==MMSYSERR_INVALPARAM, + "waveOutGetDevCapsA(%s): MMSYSERR_INVALPARAM expected, got %s\n", + dev_name(device),wave_out_error(rc)); + + rc=waveOutGetDevCapsW(device,(LPWAVEOUTCAPSW)1,sizeof(capsW)); + ok(rc==MMSYSERR_INVALPARAM || rc==MMSYSERR_NOTSUPPORTED, + "waveOutGetDevCapsW(%s): MMSYSERR_INVALPARAM or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(device),wave_out_error(rc)); + } + + rc=waveOutGetDevCapsA(device,&capsA,4); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_INVALPARAM, + "waveOutGetDevCapsA(%s): MMSYSERR_NOERROR or MMSYSERR_INVALPARAM " + "expected, got %s\n", dev_name(device),wave_out_error(rc)); + + rc=waveOutGetDevCapsW(device,&capsW,4); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED || + rc==MMSYSERR_INVALPARAM, /* Vista, W2K8 */ + "waveOutGetDevCapsW(%s): unexpected return value %s\n", + dev_name(device),wave_out_error(rc)); + + nameA=NULL; + rc=waveOutMessage((HWAVEOUT)device, DRV_QUERYDEVICEINTERFACESIZE, + (DWORD_PTR)&size, 0); + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_INVALPARAM || + rc==MMSYSERR_NOTSUPPORTED, + "waveOutMessage(%s): failed to get interface size, rc=%s\n", + dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + nameW = HeapAlloc(GetProcessHeap(), 0, size); + rc=waveOutMessage((HWAVEOUT)device, DRV_QUERYDEVICEINTERFACE, + (DWORD_PTR)nameW, size); + ok(rc==MMSYSERR_NOERROR,"waveOutMessage(%s): failed to get interface " + "name, rc=%s\n",dev_name(device),wave_out_error(rc)); + ok(lstrlenW(nameW)+1==size/sizeof(WCHAR),"got an incorrect size %d\n",size); + if (rc==MMSYSERR_NOERROR) { + nameA = HeapAlloc(GetProcessHeap(), 0, size/sizeof(WCHAR)); + WideCharToMultiByte(CP_ACP, 0, nameW, size/sizeof(WCHAR), nameA, + size/sizeof(WCHAR), NULL, NULL); + } + HeapFree(GetProcessHeap(), 0, nameW); + } + else if (rc==MMSYSERR_NOTSUPPORTED) { + nameA=HeapAlloc(GetProcessHeap(), 0, sizeof("not supported")); + strcpy(nameA, "not supported"); + } + + rc=waveOutGetDevCapsA(device,&capsA,sizeof(capsA)); + ok(rc==MMSYSERR_NOERROR, + "waveOutGetDevCapsA(%s): MMSYSERR_NOERROR expected, got %s\n", + dev_name(device),wave_out_error(rc)); + if (rc!=MMSYSERR_NOERROR) + return; + + trace(" %s: \"%s\" (%s) %d.%d (%d:%d)\n",dev_name(device),capsA.szPname, + (nameA?nameA:"failed"),capsA.vDriverVersion >> 8, + capsA.vDriverVersion & 0xff, capsA.wMid,capsA.wPid); + trace(" channels=%d formats=%05x support=%04x\n", + capsA.wChannels,capsA.dwFormats,capsA.dwSupport); + trace(" %s\n",wave_out_caps(capsA.dwSupport)); + HeapFree(GetProcessHeap(), 0, nameA); + + if (winetest_interactive && (device != WAVE_MAPPER)) + { + trace("Playing a 5 seconds reference tone.\n"); + trace("All subsequent tones should be identical to this one.\n"); + trace("Listen for stutter, changes in pitch, volume, etc.\n"); + format.wFormatTag=WAVE_FORMAT_PCM; + format.nChannels=1; + format.wBitsPerSample=8; + format.nSamplesPerSec=22050; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + + wave_out_test_deviceOut(device,5.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,TRUE,TRUE,FALSE); + wave_out_test_deviceOut(device,5.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_FUNCTION,&capsA,TRUE,TRUE,FALSE); + wave_out_test_deviceOut(device,5.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_THREAD,&capsA,TRUE,TRUE,FALSE); + + wave_out_test_deviceOut(device,5.0,10,0,&format,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,TRUE,TRUE,FALSE); + wave_out_test_deviceOut(device,5.0,5,1,&format,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,TRUE,TRUE,FALSE); + } else { + format.wFormatTag=WAVE_FORMAT_PCM; + format.nChannels=1; + format.wBitsPerSample=8; + format.nSamplesPerSec=22050; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + wave_out_test_deviceOut(device,1.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,TRUE,FALSE,FALSE); + wave_out_test_deviceOut(device,1.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,TRUE,FALSE,TRUE); + wave_out_test_deviceOut(device,1.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_FUNCTION,&capsA,TRUE,FALSE,FALSE); + wave_out_test_deviceOut(device,1.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_FUNCTION,&capsA,TRUE,FALSE,TRUE); + wave_out_test_deviceOut(device,1.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_THREAD,&capsA,TRUE,FALSE,FALSE); + wave_out_test_deviceOut(device,1.0,1,0,&format,WAVE_FORMAT_2M08, + CALLBACK_THREAD,&capsA,TRUE,FALSE,TRUE); + + wave_out_test_deviceOut(device,1.0,10,0,&format,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,TRUE,FALSE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,&format,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,TRUE,FALSE,FALSE); + } + + for (f=0;fwFormatTag=WAVE_FORMAT_PCM; + pwfx->nChannels=1; + pwfx->wBitsPerSample=8; + pwfx->nSamplesPerSec=22050; + pwfx->nBlockAlign=pwfx->nChannels*pwfx->wBitsPerSample/8; + pwfx->nAvgBytesPerSec=pwfx->nSamplesPerSec*pwfx->nBlockAlign; + wave_out_test_deviceOut(device,1.0,1,0,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + if (device != WAVE_MAPPER) + { + wave_out_test_deviceOut(device,1.0,1,0,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT|WAVE_FORMAT_DIRECT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,1,0,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT|WAVE_MAPPED,&capsA, + winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT|WAVE_FORMAT_DIRECT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT|WAVE_MAPPED,&capsA, + winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT|WAVE_FORMAT_DIRECT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,pwfx,WAVE_FORMAT_2M08, + CALLBACK_EVENT|WAVE_MAPPED,&capsA, + winetest_interactive,TRUE,FALSE); + } + } + VirtualFree(twoPages, 0, MEM_RELEASE); + } + + /* Testing invalid format: 11 bits per sample */ + format.wFormatTag=WAVE_FORMAT_PCM; + format.nChannels=2; + format.wBitsPerSample=11; + format.nSamplesPerSec=22050; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + oformat=format; + rc=waveOutOpen(&wout,device,&format,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==WAVERR_BADFORMAT || rc==MMSYSERR_INVALFLAG || + rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): opening the device in 11 bits mode should fail: " + "rc=%s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + trace(" got %dx%2dx%d for %dx%2dx%d\n", + format.nSamplesPerSec, format.wBitsPerSample, + format.nChannels, + oformat.nSamplesPerSec, oformat.wBitsPerSample, + oformat.nChannels); + waveOutClose(wout); + } + + /* Testing invalid format: 2 MHz sample rate */ + format.wFormatTag=WAVE_FORMAT_PCM; + format.nChannels=2; + format.wBitsPerSample=16; + format.nSamplesPerSec=2000000; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + oformat=format; + rc=waveOutOpen(&wout,device,&format,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==WAVERR_BADFORMAT || rc==MMSYSERR_INVALFLAG || + rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): opening the device at 2 MHz sample rate should fail: " + "rc=%s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + trace(" got %dx%2dx%d for %dx%2dx%d\n", + format.nSamplesPerSec, format.wBitsPerSample, + format.nChannels, + oformat.nSamplesPerSec, oformat.wBitsPerSample, + oformat.nChannels); + waveOutClose(wout); + } + + /* try some non PCM formats */ + format.wFormatTag=WAVE_FORMAT_MULAW; + format.nChannels=1; + format.wBitsPerSample=8; + format.nSamplesPerSec=8000; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + rc=waveOutOpen(&wout,device,&format,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR ||rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveOutClose(wout); + wave_out_test_deviceOut(device,1.0,1,0,&format,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,&format,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,&format,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + } else + trace("waveOutOpen(%s): WAVE_FORMAT_MULAW not supported\n", + dev_name(device)); + + wfa.wfx.wFormatTag=WAVE_FORMAT_IMA_ADPCM; + wfa.wfx.nChannels=1; + wfa.wfx.nSamplesPerSec=11025; + wfa.wfx.nAvgBytesPerSec=5588; + wfa.wfx.nBlockAlign=256; + wfa.wfx.wBitsPerSample=4; /* see imaadp32.c */ + wfa.wfx.cbSize=2; + wfa.wSamplesPerBlock=505; + rc=waveOutOpen(&wout,device,&wfa.wfx,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR ||rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveOutClose(wout); + /* TODO: teach wave_generate_* ADPCM + wave_out_test_deviceOut(device,1.0,1,0,&wfa.wfx,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,&wfa.wfx,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,&wfa.wfx,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + */ + } else + trace("waveOutOpen(%s): WAVE_FORMAT_IMA_ADPCM not supported\n", + dev_name(device)); + + /* test if WAVEFORMATEXTENSIBLE supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=2; + wfex.Format.wBitsPerSample=16; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveOutOpen(&wout,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveOutClose(wout); + wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + } else + trace("waveOutOpen(%s): WAVE_FORMAT_EXTENSIBLE not supported\n", + dev_name(device)); + + /* test if 4 channels supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=4; + wfex.Format.wBitsPerSample=16; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveOutOpen(&wout,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveOutClose(wout); + wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,0,CALLBACK_EVENT, + &capsA,winetest_interactive,TRUE,FALSE); + } else + trace("waveOutOpen(%s): 4 channels not supported\n", + dev_name(device)); + + /* test if 6 channels supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=6; + wfex.Format.wBitsPerSample=16; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveOutOpen(&wout,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveOutClose(wout); + wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + } else + trace("waveOutOpen(%s): 6 channels not supported\n", + dev_name(device)); + + if (0) + { + /* FIXME: ALSA doesn't like this format */ + /* test if 24 bit samples supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=2; + wfex.Format.wBitsPerSample=24; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveOutOpen(&wout,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveOutClose(wout); + wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + } else + trace("waveOutOpen(%s): 24 bit samples not supported\n", + dev_name(device)); + } + + /* test if 32 bit samples supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=2; + wfex.Format.wBitsPerSample=32; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + rc=waveOutOpen(&wout,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveOutClose(wout); + wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + } else + trace("waveOutOpen(%s): 32 bit samples not supported\n", + dev_name(device)); + + /* test if 32 bit float samples supported */ + wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE; + wfex.Format.nChannels=2; + wfex.Format.wBitsPerSample=32; + wfex.Format.nSamplesPerSec=22050; + wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; + wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec* + wfex.Format.nBlockAlign; + wfex.Format.cbSize=22; + wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; + wfex.dwChannelMask=SPEAKER_ALL; + wfex.SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + rc=waveOutOpen(&wout,device,&wfex.Format,0,0, + CALLBACK_NULL|WAVE_FORMAT_DIRECT); + ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT || + rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM, + "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc)); + if (rc==MMSYSERR_NOERROR) { + waveOutClose(wout); + wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,WAVE_FORMAT_2M16, + CALLBACK_EVENT,&capsA,winetest_interactive, + TRUE,FALSE); + } else + trace("waveOutOpen(%s): 32 bit float samples not supported\n", + dev_name(device)); +} + +static void wave_out_tests(void) +{ + WAVEOUTCAPSA capsA; + WAVEOUTCAPSW capsW; + WAVEFORMATEX format; + HWAVEOUT wout; + MMRESULT rc; + UINT ndev,d; + + ndev=waveOutGetNumDevs(); + trace("found %d WaveOut devices\n",ndev); + + rc=waveOutGetDevCapsA(ndev+1,&capsA,sizeof(capsA)); + ok(rc==MMSYSERR_BADDEVICEID, + "waveOutGetDevCapsA(%s): MMSYSERR_BADDEVICEID expected, got %s\n", + dev_name(ndev+1),mmsys_error(rc)); + + rc=waveOutGetDevCapsW(ndev+1,&capsW,sizeof(capsW)); + ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NOTSUPPORTED, + "waveOutGetDevCapsW(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(ndev+1),mmsys_error(rc)); + + rc=waveOutGetDevCapsA(WAVE_MAPPER,&capsA,sizeof(capsA)); + if (ndev>0) + ok(rc==MMSYSERR_NOERROR, + "waveOutGetDevCapsA(%s): MMSYSERR_NOERROR expected, got %s\n", + dev_name(WAVE_MAPPER),mmsys_error(rc)); + else + ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER, + "waveOutGetDevCapsA(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NODRIVER " + "expected, got %s\n",dev_name(WAVE_MAPPER),mmsys_error(rc)); + + rc=waveOutGetDevCapsW(WAVE_MAPPER,&capsW,sizeof(capsW)); + if (ndev>0) + ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED, + "waveOutGetDevCapsW(%s): MMSYSERR_NOERROR or MMSYSERR_NOTSUPPORTED " + "expected, got %s\n",dev_name(WAVE_MAPPER),mmsys_error(rc)); + else + ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER || + rc==MMSYSERR_NOTSUPPORTED, + "waveOutGetDevCapsW(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NODRIVER " + " or MMSYSERR_NOTSUPPORTED expected, got %s\n", + dev_name(WAVE_MAPPER),mmsys_error(rc)); + + format.wFormatTag=WAVE_FORMAT_PCM; + format.nChannels=2; + format.wBitsPerSample=16; + format.nSamplesPerSec=44100; + format.nBlockAlign=format.nChannels*format.wBitsPerSample/8; + format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign; + format.cbSize=0; + rc=waveOutOpen(&wout,ndev+1,&format,0,0,CALLBACK_NULL); + ok(rc==MMSYSERR_BADDEVICEID, + "waveOutOpen(%s): MMSYSERR_BADDEVICEID expected, got %s\n", + dev_name(ndev+1),mmsys_error(rc)); + + for (d=0;d0) + wave_out_test_device(WAVE_MAPPER); +} + +START_TEST(wave) +{ + test_multiple_waveopens(); + wave_out_tests(); +} diff --git a/rostests/winetests/winmm/winmm.rbuild b/rostests/winetests/winmm/winmm.rbuild new file mode 100644 index 00000000000..778b2e6dead --- /dev/null +++ b/rostests/winetests/winmm/winmm.rbuild @@ -0,0 +1,15 @@ + + + . + + dxguid + winmm + user32 + capture.c + mci.c + mixer.c + mmio.c + timer.c + wave.c + testlist.c + diff --git a/rostests/winetests/winmm/winmm_test.h b/rostests/winetests/winmm/winmm_test.h new file mode 100644 index 00000000000..177dc2e837b --- /dev/null +++ b/rostests/winetests/winmm/winmm_test.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002 Francois Gouget + * + * 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 + */ + +#ifndef WAVE_FORMAT_48M08 +#define WAVE_FORMAT_48M08 0x00001000 /* 48 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_48S08 0x00002000 /* 48 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_48M16 0x00004000 /* 48 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_48S16 0x00008000 /* 48 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */ +#endif + +#ifndef DRV_QUERYDEVICEINTERFACE +#define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12) +#endif +#ifndef DRV_QUERYDEVICEINTERFACESIZE +#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13) +#endif + +static const unsigned int win_formats[][4] = { + {0, 8000, 8, 1}, + {0, 8000, 8, 2}, + {0, 8000, 16, 1}, + {0, 8000, 16, 2}, + {WAVE_FORMAT_1M08, 11025, 8, 1}, + {WAVE_FORMAT_1S08, 11025, 8, 2}, + {WAVE_FORMAT_1M16, 11025, 16, 1}, + {WAVE_FORMAT_1S16, 11025, 16, 2}, + {0, 12000, 8, 1}, + {0, 12000, 8, 2}, + {0, 12000, 16, 1}, + {0, 12000, 16, 2}, + {0, 16000, 8, 1}, + {0, 16000, 8, 2}, + {0, 16000, 16, 1}, + {0, 16000, 16, 2}, + {WAVE_FORMAT_2M08, 22050, 8, 1}, + {WAVE_FORMAT_2S08, 22050, 8, 2}, + {WAVE_FORMAT_2M16, 22050, 16, 1}, + {WAVE_FORMAT_2S16, 22050, 16, 2}, + {WAVE_FORMAT_4M08, 44100, 8, 1}, + {WAVE_FORMAT_4S08, 44100, 8, 2}, + {WAVE_FORMAT_4M16, 44100, 16, 1}, + {WAVE_FORMAT_4S16, 44100, 16, 2}, + {WAVE_FORMAT_48M08, 48000, 8, 1}, + {WAVE_FORMAT_48S08, 48000, 8, 2}, + {WAVE_FORMAT_48M16, 48000, 16, 1}, + {WAVE_FORMAT_48S16, 48000, 16, 2}, + {WAVE_FORMAT_96M08, 96000, 8, 1}, + {WAVE_FORMAT_96S08, 96000, 8, 2}, + {WAVE_FORMAT_96M16, 96000, 16, 1}, + {WAVE_FORMAT_96S16, 96000, 16, 2} +}; +#define NB_WIN_FORMATS (sizeof(win_formats)/sizeof(*win_formats)) + +extern const char* dev_name(int); +extern const char* wave_open_flags(DWORD); +extern const char* mmsys_error(MMRESULT); +extern const char* wave_out_error(MMRESULT); +extern const char* get_format_str(WORD format); +extern const char* wave_time_format(UINT type); +extern DWORD bytes_to_samples(DWORD bytes, LPWAVEFORMATEX pwfx); +extern DWORD bytes_to_ms(DWORD bytes, LPWAVEFORMATEX pwfx); +extern DWORD time_to_bytes(LPMMTIME mmtime, LPWAVEFORMATEX pwfx); diff --git a/rostests/winetests/wintrust/asn.c b/rostests/winetests/wintrust/asn.c new file mode 100644 index 00000000000..2fa45c6ceac --- /dev/null +++ b/rostests/winetests/wintrust/asn.c @@ -0,0 +1,961 @@ +/* Unit test suite for wintrust asn functions + * + * Copyright 2007 Juan Lang + * + * 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 + * + */ +#include +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wincrypt.h" +#include "wintrust.h" + +#include "wine/test.h" + +static BOOL (WINAPI *pCryptDecodeObjectEx)(DWORD,LPCSTR,const BYTE*,DWORD,DWORD,PCRYPT_DECODE_PARA,void*,DWORD*); +static BOOL (WINAPI *pCryptEncodeObjectEx)(DWORD,LPCSTR,const void*,DWORD,PCRYPT_ENCODE_PARA,void*,DWORD*); + +static const BYTE falseCriteria[] = { 0x30,0x06,0x01,0x01,0x00,0x01,0x01,0x00 }; +static const BYTE trueCriteria[] = { 0x30,0x06,0x01,0x01,0xff,0x01,0x01,0xff }; + +static void test_encodeSPCFinancialCriteria(void) +{ + BOOL ret; + DWORD size = 0; + LPBYTE buf; + SPC_FINANCIAL_CRITERIA criteria = { FALSE, FALSE }; + + if (!pCryptEncodeObjectEx) + { + win_skip("CryptEncodeObjectEx() is not available. Skipping the encodeFinancialCriteria tests\n"); + return; + } + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_FINANCIAL_CRITERIA_STRUCT, + &criteria, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(falseCriteria), "Unexpected size %d\n", size); + ok(!memcmp(buf, falseCriteria, size), "Unexpected value\n"); + LocalFree(buf); + } + criteria.fFinancialInfoAvailable = criteria.fMeetsCriteria = TRUE; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_FINANCIAL_CRITERIA_STRUCT, + &criteria, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(trueCriteria), "Unexpected size %d\n", size); + ok(!memcmp(buf, trueCriteria, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeSPCFinancialCriteria(void) +{ + BOOL ret; + SPC_FINANCIAL_CRITERIA criteria; + DWORD size = sizeof(criteria); + + if (!pCryptDecodeObjectEx) + { + win_skip("CryptDecodeObjectEx() is not available. Skipping the decodeSPCFinancialCriteria tests\n"); + return; + } + + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_FINANCIAL_CRITERIA_STRUCT, + falseCriteria, sizeof(falseCriteria), 0, NULL, &criteria, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(!criteria.fFinancialInfoAvailable, "expected FALSE\n"); + ok(!criteria.fMeetsCriteria, "expected FALSE\n"); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_FINANCIAL_CRITERIA_STRUCT, + trueCriteria, sizeof(trueCriteria), 0, NULL, &criteria, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(criteria.fFinancialInfoAvailable, "expected TRUE\n"); + ok(criteria.fMeetsCriteria, "expected TRUE\n"); + } +} + +static WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.', + 'o','r','g',0 }; +static const WCHAR nihongoURL[] = { 'h','t','t','p',':','/','/',0x226f, + 0x575b, 0 }; +static const BYTE emptyURLSPCLink[] = { 0x80,0x00 }; +static const BYTE urlSPCLink[] = { +0x80,0x11,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e,0x65,0x68,0x71, +0x2e,0x6f,0x72,0x67}; +static const BYTE fileSPCLink[] = { +0xa2,0x14,0x80,0x12,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00, +0x2f,0x00,0x2f,0x22,0x6f,0x57,0x5b }; +static const BYTE emptyMonikerSPCLink[] = { +0xa1,0x14,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x04,0x00 }; +static BYTE data[] = { 0xba, 0xad, 0xf0, 0x0d }; +static const BYTE monikerSPCLink[] = { +0xa1,0x18,0x04,0x10,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea, +0xea,0xea,0xea,0xea,0xea,0x04,0x04,0xba,0xad,0xf0,0x0d }; + +static void test_encodeSPCLink(void) +{ + BOOL ret; + DWORD size = 0; + LPBYTE buf; + SPC_LINK link = { 0 }; + + if (!pCryptEncodeObjectEx) + { + win_skip("CryptEncodeObjectEx() is not available. Skipping the encodeSPCLink tests\n"); + return; + } + + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + link.dwLinkChoice = SPC_URL_LINK_CHOICE; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptyURLSPCLink), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyURLSPCLink, size), "Unexpected value\n"); + LocalFree(buf); + } + /* With an invalid char: */ + U(link).pwszUrl = (LPWSTR)nihongoURL; + size = 1; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && + (GetLastError() == CRYPT_E_INVALID_IA5_STRING || + GetLastError() == OSS_BAD_PTR /* Win9x */), + "Expected CRYPT_E_INVALID_IA5_STRING, got %08x\n", GetLastError()); + /* Unlike the crypt32 string encoding routines, size is not set to the + * index of the first invalid character. + */ + ok(size == 0, "Expected size 0, got %d\n", size); + U(link).pwszUrl = url; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(urlSPCLink), "Unexpected size %d\n", size); + ok(!memcmp(buf, urlSPCLink, size), "Unexpected value\n"); + LocalFree(buf); + } + link.dwLinkChoice = SPC_FILE_LINK_CHOICE; + U(link).pwszFile = (LPWSTR)nihongoURL; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(fileSPCLink), "Unexpected size %d\n", size); + ok(!memcmp(buf, fileSPCLink, size), "Unexpected value\n"); + LocalFree(buf); + } + link.dwLinkChoice = SPC_MONIKER_LINK_CHOICE; + memset(&U(link).Moniker, 0, sizeof(U(link).Moniker)); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptyMonikerSPCLink), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyMonikerSPCLink, size), "Unexpected value\n"); + LocalFree(buf); + } + memset(&U(link).Moniker.ClassId, 0xea, sizeof(U(link).Moniker.ClassId)); + U(link).Moniker.SerializedData.pbData = data; + U(link).Moniker.SerializedData.cbData = sizeof(data); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link, + CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(monikerSPCLink), "Unexpected size %d\n", size); + ok(!memcmp(buf, monikerSPCLink, size), "Unexpected value\n"); + LocalFree(buf); + } +} + +static const BYTE badMonikerSPCLink[] = { +0xa1,0x19,0x04,0x11,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea, +0xea,0xea,0xea,0xea,0xea,0xea,0x04,0x04,0xba,0xad,0xf0,0x0d }; + +static void test_decodeSPCLink(void) +{ + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + SPC_LINK *link; + + if (!pCryptDecodeObjectEx) + { + win_skip("CryptDecodeObjectEx() is not available. Skipping the decodeSPCLink tests\n"); + return; + } + + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, + emptyURLSPCLink, sizeof(emptyURLSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + link = (SPC_LINK *)buf; + ok(link->dwLinkChoice == SPC_URL_LINK_CHOICE, + "Expected SPC_URL_LINK_CHOICE, got %d\n", link->dwLinkChoice); + ok(lstrlenW(U(*link).pwszUrl) == 0, "Expected empty string\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, + urlSPCLink, sizeof(urlSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + link = (SPC_LINK *)buf; + ok(link->dwLinkChoice == SPC_URL_LINK_CHOICE, + "Expected SPC_URL_LINK_CHOICE, got %d\n", link->dwLinkChoice); + ok(!lstrcmpW(U(*link).pwszUrl, url), "Unexpected URL\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, + fileSPCLink, sizeof(fileSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + link = (SPC_LINK *)buf; + ok(link->dwLinkChoice == SPC_FILE_LINK_CHOICE, + "Expected SPC_FILE_LINK_CHOICE, got %d\n", link->dwLinkChoice); + ok(!lstrcmpW(U(*link).pwszFile, nihongoURL), "Unexpected file\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, + emptyMonikerSPCLink, sizeof(emptyMonikerSPCLink), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + SPC_SERIALIZED_OBJECT emptyMoniker = { { 0 } }; + + link = (SPC_LINK *)buf; + ok(link->dwLinkChoice == SPC_MONIKER_LINK_CHOICE, + "Expected SPC_MONIKER_LINK_CHOICE, got %d\n", link->dwLinkChoice); + ok(!memcmp(&U(*link).Moniker.ClassId, &emptyMoniker.ClassId, + sizeof(emptyMoniker.ClassId)), "Unexpected value\n"); + ok(U(*link).Moniker.SerializedData.cbData == 0, + "Expected no serialized data\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, + monikerSPCLink, sizeof(monikerSPCLink), CRYPT_DECODE_ALLOC_FLAG, NULL, + &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + SPC_UUID id; + + link = (SPC_LINK *)buf; + ok(link->dwLinkChoice == SPC_MONIKER_LINK_CHOICE, + "Expected SPC_MONIKER_LINK_CHOICE, got %d\n", link->dwLinkChoice); + memset(&id, 0xea, sizeof(id)); + ok(!memcmp(&U(*link).Moniker.ClassId, &id, sizeof(id)), + "Unexpected value\n"); + ok(U(*link).Moniker.SerializedData.cbData == sizeof(data), + "Unexpected data size %d\n", U(*link).Moniker.SerializedData.cbData); + ok(!memcmp(U(*link).Moniker.SerializedData.pbData, data, sizeof(data)), + "Unexpected value\n"); + LocalFree(buf); + } + SetLastError(0xdeadbeef); + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, + badMonikerSPCLink, sizeof(badMonikerSPCLink), CRYPT_DECODE_ALLOC_FLAG, + NULL, &buf, &size); + ok(!ret && + (GetLastError() == CRYPT_E_BAD_ENCODE || + GetLastError() == OSS_DATA_ERROR /* Win9x */), + "Expected CRYPT_E_BAD_ENCODE, got %08x\n", GetLastError()); +} + +static const BYTE emptySequence[] = { 0x30,0x00 }; +static BYTE flags[] = { 1 }; +static const BYTE onlyFlagsPEImage[] = { 0x30,0x04,0x03,0x02,0x00,0x01 }; +static const BYTE moreFlagsPEImage[] = { +0x30,0x06,0x03,0x04,0x04,0xff,0x80,0x10 }; +static const BYTE onlyEmptyFilePEImage[] = { +0x30,0x06,0xa0,0x04,0xa2,0x02,0x80,0x00 }; +static const BYTE flagsAndEmptyFilePEImage[] = { +0x30,0x0a,0x03,0x02,0x00,0x01,0xa0,0x04,0xa2,0x02,0x80,0x00 }; +static const BYTE flagsAndFilePEImage[] = { +0x30,0x1c,0x03,0x02,0x00,0x01,0xa0,0x16,0xa2,0x14,0x80,0x12,0x00,0x68,0x00, +0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,0x2f,0x22,0x6f,0x57,0x5b }; + +static void test_encodeSPCPEImage(void) +{ + BOOL ret; + DWORD size = 0; + LPBYTE buf; + SPC_PE_IMAGE_DATA imageData = { { 0 } }; + SPC_LINK link = { 0 }; + + if (!pCryptEncodeObjectEx) + { + win_skip("CryptEncodeObjectEx() is not available. Skipping the encodeSPCPEImage tests\n"); + return; + } + + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptySequence), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, sizeof(emptySequence)), + "Unexpected value\n"); + LocalFree(buf); + } + /* With an invalid link: */ + imageData.pFile = &link; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError () == E_INVALIDARG, + "Expected E_INVALIDARG, got %08x\n", GetLastError()); + /* With just unused bits field set: */ + imageData.pFile = NULL; + imageData.Flags.cUnusedBits = 1; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptySequence), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, sizeof(emptySequence)), + "Unexpected value\n"); + LocalFree(buf); + } + /* With flags set: */ + imageData.Flags.cUnusedBits = 0; + imageData.Flags.pbData = flags; + imageData.Flags.cbData = sizeof(flags); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + if (!ret && GetLastError() == OSS_TOO_LONG) + { + skip("SPC_PE_IMAGE_DATA_STRUCT not supported\n"); + return; + } + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(onlyFlagsPEImage), "Unexpected size %d\n", size); + ok(!memcmp(buf, onlyFlagsPEImage, sizeof(onlyFlagsPEImage)), + "Unexpected value\n"); + LocalFree(buf); + } + /* With just an empty file: */ + imageData.Flags.cbData = 0; + link.dwLinkChoice = SPC_FILE_LINK_CHOICE; + imageData.pFile = &link; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(onlyEmptyFilePEImage), "Unexpected size %d\n", size); + ok(!memcmp(buf, onlyEmptyFilePEImage, sizeof(onlyEmptyFilePEImage)), + "Unexpected value\n"); + LocalFree(buf); + } + /* With flags and an empty file: */ + imageData.Flags.pbData = flags; + imageData.Flags.cbData = sizeof(flags); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(flagsAndEmptyFilePEImage), "Unexpected size %d\n", + size); + ok(!memcmp(buf, flagsAndEmptyFilePEImage, + sizeof(flagsAndEmptyFilePEImage)), "Unexpected value\n"); + LocalFree(buf); + } + /* Finally, a non-empty file: */ + U(link).pwszFile = (LPWSTR)nihongoURL; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(flagsAndFilePEImage), "Unexpected size %d\n", size); + ok(!memcmp(buf, flagsAndFilePEImage, sizeof(flagsAndFilePEImage)), + "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeSPCPEImage(void) +{ + static const WCHAR emptyString[] = { 0 }; + BOOL ret; + LPBYTE buf = NULL; + DWORD size = 0; + SPC_PE_IMAGE_DATA *imageData; + + if (!pCryptDecodeObjectEx) + { + win_skip("CryptDecodeObjectEx() is not available. Skipping the decodeSPCPEImage tests\n"); + return; + } + + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + emptySequence, sizeof(emptySequence), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + imageData = (SPC_PE_IMAGE_DATA *)buf; + ok(imageData->Flags.cbData == 0, "Expected empty flags, got %d\n", + imageData->Flags.cbData); + ok(imageData->pFile == NULL, "Expected no file\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + onlyFlagsPEImage, sizeof(onlyFlagsPEImage), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + imageData = (SPC_PE_IMAGE_DATA *)buf; + ok(imageData->Flags.cbData == sizeof(flags), + "Unexpected flags size %d\n", imageData->Flags.cbData); + if (imageData->Flags.cbData) + ok(!memcmp(imageData->Flags.pbData, flags, sizeof(flags)), + "Unexpected flags\n"); + ok(imageData->pFile == NULL, "Expected no file\n"); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + onlyEmptyFilePEImage, sizeof(onlyEmptyFilePEImage), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + imageData = (SPC_PE_IMAGE_DATA *)buf; + ok(imageData->Flags.cbData == 0, "Expected empty flags, got %d\n", + imageData->Flags.cbData); + ok(imageData->pFile != NULL, "Expected a file\n"); + if (imageData->pFile) + { + ok(imageData->pFile->dwLinkChoice == SPC_FILE_LINK_CHOICE, + "Expected SPC_FILE_LINK_CHOICE, got %d\n", + imageData->pFile->dwLinkChoice); + ok(!lstrcmpW(U(*imageData->pFile).pwszFile, emptyString), + "Unexpected file\n"); + } + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + flagsAndEmptyFilePEImage, sizeof(flagsAndEmptyFilePEImage), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + imageData = (SPC_PE_IMAGE_DATA *)buf; + ok(imageData->Flags.cbData == sizeof(flags), + "Unexpected flags size %d\n", imageData->Flags.cbData); + if (imageData->Flags.cbData) + ok(!memcmp(imageData->Flags.pbData, flags, sizeof(flags)), + "Unexpected flags\n"); + ok(imageData->pFile != NULL, "Expected a file\n"); + if (imageData->pFile) + { + ok(imageData->pFile->dwLinkChoice == SPC_FILE_LINK_CHOICE, + "Expected SPC_FILE_LINK_CHOICE, got %d\n", + imageData->pFile->dwLinkChoice); + ok(!lstrcmpW(U(*imageData->pFile).pwszFile, emptyString), + "Unexpected file\n"); + } + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT, + flagsAndFilePEImage, sizeof(flagsAndFilePEImage), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + imageData = (SPC_PE_IMAGE_DATA *)buf; + ok(imageData->Flags.cbData == sizeof(flags), + "Unexpected flags size %d\n", imageData->Flags.cbData); + if (imageData->Flags.cbData) + ok(!memcmp(imageData->Flags.pbData, flags, sizeof(flags)), + "Unexpected flags\n"); + ok(imageData->pFile != NULL, "Expected a file\n"); + if (imageData->pFile) + { + ok(imageData->pFile->dwLinkChoice == SPC_FILE_LINK_CHOICE, + "Expected SPC_FILE_LINK_CHOICE, got %d\n", + imageData->pFile->dwLinkChoice); + ok(!lstrcmpW(U(*imageData->pFile).pwszFile, nihongoURL), + "Unexpected file\n"); + } + LocalFree(buf); + } +} + +static WCHAR foo[] = { 'f','o','o',0 }; +static WCHAR guidStr[] = { '{','8','b','c','9','6','b','0','0','-', + '8','d','a','1','-','1','1','c','f','-','8','7','3','6','-','0','0', + 'a','a','0','0','a','4','8','5','e','b','}',0 }; + +static const BYTE emptyCatMemberInfo[] = { 0x30,0x05,0x1e,0x00,0x02,0x01,0x00 }; +static const BYTE catMemberInfoWithSillyGuid[] = { +0x30,0x0b,0x1e,0x06,0x00,0x66,0x00,0x6f,0x00,0x6f,0x02,0x01,0x00 }; +static const BYTE catMemberInfoWithGuid[] = { +0x30,0x51,0x1e,0x4c,0x00,0x7b,0x00,0x38,0x00,0x62,0x00,0x63,0x00,0x39,0x00,0x36, +0x00,0x62,0x00,0x30,0x00,0x30,0x00,0x2d,0x00,0x38,0x00,0x64,0x00,0x61,0x00,0x31, +0x00,0x2d,0x00,0x31,0x00,0x31,0x00,0x63,0x00,0x66,0x00,0x2d,0x00,0x38,0x00,0x37, +0x00,0x33,0x00,0x36,0x00,0x2d,0x00,0x30,0x00,0x30,0x00,0x61,0x00,0x61,0x00,0x30, +0x00,0x30,0x00,0x61,0x00,0x34,0x00,0x38,0x00,0x35,0x00,0x65,0x00,0x62,0x00,0x7d, +0x02,0x01,0x00 }; + +static void test_encodeCatMemberInfo(void) +{ + CAT_MEMBERINFO info; + BOOL ret; + DWORD size = 0; + LPBYTE buf; + + memset(&info, 0, sizeof(info)); + + if (!pCryptEncodeObjectEx) + { + win_skip("CryptEncodeObjectEx() is not available. Skipping the encodeCatMemberInfo tests\n"); + return; + } + + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptyCatMemberInfo), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyCatMemberInfo, sizeof(emptyCatMemberInfo)), + "Unexpected value\n"); + LocalFree(buf); + } + info.pwszSubjGuid = foo; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(catMemberInfoWithSillyGuid), "Unexpected size %d\n", + size); + ok(!memcmp(buf, catMemberInfoWithSillyGuid, + sizeof(catMemberInfoWithSillyGuid)), "Unexpected value\n"); + LocalFree(buf); + } + info.pwszSubjGuid = guidStr; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(catMemberInfoWithGuid), "Unexpected size %d\n", + size); + ok(!memcmp(buf, catMemberInfoWithGuid, sizeof(catMemberInfoWithGuid)), + "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeCatMemberInfo(void) +{ + BOOL ret; + LPBYTE buf; + DWORD size; + CAT_MEMBERINFO *info; + + if (!pCryptDecodeObjectEx) + { + win_skip("CryptDecodeObjectEx() is not available. Skipping the decodeCatMemberInfo tests\n"); + return; + } + + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT, + emptyCatMemberInfo, sizeof(emptyCatMemberInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + info = (CAT_MEMBERINFO *)buf; + ok(!info->pwszSubjGuid || !info->pwszSubjGuid[0], + "expected empty pwszSubjGuid\n"); + ok(info->dwCertVersion == 0, "expected dwCertVersion == 0, got %d\n", + info->dwCertVersion); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT, + catMemberInfoWithSillyGuid, sizeof(catMemberInfoWithSillyGuid), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + info = (CAT_MEMBERINFO *)buf; + ok(info->pwszSubjGuid && !lstrcmpW(info->pwszSubjGuid, foo), + "unexpected pwszSubjGuid\n"); + ok(info->dwCertVersion == 0, "expected dwCertVersion == 0, got %d\n", + info->dwCertVersion); + LocalFree(buf); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_MEMBERINFO_STRUCT, + catMemberInfoWithGuid, sizeof(catMemberInfoWithGuid), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + info = (CAT_MEMBERINFO *)buf; + ok(info->pwszSubjGuid && !lstrcmpW(info->pwszSubjGuid, guidStr), + "unexpected pwszSubjGuid\n"); + ok(info->dwCertVersion == 0, "expected dwCertVersion == 0, got %d\n", + info->dwCertVersion); + LocalFree(buf); + } +} + +static const BYTE emptyCatNameValue[] = { +0x30,0x07,0x1e,0x00,0x02,0x01,0x00,0x04,0x00 }; +static const BYTE catNameValueWithTag[] = { +0x30,0x0d,0x1e,0x06,0x00,0x66,0x00,0x6f,0x00,0x6f,0x02,0x01,0x00,0x04,0x00 }; +static const BYTE catNameValueWithFlags[] = { +0x30,0x0a,0x1e,0x00,0x02,0x04,0xf0,0x0d,0xd0,0x0d,0x04,0x00 }; +static const BYTE catNameValueWithValue[] = { +0x30,0x0b,0x1e,0x00,0x02,0x01,0x00,0x04,0x04,0x01,0x02,0x03,0x04 }; + +static BYTE aVal[] = { 1,2,3,4 }; + +static void test_encodeCatNameValue(void) +{ + static WCHAR foo[] = { 'f','o','o',0 }; + BOOL ret; + LPBYTE buf; + DWORD size; + CAT_NAMEVALUE value; + + memset(&value, 0, sizeof(value)); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT, + &value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptyCatNameValue), "Unexpected size %d\n", size); + ok(!memcmp(buf, emptyCatNameValue, sizeof(emptyCatNameValue)), + "Unexpected value\n"); + LocalFree(buf); + } + value.pwszTag = foo; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT, + &value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(catNameValueWithTag), "Unexpected size %d\n", size); + ok(!memcmp(buf, catNameValueWithTag, sizeof(catNameValueWithTag)), + "Unexpected value\n"); + LocalFree(buf); + } + value.pwszTag = NULL; + value.fdwFlags = 0xf00dd00d; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT, + &value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(catNameValueWithFlags), "Unexpected size %d\n", size); + ok(!memcmp(buf, catNameValueWithFlags, sizeof(catNameValueWithFlags)), + "Unexpected value\n"); + LocalFree(buf); + } + value.fdwFlags = 0; + value.Value.cbData = sizeof(aVal); + value.Value.pbData = aVal; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT, + &value, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(catNameValueWithValue), "Unexpected size %d\n", size); + ok(!memcmp(buf, catNameValueWithValue, sizeof(catNameValueWithValue)), + "Unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeCatNameValue(void) +{ + BOOL ret; + LPBYTE buf; + DWORD size; + CAT_NAMEVALUE *value; + + buf = NULL; + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT, + emptyCatNameValue, sizeof(emptyCatNameValue), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + value = (CAT_NAMEVALUE *)buf; + ok(!value->pwszTag || !value->pwszTag[0], "expected empty pwszTag\n"); + ok(value->fdwFlags == 0, "expected fdwFlags == 0, got %08x\n", + value->fdwFlags); + ok(value->Value.cbData == 0, "expected 0-length value, got %d\n", + value->Value.cbData); + LocalFree(buf); + } + buf = NULL; + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT, + catNameValueWithTag, sizeof(catNameValueWithTag), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + value = (CAT_NAMEVALUE *)buf; + ok(value->pwszTag && !lstrcmpW(value->pwszTag, foo), + "unexpected pwszTag\n"); + ok(value->fdwFlags == 0, "expected fdwFlags == 0, got %08x\n", + value->fdwFlags); + ok(value->Value.cbData == 0, "expected 0-length value, got %d\n", + value->Value.cbData); + LocalFree(buf); + } + buf = NULL; + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT, + catNameValueWithFlags, sizeof(catNameValueWithFlags), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + value = (CAT_NAMEVALUE *)buf; + ok(!value->pwszTag || !value->pwszTag[0], "expected empty pwszTag\n"); + ok(value->fdwFlags == 0xf00dd00d, + "expected fdwFlags == 0xf00dd00d, got %08x\n", value->fdwFlags); + ok(value->Value.cbData == 0, "expected 0-length value, got %d\n", + value->Value.cbData); + LocalFree(buf); + } + buf = NULL; + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, CAT_NAMEVALUE_STRUCT, + catNameValueWithValue, sizeof(catNameValueWithValue), + CRYPT_DECODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + value = (CAT_NAMEVALUE *)buf; + ok(!value->pwszTag || !value->pwszTag[0], "expected empty pwszTag\n"); + ok(value->fdwFlags == 0, "expected fdwFlags == 0, got %08x\n", + value->fdwFlags); + ok(value->Value.cbData == sizeof(aVal), "unexpected size %d\n", + value->Value.cbData); + ok(!memcmp(value->Value.pbData, aVal, value->Value.cbData), + "unexpected value\n"); + LocalFree(buf); + } +} + +static const WCHAR progName[] = { 'A',' ','p','r','o','g','r','a','m',0 }; +static const BYTE spOpusInfoWithProgramName[] = { +0x30,0x16,0xa0,0x14,0x80,0x12,0x00,0x41,0x00,0x20,0x00,0x70,0x00,0x72,0x00,0x6f, +0x00,0x67,0x00,0x72,0x00,0x61,0x00,0x6d }; +static WCHAR winehq[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q', + '.','o','r','g','/',0 }; +static const BYTE spOpusInfoWithMoreInfo[] = { +0x30,0x16,0xa1,0x14,0x80,0x12,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e, +0x65,0x68,0x71,0x2e,0x6f,0x72,0x67,0x2f }; +static const BYTE spOpusInfoWithPublisherInfo[] = { +0x30,0x16,0xa2,0x14,0x80,0x12,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x69,0x6e, +0x65,0x68,0x71,0x2e,0x6f,0x72,0x67,0x2f }; + +static void test_encodeSpOpusInfo(void) +{ + BOOL ret; + LPBYTE buf; + DWORD size; + SPC_SP_OPUS_INFO info; + SPC_LINK moreInfo; + + memset(&info, 0, sizeof(info)); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(emptySequence), "unexpected size %d\n", size); + ok(!memcmp(buf, emptySequence, size), "unexpected value\n"); + LocalFree(buf); + } + info.pwszProgramName = progName; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(spOpusInfoWithProgramName), "unexpected size %d\n", + size); + ok(!memcmp(buf, spOpusInfoWithProgramName, size), + "unexpected value\n"); + LocalFree(buf); + } + info.pwszProgramName = NULL; + memset(&moreInfo, 0, sizeof(moreInfo)); + info.pMoreInfo = &moreInfo; + SetLastError(0xdeadbeef); + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(!ret && GetLastError() == E_INVALIDARG, + "expected E_INVALIDARG, got %08x\n", GetLastError()); + moreInfo.dwLinkChoice = SPC_URL_LINK_CHOICE; + U(moreInfo).pwszUrl = winehq; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(spOpusInfoWithMoreInfo), + "unexpected size %d\n", size); + ok(!memcmp(buf, spOpusInfoWithMoreInfo, size), + "unexpected value\n"); + LocalFree(buf); + } + info.pMoreInfo = NULL; + info.pPublisherInfo = &moreInfo; + ret = pCryptEncodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size); + ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(size == sizeof(spOpusInfoWithPublisherInfo), + "unexpected size %d\n", size); + ok(!memcmp(buf, spOpusInfoWithPublisherInfo, size), + "unexpected value\n"); + LocalFree(buf); + } +} + +static void test_decodeSpOpusInfo(void) +{ + BOOL ret; + DWORD size; + SPC_SP_OPUS_INFO *info; + + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + emptySequence, sizeof(emptySequence), CRYPT_DECODE_ALLOC_FLAG, NULL, + &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(!info->pwszProgramName, "expected NULL\n"); + ok(!info->pMoreInfo, "expected NULL\n"); + ok(!info->pPublisherInfo, "expected NULL\n"); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + spOpusInfoWithProgramName, sizeof(spOpusInfoWithProgramName), + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(info->pwszProgramName && !lstrcmpW(info->pwszProgramName, + progName), "unexpected program name\n"); + ok(!info->pMoreInfo, "expected NULL\n"); + ok(!info->pPublisherInfo, "expected NULL\n"); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + spOpusInfoWithMoreInfo, sizeof(spOpusInfoWithMoreInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(!info->pwszProgramName, "expected NULL\n"); + ok(info->pMoreInfo != NULL, "expected a value for pMoreInfo\n"); + if (info->pMoreInfo) + { + ok(info->pMoreInfo->dwLinkChoice == SPC_URL_LINK_CHOICE, + "unexpected link choice %d\n", info->pMoreInfo->dwLinkChoice); + ok(!lstrcmpW(U(*info->pMoreInfo).pwszUrl, winehq), + "unexpected link value\n"); + } + ok(!info->pPublisherInfo, "expected NULL\n"); + LocalFree(info); + } + ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, SPC_SP_OPUS_INFO_STRUCT, + spOpusInfoWithPublisherInfo, sizeof(spOpusInfoWithPublisherInfo), + CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "CryptDecodeObjectEx failed: %08x\n", GetLastError()); + if (ret) + { + ok(!info->pwszProgramName, "expected NULL\n"); + ok(!info->pMoreInfo, "expected NULL\n"); + ok(info->pPublisherInfo != NULL, + "expected a value for pPublisherInfo\n"); + if (info->pPublisherInfo) + { + ok(info->pPublisherInfo->dwLinkChoice == SPC_URL_LINK_CHOICE, + "unexpected link choice %d\n", + info->pPublisherInfo->dwLinkChoice); + ok(!lstrcmpW(U(*info->pPublisherInfo).pwszUrl, winehq), + "unexpected link value\n"); + } + LocalFree(info); + } +} + +START_TEST(asn) +{ + HMODULE hCrypt32 = LoadLibraryA("crypt32.dll"); + pCryptDecodeObjectEx = (void*)GetProcAddress(hCrypt32, "CryptDecodeObjectEx"); + pCryptEncodeObjectEx = (void*)GetProcAddress(hCrypt32, "CryptEncodeObjectEx"); + + test_encodeSPCFinancialCriteria(); + test_decodeSPCFinancialCriteria(); + test_encodeSPCLink(); + test_decodeSPCLink(); + test_encodeSPCPEImage(); + test_decodeSPCPEImage(); + test_encodeCatMemberInfo(); + test_decodeCatMemberInfo(); + test_encodeCatNameValue(); + test_decodeCatNameValue(); + test_encodeSpOpusInfo(); + test_decodeSpOpusInfo(); + + FreeLibrary(hCrypt32); +} diff --git a/rostests/winetests/wintrust/crypt.c b/rostests/winetests/wintrust/crypt.c new file mode 100644 index 00000000000..3e77814079f --- /dev/null +++ b/rostests/winetests/wintrust/crypt.c @@ -0,0 +1,1145 @@ +/* Unit test suite for wintrust crypt functions + * + * Copyright 2007 Paul Vriens + * Copyright 2008 Hans Leidekker for CodeWeavers + * + * 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 + * + */ + +#include +#include + +#include "windows.h" +#include "mscat.h" + +#include "wine/test.h" + +static char selfname[MAX_PATH]; +static CHAR CURR_DIR[MAX_PATH]; +static CHAR catroot[MAX_PATH]; +static CHAR catroot2[MAX_PATH]; + +static const WCHAR hashmeW[] = {'h','a','s','h','m','e',0}; +static const WCHAR attr1W[] = {'a','t','t','r','1',0}; +static const WCHAR attr2W[] = {'a','t','t','r','2',0}; + +/* + * Minimalistic catalog file. To reconstruct, save text below as winetest.cdf, + * convert to DOS line endings and run 'makecat /cat winetest.cdf' + */ + +/* +[CatalogHeader] +Name=winetest.cat +ResultDir=.\ +PublicVersion=0x00000001 +EncodingType= +CATATTR1=0x10010001:attr1:value1 +CATATTR2=0x10010001:attr2:value2 + +[CatalogFiles] +hashme=.\winetest.cdf +*/ + +static const CHAR test_cdf[] = + "[CatalogHeader]\r\n" + "Name=winetest.cat\r\n" + "ResultDir=.\\\r\n" + "PublicVersion=0x00000001\r\n" + "EncodingType=\r\n" + "CATATTR1=0x10010001:attr1:value1\r\n" + "CATATTR2=0x10010001:attr2:value2\r\n" + "\r\n" + "[CatalogFiles]\r\n" + "hashme=.\\winetest.cdf\r\n"; + +static const BYTE test_catalog[] = { + 0x30, 0x82, 0x01, 0xbc, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, + 0x82, 0x01, 0xad, 0x30, 0x82, 0x01, 0xa9, 0x02, 0x01, 0x01, 0x31, 0x00, 0x30, 0x82, 0x01, 0x9e, + 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x01, 0xa0, 0x82, 0x01, 0x8f, 0x30, + 0x82, 0x01, 0x8b, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0c, 0x01, + 0x01, 0x04, 0x10, 0xfa, 0x55, 0x2c, 0xc2, 0xf6, 0xcc, 0xdd, 0x11, 0x2a, 0x9c, 0x00, 0x14, 0x22, + 0xec, 0x8f, 0x3b, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x32, 0x31, 0x38, 0x31, 0x31, 0x32, 0x36, 0x34, + 0x38, 0x5a, 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0c, 0x01, 0x02, + 0x05, 0x00, 0x30, 0x81, 0xdd, 0x30, 0x81, 0xda, 0x04, 0x0e, 0x68, 0x00, 0x61, 0x00, 0x73, 0x00, + 0x68, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x31, 0x81, 0xc7, 0x30, 0x61, 0x06, 0x0a, 0x2b, + 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04, 0x31, 0x53, 0x30, 0x51, 0x30, 0x2c, 0x06, + 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x19, 0xa2, 0x1e, 0x80, 0x1c, 0x00, + 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, + 0x65, 0x00, 0x74, 0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x30, 0x21, 0x30, 0x09, 0x06, + 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0xed, 0xd6, 0x9c, 0x9c, 0xb2, 0xfc, + 0xaa, 0x03, 0xe8, 0xd3, 0x20, 0xf6, 0xab, 0x28, 0xc3, 0xff, 0xbd, 0x07, 0x36, 0xf5, 0x30, 0x62, + 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0c, 0x02, 0x02, 0x31, 0x54, 0x30, 0x52, + 0x1e, 0x4c, 0x00, 0x7b, 0x00, 0x44, 0x00, 0x45, 0x00, 0x33, 0x00, 0x35, 0x00, 0x31, 0x00, 0x41, + 0x00, 0x34, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x45, 0x00, 0x35, 0x00, 0x39, 0x00, 0x2d, + 0x00, 0x31, 0x00, 0x31, 0x00, 0x44, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x34, + 0x00, 0x37, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x43, 0x00, 0x30, 0x00, 0x34, 0x00, 0x46, + 0x00, 0x43, 0x00, 0x32, 0x00, 0x39, 0x00, 0x35, 0x00, 0x45, 0x00, 0x45, 0x00, 0x7d, 0x02, 0x02, + 0x02, 0x00, 0xa0, 0x6a, 0x30, 0x68, 0x30, 0x32, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, + 0x37, 0x0c, 0x02, 0x01, 0x04, 0x24, 0x30, 0x22, 0x1e, 0x0a, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, + 0x00, 0x72, 0x00, 0x32, 0x02, 0x04, 0x10, 0x01, 0x00, 0x01, 0x04, 0x0e, 0x76, 0x00, 0x61, 0x00, + 0x6c, 0x00, 0x75, 0x00, 0x65, 0x00, 0x32, 0x00, 0x00, 0x00, 0x30, 0x32, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0x82, 0x37, 0x0c, 0x02, 0x01, 0x04, 0x24, 0x30, 0x22, 0x1e, 0x0a, 0x00, 0x61, + 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x02, 0x04, 0x10, 0x01, 0x00, 0x01, 0x04, 0x0e, + 0x76, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x31, 0x00, +}; + +static BOOL (WINAPI * pCryptCATAdminAcquireContext)(HCATADMIN*, const GUID*, DWORD); +static BOOL (WINAPI * pCryptCATAdminReleaseContext)(HCATADMIN, DWORD); +static BOOL (WINAPI * pCryptCATAdminCalcHashFromFileHandle)(HANDLE hFile, DWORD*, BYTE*, DWORD); +static HCATINFO (WINAPI * pCryptCATAdminAddCatalog)(HCATADMIN, PWSTR, PWSTR, DWORD); +static BOOL (WINAPI * pCryptCATAdminRemoveCatalog)(HCATADMIN, LPCWSTR, DWORD); +static BOOL (WINAPI * pCryptCATAdminReleaseCatalogContext)(HCATADMIN, HCATINFO, DWORD); +static HANDLE (WINAPI * pCryptCATOpen)(LPWSTR, DWORD, HCRYPTPROV, DWORD, DWORD); +static BOOL (WINAPI * pCryptCATCatalogInfoFromContext)(HCATINFO, CATALOG_INFO *, DWORD); +static BOOL (WINAPI * pCryptCATCDFClose)(CRYPTCATCDF *); +static CRYPTCATATTRIBUTE * (WINAPI * pCryptCATCDFEnumCatAttributes)(CRYPTCATCDF *, CRYPTCATATTRIBUTE *, + PFN_CDF_PARSE_ERROR_CALLBACK); +static LPWSTR (WINAPI * pCryptCATCDFEnumMembersByCDFTagEx)(CRYPTCATCDF *, LPWSTR, PFN_CDF_PARSE_ERROR_CALLBACK, + CRYPTCATMEMBER **, BOOL, LPVOID); +static CRYPTCATCDF * (WINAPI * pCryptCATCDFOpen)(LPWSTR, PFN_CDF_PARSE_ERROR_CALLBACK); +static CRYPTCATATTRIBUTE * (WINAPI * pCryptCATEnumerateCatAttr)(HANDLE, CRYPTCATATTRIBUTE *); +static CRYPTCATMEMBER * (WINAPI * pCryptCATEnumerateMember)(HANDLE, CRYPTCATMEMBER *); +static CRYPTCATATTRIBUTE * (WINAPI * pCryptCATEnumerateAttr)(HANDLE, CRYPTCATMEMBER *, CRYPTCATATTRIBUTE *); +static BOOL (WINAPI * pCryptCATClose)(HANDLE); + +static void InitFunctionPtrs(void) +{ + HMODULE hWintrust = GetModuleHandleA("wintrust.dll"); + +#define WINTRUST_GET_PROC(func) \ + p ## func = (void*)GetProcAddress(hWintrust, #func); \ + if(!p ## func) { \ + trace("GetProcAddress(%s) failed\n", #func); \ + } + + WINTRUST_GET_PROC(CryptCATAdminAcquireContext) + WINTRUST_GET_PROC(CryptCATAdminReleaseContext) + WINTRUST_GET_PROC(CryptCATAdminCalcHashFromFileHandle) + WINTRUST_GET_PROC(CryptCATAdminAddCatalog) + WINTRUST_GET_PROC(CryptCATAdminRemoveCatalog) + WINTRUST_GET_PROC(CryptCATAdminReleaseCatalogContext) + WINTRUST_GET_PROC(CryptCATOpen) + WINTRUST_GET_PROC(CryptCATCatalogInfoFromContext) + WINTRUST_GET_PROC(CryptCATCDFClose) + WINTRUST_GET_PROC(CryptCATCDFEnumCatAttributes) + WINTRUST_GET_PROC(CryptCATCDFEnumMembersByCDFTagEx) + WINTRUST_GET_PROC(CryptCATCDFOpen) + WINTRUST_GET_PROC(CryptCATEnumerateCatAttr) + WINTRUST_GET_PROC(CryptCATEnumerateMember) + WINTRUST_GET_PROC(CryptCATEnumerateAttr) + WINTRUST_GET_PROC(CryptCATClose) + +#undef WINTRUST_GET_PROC +} + +static GUID dummy = {0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}}; + +static void test_context(void) +{ + BOOL ret; + HCATADMIN hca; + static GUID unknown = { 0xC689AABA, 0x8E78, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; /* WINTRUST.DLL */ + CHAR dummydir[MAX_PATH]; + DWORD attrs; + + /* When CryptCATAdminAcquireContext is successful it will create + * several directories if they don't exist: + * + * ...\system32\CatRoot\{GUID}, this directory holds the .cat files + * ...\system32\CatRoot2\{GUID} (WinXP and up), here we find the catalog database for that GUID + * + * Windows Vista uses lowercase catroot and catroot2. + * + * When passed a NULL GUID it will create the following directories although on + * WinXP and up these directories are already present when Windows is installed: + * + * ...\system32\CatRoot\{127D0A1D-4EF2-11D1-8608-00C04FC295EE} + * ...\system32\CatRoot2\{127D0A1D-4EF2-11D1-8608-00C04FC295EE} (WinXP up) + * + * TODO: Find out what this GUID is/does. + * + * On WinXP and up there is also a TimeStamp file in some of directories that + * seem to indicate the last change to the catalog database for that GUID. + * + * On Windows 2000 some files are created/updated: + * + * ...\system32\CatRoot\SYSMAST.cbk + * ...\system32\CatRoot\SYSMAST.cbd + * ...\system32\CatRoot\{GUID}\CATMAST.cbk + * ...\system32\CatRoot\{GUID}\CATMAST.cbd + * + */ + + /* All NULL */ + SetLastError(0xdeadbeef); + ret = pCryptCATAdminAcquireContext(NULL, NULL, 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* NULL GUID */ + ret = pCryptCATAdminAcquireContext(&hca, NULL, 0); + ok(ret, "Expected success\n"); + ok(hca != NULL, "Expected a context handle, got NULL\n"); + + /* All NULL */ + SetLastError(0xdeadbeef); + ret = pCryptCATAdminReleaseContext(NULL, 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* Proper release */ + SetLastError(0xdeadbeef); + ret = pCryptCATAdminReleaseContext(hca, 0); + ok(ret, "Expected success, got FALSE with %d\n", GetLastError()); + + /* Try to release a second time */ + SetLastError(0xdeadbeef); + ret = pCryptCATAdminReleaseContext(hca, 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* NULL context handle and dummy GUID */ + SetLastError(0xdeadbeef); + ret = pCryptCATAdminAcquireContext(NULL, &dummy, 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* Correct context handle and dummy GUID + * + * The tests run in the past unfortunately made sure that some directories were created. + * + * FIXME: + * We don't want to mess too much with these for now so we should delete only the ones + * that shouldn't be there like the deadbeef ones. We first have to figure out if it's + * save to remove files and directories from CatRoot/CatRoot2. + */ + + ret = pCryptCATAdminAcquireContext(&hca, &dummy, 0); + ok(ret, "Expected success\n"); + ok(hca != NULL, "Expected a context handle, got NULL\n"); + + attrs = GetFileAttributes(catroot); + ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected the CatRoot directory to exist\n"); + + /* Windows creates the GUID directory in capitals */ + lstrcpyA(dummydir, catroot); + lstrcatA(dummydir, "\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}"); + attrs = GetFileAttributes(dummydir); + ok(attrs != INVALID_FILE_ATTRIBUTES, + "Expected CatRoot\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF} directory to exist\n"); + + /* Only present on XP or higher. */ + attrs = GetFileAttributes(catroot2); + if (attrs != INVALID_FILE_ATTRIBUTES) + { + lstrcpyA(dummydir, catroot2); + lstrcatA(dummydir, "\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}"); + attrs = GetFileAttributes(dummydir); + ok(attrs != INVALID_FILE_ATTRIBUTES, + "Expected CatRoot2\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF} directory to exist\n"); + } + + ret = pCryptCATAdminReleaseContext(hca, 0); + ok(ret, "Expected success\n"); + + /* Correct context handle and GUID */ + ret = pCryptCATAdminAcquireContext(&hca, &unknown, 0); + ok(ret, "Expected success\n"); + ok(hca != NULL, "Expected a context handle, got NULL\n"); + + ret = pCryptCATAdminReleaseContext(hca, 0); + ok(ret, "Expected success\n"); + + /* Flags not equal to 0 */ + ret = pCryptCATAdminAcquireContext(&hca, &unknown, 1); + ok(ret, "Expected success\n"); + ok(hca != NULL, "Expected a context handle, got NULL\n"); + + ret = pCryptCATAdminReleaseContext(hca, 0); + ok(ret, "Expected success\n"); +} + +/* TODO: Check whether SHA-1 is the algorithm that's always used */ +static void test_calchash(void) +{ + BOOL ret; + HANDLE file; + DWORD hashsize = 0; + BYTE* hash; + BYTE expectedhash[20] = {0x3a,0xa1,0x19,0x08,0xec,0xa6,0x0d,0x2e,0x7e,0xcc,0x7a,0xca,0xf5,0xb8,0x2e,0x62,0x6a,0xda,0xf0,0x19}; + CHAR temp[MAX_PATH]; + DWORD written; + + /* All NULL */ + SetLastError(0xdeadbeef); + ret = pCryptCATAdminCalcHashFromFileHandle(NULL, NULL, NULL, 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* NULL filehandle, rest is legal */ + SetLastError(0xdeadbeef); + ret = pCryptCATAdminCalcHashFromFileHandle(NULL, &hashsize, NULL, 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* Correct filehandle, rest is NULL */ + file = CreateFileA(selfname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + SetLastError(0xdeadbeef); + ret = pCryptCATAdminCalcHashFromFileHandle(file, NULL, NULL, 0); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + CloseHandle(file); + + /* All OK, but dwFlags set to 1 */ + file = CreateFileA(selfname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + SetLastError(0xdeadbeef); + ret = pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, NULL, 1); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + CloseHandle(file); + + /* All OK, requesting the size of the hash */ + file = CreateFileA(selfname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed %u\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, NULL, 0); + ok(ret, "Expected success %u\n", GetLastError()); + ok(hashsize == 20," Expected a hash size of 20, got %d\n", hashsize); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + CloseHandle(file); + + /* All OK, retrieve the hash + * Double the hash buffer to see what happens to the size parameter + */ + file = CreateFileA(selfname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + hashsize *= 2; + hash = HeapAlloc(GetProcessHeap(), 0, hashsize); + SetLastError(0xdeadbeef); + ret = pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, hash, 0); + ok(ret, "Expected success %u\n", GetLastError()); + ok(hashsize == 20," Expected a hash size of 20, got %d\n", hashsize); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + CloseHandle(file); + HeapFree(GetProcessHeap(), 0, hash); + + /* Do the same test with a file created and filled by ourselves (and we thus + * have a known hash for). + */ + GetTempFileNameA(CURR_DIR, "hsh", 0, temp); + file = CreateFileA(temp, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + WriteFile(file, "Text in this file is needed to create a know hash", 49, &written, NULL); + CloseHandle(file); + + /* All OK, first request the size and then retrieve the hash */ + file = CreateFileA(temp, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + hashsize = 0; + pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, NULL, 0); + hash = HeapAlloc(GetProcessHeap(), 0, hashsize); + SetLastError(0xdeadbeef); + ret = pCryptCATAdminCalcHashFromFileHandle(file, &hashsize, hash, 0); + ok(ret, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS, + "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + ok(hashsize == sizeof(expectedhash) && + !memcmp(hash, expectedhash, sizeof(expectedhash)), + "Hashes didn't match\n"); + CloseHandle(file); + + HeapFree(GetProcessHeap(), 0, hash); + DeleteFileA(temp); +} + +static void test_CryptCATOpen(void) +{ + HANDLE hcat; + char empty[MAX_PATH]; + WCHAR emptyW[MAX_PATH]; + HANDLE file; + BOOL ret; + + SetLastError(0xdeadbeef); + hcat = pCryptCATOpen(NULL, 0, 0, 0, 0); + ok(hcat == INVALID_HANDLE_VALUE, "CryptCATOpen succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + + if (!GetTempFileNameA(CURR_DIR, "cat", 0, empty)) return; + + file = CreateFileA(empty, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError()); + CloseHandle(file); + MultiByteToWideChar(CP_ACP, 0, empty, -1, emptyW, MAX_PATH); + + hcat = pCryptCATOpen(emptyW, 0, 0, 0, 0); + todo_wine + ok(hcat != INVALID_HANDLE_VALUE, "Expected a correct handle\n"); + + ret = pCryptCATClose(hcat); + todo_wine + ok(ret, "CryptCATClose failed\n"); + DeleteFileA(empty); +} + +static DWORD error_area; +static DWORD local_error; + +static void WINAPI cdf_callback(DWORD area, DWORD error, WCHAR* line) +{ + ok(error_area != -2, "Didn't expect cdf_callback() to be called (%08x, %08x)\n", + area, error); + + error_area = area; + local_error = error; +} + +static void test_CryptCATCDF_params(void) +{ + static WCHAR nonexistent[] = {'d','e','a','d','b','e','e','f','.','c','d','f',0}; + CRYPTCATCDF *catcdf; + BOOL ret; + + if (!pCryptCATCDFOpen) + { + win_skip("CryptCATCDFOpen is not available\n"); + return; + } + + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(NULL, NULL); + ok(catcdf == NULL, "CryptCATCDFOpen succeeded\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(NULL, cdf_callback); + ok(catcdf == NULL, "CryptCATCDFOpen succeeded\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* File doesn't exist */ + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(nonexistent, cdf_callback); + ok(catcdf == NULL, "CryptCATCDFOpen succeeded\n"); + todo_wine + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = pCryptCATCDFClose(NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + catcdf = NULL; + SetLastError(0xdeadbeef); + ret = pCryptCATCDFClose(catcdf); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); +} + +/* FIXME: Once Wine can create catalog files we should use the created catalog file in this test */ +static void test_CryptCATAdminAddRemoveCatalog(void) +{ + static WCHAR basenameW[] = {'w','i','n','e','t','e','s','t','.','c','a','t',0}; + static CHAR basename[] = "winetest.cat"; + HCATADMIN hcatadmin; + HCATINFO hcatinfo; + CATALOG_INFO info; + WCHAR tmpfileW[MAX_PATH]; + char tmpfile[MAX_PATH]; + char catfile[MAX_PATH], catfilepath[MAX_PATH], *p; + WCHAR catfileW[MAX_PATH]; + HANDLE file; + DWORD error, written; + BOOL ret; + DWORD attrs; + + if (!pCryptCATAdminRemoveCatalog) + { + /* NT4 and W2K do have CryptCATAdminAddCatalog !! */ + win_skip("CryptCATAdminRemoveCatalog is not available\n"); + return; + } + + if (!GetTempFileNameA(CURR_DIR, "cat", 0, tmpfile)) return; + DeleteFileA(tmpfile); + file = CreateFileA(tmpfile, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError()); + CloseHandle(file); + + ret = pCryptCATAdminAcquireContext(&hcatadmin, &dummy, 0); + ok(ret, "CryptCATAdminAcquireContext failed %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + hcatinfo = pCryptCATAdminAddCatalog(NULL, NULL, NULL, 0); + error = GetLastError(); + ok(hcatinfo == NULL, "CryptCATAdminAddCatalog succeeded\n"); + ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", GetLastError()); + + SetLastError(0xdeadbeef); + hcatinfo = pCryptCATAdminAddCatalog(hcatadmin, NULL, NULL, 0); + error = GetLastError(); + ok(hcatinfo == NULL, "CryptCATAdminAddCatalog succeeded\n"); + ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", GetLastError()); + + MultiByteToWideChar(0, 0, tmpfile, -1, tmpfileW, MAX_PATH); + + SetLastError(0xdeadbeef); + hcatinfo = pCryptCATAdminAddCatalog(hcatadmin, tmpfileW, basenameW, 0); + error = GetLastError(); + todo_wine { + ok(hcatinfo == NULL, "CryptCATAdminAddCatalog succeeded\n"); + ok(error == ERROR_BAD_FORMAT, "got %u expected ERROR_BAD_FORMAT\n", GetLastError()); + } + + SetLastError(0xdeadbeef); + hcatinfo = pCryptCATAdminAddCatalog(hcatadmin, tmpfileW, basenameW, 1); + error = GetLastError(); + ok(hcatinfo == NULL, "CryptCATAdminAddCatalog succeeded\n"); + ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", GetLastError()); + + SetLastError(0xdeadbeef); + hcatinfo = pCryptCATAdminAddCatalog(hcatadmin, tmpfileW, NULL, 0); + error = GetLastError(); + ok(hcatinfo == NULL, "CryptCATAdminAddCatalog succeeded\n"); + todo_wine ok(error == ERROR_BAD_FORMAT, "got %u expected ERROR_BAD_FORMAT\n", GetLastError()); + + DeleteFileA(tmpfile); + file = CreateFileA(tmpfile, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError()); + WriteFile(file, test_catalog, sizeof(test_catalog), &written, NULL); + CloseHandle(file); + + /* Unique name will be created */ + hcatinfo = pCryptCATAdminAddCatalog(hcatadmin, tmpfileW, NULL, 0); + todo_wine ok(hcatinfo != NULL, "CryptCATAdminAddCatalog failed %u\n", GetLastError()); + + info.cbStruct = sizeof(info); + info.wszCatalogFile[0] = 0; + ret = pCryptCATCatalogInfoFromContext(hcatinfo, &info, 0); + todo_wine + { + ok(ret, "CryptCATCatalogInfoFromContext failed %u\n", GetLastError()); + ok(info.wszCatalogFile[0] != 0, "Expected a filename\n"); + } + WideCharToMultiByte(CP_ACP, 0, info.wszCatalogFile, -1, catfile, MAX_PATH, 0, 0); + if ((p = strrchr(catfile, '\\'))) p++; + memset(catfileW, 0, sizeof(catfileW)); + MultiByteToWideChar(0, 0, p, -1, catfileW, MAX_PATH); + + /* Set the file attributes so we can check what happens with them during the 'copy' */ + attrs = FILE_ATTRIBUTE_READONLY; + ret = SetFileAttributesA(tmpfile, attrs); + ok(ret, "SetFileAttributesA failed : %u\n", GetLastError()); + + /* winetest.cat will be created */ + hcatinfo = pCryptCATAdminAddCatalog(hcatadmin, tmpfileW, basenameW, 0); + ok(hcatinfo != NULL, "CryptCATAdminAddCatalog failed %u\n", GetLastError()); + + lstrcpyA(catfilepath, catroot); + lstrcatA(catfilepath, "\\{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}\\winetest.cat"); + attrs = GetFileAttributes(catfilepath); + ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected %s to exist\n", catfilepath); + todo_wine + ok(attrs == FILE_ATTRIBUTE_SYSTEM || + attrs == (FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_SYSTEM), /* Vista */ + "File has wrong attributes : %08x\n", attrs); + + info.cbStruct = sizeof(info); + info.wszCatalogFile[0] = 0; + ret = pCryptCATCatalogInfoFromContext(hcatinfo, &info, 0); + ok(ret, "CryptCATCatalogInfoFromContext failed %u\n", GetLastError()); + ok(info.wszCatalogFile[0] != 0, "Expected a filename\n"); + WideCharToMultiByte(CP_ACP, 0, info.wszCatalogFile, -1, catfile, MAX_PATH, 0, 0); + if ((p = strrchr(catfile, '\\'))) p++; + ok(!lstrcmpA(basename, p), "Expected %s, got %s\n", basename, p); + + ret = pCryptCATAdminReleaseCatalogContext(hcatadmin, hcatinfo, 0); + ok(ret, "CryptCATAdminReleaseCatalogContext failed %u\n", GetLastError()); + + /* Remove the catalog file with the unique name */ + ret = pCryptCATAdminRemoveCatalog(hcatadmin, catfileW, 0); + ok(ret, "CryptCATAdminRemoveCatalog failed %u\n", GetLastError()); + + /* Remove the winetest.cat catalog file, first with the full path. This should not succeed + * according to MSDN */ + ret = pCryptCATAdminRemoveCatalog(hcatadmin, info.wszCatalogFile, 0); + ok(ret, "CryptCATAdminRemoveCatalog failed %u\n", GetLastError()); + /* The call succeeded with the full path but the file is not removed */ + attrs = GetFileAttributes(catfilepath); + ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected %s to exist\n", catfilepath); + /* Given only the filename the file is removed */ + ret = pCryptCATAdminRemoveCatalog(hcatadmin, basenameW, 0); + ok(ret, "CryptCATAdminRemoveCatalog failed %u\n", GetLastError()); + attrs = GetFileAttributes(catfilepath); + ok(attrs == INVALID_FILE_ATTRIBUTES, "Expected %s to be removed\n", catfilepath); + + ret = pCryptCATAdminReleaseContext(hcatadmin, 0); + ok(ret, "CryptCATAdminReleaseContext failed %u\n", GetLastError()); + + /* Set the attributes so we can delete the file */ + attrs = FILE_ATTRIBUTE_NORMAL; + ret = SetFileAttributesA(tmpfile, attrs); + DeleteFileA(tmpfile); +} + +static void test_catalog_properties(CHAR *catfile, int attributes, int members) +{ + static const GUID subject = {0xde351a42,0x8e59,0x11d0,{0x8c,0x47,0x00,0xc0,0x4f,0xc2,0x95,0xee}}; + + HANDLE hcat; + CRYPTCATMEMBER *m; + CRYPTCATATTRIBUTE *attr; + char catalog[MAX_PATH]; + WCHAR catalogW[MAX_PATH]; + DWORD attrs; + BOOL ret; + int attrcount = 0, membercount = 0; + + /* FIXME: Wine can't create catalog files out of catalog definition files yet. Remove this piece + * once wine is fixed + */ + attrs = GetFileAttributesA(catfile); + if (attrs == INVALID_FILE_ATTRIBUTES) + { + HANDLE file; + DWORD written; + + trace("Creating the catalog file\n"); + if (!GetTempFileNameA(CURR_DIR, "cat", 0, catalog)) return; + file = CreateFileA(catalog, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError()); + WriteFile(file, test_catalog, sizeof(test_catalog), &written, NULL); + CloseHandle(file); + + attributes = 2; + members = 1; + MultiByteToWideChar(CP_ACP, 0, catalog, -1, catalogW, MAX_PATH); + } + else + { + MultiByteToWideChar(CP_ACP, 0, catfile, -1, catalogW, MAX_PATH); + catalog[0] = 0; + } + + hcat = pCryptCATOpen(catalogW, 0, 0, 0, 0); + if (hcat == INVALID_HANDLE_VALUE && members == 0) + { + win_skip("CryptCATOpen on W2K can't handle catalog files with no members\n"); + return; + } + ok(hcat != INVALID_HANDLE_VALUE, "CryptCATOpen failed %u\n", GetLastError()); + + m = pCryptCATEnumerateMember(NULL, NULL); + ok(m == NULL, "CryptCATEnumerateMember succeeded\n"); + + m = NULL; + while ((m = pCryptCATEnumerateMember(hcat, m))) + { + ok(m->cbStruct == sizeof(CRYPTCATMEMBER), "unexpected size %u\n", m->cbStruct); + todo_wine ok(!lstrcmpW(m->pwszReferenceTag, hashmeW), "unexpected tag\n"); + ok(!memcmp(&m->gSubjectType, &subject, sizeof(subject)), "guid differs\n"); + ok(!m->fdwMemberFlags, "got %x expected 0\n", m->fdwMemberFlags); + ok(m->dwCertVersion == 0x200, "got %x expected 0x200\n", m->dwCertVersion); + ok(!m->dwReserved, "got %x expected 0\n", m->dwReserved); + ok(m->hReserved == NULL, "got %p expected NULL\n", m->hReserved); + + attr = pCryptCATEnumerateAttr(hcat, m, NULL); + ok(attr == NULL, "CryptCATEnumerateAttr succeeded\n"); + + membercount++; + } + ok(membercount == members, "Expected %d members, got %d\n", members, membercount); + + attr = pCryptCATEnumerateAttr(NULL, NULL, NULL); + ok(attr == NULL, "CryptCATEnumerateAttr succeeded\n"); + + attr = pCryptCATEnumerateAttr(hcat, NULL, NULL); + ok(attr == NULL, "CryptCATEnumerateAttr succeeded\n"); + + attr = NULL; + while ((attr = pCryptCATEnumerateCatAttr(hcat, attr))) + { + ok(!lstrcmpW(attr->pwszReferenceTag, attr1W) || + !lstrcmpW(attr->pwszReferenceTag, attr2W), + "Expected 'attr1' or 'attr2'\n"); + + attrcount++; + } + todo_wine + ok(attrcount == attributes, "Expected %d catalog attributes, got %d\n", attributes, attrcount); + + ret = pCryptCATClose(hcat); + ok(ret, "CryptCATClose failed\n"); + if (catalog[0]) DeleteFileA( catalog ); +} + +static void test_create_catalog_file(void) +{ + static CHAR catfileA[] = "winetest.cat"; + static CHAR cdffileA[] = "winetest.cdf"; + static WCHAR cdffileW[] = {'w','i','n','e','t','e','s','t','.','c','d','f',0}; + CRYPTCATCDF *catcdf; + CRYPTCATATTRIBUTE *catattr; + CRYPTCATMEMBER *catmember; + WCHAR *catmembertag; + DWORD written, attrs; + HANDLE file; + BOOL ret; + int attrcount, membercount; + + if (!pCryptCATCDFOpen) + { + win_skip("CryptCATCDFOpen is not available\n"); + return; + } + + /* Create the cdf file */ + file = CreateFileA(cdffileA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError()); + WriteFile(file, test_cdf, sizeof(test_cdf) - 1, &written, NULL); + CloseHandle(file); + + /* Don't enumerate attributes and members */ + trace("No attribs and members\n"); + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, NULL); + todo_wine + { + ok(catcdf != NULL, "CryptCATCDFOpen failed\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + + ret = pCryptCATCDFClose(catcdf); + todo_wine + { + ok(ret, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + + attrs = GetFileAttributesA(catfileA); + todo_wine + ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected the catalog file to exist\n"); + + test_catalog_properties(catfileA, 0, 0); + DeleteFileA(catfileA); + + /* Only enumerate the attributes */ + trace("Only attributes\n"); + attrcount = membercount = 0; + catcdf = pCryptCATCDFOpen(cdffileW, NULL); + + catattr = NULL; + while ((catattr = pCryptCATCDFEnumCatAttributes(catcdf, catattr, NULL))) + { + ok(!lstrcmpW(catattr->pwszReferenceTag, attr1W) || + !lstrcmpW(catattr->pwszReferenceTag, attr2W), + "Expected 'attr1' or 'attr2'\n"); + + attrcount++; + } + todo_wine + ok(attrcount == 2, "Expected 2 attributes, got %d\n", attrcount); + + pCryptCATCDFClose(catcdf); + /* Even though the resulting catalog file shows the attributes, they will not be enumerated */ + test_catalog_properties(catfileA, 0, 0); + DeleteFileA(catfileA); + + /* Only enumerate the members */ + trace("Only members\n"); + attrcount = membercount = 0; + catcdf = pCryptCATCDFOpen(cdffileW, NULL); + + catmember = NULL; + catmembertag = NULL; + while ((catmembertag = pCryptCATCDFEnumMembersByCDFTagEx(catcdf, catmembertag, NULL, &catmember, FALSE, NULL))) + { + ok(!lstrcmpW(catmembertag, hashmeW), "Expected 'hashme'\n"); + membercount++; + } + todo_wine + ok(membercount == 1, "Expected 1 member, got %d\n", membercount); + + pCryptCATCDFClose(catcdf); + test_catalog_properties(catfileA, 0, 1); + DeleteFileA(catfileA); + + /* Enumerate members and attributes */ + trace("Attributes and members\n"); + attrcount = membercount = 0; + catcdf = pCryptCATCDFOpen(cdffileW, NULL); + + catattr = NULL; + while ((catattr = pCryptCATCDFEnumCatAttributes(catcdf, catattr, NULL))) + attrcount++; + todo_wine + ok(attrcount == 2, "Expected 2 attributes, got %d\n", attrcount); + + catmember = NULL; + catmembertag = NULL; + while ((catmembertag = pCryptCATCDFEnumMembersByCDFTagEx(catcdf, catmembertag, NULL, &catmember, FALSE, NULL))) + membercount++; + todo_wine + ok(membercount == 1, "Expected 1 member, got %d\n", membercount); + + pCryptCATCDFClose(catcdf); + test_catalog_properties(catfileA, 2, 1); + DeleteFileA(catfileA); + + DeleteFileA(cdffileA); +} + +static void create_cdf_file(const CHAR *filename, const CHAR *contents) +{ + HANDLE file; + DWORD written; + + file = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError()); + WriteFile(file, contents, lstrlenA(contents), &written, NULL); + CloseHandle(file); +} + +#define CHECK_EXPECT(a, b) \ + do { \ + ok(a == error_area, "Expected %08x, got %08x\n", a, error_area); \ + ok(b == local_error, "Expected %08x, got %08x\n", b, local_error); \ + } while (0) + +/* Clear the variables (can't use 0) */ +#define CLEAR_EXPECT \ + error_area = local_error = -1 + +/* Set both variables so the callback routine can check if a call to it was unexpected */ +#define SET_UNEXPECTED \ + error_area = local_error = -2 + +static void test_cdf_parsing(void) +{ + static CHAR catfileA[] = "tempfile.cat"; + static CHAR cdffileA[] = "tempfile.cdf"; + static WCHAR cdffileW[] = {'t','e','m','p','f','i','l','e','.','c','d','f',0}; + CHAR cdf_contents[4096]; + CRYPTCATCDF *catcdf; + CRYPTCATATTRIBUTE *catattr; + CRYPTCATMEMBER *catmember; + WCHAR *catmembertag; + + if (!pCryptCATCDFOpen) + { + win_skip("CryptCATCDFOpen is not available\n"); + return; + } + + /* Empty file */ + DeleteFileA(cdffileA); + create_cdf_file(cdffileA, ""); + + CLEAR_EXPECT; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + todo_wine + CHECK_EXPECT(CRYPTCAT_E_AREA_HEADER, CRYPTCAT_E_CDF_TAGNOTFOUND); + ok(catcdf == NULL, "CryptCATCDFOpen succeeded\n"); + todo_wine + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + DeleteFileA(cdffileA); + ok(!DeleteFileA(catfileA), "Didn't expect a catalog file to be created\n"); + + /* Just the header */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + ok(catcdf == NULL, "CryptCATCDFOpen succeeded\n"); + todo_wine + ok(GetLastError() == ERROR_SHARING_VIOLATION || + broken(GetLastError() == ERROR_SUCCESS), /* win9x */ + "Expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + DeleteFileA(cdffileA); + + /* Header and member only */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "[CatalogFiles]\r\n"); + lstrcatA(cdf_contents, "hashme=.\\tempfile.cdf\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + ok(catcdf == NULL, "CryptCATCDFOpen succeeded\n"); + todo_wine + ok(GetLastError() == ERROR_SHARING_VIOLATION || + broken(GetLastError() == ERROR_SUCCESS), /* win9x */ + "Expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + DeleteFileA(cdffileA); + ok(!DeleteFileA(catfileA), "Didn't expect a catalog file to be created\n"); + + /* Header and Name (no value) */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "Name=\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + ok(catcdf == NULL, "CryptCATCDFOpen succeeded\n"); + todo_wine + ok(GetLastError() == ERROR_SHARING_VIOLATION || + broken(GetLastError() == ERROR_SUCCESS), /* win9x */ + "Expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError()); + DeleteFileA(cdffileA); + ok(!DeleteFileA(catfileA), "Didn't expect a catalog file to be created\n"); + + /* Header and Name */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "Name=tempfile.cat\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + todo_wine + { + ok(catcdf != NULL, "CryptCATCDFOpen failed\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + pCryptCATCDFClose(catcdf); + DeleteFileA(cdffileA); + todo_wine + ok(DeleteFileA(catfileA), "Expected a catalog file to be created\n"); + + /* Header and nonexistent member */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "Name=tempfile.cat\r\n"); + lstrcatA(cdf_contents, "[CatalogFiles]\r\n"); + lstrcatA(cdf_contents, "hashme=.\\deadbeef.cdf\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + todo_wine + { + ok(catcdf != NULL, "CryptCATCDFOpen failed\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + /* Loop through the members */ + CLEAR_EXPECT; + catmember = NULL; + catmembertag = NULL; + while ((catmembertag = pCryptCATCDFEnumMembersByCDFTagEx(catcdf, catmembertag, cdf_callback, &catmember, FALSE, NULL))) ; + todo_wine + CHECK_EXPECT(CRYPTCAT_E_AREA_MEMBER, CRYPTCAT_E_CDF_MEMBER_FILENOTFOUND); + pCryptCATCDFClose(catcdf); + DeleteFileA(cdffileA); + todo_wine + ok(DeleteFileA(catfileA), "Expected a catalog file to be created\n"); + + /* Header, correct member but no explicit newline */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "Name=tempfile.cat\r\n"); + lstrcatA(cdf_contents, "[CatalogFiles]\r\n"); + lstrcatA(cdf_contents, "hashme=.\\tempfile.cdf\r"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + todo_wine + { + ok(catcdf != NULL, "CryptCATCDFOpen failed\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + /* Loop through the members */ + CLEAR_EXPECT; + catmember = NULL; + catmembertag = NULL; + while ((catmembertag = pCryptCATCDFEnumMembersByCDFTagEx(catcdf, catmembertag, cdf_callback, &catmember, FALSE, NULL))) ; + todo_wine + CHECK_EXPECT(CRYPTCAT_E_AREA_MEMBER, CRYPTCAT_E_CDF_MEMBER_FILE_PATH); + pCryptCATCDFClose(catcdf); + DeleteFileA(cdffileA); + todo_wine + ok(DeleteFileA(catfileA), "Expected a catalog file to be created\n"); + + /* Header and 2 duplicate members */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "Name=tempfile.cat\r\n"); + lstrcatA(cdf_contents, "[CatalogFiles]\r\n"); + lstrcatA(cdf_contents, "hashme=.\\tempfile.cdf\r\n"); + lstrcatA(cdf_contents, "hashme=.\\tempfile.cdf\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + todo_wine + { + ok(catcdf != NULL, "CryptCATCDFOpen failed\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + /* Loop through the members */ + SET_UNEXPECTED; + catmember = NULL; + catmembertag = NULL; + while ((catmembertag = pCryptCATCDFEnumMembersByCDFTagEx(catcdf, catmembertag, cdf_callback, &catmember, FALSE, NULL))) ; + pCryptCATCDFClose(catcdf); + test_catalog_properties(catfileA, 0, 1); + DeleteFileA(cdffileA); + todo_wine + ok(DeleteFileA(catfileA), "Expected a catalog file to be created\n"); + + /* Wrong attribute */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "Name=tempfile.cat\r\n"); + lstrcatA(cdf_contents, "CATATTR1=0x10010001:attr1\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + todo_wine + { + ok(catcdf != NULL, "CryptCATCDFOpen failed\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + /* Loop through the attributes */ + CLEAR_EXPECT; + catattr = NULL; + while ((catattr = pCryptCATCDFEnumCatAttributes(catcdf, catattr, cdf_callback))) ; + todo_wine + CHECK_EXPECT(CRYPTCAT_E_AREA_ATTRIBUTE, CRYPTCAT_E_CDF_ATTR_TOOFEWVALUES); + pCryptCATCDFClose(catcdf); + DeleteFileA(cdffileA); + todo_wine + ok(DeleteFileA(catfileA), "Expected a catalog file to be created\n"); + + /* Two identical attributes */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "Name=tempfile.cat\r\n"); + lstrcatA(cdf_contents, "CATATTR1=0x10010001:attr1:value1\r\n"); + lstrcatA(cdf_contents, "CATATTR1=0x10010001:attr1:value1\r\n"); + lstrcatA(cdf_contents, "[CatalogFiles]\r\n"); + lstrcatA(cdf_contents, "hashme=.\\tempfile.cdf\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + todo_wine + { + ok(catcdf != NULL, "CryptCATCDFOpen failed\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + /* Loop through the members */ + SET_UNEXPECTED; + catmember = NULL; + catmembertag = NULL; + while ((catmembertag = pCryptCATCDFEnumMembersByCDFTagEx(catcdf, catmembertag, cdf_callback, &catmember, FALSE, NULL))) ; + /* Loop through the attributes */ + SET_UNEXPECTED; + catattr = NULL; + while ((catattr = pCryptCATCDFEnumCatAttributes(catcdf, catattr, cdf_callback))) ; + pCryptCATCDFClose(catcdf); + test_catalog_properties(catfileA, 1, 1); + DeleteFileA(cdffileA); + todo_wine + ok(DeleteFileA(catfileA), "Expected a catalog file to be created\n"); + + /* Two different attribute values with the same tag */ + lstrcpyA(cdf_contents, "[CatalogHeader]\r\n"); + lstrcatA(cdf_contents, "Name=tempfile.cat\r\n"); + lstrcatA(cdf_contents, "CATATTR1=0x10010001:attr1:value1\r\n"); + lstrcatA(cdf_contents, "CATATTR1=0x10010001:attr2:value2\r\n"); + lstrcatA(cdf_contents, "[CatalogFiles]\r\n"); + lstrcatA(cdf_contents, "hashme=.\\tempfile.cdf\r\n"); + create_cdf_file(cdffileA, cdf_contents); + + SET_UNEXPECTED; + SetLastError(0xdeadbeef); + catcdf = pCryptCATCDFOpen(cdffileW, cdf_callback); + todo_wine + { + ok(catcdf != NULL, "CryptCATCDFOpen failed\n"); + ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError()); + } + /* Loop through the members */ + SET_UNEXPECTED; + catmember = NULL; + catmembertag = NULL; + while ((catmembertag = pCryptCATCDFEnumMembersByCDFTagEx(catcdf, catmembertag, cdf_callback, &catmember, FALSE, NULL))) ; + /* Loop through the attributes */ + SET_UNEXPECTED; + catattr = NULL; + while ((catattr = pCryptCATCDFEnumCatAttributes(catcdf, catattr, cdf_callback))) ; + pCryptCATCDFClose(catcdf); + test_catalog_properties(catfileA, 1, 1); + DeleteFileA(cdffileA); + todo_wine + ok(DeleteFileA(catfileA), "Expected a catalog file to be created\n"); +} + +START_TEST(crypt) +{ + int myARGC; + char** myARGV; + char sysdir[MAX_PATH]; + + InitFunctionPtrs(); + + if (!pCryptCATAdminAcquireContext) + { + win_skip("CryptCATAdmin functions are not available\n"); + return; + } + + GetSystemDirectoryA(sysdir, MAX_PATH); + lstrcpyA(catroot, sysdir); + lstrcatA(catroot, "\\CatRoot"); + lstrcpyA(catroot2, sysdir); + lstrcatA(catroot2, "\\CatRoot2"); + + myARGC = winetest_get_mainargs(&myARGV); + strcpy(selfname, myARGV[0]); + + GetCurrentDirectoryA(MAX_PATH, CURR_DIR); + + test_context(); + test_calchash(); + test_CryptCATOpen(); + /* Parameter checking only */ + test_CryptCATCDF_params(); + /* Test the parsing of a cdf file */ + test_cdf_parsing(); + /* Create a catalog file out of our own catalog definition file */ + test_create_catalog_file(); + test_CryptCATAdminAddRemoveCatalog(); +} diff --git a/rostests/winetests/wintrust/register.c b/rostests/winetests/wintrust/register.c new file mode 100644 index 00000000000..dd266bd807d --- /dev/null +++ b/rostests/winetests/wintrust/register.c @@ -0,0 +1,317 @@ +/* Unit test suite for wintrust API functions + * + * Copyright 2006 Paul Vriens + * + * 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 + * + */ + +#include +#include + +#include "windows.h" +#include "softpub.h" +#include "wintrust.h" +#include "winreg.h" + +#include "wine/test.h" + +static BOOL (WINAPI * pWintrustAddActionID)(GUID*, DWORD, CRYPT_REGISTER_ACTIONID*); +static BOOL (WINAPI * pWintrustAddDefaultForUsage)(const CHAR*,CRYPT_PROVIDER_REGDEFUSAGE*); +static void (WINAPI * pWintrustGetRegPolicyFlags)(DWORD *); +static BOOL (WINAPI * pWintrustLoadFunctionPointers)(GUID *, CRYPT_PROVIDER_FUNCTIONS *); +static BOOL (WINAPI * pWintrustRemoveActionID)(GUID*); +static BOOL (WINAPI * pWintrustSetRegPolicyFlags)(DWORD); + +static void InitFunctionPtrs(void) +{ + HMODULE hWintrust = GetModuleHandleA("wintrust.dll"); + +#define WINTRUST_GET_PROC(func) \ + p ## func = (void*)GetProcAddress(hWintrust, #func); \ + if(!p ## func) \ + trace("GetProcAddress(%s) failed\n", #func); + + WINTRUST_GET_PROC(WintrustAddActionID) + WINTRUST_GET_PROC(WintrustAddDefaultForUsage) + WINTRUST_GET_PROC(WintrustGetRegPolicyFlags) + WINTRUST_GET_PROC(WintrustLoadFunctionPointers) + WINTRUST_GET_PROC(WintrustRemoveActionID) + WINTRUST_GET_PROC(WintrustSetRegPolicyFlags) + +#undef WINTRUST_GET_PROC +} + +static void test_AddRem_ActionID(void) +{ + static WCHAR DummyDllW[] = {'d','e','a','d','b','e','e','f','.','d','l','l',0 }; + static WCHAR DummyFunctionW[] = {'d','u','m','m','y','f','u','n','c','t','i','o','n',0 }; + GUID ActionID = { 0xdeadbeef, 0xdead, 0xbeef, { 0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef }}; + CRYPT_REGISTER_ACTIONID ActionIDFunctions; + CRYPT_TRUST_REG_ENTRY EmptyProvider = { 0, NULL, NULL }; + CRYPT_TRUST_REG_ENTRY DummyProvider = { sizeof(CRYPT_TRUST_REG_ENTRY), DummyDllW, DummyFunctionW }; + BOOL ret; + + if (!pWintrustAddActionID || !pWintrustRemoveActionID) + { + win_skip("WintrustAddActionID and/or WintrustRemoveActionID are not available\n"); + return; + } + + /* All NULL */ + SetLastError(0xdeadbeef); + ret = pWintrustAddActionID(NULL, 0, NULL); + ok (!ret, "Expected WintrustAddActionID to fail.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ || + GetLastError() == 0xdeadbeef /* Win98/NT4/W2K */, + "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %u.\n", GetLastError()); + + /* NULL functions */ + SetLastError(0xdeadbeef); + ret = pWintrustAddActionID(&ActionID, 0, NULL); + ok (!ret, "Expected WintrustAddActionID to fail.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ || + GetLastError() == 0xdeadbeef /* Win98/NT4/W2K */, + "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %u.\n", GetLastError()); + + /* All OK (although no functions defined), except cbStruct is not set in ActionIDFunctions */ + SetLastError(0xdeadbeef); + memset(&ActionIDFunctions, 0, sizeof(CRYPT_REGISTER_ACTIONID)); + ret = pWintrustAddActionID(&ActionID, 0, &ActionIDFunctions); + ok (!ret, "Expected WintrustAddActionID to fail.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER /* XP/W2K3 */ || + GetLastError() == 0xdeadbeef /* Win98/NT4/W2K */, + "Expected ERROR_INVALID_PARAMETER(W2K3) or 0xdeadbeef(Win98/NT4/W2K), got %u.\n", GetLastError()); + + /* All OK (although no functions defined) and cbStruct is set now */ + SetLastError(0xdeadbeef); + memset(&ActionIDFunctions, 0, sizeof(CRYPT_REGISTER_ACTIONID)); + ActionIDFunctions.cbStruct = sizeof(CRYPT_REGISTER_ACTIONID); + ret = pWintrustAddActionID(&ActionID, 0, &ActionIDFunctions); + ok (ret, "Expected WintrustAddActionID to succeed.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); + + /* All OK and all (but 1) functions are correctly defined. The DLL and entrypoints + * are not present. + */ + memset(&ActionIDFunctions, 0, sizeof(CRYPT_REGISTER_ACTIONID)); + ActionIDFunctions.cbStruct = sizeof(CRYPT_REGISTER_ACTIONID); + ActionIDFunctions.sInitProvider = DummyProvider; + ActionIDFunctions.sObjectProvider = DummyProvider; + ActionIDFunctions.sSignatureProvider = EmptyProvider; + ActionIDFunctions.sCertificateProvider = DummyProvider; + ActionIDFunctions.sCertificatePolicyProvider = DummyProvider; + ActionIDFunctions.sFinalPolicyProvider = DummyProvider; + ActionIDFunctions.sTestPolicyProvider = DummyProvider; + ActionIDFunctions.sCleanupProvider = DummyProvider; + SetLastError(0xdeadbeef); + ret = pWintrustAddActionID(&ActionID, 0, &ActionIDFunctions); + ok (ret, "Expected WintrustAddActionID to succeed.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_INVALID_PARAMETER or ERROR_ACCESS_DENIED, got %u.\n", + GetLastError()); + + /* All OK and all functions are correctly defined. The DLL and entrypoints + * are not present. + */ + memset(&ActionIDFunctions, 0, sizeof(CRYPT_REGISTER_ACTIONID)); + ActionIDFunctions.cbStruct = sizeof(CRYPT_REGISTER_ACTIONID); + ActionIDFunctions.sInitProvider = DummyProvider; + ActionIDFunctions.sObjectProvider = DummyProvider; + ActionIDFunctions.sSignatureProvider = DummyProvider; + ActionIDFunctions.sCertificateProvider = DummyProvider; + ActionIDFunctions.sCertificatePolicyProvider = DummyProvider; + ActionIDFunctions.sFinalPolicyProvider = DummyProvider; + ActionIDFunctions.sTestPolicyProvider = DummyProvider; + ActionIDFunctions.sCleanupProvider = DummyProvider; + SetLastError(0xdeadbeef); + ret = pWintrustAddActionID(&ActionID, 0, &ActionIDFunctions); + ok (ret, "Expected WintrustAddActionID to succeed.\n"); + ok (GetLastError() == 0xdeadbeef || GetLastError() == ERROR_ACCESS_DENIED, + "Expected 0xdeadbeef or ERROR_ACCESS_DENIED, got %u.\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pWintrustRemoveActionID(&ActionID); + ok ( ret, "WintrustRemoveActionID failed : %d\n", GetLastError()); + ok ( GetLastError() == 0xdeadbeef, "Last error should not have been changed: %u\n", GetLastError()); + + /* NULL input */ + SetLastError(0xdeadbeef); + ret = pWintrustRemoveActionID(NULL); + ok (ret, "Expected WintrustRemoveActionID to succeed.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); + + /* The passed GUID is removed by a previous call, so it's basically a test with a nonexistent Trust provider */ + SetLastError(0xdeadbeef); + ret = pWintrustRemoveActionID(&ActionID); + ok (ret, "Expected WintrustRemoveActionID to succeed.\n"); + ok (GetLastError() == 0xdeadbeef, + "Expected 0xdeadbeef, got %u.\n", GetLastError()); +} + +static void test_AddDefaultForUsage(void) +{ + BOOL ret; + static GUID ActionID = { 0xdeadbeef, 0xdead, 0xbeef, { 0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef }}; + static WCHAR DummyDllW[] = {'d','e','a','d','b','e','e','f','.','d','l','l',0 }; + static CHAR DummyFunction[] = "dummyfunction"; + static const CHAR oid[] = "1.2.3.4.5.6.7.8.9.10"; + static CRYPT_PROVIDER_REGDEFUSAGE DefUsage; + + if (!pWintrustAddDefaultForUsage) + { + win_skip("WintrustAddDefaultForUsage is not available\n"); + return; + } + + /* All NULL */ + SetLastError(0xdeadbeef); + ret = pWintrustAddDefaultForUsage(NULL, NULL); + ok (!ret, "Expected WintrustAddDefaultForUsage to fail.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); + + /* NULL defusage */ + SetLastError(0xdeadbeef); + ret = pWintrustAddDefaultForUsage(oid, NULL); + ok (!ret, "Expected WintrustAddDefaultForUsage to fail.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); + + /* NULL oid and proper defusage */ + memset(&DefUsage, 0 , sizeof(CRYPT_PROVIDER_REGDEFUSAGE)); + DefUsage.cbStruct = sizeof(CRYPT_PROVIDER_REGDEFUSAGE); + DefUsage.pgActionID = &ActionID; + DefUsage.pwszDllName = DummyDllW; + DefUsage.pwszLoadCallbackDataFunctionName = DummyFunction; + DefUsage.pwszFreeCallbackDataFunctionName = DummyFunction; + SetLastError(0xdeadbeef); + ret = pWintrustAddDefaultForUsage(NULL, &DefUsage); + ok (!ret, "Expected WintrustAddDefaultForUsage to fail.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); + + /* cbStruct set to 0 */ + memset(&DefUsage, 0 , sizeof(CRYPT_PROVIDER_REGDEFUSAGE)); + DefUsage.cbStruct = 0; + DefUsage.pgActionID = &ActionID; + DefUsage.pwszDllName = DummyDllW; + DefUsage.pwszLoadCallbackDataFunctionName = DummyFunction; + DefUsage.pwszFreeCallbackDataFunctionName = DummyFunction; + SetLastError(0xdeadbeef); + ret = pWintrustAddDefaultForUsage(oid, &DefUsage); + ok (!ret, "Expected WintrustAddDefaultForUsage to fail.\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %u.\n", GetLastError()); +} + +static void test_LoadFunctionPointers(void) +{ + BOOL ret; + CRYPT_PROVIDER_FUNCTIONS funcs; + GUID action = WINTRUST_ACTION_GENERIC_VERIFY_V2; + + if (!pWintrustLoadFunctionPointers) + { + win_skip("WintrustLoadFunctionPointers is not available\n"); + return; + } + SetLastError(0xdeadbeef); + ret = pWintrustLoadFunctionPointers(NULL, NULL); + ok(!ret && GetLastError() == 0xdeadbeef, "Expected failure\n"); + SetLastError(0xdeadbeef); + ret = pWintrustLoadFunctionPointers(&action, NULL); + ok(!ret && GetLastError() == 0xdeadbeef, "Expected failure\n"); + + SetLastError(0xdeadbeef); + ret = pWintrustLoadFunctionPointers(NULL, &funcs); + ok(!ret, "WintrustLoadFunctionPointers succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER || + GetLastError() == 0xdeadbeef /* W2K and XP-SP1 */, + "Expected ERROR_INVALID_PARAMETER or 0xdeadbeef, got %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + funcs.cbStruct = 0; + ret = pWintrustLoadFunctionPointers(&action, &funcs); + ok(!ret && GetLastError() == 0xdeadbeef, "Expected failure\n"); + SetLastError(0xdeadbeef); + funcs.cbStruct = sizeof(funcs); + ret = pWintrustLoadFunctionPointers(&action, &funcs); + ok(ret, "WintrustLoadFunctionPointers failed: %d\n", GetLastError()); + ok(funcs.pfnAlloc != NULL, "Expected a pointer\n"); + ok(funcs.pfnFree != NULL, "Expected a pointer\n"); +} + +static void test_RegPolicyFlags(void) +{ + /* Default state value 0x00023c00, which is + * WTPF_IGNOREREVOCATIONONTS | + * WTPF_OFFLINEOKNBU_COM | + * WTPF_OFFLINEOKNBU_IND | + * WTPF_OFFLINEOK_COM | + * WTPF_OFFLINEOK_IND + */ + static const CHAR Software_Publishing[] = + "Software\\Microsoft\\Windows\\CurrentVersion\\Wintrust\\" + "Trust Providers\\Software Publishing"; + static const CHAR State[] = "State"; + HKEY key; + LONG r; + DWORD flags1, flags2, flags3, size; + BOOL ret; + + if (!pWintrustGetRegPolicyFlags || !pWintrustSetRegPolicyFlags) + { + win_skip("Policy flags functions not present\n"); + return; + } + + pWintrustGetRegPolicyFlags(&flags2); + + r = RegOpenKeyExA(HKEY_CURRENT_USER, Software_Publishing, 0, KEY_ALL_ACCESS, + &key); + ok(!r, "RegOpenKeyEx failed: %d\n", r); + + size = sizeof(flags1); + r = RegQueryValueExA(key, State, NULL, NULL, (LPBYTE)&flags1, &size); + ok(!r || r == ERROR_FILE_NOT_FOUND, "RegQueryValueEx failed: %d\n", r); + if (!r) + ok(flags1 == flags2, "Got %08x flags instead of %08x\n", flags1, flags2); + + flags3 = flags2 | 1; + ret = pWintrustSetRegPolicyFlags(flags3); + ok(ret, "WintrustSetRegPolicyFlags failed: %d\n", GetLastError()); + size = sizeof(flags1); + r = RegQueryValueExA(key, State, NULL, NULL, (LPBYTE)&flags1, &size); + ok(flags1 == flags3, "Got %08x flags instead of %08x\n", flags1, flags3); + + pWintrustSetRegPolicyFlags(flags2); + + RegCloseKey(key); +} + +START_TEST(register) +{ + InitFunctionPtrs(); + + test_AddRem_ActionID(); + test_AddDefaultForUsage(); + test_LoadFunctionPointers(); + test_RegPolicyFlags(); +} diff --git a/rostests/winetests/wintrust/softpub.c b/rostests/winetests/wintrust/softpub.c new file mode 100644 index 00000000000..3e4347d80d3 --- /dev/null +++ b/rostests/winetests/wintrust/softpub.c @@ -0,0 +1,549 @@ +/* + * wintrust softpub functions tests + * + * Copyright 2007 Juan Lang + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "winnls.h" + +#include "wine/test.h" + +/* Just in case we're being built with borked headers, redefine function + * pointers to have the correct calling convention. + */ +typedef void *(WINAPI *SAFE_MEM_ALLOC)(DWORD); +typedef void (WINAPI *SAFE_MEM_FREE)(void *); +typedef BOOL (WINAPI *SAFE_ADD_STORE)(CRYPT_PROVIDER_DATA *, + HCERTSTORE); +typedef BOOL (WINAPI *SAFE_ADD_SGNR)(CRYPT_PROVIDER_DATA *, + BOOL, DWORD, struct _CRYPT_PROVIDER_SGNR *); +typedef BOOL (WINAPI *SAFE_ADD_CERT)(CRYPT_PROVIDER_DATA *, + DWORD, BOOL, DWORD, PCCERT_CONTEXT); +typedef BOOL (WINAPI *SAFE_ADD_PRIVDATA)(CRYPT_PROVIDER_DATA *, + CRYPT_PROVIDER_PRIVDATA *); +typedef HRESULT (WINAPI *SAFE_PROVIDER_INIT_CALL)(CRYPT_PROVIDER_DATA *); +typedef HRESULT (WINAPI *SAFE_PROVIDER_OBJTRUST_CALL)(CRYPT_PROVIDER_DATA *); +typedef HRESULT (WINAPI *SAFE_PROVIDER_SIGTRUST_CALL)(CRYPT_PROVIDER_DATA *); +typedef HRESULT (WINAPI *SAFE_PROVIDER_CERTTRUST_CALL)(CRYPT_PROVIDER_DATA *); +typedef HRESULT (WINAPI *SAFE_PROVIDER_FINALPOLICY_CALL)(CRYPT_PROVIDER_DATA *); +typedef HRESULT (WINAPI *SAFE_PROVIDER_TESTFINALPOLICY_CALL)( + CRYPT_PROVIDER_DATA *); +typedef HRESULT (WINAPI *SAFE_PROVIDER_CLEANUP_CALL)(CRYPT_PROVIDER_DATA *); +typedef BOOL (WINAPI *SAFE_PROVIDER_CERTCHKPOLICY_CALL)( + CRYPT_PROVIDER_DATA *, DWORD, BOOL, DWORD); + +typedef struct _SAFE_PROVIDER_FUNCTIONS +{ + DWORD cbStruct; + SAFE_MEM_ALLOC pfnAlloc; + SAFE_MEM_FREE pfnFree; + SAFE_ADD_STORE pfnAddStore2Chain; + SAFE_ADD_SGNR pfnAddSgnr2Chain; + SAFE_ADD_CERT pfnAddCert2Chain; + SAFE_ADD_PRIVDATA pfnAddPrivData2Chain; + SAFE_PROVIDER_INIT_CALL pfnInitialize; + SAFE_PROVIDER_OBJTRUST_CALL pfnObjectTrust; + SAFE_PROVIDER_SIGTRUST_CALL pfnSignatureTrust; + SAFE_PROVIDER_CERTTRUST_CALL pfnCertificateTrust; + SAFE_PROVIDER_FINALPOLICY_CALL pfnFinalPolicy; + SAFE_PROVIDER_CERTCHKPOLICY_CALL pfnCertCheckPolicy; + SAFE_PROVIDER_TESTFINALPOLICY_CALL pfnTestFinalPolicy; + struct _CRYPT_PROVUI_FUNCS *psUIpfns; + SAFE_PROVIDER_CLEANUP_CALL pfnCleanupPolicy; +} SAFE_PROVIDER_FUNCTIONS; + +static const BYTE v1CertWithPubKey[] = { +0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, +0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, +0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31, +0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31, +0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11, +0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e, +0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01, +0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, +0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06, +0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02, +0x01,0x01 }; + +static void test_utils(SAFE_PROVIDER_FUNCTIONS *funcs) +{ + CRYPT_PROVIDER_DATA data = { 0 }; + HCERTSTORE store; + CRYPT_PROVIDER_SGNR sgnr = { 0 }; + BOOL ret; + + /* Crash + ret = funcs->pfnAddStore2Chain(NULL, NULL); + ret = funcs->pfnAddStore2Chain(&data, NULL); + */ + store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (store) + { + ret = funcs->pfnAddStore2Chain(&data, store); + ok(ret, "pfnAddStore2Chain failed: %08x\n", GetLastError()); + ok(data.chStores == 1, "Expected 1 store, got %d\n", data.chStores); + ok(data.pahStores != NULL, "Expected pahStores to be allocated\n"); + if (data.pahStores) + { + ok(data.pahStores[0] == store, "Unexpected store\n"); + CertCloseStore(data.pahStores[0], 0); + funcs->pfnFree(data.pahStores); + data.pahStores = NULL; + data.chStores = 0; + CertCloseStore(store, 0); + store = NULL; + } + } + else + skip("CertOpenStore failed: %08x\n", GetLastError()); + + /* Crash + ret = funcs->pfnAddSgnr2Chain(NULL, FALSE, 0, NULL); + ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, NULL); + */ + ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr); + ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError()); + ok(data.csSigners == 1, "Expected 1 signer, got %d\n", data.csSigners); + ok(data.pasSigners != NULL, "Expected pasSigners to be allocated\n"); + if (data.pasSigners) + { + PCCERT_CONTEXT cert; + + ok(!memcmp(&data.pasSigners[0], &sgnr, sizeof(sgnr)), + "Unexpected data in signer\n"); + /* Adds into the location specified by the index */ + sgnr.cbStruct = sizeof(CRYPT_PROVIDER_SGNR); + sgnr.sftVerifyAsOf.dwLowDateTime = 0xdeadbeef; + ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 1, &sgnr); + ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError()); + ok(data.csSigners == 2, "Expected 2 signers, got %d\n", data.csSigners); + ok(!memcmp(&data.pasSigners[1], &sgnr, sizeof(sgnr)), + "Unexpected data in signer\n"); + /* This also adds, but the data aren't copied */ + sgnr.cbStruct = sizeof(DWORD); + ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr); + ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError()); + ok(data.csSigners == 3, "Expected 3 signers, got %d\n", data.csSigners); + ok(data.pasSigners[0].cbStruct == 0, "Unexpected data size %d\n", + data.pasSigners[0].cbStruct); + ok(data.pasSigners[0].sftVerifyAsOf.dwLowDateTime == 0, + "Unexpected verify time %d\n", + data.pasSigners[0].sftVerifyAsOf.dwLowDateTime); + /* But too large a thing isn't added */ + sgnr.cbStruct = sizeof(sgnr) + sizeof(DWORD); + SetLastError(0xdeadbeef); + ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* Crash + ret = funcs->pfnAddCert2Chain(NULL, 0, FALSE, 0, NULL); + ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, NULL); + */ + cert = CertCreateCertificateContext(X509_ASN_ENCODING, v1CertWithPubKey, + sizeof(v1CertWithPubKey)); + if (cert) + { + /* Notes on behavior that are hard to test: + * 1. If pasSigners is invalid, pfnAddCert2Chain crashes + * 2. An invalid signer index isn't checked. + */ + ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert); + ok(ret, "pfnAddCert2Chain failed: %08x\n", GetLastError()); + ok(data.pasSigners[0].csCertChain == 1, "Expected 1 cert, got %d\n", + data.pasSigners[0].csCertChain); + ok(data.pasSigners[0].pasCertChain != NULL, + "Expected pasCertChain to be allocated\n"); + if (data.pasSigners[0].pasCertChain) + ok(data.pasSigners[0].pasCertChain[0].pCert == cert, + "Unexpected cert\n"); + CertFreeCertificateContext(cert); + } + else + skip("CertCreateCertificateContext failed: %08x\n", GetLastError()); + } +} + +static void testInitialize(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID) +{ + HRESULT ret; + CRYPT_PROVIDER_DATA data = { 0 }; + WINTRUST_DATA wintrust_data = { 0 }; + + if (!funcs->pfnInitialize) + { + skip("missing pfnInitialize\n"); + return; + } + + /* Crashes + ret = funcs->pfnInitialize(NULL); + */ + memset(&data, 0, sizeof(data)); + ret = funcs->pfnInitialize(&data); + ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret); + data.padwTrustStepErrors = + funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD)); + /* Without wintrust data set, crashes when padwTrustStepErrors is set */ + data.pWintrustData = &wintrust_data; + if (data.padwTrustStepErrors) + { + /* Apparently, cdwTrustStepErrors does not need to be set. */ + ret = funcs->pfnInitialize(&data); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + data.cdwTrustStepErrors = 1; + ret = funcs->pfnInitialize(&data); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + memset(data.padwTrustStepErrors, 0xba, + TRUSTERROR_MAX_STEPS * sizeof(DWORD)); + ret = funcs->pfnInitialize(&data); + ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret); + data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT] = 0; + ret = funcs->pfnInitialize(&data); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + funcs->pfnFree(data.padwTrustStepErrors); + } +} + +static void getNotepadPath(WCHAR *notepadPathW, DWORD size) +{ + static const CHAR notepad[] = "\\notepad.exe"; + CHAR notepadPath[MAX_PATH]; + + /* Workaround missing W-functions for win9x */ + GetWindowsDirectoryA(notepadPath, MAX_PATH); + lstrcatA(notepadPath, notepad); + MultiByteToWideChar(0, 0, notepadPath, -1, notepadPathW, size); +} + +static void testObjTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID) +{ + HRESULT ret; + CRYPT_PROVIDER_DATA data = { 0 }; + WINTRUST_DATA wintrust_data = { 0 }; + WINTRUST_CERT_INFO certInfo = { sizeof(WINTRUST_CERT_INFO), 0 }; + WINTRUST_FILE_INFO fileInfo = { sizeof(WINTRUST_FILE_INFO), 0 }; + + if (!funcs->pfnObjectTrust) + { + skip("missing pfnObjectTrust\n"); + return; + } + + /* Crashes + ret = funcs->pfnObjectTrust(NULL); + */ + data.pWintrustData = &wintrust_data; + data.padwTrustStepErrors = + funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD)); + if (data.padwTrustStepErrors) + { + WCHAR notepadPathW[MAX_PATH]; + PROVDATA_SIP provDataSIP = { 0 }; + static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47, + 0x00,0xC0,0x4F,0xC2,0x95,0xEE } }; + + ret = funcs->pfnObjectTrust(&data); + ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret); + ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] == + ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", + data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]); + U(wintrust_data).pCert = &certInfo; + wintrust_data.dwUnionChoice = WTD_CHOICE_CERT; + ret = funcs->pfnObjectTrust(&data); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + certInfo.psCertContext = (PCERT_CONTEXT)CertCreateCertificateContext( + X509_ASN_ENCODING, v1CertWithPubKey, sizeof(v1CertWithPubKey)); + ret = funcs->pfnObjectTrust(&data); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + CertFreeCertificateContext(certInfo.psCertContext); + certInfo.psCertContext = NULL; + wintrust_data.dwUnionChoice = WTD_CHOICE_FILE; + U(wintrust_data).pFile = NULL; + ret = funcs->pfnObjectTrust(&data); + ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret); + ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] == + ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %08x\n", + data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]); + U(wintrust_data).pFile = &fileInfo; + /* Crashes + ret = funcs->pfnObjectTrust(&data); + */ + getNotepadPath(notepadPathW, MAX_PATH); + fileInfo.pcwszFilePath = notepadPathW; + /* pfnObjectTrust now crashes unless both pPDSip and psPfns are set */ + U(data).pPDSip = &provDataSIP; + data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs; + ret = funcs->pfnObjectTrust(&data); + ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret); + ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] == + TRUST_E_NOSIGNATURE || + data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] == + TRUST_E_SUBJECT_FORM_UNKNOWN, + "Expected TRUST_E_NOSIGNATURE or TRUST_E_SUBJECT_FORM_UNKNOWN, got %08x\n", + data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]); + if (data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] == + TRUST_E_NOSIGNATURE) + { + ok(!memcmp(&provDataSIP.gSubject, &unknown, sizeof(unknown)), + "Unexpected subject GUID\n"); + ok(provDataSIP.pSip != NULL, "Expected a SIP\n"); + ok(provDataSIP.psSipSubjectInfo != NULL, + "Expected a subject info\n"); + } + funcs->pfnFree(data.padwTrustStepErrors); + } +} + +static const BYTE selfSignedCert[] = { + 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, + 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49, + 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, + 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, + 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30, + 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31, + 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, + 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, + 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4, + 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b, + 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0, + 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96, + 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, + 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41, + 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66, + 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a, + 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7, + 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f, + 0xa8, 0x76, 0x57, 0x92, 0x36 }; + +static void testCertTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID) +{ + CRYPT_PROVIDER_DATA data = { 0 }; + CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } }; + HRESULT ret; + + data.padwTrustStepErrors = + funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD)); + if (!data.padwTrustStepErrors) + { + skip("pfnAlloc failed\n"); + return; + } + ret = funcs->pfnCertificateTrust(&data); + ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret); + ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] == + TRUST_E_NOSIGNATURE, "Expected TRUST_E_NOSIGNATURE, got %08x\n", + data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]); + ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr); + if (ret) + { + PCCERT_CONTEXT cert; + + /* An empty signer "succeeds," even though there's no cert */ + ret = funcs->pfnCertificateTrust(&data); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert, + sizeof(selfSignedCert)); + if (cert) + { + WINTRUST_DATA wintrust_data = { 0 }; + + ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert); + /* If pWintrustData isn't set, crashes attempting to access + * pWintrustData->fdwRevocationChecks + */ + data.pWintrustData = &wintrust_data; + /* If psPfns isn't set, crashes attempting to access + * psPfns->pfnCertCheckPolicy + */ + data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs; + ret = funcs->pfnCertificateTrust(&data); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + ok(data.csSigners == 1, "Unexpected number of signers %d\n", + data.csSigners); + ok(data.pasSigners[0].pChainContext != NULL, + "Expected a certificate chain\n"); + ok(data.pasSigners[0].csCertChain == 1, + "Unexpected number of chain elements %d\n", + data.pasSigners[0].csCertChain); + /* pasSigners and pasSigners[0].pasCertChain are guaranteed to be + * initialized, see tests for pfnAddSgnr2Chain and pfnAddCert2Chain + */ + ok(!data.pasSigners[0].pasCertChain[0].fTrustedRoot, + "Didn't expect cert to be trusted\n"); + ok(data.pasSigners[0].pasCertChain[0].fSelfSigned, + "Expected cert to be self-signed\n"); + ok(data.pasSigners[0].pasCertChain[0].dwConfidence == + (CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST), + "Expected CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST, got %08x\n", + data.pasSigners[0].pasCertChain[0].dwConfidence); + CertFreeCertificateContext(cert); + } + } +} + +static void test_provider_funcs(void) +{ + static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; + SAFE_PROVIDER_FUNCTIONS funcs = { sizeof(SAFE_PROVIDER_FUNCTIONS), 0 }; + BOOL ret; + + ret = WintrustLoadFunctionPointers(&generic_verify_v2, + (CRYPT_PROVIDER_FUNCTIONS *)&funcs); + if (!ret) + skip("WintrustLoadFunctionPointers failed\n"); + else + { + test_utils(&funcs); + testInitialize(&funcs, &generic_verify_v2); + testObjTrust(&funcs, &generic_verify_v2); + testCertTrust(&funcs, &generic_verify_v2); + } +} + +static void test_wintrust(void) +{ + static GUID generic_action_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; + WINTRUST_DATA wtd; + WINTRUST_FILE_INFO file; + LONG r; + HRESULT hr; + WCHAR notepadPathW[MAX_PATH]; + + memset(&wtd, 0, sizeof(wtd)); + wtd.cbStruct = sizeof(wtd); + wtd.dwUIChoice = WTD_UI_NONE; + wtd.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN; + wtd.dwUnionChoice = WTD_CHOICE_FILE; + U(wtd).pFile = &file; + wtd.dwStateAction = WTD_STATEACTION_VERIFY; + memset(&file, 0, sizeof(file)); + file.cbStruct = sizeof(file); + getNotepadPath(notepadPathW, MAX_PATH); + file.pcwszFilePath = notepadPathW; + r = WinVerifyTrust(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd); + ok(r == TRUST_E_NOSIGNATURE || r == CRYPT_E_FILE_ERROR, + "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", r); + hr = WinVerifyTrustEx(INVALID_HANDLE_VALUE, &generic_action_v2, &wtd); + ok(hr == TRUST_E_NOSIGNATURE || r == CRYPT_E_FILE_ERROR, + "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", hr); +} + +static BOOL (WINAPI * pWTHelperGetKnownUsages)(DWORD action, PCCRYPT_OID_INFO **usages); + +static void InitFunctionPtrs(void) +{ + HMODULE hWintrust = GetModuleHandleA("wintrust.dll"); + +#define WINTRUST_GET_PROC(func) \ + p ## func = (void*)GetProcAddress(hWintrust, #func); \ + if(!p ## func) { \ + trace("GetProcAddress(%s) failed\n", #func); \ + } + + WINTRUST_GET_PROC(WTHelperGetKnownUsages) + +#undef WINTRUST_GET_PROC +} + +static void test_get_known_usages(void) +{ + BOOL ret; + PCCRYPT_OID_INFO *usages; + + if (!pWTHelperGetKnownUsages) + { + skip("missing WTHelperGetKnownUsages\n"); + return; + } + SetLastError(0xdeadbeef); + ret = pWTHelperGetKnownUsages(0, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pWTHelperGetKnownUsages(1, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pWTHelperGetKnownUsages(0, &usages); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + /* A value of 1 for the first parameter seems to imply the value is + * allocated + */ + SetLastError(0xdeadbeef); + usages = NULL; + ret = pWTHelperGetKnownUsages(1, &usages); + ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError()); + ok(usages != NULL, "expected a pointer\n"); + if (ret && usages) + { + PCCRYPT_OID_INFO *ptr; + + /* The returned usages are an array of PCCRYPT_OID_INFOs, terminated with a + * NULL pointer. + */ + for (ptr = usages; *ptr; ptr++) + { + ok((*ptr)->cbSize == sizeof(CRYPT_OID_INFO) || + (*ptr)->cbSize == (sizeof(CRYPT_OID_INFO) + 2 * sizeof(LPCWSTR)), /* Vista */ + "unexpected size %d\n", (*ptr)->cbSize); + /* Each returned usage is in the CRYPT_ENHKEY_USAGE_OID_GROUP_ID group */ + ok((*ptr)->dwGroupId == CRYPT_ENHKEY_USAGE_OID_GROUP_ID, + "expected group CRYPT_ENHKEY_USAGE_OID_GROUP_ID, got %d\n", + (*ptr)->dwGroupId); + } + } + /* A value of 2 for the second parameter seems to imply the value is freed + */ + SetLastError(0xdeadbeef); + ret = pWTHelperGetKnownUsages(2, &usages); + ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError()); + ok(usages == NULL, "expected pointer to be cleared\n"); + SetLastError(0xdeadbeef); + usages = NULL; + ret = pWTHelperGetKnownUsages(2, &usages); + ok(ret, "WTHelperGetKnownUsages failed: %d\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = pWTHelperGetKnownUsages(2, NULL); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); +} + +START_TEST(softpub) +{ + InitFunctionPtrs(); + test_provider_funcs(); + test_wintrust(); + test_get_known_usages(); +} diff --git a/rostests/winetests/wintrust/testlist.c b/rostests/winetests/wintrust/testlist.c new file mode 100644 index 00000000000..6ef19728c3d --- /dev/null +++ b/rostests/winetests/wintrust/testlist.c @@ -0,0 +1,21 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_asn(void); +extern void func_crypt(void); +extern void func_register(void); +extern void func_softpub(void); + +const struct test winetest_testlist[] = +{ + { "asn", func_asn }, + { "crypt", func_crypt }, + { "register", func_register }, + { "softpub", func_softpub }, + { 0, 0 } +}; diff --git a/rostests/winetests/wintrust/wintrust.rbuild b/rostests/winetests/wintrust/wintrust.rbuild new file mode 100644 index 00000000000..7b7caa73ba7 --- /dev/null +++ b/rostests/winetests/wintrust/wintrust.rbuild @@ -0,0 +1,18 @@ + + + + + . + + asn.c + crypt.c + register.c + softpub.c + testlist.c + wine + wintrust + crypt32 + advapi32 + ntdll + + diff --git a/rostests/winetests/wlanapi/testlist.c b/rostests/winetests/wlanapi/testlist.c new file mode 100644 index 00000000000..b5ff645ba27 --- /dev/null +++ b/rostests/winetests/wlanapi/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_wlanapi(void); + +const struct test winetest_testlist[] = +{ + { "wlanapi", func_wlanapi }, + { 0, 0 } +}; diff --git a/rostests/winetests/wlanapi/wlanapi.c b/rostests/winetests/wlanapi/wlanapi.c new file mode 100644 index 00000000000..8f8255657c3 --- /dev/null +++ b/rostests/winetests/wlanapi/wlanapi.c @@ -0,0 +1,82 @@ +/* + * Wlanapi - tests + * + * Copyright 2009 Christoph von Wittich + * + * 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 + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wlanapi.h" + +#include "wine/test.h" + +static void WlanOpenHandle_test(void) +{ + DWORD ret; + DWORD dwNegotiatedVersion; + HANDLE hClientHandle; + + /* correct call to determine if WlanSvc is running */ + ret = WlanOpenHandle(1, NULL, &dwNegotiatedVersion, &hClientHandle); + if (ret == ERROR_SERVICE_EXISTS) + { + skip("Skipping wlanapi tests, WlanSvc is not running\n"); + return; + } + ok(ret == ERROR_SUCCESS, "WlanOpenHandle failed, error %d\n", ret); + WlanCloseHandle(hClientHandle, NULL); + + /* invalid pdwNegotiatedVersion */ + ret = WlanOpenHandle(1, NULL, NULL, &hClientHandle); + ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* invalid hClientHandle */ + ret = WlanOpenHandle(1, NULL, &dwNegotiatedVersion, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + + /* invalid pReserved */ + ret = WlanOpenHandle(1, (PVOID) 1, &dwNegotiatedVersion, &hClientHandle); + ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); +} + +static void WlanCloseHandle_test(void) +{ + DWORD ret; + HANDLE hClientHandle = (HANDLE) 0xdeadbeef; + + /* invalid pReserved */ + ret = WlanCloseHandle(hClientHandle, (PVOID) 1); + ok(ret == ERROR_INVALID_PARAMETER, "expected failure\n"); + + /* invalid hClientHandle */ + ret = WlanCloseHandle(NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "expected failure\n"); + + /* invalid hClientHandle */ + ret = WlanCloseHandle(hClientHandle, NULL); + ok(ret == ERROR_INVALID_HANDLE, "expected failure\n"); +} + +START_TEST(wlanapi) +{ + WlanOpenHandle_test(); + WlanCloseHandle_test(); +} diff --git a/rostests/winetests/wlanapi/wlanapi.rbuild b/rostests/winetests/wlanapi/wlanapi.rbuild new file mode 100644 index 00000000000..021d3cb9a26 --- /dev/null +++ b/rostests/winetests/wlanapi/wlanapi.rbuild @@ -0,0 +1,13 @@ + + + + + . + + wine + wlanapi + ntdll + wlanapi.c + testlist.c + + diff --git a/rostests/winetests/wldap32/parse.c b/rostests/winetests/wldap32/parse.c new file mode 100644 index 00000000000..d4b5de2fadf --- /dev/null +++ b/rostests/winetests/wldap32/parse.c @@ -0,0 +1,93 @@ +/* + * test parsing functions + * + * Copyright 2008 Hans Leidekker for CodeWeavers + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include "wine/test.h" + +static void test_ldap_parse_sort_control( LDAP *ld ) +{ + ULONG ret, result; + LDAPSortKeyA *sortkeys[2], key; + LDAPControlA *sort, *ctrls[2], **server_ctrls; + LDAPMessage *res = NULL; + struct l_timeval timeout; + + key.sk_attrtype = (char *)"ou"; + key.sk_matchruleoid = NULL; + key.sk_reverseorder = FALSE; + + sortkeys[0] = &key; + sortkeys[1] = NULL; + ret = ldap_create_sort_controlA( ld, sortkeys, 0, &sort ); + ok( !ret, "ldap_create_sort_controlA failed 0x%x\n", ret ); + + ctrls[0] = sort; + ctrls[1] = NULL; + timeout.tv_sec = 20; + timeout.tv_usec = 0; + ret = ldap_search_ext_sA( ld, (char *)"", LDAP_SCOPE_ONELEVEL, (char *)"(ou=*)", NULL, 0, ctrls, NULL, &timeout, 10, &res ); + if (ret == LDAP_SERVER_DOWN) + { + skip("test server can't be reached\n"); + ldap_control_free( sort ); + return; + } + ok( !ret, "ldap_search_ext_sA failed 0x%x\n", ret ); + ok( res != NULL, "expected res != NULL\n" ); + + ret = ldap_parse_resultA( NULL, res, &result, NULL, NULL, NULL, &server_ctrls, 1 ); + ok( ret == LDAP_PARAM_ERROR, "ldap_parse_resultA failed 0x%x\n", ret ); + + result = ~0u; + ret = ldap_parse_resultA( ld, res, &result, NULL, NULL, NULL, &server_ctrls, 1 ); + ok( !ret, "ldap_parse_resultA failed 0x%x\n", ret ); + ok( !result, "got 0x%x expected 0\n", result ); + + ret = ldap_parse_sort_controlA( NULL, NULL, NULL, NULL ); + ok( ret == LDAP_PARAM_ERROR, "ldap_parse_sort_controlA failed 0x%d\n", ret ); + + ret = ldap_parse_sort_controlA( ld, NULL, NULL, NULL ); + ok( ret == LDAP_CONTROL_NOT_FOUND, "ldap_parse_sort_controlA failed 0x%x\n", ret ); + + ret = ldap_parse_sort_controlA( ld, NULL, &result, NULL ); + ok( ret == LDAP_CONTROL_NOT_FOUND, "ldap_parse_sort_controlA failed 0x%x\n", ret ); + + ret = ldap_parse_sort_controlA( ld, server_ctrls, &result, NULL ); + ok( ret == LDAP_CONTROL_NOT_FOUND, "ldap_parse_sort_controlA failed 0x%x\n", ret ); + + ldap_control_free( sort ); + ldap_controls_free( server_ctrls ); +} + +START_TEST (parse) +{ + LDAP *ld; + + ld = ldap_initA((char *)"ldap.itd.umich.edu", 389 ); + ok( ld != NULL, "ldap_init failed\n" ); + + test_ldap_parse_sort_control( ld ); + ldap_unbind( ld ); +} diff --git a/rostests/winetests/wldap32/testlist.c b/rostests/winetests/wldap32/testlist.c new file mode 100644 index 00000000000..f6cb4b87289 --- /dev/null +++ b/rostests/winetests/wldap32/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_parse(void); + +const struct test winetest_testlist[] = +{ + { "parse", func_parse }, + { 0, 0 } +}; diff --git a/rostests/winetests/wldap32/wldap32.rbuild b/rostests/winetests/wldap32/wldap32.rbuild new file mode 100644 index 00000000000..da1ad318c62 --- /dev/null +++ b/rostests/winetests/wldap32/wldap32.rbuild @@ -0,0 +1,9 @@ + + . + + parse.c + testlist.c + wine + wldap32 + ntdll + diff --git a/rostests/winetests/ws2_32/protocol.c b/rostests/winetests/ws2_32/protocol.c new file mode 100644 index 00000000000..368955b65ba --- /dev/null +++ b/rostests/winetests/ws2_32/protocol.c @@ -0,0 +1,109 @@ +/* + * Unit test suite for protocol functions + * + * Copyright 2004 Hans Leidekker + * + * 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 + */ + +#include + +#include +#include +#include + +#include "wine/test.h" + + +static void test_WSAEnumProtocolsA(void) +{ + INT ret; + DWORD len = 0; + WSAPROTOCOL_INFOA info, *buffer; + + ret = WSAEnumProtocolsA( NULL, NULL, &len ); + ok( ret == SOCKET_ERROR, "WSAEnumProtocolsA() succeeded unexpectedly: %d\n", + WSAGetLastError() ); + + len = 0; + + ret = WSAEnumProtocolsA( NULL, &info, &len ); + ok( ret == SOCKET_ERROR, "WSAEnumProtocolsA() succeeded unexpectedly: %d\n", + WSAGetLastError() ); + + buffer = HeapAlloc( GetProcessHeap(), 0, len ); + + if (buffer) + { + INT i; + + ret = WSAEnumProtocolsA( NULL, buffer, &len ); + ok( ret != SOCKET_ERROR, "WSAEnumProtocolsA() failed unexpectedly: %d\n", + WSAGetLastError() ); + + for (i = 0; i < ret; i++) + { + ok( strlen( buffer[i].szProtocol ), "No protocol name found\n" ); + } + + HeapFree( GetProcessHeap(), 0, buffer ); + } +} + +static void test_WSAEnumProtocolsW(void) +{ + INT ret; + DWORD len = 0; + WSAPROTOCOL_INFOW info, *buffer; + + ret = WSAEnumProtocolsW( NULL, NULL, &len ); + ok( ret == SOCKET_ERROR, "WSAEnumProtocolsW() succeeded unexpectedly: %d\n", + WSAGetLastError() ); + + len = 0; + + ret = WSAEnumProtocolsW( NULL, &info, &len ); + ok( ret == SOCKET_ERROR, "WSAEnumProtocolsW() succeeded unexpectedly: %d\n", + WSAGetLastError() ); + + buffer = HeapAlloc( GetProcessHeap(), 0, len ); + + if (buffer) + { + INT i; + + ret = WSAEnumProtocolsW( NULL, buffer, &len ); + ok( ret != SOCKET_ERROR, "WSAEnumProtocolsW() failed unexpectedly: %d\n", + WSAGetLastError() ); + + for (i = 0; i < ret; i++) + { + ok( lstrlenW( buffer[i].szProtocol ), "No protocol name found\n" ); + } + + HeapFree( GetProcessHeap(), 0, buffer ); + } +} + +START_TEST( protocol ) +{ + WSADATA data; + WORD version = MAKEWORD( 2, 2 ); + + if (WSAStartup( version, &data )) return; + + test_WSAEnumProtocolsA(); + test_WSAEnumProtocolsW(); +} diff --git a/rostests/winetests/ws2_32/sock.c b/rostests/winetests/ws2_32/sock.c new file mode 100644 index 00000000000..22455ef0c3e --- /dev/null +++ b/rostests/winetests/ws2_32/sock.c @@ -0,0 +1,2354 @@ +/* + * Unit test suite for winsock functions + * + * Copyright 2002 Martin Wilck + * Copyright 2005 Thomas Kho + * Copyright 2008 Jeff Zaroyko + * + * 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 + */ + +#include + +#include +#include +#include +#include +#include +#include "wine/test.h" +#include +#include + +#define MAX_CLIENTS 4 /* Max number of clients */ +#define NUM_TESTS 4 /* Number of tests performed */ +#define FIRST_CHAR 'A' /* First character in transferred pattern */ +#define BIND_SLEEP 10 /* seconds to wait between attempts to bind() */ +#define BIND_TRIES 6 /* Number of bind() attempts */ +#define TEST_TIMEOUT 30 /* seconds to wait before killing child threads + after server initialization, if something hangs */ + +#define NUM_UDP_PEERS 3 /* Number of UDP sockets to create and test > 1 */ + +#define NUM_THREADS 3 /* Number of threads to run getservbyname */ +#define NUM_QUERIES 250 /* Number of getservbyname queries per thread */ + +#define SERVERIP "127.0.0.1" /* IP to bind to */ +#define SERVERPORT 9374 /* Port number to bind to */ + +#define wsa_ok(op, cond, msg) \ + do { \ + int tmp, err = 0; \ + tmp = op; \ + if ( !(cond tmp) ) err = WSAGetLastError(); \ + ok ( cond tmp, msg, GetCurrentThreadId(), err); \ + } while (0); + + +/**************** Structs and typedefs ***************/ + +typedef struct thread_info +{ + HANDLE thread; + DWORD id; +} thread_info; + +/* Information in the server about open client connections */ +typedef struct sock_info +{ + SOCKET s; + struct sockaddr_in addr; + struct sockaddr_in peer; + char *buf; + int n_recvd; + int n_sent; +} sock_info; + +/* Test parameters for both server & client */ +typedef struct test_params +{ + int sock_type; + int sock_prot; + const char *inet_addr; + short inet_port; + int chunk_size; + int n_chunks; + int n_clients; +} test_params; + +/* server-specific test parameters */ +typedef struct server_params +{ + test_params *general; + DWORD sock_flags; + int buflen; +} server_params; + +/* client-specific test parameters */ +typedef struct client_params +{ + test_params *general; + DWORD sock_flags; + int buflen; +} client_params; + +/* This type combines all information for setting up a test scenario */ +typedef struct test_setup +{ + test_params general; + LPVOID srv; + server_params srv_params; + LPVOID clt; + client_params clt_params; +} test_setup; + +/* Thread local storage for server */ +typedef struct server_memory +{ + SOCKET s; + struct sockaddr_in addr; + sock_info sock[MAX_CLIENTS]; +} server_memory; + +/* Thread local storage for client */ +typedef struct client_memory +{ + SOCKET s; + struct sockaddr_in addr; + char *send_buf; + char *recv_buf; +} client_memory; + +/* SelectReadThread thread parameters */ +typedef struct select_thread_params +{ + SOCKET s; + BOOL ReadKilled; +} select_thread_params; + +/**************** Static variables ***************/ + +static DWORD tls; /* Thread local storage index */ +static HANDLE thread[1+MAX_CLIENTS]; +static DWORD thread_id[1+MAX_CLIENTS]; +static HANDLE server_ready; +static HANDLE client_ready[MAX_CLIENTS]; +static int client_id; + +/**************** General utility functions ***************/ + +static int tcp_socketpair(SOCKET *src, SOCKET *dst) +{ + SOCKET server = INVALID_SOCKET; + struct sockaddr_in addr; + int len; + int ret; + + *src = INVALID_SOCKET; + *dst = INVALID_SOCKET; + + *src = socket(AF_INET, SOCK_STREAM, 0); + if (*src == INVALID_SOCKET) + goto end; + + server = socket(AF_INET, SOCK_STREAM, 0); + if (server == INVALID_SOCKET) + goto end; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + ret = bind(server, (struct sockaddr*)&addr, sizeof(addr)); + if (ret != 0) + goto end; + + len = sizeof(addr); + ret = getsockname(server, (struct sockaddr*)&addr, &len); + if (ret != 0) + goto end; + + ret = listen(server, 1); + if (ret != 0) + goto end; + + ret = connect(*src, (struct sockaddr*)&addr, sizeof(addr)); + if (ret != 0) + goto end; + + len = sizeof(addr); + *dst = accept(server, (struct sockaddr*)&addr, &len); + +end: + if (server != INVALID_SOCKET) + closesocket(server); + if (*src != INVALID_SOCKET && *dst != INVALID_SOCKET) + return 0; + closesocket(*src); + closesocket(*dst); + return -1; +} + +static void set_so_opentype ( BOOL overlapped ) +{ + int optval = !overlapped, newval, len = sizeof (int); + + ok ( setsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, + (LPVOID) &optval, sizeof (optval) ) == 0, + "setting SO_OPENTYPE failed\n" ); + ok ( getsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, + (LPVOID) &newval, &len ) == 0, + "getting SO_OPENTYPE failed\n" ); + ok ( optval == newval, "failed to set SO_OPENTYPE\n" ); +} + +static int set_blocking ( SOCKET s, BOOL blocking ) +{ + u_long val = !blocking; + return ioctlsocket ( s, FIONBIO, &val ); +} + +static void fill_buffer ( char *buf, int chunk_size, int n_chunks ) +{ + char c, *p; + for ( c = FIRST_CHAR, p = buf; c < FIRST_CHAR + n_chunks; c++, p += chunk_size ) + memset ( p, c, chunk_size ); +} + +static int test_buffer ( char *buf, int chunk_size, int n_chunks ) +{ + char c, *p; + int i; + for ( c = FIRST_CHAR, p = buf; c < FIRST_CHAR + n_chunks; c++, p += chunk_size ) + { + for ( i = 0; i < chunk_size; i++ ) + if ( p[i] != c ) return i; + } + return -1; +} + +/* + * This routine is called when a client / server does not expect any more data, + * but needs to acknowledge the closing of the connection (by reading 0 bytes). + */ +static void read_zero_bytes ( SOCKET s ) +{ + char buf[256]; + int tmp, n = 0; + while ( ( tmp = recv ( s, buf, 256, 0 ) ) > 0 ) + n += tmp; + ok ( n <= 0, "garbage data received: %d bytes\n", n ); +} + +static int do_synchronous_send ( SOCKET s, char *buf, int buflen, int sendlen ) +{ + char* last = buf + buflen, *p; + int n = 1; + for ( p = buf; n > 0 && p < last; p += n ) + n = send ( s, p, min ( sendlen, last - p ), 0 ); + wsa_ok ( n, 0 <=, "do_synchronous_send (%x): error %d\n" ); + return p - buf; +} + +static int do_synchronous_recv ( SOCKET s, char *buf, int buflen, int recvlen ) +{ + char* last = buf + buflen, *p; + int n = 1; + for ( p = buf; n > 0 && p < last; p += n ) + n = recv ( s, p, min ( recvlen, last - p ), 0 ); + wsa_ok ( n, 0 <=, "do_synchronous_recv (%x): error %d:\n" ); + return p - buf; +} + +static int do_synchronous_recvfrom ( SOCKET s, char *buf, int buflen,int flags,struct sockaddr *from, socklen_t *fromlen, int recvlen ) +{ + char* last = buf + buflen, *p; + int n = 1; + for ( p = buf; n > 0 && p < last; p += n ) + n = recvfrom ( s, p, min ( recvlen, last - p ), 0, from, fromlen ); + wsa_ok ( n, 0 <=, "do_synchronous_recv (%x): error %d:\n" ); + return p - buf; +} + +/* + * Call this routine right after thread startup. + * SO_OPENTYPE must by 0, regardless what the server did. + */ +static void check_so_opentype (void) +{ + int tmp = 1, len; + len = sizeof (tmp); + getsockopt ( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (LPVOID) &tmp, &len ); + ok ( tmp == 0, "check_so_opentype: wrong startup value of SO_OPENTYPE: %d\n", tmp ); +} + +/**************** Server utility functions ***************/ + +/* + * Even if we have closed our server socket cleanly, + * the OS may mark the address "in use" for some time - + * this happens with native Linux apps, too. + */ +static void do_bind ( SOCKET s, struct sockaddr* addr, int addrlen ) +{ + int err, wsaerr = 0, n_try = BIND_TRIES; + + while ( ( err = bind ( s, addr, addrlen ) ) != 0 && + ( wsaerr = WSAGetLastError () ) == WSAEADDRINUSE && + n_try-- >= 0) + { + trace ( "address in use, waiting ...\n" ); + Sleep ( 1000 * BIND_SLEEP ); + } + ok ( err == 0, "failed to bind: %d\n", wsaerr ); +} + +static void server_start ( server_params *par ) +{ + int i; + test_params *gen = par->general; + server_memory *mem = LocalAlloc ( LPTR, sizeof ( server_memory ) ); + + TlsSetValue ( tls, mem ); + mem->s = WSASocketA ( AF_INET, gen->sock_type, gen->sock_prot, + NULL, 0, par->sock_flags ); + ok ( mem->s != INVALID_SOCKET, "Server: WSASocket failed\n" ); + + mem->addr.sin_family = AF_INET; + mem->addr.sin_addr.s_addr = inet_addr ( gen->inet_addr ); + mem->addr.sin_port = htons ( gen->inet_port ); + + for (i = 0; i < MAX_CLIENTS; i++) + { + mem->sock[i].s = INVALID_SOCKET; + mem->sock[i].buf = LocalAlloc ( LPTR, gen->n_chunks * gen->chunk_size ); + mem->sock[i].n_recvd = 0; + mem->sock[i].n_sent = 0; + } + + if ( gen->sock_type == SOCK_STREAM ) + do_bind ( mem->s, (struct sockaddr*) &mem->addr, sizeof (mem->addr) ); +} + +static void server_stop (void) +{ + int i; + server_memory *mem = TlsGetValue ( tls ); + + for (i = 0; i < MAX_CLIENTS; i++ ) + { + LocalFree ( mem->sock[i].buf ); + if ( mem->sock[i].s != INVALID_SOCKET ) + closesocket ( mem->sock[i].s ); + } + ok ( closesocket ( mem->s ) == 0, "closesocket failed\n" ); + LocalFree ( mem ); + ExitThread ( GetCurrentThreadId () ); +} + +/**************** Client utilitiy functions ***************/ + +static void client_start ( client_params *par ) +{ + test_params *gen = par->general; + client_memory *mem = LocalAlloc (LPTR, sizeof (client_memory)); + + TlsSetValue ( tls, mem ); + + WaitForSingleObject ( server_ready, INFINITE ); + + mem->s = WSASocketA ( AF_INET, gen->sock_type, gen->sock_prot, + NULL, 0, par->sock_flags ); + + mem->addr.sin_family = AF_INET; + mem->addr.sin_addr.s_addr = inet_addr ( gen->inet_addr ); + mem->addr.sin_port = htons ( gen->inet_port ); + + ok ( mem->s != INVALID_SOCKET, "Client: WSASocket failed\n" ); + + mem->send_buf = LocalAlloc ( LPTR, 2 * gen->n_chunks * gen->chunk_size ); + mem->recv_buf = mem->send_buf + gen->n_chunks * gen->chunk_size; + fill_buffer ( mem->send_buf, gen->chunk_size, gen->n_chunks ); + + SetEvent ( client_ready[client_id] ); + /* Wait for the other clients to come up */ + WaitForMultipleObjects ( min ( gen->n_clients, MAX_CLIENTS ), client_ready, TRUE, INFINITE ); +} + +static void client_stop (void) +{ + client_memory *mem = TlsGetValue ( tls ); + wsa_ok ( closesocket ( mem->s ), 0 ==, "closesocket error (%x): %d\n" ); + LocalFree ( mem->send_buf ); + LocalFree ( mem ); + ExitThread(0); +} + +/**************** Servers ***************/ + +/* + * simple_server: A very basic server doing synchronous IO. + */ +static VOID WINAPI simple_server ( server_params *par ) +{ + test_params *gen = par->general; + server_memory *mem; + int pos, n_recvd, n_sent, n_expected = gen->n_chunks * gen->chunk_size, tmp, i, + id = GetCurrentThreadId(); + + trace ( "simple_server (%x) starting\n", id ); + + set_so_opentype ( FALSE ); /* non-overlapped */ + server_start ( par ); + mem = TlsGetValue ( tls ); + + wsa_ok ( set_blocking ( mem->s, TRUE ), 0 ==, "simple_server (%x): failed to set blocking mode: %d\n"); + wsa_ok ( listen ( mem->s, SOMAXCONN ), 0 ==, "simple_server (%x): listen failed: %d\n"); + + trace ( "simple_server (%x) ready\n", id ); + SetEvent ( server_ready ); /* notify clients */ + + for ( i = 0; i < min ( gen->n_clients, MAX_CLIENTS ); i++ ) + { + trace ( "simple_server (%x): waiting for client\n", id ); + + /* accept a single connection */ + tmp = sizeof ( mem->sock[0].peer ); + mem->sock[0].s = accept ( mem->s, (struct sockaddr*) &mem->sock[0].peer, &tmp ); + wsa_ok ( mem->sock[0].s, INVALID_SOCKET !=, "simple_server (%x): accept failed: %d\n" ); + + ok ( mem->sock[0].peer.sin_addr.s_addr == inet_addr ( gen->inet_addr ), + "simple_server (%x): strange peer address\n", id ); + + /* Receive data & check it */ + n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen ); + ok ( n_recvd == n_expected, + "simple_server (%x): received less data than expected: %d of %d\n", id, n_recvd, n_expected ); + pos = test_buffer ( mem->sock[0].buf, gen->chunk_size, gen->n_chunks ); + ok ( pos == -1, "simple_server (%x): test pattern error: %d\n", id, pos); + + /* Echo data back */ + n_sent = do_synchronous_send ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen ); + ok ( n_sent == n_expected, + "simple_server (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); + + /* cleanup */ + read_zero_bytes ( mem->sock[0].s ); + wsa_ok ( closesocket ( mem->sock[0].s ), 0 ==, "simple_server (%x): closesocket error: %d\n" ); + mem->sock[0].s = INVALID_SOCKET; + } + + trace ( "simple_server (%x) exiting\n", id ); + server_stop (); +} + +/* + * select_server: A non-blocking server. + */ +static VOID WINAPI select_server ( server_params *par ) +{ + test_params *gen = par->general; + server_memory *mem; + int n_expected = gen->n_chunks * gen->chunk_size, tmp, i, + id = GetCurrentThreadId(), n_connections = 0, n_sent, n_recvd, + n_set, delta, n_ready; + struct timeval timeout = {0,10}; /* wait for 10 milliseconds */ + fd_set fds_recv, fds_send, fds_openrecv, fds_opensend; + + trace ( "select_server (%x) starting\n", id ); + + set_so_opentype ( FALSE ); /* non-overlapped */ + server_start ( par ); + mem = TlsGetValue ( tls ); + + wsa_ok ( set_blocking ( mem->s, FALSE ), 0 ==, "select_server (%x): failed to set blocking mode: %d\n"); + wsa_ok ( listen ( mem->s, SOMAXCONN ), 0 ==, "select_server (%x): listen failed: %d\n"); + + trace ( "select_server (%x) ready\n", id ); + SetEvent ( server_ready ); /* notify clients */ + + FD_ZERO ( &fds_openrecv ); + FD_ZERO ( &fds_recv ); + FD_ZERO ( &fds_send ); + FD_ZERO ( &fds_opensend ); + + FD_SET ( mem->s, &fds_openrecv ); + + while(1) + { + fds_recv = fds_openrecv; + fds_send = fds_opensend; + + n_set = 0; + + wsa_ok ( ( n_ready = select ( 0, &fds_recv, &fds_send, NULL, &timeout ) ), SOCKET_ERROR !=, + "select_server (%x): select() failed: %d\n" ); + + /* check for incoming requests */ + if ( FD_ISSET ( mem->s, &fds_recv ) ) { + n_set += 1; + + trace ( "select_server (%x): accepting client connection\n", id ); + + /* accept a single connection */ + tmp = sizeof ( mem->sock[n_connections].peer ); + mem->sock[n_connections].s = accept ( mem->s, (struct sockaddr*) &mem->sock[n_connections].peer, &tmp ); + wsa_ok ( mem->sock[n_connections].s, INVALID_SOCKET !=, "select_server (%x): accept() failed: %d\n" ); + + ok ( mem->sock[n_connections].peer.sin_addr.s_addr == inet_addr ( gen->inet_addr ), + "select_server (%x): strange peer address\n", id ); + + /* add to list of open connections */ + FD_SET ( mem->sock[n_connections].s, &fds_openrecv ); + FD_SET ( mem->sock[n_connections].s, &fds_opensend ); + + n_connections++; + } + + /* handle open requests */ + + for ( i = 0; i < n_connections; i++ ) + { + if ( FD_ISSET( mem->sock[i].s, &fds_recv ) ) { + n_set += 1; + + if ( mem->sock[i].n_recvd < n_expected ) { + /* Receive data & check it */ + n_recvd = recv ( mem->sock[i].s, mem->sock[i].buf + mem->sock[i].n_recvd, min ( n_expected - mem->sock[i].n_recvd, par->buflen ), 0 ); + ok ( n_recvd != SOCKET_ERROR, "select_server (%x): error in recv(): %d\n", id, WSAGetLastError() ); + mem->sock[i].n_recvd += n_recvd; + + if ( mem->sock[i].n_recvd == n_expected ) { + int pos = test_buffer ( mem->sock[i].buf, gen->chunk_size, gen->n_chunks ); + ok ( pos == -1, "select_server (%x): test pattern error: %d\n", id, pos ); + FD_CLR ( mem->sock[i].s, &fds_openrecv ); + } + + ok ( mem->sock[i].n_recvd <= n_expected, "select_server (%x): received too many bytes: %d\n", id, mem->sock[i].n_recvd ); + } + } + + /* only echo back what we've received */ + delta = mem->sock[i].n_recvd - mem->sock[i].n_sent; + + if ( FD_ISSET ( mem->sock[i].s, &fds_send ) ) { + n_set += 1; + + if ( ( delta > 0 ) && ( mem->sock[i].n_sent < n_expected ) ) { + /* Echo data back */ + n_sent = send ( mem->sock[i].s, mem->sock[i].buf + mem->sock[i].n_sent, min ( delta, par->buflen ), 0 ); + ok ( n_sent != SOCKET_ERROR, "select_server (%x): error in send(): %d\n", id, WSAGetLastError() ); + mem->sock[i].n_sent += n_sent; + + if ( mem->sock[i].n_sent == n_expected ) { + FD_CLR ( mem->sock[i].s, &fds_opensend ); + } + + ok ( mem->sock[i].n_sent <= n_expected, "select_server (%x): sent too many bytes: %d\n", id, mem->sock[i].n_sent ); + } + } + } + + /* check that select returned the correct number of ready sockets */ + ok ( ( n_set == n_ready ), "select_server (%x): select() returns wrong number of ready sockets\n", id ); + + /* check if all clients are done */ + if ( ( fds_opensend.fd_count == 0 ) + && ( fds_openrecv.fd_count == 1 ) /* initial socket that accepts clients */ + && ( n_connections == min ( gen->n_clients, MAX_CLIENTS ) ) ) { + break; + } + } + + for ( i = 0; i < min ( gen->n_clients, MAX_CLIENTS ); i++ ) + { + /* cleanup */ + read_zero_bytes ( mem->sock[i].s ); + wsa_ok ( closesocket ( mem->sock[i].s ), 0 ==, "select_server (%x): closesocket error: %d\n" ); + mem->sock[i].s = INVALID_SOCKET; + } + + trace ( "select_server (%x) exiting\n", id ); + server_stop (); +} + +/**************** Clients ***************/ + +/* + * simple_client: A very basic client doing synchronous IO. + */ +static VOID WINAPI simple_client ( client_params *par ) +{ + test_params *gen = par->general; + client_memory *mem; + int pos, n_sent, n_recvd, n_expected = gen->n_chunks * gen->chunk_size, id; + + id = GetCurrentThreadId(); + trace ( "simple_client (%x): starting\n", id ); + /* wait here because we want to call set_so_opentype before creating a socket */ + WaitForSingleObject ( server_ready, INFINITE ); + trace ( "simple_client (%x): server ready\n", id ); + + check_so_opentype (); + set_so_opentype ( FALSE ); /* non-overlapped */ + client_start ( par ); + mem = TlsGetValue ( tls ); + + /* Connect */ + wsa_ok ( connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) ), + 0 ==, "simple_client (%x): connect error: %d\n" ); + ok ( set_blocking ( mem->s, TRUE ) == 0, + "simple_client (%x): failed to set blocking mode\n", id ); + trace ( "simple_client (%x) connected\n", id ); + + /* send data to server */ + n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, par->buflen ); + ok ( n_sent == n_expected, + "simple_client (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); + + /* shutdown send direction */ + wsa_ok ( shutdown ( mem->s, SD_SEND ), 0 ==, "simple_client (%x): shutdown failed: %d\n" ); + + /* Receive data echoed back & check it */ + n_recvd = do_synchronous_recv ( mem->s, mem->recv_buf, n_expected, par->buflen ); + ok ( n_recvd == n_expected, + "simple_client (%x): received less data than expected: %d of %d\n", id, n_recvd, n_expected ); + + /* check data */ + pos = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks ); + ok ( pos == -1, "simple_client (%x): test pattern error: %d\n", id, pos); + + /* cleanup */ + read_zero_bytes ( mem->s ); + trace ( "simple_client (%x) exiting\n", id ); + client_stop (); +} + +/* + * simple_mixed_client: mixing send and recvfrom + */ +static VOID WINAPI simple_mixed_client ( client_params *par ) +{ + test_params *gen = par->general; + client_memory *mem; + int pos, n_sent, n_recvd, n_expected = gen->n_chunks * gen->chunk_size, id; + socklen_t fromLen = sizeof(mem->addr); + struct sockaddr test; + + id = GetCurrentThreadId(); + trace ( "simple_client (%x): starting\n", id ); + /* wait here because we want to call set_so_opentype before creating a socket */ + WaitForSingleObject ( server_ready, INFINITE ); + trace ( "simple_client (%x): server ready\n", id ); + + check_so_opentype (); + set_so_opentype ( FALSE ); /* non-overlapped */ + client_start ( par ); + mem = TlsGetValue ( tls ); + + /* Connect */ + wsa_ok ( connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) ), + 0 ==, "simple_client (%x): connect error: %d\n" ); + ok ( set_blocking ( mem->s, TRUE ) == 0, + "simple_client (%x): failed to set blocking mode\n", id ); + trace ( "simple_client (%x) connected\n", id ); + + /* send data to server */ + n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, par->buflen ); + ok ( n_sent == n_expected, + "simple_client (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); + + /* shutdown send direction */ + wsa_ok ( shutdown ( mem->s, SD_SEND ), 0 ==, "simple_client (%x): shutdown failed: %d\n" ); + + /* this shouldn't change, since lpFrom, is not updated on + connection oriented sockets - exposed by bug 11640 + */ + ((struct sockaddr_in*)&test)->sin_addr.s_addr = inet_addr("0.0.0.0"); + + /* Receive data echoed back & check it */ + n_recvd = do_synchronous_recvfrom ( mem->s, + mem->recv_buf, + n_expected, + 0, + (struct sockaddr *)&test, + &fromLen, + par->buflen ); + ok ( n_recvd == n_expected, + "simple_client (%x): received less data than expected: %d of %d\n", id, n_recvd, n_expected ); + + /* check that lpFrom was not updated */ + ok(0 == + strcmp( + inet_ntoa(((struct sockaddr_in*)&test)->sin_addr), + "0.0.0.0"), "lpFrom shouldn't be updated on connection oriented sockets\n"); + + /* check data */ + pos = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks ); + ok ( pos == -1, "simple_client (%x): test pattern error: %d\n", id, pos); + + /* cleanup */ + read_zero_bytes ( mem->s ); + trace ( "simple_client (%x) exiting\n", id ); + client_stop (); +} + +/* + * event_client: An event-driven client + */ +static void WINAPI event_client ( client_params *par ) +{ + test_params *gen = par->general; + client_memory *mem; + int id = GetCurrentThreadId(), n_expected = gen->n_chunks * gen->chunk_size, + tmp, err, n; + HANDLE event; + WSANETWORKEVENTS wsa_events; + char *send_last, *recv_last, *send_p, *recv_p; + long mask = FD_READ | FD_WRITE | FD_CLOSE; + + trace ( "event_client (%x): starting\n", id ); + client_start ( par ); + trace ( "event_client (%x): server ready\n", id ); + + mem = TlsGetValue ( tls ); + + /* Prepare event notification for connect, makes socket nonblocking */ + event = WSACreateEvent (); + WSAEventSelect ( mem->s, event, FD_CONNECT ); + tmp = connect ( mem->s, (struct sockaddr*) &mem->addr, sizeof ( mem->addr ) ); + if ( tmp != 0 ) { + err = WSAGetLastError (); + ok ( err == WSAEWOULDBLOCK, "event_client (%x): connect error: %d\n", id, err ); + tmp = WaitForSingleObject ( event, INFINITE ); + ok ( tmp == WAIT_OBJECT_0, "event_client (%x): wait for connect event failed: %d\n", id, tmp ); + err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events ); + wsa_ok ( err, 0 ==, "event_client (%x): WSAEnumNetworkEvents error: %d\n" ); + err = wsa_events.iErrorCode[ FD_CONNECT_BIT ]; + ok ( err == 0, "event_client (%x): connect error: %d\n", id, err ); + if ( err ) goto out; + } + + trace ( "event_client (%x) connected\n", id ); + + WSAEventSelect ( mem->s, event, mask ); + + recv_p = mem->recv_buf; + recv_last = mem->recv_buf + n_expected; + send_p = mem->send_buf; + send_last = mem->send_buf + n_expected; + + while ( TRUE ) + { + err = WaitForSingleObject ( event, INFINITE ); + ok ( err == WAIT_OBJECT_0, "event_client (%x): wait failed\n", id ); + + err = WSAEnumNetworkEvents ( mem->s, event, &wsa_events ); + wsa_ok ( err, 0 ==, "event_client (%x): WSAEnumNetworkEvents error: %d\n" ); + + if ( wsa_events.lNetworkEvents & FD_WRITE ) + { + err = wsa_events.iErrorCode[ FD_WRITE_BIT ]; + ok ( err == 0, "event_client (%x): FD_WRITE error code: %d\n", id, err ); + + if ( err== 0 ) + do + { + n = send ( mem->s, send_p, min ( send_last - send_p, par->buflen ), 0 ); + if ( n < 0 ) + { + err = WSAGetLastError (); + ok ( err == WSAEWOULDBLOCK, "event_client (%x): send error: %d\n", id, err ); + } + else + send_p += n; + } + while ( n >= 0 && send_p < send_last ); + + if ( send_p == send_last ) + { + trace ( "event_client (%x): all data sent - shutdown\n", id ); + shutdown ( mem->s, SD_SEND ); + mask &= ~FD_WRITE; + WSAEventSelect ( mem->s, event, mask ); + } + } + if ( wsa_events.lNetworkEvents & FD_READ ) + { + err = wsa_events.iErrorCode[ FD_READ_BIT ]; + ok ( err == 0, "event_client (%x): FD_READ error code: %d\n", id, err ); + if ( err != 0 ) break; + + /* First read must succeed */ + n = recv ( mem->s, recv_p, min ( recv_last - recv_p, par->buflen ), 0 ); + wsa_ok ( n, 0 <=, "event_client (%x): recv error: %d\n" ); + + while ( n >= 0 ) { + recv_p += n; + if ( recv_p == recv_last ) + { + mask &= ~FD_READ; + trace ( "event_client (%x): all data received\n", id ); + WSAEventSelect ( mem->s, event, mask ); + break; + } + n = recv ( mem->s, recv_p, min ( recv_last - recv_p, par->buflen ), 0 ); + if ( n < 0 && ( err = WSAGetLastError()) != WSAEWOULDBLOCK ) + ok ( 0, "event_client (%x): read error: %d\n", id, err ); + + } + } + if ( wsa_events.lNetworkEvents & FD_CLOSE ) + { + trace ( "event_client (%x): close event\n", id ); + err = wsa_events.iErrorCode[ FD_CLOSE_BIT ]; + ok ( err == 0, "event_client (%x): FD_CLOSE error code: %d\n", id, err ); + break; + } + } + + n = send_p - mem->send_buf; + ok ( send_p == send_last, + "simple_client (%x): sent less data than expected: %d of %d\n", id, n, n_expected ); + n = recv_p - mem->recv_buf; + ok ( recv_p == recv_last, + "simple_client (%x): received less data than expected: %d of %d\n", id, n, n_expected ); + n = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks ); + ok ( n == -1, "event_client (%x): test pattern error: %d\n", id, n); + +out: + WSACloseEvent ( event ); + trace ( "event_client (%x) exiting\n", id ); + client_stop (); +} + +/**************** Main program utility functions ***************/ + +static void Init (void) +{ + WORD ver = MAKEWORD (2, 2); + WSADATA data; + + ok ( WSAStartup ( ver, &data ) == 0, "WSAStartup failed\n" ); + tls = TlsAlloc(); +} + +static void Exit (void) +{ + INT ret, err; + TlsFree ( tls ); + ret = WSACleanup(); + err = WSAGetLastError(); + ok ( ret == 0, "WSACleanup failed ret = %d GetLastError is %d\n", ret, err); + ret = WSACleanup(); + err = WSAGetLastError(); + ok ( (ret == SOCKET_ERROR && err == WSANOTINITIALISED) || + broken(ret == 0), /* WinME */ + "WSACleanup returned %d GetLastError is %d\n", ret, err); +} + +static void StartServer (LPTHREAD_START_ROUTINE routine, + test_params *general, server_params *par) +{ + par->general = general; + thread[0] = CreateThread ( NULL, 0, routine, par, 0, &thread_id[0] ); + ok ( thread[0] != NULL, "Failed to create server thread\n" ); +} + +static void StartClients (LPTHREAD_START_ROUTINE routine, + test_params *general, client_params *par) +{ + int i; + par->general = general; + for ( i = 1; i <= min ( general->n_clients, MAX_CLIENTS ); i++ ) + { + client_id = i - 1; + thread[i] = CreateThread ( NULL, 0, routine, par, 0, &thread_id[i] ); + ok ( thread[i] != NULL, "Failed to create client thread\n" ); + /* Make sure the client is up and running */ + WaitForSingleObject ( client_ready[client_id], INFINITE ); + }; +} + +static void do_test( test_setup *test ) +{ + DWORD i, n = min (test->general.n_clients, MAX_CLIENTS); + DWORD wait; + + server_ready = CreateEventA ( NULL, TRUE, FALSE, NULL ); + for (i = 0; i <= n; i++) + client_ready[i] = CreateEventA ( NULL, TRUE, FALSE, NULL ); + + StartServer ( test->srv, &test->general, &test->srv_params ); + StartClients ( test->clt, &test->general, &test->clt_params ); + WaitForSingleObject ( server_ready, INFINITE ); + + wait = WaitForMultipleObjects ( 1 + n, thread, TRUE, 1000 * TEST_TIMEOUT ); + ok ( wait <= WAIT_OBJECT_0 + n , + "some threads have not completed: %x\n", wait ); + + if ( ! ( wait <= WAIT_OBJECT_0 + n ) ) + { + for (i = 0; i <= n; i++) + { + trace ("terminating thread %08x\n", thread_id[i]); + if ( WaitForSingleObject ( thread[i], 0 ) != WAIT_OBJECT_0 ) + TerminateThread ( thread [i], 0 ); + } + } + CloseHandle ( server_ready ); + for (i = 0; i <= n; i++) + CloseHandle ( client_ready[i] ); +} + +/********* some tests for getsockopt(setsockopt(X)) == X ***********/ +/* optname = SO_LINGER */ +LINGER linger_testvals[] = { + {0,0}, + {0,73}, + {1,0}, + {5,189} +}; + +/* optname = SO_RCVTIMEO, SOSNDTIMEO */ +#define SOCKTIMEOUT1 63000 /* 63 seconds. Do not test fractional part because of a + bug in the linux kernel (fixed in 2.6.8) */ +#define SOCKTIMEOUT2 997000 /* 997 seconds */ + +static void test_set_getsockopt(void) +{ + SOCKET s; + int i, err, lasterr; + int timeout; + LINGER lingval; + int size; + + s = socket(AF_INET, SOCK_STREAM, 0); + ok(s!=INVALID_SOCKET, "socket() failed error: %d\n", WSAGetLastError()); + if( s == INVALID_SOCKET) return; + /* SO_RCVTIMEO */ + timeout = SOCKTIMEOUT1; + size = sizeof(timeout); + err = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, size); + if( !err) + err = getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, &size); + ok( !err, "get/setsockopt(SO_RCVTIMEO) failed error: %d\n", WSAGetLastError()); + ok( timeout == SOCKTIMEOUT1, "getsockopt(SO_RCVTIMEO) returned wrong value %d\n", timeout); + /* SO_SNDTIMEO */ + timeout = SOCKTIMEOUT2; /* 54 seconds. See remark above */ + size = sizeof(timeout); + err = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, size); + if( !err) + err = getsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, &size); + ok( !err, "get/setsockopt(SO_SNDTIMEO) failed error: %d\n", WSAGetLastError()); + ok( timeout == SOCKTIMEOUT2, "getsockopt(SO_SNDTIMEO) returned wrong value %d\n", timeout); + /* SO_LINGER */ + for( i = 0; i < sizeof(linger_testvals)/sizeof(LINGER);i++) { + size = sizeof(lingval); + lingval = linger_testvals[i]; + err = setsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &lingval, size); + if( !err) + err = getsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &lingval, &size); + ok( !err, "get/setsockopt(SO_LINGER) failed error: %d\n", WSAGetLastError()); + ok( !lingval.l_onoff == !linger_testvals[i].l_onoff && + (lingval.l_linger == linger_testvals[i].l_linger || + (!lingval.l_linger && !linger_testvals[i].l_onoff)) + , "getsockopt(SO_LINGER #%d) returned wrong value %d,%d not %d,%d\n", i, + lingval.l_onoff, lingval.l_linger, + linger_testvals[i].l_onoff, linger_testvals[i].l_linger); + } + /* Test for erroneously passing a value instead of a pointer as optval */ + size = sizeof(char); + err = setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)1, size); + ok(err == SOCKET_ERROR, "setsockopt with optval being a value passed " + "instead of failing.\n"); + lasterr = WSAGetLastError(); + ok(lasterr == WSAEFAULT, "setsockopt with optval being a value " + "returned 0x%08x, not WSAEFAULT(0x%08x)\n", + lasterr, WSAEFAULT); + closesocket(s); +} + +static void test_so_reuseaddr(void) +{ + struct sockaddr_in saddr; + SOCKET s1,s2; + unsigned int rc,reuse; + int size; + + saddr.sin_family = AF_INET; + saddr.sin_port = htons(9375); + saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + s1=socket(AF_INET, SOCK_STREAM, 0); + ok(s1!=INVALID_SOCKET, "socket() failed error: %d\n", WSAGetLastError()); + rc = bind(s1, (struct sockaddr*)&saddr, sizeof(saddr)); + ok(rc!=SOCKET_ERROR, "bind(s1) failed error: %d\n", WSAGetLastError()); + + s2=socket(AF_INET, SOCK_STREAM, 0); + ok(s2!=INVALID_SOCKET, "socket() failed error: %d\n", WSAGetLastError()); + + reuse=0x1234; + size=sizeof(reuse); + rc=getsockopt(s2, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, &size ); + ok(rc==0 && reuse==0,"wrong result in getsockopt(SO_REUSEADDR): rc=%d reuse=%d\n",rc,reuse); + + rc = bind(s2, (struct sockaddr*)&saddr, sizeof(saddr)); + ok(rc==SOCKET_ERROR, "bind() succeeded\n"); + + reuse = 1; + rc = setsockopt(s2, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)); + ok(rc==0, "setsockopt() failed error: %d\n", WSAGetLastError()); + + /* On Win2k3 and above, all SO_REUSEADDR seems to do is to allow binding to + * a port immediately after closing another socket on that port, so + * basically following the BSD socket semantics here. */ + closesocket(s1); + rc = bind(s2, (struct sockaddr*)&saddr, sizeof(saddr)); + ok(rc==0, "bind() failed error: %d\n", WSAGetLastError()); + + closesocket(s2); +} + +/************* Array containing the tests to run **********/ + +#define STD_STREAM_SOCKET \ + SOCK_STREAM, \ + 0, \ + SERVERIP, \ + SERVERPORT + +static test_setup tests [NUM_TESTS] = +{ + /* Test 0: synchronous client and server */ + { + { + STD_STREAM_SOCKET, + 2048, + 16, + 2 + }, + simple_server, + { + NULL, + 0, + 64 + }, + simple_client, + { + NULL, + 0, + 128 + } + }, + /* Test 1: event-driven client, synchronous server */ + { + { + STD_STREAM_SOCKET, + 2048, + 16, + 2 + }, + simple_server, + { + NULL, + 0, + 64 + }, + event_client, + { + NULL, + WSA_FLAG_OVERLAPPED, + 128 + } + }, + /* Test 2: synchronous client, non-blocking server via select() */ + { + { + STD_STREAM_SOCKET, + 2048, + 16, + 2 + }, + select_server, + { + NULL, + 0, + 64 + }, + simple_client, + { + NULL, + 0, + 128 + } + }, + /* Test 3: synchronous mixed client and server */ + { + { + STD_STREAM_SOCKET, + 2048, + 16, + 2 + }, + simple_server, + { + NULL, + 0, + 64 + }, + simple_mixed_client, + { + NULL, + 0, + 128 + } + } +}; + +static void test_UDP(void) +{ + /* This function tests UDP sendto() and recvfrom(). UDP is unreliable, so it is + possible that this test fails due to dropped packets. */ + + /* peer 0 receives data from all other peers */ + struct sock_info peer[NUM_UDP_PEERS]; + char buf[16]; + int ss, i, n_recv, n_sent; + + memset (buf,0,sizeof(buf)); + for ( i = NUM_UDP_PEERS - 1; i >= 0; i-- ) { + ok ( ( peer[i].s = socket ( AF_INET, SOCK_DGRAM, 0 ) ) != INVALID_SOCKET, "UDP: socket failed\n" ); + + peer[i].addr.sin_family = AF_INET; + peer[i].addr.sin_addr.s_addr = inet_addr ( SERVERIP ); + + if ( i == 0 ) { + peer[i].addr.sin_port = htons ( SERVERPORT ); + } else { + peer[i].addr.sin_port = htons ( 0 ); + } + + do_bind ( peer[i].s, (struct sockaddr *) &peer[i].addr, sizeof( peer[i].addr ) ); + + /* test getsockname() to get peer's port */ + ss = sizeof ( peer[i].addr ); + ok ( getsockname ( peer[i].s, (struct sockaddr *) &peer[i].addr, &ss ) != SOCKET_ERROR, "UDP: could not getsockname()\n" ); + ok ( peer[i].addr.sin_port != htons ( 0 ), "UDP: bind() did not associate port\n" ); + } + + /* test getsockname() */ + ok ( peer[0].addr.sin_port == htons ( SERVERPORT ), "UDP: getsockname returned incorrect peer port\n" ); + + for ( i = 1; i < NUM_UDP_PEERS; i++ ) { + /* send client's ip */ + memcpy( buf, &peer[i].addr.sin_port, sizeof(peer[i].addr.sin_port) ); + n_sent = sendto ( peer[i].s, buf, sizeof(buf), 0, (struct sockaddr*) &peer[0].addr, sizeof(peer[0].addr) ); + ok ( n_sent == sizeof(buf), "UDP: sendto() sent wrong amount of data or socket error: %d\n", n_sent ); + } + + for ( i = 1; i < NUM_UDP_PEERS; i++ ) { + n_recv = recvfrom ( peer[0].s, buf, sizeof(buf), 0,(struct sockaddr *) &peer[0].peer, &ss ); + ok ( n_recv == sizeof(buf), "UDP: recvfrom() received wrong amount of data or socket error: %d\n", n_recv ); + ok ( memcmp ( &peer[0].peer.sin_port, buf, sizeof(peer[0].addr.sin_port) ) == 0, "UDP: port numbers do not match\n" ); + } +} + +static void WINAPI do_getservbyname( HANDLE *starttest ) +{ + struct { + const char *name; + const char *proto; + int port; + } serv[2] = { {"domain", "udp", 53}, {"telnet", "tcp", 23} }; + + int i, j; + struct servent *pserv[2]; + + ok ( WaitForSingleObject ( *starttest, TEST_TIMEOUT * 1000 ) != WAIT_TIMEOUT, "test_getservbyname: timeout waiting for start signal\n"); + + /* ensure that necessary buffer resizes are completed */ + for ( j = 0; j < 2; j++) { + pserv[j] = getservbyname ( serv[j].name, serv[j].proto ); + } + + for ( i = 0; i < NUM_QUERIES / 2; i++ ) { + for ( j = 0; j < 2; j++ ) { + pserv[j] = getservbyname ( serv[j].name, serv[j].proto ); + ok ( pserv[j] != NULL, "getservbyname could not retrieve information for %s: %d\n", serv[j].name, WSAGetLastError() ); + ok ( pserv[j]->s_port == htons(serv[j].port), "getservbyname returned the wrong port for %s: %d\n", serv[j].name, ntohs(pserv[j]->s_port) ); + ok ( !strcmp ( pserv[j]->s_proto, serv[j].proto ), "getservbyname returned the wrong protocol for %s: %s\n", serv[j].name, pserv[j]->s_proto ); + ok ( !strcmp ( pserv[j]->s_name, serv[j].name ), "getservbyname returned the wrong name for %s: %s\n", serv[j].name, pserv[j]->s_name ); + } + + ok ( pserv[0] == pserv[1], "getservbyname: winsock resized servent buffer when not necessary\n" ); + } +} + +static void test_getservbyname(void) +{ + int i; + HANDLE starttest, thread[NUM_THREADS]; + DWORD thread_id[NUM_THREADS]; + + starttest = CreateEvent ( NULL, 1, 0, "test_getservbyname_starttest" ); + + /* create threads */ + for ( i = 0; i < NUM_THREADS; i++ ) { + thread[i] = CreateThread ( NULL, 0, (LPTHREAD_START_ROUTINE) &do_getservbyname, &starttest, 0, &thread_id[i] ); + } + + /* signal threads to start */ + SetEvent ( starttest ); + + for ( i = 0; i < NUM_THREADS; i++) { + WaitForSingleObject ( thread[i], TEST_TIMEOUT * 1000 ); + } +} + +static void test_WSASocket(void) +{ + SOCKET sock = INVALID_SOCKET; + WSAPROTOCOL_INFOA *pi; + int providers[] = {6, 0}; + int ret, err; + UINT pi_size; + + /* Set pi_size explicitly to a value below 2*sizeof(WSAPROTOCOL_INFOA) + * to avoid a crash on win98. + */ + pi_size = 0; + ret = WSAEnumProtocolsA(providers, NULL, &pi_size); + ok(ret == SOCKET_ERROR, "WSAEnumProtocolsA({6,0}, NULL, 0) returned %d\n", + ret); + err = WSAGetLastError(); + ok(err == WSAENOBUFS, "WSAEnumProtocolsA error is %d, not WSAENOBUFS(%d)\n", + err, WSAENOBUFS); + + pi = HeapAlloc(GetProcessHeap(), 0, pi_size); + ok(pi != NULL, "Failed to allocate memory\n"); + if (pi == NULL) { + skip("Can't continue without memory.\n"); + return; + } + + ret = WSAEnumProtocolsA(providers, pi, &pi_size); + ok(ret != SOCKET_ERROR, "WSAEnumProtocolsA failed, last error is %d\n", + WSAGetLastError()); + + if (ret == 0) { + skip("No protocols enumerated.\n"); + HeapFree(GetProcessHeap(), 0, pi); + return; + } + + sock = WSASocketA(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, &pi[0], 0, 0); + ok(sock != INVALID_SOCKET, "Failed to create socket: %d\n", + WSAGetLastError()); + + closesocket(sock); + HeapFree(GetProcessHeap(), 0, pi); +} + +static void test_WSAAddressToStringA(void) +{ + INT ret; + DWORD len; + int GLE; + SOCKADDR_IN sockaddr; + CHAR address[22]; /* 12 digits + 3 dots + ':' + 5 digits + '\0' */ + + CHAR expect1[] = "0.0.0.0"; + CHAR expect2[] = "255.255.255.255"; + CHAR expect3[] = "0.0.0.0:65535"; + CHAR expect4[] = "255.255.255.255:65535"; + + len = 0; + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAAddressToStringA( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + GLE = WSAGetLastError(); + ok( (ret == SOCKET_ERROR && GLE == WSAEFAULT) || (ret == 0), + "WSAAddressToStringA() failed unexpectedly: WSAGetLastError()=%d, ret=%d\n", + GLE, ret ); + + len = sizeof(address); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAAddressToStringA( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + ok( !ret, "WSAAddressToStringA() failed unexpectedly: %d\n", WSAGetLastError() ); + + ok( !strcmp( address, expect1 ), "Expected: %s, got: %s\n", expect1, address ); + + len = sizeof(address); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0xffffffff; + + ret = WSAAddressToStringA( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + ok( !ret, "WSAAddressToStringA() failed unexpectedly: %d\n", WSAGetLastError() ); + + ok( !strcmp( address, expect2 ), "Expected: %s, got: %s\n", expect2, address ); + + len = sizeof(address); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0xffff; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAAddressToStringA( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + ok( !ret, "WSAAddressToStringA() failed unexpectedly: %d\n", WSAGetLastError() ); + + ok( !strcmp( address, expect3 ), "Expected: %s, got: %s\n", expect3, address ); + + len = sizeof(address); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0xffff; + sockaddr.sin_addr.s_addr = 0xffffffff; + + ret = WSAAddressToStringA( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + ok( !ret, "WSAAddressToStringA() failed unexpectedly: %d\n", WSAGetLastError() ); + + ok( !strcmp( address, expect4 ), "Expected: %s, got: %s\n", expect4, address ); +} + +static void test_WSAAddressToStringW(void) +{ + INT ret; + DWORD len; + int GLE; + SOCKADDR_IN sockaddr; + WCHAR address[22]; /* 12 digits + 3 dots + ':' + 5 digits + '\0' */ + + WCHAR expect1[] = { '0','.','0','.','0','.','0', 0 }; + WCHAR expect2[] = { '2','5','5','.','2','5','5','.','2','5','5','.','2','5','5', 0 }; + WCHAR expect3[] = { '0','.','0','.','0','.','0', ':', '6', '5', '5', '3', '5', 0 }; + WCHAR expect4[] = { '2','5','5','.','2','5','5','.','2','5','5','.','2','5','5', ':', + '6', '5', '5', '3', '5', 0 }; + + len = 0; + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAAddressToStringW( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + GLE = WSAGetLastError(); + ok( (ret == SOCKET_ERROR && GLE == WSAEFAULT) || (ret == 0), + "WSAAddressToStringW() failed unexpectedly: WSAGetLastError()=%d, ret=%d\n", + GLE, ret ); + + len = sizeof(address); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAAddressToStringW( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + ok( !ret, "WSAAddressToStringW() failed unexpectedly: %d\n", WSAGetLastError() ); + + ok( !lstrcmpW( address, expect1 ), "Expected different address string\n" ); + + len = sizeof(address); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0xffffffff; + + ret = WSAAddressToStringW( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + ok( !ret, "WSAAddressToStringW() failed unexpectedly: %d\n", WSAGetLastError() ); + + ok( !lstrcmpW( address, expect2 ), "Expected different address string\n" ); + + len = sizeof(address); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0xffff; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAAddressToStringW( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + ok( !ret, "WSAAddressToStringW() failed unexpectedly: %d\n", WSAGetLastError() ); + + ok( !lstrcmpW( address, expect3 ), "Expected different address string\n" ); + + len = sizeof(address); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = 0xffff; + sockaddr.sin_addr.s_addr = 0xffffffff; + + ret = WSAAddressToStringW( (SOCKADDR*)&sockaddr, sizeof(sockaddr), NULL, address, &len ); + ok( !ret, "WSAAddressToStringW() failed unexpectedly: %d\n", WSAGetLastError() ); + + ok( !lstrcmpW( address, expect4 ), "Expected different address string\n" ); +} + +static void test_WSAStringToAddressA(void) +{ + INT ret, len; + SOCKADDR_IN sockaddr; + SOCKADDR_IN6 sockaddr6; + int GLE; + + CHAR address1[] = "0.0.0.0"; + CHAR address2[] = "127.127.127.127"; + CHAR address3[] = "255.255.255.255"; + CHAR address4[] = "127.127.127.127:65535"; + CHAR address5[] = "255.255.255.255:65535"; + CHAR address6[] = "::1"; + CHAR address7[] = "[::1]"; + CHAR address8[] = "[::1]:65535"; + + len = 0; + sockaddr.sin_family = AF_INET; + + ret = WSAStringToAddressA( address1, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( ret == SOCKET_ERROR, "WSAStringToAddressA() succeeded unexpectedly: %d\n", + WSAGetLastError() ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressA( address1, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( !ret && sockaddr.sin_addr.s_addr == 0, + "WSAStringToAddressA() failed unexpectedly: %d\n", WSAGetLastError() ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressA( address2, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( !ret && sockaddr.sin_addr.s_addr == 0x7f7f7f7f, + "WSAStringToAddressA() failed unexpectedly: %d\n", WSAGetLastError() ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressA( address3, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + GLE = WSAGetLastError(); + ok( (ret == 0 && sockaddr.sin_addr.s_addr == 0xffffffff) || + (ret == SOCKET_ERROR && (GLE == ERROR_INVALID_PARAMETER || GLE == WSAEINVAL)), + "WSAStringToAddressA() failed unexpectedly: %d\n", GLE ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressA( address4, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( !ret && sockaddr.sin_addr.s_addr == 0x7f7f7f7f && sockaddr.sin_port == 0xffff, + "WSAStringToAddressA() failed unexpectedly: %d\n", WSAGetLastError() ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressA( address5, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + GLE = WSAGetLastError(); + ok( (ret == 0 && sockaddr.sin_addr.s_addr == 0xffffffff && sockaddr.sin_port == 0xffff) || + (ret == SOCKET_ERROR && (GLE == ERROR_INVALID_PARAMETER || GLE == WSAEINVAL)), + "WSAStringToAddressA() failed unexpectedly: %d\n", GLE ); + + len = sizeof(sockaddr6); + memset(&sockaddr6, 0, len); + sockaddr6.sin6_family = AF_INET6; + + ret = WSAStringToAddressA( address6, AF_INET6, NULL, (SOCKADDR*)&sockaddr6, + &len ); + GLE = WSAGetLastError(); + ok( ret == 0 || (ret == SOCKET_ERROR && GLE == WSAEINVAL), + "WSAStringToAddressA() failed for IPv6 address: %d\n", GLE); + + len = sizeof(sockaddr6); + memset(&sockaddr6, 0, len); + sockaddr6.sin6_family = AF_INET6; + + ret = WSAStringToAddressA( address7, AF_INET6, NULL, (SOCKADDR*)&sockaddr6, + &len ); + GLE = WSAGetLastError(); + ok( ret == 0 || (ret == SOCKET_ERROR && GLE == WSAEINVAL), + "WSAStringToAddressA() failed for IPv6 address: %d\n", GLE); + + len = sizeof(sockaddr6); + memset(&sockaddr6, 0, len); + sockaddr6.sin6_family = AF_INET6; + + ret = WSAStringToAddressA( address8, AF_INET6, NULL, (SOCKADDR*)&sockaddr6, + &len ); + GLE = WSAGetLastError(); + ok( (ret == 0 && sockaddr6.sin6_port == 0xffff) || + (ret == SOCKET_ERROR && GLE == WSAEINVAL), + "WSAStringToAddressA() failed for IPv6 address: %d\n", GLE); + +} + +static void test_WSAStringToAddressW(void) +{ + INT ret, len; + SOCKADDR_IN sockaddr; + SOCKADDR_IN6 sockaddr6; + int GLE; + + WCHAR address1[] = { '0','.','0','.','0','.','0', 0 }; + WCHAR address2[] = { '1','2','7','.','1','2','7','.','1','2','7','.','1','2','7', 0 }; + WCHAR address3[] = { '2','5','5','.','2','5','5','.','2','5','5','.','2','5','5', 0 }; + WCHAR address4[] = { '1','2','7','.','1','2','7','.','1','2','7','.','1','2','7', + ':', '6', '5', '5', '3', '5', 0 }; + WCHAR address5[] = { '2','5','5','.','2','5','5','.','2','5','5','.','2','5','5', ':', + '6', '5', '5', '3', '5', 0 }; + WCHAR address6[] = {':',':','1','\0'}; + WCHAR address7[] = {'[',':',':','1',']','\0'}; + WCHAR address8[] = {'[',':',':','1',']',':','6','5','5','3','5','\0'}; + + len = 0; + sockaddr.sin_family = AF_INET; + + ret = WSAStringToAddressW( address1, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( ret == SOCKET_ERROR, "WSAStringToAddressW() failed unexpectedly: %d\n", + WSAGetLastError() ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressW( address1, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( !ret && sockaddr.sin_addr.s_addr == 0, + "WSAStringToAddressW() failed unexpectedly: %d\n", WSAGetLastError() ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressW( address2, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( !ret && sockaddr.sin_addr.s_addr == 0x7f7f7f7f, + "WSAStringToAddressW() failed unexpectedly: %d\n", WSAGetLastError() ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressW( address3, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + GLE = WSAGetLastError(); + ok( (ret == 0 && sockaddr.sin_addr.s_addr == 0xffffffff) || + (ret == SOCKET_ERROR && (GLE == ERROR_INVALID_PARAMETER || GLE == WSAEINVAL)), + "WSAStringToAddressW() failed unexpectedly: %d\n", GLE ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressW( address4, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( !ret && sockaddr.sin_addr.s_addr == 0x7f7f7f7f && sockaddr.sin_port == 0xffff, + "WSAStringToAddressW() failed unexpectedly: %d\n", WSAGetLastError() ); + + len = sizeof(sockaddr); + sockaddr.sin_port = 0; + sockaddr.sin_addr.s_addr = 0; + + ret = WSAStringToAddressW( address5, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + ok( (ret == 0 && sockaddr.sin_addr.s_addr == 0xffffffff && sockaddr.sin_port == 0xffff) || + (ret == SOCKET_ERROR && (GLE == ERROR_INVALID_PARAMETER || GLE == WSAEINVAL)), + "WSAStringToAddressW() failed unexpectedly: %d\n", GLE ); + + len = sizeof(sockaddr6); + memset(&sockaddr6, 0, len); + sockaddr6.sin6_family = AF_INET6; + + ret = WSAStringToAddressW( address6, AF_INET6, NULL, (SOCKADDR*)&sockaddr6, + &len ); + GLE = WSAGetLastError(); + ok( ret == 0 || (ret == SOCKET_ERROR && GLE == WSAEINVAL), + "WSAStringToAddressW() failed for IPv6 address: %d\n", GLE); + + len = sizeof(sockaddr6); + memset(&sockaddr6, 0, len); + sockaddr6.sin6_family = AF_INET6; + + ret = WSAStringToAddressW( address7, AF_INET6, NULL, (SOCKADDR*)&sockaddr6, + &len ); + GLE = WSAGetLastError(); + ok( ret == 0 || (ret == SOCKET_ERROR && GLE == WSAEINVAL), + "WSAStringToAddressW() failed for IPv6 address: %d\n", GLE); + + len = sizeof(sockaddr6); + memset(&sockaddr6, 0, len); + sockaddr6.sin6_family = AF_INET6; + + ret = WSAStringToAddressW( address8, AF_INET6, NULL, (SOCKADDR*)&sockaddr6, + &len ); + GLE = WSAGetLastError(); + ok( (ret == 0 && sockaddr6.sin6_port == 0xffff) || + (ret == SOCKET_ERROR && GLE == WSAEINVAL), + "WSAStringToAddressW() failed for IPv6 address: %d\n", GLE); + +} + +static VOID WINAPI SelectReadThread(select_thread_params *par) +{ + fd_set readfds; + int ret; + struct sockaddr_in addr; + struct timeval select_timeout; + + FD_ZERO(&readfds); + FD_SET(par->s, &readfds); + select_timeout.tv_sec=5; + select_timeout.tv_usec=0; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(SERVERIP); + addr.sin_port = htons(SERVERPORT); + + do_bind(par->s, (struct sockaddr *)&addr, sizeof(addr)); + wsa_ok(listen(par->s, SOMAXCONN ), 0 ==, "SelectReadThread (%x): listen failed: %d\n"); + + SetEvent(server_ready); + ret = select(par->s+1, &readfds, NULL, NULL, &select_timeout); + par->ReadKilled = (ret == 1); +} + +static void test_select(void) +{ + SOCKET fdRead, fdWrite; + fd_set readfds, writefds, exceptfds; + unsigned int maxfd; + int ret; + struct timeval select_timeout; + select_thread_params thread_params; + HANDLE thread_handle; + DWORD id; + + fdRead = socket(AF_INET, SOCK_STREAM, 0); + ok( (fdRead != INVALID_SOCKET), "socket failed unexpectedly: %d\n", WSAGetLastError() ); + fdWrite = socket(AF_INET, SOCK_STREAM, 0); + ok( (fdWrite != INVALID_SOCKET), "socket failed unexpectedly: %d\n", WSAGetLastError() ); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(fdRead, &readfds); + FD_SET(fdWrite, &writefds); + FD_SET(fdRead, &exceptfds); + FD_SET(fdWrite, &exceptfds); + select_timeout.tv_sec=0; + select_timeout.tv_usec=500; + + maxfd = fdRead; + if (fdWrite > maxfd) + maxfd = fdWrite; + + todo_wine { + ret = select(maxfd+1, &readfds, &writefds, &exceptfds, &select_timeout); + ok ( (ret == 0), "select should not return any socket handles\n"); + ok ( !FD_ISSET(fdRead, &readfds), "FD should not be set\n"); + ok ( !FD_ISSET(fdWrite, &writefds), "FD should not be set\n"); + } + + ok ( !FD_ISSET(fdRead, &exceptfds), "FD should not be set\n"); + ok ( !FD_ISSET(fdWrite, &exceptfds), "FD should not be set\n"); + + todo_wine { + ok ((listen(fdWrite, SOMAXCONN) == SOCKET_ERROR), "listen did not fail\n"); + } + ret = closesocket(fdWrite); + ok ( (ret == 0), "closesocket failed unexpectedly: %d\n", ret); + + thread_params.s = fdRead; + thread_params.ReadKilled = FALSE; + server_ready = CreateEventA(NULL, TRUE, FALSE, NULL); + thread_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) &SelectReadThread, &thread_params, 0, &id ); + ok ( (thread_handle != NULL), "CreateThread failed unexpectedly: %d\n", GetLastError()); + + WaitForSingleObject (server_ready, INFINITE); + Sleep(200); + ret = closesocket(fdRead); + ok ( (ret == 0), "closesocket failed unexpectedly: %d\n", ret); + + WaitForSingleObject (thread_handle, 1000); + ok ( (thread_params.ReadKilled) || + broken(thread_params.ReadKilled == 0), /*Win98*/ + "closesocket did not wakeup select\n"); + +} + +static DWORD WINAPI AcceptKillThread(select_thread_params *par) +{ + struct sockaddr_in address; + int len = sizeof(address); + SOCKET client_socket; + + SetEvent(server_ready); + client_socket = accept(par->s, (struct sockaddr*) &address, &len); + if (client_socket != INVALID_SOCKET) + closesocket(client_socket); + par->ReadKilled = (client_socket == INVALID_SOCKET); + return 0; +} + +static void test_accept(void) +{ + int ret; + SOCKET server_socket = INVALID_SOCKET; + struct sockaddr_in address; + select_thread_params thread_params; + HANDLE thread_handle = NULL; + DWORD id; + + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket == INVALID_SOCKET) + { + trace("error creating server socket: %d\n", WSAGetLastError()); + goto done; + } + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + ret = bind(server_socket, (struct sockaddr*) &address, sizeof(address)); + if (ret != 0) + { + trace("error binding server socket: %d\n", WSAGetLastError()); + goto done; + } + + ret = listen(server_socket, 1); + if (ret != 0) + { + trace("error making server socket listen: %d\n", WSAGetLastError()); + goto done; + } + + server_ready = CreateEventA(NULL, TRUE, FALSE, NULL); + if (server_ready == INVALID_HANDLE_VALUE) + { + trace("error creating event: %d\n", GetLastError()); + goto done; + } + + thread_params.s = server_socket; + thread_params.ReadKilled = FALSE; + thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) AcceptKillThread, + &thread_params, 0, &id); + if (thread_handle == NULL) + { + trace("error creating thread: %d\n", GetLastError()); + goto done; + } + + WaitForSingleObject(server_ready, INFINITE); + Sleep(200); + ret = closesocket(server_socket); + if (ret != 0) + { + trace("closesocket failed: %d\n", WSAGetLastError()); + goto done; + } + + WaitForSingleObject(thread_handle, 1000); + ok(thread_params.ReadKilled, "closesocket did not wakeup accept\n"); + +done: + if (thread_handle != NULL) + CloseHandle(thread_handle); + if (server_ready != INVALID_HANDLE_VALUE) + CloseHandle(server_ready); + if (server_socket != INVALID_SOCKET) + closesocket(server_socket); +} + +static void test_extendedSocketOptions(void) +{ + WSADATA wsa; + SOCKET sock; + struct sockaddr_in sa; + int sa_len = sizeof(struct sockaddr_in); + int optval, optlen = sizeof(int), ret; + BOOL bool_opt_val; + LINGER linger_val; + + if(WSAStartup(MAKEWORD(2,0), &wsa)){ + trace("Winsock failed: %d. Aborting test\n", WSAGetLastError()); + return; + } + + memset(&sa, 0, sa_len); + + sa.sin_family = AF_INET; + sa.sin_port = htons(0); + sa.sin_addr.s_addr = htonl(INADDR_ANY); + + if((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) == INVALID_SOCKET) { + trace("Creating the socket failed: %d\n", WSAGetLastError()); + WSACleanup(); + return; + } + + if(bind(sock, (struct sockaddr *) &sa, sa_len) < 0){ + trace("Failed to bind socket: %d\n", WSAGetLastError()); + closesocket(sock); + WSACleanup(); + return; + } + + ret = getsockopt(sock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&optval, &optlen); + + ok(ret == 0, "getsockopt failed to query SO_MAX_MSG_SIZE, return value is 0x%08x\n", ret); + ok((optval == 65507) || (optval == 65527), + "SO_MAX_MSG_SIZE reported %d, expected 65507 or 65527\n", optval); + + optlen = sizeof(LINGER); + ret = getsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&linger_val, &optlen); + todo_wine{ + ok(ret == SOCKET_ERROR, "getsockopt should fail for UDP sockets but return value is 0x%08x\n", ret); + } + + closesocket(sock); + + if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) { + trace("Creating the socket failed: %d\n", WSAGetLastError()); + WSACleanup(); + return; + } + + if(bind(sock, (struct sockaddr *) &sa, sa_len) < 0){ + trace("Failed to bind socket: %d\n", WSAGetLastError()); + closesocket(sock); + WSACleanup(); + return; + } + + ret = getsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&linger_val, &optlen); + ok(ret == 0, "getsockopt failed to query SO_LINGER, return value is 0x%08x\n", ret); + + optlen = sizeof(BOOL); + ret = getsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char *)&bool_opt_val, &optlen); + ok(ret == 0, "getsockopt failed to query SO_DONTLINGER, return value is 0x%08x\n", ret); + ok((linger_val.l_onoff && !bool_opt_val) || (!linger_val.l_onoff && bool_opt_val), + "Return value of SO_DONTLINGER is %d, but SO_LINGER returned l_onoff == %d.\n", + bool_opt_val, linger_val.l_onoff); + + closesocket(sock); + WSACleanup(); +} + +static void test_getsockname(void) +{ + WSADATA wsa; + SOCKET sock; + struct sockaddr_in sa_set, sa_get; + int sa_set_len = sizeof(struct sockaddr_in); + int sa_get_len = sa_set_len; + static const unsigned char null_padding[] = {0,0,0,0,0,0,0,0}; + int ret; + + if(WSAStartup(MAKEWORD(2,0), &wsa)){ + trace("Winsock failed: %d. Aborting test\n", WSAGetLastError()); + return; + } + + memset(&sa_set, 0, sa_set_len); + + sa_set.sin_family = AF_INET; + sa_set.sin_port = htons(0); + sa_set.sin_addr.s_addr = htonl(INADDR_ANY); + + if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) { + trace("Creating the socket failed: %d\n", WSAGetLastError()); + WSACleanup(); + return; + } + + memcpy(&sa_get, &sa_set, sizeof(sa_set)); + if (getsockname(sock, (struct sockaddr*) &sa_get, &sa_get_len) == 0) + ok(0, "getsockname on unbound socket should fail\n"); + else { + ok(WSAGetLastError() == WSAEINVAL, "getsockname on unbound socket " + "failed with %d, expected %d\n", WSAGetLastError(), WSAEINVAL); + ok(memcmp(&sa_get, &sa_set, sizeof(sa_get)) == 0, + "failed getsockname modified sockaddr when it shouldn't\n"); + } + + if(bind(sock, (struct sockaddr *) &sa_set, sa_set_len) < 0){ + trace("Failed to bind socket: %d\n", WSAGetLastError()); + closesocket(sock); + WSACleanup(); + return; + } + + if(getsockname(sock, (struct sockaddr *) &sa_get, &sa_get_len) != 0){ + trace("Failed to call getsockname: %d\n", WSAGetLastError()); + closesocket(sock); + WSACleanup(); + return; + } + + ret = memcmp(sa_get.sin_zero, null_padding, 8); + ok(ret == 0 || broken(ret != 0), /* NT4 */ + "getsockname did not zero the sockaddr_in structure\n"); + + closesocket(sock); + WSACleanup(); +} + +static void test_dns(void) +{ + struct hostent *h; + + h = gethostbyname(""); + ok(h != NULL, "gethostbyname(\"\") failed with %d\n", h_errno); +} + +/* Our winsock headers don't define gethostname because it conflicts with the + * definition in unistd.h. Define it here to get rid of the warning. */ + +int WINAPI gethostname(char *name, int namelen); + +static void test_gethostbyname_hack(void) +{ + struct hostent *he; + char name[256]; + static BYTE loopback[] = {127, 0, 0, 1}; + static BYTE magic_loopback[] = {127, 12, 34, 56}; + int ret; + + ret = gethostname(name, 256); + ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); + + he = gethostbyname("localhost"); + ok(he != NULL, "gethostbyname(\"localhost\") failed: %d\n", h_errno); + if(he) + { + if(he->h_length != 4) + { + skip("h_length is %d, not IPv4, skipping test.\n", he->h_length); + return; + } + + ok(memcmp(he->h_addr_list[0], loopback, he->h_length) == 0, + "gethostbyname(\"localhost\") returned %d.%d.%d.%d\n", + he->h_addr_list[0][0], he->h_addr_list[0][1], he->h_addr_list[0][2], + he->h_addr_list[0][3]); + } + + /* No reason to test further with NULL hostname */ + if(name == NULL) + return; + + if(strcmp(name, "localhost") == 0) + { + skip("hostname seems to be \"localhost\", skipping test.\n"); + return; + } + + he = NULL; + he = gethostbyname(name); + ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, h_errno); + if(he) + { + if(he->h_length != 4) + { + skip("h_length is %d, not IPv4, skipping test.\n", he->h_length); + return; + } + + if (he->h_addr_list[0][0] == 127) + { + ok(memcmp(he->h_addr_list[0], magic_loopback, he->h_length) == 0, + "gethostbyname(\"%s\") returned %d.%d.%d.%d not 127.12.34.56\n", + name, he->h_addr_list[0][0], he->h_addr_list[0][1], + he->h_addr_list[0][2], he->h_addr_list[0][3]); + } + } + + he = NULL; + he = gethostbyname("nonexistent.winehq.org"); + /* Don't check for the return value, as some braindead ISPs will kindly + * resolve nonexistent host names to addresses of the ISP's spam pages. */ +} + +static void test_inet_addr(void) +{ + u_long addr; + + addr = inet_addr(NULL); + ok(addr == INADDR_NONE, "inet_addr succeeded unexpectedly\n"); +} + +static void test_ioctlsocket(void) +{ + SOCKET sock; + int ret; + long cmds[] = {FIONBIO, FIONREAD, SIOCATMARK}; + int i; + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(sock != INVALID_SOCKET, "Creating the socket failed: %d\n", WSAGetLastError()); + if(sock == INVALID_SOCKET) + { + skip("Can't continue without a socket.\n"); + return; + } + + for(i = 0; i < sizeof(cmds)/sizeof(long); i++) + { + /* broken apps like defcon pass the argp value directly instead of a pointer to it */ + ret = ioctlsocket(sock, cmds[i], (u_long *)1); + ok(ret == SOCKET_ERROR, "ioctlsocket succeeded unexpectedly\n"); + ret = WSAGetLastError(); + ok(ret == WSAEFAULT, "expected WSAEFAULT, got %d instead\n", ret); + } +} + +static int drain_pause=0; +static DWORD WINAPI drain_socket_thread(LPVOID arg) +{ + char buffer[1024]; + SOCKET sock = *(SOCKET*)arg; + int ret; + + while ((ret = recv(sock, buffer, sizeof(buffer), 0)) != 0) + { + if (ret < 0) + { + if (WSAGetLastError() == WSAEWOULDBLOCK) + { + fd_set readset; + FD_ZERO(&readset); + FD_SET(sock, &readset); + select(0, &readset, NULL, NULL, NULL); + while (drain_pause) + Sleep(100); + } + else + break; + } + } + return 0; +} + +static void test_send(void) +{ + SOCKET src = INVALID_SOCKET; + SOCKET dst = INVALID_SOCKET; + HANDLE hThread = NULL; + const int buflen = 1024*1024; + char *buffer = NULL; + int ret; + DWORD id; + + if (tcp_socketpair(&src, &dst) != 0) + { + ok(0, "creating socket pair failed, skipping test\n"); + return; + } + + hThread = CreateThread(NULL, 0, drain_socket_thread, &dst, 0, &id); + if (hThread == NULL) + { + ok(0, "CreateThread failed, error %d\n", GetLastError()); + goto end; + } + + buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buflen); + if (buffer == NULL) + { + ok(0, "HeapAlloc failed, error %d\n", GetLastError()); + goto end; + } + + ret = send(src, buffer, buflen, 0); + if (ret >= 0) + ok(ret == buflen, "send should have sent %d bytes, but it only sent %d\n", buflen, ret); + else + ok(0, "send failed, error %d\n", WSAGetLastError()); + +end: + if (src != INVALID_SOCKET) + closesocket(src); + if (dst != INVALID_SOCKET) + closesocket(dst); + if (hThread != NULL) + CloseHandle(hThread); + HeapFree(GetProcessHeap(), 0, buffer); +} + +static void test_write_events(void) +{ + SOCKET src = INVALID_SOCKET; + SOCKET dst = INVALID_SOCKET; + HANDLE hThread = NULL; + HANDLE hEvent = INVALID_HANDLE_VALUE; + char *buffer = NULL; + int bufferSize = 1024*1024; + u_long one = 1; + int ret; + DWORD id; + WSANETWORKEVENTS netEvents; + DWORD dwRet; + + if (tcp_socketpair(&src, &dst) != 0) + { + ok(0, "creating socket pair failed, skipping test\n"); + return; + } + + /* On Windows it seems when a non-blocking socket sends to a + blocking socket on the same host, the send() is BLOCKING, + so make both sockets non-blocking */ + ret = ioctlsocket(src, FIONBIO, &one); + if (ret) + { + ok(0, "ioctlsocket failed, error %d\n", WSAGetLastError()); + goto end; + } + ret = ioctlsocket(dst, FIONBIO, &one); + if (ret) + { + ok(0, "ioctlsocket failed, error %d\n", WSAGetLastError()); + goto end; + } + + buffer = HeapAlloc(GetProcessHeap(), 0, bufferSize); + if (buffer == NULL) + { + ok(0, "could not allocate memory for test\n"); + goto end; + } + + hThread = CreateThread(NULL, 0, drain_socket_thread, &dst, 0, &id); + if (hThread == NULL) + { + ok(0, "CreateThread failed, error %d\n", GetLastError()); + goto end; + } + + hEvent = CreateEventA(NULL, FALSE, TRUE, NULL); + if (hEvent == INVALID_HANDLE_VALUE) + { + ok(0, "CreateEventA failed, error %d\n", GetLastError()); + goto end; + } + + ret = WSAEventSelect(src, hEvent, FD_WRITE | FD_CLOSE); + if (ret) + { + ok(0, "WSAEventSelect failed, error %d\n", ret); + goto end; + } + + /* FD_WRITE should be set initially, and allow us to send at least 1 byte */ + dwRet = WaitForSingleObject(hEvent, 5000); + if (dwRet != WAIT_OBJECT_0) + { + ok(0, "Initial WaitForSingleObject failed, error %d\n", dwRet); + goto end; + } + ret = WSAEnumNetworkEvents(src, NULL, &netEvents); + if (ret) + { + ok(0, "WSAEnumNetworkEvents failed, error %d\n", ret); + goto end; + } + if (netEvents.lNetworkEvents & FD_WRITE) + { + ret = send(src, "a", 1, 0); + ok(ret == 1, "sending 1 byte failed, error %d\n", WSAGetLastError()); + if (ret != 1) + goto end; + } + else + { + ok(0, "FD_WRITE not among initial events\n"); + goto end; + } + + /* Now FD_WRITE should not be set, because the socket send buffer isn't full yet */ + dwRet = WaitForSingleObject(hEvent, 2000); + if (dwRet == WAIT_OBJECT_0) + { + ok(0, "WaitForSingleObject should have timed out, but succeeded!\n"); + goto end; + } + + /* Now if we send a ton of data and the 'server' does not drain it fast + * enough (set drain_pause to be sure), the socket send buffer will only + * take some of it, and we will get a short write. This will trigger + * another FD_WRITE event as soon as data is sent and more space becomes + * available, but not any earlier. */ + drain_pause=1; + do + { + ret = send(src, buffer, bufferSize, 0); + } while (ret == bufferSize); + drain_pause=0; + if (ret >= 0 || WSAGetLastError() == WSAEWOULDBLOCK) + { + dwRet = WaitForSingleObject(hEvent, 5000); + ok(dwRet == WAIT_OBJECT_0, "Waiting failed with %d\n", dwRet); + if (dwRet == WAIT_OBJECT_0) + { + ret = WSAEnumNetworkEvents(src, NULL, &netEvents); + ok(ret == 0, "WSAEnumNetworkEvents failed, error %d\n", ret); + if (ret == 0) + goto end; + ok(netEvents.lNetworkEvents & FD_WRITE, + "FD_WRITE event not set as expected, events are 0x%x\n", netEvents.lNetworkEvents); + } + else + goto end; + } + else + { + ok(0, "sending a lot of data failed with error %d\n", WSAGetLastError()); + goto end; + } + +end: + HeapFree(GetProcessHeap(), 0, buffer); + if (src != INVALID_SOCKET) + closesocket(src); + if (dst != INVALID_SOCKET) + closesocket(dst); + if (hThread != NULL) + CloseHandle(hThread); + CloseHandle(hEvent); +} + +static void test_ipv6only(void) +{ + SOCKET v4 = INVALID_SOCKET, + v6 = INVALID_SOCKET; + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + int ret; + + memset(&sin4, 0, sizeof(sin4)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons(SERVERPORT); + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(SERVERPORT); + + v6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + if (v6 == INVALID_SOCKET) { + skip("Could not create IPv6 socket (LastError: %d; %d expected if IPv6 not available).\n", + WSAGetLastError(), WSAEAFNOSUPPORT); + goto end; + } + ret = bind(v6, (struct sockaddr*)&sin6, sizeof(sin6)); + if (ret) { + skip("Could not bind IPv6 address (LastError: %d).\n", + WSAGetLastError()); + goto end; + } + + v4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (v4 == INVALID_SOCKET) { + skip("Could not create IPv4 socket (LastError: %d).\n", + WSAGetLastError()); + goto end; + } + ret = bind(v4, (struct sockaddr*)&sin4, sizeof(sin4)); + ok(!ret, "Could not bind IPv4 address (LastError: %d; %d expected if IPv6 binds to IPv4 as well).\n", + WSAGetLastError(), WSAEADDRINUSE); + +end: + if (v4 != INVALID_SOCKET) + closesocket(v4); + if (v6 != INVALID_SOCKET) + closesocket(v6); +} + +static void test_WSASendTo(void) +{ + SOCKET s; + struct sockaddr_in addr; + char buf[12] = "hello world"; + WSABUF data_buf; + DWORD bytesSent; + + addr.sin_family = AF_INET; + addr.sin_port = htons(139); + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + data_buf.len = sizeof(buf); + data_buf.buf = buf; + + if( (s = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { + ok(0, "socket() failed error: %d\n", WSAGetLastError()); + return; + } + + WSASetLastError(12345); + if(WSASendTo(s, &data_buf, 1, &bytesSent, 0, (struct sockaddr*)&addr, sizeof(addr), NULL, NULL)) { + ok(0, "WSASendTo() failed error: %d\n", WSAGetLastError()); + return; + } + ok(!WSAGetLastError(), "WSAGetLastError() should return zero after " + "a successful call to WSASendTo()\n"); +} + +/**************** Main program ***************/ + +START_TEST( sock ) +{ + int i; + Init(); + + test_set_getsockopt(); + test_so_reuseaddr(); + test_extendedSocketOptions(); + + for (i = 0; i < NUM_TESTS; i++) + { + trace ( " **** STARTING TEST %d ****\n", i ); + do_test ( &tests[i] ); + trace ( " **** TEST %d COMPLETE ****\n", i ); + } + + test_UDP(); + + test_getservbyname(); + test_WSASocket(); + + test_WSAAddressToStringA(); + test_WSAAddressToStringW(); + + test_WSAStringToAddressA(); + test_WSAStringToAddressW(); + + test_select(); + test_accept(); + test_getsockname(); + test_inet_addr(); + test_ioctlsocket(); + test_dns(); + test_gethostbyname_hack(); + + test_send(); + test_write_events(); + + test_WSASendTo(); + + test_ipv6only(); + + Exit(); +} diff --git a/rostests/winetests/ws2_32/testlist.c b/rostests/winetests/ws2_32/testlist.c new file mode 100644 index 00000000000..9c0b71f7217 --- /dev/null +++ b/rostests/winetests/ws2_32/testlist.c @@ -0,0 +1,17 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_protocol(void); +extern void func_sock(void); + +const struct test winetest_testlist[] = +{ + { "protocol", func_protocol }, + { "sock", func_sock }, + { 0, 0 } +}; diff --git a/rostests/winetests/ws2_32/ws2_32.rbuild b/rostests/winetests/ws2_32/ws2_32.rbuild new file mode 100644 index 00000000000..c5ac9fc4f62 --- /dev/null +++ b/rostests/winetests/ws2_32/ws2_32.rbuild @@ -0,0 +1,14 @@ + + + + + . + + protocol.c + sock.c + testlist.c + wine + ws2_32 + ntdll + +